diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 92380492a2..9f039ce5b9 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -36,7 +36,7 @@ jobs: distribution: 'temurin' # See 'Supported distributions' for available options java-version: '17' - name: Configure gradle - uses: gradle/actions/setup-gradle@v3 + uses: gradle/actions/setup-gradle@v4 with: cache-read-only: ${{ github.ref != 'refs/heads/develop' }} - name: Assemble debug Gplay APK diff --git a/.github/workflows/build_enterprise.yml b/.github/workflows/build_enterprise.yml index 602b43a7e1..737b61ee06 100644 --- a/.github/workflows/build_enterprise.yml +++ b/.github/workflows/build_enterprise.yml @@ -44,7 +44,7 @@ jobs: distribution: 'temurin' # See 'Supported distributions' for available options java-version: '17' - name: Configure gradle - uses: gradle/actions/setup-gradle@v3 + uses: gradle/actions/setup-gradle@v4 with: cache-read-only: ${{ github.ref != 'refs/heads/develop' }} - name: Assemble debug Gplay Enterprise APK diff --git a/.github/workflows/generate_github_pages.yml b/.github/workflows/generate_github_pages.yml index 46494ba76a..c86c5799e3 100644 --- a/.github/workflows/generate_github_pages.yml +++ b/.github/workflows/generate_github_pages.yml @@ -19,7 +19,7 @@ jobs: distribution: 'temurin' # See 'Supported distributions' for available options java-version: '17' - name: Configure gradle - uses: gradle/actions/setup-gradle@v3 + uses: gradle/actions/setup-gradle@v4 with: cache-read-only: ${{ github.ref != 'refs/heads/develop' }} - name: Set up Python 3.12 diff --git a/.github/workflows/gradle-wrapper-validation.yml b/.github/workflows/gradle-wrapper-validation.yml deleted file mode 100644 index 3c619328ae..0000000000 --- a/.github/workflows/gradle-wrapper-validation.yml +++ /dev/null @@ -1,15 +0,0 @@ -name: "Validate Gradle Wrapper" -on: - pull_request: - merge_group: - push: - branches: [ main, develop ] - -jobs: - validation: - name: "Validation" - runs-on: ubuntu-latest - # No concurrency required, this is a prerequisite to other actions and should run every time. - steps: - - uses: actions/checkout@v4 - - uses: gradle/wrapper-validation-action@v3 diff --git a/.github/workflows/maestro.yml b/.github/workflows/maestro.yml index eb39516e5e..fd2cc75fd0 100644 --- a/.github/workflows/maestro.yml +++ b/.github/workflows/maestro.yml @@ -39,7 +39,7 @@ jobs: distribution: 'temurin' # See 'Supported distributions' for available options java-version: '17' - name: Configure gradle - uses: gradle/actions/setup-gradle@v3 + uses: gradle/actions/setup-gradle@v4 with: cache-read-only: ${{ github.ref != 'refs/heads/develop' }} - name: Assemble debug APK diff --git a/.github/workflows/nightlyReports.yml b/.github/workflows/nightlyReports.yml index 94f1ab275d..a0d39068eb 100644 --- a/.github/workflows/nightlyReports.yml +++ b/.github/workflows/nightlyReports.yml @@ -27,7 +27,7 @@ jobs: java-version: '17' - name: Configure gradle - uses: gradle/actions/setup-gradle@v3 + uses: gradle/actions/setup-gradle@v4 with: cache-read-only: false @@ -67,7 +67,7 @@ jobs: distribution: 'temurin' # See 'Supported distributions' for available options java-version: '17' - name: Configure gradle - uses: gradle/actions/setup-gradle@v3 + uses: gradle/actions/setup-gradle@v4 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 a0643c426f..5157a4b3d6 100644 --- a/.github/workflows/quality.yml +++ b/.github/workflows/quality.yml @@ -52,7 +52,7 @@ jobs: distribution: 'temurin' # See 'Supported distributions' for available options java-version: '17' - name: Configure gradle - uses: gradle/actions/setup-gradle@v3 + uses: gradle/actions/setup-gradle@v4 with: cache-read-only: ${{ github.ref != 'refs/heads/develop' }} - name: Set up Python 3.12 @@ -90,7 +90,7 @@ jobs: distribution: 'temurin' # See 'Supported distributions' for available options java-version: '17' - name: Configure gradle - uses: gradle/actions/setup-gradle@v3 + uses: gradle/actions/setup-gradle@v4 with: cache-read-only: ${{ github.ref != 'refs/heads/develop' }} - name: Run Konsist tests @@ -130,7 +130,7 @@ jobs: distribution: 'temurin' # See 'Supported distributions' for available options java-version: '17' - name: Configure gradle - uses: gradle/actions/setup-gradle@v3 + uses: gradle/actions/setup-gradle@v4 with: cache-read-only: ${{ github.ref != 'refs/heads/develop' }} - name: Build Gplay Debug @@ -174,7 +174,7 @@ jobs: distribution: 'temurin' # See 'Supported distributions' for available options java-version: '17' - name: Configure gradle - uses: gradle/actions/setup-gradle@v3 + uses: gradle/actions/setup-gradle@v4 with: cache-read-only: ${{ github.ref != 'refs/heads/develop' }} - name: Run Detekt @@ -214,7 +214,7 @@ jobs: distribution: 'temurin' # See 'Supported distributions' for available options java-version: '17' - name: Configure gradle - uses: gradle/actions/setup-gradle@v3 + uses: gradle/actions/setup-gradle@v4 with: cache-read-only: ${{ github.ref != 'refs/heads/develop' }} - name: Run Ktlint check @@ -254,7 +254,7 @@ jobs: distribution: 'temurin' # See 'Supported distributions' for available options java-version: '17' - name: Configure gradle - uses: gradle/actions/setup-gradle@v3 + uses: gradle/actions/setup-gradle@v4 with: cache-read-only: ${{ github.ref != 'refs/heads/develop' }} - name: Run Knit diff --git a/.github/workflows/recordScreenshots.yml b/.github/workflows/recordScreenshots.yml index 44522a0084..e176c5d7bc 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/actions/setup-gradle@v3 + uses: gradle/actions/setup-gradle@v4 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 38be804fc1..fea2b6715c 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/actions/setup-gradle@v3 + uses: gradle/actions/setup-gradle@v4 - name: Create app bundle env: ELEMENT_ANDROID_MAPTILER_API_KEY: ${{ secrets.MAPTILER_KEY }} @@ -61,7 +61,7 @@ jobs: distribution: 'temurin' # See 'Supported distributions' for available options java-version: '17' - name: Configure gradle - uses: gradle/actions/setup-gradle@v3 + uses: gradle/actions/setup-gradle@v4 - name: Create Enterprise app bundle env: ELEMENT_ANDROID_MAPTILER_API_KEY: ${{ secrets.MAPTILER_KEY }} @@ -89,7 +89,7 @@ jobs: distribution: 'temurin' # See 'Supported distributions' for available options java-version: '17' - name: Configure gradle - uses: gradle/actions/setup-gradle@v3 + uses: gradle/actions/setup-gradle@v4 - name: Create APKs env: ELEMENT_ANDROID_MAPTILER_API_KEY: ${{ secrets.MAPTILER_KEY }} diff --git a/.github/workflows/sonar.yml b/.github/workflows/sonar.yml index bbab77cf65..b5e0be7e2d 100644 --- a/.github/workflows/sonar.yml +++ b/.github/workflows/sonar.yml @@ -33,7 +33,7 @@ jobs: distribution: 'temurin' # See 'Supported distributions' for available options java-version: '17' - name: Configure gradle - uses: gradle/actions/setup-gradle@v3 + uses: gradle/actions/setup-gradle@v4 with: cache-read-only: ${{ github.ref != 'refs/heads/develop' }} - name: Build Gplay Debug diff --git a/.github/workflows/sync-localazy.yml b/.github/workflows/sync-localazy.yml index 5f99cac17a..1330b373bf 100644 --- a/.github/workflows/sync-localazy.yml +++ b/.github/workflows/sync-localazy.yml @@ -18,7 +18,7 @@ jobs: distribution: 'temurin' # See 'Supported distributions' for available options java-version: '17' - name: Configure gradle - uses: gradle/actions/setup-gradle@v3 + uses: gradle/actions/setup-gradle@v4 with: cache-read-only: ${{ github.ref != 'refs/heads/develop' }} - name: Set up Python 3.12 diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index fa274baf89..e96dcae925 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -52,7 +52,7 @@ jobs: distribution: 'temurin' # See 'Supported distributions' for available options java-version: '17' - name: Configure gradle - uses: gradle/actions/setup-gradle@v3 + uses: gradle/actions/setup-gradle@v4 with: cache-read-only: ${{ github.ref != 'refs/heads/develop' }} diff --git a/.idea/kotlinc.xml b/.idea/kotlinc.xml index 148fdd2469..4cb7457249 100644 --- a/.idea/kotlinc.xml +++ b/.idea/kotlinc.xml @@ -1,6 +1,6 @@ - \ No newline at end of file diff --git a/README.md b/README.md index 35d4cffb27..25f2f2c835 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ [![Latest build](https://github.com/element-hq/element-x-android/actions/workflows/build.yml/badge.svg?query=branch%3Adevelop)](https://github.com/element-hq/element-x-android/actions/workflows/build.yml?query=branch%3Adevelop) -[![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=vector-im_element-x-android&metric=alert_status)](https://sonarcloud.io/summary/new_code?id=vector-im_element-x-android) -[![Vulnerabilities](https://sonarcloud.io/api/project_badges/measure?project=vector-im_element-x-android&metric=vulnerabilities)](https://sonarcloud.io/summary/new_code?id=vector-im_element-x-android) -[![Bugs](https://sonarcloud.io/api/project_badges/measure?project=vector-im_element-x-android&metric=bugs)](https://sonarcloud.io/summary/new_code?id=vector-im_element-x-android) +[![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=element-x-android&metric=alert_status)](https://sonarcloud.io/summary/new_code?id=element-x-android) +[![Vulnerabilities](https://sonarcloud.io/api/project_badges/measure?project=element-x-android&metric=vulnerabilities)](https://sonarcloud.io/summary/new_code?id=element-x-android) +[![Bugs](https://sonarcloud.io/api/project_badges/measure?project=element-x-android&metric=bugs)](https://sonarcloud.io/summary/new_code?id=element-x-android) [![codecov](https://codecov.io/github/element-hq/element-x-android/branch/develop/graph/badge.svg?token=ecwvia7amV)](https://codecov.io/github/vector-im/element-x-android) [![Element X Android Matrix room #element-x-android:matrix.org](https://img.shields.io/matrix/element-x-android:matrix.org.svg?label=%23element-x-android:matrix.org&logo=matrix&server_fqdn=matrix.org)](https://matrix.to/#/#element-x-android:matrix.org) [![Localazy](https://img.shields.io/endpoint?url=https%3A%2F%2Fconnect.localazy.com%2Fstatus%2Felement%2Fdata%3Fcontent%3Dall%26title%3Dlocalazy%26logo%3Dtrue)](https://localazy.com/p/element) diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro index c800b9d996..89dcab5fad 100644 --- a/app/proguard-rules.pro +++ b/app/proguard-rules.pro @@ -40,3 +40,5 @@ -keepclassmembers class android.view.JavaViewSpy { static int windowAttachCount(android.view.View); } + +-keep class io.element.android.x.di.** { *; } diff --git a/app/src/main/res/xml/locales_config.xml b/app/src/main/res/xml/locales_config.xml index fa0e1e2199..e49aa1e4a0 100644 --- a/app/src/main/res/xml/locales_config.xml +++ b/app/src/main/res/xml/locales_config.xml @@ -21,6 +21,7 @@ + diff --git a/appconfig/src/main/kotlin/io/element/android/appconfig/TimelineConfig.kt b/appconfig/src/main/kotlin/io/element/android/appconfig/TimelineConfig.kt index 2ad2916550..2bbb96cabb 100644 --- a/appconfig/src/main/kotlin/io/element/android/appconfig/TimelineConfig.kt +++ b/appconfig/src/main/kotlin/io/element/android/appconfig/TimelineConfig.kt @@ -31,7 +31,6 @@ object TimelineConfig { 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, diff --git a/build.gradle.kts b/build.gradle.kts index 8139ed6eb8..97daebb1d3 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -61,7 +61,7 @@ allprojects { config.from(files("$rootDir/tools/detekt/detekt.yml")) } dependencies { - detektPlugins("io.nlopez.compose.rules:detekt:0.4.5") + detektPlugins("io.nlopez.compose.rules:detekt:0.4.10") } // KtLint @@ -129,11 +129,11 @@ dependencyAnalysis { // To run a sonar analysis: // Run './gradlew sonar -Dsonar.login=' // The SONAR_LOGIN is stored in passbolt as Token Sonar Cloud Bma -// Sonar result can be found here: https://sonarcloud.io/project/overview?id=vector-im_element-x-android +// Sonar result can be found here: https://sonarcloud.io/project/overview?id=element-x-android sonar { properties { property("sonar.projectName", "element-x-android") - property("sonar.projectKey", "vector-im_element-x-android") + property("sonar.projectKey", "element-x-android") property("sonar.host.url", "https://sonarcloud.io") property("sonar.projectVersion", "1.0") // TODO project(":app").android.defaultConfig.versionName) property("sonar.sourceEncoding", "UTF-8") @@ -141,7 +141,7 @@ sonar { property("sonar.links.ci", "https://github.com/element-hq/element-x-android/actions") property("sonar.links.scm", "https://github.com/element-hq/element-x-android/") property("sonar.links.issue", "https://github.com/element-hq/element-x-android/issues") - property("sonar.organization", "new_vector_ltd_organization") + property("sonar.organization", "element-hq") property("sonar.login", if (project.hasProperty("SONAR_LOGIN")) project.property("SONAR_LOGIN")!! else "invalid") // exclude source code from analyses separated by a colon (:) diff --git a/features/analytics/api/src/main/res/values-pl/translations.xml b/features/analytics/api/src/main/res/values-pl/translations.xml index 26aa9c6073..9fd1f51683 100644 --- a/features/analytics/api/src/main/res/values-pl/translations.xml +++ b/features/analytics/api/src/main/res/values-pl/translations.xml @@ -1,7 +1,7 @@ "Udostępniaj anonimowe dane dotyczące użytkowania, aby pomóc nam identyfikować problemy." - "Możesz przeczytać wszystkie nasze warunki %1$s." + "Przeczytaj nasze warunki użytkowania %1$s." "tutaj" "Udostępniaj dane analityczne" diff --git a/features/analytics/api/src/main/res/values-uz/translations.xml b/features/analytics/api/src/main/res/values-uz/translations.xml new file mode 100644 index 0000000000..787a1b03bc --- /dev/null +++ b/features/analytics/api/src/main/res/values-uz/translations.xml @@ -0,0 +1,7 @@ + + + "Muammolarni aniqlashda yordam berish uchun anonim foydalanish maʼlumotlarini baham koʻring." + "Siz bizning barcha shartlarimizni o\'qishingiz mumkin%1$s." + "Bu yerga" + "Analitik ma\'lumotlarni ulashish" + diff --git a/features/analytics/impl/src/main/res/values-pl/translations.xml b/features/analytics/impl/src/main/res/values-pl/translations.xml index 99e3e441bb..02faba157f 100644 --- a/features/analytics/impl/src/main/res/values-pl/translations.xml +++ b/features/analytics/impl/src/main/res/values-pl/translations.xml @@ -2,7 +2,7 @@ "Nie będziemy rejestrować ani profilować żadnych danych osobistych" "Udostępniaj anonimowe dane dotyczące użytkowania, aby pomóc nam identyfikować problemy." - "Możesz przeczytać wszystkie nasze warunki %1$s." + "Przeczytaj nasze warunki użytkowania %1$s." "tutaj" "Możesz to wyłączyć w dowolnym momencie" "Nie będziemy udostępniać Twoich danych podmiotom trzecim" diff --git a/features/analytics/impl/src/main/res/values-uz/translations.xml b/features/analytics/impl/src/main/res/values-uz/translations.xml new file mode 100644 index 0000000000..daa1080628 --- /dev/null +++ b/features/analytics/impl/src/main/res/values-uz/translations.xml @@ -0,0 +1,10 @@ + + + "Biz hech qanday shaxsiy ma\'lumotlarni yozmaymiz yoki profilga kiritmaymiz" + "Muammolarni aniqlashda yordam berish uchun anonim foydalanish maʼlumotlarini baham koʻring." + "Siz bizning barcha shartlarimizni o\'qishingiz mumkin%1$s." + "Bu yerga" + "Buni istalgan vaqtda oʻchirib qoʻyishingiz mumkin" + "Biz sizning ma\'lumotlaringizni uchinchi tomonlar bilan baham ko\'rmaymiz" + "Yaxshilashga yordam bering%1$s" + diff --git a/features/call/impl/src/main/res/values-pl/translations.xml b/features/call/impl/src/main/res/values-pl/translations.xml index 27133cd91b..e63fc80d14 100644 --- a/features/call/impl/src/main/res/values-pl/translations.xml +++ b/features/call/impl/src/main/res/values-pl/translations.xml @@ -3,4 +3,5 @@ "Połączenie w trakcie" "Stuknij, aby wrócić do rozmowy" "☎️ Rozmowa w toku" + "Przychodzące połączenie Element" diff --git a/features/call/impl/src/main/res/values-sv/translations.xml b/features/call/impl/src/main/res/values-sv/translations.xml index 8b76a70818..b5ee7bc2da 100644 --- a/features/call/impl/src/main/res/values-sv/translations.xml +++ b/features/call/impl/src/main/res/values-sv/translations.xml @@ -3,4 +3,5 @@ "Pågående samtal" "Tryck för att återgå till samtalet" "☎️ Samtal pågår" + "Inkommande Element Call" diff --git a/features/call/impl/src/main/res/values-uz/translations.xml b/features/call/impl/src/main/res/values-uz/translations.xml new file mode 100644 index 0000000000..010695a2ef --- /dev/null +++ b/features/call/impl/src/main/res/values-uz/translations.xml @@ -0,0 +1,6 @@ + + + "Davom etayotgan qo\'ng\'iroq" + "Qo\'ng\'iroqqa qaytish uchun bosing" + "☎️ Qo‘ng‘iroq davom etmoqda" + diff --git a/features/call/impl/src/test/kotlin/io/element/android/features/call/ui/CallScreenPresenterTest.kt b/features/call/impl/src/test/kotlin/io/element/android/features/call/ui/CallScreenPresenterTest.kt index 09e6c86158..f56163b25d 100644 --- a/features/call/impl/src/test/kotlin/io/element/android/features/call/ui/CallScreenPresenterTest.kt +++ b/features/call/impl/src/test/kotlin/io/element/android/features/call/ui/CallScreenPresenterTest.kt @@ -36,6 +36,7 @@ import io.element.android.libraries.matrix.test.A_SESSION_ID import io.element.android.libraries.matrix.test.FakeMatrixClient import io.element.android.libraries.matrix.test.FakeMatrixClientProvider import io.element.android.libraries.matrix.test.room.FakeMatrixRoom +import io.element.android.libraries.matrix.test.sync.FakeSyncService import io.element.android.libraries.matrix.test.widget.FakeMatrixWidgetDriver import io.element.android.libraries.network.useragent.UserAgentProvider import io.element.android.services.analytics.api.ScreenTracker @@ -43,11 +44,13 @@ import io.element.android.services.analytics.test.FakeScreenTracker import io.element.android.services.toolbox.api.systemclock.SystemClock import io.element.android.tests.testutils.WarmUpRule import io.element.android.tests.testutils.consumeItemsUntilTimeout +import io.element.android.tests.testutils.lambda.assert import io.element.android.tests.testutils.lambda.lambdaRecorder import io.element.android.tests.testutils.lambda.value import io.element.android.tests.testutils.testCoroutineDispatchers import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.cancelAndJoin +import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.launch import kotlinx.coroutines.sync.Mutex import kotlinx.coroutines.test.TestScope @@ -86,8 +89,9 @@ class CallScreenPresenterTest { @Test fun `present - with CallType RoomCall sets call as active, loads URL, runs WidgetDriver and notifies the other clients a call started`() = runTest { val sendCallNotificationIfNeededLambda = lambdaRecorder> { Result.success(Unit) } + val syncService = FakeSyncService(MutableStateFlow(SyncState.Running)) val fakeRoom = FakeMatrixRoom(sendCallNotificationIfNeededResult = sendCallNotificationIfNeededLambda) - val client = FakeMatrixClient().apply { + val client = FakeMatrixClient(syncService = syncService).apply { givenGetRoomResult(A_ROOM_ID, fakeRoom) } val widgetDriver = FakeMatrixWidgetDriver() @@ -216,7 +220,12 @@ class CallScreenPresenterTest { fun `present - automatically starts the Matrix client sync when on RoomCall`() = runTest { val navigator = FakeCallScreenNavigator() val widgetDriver = FakeMatrixWidgetDriver() - val matrixClient = FakeMatrixClient() + val syncStateFlow = MutableStateFlow(SyncState.Idle) + val startSyncLambda = lambdaRecorder> { Result.success(Unit) } + val syncService = FakeSyncService(syncStateFlow = syncStateFlow).apply { + this.startSyncLambda = startSyncLambda + } + val matrixClient = FakeMatrixClient(syncService = syncService) val presenter = createCallScreenPresenter( callType = CallType.RoomCall(A_SESSION_ID, A_ROOM_ID), widgetDriver = widgetDriver, @@ -230,7 +239,7 @@ class CallScreenPresenterTest { }.test { consumeItemsUntilTimeout() - assertThat(matrixClient.syncService().syncState.value).isEqualTo(SyncState.Running) + assert(startSyncLambda).isCalledOnce() cancelAndIgnoreRemainingEvents() } @@ -240,7 +249,12 @@ class CallScreenPresenterTest { fun `present - automatically stops the Matrix client sync on dispose`() = runTest { val navigator = FakeCallScreenNavigator() val widgetDriver = FakeMatrixWidgetDriver() - val matrixClient = FakeMatrixClient() + val syncStateFlow = MutableStateFlow(SyncState.Running) + val stopSyncLambda = lambdaRecorder> { Result.success(Unit) } + val syncService = FakeSyncService(syncStateFlow = syncStateFlow).apply { + this.stopSyncLambda = stopSyncLambda + } + val matrixClient = FakeMatrixClient(syncService = syncService) val presenter = createCallScreenPresenter( callType = CallType.RoomCall(A_SESSION_ID, A_ROOM_ID), widgetDriver = widgetDriver, @@ -262,7 +276,7 @@ class CallScreenPresenterTest { job.cancelAndJoin() - assertThat(matrixClient.syncService().syncState.value).isEqualTo(SyncState.Terminated) + assert(stopSyncLambda).isCalledOnce() } private fun TestScope.createCallScreenPresenter( diff --git a/features/createroom/impl/src/main/res/values-pl/translations.xml b/features/createroom/impl/src/main/res/values-pl/translations.xml index eb64b46d8c..37090055b9 100644 --- a/features/createroom/impl/src/main/res/values-pl/translations.xml +++ b/features/createroom/impl/src/main/res/values-pl/translations.xml @@ -6,7 +6,7 @@ "Wiadomości w tym pokoju są szyfrowane. Szyfrowania nie można później wyłączyć." "Pokój prywatny (tylko zaproszenie)" "Wiadomości nie są szyfrowane i każdy może je odczytać. Możesz aktywować szyfrowanie później." - "Pokój publiczny (każdy)" + "Pokój publiczny (wszyscy)" "Nazwa pokoju" "Utwórz pokój" "Temat (opcjonalnie)" diff --git a/features/createroom/impl/src/main/res/values-uz/translations.xml b/features/createroom/impl/src/main/res/values-uz/translations.xml new file mode 100644 index 0000000000..649bdf8613 --- /dev/null +++ b/features/createroom/impl/src/main/res/values-uz/translations.xml @@ -0,0 +1,14 @@ + + + "Yangi xona" + "Odamlarni taklif qiling" + "Xonani yaratishda xatolik yuz berdi" + "Bu xonadagi xabarlar shifrlangan. Keyinchalik shifrlashni o‘chirib bo‘lmaydi." + "Shaxsiy xona (faqat taklif)" + "Xabarlar shifrlanmagan va har kim ularni o\'qiy oladi. Keyinchalik shifrlashni yoqishingiz mumkin." + "Jamoat xonasi (har kim)" + "Xona nomi" + "Xonani yaratish" + "Mavzu (ixtiyoriy)" + "Suhbatni boshlashda xatolik yuz berdi" + diff --git a/features/ftue/impl/src/main/res/values-uz/translations.xml b/features/ftue/impl/src/main/res/values-uz/translations.xml new file mode 100644 index 0000000000..f8ede2ecf4 --- /dev/null +++ b/features/ftue/impl/src/main/res/values-uz/translations.xml @@ -0,0 +1,11 @@ + + + "Sozlamalaringizni keyinroq o\'zgartirishingiz mumkin." + "Bildirishnomalarga ruxsat bering va hech qachon xabarni o\'tkazib yubormang" + "Qo\'ng\'iroqlar, so\'ro\'vlar, qidiruv va boshqalar shu yil oxirida qo\'shiladi." + "Shifrlangan xonalar uchun xabarlar tarixi hali mavjud emas." + "Biz sizdan eshitishni istardik, sozlamalar sahifasi orqali fikringizni bildiring." + "Qani ketdik!" + "Buni bilishingiz kerak:" + "%1$sga Xush kelibsiz!" + diff --git a/features/invite/impl/src/main/res/values-pl/translations.xml b/features/invite/impl/src/main/res/values-pl/translations.xml index e33b1ae106..95283e4cba 100644 --- a/features/invite/impl/src/main/res/values-pl/translations.xml +++ b/features/invite/impl/src/main/res/values-pl/translations.xml @@ -1,6 +1,6 @@ - "Czy na pewno chcesz odrzucić zaproszenie do dołączenia do %1$s?" + "Czy na pewno chcesz odrzucić zaproszenie dołączenia do %1$s?" "Odrzuć zaproszenie" "Czy na pewno chcesz odrzucić rozmowę prywatną z %1$s?" "Odrzuć czat" diff --git a/features/invite/impl/src/main/res/values-uz/translations.xml b/features/invite/impl/src/main/res/values-uz/translations.xml new file mode 100644 index 0000000000..78e3975700 --- /dev/null +++ b/features/invite/impl/src/main/res/values-uz/translations.xml @@ -0,0 +1,9 @@ + + + "Haqiqatan ham qo\'shilish taklifini rad qilmoqchimisiz%1$s ?" + "Taklifni rad etish" + "Haqiqatan ham bu shaxsiy chatni rad qilmoqchimisiz%1$s ?" + "Chatni rad etish" + "Takliflar yo\'q" + "%1$s(%2$s ) sizni taklif qildi" + diff --git a/features/joinroom/impl/src/main/res/values-pl/translations.xml b/features/joinroom/impl/src/main/res/values-pl/translations.xml new file mode 100644 index 0000000000..585169fa80 --- /dev/null +++ b/features/joinroom/impl/src/main/res/values-pl/translations.xml @@ -0,0 +1,11 @@ + + + "Dołącz do pokoju" + "Zapukaj, by dołączyć" + "%1$s jeszcze nie obsługuje przestrzeni. Uzyskaj dostęp do przestrzeni w wersji web." + "Przestrzenie nie są jeszcze obsługiwane" + "Kliknij przycisk poniżej, aby powiadomić administratora pokoju. Po zatwierdzeniu będziesz mógł dołączyć do rozmowy." + "Musisz być członkiem tego pokoju, aby wyświetlić historię wiadomości." + "Chcesz dołączyć do tego pokoju?" + "Podgląd nie jest dostępny" + diff --git a/features/joinroom/impl/src/main/res/values-sv/translations.xml b/features/joinroom/impl/src/main/res/values-sv/translations.xml new file mode 100644 index 0000000000..0181a01381 --- /dev/null +++ b/features/joinroom/impl/src/main/res/values-sv/translations.xml @@ -0,0 +1,11 @@ + + + "Gå med i rummet" + "Knacka för att gå med" + "%1$s stöder inte utrymmen än. Du kan komma åt utrymmen på webben." + "Utrymmen stöds inte ännu" + "Klicka på knappen nedan så kommer en rumsadministratör att meddelas. Du kommer att kunna gå med i konversationen när den har godkänts." + "Du måste vara medlem i det här rummet för att se meddelandehistoriken." + "Vill du gå med i det här rummet?" + "Förhandsgranskning är inte tillgänglig" + diff --git a/features/joinroom/impl/src/main/res/values-uk/translations.xml b/features/joinroom/impl/src/main/res/values-uk/translations.xml new file mode 100644 index 0000000000..ba19245e40 --- /dev/null +++ b/features/joinroom/impl/src/main/res/values-uk/translations.xml @@ -0,0 +1,11 @@ + + + "Приєднатися до кімнати" + "Постукати, щоб приєднатися" + "%1$s ще не підтримує простори. Ви можете отримати доступ до них в вебверсії." + "Простори поки що не підтримуються" + "Натисніть кнопку нижче, і адміністратор кімнати отримає сповіщення. Ви зможете приєднатися до розмови після схвалення." + "Ви мусите бути учасником цієї кімнати, щоб переглядати історію повідомлень." + "Хочете приєднатися до цієї кімнати?" + "Попередній перегляд недоступний" + diff --git a/features/leaveroom/api/src/main/res/values-uz/translations.xml b/features/leaveroom/api/src/main/res/values-uz/translations.xml new file mode 100644 index 0000000000..59c111e2ac --- /dev/null +++ b/features/leaveroom/api/src/main/res/values-uz/translations.xml @@ -0,0 +1,6 @@ + + + "Bu xonani tark etmoqchi ekanligingizga ishonchingiz komilmi? Siz bu yerda yagona odamsiz. Agar siz tark etsangiz, kelajakda hech kim qo\'shila olmaydi, jumladan siz ham." + "Bu xonani tark etmoqchi ekanligingizga ishonchingiz komilmi? Bu xona ochiq emas va siz taklifsiz qayta qo‘shila olmaysiz." + "Xonani tark etmoqchi ekanligingizga ishonchingiz komilmi?" + diff --git a/features/lockscreen/impl/build.gradle.kts b/features/lockscreen/impl/build.gradle.kts index 21f3e05421..b8dc1c5035 100644 --- a/features/lockscreen/impl/build.gradle.kts +++ b/features/lockscreen/impl/build.gradle.kts @@ -41,6 +41,7 @@ dependencies { implementation(projects.libraries.featureflag.api) implementation(projects.libraries.cryptography.api) implementation(projects.libraries.preferences.api) + implementation(projects.features.logout.api) implementation(projects.libraries.uiStrings) implementation(projects.libraries.sessionStorage.api) implementation(projects.services.appnavstate.api) @@ -59,4 +60,5 @@ dependencies { testImplementation(projects.libraries.featureflag.test) testImplementation(projects.libraries.sessionStorage.test) testImplementation(projects.services.appnavstate.test) + testImplementation(projects.features.logout.test) } diff --git a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/unlock/PinUnlockPresenter.kt b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/unlock/PinUnlockPresenter.kt index db56b8c17b..b563b3ac70 100644 --- a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/unlock/PinUnlockPresenter.kt +++ b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/unlock/PinUnlockPresenter.kt @@ -29,7 +29,7 @@ import io.element.android.features.lockscreen.impl.biometric.BiometricUnlockMana import io.element.android.features.lockscreen.impl.pin.PinCodeManager import io.element.android.features.lockscreen.impl.pin.model.PinEntry import io.element.android.features.lockscreen.impl.unlock.keypad.PinKeypadModel -import io.element.android.features.lockscreen.impl.unlock.signout.SignOut +import io.element.android.features.logout.api.LogoutUseCase import io.element.android.libraries.architecture.AsyncData import io.element.android.libraries.architecture.Presenter import io.element.android.libraries.architecture.runCatchingUpdatingState @@ -41,7 +41,7 @@ import javax.inject.Inject class PinUnlockPresenter @Inject constructor( private val pinCodeManager: PinCodeManager, private val biometricUnlockManager: BiometricUnlockManager, - private val signOut: SignOut, + private val logoutUseCase: LogoutUseCase, private val coroutineScope: CoroutineScope, private val pinUnlockHelper: PinUnlockHelper, ) : Presenter { @@ -179,7 +179,7 @@ class PinUnlockPresenter @Inject constructor( private fun CoroutineScope.signOut(signOutAction: MutableState>) = launch { suspend { - signOut() + logoutUseCase.logout(ignoreSdkError = true) }.runCatchingUpdatingState(signOutAction) } } diff --git a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/unlock/di/PinUnlockBindings.kt b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/unlock/di/PinUnlockBindings.kt index ddd62d2fb6..0f71222ebd 100644 --- a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/unlock/di/PinUnlockBindings.kt +++ b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/unlock/di/PinUnlockBindings.kt @@ -18,9 +18,9 @@ package io.element.android.features.lockscreen.impl.unlock.di import com.squareup.anvil.annotations.ContributesTo import io.element.android.features.lockscreen.impl.unlock.activity.PinUnlockActivity -import io.element.android.libraries.di.AppScope +import io.element.android.libraries.di.SessionScope -@ContributesTo(AppScope::class) +@ContributesTo(SessionScope::class) interface PinUnlockBindings { fun inject(activity: PinUnlockActivity) } diff --git a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/unlock/signout/DefaultSignOut.kt b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/unlock/signout/DefaultSignOut.kt deleted file mode 100644 index 2c541911e6..0000000000 --- a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/unlock/signout/DefaultSignOut.kt +++ /dev/null @@ -1,40 +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.features.lockscreen.impl.unlock.signout - -import com.squareup.anvil.annotations.ContributesBinding -import io.element.android.libraries.di.AppScope -import io.element.android.libraries.matrix.api.MatrixClientProvider -import io.element.android.libraries.matrix.api.auth.MatrixAuthenticationService -import javax.inject.Inject - -@ContributesBinding(AppScope::class) -class DefaultSignOut @Inject constructor( - private val authenticationService: MatrixAuthenticationService, - private val matrixClientProvider: MatrixClientProvider, -) : SignOut { - override suspend fun invoke(): String? { - val currentSession = authenticationService.getLatestSessionId() - return if (currentSession != null) { - matrixClientProvider.getOrRestore(currentSession) - .getOrThrow() - .logout(ignoreSdkError = true) - } else { - error("No session to sign out") - } - } -} diff --git a/features/lockscreen/impl/src/main/res/values-pl/translations.xml b/features/lockscreen/impl/src/main/res/values-pl/translations.xml index 1eb904b13e..134799b146 100644 --- a/features/lockscreen/impl/src/main/res/values-pl/translations.xml +++ b/features/lockscreen/impl/src/main/res/values-pl/translations.xml @@ -16,11 +16,11 @@ "Potwierdź PIN" "Zablokuj %1$s, aby zwiększyć bezpieczeństwo swoich czatów. -Wybierz coś łatwego do zapamiętania. Jeśli zapomnisz tego PINU, zostaniesz wylogowany z aplikacji." - "Nie możesz wybrać tego PINU ze względów bezpieczeństwa" +Wybierz coś łatwego do zapamiętania. Jeśli zapomnisz tego PIN\'u, zostaniesz wylogowany z aplikacji." + "Nie możesz wybrać tego PIN\'u ze względów bezpieczeństwa" "Wybierz inny kod PIN" "Wprowadź ten sam kod PIN dwa razy" - "PINY nie pasują do siebie" + "PIN\'y nie pasują do siebie" "Aby kontynuować, zaloguj się ponownie i utwórz nowy kod PIN" "Trwa wylogowywanie" diff --git a/features/lockscreen/impl/src/main/res/values-pt-rBR/translations.xml b/features/lockscreen/impl/src/main/res/values-pt-rBR/translations.xml index b7af1aba25..da8b201b6d 100644 --- a/features/lockscreen/impl/src/main/res/values-pt-rBR/translations.xml +++ b/features/lockscreen/impl/src/main/res/values-pt-rBR/translations.xml @@ -1,14 +1,27 @@ + "autenticação por biometria" + "desbloqueio por biometria" + "Desbloquear com biometria" "Esqueceu o PIN?" - "Mudar código de PIN" + "Alterar código de PIN" "Permitir desbloqueio biométrico" "Remover PIN" "Tem certeza de que quer remover o PIN?" "Remover PIN?" + "Permitir %1$s" + "Prefiro usar o PIN" + "Poupe tempo e use %1$s para desbloquear o aplicativo todas as vezes" "Escolher PIN" "Confirmar PIN" + "Bloqueie o %1$s para adicionar uma segurança extra às suas conversas. + +Escolha algo memorável. Se você esquecer este PIN, você será desconectado do app." + "Você não pode escolher este PIN por razões de segurança" + "Escolha um PIN diferente" + "Por favor, insira o mesmo PIN duas vezes" "Os PINs não correspondem" + "Você terá que fazer login novamente e criar um novo PIN para prosseguir" "Você está sendo desconectado" "Você tem %1$d tentativa de debloqueio" @@ -18,5 +31,7 @@ "PIN incorreto. Você tem mais %1$d chance" "PIN incorreto. Você tem mais %1$d chances" + "Usar biometria" + "Usar PIN" "Saindo…" diff --git a/features/lockscreen/impl/src/main/res/values-uz/translations.xml b/features/lockscreen/impl/src/main/res/values-uz/translations.xml new file mode 100644 index 0000000000..b9f1c4f5cb --- /dev/null +++ b/features/lockscreen/impl/src/main/res/values-uz/translations.xml @@ -0,0 +1,4 @@ + + + "Chiqish…" + diff --git a/features/lockscreen/impl/src/test/kotlin/io/element/android/features/lockscreen/impl/unlock/DefaultSignOutTest.kt b/features/lockscreen/impl/src/test/kotlin/io/element/android/features/lockscreen/impl/unlock/DefaultSignOutTest.kt deleted file mode 100644 index 392693d9ef..0000000000 --- a/features/lockscreen/impl/src/test/kotlin/io/element/android/features/lockscreen/impl/unlock/DefaultSignOutTest.kt +++ /dev/null @@ -1,61 +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.features.lockscreen.impl.unlock - -import com.google.common.truth.Truth.assertThat -import io.element.android.features.lockscreen.impl.unlock.signout.DefaultSignOut -import io.element.android.libraries.matrix.test.FakeMatrixClient -import io.element.android.libraries.matrix.test.FakeMatrixClientProvider -import io.element.android.libraries.matrix.test.auth.FakeMatrixAuthenticationService -import io.element.android.tests.testutils.lambda.assert -import io.element.android.tests.testutils.lambda.lambdaRecorder -import kotlinx.coroutines.test.runTest -import org.junit.Test - -class DefaultSignOutTest { - private val matrixClient = FakeMatrixClient() - private val authenticationService = FakeMatrixAuthenticationService() - private val matrixClientProvider = FakeMatrixClientProvider(getClient = { Result.success(matrixClient) }) - private val sut = DefaultSignOut(authenticationService, matrixClientProvider) - - @Test - fun `when no active session then it throws`() = runTest { - authenticationService.getLatestSessionIdLambda = { null } - val result = runCatching { sut.invoke() } - assertThat(result.isFailure).isTrue() - } - - @Test - fun `with one active session and successful logout on client`() = runTest { - val logoutLambda = lambdaRecorder { _: Boolean -> null } - authenticationService.getLatestSessionIdLambda = { matrixClient.sessionId } - matrixClient.logoutLambda = logoutLambda - val result = runCatching { sut.invoke() } - assertThat(result.isSuccess).isTrue() - assert(logoutLambda).isCalledOnce() - } - - @Test - fun `with one active session and and failed logout on client`() = runTest { - val logoutLambda = lambdaRecorder { _: Boolean -> error("Failed to logout") } - authenticationService.getLatestSessionIdLambda = { matrixClient.sessionId } - matrixClient.logoutLambda = logoutLambda - val result = runCatching { sut.invoke() } - assertThat(result.isFailure).isTrue() - assert(logoutLambda).isCalledOnce() - } -} diff --git a/features/lockscreen/impl/src/test/kotlin/io/element/android/features/lockscreen/impl/unlock/PinUnlockPresenterTest.kt b/features/lockscreen/impl/src/test/kotlin/io/element/android/features/lockscreen/impl/unlock/PinUnlockPresenterTest.kt index 89d0e92ee2..8299b5a1ab 100644 --- a/features/lockscreen/impl/src/test/kotlin/io/element/android/features/lockscreen/impl/unlock/PinUnlockPresenterTest.kt +++ b/features/lockscreen/impl/src/test/kotlin/io/element/android/features/lockscreen/impl/unlock/PinUnlockPresenterTest.kt @@ -28,7 +28,7 @@ import io.element.android.features.lockscreen.impl.pin.PinCodeManager import io.element.android.features.lockscreen.impl.pin.model.PinEntry import io.element.android.features.lockscreen.impl.pin.model.assertText import io.element.android.features.lockscreen.impl.unlock.keypad.PinKeypadModel -import io.element.android.features.lockscreen.impl.unlock.signout.SignOut +import io.element.android.features.logout.test.FakeLogoutUseCase import io.element.android.libraries.architecture.AsyncData import io.element.android.tests.testutils.lambda.assert import io.element.android.tests.testutils.lambda.lambdaRecorder @@ -106,9 +106,9 @@ class PinUnlockPresenterTest { @Test fun `present - forgot pin flow`() = runTest { - val signOutLambda = lambdaRecorder { null } - val signOut = FakeSignOut(signOutLambda) - val presenter = createPinUnlockPresenter(this, signOut = signOut) + val signOutLambda = lambdaRecorder { "" } + val signOut = FakeLogoutUseCase(signOutLambda) + val presenter = createPinUnlockPresenter(this, logoutUseCase = signOut) moleculeFlow(RecompositionMode.Immediate) { presenter.present() }.test { @@ -135,7 +135,7 @@ class PinUnlockPresenterTest { awaitItem().also { state -> assertThat(state.signOutAction).isInstanceOf(AsyncData.Success::class.java) } - assert(signOutLambda).isCalledOnce().withNoParameter() + assert(signOutLambda).isCalledOnce() } } @@ -147,7 +147,7 @@ class PinUnlockPresenterTest { scope: CoroutineScope, biometricUnlockManager: BiometricUnlockManager = FakeBiometricUnlockManager(), callback: PinCodeManager.Callback = DefaultPinCodeManagerCallback(), - signOut: SignOut = FakeSignOut(), + logoutUseCase: FakeLogoutUseCase = FakeLogoutUseCase(logoutLambda = { "" }), ): PinUnlockPresenter { val pinCodeManager = aPinCodeManager().apply { addCallback(callback) @@ -156,7 +156,7 @@ class PinUnlockPresenterTest { return PinUnlockPresenter( pinCodeManager = pinCodeManager, biometricUnlockManager = biometricUnlockManager, - signOut = signOut, + logoutUseCase = logoutUseCase, coroutineScope = scope, pinUnlockHelper = PinUnlockHelper(biometricUnlockManager, pinCodeManager), ) diff --git a/features/login/impl/src/main/res/values-pl/translations.xml b/features/login/impl/src/main/res/values-pl/translations.xml index 8adfbcb8a8..4d23e15fe8 100644 --- a/features/login/impl/src/main/res/values-pl/translations.xml +++ b/features/login/impl/src/main/res/values-pl/translations.xml @@ -6,7 +6,7 @@ "Szukaj serwera firmowego, społeczności lub prywatnego." "Znajdź dostawcę konta" "Tutaj będą przechowywane Twoje konwersacje - w podobnej formie jak wiadomości widnieją na skrzynce e-mail." - "Zamierzasz się zalogować %s" + "Zamierzasz zalogować się do %s" "Tutaj będą przechowywane Twoje konwersacje - w podobnej formie jak wiadomości widnieją na skrzynce e-mail." "Zamierzasz założyć konto na %s" "Matrix.org jest ogromnym i darmowym serwerem na publicznej sieci Matrix zapewniający bezpieczną i zdecentralizowaną komunikację zarządzaną przez Fundację Matrix.org." @@ -14,20 +14,64 @@ "Użyj innego dostawcy konta, takiego jak własny serwer lub konta służbowego." "Zmień dostawcę konta" "Nie mogliśmy połączyć się z tym serwerem domowym. Sprawdź, czy adres URL serwera został wprowadzony poprawnie. Jeśli adres URL jest poprawny, skontaktuj się z administratorem serwera w celu uzyskania dalszej pomocy." + "Sliding sync nie jest dostępny z powodu problemu w znanym pliku: +%1$s" "Ten serwer obecnie nie obsługuje technologii Sliding Sync." - "Adres URL serwera domowego" + "URL serwera domowego" "Możesz połączyć się tylko z serwerem, który obsługuje technologię Sliding Sync. Administrator serwera domowego będzie musiał ją skonfigurować. %1$s" "Jaki jest adres Twojego serwera?" "Wybierz swój serwer" "To konto zostało dezaktywowane." "Nieprawidłowa nazwa użytkownika i/lub hasło" "To nie jest prawidłowy identyfikator użytkownika. Oczekiwany format: \'@user:homeserver.org\'" + "Ten serwer został skonfigurowany do korzystania z tokenów odświeżania. Nie są one obsługiwane, gdy korzystasz z hasła." "Wybrany serwer domowy nie obsługuje uwierzytelniania hasłem, ani OIDC. Skontaktuj się z jego administratorem lub wybierz inny serwer domowy." "Wprowadź swoje dane" "Matrix to otwarta sieć do bezpiecznej i zdecentralizowanej komunikacji." "Witaj ponownie!" "Zaloguj się do %1$s" + "Nawiązanie bezpiecznego połączenia" + "Nie udało się nawiązać bezpiecznego połączenia z nowym urządzeniem. Twoje istniejące urządzenia są nadal bezpieczne i nie musisz się o nie martwić." + "Co teraz?" + "Spróbuj zalogować się ponownie za pomocą kodu QR, jeśli byłby to problem z siecią" + "Jeśli napotkasz ten sam problem, użyj innej sieci Wi-FI lub danych mobilnych" + "Jeśli to nie zadziała, zaloguj się ręcznie" + "Połączenie nie jest bezpieczne" + "Zostaniesz poproszony o wprowadzenie dwóch cyfr widocznych na tym urządzeniu." + "Wprowadź numer poniżej na innym urządzeniu" + "Zaloguj się na drugie urządzenie lub użyj tego, które jest już zalogowane, a następnie spróbuj ponownie." + "Drugie urządzenie nie jest zalogowane" + "Logowanie zostało anulowane na drugim urządzeniu." + "Prośba o logowanie została anulowana" + "Logowanie zostało odrzucone na drugim urządzeniu." + "Logowanie odrzucone" + "Logowanie wygasło. Spróbuj ponownie." + "Logowanie nie zostało ukończone na czas" + "Twoje drugie urządzenie nie wspiera logowania się do %s za pomocą kodu QR. + +Spróbuj zalogować się ręcznie lub zeskanuj kod QR na innym urządzeniu." + "Kod QR nie jest wspierany" + "Twój dostawca konta nie obsługuje %1$s." + "%1$s nie jest wspierany" + "Gotowy do skanowania" + "Otwórz %1$s na urządzeniu stacjonarnym" + "Kliknij na swój awatar" + "Wybierz %1$s" + "“Powiąż nowe urządzenie”" + "Zeskanuj kod QR za pomocą tego urządzenia" + "Otwórz %1$s na innym urządzeniu, aby uzyskać kod QR" + "Użyj kodu QR widocznego na drugim urządzeniu." "Spróbuj ponownie" + "Błędny kod QR" + "Przejdź do ustawień aparatu" + "Musisz przyznać uprawnienia %1$s do korzystania z kamery, aby kontynuować." + "Zezwól na dostęp do kamery, aby zeskanować kod QR" + "Skanuj kod QR" + "Zacznij od nowa" + "Wystąpił nieoczekiwany błąd. Spróbuj ponownie." + "Oczekiwanie na drugie urządzenie" + "Twój dostawca konta może poprosić o podany kod, aby zweryfikować logowanie." + "Twój kod weryfikacyjny" "Zmień dostawcę konta" "Serwer prywatny dla pracowników Element." "Matrix to otwarta sieć do bezpiecznej i zdecentralizowanej komunikacji." diff --git a/features/login/impl/src/main/res/values-sv/translations.xml b/features/login/impl/src/main/res/values-sv/translations.xml index 0362c6c0d0..d50610adcc 100644 --- a/features/login/impl/src/main/res/values-sv/translations.xml +++ b/features/login/impl/src/main/res/values-sv/translations.xml @@ -30,7 +30,48 @@ "Matrix är ett öppet nätverk för säker, decentraliserad kommunikation." "Välkommen tillbaka!" "Logga in på %1$s" + "Upprättar en säker anslutning" + "En säker anslutning kunde inte göras till den nya enheten. Dina befintliga enheter är fortfarande säkra och du behöver inte oroa dig för dem." + "Nu då?" + "Pröva att logga in igen med en QR-kod ifall detta skulle vara ett nätverksproblem" + "Om du stöter på samma problem, prova ett annat wifi-nätverk eller använd din mobildata istället för wifi" + "Om det inte fungerar, logga in manuellt" + "Anslutningen är inte säker" + "Du kommer att bli ombedd att ange de två siffrorna som visas på den här enheten." + "Ange numret nedan på din andra enhet" + "Logga in på din andra enhet och försök sedan igen, eller använd en annan enhet som redan är inloggad." + "Den andra enheten är inte inloggad" + "Inloggningen avbröts på den andra enheten." + "Inloggningsförfrågan avbröts" + "Inloggningen avvisades på den andra enheten." + "Inloggning avvisad" + "Inloggningen har löpt ut. Vänligen försök igen." + "Inloggningen slutfördes inte i tid" + "Din andra enhet stöder inte inloggning i %s med en QR-kod. + +Prova att logga in manuellt eller skanna QR-koden med en annan enhet." + "QR-kod stöds inte" + "Din kontoleverantör stöder inte %1$s." + "%1$s stöds inte" + "Redo att skanna" + "Öppna %1$s på en skrivbordsenhet" + "Klicka på din avatar" + "Välj %1$s" + "”Länka ny enhet”" + "Skanna QR-koden med den här enheten" + "Öppna %1$s på en annan enhet för att få QR-koden" + "Använd QR-koden som visas på den andra enheten." "Försök igen" + "Fel QR-kod" + "Gå till kamerainställningar" + "Du måste ge tillstånd för %1$s att använda enhetens kamera för att kunna fortsätta." + "Tillåt kameraåtkomst för att skanna QR-koden" + "Skanna QR-koden" + "Börja om" + "Ett oväntat fel inträffade. Vänligen försök igen." + "Väntar på din andra enhet" + "Din kontoleverantör kan be om följande kod för att verifiera inloggningen." + "Din verifieringskod" "Byt kontoleverantör" "En privat server för Element-anställda." "Matrix är ett öppet nätverk för säker, decentraliserad kommunikation." diff --git a/features/login/impl/src/main/res/values-uk/translations.xml b/features/login/impl/src/main/res/values-uk/translations.xml index 1e01a8eba0..9cb6eb1f5f 100644 --- a/features/login/impl/src/main/res/values-uk/translations.xml +++ b/features/login/impl/src/main/res/values-uk/translations.xml @@ -30,7 +30,48 @@ "Matrix — це відкрита мережа для безпечної, децентралізованої комунікації." "З поверненням!" "Увійти в %1$s" + "Встановлення безпечного з\'єднання" + "Не вдалося встановити безпечне з\'єднання з новим пристроєм. Ваші існуючі пристрої все ще в безпеці, і вам не потрібно про них турбуватися." + "Що тепер?" + "Спробуйте увійти ще раз за допомогою QR-коду, якщо це була проблема з мережею" + "Якщо ви зіткнулися з тією ж проблемою, спробуйте іншу мережу Wi-Fi або використовуйте мобільний інтернет замість Wi-Fi" + "Якщо це не спрацює, увійдіть вручну" + "З\'єднання не є безпечним" + "Вас попросять ввести дві цифри, показані на цьому пристрої." + "Введіть номер нижче на іншому пристрої" + "Увійдіть на іншому пристрої та спробуйте ще раз або скористайтеся іншим пристроєм, що вже в обліковому записі." + "Інший пристрій не ввійшов" + "Вхід було скасовано на іншому пристрої." + "Запит на вхід скасовано" + "Вхід був відхилений на іншому пристрої." + "Вхід відхилено" + "Термін входу сплив. Будь ласка, спробуйте ще раз." + "Вхід не було завершено вчасно" + "Ваш інший пристрій не підтримує вхід у %s за допомогою QR-коду. + +Спробуйте ввійти вручну або відскануйте QR-код за допомогою іншого пристрою." + "QR-код не підтримується" + "Постачальник вашого облікового запису не підтримує %1$s." + "%1$s не підтримується" + "Готовий до сканування" + "Відкрийте %1$s на комп\'ютері" + "Натисніть на свою аватарку" + "Оберіть %1$s" + "“Підключити новий пристрій”" + "Відскануйте QR-код цим пристроєм" + "Відкрийте %1$s на іншому пристрої, щоб отримати QR-код" + "Використовуйте QR-код, показаний на іншому пристрої." "Спробуйте ще раз" + "Неправильний QR-код" + "Перейти до налаштувань камери" + "Вам потрібно дати дозвіл %1$s на використання камери вашого пристрою, щоб продовжити." + "Надайте доступ до камери, щоб сканувати QR-код" + "Відскануйте QR-код" + "Почати спочатку" + "Сталася несподівана помилка. Будь ласка, спробуйте ще раз." + "Чекаємо на ваш інший пристрій" + "Постачальник облікового запису може попросити вас ввести код нижче для підтвердження входу." + "Ваш код підтвердження" "Змінити провайдера облікового запису" "Приватний сервер для співробітників Element." "Matrix — це відкрита мережа для безпечної, децентралізованої комунікації." diff --git a/features/login/impl/src/main/res/values-uz/translations.xml b/features/login/impl/src/main/res/values-uz/translations.xml new file mode 100644 index 0000000000..67dc5129d7 --- /dev/null +++ b/features/login/impl/src/main/res/values-uz/translations.xml @@ -0,0 +1,42 @@ + + + "Hisob provayderini o\'zgartiring" + "Uy server manzili" + "Qidiruv so\'zini yoki domen manzilini kiriting." + "Kompaniya, jamoa yoki shaxsiy serverni qidiring." + "Hisob provayderini toping" + "Bu sizning suhbatlaringiz yashaydigan joy - xuddi siz elektron pochta xabarlaringizni saqlash uchun elektron pochta provayderidan foydalanganingiz kabi." + "Siz %sga kirmoqchisiz" + "Bu sizning suhbatlaringiz yashaydigan joy - xuddi siz elektron pochta xabarlaringizni saqlash uchun elektron pochta provayderidan foydalanganingiz kabi." + "Siz %sda hisob yaratmoqchisiz" + "Matrix.org - bu Matrix.org Jamg\'armasi tomonidan boshqariladigan xavfsiz, markazlashtirilmagan aloqa uchun ommaviy Matrix tarmog\'idagi katta, bepul server." + "Boshqa" + "Shaxsiy serveringiz yoki ishchi hisob qaydnomangiz kabi boshqa hisob provayderidan foydalaning." + "Hisob provayderini o\'zgartiring" + "Bu uy serveriga kira olmadik. Iltimos, uy serverining URL manzilini to\'ri kiritganingizni tekshiring. Agar URL toʻgʻri boʻlsa, qoʻshimcha yordam olish uchun uy serveri administratoriga murojaat qiling." + "Hozirda bu server siljish sinxronlashni qo‘llab-quvvatlamaydi." + "Uy serverining URL manzili" + "Siz faqat siljish sinxronlashni qo\'llab-quvvatlaydigan mavjud serverga ulanishingiz mumkin. Uy serveringiz administratori uni sozlashi kerak.%1$s" + "Serveringizning manzili nima?" + "Serveringizni tanlang" + "Bu hisob o‘chirilgan." + "Notog\'ri foydalanuvchi nomi va/yoki parol" + "Bu haqiqiy foydalanuvchi identifikatori emas. Kutilayotgan format: \'@user:homeserver.org\'" + "Tanlangan uy serveri parol yoki OIDC loginni qo\'lab-quvvatlamaydi. Iltimos, administratoringizga murojaat qiling yoki boshqa uy serverini tanlang." + "Tafsilotlaringizni kiriting" + "Matrix xavfsiz, markazlashmagan aloqa uchun ochiq tarmoqdir." + "Qaytib kelganingizdan xursandmiz!" + "Kirish%1$s" + "Hisob provayderini o\'zgartiring" + "Element xodimlari uchun shaxsiy server." + "Matrix xavfsiz, markazlashmagan aloqa uchun ochiq tarmoqdir." + "Bu sizning suhbatlaringiz yashaydigan joy - xuddi siz elektron pochta xabarlaringizni saqlash uchun elektron pochta provayderidan foydalanganingiz kabi." + "Siz tizimga kirmoqchisiz%1$s" + "Hisob yaratmoqchisiz%1$s" + "Hozirgi paytda %2$sga %1$sda talab yuqori. Bir necha kundan keyin ilovaga qayting va qaytadan urining. + +Sabr-toqatingiz uchun rahmat!" + "%1$sga Xush kelibsiz!" + "Siz deyarli keldingiz." + "Siz kirdingiz." + diff --git a/features/logout/api/src/main/kotlin/io/element/android/features/logout/api/LogoutUseCase.kt b/features/logout/api/src/main/kotlin/io/element/android/features/logout/api/LogoutUseCase.kt new file mode 100644 index 0000000000..a06b7117b1 --- /dev/null +++ b/features/logout/api/src/main/kotlin/io/element/android/features/logout/api/LogoutUseCase.kt @@ -0,0 +1,33 @@ +/* + * 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 + * + * https://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.logout.api + +/** + * Used to trigger a log out of the current user from any part of the app. + */ +interface LogoutUseCase { + /** + * Log out the current user and then perform any needed cleanup tasks. + * @param ignoreSdkError if true, the SDK error will be ignored and the user will be logged out anyway. + * @return the session id of the logged out user. + */ + suspend fun logout(ignoreSdkError: Boolean): String + + interface Factory { + fun create(sessionId: String): LogoutUseCase + } +} diff --git a/features/logout/impl/src/main/kotlin/io/element/android/features/logout/impl/DefaultLogoutUseCase.kt b/features/logout/impl/src/main/kotlin/io/element/android/features/logout/impl/DefaultLogoutUseCase.kt new file mode 100644 index 0000000000..8e5f08a87a --- /dev/null +++ b/features/logout/impl/src/main/kotlin/io/element/android/features/logout/impl/DefaultLogoutUseCase.kt @@ -0,0 +1,43 @@ +/* + * 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 + * + * https://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.logout.impl + +import com.squareup.anvil.annotations.ContributesBinding +import dagger.assisted.Assisted +import dagger.assisted.AssistedFactory +import dagger.assisted.AssistedInject +import io.element.android.features.logout.api.LogoutUseCase +import io.element.android.libraries.di.AppScope +import io.element.android.libraries.matrix.api.MatrixClientProvider +import io.element.android.libraries.matrix.api.core.SessionId + +class DefaultLogoutUseCase @AssistedInject constructor( + @Assisted private val sessionId: String, + private val matrixClientProvider: MatrixClientProvider, +) : LogoutUseCase { + @ContributesBinding(AppScope::class) + @AssistedFactory + interface Factory : LogoutUseCase.Factory { + override fun create(sessionId: String): DefaultLogoutUseCase + } + + override suspend fun logout(ignoreSdkError: Boolean): String { + val matrixClient = matrixClientProvider.getOrRestore(SessionId(sessionId)).getOrThrow() + matrixClient.logout(ignoreSdkError = ignoreSdkError) + return sessionId + } +} diff --git a/features/logout/impl/src/main/kotlin/io/element/android/features/logout/impl/SessionLogoutModule.kt b/features/logout/impl/src/main/kotlin/io/element/android/features/logout/impl/SessionLogoutModule.kt new file mode 100644 index 0000000000..ec725a34a6 --- /dev/null +++ b/features/logout/impl/src/main/kotlin/io/element/android/features/logout/impl/SessionLogoutModule.kt @@ -0,0 +1,36 @@ +/* + * 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 + * + * https://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.logout.impl + +import com.squareup.anvil.annotations.ContributesTo +import dagger.Module +import dagger.Provides +import io.element.android.features.logout.api.LogoutUseCase +import io.element.android.libraries.di.SessionScope +import io.element.android.libraries.matrix.api.user.CurrentSessionIdHolder + +@Module +@ContributesTo(SessionScope::class) +object SessionLogoutModule { + @Provides + fun provideLogoutUseCase( + currentSessionIdHolder: CurrentSessionIdHolder, + factory: DefaultLogoutUseCase.Factory, + ): LogoutUseCase { + return factory.create(currentSessionIdHolder.current.value) + } +} diff --git a/features/logout/impl/src/main/res/values-pt-rBR/translations.xml b/features/logout/impl/src/main/res/values-pt-rBR/translations.xml index 65ccf4ca6f..7d77b477ad 100644 --- a/features/logout/impl/src/main/res/values-pt-rBR/translations.xml +++ b/features/logout/impl/src/main/res/values-pt-rBR/translations.xml @@ -4,5 +4,9 @@ "Sair" "Sair" "Saindo…" + "Você desativou o backup" + "O backup das suas chaves ainda está em andamento" "Sair" + "A recuperação não está configurada" + "Você salvou sua chave de recuperação?" diff --git a/features/logout/impl/src/main/res/values-uz/translations.xml b/features/logout/impl/src/main/res/values-uz/translations.xml new file mode 100644 index 0000000000..24da45d63b --- /dev/null +++ b/features/logout/impl/src/main/res/values-uz/translations.xml @@ -0,0 +1,8 @@ + + + "Haqiqatan ham tizimdan chiqmoqchimisiz?" + "Tizimdan chiqish" + "Tizimdan chiqish" + "Chiqish…" + "Tizimdan chiqish" + diff --git a/features/lockscreen/impl/src/test/kotlin/io/element/android/features/lockscreen/impl/unlock/FakeSignOut.kt b/features/logout/test/build.gradle.kts similarity index 58% rename from features/lockscreen/impl/src/test/kotlin/io/element/android/features/lockscreen/impl/unlock/FakeSignOut.kt rename to features/logout/test/build.gradle.kts index 883a5bf97b..7be20ef279 100644 --- a/features/lockscreen/impl/src/test/kotlin/io/element/android/features/lockscreen/impl/unlock/FakeSignOut.kt +++ b/features/logout/test/build.gradle.kts @@ -5,7 +5,7 @@ * 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 + * https://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, @@ -14,15 +14,16 @@ * limitations under the License. */ -package io.element.android.features.lockscreen.impl.unlock - -import io.element.android.features.lockscreen.impl.unlock.signout.SignOut -import io.element.android.tests.testutils.simulateLongTask - -class FakeSignOut( - var lambda: () -> String? = { null } -) : SignOut { - override suspend fun invoke(): String? = simulateLongTask { - lambda() - } +plugins { + id("io.element.android-library") +} + +android { + namespace = "io.element.android.features.logout.test" +} + +dependencies { + implementation(libs.coroutines.core) + implementation(projects.tests.testutils) + api(projects.features.logout.api) } diff --git a/features/logout/test/src/main/kotlin/io/element/android/features/logout/test/FakeLogoutUseCase.kt b/features/logout/test/src/main/kotlin/io/element/android/features/logout/test/FakeLogoutUseCase.kt new file mode 100644 index 0000000000..bbc67765d1 --- /dev/null +++ b/features/logout/test/src/main/kotlin/io/element/android/features/logout/test/FakeLogoutUseCase.kt @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2024 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://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.logout.test + +import io.element.android.features.logout.api.LogoutUseCase +import io.element.android.tests.testutils.lambda.lambdaError + +class FakeLogoutUseCase( + var logoutLambda: (Boolean) -> String = lambdaError() +) : LogoutUseCase { + override suspend fun logout(ignoreSdkError: Boolean): String { + return logoutLambda(ignoreSdkError) + } +} diff --git a/features/messages/impl/build.gradle.kts b/features/messages/impl/build.gradle.kts index 781a42b2fb..c1d3067510 100644 --- a/features/messages/impl/build.gradle.kts +++ b/features/messages/impl/build.gradle.kts @@ -102,5 +102,6 @@ dependencies { testImplementation(projects.features.poll.test) testImplementation(projects.features.poll.impl) testImplementation(libs.androidx.compose.ui.test.junit) + testImplementation(projects.libraries.eventformatter.test) testReleaseImplementation(libs.androidx.compose.ui.test.manifest) } diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/ExpandableBottomSheetScaffold.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/ExpandableBottomSheetScaffold.kt index 3d61d43063..29bea5ca9e 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/ExpandableBottomSheetScaffold.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/ExpandableBottomSheetScaffold.kt @@ -58,7 +58,11 @@ import kotlin.math.roundToInt * @param modifier The modifier for the layout. * @param sheetContentKey The key for the sheet content. If the key changes, the sheet will be remeasured. */ -@Suppress("ContentTrailingLambda") +@Suppress( + "ContentTrailingLambda", + // False positive + "MultipleEmitters", +) @OptIn(ExperimentalMaterial3Api::class) @Composable internal fun ExpandableBottomSheetScaffold( diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesFlowNode.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesFlowNode.kt index 4fd59be6cb..f022fd0caf 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesFlowNode.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesFlowNode.kt @@ -81,6 +81,7 @@ import kotlinx.collections.immutable.ImmutableList import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach import kotlinx.parcelize.Parcelize +import timber.log.Timber @ContributesNode(RoomScope::class) class MessagesFlowNode @AssistedInject constructor( @@ -217,6 +218,10 @@ class MessagesFlowNode @AssistedInject constructor( analyticsService.captureInteraction(Interaction.Name.MobileRoomCallButton) elementCallEntryPoint.startCall(callType) } + + override fun onViewAllPinnedEvents() { + Timber.d("On View All Pinned Events not implemented yet.") + } } val inputs = MessagesNode.Inputs( focusedEventId = inputs.focusedEventId, diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesNode.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesNode.kt index b2ee1053a6..d722a5b7a0 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesNode.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesNode.kt @@ -97,6 +97,7 @@ class MessagesNode @AssistedInject constructor( fun onCreatePollClick() fun onEditPollClick(eventId: EventId) fun onJoinCallClick(roomId: RoomId) + fun onViewAllPinnedEvents() } override fun onBuilt() { @@ -185,6 +186,10 @@ class MessagesNode @AssistedInject constructor( callbacks.forEach { it.onEditPollClick(eventId) } } + private fun onViewAllPinnedMessagesClick() { + callbacks.forEach { it.onViewAllPinnedEvents() } + } + private fun onSendLocationClick() { callbacks.forEach { it.onSendLocationClick() } } @@ -221,6 +226,7 @@ class MessagesNode @AssistedInject constructor( onSendLocationClick = this::onSendLocationClick, onCreatePollClick = this::onCreatePollClick, onJoinCallClick = this::onJoinCallClick, + onViewAllPinnedMessagesClick = this::onViewAllPinnedMessagesClick, modifier = modifier, ) 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 b13a95d4f2..c17ac1035b 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 @@ -20,10 +20,12 @@ import android.os.Build import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.MutableState +import androidx.compose.runtime.State 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 @@ -39,6 +41,7 @@ import io.element.android.features.messages.impl.actionlist.model.TimelineItemAc 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.messages.impl.pinned.banner.PinnedMessagesBannerState import io.element.android.features.messages.impl.timeline.TimelineController import io.element.android.features.messages.impl.timeline.TimelineEvents import io.element.android.features.messages.impl.timeline.TimelinePresenter @@ -73,12 +76,13 @@ import io.element.android.libraries.matrix.api.room.MatrixRoomInfo import io.element.android.libraries.matrix.api.room.MatrixRoomMembersState import io.element.android.libraries.matrix.api.room.MessageEventType import io.element.android.libraries.matrix.api.room.isDm +import io.element.android.libraries.matrix.api.room.powerlevels.canPinUnpin +import io.element.android.libraries.matrix.api.room.powerlevels.canRedactOther +import io.element.android.libraries.matrix.api.room.powerlevels.canRedactOwn +import io.element.android.libraries.matrix.api.room.powerlevels.canSendMessage import io.element.android.libraries.matrix.ui.messages.reply.map import io.element.android.libraries.matrix.ui.model.getAvatarData import io.element.android.libraries.matrix.ui.room.canCall -import io.element.android.libraries.matrix.ui.room.canRedactOtherAsState -import io.element.android.libraries.matrix.ui.room.canRedactOwnAsState -import io.element.android.libraries.matrix.ui.room.canSendMessageAsState import io.element.android.libraries.textcomposer.model.MessageComposerMode import io.element.android.libraries.ui.strings.CommonStrings import kotlinx.collections.immutable.toPersistentList @@ -98,6 +102,7 @@ class MessagesPresenter @AssistedInject constructor( private val customReactionPresenter: CustomReactionPresenter, private val reactionSummaryPresenter: ReactionSummaryPresenter, private val readReceiptBottomSheetPresenter: ReadReceiptBottomSheetPresenter, + private val pinnedMessagesBannerPresenter: Presenter, private val networkMonitor: NetworkMonitor, private val snackbarDispatcher: SnackbarDispatcher, private val dispatchers: CoroutineDispatchers, @@ -129,12 +134,12 @@ class MessagesPresenter @AssistedInject constructor( val customReactionState = customReactionPresenter.present() val reactionSummaryState = reactionSummaryPresenter.present() val readReceiptBottomSheetState = readReceiptBottomSheetPresenter.present() + val pinnedMessagesBannerState = pinnedMessagesBannerPresenter.present() val syncUpdateFlow = room.syncUpdateFlow.collectAsState() - 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, updateKey = syncUpdateFlow.value) + + val userEventPermissions by userEventPermissions(syncUpdateFlow.value) + val roomName: AsyncData by remember { derivedStateOf { roomInfo?.name?.let { AsyncData.Success(it) } ?: AsyncData.Uninitialized } } @@ -211,11 +216,8 @@ class MessagesPresenter @AssistedInject constructor( roomName = roomName, roomAvatar = roomAvatar, heroes = heroes, - userHasPermissionToSendMessage = userHasPermissionToSendMessage, - userHasPermissionToRedactOwn = userHasPermissionToRedactOwn, - userHasPermissionToRedactOther = userHasPermissionToRedactOther, - userHasPermissionToSendReaction = userHasPermissionToSendReaction, composerState = composerState, + userEventPermissions = userEventPermissions, voiceMessageComposerState = voiceMessageComposerState, timelineState = timelineState, typingNotificationState = typingNotificationState, @@ -231,10 +233,24 @@ class MessagesPresenter @AssistedInject constructor( enableVoiceMessages = enableVoiceMessages, appName = buildMeta.applicationName, callState = callState, + pinnedMessagesBannerState = pinnedMessagesBannerState, eventSink = { handleEvents(it) } ) } + @Composable + private fun userEventPermissions(updateKey: Long): State { + return produceState(UserEventPermissions.DEFAULT, key1 = updateKey) { + value = UserEventPermissions( + canSendMessage = room.canSendMessage(type = MessageEventType.ROOM_MESSAGE).getOrElse { true }, + canSendReaction = room.canSendMessage(type = MessageEventType.REACTION).getOrElse { true }, + canRedactOwn = room.canRedactOwn().getOrElse { false }, + canRedactOther = room.canRedactOther().getOrElse { false }, + canPinUnpin = room.canPinUnpin().getOrElse { false }, + ) + } + } + private fun MatrixRoomInfo.avatarData(): AvatarData { return AvatarData( id = id.value, @@ -268,6 +284,30 @@ class MessagesPresenter @AssistedInject constructor( TimelineItemAction.Forward -> handleForwardAction(targetEvent) TimelineItemAction.ReportContent -> handleReportAction(targetEvent) TimelineItemAction.EndPoll -> handleEndPollAction(targetEvent, timelineState) + TimelineItemAction.Pin -> handlePinAction(targetEvent) + TimelineItemAction.Unpin -> handleUnpinAction(targetEvent) + } + } + + private suspend fun handlePinAction(targetEvent: TimelineItem.Event) { + if (targetEvent.eventId == null) return + timelineController.invokeOnCurrentTimeline { + pinEvent(targetEvent.eventId) + .onFailure { + Timber.e(it, "Failed to pin event ${targetEvent.eventId}") + snackbarDispatcher.post(SnackbarMessage(CommonStrings.common_error)) + } + } + } + + private suspend fun handleUnpinAction(targetEvent: TimelineItem.Event) { + if (targetEvent.eventId == null) return + timelineController.invokeOnCurrentTimeline { + unpinEvent(targetEvent.eventId) + .onFailure { + Timber.e(it, "Failed to unpin event ${targetEvent.eventId}") + snackbarDispatcher.post(SnackbarMessage(CommonStrings.common_error)) + } } } 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 e8657d70bd..172111e862 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 @@ -19,6 +19,7 @@ package io.element.android.features.messages.impl import androidx.compose.runtime.Immutable import io.element.android.features.messages.impl.actionlist.ActionListState import io.element.android.features.messages.impl.messagecomposer.MessageComposerState +import io.element.android.features.messages.impl.pinned.banner.PinnedMessagesBannerState import io.element.android.features.messages.impl.timeline.TimelineState import io.element.android.features.messages.impl.timeline.components.customreaction.CustomReactionState import io.element.android.features.messages.impl.timeline.components.reactionsummary.ReactionSummaryState @@ -37,10 +38,7 @@ data class MessagesState( val roomName: AsyncData, val roomAvatar: AsyncData, val heroes: ImmutableList, - val userHasPermissionToSendMessage: Boolean, - val userHasPermissionToRedactOwn: Boolean, - val userHasPermissionToRedactOther: Boolean, - val userHasPermissionToSendReaction: Boolean, + val userEventPermissions: UserEventPermissions, val composerState: MessageComposerState, val voiceMessageComposerState: VoiceMessageComposerState, val timelineState: TimelineState, @@ -57,6 +55,7 @@ data class MessagesState( val enableVoiceMessages: Boolean, val callState: RoomCallState, val appName: String, + val pinnedMessagesBannerState: PinnedMessagesBannerState, val eventSink: (MessagesEvents) -> Unit ) 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 1396d3e17c..97436c2bc0 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 @@ -22,6 +22,8 @@ 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.pinned.banner.PinnedMessagesBannerState +import io.element.android.features.messages.impl.pinned.banner.aLoadedPinnedMessagesBannerState import io.element.android.features.messages.impl.timeline.TimelineState import io.element.android.features.messages.impl.timeline.aTimelineItemList import io.element.android.features.messages.impl.timeline.aTimelineState @@ -53,7 +55,7 @@ open class MessagesStateProvider : PreviewParameterProvider { aMessagesState(), aMessagesState(hasNetworkConnection = false), aMessagesState(composerState = aMessageComposerState(showAttachmentSourcePicker = true)), - aMessagesState(userHasPermissionToSendMessage = false), + aMessagesState(userEventPermissions = aUserEventPermissions(canSendMessage = false)), aMessagesState(showReinvitePrompt = true), aMessagesState( roomName = AsyncData.Uninitialized, @@ -87,16 +89,19 @@ open class MessagesStateProvider : PreviewParameterProvider { aMessagesState( callState = RoomCallState.DISABLED, ), + aMessagesState( + pinnedMessagesBannerState = aLoadedPinnedMessagesBannerState( + knownPinnedMessagesCount = 4, + currentPinnedMessageIndex = 0, + ), + ), ) } fun aMessagesState( roomName: AsyncData = AsyncData.Success("Room name"), roomAvatar: AsyncData = AsyncData.Success(AvatarData("!id:domain", "Room name", size = AvatarSize.TimelineRoom)), - userHasPermissionToSendMessage: Boolean = true, - userHasPermissionToRedactOwn: Boolean = false, - userHasPermissionToRedactOther: Boolean = false, - userHasPermissionToSendReaction: Boolean = true, + userEventPermissions: UserEventPermissions = aUserEventPermissions(), composerState: MessageComposerState = aMessageComposerState( textEditorState = TextEditorState.Rich(aRichTextEditorState(initialText = "Hello", initialFocus = true)), isFullScreen = false, @@ -116,16 +121,14 @@ fun aMessagesState( showReinvitePrompt: Boolean = false, enableVoiceMessages: Boolean = true, callState: RoomCallState = RoomCallState.ENABLED, + pinnedMessagesBannerState: PinnedMessagesBannerState = aLoadedPinnedMessagesBannerState(), eventSink: (MessagesEvents) -> Unit = {}, ) = MessagesState( roomId = RoomId("!id:domain"), roomName = roomName, roomAvatar = roomAvatar, heroes = persistentListOf(), - userHasPermissionToSendMessage = userHasPermissionToSendMessage, - userHasPermissionToRedactOwn = userHasPermissionToRedactOwn, - userHasPermissionToRedactOther = userHasPermissionToRedactOther, - userHasPermissionToSendReaction = userHasPermissionToSendReaction, + userEventPermissions = userEventPermissions, composerState = composerState, voiceMessageComposerState = voiceMessageComposerState, typingNotificationState = aTypingNotificationState(), @@ -142,9 +145,24 @@ fun aMessagesState( enableVoiceMessages = enableVoiceMessages, callState = callState, appName = "Element", + pinnedMessagesBannerState = pinnedMessagesBannerState, eventSink = eventSink, ) +fun aUserEventPermissions( + canRedactOwn: Boolean = false, + canRedactOther: Boolean = false, + canSendMessage: Boolean = true, + canSendReaction: Boolean = true, + canPinUnpin: Boolean = false, +) = UserEventPermissions( + canRedactOwn = canRedactOwn, + canRedactOther = canRedactOther, + canSendMessage = canSendMessage, + canSendReaction = canSendReaction, + canPinUnpin = canPinUnpin, +) + fun aReactionSummaryState( target: ReactionSummaryState.Summary? = null, eventSink: (ReactionSummaryEvents) -> Unit = {} 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 24439c0c75..df6aa26778 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 @@ -16,6 +16,9 @@ package io.element.android.features.messages.impl +import androidx.compose.animation.AnimatedVisibility +import androidx.compose.animation.expandVertically +import androidx.compose.animation.shrinkVertically import androidx.compose.foundation.background import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Arrangement @@ -68,6 +71,11 @@ import io.element.android.features.messages.impl.messagecomposer.AttachmentsBott import io.element.android.features.messages.impl.messagecomposer.AttachmentsState import io.element.android.features.messages.impl.messagecomposer.MessageComposerEvents import io.element.android.features.messages.impl.messagecomposer.MessageComposerView +import io.element.android.features.messages.impl.pinned.banner.PinnedMessagesBannerState +import io.element.android.features.messages.impl.pinned.banner.PinnedMessagesBannerView +import io.element.android.features.messages.impl.pinned.banner.PinnedMessagesBannerViewDefaults +import io.element.android.features.messages.impl.timeline.FOCUS_ON_PINNED_EVENT_DEBOUNCE_DURATION_IN_MILLIS +import io.element.android.features.messages.impl.timeline.TimelineEvents import io.element.android.features.messages.impl.timeline.TimelineView import io.element.android.features.messages.impl.timeline.components.JoinCallMenuItem import io.element.android.features.messages.impl.timeline.components.customreaction.CustomReactionBottomSheet @@ -102,11 +110,13 @@ import io.element.android.libraries.designsystem.utils.KeepScreenOn 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 +import io.element.android.libraries.matrix.api.core.EventId import io.element.android.libraries.matrix.api.core.UserId import io.element.android.libraries.ui.strings.CommonStrings import kotlinx.collections.immutable.ImmutableList import timber.log.Timber import kotlin.random.Random +import kotlin.time.Duration.Companion.milliseconds @Composable fun MessagesView( @@ -120,8 +130,9 @@ fun MessagesView( onSendLocationClick: () -> Unit, onCreatePollClick: () -> Unit, onJoinCallClick: () -> Unit, + onViewAllPinnedMessagesClick: () -> Unit, modifier: Modifier = Modifier, - forceJumpToBottomVisibility: Boolean = false + forceJumpToBottomVisibility: Boolean = false, ) { OnLifecycleEvent { _, event -> state.voiceMessageComposerState.eventSink(VoiceMessageComposerEvents.LifecycleEvent(event)) @@ -154,10 +165,7 @@ fun MessagesView( state.actionListState.eventSink( ActionListEvents.ComputeForMessage( event = event, - canRedactOwn = state.userHasPermissionToRedactOwn, - canRedactOther = state.userHasPermissionToRedactOther, - canSendMessage = state.userHasPermissionToSendMessage, - canSendReaction = state.userHasPermissionToSendReaction, + userEventPermissions = state.userEventPermissions, ) ) } @@ -225,6 +233,7 @@ fun MessagesView( }, forceJumpToBottomVisibility = forceJumpToBottomVisibility, onJoinCallClick = onJoinCallClick, + onViewAllPinnedMessagesClick = onViewAllPinnedMessagesClick, ) }, snackbarHost = { @@ -316,6 +325,7 @@ private fun MessagesViewContent( onSendLocationClick: () -> Unit, onCreatePollClick: () -> Unit, onJoinCallClick: () -> Unit, + onViewAllPinnedMessagesClick: () -> Unit, forceJumpToBottomVisibility: Boolean, modifier: Modifier = Modifier, onSwipeToReply: (TimelineItem.Event) -> Unit, @@ -373,22 +383,41 @@ private fun MessagesViewContent( RectangleShape }, content = { paddingValues -> - TimelineView( - state = state.timelineState, - typingNotificationState = state.typingNotificationState, - onUserDataClick = onUserDataClick, - onLinkClick = onLinkClick, - onMessageClick = onMessageClick, - onMessageLongClick = onMessageLongClick, - onSwipeToReply = onSwipeToReply, - onReactionClick = onReactionClick, - onReactionLongClick = onReactionLongClick, - onMoreReactionsClick = onMoreReactionsClick, - onReadReceiptClick = onReadReceiptClick, - modifier = Modifier.padding(paddingValues), - forceJumpToBottomVisibility = forceJumpToBottomVisibility, - onJoinCallClick = onJoinCallClick, - ) + Box(modifier = Modifier.padding(paddingValues)) { + val scrollBehavior = PinnedMessagesBannerViewDefaults.rememberExitOnScrollBehavior() + TimelineView( + state = state.timelineState, + typingNotificationState = state.typingNotificationState, + onUserDataClick = onUserDataClick, + onLinkClick = onLinkClick, + onMessageClick = onMessageClick, + onMessageLongClick = onMessageLongClick, + onSwipeToReply = onSwipeToReply, + onReactionClick = onReactionClick, + onReactionLongClick = onReactionLongClick, + onMoreReactionsClick = onMoreReactionsClick, + onReadReceiptClick = onReadReceiptClick, + forceJumpToBottomVisibility = forceJumpToBottomVisibility, + onJoinCallClick = onJoinCallClick, + nestedScrollConnection = scrollBehavior.nestedScrollConnection, + ) + AnimatedVisibility( + visible = state.pinnedMessagesBannerState is PinnedMessagesBannerState.Visible && scrollBehavior.isVisible, + enter = expandVertically(), + exit = shrinkVertically(), + ) { + fun focusOnPinnedEvent(eventId: EventId) { + state.timelineState.eventSink( + TimelineEvents.FocusOnEvent(eventId = eventId, debounce = FOCUS_ON_PINNED_EVENT_DEBOUNCE_DURATION_IN_MILLIS.milliseconds) + ) + } + PinnedMessagesBannerView( + state = state.pinnedMessagesBannerState, + onClick = ::focusOnPinnedEvent, + onViewAllClick = onViewAllPinnedMessagesClick, + ) + } + } }, sheetContent = { subcomposing: Boolean -> MessagesViewComposerBottomSheetContents( @@ -408,7 +437,7 @@ private fun MessagesViewComposerBottomSheetContents( subcomposing: Boolean, state: MessagesState, ) { - if (state.userHasPermissionToSendMessage) { + if (state.userEventPermissions.canSendMessage) { Column(modifier = Modifier.fillMaxWidth()) { MentionSuggestionsPickerView( modifier = Modifier @@ -557,12 +586,13 @@ internal fun MessagesViewPreview(@PreviewParameter(MessagesStateProvider::class) onBackClick = {}, onRoomDetailsClick = {}, onEventClick = { false }, - onPreviewAttachments = {}, onUserDataClick = {}, onLinkClick = {}, + onPreviewAttachments = {}, onSendLocationClick = {}, onCreatePollClick = {}, onJoinCallClick = {}, + onViewAllPinnedMessagesClick = { }, forceJumpToBottomVisibility = true, ) } diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/UserEventPermissions.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/UserEventPermissions.kt new file mode 100644 index 0000000000..77a24b8c5d --- /dev/null +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/UserEventPermissions.kt @@ -0,0 +1,39 @@ +/* + * 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 + * + * https://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 + +/** + * Represents the permissions a user has in a room. + * It's dependent of the user's power level in the room. + */ +data class UserEventPermissions( + val canRedactOwn: Boolean, + val canRedactOther: Boolean, + val canSendMessage: Boolean, + val canSendReaction: Boolean, + val canPinUnpin: Boolean, +) { + companion object { + val DEFAULT = UserEventPermissions( + canRedactOwn = false, + canRedactOther = false, + canSendMessage = true, + canSendReaction = true, + canPinUnpin = false + ) + } +} diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/actionlist/ActionListEvents.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/actionlist/ActionListEvents.kt index e486c1ae2b..407d18afb7 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/actionlist/ActionListEvents.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/actionlist/ActionListEvents.kt @@ -16,15 +16,13 @@ package io.element.android.features.messages.impl.actionlist +import io.element.android.features.messages.impl.UserEventPermissions import io.element.android.features.messages.impl.timeline.model.TimelineItem sealed interface ActionListEvents { data object Clear : ActionListEvents data class ComputeForMessage( val event: TimelineItem.Event, - val canRedactOwn: Boolean, - val canRedactOther: Boolean, - val canSendMessage: Boolean, - val canSendReaction: Boolean, + val userEventPermissions: UserEventPermissions, ) : ActionListEvents } diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/actionlist/ActionListPresenter.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/actionlist/ActionListPresenter.kt index d1a19b600d..124f4e911d 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/actionlist/ActionListPresenter.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/actionlist/ActionListPresenter.kt @@ -23,25 +23,36 @@ import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope +import io.element.android.features.messages.impl.UserEventPermissions import io.element.android.features.messages.impl.actionlist.model.TimelineItemAction import io.element.android.features.messages.impl.timeline.model.TimelineItem import io.element.android.features.messages.impl.timeline.model.event.TimelineItemCallNotifyContent +import io.element.android.features.messages.impl.timeline.model.event.TimelineItemEventContent import io.element.android.features.messages.impl.timeline.model.event.TimelineItemLegacyCallInviteContent import io.element.android.features.messages.impl.timeline.model.event.TimelineItemPollContent import io.element.android.features.messages.impl.timeline.model.event.TimelineItemRedactedContent import io.element.android.features.messages.impl.timeline.model.event.TimelineItemStateContent -import io.element.android.features.messages.impl.timeline.model.event.TimelineItemVoiceContent import io.element.android.features.messages.impl.timeline.model.event.canBeCopied +import io.element.android.features.messages.impl.timeline.model.event.canBeForwarded import io.element.android.features.messages.impl.timeline.model.event.canReact import io.element.android.libraries.architecture.Presenter +import io.element.android.libraries.featureflag.api.FeatureFlagService +import io.element.android.libraries.featureflag.api.FeatureFlags +import io.element.android.libraries.matrix.api.core.EventId +import io.element.android.libraries.matrix.api.room.MatrixRoom import io.element.android.libraries.preferences.api.store.AppPreferencesStore +import kotlinx.collections.immutable.ImmutableList +import kotlinx.collections.immutable.persistentListOf import kotlinx.collections.immutable.toImmutableList import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.flow.map import kotlinx.coroutines.launch import javax.inject.Inject class ActionListPresenter @Inject constructor( private val appPreferencesStore: AppPreferencesStore, + private val featureFlagsService: FeatureFlagService, + private val room: MatrixRoom, ) : Presenter { @Composable override fun present(): ActionListState { @@ -52,17 +63,20 @@ class ActionListPresenter @Inject constructor( } val isDeveloperModeEnabled by appPreferencesStore.isDeveloperModeEnabledFlow().collectAsState(initial = false) + val isPinnedEventsEnabled by featureFlagsService.isFeatureEnabledFlow(FeatureFlags.PinnedEvents).collectAsState(initial = false) + val pinnedEventIds by remember { + room.roomInfoFlow.map { it.pinnedEventIds } + }.collectAsState(initial = persistentListOf()) fun handleEvents(event: ActionListEvents) { when (event) { ActionListEvents.Clear -> target.value = ActionListState.Target.None is ActionListEvents.ComputeForMessage -> localCoroutineScope.computeForMessage( timelineItem = event.event, - userCanRedactOwn = event.canRedactOwn, - userCanRedactOther = event.canRedactOther, - userCanSendMessage = event.canSendMessage, - userCanSendReaction = event.canSendReaction, + usersEventPermissions = event.userEventPermissions, isDeveloperModeEnabled = isDeveloperModeEnabled, + isPinnedEventsEnabled = isPinnedEventsEnabled, + pinnedEventIds = pinnedEventIds, target = target, ) } @@ -76,136 +90,22 @@ class ActionListPresenter @Inject constructor( private fun CoroutineScope.computeForMessage( timelineItem: TimelineItem.Event, - userCanRedactOwn: Boolean, - userCanRedactOther: Boolean, - userCanSendMessage: Boolean, - userCanSendReaction: Boolean, + usersEventPermissions: UserEventPermissions, isDeveloperModeEnabled: Boolean, + isPinnedEventsEnabled: Boolean, + pinnedEventIds: ImmutableList, target: MutableState ) = launch { target.value = ActionListState.Target.Loading(timelineItem) - val canRedact = timelineItem.isMine && userCanRedactOwn || !timelineItem.isMine && userCanRedactOther - val actions = - when (timelineItem.content) { - is TimelineItemCallNotifyContent -> { - if (isDeveloperModeEnabled) { - listOf(TimelineItemAction.ViewSource) - } else { - emptyList() - } - } - is TimelineItemRedactedContent -> { - if (isDeveloperModeEnabled) { - listOf(TimelineItemAction.ViewSource) - } else { - emptyList() - } - } - is TimelineItemStateContent -> { - buildList { - add(TimelineItemAction.Copy) - if (timelineItem.isRemote) { - add(TimelineItemAction.CopyLink) - } - if (isDeveloperModeEnabled) { - add(TimelineItemAction.ViewSource) - } - } - } - is TimelineItemPollContent -> { - val canEndPoll = timelineItem.isRemote && - !timelineItem.content.isEnded && - (timelineItem.isMine || canRedact) - buildList { - if (timelineItem.isRemote) { - // Can only reply or forward messages already uploaded to the server - add(TimelineItemAction.Reply) - } - if (timelineItem.isRemote && timelineItem.isEditable) { - add(TimelineItemAction.Edit) - } - if (canEndPoll) { - add(TimelineItemAction.EndPoll) - } - if (timelineItem.content.canBeCopied()) { - add(TimelineItemAction.Copy) - } - if (timelineItem.isRemote) { - add(TimelineItemAction.CopyLink) - } - if (isDeveloperModeEnabled) { - add(TimelineItemAction.ViewSource) - } - if (!timelineItem.isMine) { - add(TimelineItemAction.ReportContent) - } - if (canRedact) { - add(TimelineItemAction.Redact) - } - } - } - is TimelineItemVoiceContent -> { - buildList { - if (timelineItem.isRemote) { - add(TimelineItemAction.Reply) - add(TimelineItemAction.Forward) - add(TimelineItemAction.CopyLink) - } - if (isDeveloperModeEnabled) { - add(TimelineItemAction.ViewSource) - } - if (!timelineItem.isMine) { - add(TimelineItemAction.ReportContent) - } - if (canRedact) { - add(TimelineItemAction.Redact) - } - } - } - is TimelineItemLegacyCallInviteContent -> { - buildList { - if (isDeveloperModeEnabled) { - add(TimelineItemAction.ViewSource) - } - } - } - else -> buildList { - if (timelineItem.isRemote) { - // Can only reply or forward messages already uploaded to the server - if (userCanSendMessage) { - if (timelineItem.isThreaded) { - add(TimelineItemAction.ReplyInThread) - } else { - add(TimelineItemAction.Reply) - } - } - // Stickers can't be forwarded (yet) so we don't show the option - // See https://github.com/element-hq/element-x-android/issues/2161 - if (!timelineItem.isSticker) { - add(TimelineItemAction.Forward) - } - } - if (timelineItem.isEditable) { - add(TimelineItemAction.Edit) - } - if (timelineItem.content.canBeCopied()) { - add(TimelineItemAction.Copy) - } - if (timelineItem.isRemote) { - add(TimelineItemAction.CopyLink) - } - if (isDeveloperModeEnabled) { - add(TimelineItemAction.ViewSource) - } - if (!timelineItem.isMine) { - add(TimelineItemAction.ReportContent) - } - if (canRedact) { - add(TimelineItemAction.Redact) - } - } - } - val displayEmojiReactions = userCanSendReaction && + + val actions = buildActions( + timelineItem = timelineItem, + usersEventPermissions = usersEventPermissions, + isDeveloperModeEnabled = isDeveloperModeEnabled, + isPinnedEventsEnabled = isPinnedEventsEnabled, + isEventPinned = pinnedEventIds.contains(timelineItem.eventId), + ) + val displayEmojiReactions = usersEventPermissions.canSendReaction && timelineItem.isRemote && timelineItem.content.canReact() if (actions.isNotEmpty() || displayEmojiReactions) { @@ -219,3 +119,71 @@ class ActionListPresenter @Inject constructor( } } } + +private fun buildActions( + timelineItem: TimelineItem.Event, + usersEventPermissions: UserEventPermissions, + isDeveloperModeEnabled: Boolean, + isPinnedEventsEnabled: Boolean, + isEventPinned: Boolean, +): List { + val canRedact = timelineItem.isMine && usersEventPermissions.canRedactOwn || !timelineItem.isMine && usersEventPermissions.canRedactOther + return buildList { + if (timelineItem.canBeRepliedTo && usersEventPermissions.canSendMessage) { + if (timelineItem.isThreaded) { + add(TimelineItemAction.ReplyInThread) + } else { + add(TimelineItemAction.Reply) + } + } + if (timelineItem.isRemote && timelineItem.content.canBeForwarded()) { + add(TimelineItemAction.Forward) + } + if (timelineItem.isEditable) { + add(TimelineItemAction.Edit) + } + if (canRedact && timelineItem.content is TimelineItemPollContent && !timelineItem.content.isEnded) { + add(TimelineItemAction.EndPoll) + } + val canPinUnpin = isPinnedEventsEnabled && usersEventPermissions.canPinUnpin && timelineItem.isRemote + if (canPinUnpin) { + if (isEventPinned) { + add(TimelineItemAction.Unpin) + } else { + add(TimelineItemAction.Pin) + } + } + if (timelineItem.content.canBeCopied()) { + add(TimelineItemAction.Copy) + } + if (timelineItem.isRemote) { + add(TimelineItemAction.CopyLink) + } + if (isDeveloperModeEnabled) { + add(TimelineItemAction.ViewSource) + } + if (!timelineItem.isMine) { + add(TimelineItemAction.ReportContent) + } + if (canRedact) { + add(TimelineItemAction.Redact) + } + }.postFilter(timelineItem.content) +} + +/** + * Post filter the actions based on the content of the event. + */ +private fun List.postFilter(content: TimelineItemEventContent): List { + return filter { action -> + when (content) { + is TimelineItemCallNotifyContent, + is TimelineItemLegacyCallInviteContent, + is TimelineItemStateContent, + is TimelineItemRedactedContent -> { + action == TimelineItemAction.ViewSource + } + else -> true + } + } +} 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 ed6fffb90f..eb2cda8ca7 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 @@ -218,6 +218,7 @@ private fun SheetContent( } } +@Suppress("MultipleEmitters") // False positive @Composable private fun MessageSummary(event: TimelineItem.Event, modifier: Modifier = Modifier) { val content: @Composable () -> Unit diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/actionlist/model/TimelineItemAction.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/actionlist/model/TimelineItemAction.kt index f61e6197c2..a650dc88eb 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/actionlist/model/TimelineItemAction.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/actionlist/model/TimelineItemAction.kt @@ -39,4 +39,8 @@ sealed class TimelineItemAction( data object ViewSource : TimelineItemAction(CommonStrings.action_view_source, CommonDrawables.ic_developer_options) data object ReportContent : TimelineItemAction(CommonStrings.action_report_content, CompoundDrawables.ic_compound_chat_problem, destructive = true) data object EndPoll : TimelineItemAction(CommonStrings.action_end_poll, CompoundDrawables.ic_compound_polls_end) + data object Pin : TimelineItemAction(CommonStrings.action_pin, CompoundDrawables.ic_compound_pin) + + // TODO use the Unpin compound icon when available. + data object Unpin : TimelineItemAction(CommonStrings.action_unpin, CompoundDrawables.ic_compound_pin) } diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/di/MessagesModule.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/di/MessagesModule.kt new file mode 100644 index 0000000000..dba98edf3d --- /dev/null +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/di/MessagesModule.kt @@ -0,0 +1,32 @@ +/* + * 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 + * + * https://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.di + +import com.squareup.anvil.annotations.ContributesTo +import dagger.Binds +import dagger.Module +import io.element.android.features.messages.impl.pinned.banner.PinnedMessagesBannerPresenter +import io.element.android.features.messages.impl.pinned.banner.PinnedMessagesBannerState +import io.element.android.libraries.architecture.Presenter +import io.element.android.libraries.di.RoomScope + +@ContributesTo(RoomScope::class) +@Module +interface MessagesModule { + @Binds + fun bindPinnedMessagesBannerPresenter(presenter: PinnedMessagesBannerPresenter): Presenter +} diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/pinned/IsPinnedMessagesFeatureEnabled.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/pinned/IsPinnedMessagesFeatureEnabled.kt new file mode 100644 index 0000000000..5ef5e2c793 --- /dev/null +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/pinned/IsPinnedMessagesFeatureEnabled.kt @@ -0,0 +1,54 @@ +/* + * 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 + * + * https://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.pinned + +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.saveable.rememberSaveable +import androidx.compose.runtime.setValue +import com.squareup.anvil.annotations.ContributesBinding +import io.element.android.libraries.di.AppScope +import io.element.android.libraries.featureflag.api.FeatureFlagService +import io.element.android.libraries.featureflag.api.FeatureFlags +import kotlinx.coroutines.flow.launchIn +import kotlinx.coroutines.flow.onEach +import javax.inject.Inject + +fun interface IsPinnedMessagesFeatureEnabled { + @Composable + operator fun invoke(): Boolean +} + +@ContributesBinding(AppScope::class) +class DefaultIsPinnedMessagesFeatureEnabled @Inject constructor( + private val featureFlagService: FeatureFlagService, +) : IsPinnedMessagesFeatureEnabled { + @Composable + override operator fun invoke(): Boolean { + var isFeatureEnabled by rememberSaveable { + mutableStateOf(false) + } + LaunchedEffect(Unit) { + featureFlagService.isFeatureEnabledFlow(FeatureFlags.PinnedEvents) + .onEach { isFeatureEnabled = it } + .launchIn(this) + } + return isFeatureEnabled + } +} diff --git a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/unlock/signout/SignOut.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/pinned/banner/PinnedMessagesBannerEvents.kt similarity index 71% rename from features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/unlock/signout/SignOut.kt rename to features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/pinned/banner/PinnedMessagesBannerEvents.kt index f4c91aece6..792db7e3da 100644 --- a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/unlock/signout/SignOut.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/pinned/banner/PinnedMessagesBannerEvents.kt @@ -5,7 +5,7 @@ * 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 + * https://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, @@ -14,8 +14,8 @@ * limitations under the License. */ -package io.element.android.features.lockscreen.impl.unlock.signout +package io.element.android.features.messages.impl.pinned.banner -interface SignOut { - suspend operator fun invoke(): String? +sealed interface PinnedMessagesBannerEvents { + data object MoveToNextPinned : PinnedMessagesBannerEvents } diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/pinned/banner/PinnedMessagesBannerItem.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/pinned/banner/PinnedMessagesBannerItem.kt new file mode 100644 index 0000000000..19dce8a4a0 --- /dev/null +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/pinned/banner/PinnedMessagesBannerItem.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 + * + * https://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.pinned.banner + +import androidx.compose.ui.text.AnnotatedString +import io.element.android.libraries.matrix.api.core.EventId + +data class PinnedMessagesBannerItem( + val eventId: EventId, + val formatted: AnnotatedString, +) diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/pinned/banner/PinnedMessagesBannerItemFactory.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/pinned/banner/PinnedMessagesBannerItemFactory.kt new file mode 100644 index 0000000000..95c13e1f64 --- /dev/null +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/pinned/banner/PinnedMessagesBannerItemFactory.kt @@ -0,0 +1,47 @@ +/* + * 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 + * + * https://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.pinned.banner + +import androidx.compose.ui.text.AnnotatedString +import io.element.android.libraries.core.coroutine.CoroutineDispatchers +import io.element.android.libraries.eventformatter.api.PinnedMessagesBannerFormatter +import io.element.android.libraries.matrix.api.timeline.MatrixTimelineItem +import kotlinx.coroutines.withContext +import javax.inject.Inject + +class PinnedMessagesBannerItemFactory @Inject constructor( + private val coroutineDispatchers: CoroutineDispatchers, + private val formatter: PinnedMessagesBannerFormatter, +) { + suspend fun create(timelineItem: MatrixTimelineItem): PinnedMessagesBannerItem? = withContext(coroutineDispatchers.computation) { + when (timelineItem) { + is MatrixTimelineItem.Event -> { + val eventId = timelineItem.eventId ?: return@withContext null + val formatted = formatter.format(timelineItem.event) + PinnedMessagesBannerItem( + eventId = eventId, + formatted = if (formatted is AnnotatedString) { + formatted + } else { + AnnotatedString(formatted.toString()) + }, + ) + } + else -> null + } + } +} diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/pinned/banner/PinnedMessagesBannerPresenter.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/pinned/banner/PinnedMessagesBannerPresenter.kt new file mode 100644 index 0000000000..13c45e0092 --- /dev/null +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/pinned/banner/PinnedMessagesBannerPresenter.kt @@ -0,0 +1,157 @@ +/* + * 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 + * + * https://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.pinned.banner + +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.collectAsState +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableIntStateOf +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.rememberUpdatedState +import androidx.compose.runtime.saveable.rememberSaveable +import androidx.compose.runtime.setValue +import io.element.android.features.messages.impl.pinned.IsPinnedMessagesFeatureEnabled +import io.element.android.features.networkmonitor.api.NetworkMonitor +import io.element.android.libraries.architecture.Presenter +import io.element.android.libraries.matrix.api.room.MatrixRoom +import kotlinx.collections.immutable.ImmutableList +import kotlinx.collections.immutable.persistentListOf +import kotlinx.collections.immutable.toImmutableList +import kotlinx.coroutines.FlowPreview +import kotlinx.coroutines.flow.debounce +import kotlinx.coroutines.flow.launchIn +import kotlinx.coroutines.flow.map +import kotlinx.coroutines.flow.onCompletion +import kotlinx.coroutines.flow.onEach +import javax.inject.Inject +import kotlin.time.Duration.Companion.milliseconds + +class PinnedMessagesBannerPresenter @Inject constructor( + private val room: MatrixRoom, + private val itemFactory: PinnedMessagesBannerItemFactory, + private val isFeatureEnabled: IsPinnedMessagesFeatureEnabled, + private val networkMonitor: NetworkMonitor, +) : Presenter { + private val pinnedItems = mutableStateOf>(persistentListOf()) + + @Composable + override fun present(): PinnedMessagesBannerState { + val isFeatureEnabled = isFeatureEnabled() + val expectedPinnedMessagesCount by remember { + room.roomInfoFlow.map { roomInfo -> roomInfo.pinnedEventIds.size } + }.collectAsState(initial = 0) + + var hasTimelineFailedToLoad by rememberSaveable { mutableStateOf(false) } + var currentPinnedMessageIndex by rememberSaveable { mutableIntStateOf(-1) } + + PinnedMessagesBannerItemsEffect( + isFeatureEnabled = isFeatureEnabled, + onItemsChange = { newItems -> + val pinnedMessageCount = newItems.size + if (currentPinnedMessageIndex >= pinnedMessageCount || currentPinnedMessageIndex < 0) { + currentPinnedMessageIndex = pinnedMessageCount - 1 + } + pinnedItems.value = newItems + }, + onTimelineFail = { hasTimelineFailed -> + hasTimelineFailedToLoad = hasTimelineFailed + } + ) + + fun handleEvent(event: PinnedMessagesBannerEvents) { + when (event) { + is PinnedMessagesBannerEvents.MoveToNextPinned -> { + currentPinnedMessageIndex = (currentPinnedMessageIndex - 1).mod(pinnedItems.value.size) + } + } + } + + return pinnedMessagesBannerState( + isFeatureEnabled = isFeatureEnabled, + hasTimelineFailed = hasTimelineFailedToLoad, + expectedPinnedMessagesCount = expectedPinnedMessagesCount, + pinnedItems = pinnedItems.value, + currentPinnedMessageIndex = currentPinnedMessageIndex, + eventSink = ::handleEvent + ) + } + + @Composable + private fun pinnedMessagesBannerState( + isFeatureEnabled: Boolean, + hasTimelineFailed: Boolean, + expectedPinnedMessagesCount: Int, + pinnedItems: ImmutableList, + currentPinnedMessageIndex: Int, + eventSink: (PinnedMessagesBannerEvents) -> Unit + ): PinnedMessagesBannerState { + val currentPinnedMessage = pinnedItems.getOrNull(currentPinnedMessageIndex) + return when { + !isFeatureEnabled -> PinnedMessagesBannerState.Hidden + hasTimelineFailed -> PinnedMessagesBannerState.Hidden + currentPinnedMessage != null -> PinnedMessagesBannerState.Loaded( + currentPinnedMessage = currentPinnedMessage, + currentPinnedMessageIndex = currentPinnedMessageIndex, + loadedPinnedMessagesCount = pinnedItems.size, + eventSink = eventSink + ) + expectedPinnedMessagesCount == 0 -> PinnedMessagesBannerState.Hidden + else -> PinnedMessagesBannerState.Loading(expectedPinnedMessagesCount = expectedPinnedMessagesCount) + } + } + + @OptIn(FlowPreview::class) + @Composable + private fun PinnedMessagesBannerItemsEffect( + isFeatureEnabled: Boolean, + onItemsChange: (ImmutableList) -> Unit, + onTimelineFail: (Boolean) -> Unit, + ) { + val updatedOnItemsChange by rememberUpdatedState(onItemsChange) + val updatedOnTimelineFail by rememberUpdatedState(onTimelineFail) + val networkStatus by networkMonitor.connectivity.collectAsState() + + LaunchedEffect(isFeatureEnabled, networkStatus) { + if (!isFeatureEnabled) { + updatedOnItemsChange(persistentListOf()) + return@LaunchedEffect + } + val pinnedEventsTimeline = room.pinnedEventsTimeline() + .onFailure { updatedOnTimelineFail(true) } + .onSuccess { updatedOnTimelineFail(false) } + .getOrNull() + ?: return@LaunchedEffect + + pinnedEventsTimeline.timelineItems + .debounce(300.milliseconds) + .map { timelineItems -> + timelineItems.mapNotNull { timelineItem -> + itemFactory.create(timelineItem) + }.toImmutableList() + } + .onEach { newItems -> + updatedOnItemsChange(newItems) + } + .onCompletion { + pinnedEventsTimeline.close() + } + .launchIn(this) + } + } +} diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/pinned/banner/PinnedMessagesBannerState.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/pinned/banner/PinnedMessagesBannerState.kt new file mode 100644 index 0000000000..a686ada33c --- /dev/null +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/pinned/banner/PinnedMessagesBannerState.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 + * + * https://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.pinned.banner + +import androidx.compose.runtime.Composable +import androidx.compose.runtime.Immutable +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.AnnotatedString +import io.element.android.libraries.designsystem.text.toAnnotatedString +import io.element.android.libraries.ui.strings.CommonStrings + +@Immutable +sealed interface PinnedMessagesBannerState { + data object Hidden : PinnedMessagesBannerState + sealed interface Visible : PinnedMessagesBannerState + data class Loading(val expectedPinnedMessagesCount: Int) : Visible + data class Loaded( + val currentPinnedMessage: PinnedMessagesBannerItem, + val currentPinnedMessageIndex: Int, + val loadedPinnedMessagesCount: Int, + val eventSink: (PinnedMessagesBannerEvents) -> Unit + ) : Visible + + fun pinnedMessagesCount() = when (this) { + is Hidden -> 0 + is Loading -> expectedPinnedMessagesCount + is Loaded -> loadedPinnedMessagesCount + } + + fun currentPinnedMessageIndex() = when (this) { + is Hidden -> 0 + is Loading -> expectedPinnedMessagesCount - 1 + is Loaded -> currentPinnedMessageIndex + } + + @Composable + fun formattedMessage() = when (this) { + is Hidden -> AnnotatedString("") + is Loading -> stringResource(id = CommonStrings.screen_room_pinned_banner_loading_description).toAnnotatedString() + is Loaded -> currentPinnedMessage.formatted + } +} diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/pinned/banner/PinnedMessagesBannerStateProvider.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/pinned/banner/PinnedMessagesBannerStateProvider.kt new file mode 100644 index 0000000000..e9d0a27c16 --- /dev/null +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/pinned/banner/PinnedMessagesBannerStateProvider.kt @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2024 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://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.pinned.banner + +import androidx.compose.ui.text.AnnotatedString +import androidx.compose.ui.tooling.preview.PreviewParameterProvider +import io.element.android.libraries.matrix.api.core.EventId +import kotlin.random.Random + +internal class PinnedMessagesBannerStateProvider : PreviewParameterProvider { + override val values: Sequence + get() = sequenceOf( + aHiddenPinnedMessagesBannerState(), + aLoadingPinnedMessagesBannerState(knownPinnedMessagesCount = 1), + aLoadingPinnedMessagesBannerState(knownPinnedMessagesCount = 4), + aLoadedPinnedMessagesBannerState(knownPinnedMessagesCount = 1, currentPinnedMessageIndex = 0), + aLoadedPinnedMessagesBannerState(knownPinnedMessagesCount = 2, currentPinnedMessageIndex = 0), + aLoadedPinnedMessagesBannerState(knownPinnedMessagesCount = 3, currentPinnedMessageIndex = 0), + aLoadedPinnedMessagesBannerState(knownPinnedMessagesCount = 4, currentPinnedMessageIndex = 0), + aLoadedPinnedMessagesBannerState(knownPinnedMessagesCount = 4, currentPinnedMessageIndex = 1), + aLoadedPinnedMessagesBannerState(knownPinnedMessagesCount = 4, currentPinnedMessageIndex = 2), + aLoadedPinnedMessagesBannerState(knownPinnedMessagesCount = 4, currentPinnedMessageIndex = 3), + ) +} + +internal fun aHiddenPinnedMessagesBannerState() = PinnedMessagesBannerState.Hidden + +internal fun aLoadingPinnedMessagesBannerState( + knownPinnedMessagesCount: Int = 4 +) = PinnedMessagesBannerState.Loading( + expectedPinnedMessagesCount = knownPinnedMessagesCount +) + +internal fun aLoadedPinnedMessagesBannerState( + currentPinnedMessageIndex: Int = 0, + knownPinnedMessagesCount: Int = 1, + currentPinnedMessage: PinnedMessagesBannerItem = PinnedMessagesBannerItem( + eventId = EventId("\$" + Random.nextInt().toString()), + formatted = AnnotatedString("This is a pinned message") + ), + eventSink: (PinnedMessagesBannerEvents) -> Unit = {} +) = PinnedMessagesBannerState.Loaded( + currentPinnedMessage = currentPinnedMessage, + currentPinnedMessageIndex = currentPinnedMessageIndex, + loadedPinnedMessagesCount = knownPinnedMessagesCount, + eventSink = eventSink +) diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/pinned/banner/PinnedMessagesBannerView.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/pinned/banner/PinnedMessagesBannerView.kt new file mode 100644 index 0000000000..e925220796 --- /dev/null +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/pinned/banner/PinnedMessagesBannerView.kt @@ -0,0 +1,289 @@ +/* + * 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 + * + * https://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.pinned.banner + +import androidx.compose.animation.AnimatedVisibility +import androidx.compose.foundation.background +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Arrangement.spacedBy +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.heightIn +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.width +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.rememberLazyListState +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.Stable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.drawBehind +import androidx.compose.ui.draw.shadow +import androidx.compose.ui.geometry.Offset +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.input.nestedscroll.NestedScrollConnection +import androidx.compose.ui.input.nestedscroll.NestedScrollSource +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.AnnotatedString +import androidx.compose.ui.text.style.TextOverflow +import androidx.compose.ui.tooling.preview.PreviewParameter +import androidx.compose.ui.unit.dp +import io.element.android.compound.theme.ElementTheme +import io.element.android.compound.tokens.generated.CompoundIcons +import io.element.android.libraries.designsystem.preview.ElementPreview +import io.element.android.libraries.designsystem.preview.PreviewsDayNight +import io.element.android.libraries.designsystem.theme.components.Icon +import io.element.android.libraries.designsystem.theme.components.Text +import io.element.android.libraries.designsystem.theme.components.TextButton +import io.element.android.libraries.designsystem.theme.pinnedMessageBannerBorder +import io.element.android.libraries.designsystem.theme.pinnedMessageBannerIndicator +import io.element.android.libraries.designsystem.utils.annotatedTextWithBold +import io.element.android.libraries.matrix.api.core.EventId +import io.element.android.libraries.ui.strings.CommonStrings + +@Composable +fun PinnedMessagesBannerView( + state: PinnedMessagesBannerState, + onClick: (EventId) -> Unit, + onViewAllClick: () -> Unit, + modifier: Modifier = Modifier, +) { + Box(modifier = modifier) { + when (state) { + PinnedMessagesBannerState.Hidden -> Unit + is PinnedMessagesBannerState.Visible -> { + PinnedMessagesBannerRow( + state = state, + onClick = onClick, + onViewAllClick = onViewAllClick, + ) + } + } + } +} + +@Composable +private fun PinnedMessagesBannerRow( + state: PinnedMessagesBannerState, + onClick: (EventId) -> Unit, + onViewAllClick: () -> Unit, + modifier: Modifier = Modifier, +) { + val borderColor = ElementTheme.colors.pinnedMessageBannerBorder + Row( + modifier = modifier + .background(color = ElementTheme.colors.bgCanvasDefault) + .fillMaxWidth() + .drawBorder(borderColor) + .heightIn(min = 64.dp) + .clickable { + if (state is PinnedMessagesBannerState.Loaded) { + onClick(state.currentPinnedMessage.eventId) + state.eventSink(PinnedMessagesBannerEvents.MoveToNextPinned) + } + }, + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = spacedBy(10.dp) + ) { + Spacer(modifier = Modifier.width(16.dp)) + PinIndicators( + pinIndex = state.currentPinnedMessageIndex(), + pinsCount = state.pinnedMessagesCount(), + modifier = Modifier.heightIn(max = 40.dp) + ) + Icon( + imageVector = CompoundIcons.PinSolid(), + contentDescription = null, + tint = ElementTheme.materialColors.secondary, + modifier = Modifier.size(20.dp) + ) + PinnedMessageItem( + index = state.currentPinnedMessageIndex(), + totalCount = state.pinnedMessagesCount(), + message = state.formattedMessage(), + modifier = Modifier.weight(1f) + ) + ViewAllButton(state, onViewAllClick) + } +} + +@Composable +private fun ViewAllButton( + state: PinnedMessagesBannerState, + onViewAllClick: () -> Unit, + modifier: Modifier = Modifier, +) { + Box(modifier = modifier) { + val text = if (state is PinnedMessagesBannerState.Loaded) { + stringResource(id = CommonStrings.screen_room_pinned_banner_view_all_button_title) + } else { + "" + } + TextButton( + text = text, + showProgress = state is PinnedMessagesBannerState.Loading, + onClick = onViewAllClick + ) + } +} + +private fun Modifier.drawBorder(borderColor: Color): Modifier { + return this + .drawBehind { + val strokeWidth = 0.5.dp.toPx() + val y = size.height - strokeWidth / 2 + drawLine( + borderColor, + Offset(0f, y), + Offset(size.width, y), + strokeWidth + ) + drawLine( + borderColor, + Offset(0f, 0f), + Offset(size.width, 0f), + strokeWidth + ) + } + .shadow(elevation = 5.dp, spotColor = Color.Transparent) +} + +@Composable +private fun PinIndicators( + pinIndex: Int, + pinsCount: Int, + modifier: Modifier = Modifier, +) { + val indicatorHeight = remember(pinsCount) { + when (pinsCount) { + 0 -> 0 + 1 -> 32 + 2 -> 18 + else -> 11 + } + } + val lazyListState = rememberLazyListState() + LaunchedEffect(pinIndex) { + val viewportSize = lazyListState.layoutInfo.viewportSize + lazyListState.animateScrollToItem( + pinIndex, + indicatorHeight / 2 - viewportSize.height / 2 + ) + } + LazyColumn( + modifier = modifier, + state = lazyListState, + verticalArrangement = spacedBy(2.dp), + userScrollEnabled = false, + ) { + items(pinsCount) { index -> + Box( + modifier = Modifier + .width(2.dp) + .height(indicatorHeight.dp) + .background( + color = if (index == pinIndex) { + ElementTheme.colors.iconAccentPrimary + } else { + ElementTheme.colors.pinnedMessageBannerIndicator + } + ) + ) + } + } +} + +@Composable +private fun PinnedMessageItem( + index: Int, + totalCount: Int, + message: AnnotatedString?, + modifier: Modifier = Modifier, +) { + val countMessage = stringResource(id = CommonStrings.screen_room_pinned_banner_indicator, index + 1, totalCount) + val fullCountMessage = stringResource(id = CommonStrings.screen_room_pinned_banner_indicator_description, countMessage) + Column(modifier = modifier) { + AnimatedVisibility(totalCount > 1) { + Text( + text = annotatedTextWithBold( + text = fullCountMessage, + boldText = countMessage, + ), + style = ElementTheme.typography.fontBodySmMedium, + color = ElementTheme.colors.textActionAccent, + maxLines = 1, + overflow = TextOverflow.Ellipsis, + ) + } + if (message != null) { + Text( + text = message, + style = ElementTheme.typography.fontBodyMdRegular, + color = ElementTheme.colors.textPrimary, + overflow = TextOverflow.Ellipsis, + maxLines = 1, + ) + } + } +} + +@Stable +internal interface PinnedMessagesBannerViewScrollBehavior { + val isVisible: Boolean + val nestedScrollConnection: NestedScrollConnection +} + +internal object PinnedMessagesBannerViewDefaults { + @Composable + fun rememberExitOnScrollBehavior(): PinnedMessagesBannerViewScrollBehavior = remember { + ExitOnScrollBehavior() + } +} + +private class ExitOnScrollBehavior : PinnedMessagesBannerViewScrollBehavior { + override var isVisible by mutableStateOf(true) + override val nestedScrollConnection: NestedScrollConnection = object : NestedScrollConnection { + override fun onPreScroll(available: Offset, source: NestedScrollSource): Offset { + if (available.y < -1) { + isVisible = true + } + if (available.y > 1) { + isVisible = false + } + return Offset.Zero + } + } +} + +@PreviewsDayNight +@Composable +internal fun PinnedMessagesBannerViewPreview(@PreviewParameter(PinnedMessagesBannerStateProvider::class) state: PinnedMessagesBannerState) = ElementPreview { + PinnedMessagesBannerView( + state = state, + onClick = {}, + onViewAllClick = {}, + ) +} 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 24007530e6..25ed908cd0 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 @@ -18,10 +18,11 @@ package io.element.android.features.messages.impl.timeline import io.element.android.libraries.matrix.api.core.EventId import io.element.android.libraries.matrix.api.timeline.Timeline +import kotlin.time.Duration sealed interface TimelineEvents { data class OnScrollFinished(val firstIndex: Int) : TimelineEvents - data class FocusOnEvent(val eventId: EventId) : TimelineEvents + data class FocusOnEvent(val eventId: EventId, val debounce: Duration = Duration.ZERO) : TimelineEvents data object ClearFocusRequestState : TimelineEvents data object OnFocusEventRender : TimelineEvents data object JumpToLive : TimelineEvents 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 f5903f036b..3f7db9607a 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 @@ -50,12 +50,15 @@ import io.element.android.libraries.matrix.ui.room.canSendMessageAsState import io.element.android.libraries.preferences.api.store.SessionPreferencesStore import kotlinx.collections.immutable.ImmutableList import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.delay import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.launch import kotlinx.coroutines.withContext +const val FOCUS_ON_PINNED_EVENT_DEBOUNCE_DURATION_IN_MILLIS = 200L + class TimelinePresenter @AssistedInject constructor( private val timelineItemsFactory: TimelineItemsFactory, private val timelineItemIndexer: TimelineItemIndexer, @@ -136,13 +139,8 @@ class TimelinePresenter @AssistedInject constructor( is TimelineEvents.EditPoll -> { navigator.onEditPollClick(event.pollStartId) } - is TimelineEvents.FocusOnEvent -> localScope.launch { - if (timelineItemIndexer.isKnown(event.eventId)) { - val index = timelineItemIndexer.indexOf(event.eventId) - focusRequestState.value = FocusRequestState.Success(eventId = event.eventId, index = index) - } else { - focusRequestState.value = FocusRequestState.Loading(eventId = event.eventId) - } + is TimelineEvents.FocusOnEvent -> { + focusRequestState.value = FocusRequestState.Requested(event.eventId, event.debounce) } is TimelineEvents.OnFocusEventRender -> { focusRequestState.value = focusRequestState.value.onFocusEventRender() @@ -157,18 +155,29 @@ class TimelinePresenter @AssistedInject constructor( } LaunchedEffect(focusRequestState.value) { - val currentFocusRequestState = focusRequestState.value - if (currentFocusRequestState is FocusRequestState.Loading) { - val eventId = currentFocusRequestState.eventId - timelineController.focusOnEvent(eventId) - .fold( - onSuccess = { - focusRequestState.value = FocusRequestState.Success(eventId = eventId) - }, - onFailure = { - focusRequestState.value = FocusRequestState.Failure(throwable = it) - } - ) + when (val currentFocusRequestState = focusRequestState.value) { + is FocusRequestState.Requested -> { + delay(currentFocusRequestState.debounce) + if (timelineItemIndexer.isKnown(currentFocusRequestState.eventId)) { + val index = timelineItemIndexer.indexOf(currentFocusRequestState.eventId) + focusRequestState.value = FocusRequestState.Success(eventId = currentFocusRequestState.eventId, index = index) + } else { + focusRequestState.value = FocusRequestState.Loading(eventId = currentFocusRequestState.eventId) + } + } + is FocusRequestState.Loading -> { + val eventId = currentFocusRequestState.eventId + timelineController.focusOnEvent(eventId) + .fold( + onSuccess = { + focusRequestState.value = FocusRequestState.Success(eventId = eventId) + }, + onFailure = { + focusRequestState.value = FocusRequestState.Failure(throwable = it) + } + ) + } + else -> Unit } } 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 eb8622d0bc..9339fcb620 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 @@ -21,6 +21,7 @@ import io.element.android.features.messages.impl.timeline.model.NewEventState import io.element.android.features.messages.impl.timeline.model.TimelineItem import io.element.android.libraries.matrix.api.core.EventId import kotlinx.collections.immutable.ImmutableList +import kotlin.time.Duration @Immutable data class TimelineState( @@ -39,6 +40,7 @@ data class TimelineState( @Immutable sealed interface FocusRequestState { data object None : FocusRequestState + data class Requested(val eventId: EventId, val debounce: Duration) : FocusRequestState data class Loading(val eventId: EventId) : FocusRequestState data class Success( val eventId: EventId, @@ -54,6 +56,7 @@ sealed interface FocusRequestState { fun eventId(): EventId? { return when (this) { + is Requested -> eventId is Loading -> eventId is Success -> eventId else -> null diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/TimelineStateProvider.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/TimelineStateProvider.kt index e386efc781..e40a1dd78a 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 @@ -128,6 +128,7 @@ internal fun aTimelineItemEvent( transactionId: TransactionId? = null, isMine: Boolean = false, isEditable: Boolean = false, + canBeRepliedTo: Boolean = false, senderDisplayName: String = "Sender", displayNameAmbiguous: Boolean = false, content: TimelineItemEventContent = aTimelineItemTextContent(), @@ -152,6 +153,7 @@ internal fun aTimelineItemEvent( sentTime = "12:34", isMine = isMine, isEditable = isEditable, + canBeRepliedTo = canBeRepliedTo, senderProfile = aProfileTimelineDetailsReady( displayName = senderDisplayName, displayNameAmbiguous = displayNameAmbiguous, 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 eff2019a11..2b62071c19 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 @@ -48,7 +48,10 @@ import androidx.compose.runtime.rememberUpdatedState import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.rotate +import androidx.compose.ui.input.nestedscroll.NestedScrollConnection +import androidx.compose.ui.input.nestedscroll.nestedScroll import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.platform.rememberNestedScrollInteropConnection import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.PreviewParameter import androidx.compose.ui.unit.dp @@ -90,7 +93,9 @@ fun TimelineView( onReadReceiptClick: (TimelineItem.Event) -> Unit, onJoinCallClick: () -> Unit, modifier: Modifier = Modifier, - forceJumpToBottomVisibility: Boolean = false + lazyListState: LazyListState = rememberLazyListState(), + forceJumpToBottomVisibility: Boolean = false, + nestedScrollConnection: NestedScrollConnection = rememberNestedScrollInteropConnection(), ) { fun clearFocusRequestState() { state.eventSink(TimelineEvents.ClearFocusRequestState) @@ -109,7 +114,6 @@ fun TimelineView( } val context = LocalContext.current - val lazyListState = rememberLazyListState() // Disable reverse layout when TalkBack is enabled to avoid incorrect ordering issues seen in the current Compose UI version val useReverseLayout = remember { val accessibilityManager = context.getSystemService(AccessibilityManager::class.java) @@ -124,7 +128,9 @@ fun TimelineView( AnimatedVisibility(visible = true, enter = fadeIn()) { Box(modifier) { LazyColumn( - modifier = Modifier.fillMaxSize(), + modifier = Modifier + .fillMaxSize() + .nestedScroll(nestedScrollConnection), state = lazyListState, reverseLayout = useReverseLayout, contentPadding = PaddingValues(vertical = 8.dp), 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 486732d7c7..e3c7aa8c9e 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 @@ -82,7 +82,6 @@ import io.element.android.features.messages.impl.timeline.model.event.aGreyShiel import io.element.android.features.messages.impl.timeline.model.event.aRedShield import io.element.android.features.messages.impl.timeline.model.event.aTimelineItemImageContent import io.element.android.features.messages.impl.timeline.model.event.aTimelineItemTextContent -import io.element.android.features.messages.impl.timeline.model.event.canBeRepliedTo import io.element.android.libraries.designsystem.colors.AvatarColorsProvider import io.element.android.libraries.designsystem.components.EqualWidthColumn import io.element.android.libraries.designsystem.components.avatar.Avatar @@ -153,7 +152,7 @@ fun TimelineItemEventRow( } else { Spacer(modifier = Modifier.height(2.dp)) } - val canReply = timelineRoomInfo.userHasPermissionToSendMessage && event.content.canBeRepliedTo() + val canReply = timelineRoomInfo.userHasPermissionToSendMessage && event.canBeRepliedTo if (canReply) { val state: SwipeableActionsState = rememberSwipeableActionsState() val offset = state.offset.floatValue @@ -410,6 +409,7 @@ private fun MessageSenderInformation( } } +@Suppress("MultipleEmitters") // False positive @Composable private fun MessageEventBubbleContent( event: TimelineItem.Event, diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/TimelineItemReactionsLayout.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/TimelineItemReactionsLayout.kt index b4ec1e7461..77e6c5b9ff 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/TimelineItemReactionsLayout.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/TimelineItemReactionsLayout.kt @@ -110,7 +110,7 @@ fun TimelineItemReactionsLayout( } val rows = rowsIn.toMutableList() val secondLastRow = rows[rows.size - 2].toMutableList() - val expandButtonPlaceable = secondLastRow.removeLast() + val expandButtonPlaceable = secondLastRow.removeAt(secondLastRow.lastIndex) lastRow.add(0, expandButtonPlaceable) rows[rows.size - 2] = secondLastRow rows[rows.size - 1] = lastRow diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/factories/event/TimelineItemEventFactory.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/factories/event/TimelineItemEventFactory.kt index ae2dd3e39c..bbf00a83a9 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/factories/event/TimelineItemEventFactory.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/factories/event/TimelineItemEventFactory.kt @@ -76,6 +76,7 @@ class TimelineItemEventFactory @Inject constructor( content = contentFactory.create(currentTimelineItem.event), isMine = currentTimelineItem.event.isOwn, isEditable = currentTimelineItem.event.isEditable, + canBeRepliedTo = currentTimelineItem.event.canBeRepliedTo, sentTime = sentTime, groupPosition = groupPosition, reactionsState = currentTimelineItem.computeReactionsState(), diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/model/TimelineItem.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/model/TimelineItem.kt index 73bfac5a9d..208a6b07dc 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/model/TimelineItem.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/model/TimelineItem.kt @@ -75,6 +75,7 @@ sealed interface TimelineItem { val sentTime: String = "", val isMine: Boolean = false, val isEditable: Boolean, + val canBeRepliedTo: Boolean, val groupPosition: TimelineItemGroupPosition = TimelineItemGroupPosition.None, val reactionsState: TimelineItemReactions, val readReceiptState: TimelineItemReadReceipts, diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/model/event/TimelineItemEventContent.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/model/event/TimelineItemEventContent.kt index 43fb947433..5a52f476f1 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/model/event/TimelineItemEventContent.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/model/event/TimelineItemEventContent.kt @@ -24,27 +24,27 @@ sealed interface TimelineItemEventContent { } /** - * Only text based content and states can be copied. + * Only text based content can be copied. */ fun TimelineItemEventContent.canBeCopied(): Boolean = - when (this) { - is TimelineItemTextBasedContent, - is TimelineItemStateContent, - is TimelineItemRedactedContent -> true - else -> false - } + this is TimelineItemTextBasedContent /** - * Determine if the event content can be replied to. - * Note: it should match the logic in [io.element.android.features.messages.impl.actionlist.ActionListPresenter]. + * Returns true if the event content can be forwarded. */ -fun TimelineItemEventContent.canBeRepliedTo(): Boolean = +fun TimelineItemEventContent.canBeForwarded(): Boolean = when (this) { - is TimelineItemRedactedContent, - is TimelineItemLegacyCallInviteContent, - is TimelineItemCallNotifyContent, - is TimelineItemStateContent -> false - else -> true + is TimelineItemTextBasedContent, + is TimelineItemImageContent, + is TimelineItemFileContent, + is TimelineItemAudioContent, + is TimelineItemVideoContent, + is TimelineItemLocationContent, + is TimelineItemVoiceContent -> true + // Stickers can't be forwarded (yet) so we don't show the option + // See https://github.com/element-hq/element-x-android/issues/2161 + is TimelineItemStickerContent -> false + else -> false } /** 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 index c4a8a88153..9dadb7515d 100644 --- 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 @@ -33,11 +33,12 @@ internal fun MessagesViewWithTypingPreview( onBackClick = {}, onRoomDetailsClick = {}, onEventClick = { false }, - onPreviewAttachments = {}, onUserDataClick = {}, onLinkClick = {}, + onPreviewAttachments = {}, onSendLocationClick = {}, onCreatePollClick = {}, onJoinCallClick = {}, + onViewAllPinnedMessagesClick = {}, ) } 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 index c568635a02..4ab81677d3 100644 --- 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 @@ -53,6 +53,7 @@ import io.element.android.libraries.designsystem.theme.components.Text import io.element.android.libraries.matrix.api.room.RoomMember import kotlinx.collections.immutable.ImmutableList +@Suppress("MultipleEmitters") // False positive @Composable fun TypingNotificationView( state: TypingNotificationState, diff --git a/features/messages/impl/src/main/res/values-pl/translations.xml b/features/messages/impl/src/main/res/values-pl/translations.xml index ebb2b54369..add70eb71d 100644 --- a/features/messages/impl/src/main/res/values-pl/translations.xml +++ b/features/messages/impl/src/main/res/values-pl/translations.xml @@ -39,12 +39,18 @@ "Nowe" "%1$d zmiana pokoju" - "%1$d zmian pokoju" - "%1$d zmiany pokoju" + "%1$d zmiany pokoju" + "%1$d zmian pokoju" + + + "%1$s, %2$s i %3$d inny" + "%1$s, %2$s i %3$d innych" + "%1$s, %2$s i %3$d innych" "%1$s piszę" "%1$s piszą" - "%1$s piszą" + "%1$s pisze" + "%1$s i %2$s" diff --git a/features/messages/impl/src/main/res/values-pt-rBR/translations.xml b/features/messages/impl/src/main/res/values-pt-rBR/translations.xml index 6d324fd695..1c668ae3f6 100644 --- a/features/messages/impl/src/main/res/values-pt-rBR/translations.xml +++ b/features/messages/impl/src/main/res/values-pt-rBR/translations.xml @@ -23,6 +23,7 @@ "O histórico de mensagens não está disponível no momento." "Gostaria de convidá-los de volta?" "Você está sozinho neste chat" + "Notificar a sala inteira" "Todos" "Enviar novamente" "Sua mensagem não foi enviada" @@ -36,7 +37,16 @@ "Mostrar mais" "Novo" - "%1$d mudança de sala" - "%1$d mudanças de salas" + "%1$d alteração na sala" + "%1$d alterações na sala" + + "%1$s, %2$s e %3$d outro" + "%1$s, %2$s e %3$d outros" + + + "%1$s está digitando" + "%1$s estão digitando" + + "%1$s e %2$s" diff --git a/features/messages/impl/src/main/res/values-uz/translations.xml b/features/messages/impl/src/main/res/values-uz/translations.xml new file mode 100644 index 0000000000..78681df692 --- /dev/null +++ b/features/messages/impl/src/main/res/values-uz/translations.xml @@ -0,0 +1,42 @@ + + + "Faoliyatlar" + "Bayroqlar" + "Oziq-ovqat va ichimliklar" + "Hayvonlar va tabiat" + "Ob\'ektlar" + "Smayllar va odamlar" + "Sayohat va Joylar" + "Belgilar" + "Foydalanuvchini bloklash" + "Ushbu foydalanuvchidan barcha joriy va kelajakdagi xabarlarni yashirishni xohlayotganingizni tekshiring" + "Bu xabar uy serveringiz administratoriga xabar qilinadi. Ular hech qanday shifrlangan xabarlarni o\'qiy olmaydi." + "Ushbu kontent haqida xabar berish sababi" + "Kamera" + "Rasmga olmoq" + "Video yozib olish" + "Biriktirma" + "Fotosurat va video kutubxonasi" + "Joylashuv" + "So\'ro\'vnoma" + "Matnni formatlash" + "Xabarlar tarixi hozirda mavjud emas." + "Ularni yana taklif qilmoqchimisiz?" + "Siz bu chatda yolg\'izsiz" + "Har kim" + "Yana yuboring" + "Xabaringiz yuborilmadi" + "Emoji qo\'shmoq" + "Bu %1$sni boshlanishi" + "Bu suhbatning boshlanishi." + "Kamroq ko\'rsatish" + "Xabar nusxalandi" + "Sizda bu xonaga post yozishga ruxsat yo‘q" + "Kamroq ko\'rsatish" + "Ko\'proq ko\'rsatish" + "Yangi" + + "%1$dxonani almashtirish" + "%1$dxona o\'zgarishi" + + 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 091305893e..a6c123971b 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 @@ -30,6 +30,7 @@ import io.element.android.features.messages.impl.fixtures.aMessageEvent import io.element.android.features.messages.impl.fixtures.aTimelineItemsFactory import io.element.android.features.messages.impl.messagecomposer.DefaultMessageComposerContext import io.element.android.features.messages.impl.messagecomposer.MessageComposerPresenter +import io.element.android.features.messages.impl.pinned.banner.aLoadedPinnedMessagesBannerState import io.element.android.features.messages.impl.textcomposer.TestRichTextEditorStateFactory import io.element.android.features.messages.impl.timeline.TimelineController import io.element.android.features.messages.impl.timeline.TimelineItemIndexer @@ -43,6 +44,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.timeline.model.event.aTimelineItemTextContent import io.element.android.features.messages.impl.typing.TypingNotificationPresenter import io.element.android.features.messages.impl.utils.FakeTextPillificationHelper import io.element.android.features.messages.impl.voicemessages.composer.VoiceMessageComposerPlayer @@ -77,6 +79,7 @@ import io.element.android.libraries.matrix.test.AN_EVENT_ID import io.element.android.libraries.matrix.test.A_ROOM_ID import io.element.android.libraries.matrix.test.A_SESSION_ID import io.element.android.libraries.matrix.test.A_SESSION_ID_2 +import io.element.android.libraries.matrix.test.A_THROWABLE import io.element.android.libraries.matrix.test.core.aBuildMeta import io.element.android.libraries.matrix.test.permalink.FakePermalinkBuilder import io.element.android.libraries.matrix.test.permalink.FakePermalinkParser @@ -137,8 +140,8 @@ class MessagesPresenterTest { assertThat(initialState.roomName).isEqualTo(AsyncData.Success("")) assertThat(initialState.roomAvatar) .isEqualTo(AsyncData.Success(AvatarData(id = A_ROOM_ID.value, name = "", url = AN_AVATAR_URL, size = AvatarSize.TimelineRoom))) - assertThat(initialState.userHasPermissionToSendMessage).isTrue() - assertThat(initialState.userHasPermissionToRedactOwn).isTrue() + assertThat(initialState.userEventPermissions.canSendMessage).isTrue() + assertThat(initialState.userEventPermissions.canRedactOwn).isTrue() assertThat(initialState.hasNetworkConnection).isTrue() assertThat(initialState.snackbarMessage).isNull() assertThat(initialState.inviteProgress).isEqualTo(AsyncData.Uninitialized) @@ -155,6 +158,7 @@ class MessagesPresenterTest { canRedactOtherResult = { Result.success(true) }, canUserJoinCallResult = { Result.success(true) }, typingNoticeResult = { Result.success(Unit) }, + canUserPinUnpinResult = { Result.success(true) }, ) assertThat(room.markAsReadCalls).isEmpty() val presenter = createMessagesPresenter(matrixRoom = room) @@ -175,6 +179,7 @@ class MessagesPresenterTest { canRedactOwnResult = { Result.success(true) }, canRedactOtherResult = { Result.success(true) }, typingNoticeResult = { Result.success(Unit) }, + canUserPinUnpinResult = { Result.success(true) }, ).apply { givenRoomInfo(aRoomInfo(hasRoomCall = true)) } @@ -203,6 +208,7 @@ class MessagesPresenterTest { canRedactOtherResult = { Result.success(true) }, canUserJoinCallResult = { Result.success(true) }, typingNoticeResult = { Result.success(Unit) }, + canUserPinUnpinResult = { Result.success(true) }, ) val presenter = createMessagesPresenter(matrixRoom = room, coroutineDispatchers = coroutineDispatchers) moleculeFlow(RecompositionMode.Immediate) { @@ -240,6 +246,7 @@ class MessagesPresenterTest { canRedactOtherResult = { Result.success(true) }, canUserJoinCallResult = { Result.success(true) }, typingNoticeResult = { Result.success(Unit) }, + canUserPinUnpinResult = { Result.success(true) }, ) val presenter = createMessagesPresenter(matrixRoom = room, coroutineDispatchers = coroutineDispatchers) moleculeFlow(RecompositionMode.Immediate) { @@ -298,6 +305,7 @@ class MessagesPresenterTest { canRedactOtherResult = { Result.success(true) }, canUserJoinCallResult = { Result.success(true) }, typingNoticeResult = { Result.success(Unit) }, + canUserPinUnpinResult = { Result.success(true) }, ) val presenter = createMessagesPresenter( clipboardHelper = clipboardHelper, @@ -487,6 +495,7 @@ class MessagesPresenterTest { canRedactOtherResult = { Result.success(true) }, canUserJoinCallResult = { Result.success(true) }, typingNoticeResult = { Result.success(Unit) }, + canUserPinUnpinResult = { Result.success(true) }, ) val redactEventLambda = lambdaRecorder { _: EventId?, _: TransactionId?, _: String? -> Result.success(true) } @@ -561,6 +570,7 @@ class MessagesPresenterTest { canRedactOtherResult = { Result.success(true) }, canUserJoinCallResult = { Result.success(true) }, typingNoticeResult = { Result.success(Unit) }, + canUserPinUnpinResult = { Result.success(true) }, ) val presenter = createMessagesPresenter(matrixRoom = room) moleculeFlow(RecompositionMode.Immediate) { @@ -596,6 +606,7 @@ class MessagesPresenterTest { canRedactOtherResult = { Result.success(true) }, canUserJoinCallResult = { Result.success(true) }, typingNoticeResult = { Result.success(Unit) }, + canUserPinUnpinResult = { Result.success(true) }, ) val presenter = createMessagesPresenter(matrixRoom = room) moleculeFlow(RecompositionMode.Immediate) { @@ -620,6 +631,7 @@ class MessagesPresenterTest { canRedactOtherResult = { Result.success(true) }, canUserJoinCallResult = { Result.success(true) }, typingNoticeResult = { Result.success(Unit) }, + canUserPinUnpinResult = { Result.success(true) }, ) val presenter = createMessagesPresenter(matrixRoom = room) moleculeFlow(RecompositionMode.Immediate) { @@ -644,6 +656,7 @@ class MessagesPresenterTest { canRedactOtherResult = { Result.success(true) }, canUserJoinCallResult = { Result.success(true) }, typingNoticeResult = { Result.success(Unit) }, + canUserPinUnpinResult = { Result.success(true) }, ) room.givenRoomMembersState( MatrixRoomMembersState.Ready( @@ -679,6 +692,7 @@ class MessagesPresenterTest { canRedactOtherResult = { Result.success(true) }, canUserJoinCallResult = { Result.success(true) }, typingNoticeResult = { Result.success(Unit) }, + canUserPinUnpinResult = { Result.success(true) }, ) room.givenRoomMembersState( MatrixRoomMembersState.Error( @@ -715,6 +729,7 @@ class MessagesPresenterTest { canRedactOtherResult = { Result.success(true) }, canUserJoinCallResult = { Result.success(true) }, typingNoticeResult = { Result.success(Unit) }, + canUserPinUnpinResult = { Result.success(true) }, ) room.givenRoomMembersState(MatrixRoomMembersState.Unknown) val presenter = createMessagesPresenter(matrixRoom = room) @@ -741,6 +756,7 @@ class MessagesPresenterTest { canRedactOtherResult = { Result.success(true) }, canUserJoinCallResult = { Result.success(true) }, typingNoticeResult = { Result.success(Unit) }, + canUserPinUnpinResult = { Result.success(true) }, ) room.givenRoomMembersState( MatrixRoomMembersState.Ready( @@ -781,13 +797,14 @@ class MessagesPresenterTest { canRedactOtherResult = { Result.success(true) }, canUserJoinCallResult = { Result.success(true) }, typingNoticeResult = { Result.success(Unit) }, + canUserPinUnpinResult = { Result.success(true) }, ) val presenter = createMessagesPresenter(matrixRoom = matrixRoom) moleculeFlow(RecompositionMode.Immediate) { presenter.present() }.test { val state = awaitFirstItem() - assertThat(state.userHasPermissionToSendMessage).isTrue() + assertThat(state.userEventPermissions.canSendMessage).isTrue() } } @@ -805,15 +822,16 @@ class MessagesPresenterTest { canRedactOtherResult = { Result.success(true) }, canUserJoinCallResult = { Result.success(true) }, typingNoticeResult = { Result.success(Unit) }, + canUserPinUnpinResult = { Result.success(true) }, ) val presenter = createMessagesPresenter(matrixRoom = matrixRoom) moleculeFlow(RecompositionMode.Immediate) { presenter.present() }.test { // Default value - assertThat(awaitItem().userHasPermissionToSendMessage).isTrue() + assertThat(awaitItem().userEventPermissions.canSendMessage).isTrue() skipItems(1) - assertThat(awaitItem().userHasPermissionToSendMessage).isFalse() + assertThat(awaitItem().userEventPermissions.canSendMessage).isFalse() cancelAndIgnoreRemainingEvents() } } @@ -826,14 +844,15 @@ class MessagesPresenterTest { canRedactOtherResult = { Result.success(false) }, canUserJoinCallResult = { Result.success(true) }, typingNoticeResult = { Result.success(Unit) }, + canUserPinUnpinResult = { Result.success(true) }, ) val presenter = createMessagesPresenter(matrixRoom = matrixRoom) moleculeFlow(RecompositionMode.Immediate) { presenter.present() }.test { - val initialState = consumeItemsUntilPredicate { it.userHasPermissionToRedactOwn }.last() - assertThat(initialState.userHasPermissionToRedactOwn).isTrue() - assertThat(initialState.userHasPermissionToRedactOther).isFalse() + val initialState = consumeItemsUntilPredicate { it.userEventPermissions.canRedactOwn }.last() + assertThat(initialState.userEventPermissions.canRedactOwn).isTrue() + assertThat(initialState.userEventPermissions.canRedactOther).isFalse() cancelAndIgnoreRemainingEvents() } } @@ -846,14 +865,15 @@ class MessagesPresenterTest { canRedactOwnResult = { Result.success(false) }, canUserJoinCallResult = { Result.success(true) }, typingNoticeResult = { Result.success(Unit) }, + canUserPinUnpinResult = { Result.success(true) }, ) val presenter = createMessagesPresenter(matrixRoom = matrixRoom) moleculeFlow(RecompositionMode.Immediate) { presenter.present() }.test { - val initialState = consumeItemsUntilPredicate { it.userHasPermissionToRedactOther }.last() - assertThat(initialState.userHasPermissionToRedactOwn).isFalse() - assertThat(initialState.userHasPermissionToRedactOther).isTrue() + val initialState = consumeItemsUntilPredicate { it.userEventPermissions.canRedactOther }.last() + assertThat(initialState.userEventPermissions.canRedactOwn).isFalse() + assertThat(initialState.userEventPermissions.canRedactOther).isTrue() cancelAndIgnoreRemainingEvents() } } @@ -878,6 +898,74 @@ class MessagesPresenterTest { } } + @Test + fun `present - handle action pin`() = runTest { + val successPinEventLambda = lambdaRecorder { _: EventId -> Result.success(true) } + val failurePinEventLambda = lambdaRecorder { _: EventId -> Result.failure(A_THROWABLE) } + val timeline = FakeTimeline() + val room = FakeMatrixRoom( + liveTimeline = timeline, + canUserSendMessageResult = { _, _ -> Result.success(true) }, + canRedactOwnResult = { Result.success(true) }, + canRedactOtherResult = { Result.success(true) }, + canUserJoinCallResult = { Result.success(true) }, + typingNoticeResult = { Result.success(Unit) }, + canUserPinUnpinResult = { Result.success(true) }, + ) + val presenter = createMessagesPresenter(matrixRoom = room) + moleculeFlow(RecompositionMode.Immediate) { + presenter.present() + }.test { + val messageEvent = aMessageEvent( + content = aTimelineItemTextContent() + ) + val initialState = awaitFirstItem() + + timeline.pinEventLambda = successPinEventLambda + initialState.eventSink.invoke(MessagesEvents.HandleAction(TimelineItemAction.Pin, messageEvent)) + assert(successPinEventLambda).isCalledOnce().with(value(messageEvent.eventId)) + + timeline.pinEventLambda = failurePinEventLambda + initialState.eventSink.invoke(MessagesEvents.HandleAction(TimelineItemAction.Pin, messageEvent)) + assert(failurePinEventLambda).isCalledOnce().with(value(messageEvent.eventId)) + assertThat(awaitItem().snackbarMessage).isNotNull() + } + } + + @Test + fun `present - handle action unpin`() = runTest { + val successUnpinEventLambda = lambdaRecorder { _: EventId -> Result.success(true) } + val failureUnpinEventLambda = lambdaRecorder { _: EventId -> Result.failure(A_THROWABLE) } + val timeline = FakeTimeline() + val room = FakeMatrixRoom( + liveTimeline = timeline, + canUserSendMessageResult = { _, _ -> Result.success(true) }, + canRedactOwnResult = { Result.success(true) }, + canRedactOtherResult = { Result.success(true) }, + canUserJoinCallResult = { Result.success(true) }, + typingNoticeResult = { Result.success(Unit) }, + canUserPinUnpinResult = { Result.success(true) }, + ) + val presenter = createMessagesPresenter(matrixRoom = room) + moleculeFlow(RecompositionMode.Immediate) { + presenter.present() + }.test { + val messageEvent = aMessageEvent( + content = aTimelineItemTextContent() + ) + val initialState = awaitFirstItem() + + timeline.unpinEventLambda = successUnpinEventLambda + initialState.eventSink.invoke(MessagesEvents.HandleAction(TimelineItemAction.Unpin, messageEvent)) + assert(successUnpinEventLambda).isCalledOnce().with(value(messageEvent.eventId)) + + timeline.unpinEventLambda = failureUnpinEventLambda + initialState.eventSink.invoke(MessagesEvents.HandleAction(TimelineItemAction.Unpin, messageEvent)) + assert(failureUnpinEventLambda).isCalledOnce().with(value(messageEvent.eventId)) + assertThat(awaitItem().snackbarMessage).isNotNull() + } + } + private suspend fun ReceiveTurbine.awaitFirstItem(): T { // Skip 2 item if Mentions feature is enabled, else 1 skipItems(if (FeatureFlags.Mentions.defaultValue(aBuildMeta())) 2 else 1) @@ -892,6 +980,7 @@ class MessagesPresenterTest { canRedactOtherResult = { Result.success(true) }, canUserJoinCallResult = { Result.success(true) }, typingNoticeResult = { Result.success(Unit) }, + canUserPinUnpinResult = { Result.success(true) }, ).apply { givenRoomInfo(aRoomInfo(id = roomId, name = "")) }, @@ -958,14 +1047,21 @@ class MessagesPresenterTest { return timelinePresenter } } - val actionListPresenter = ActionListPresenter(appPreferencesStore = appPreferencesStore) + val featureFlagService = FakeFeatureFlagService() + val actionListPresenter = ActionListPresenter( + appPreferencesStore = appPreferencesStore, + featureFlagsService = featureFlagService, + room = matrixRoom, + ) val typingNotificationPresenter = TypingNotificationPresenter( room = matrixRoom, sessionPreferencesStore = sessionPreferencesStore, ) + val readReceiptBottomSheetPresenter = ReadReceiptBottomSheetPresenter() val customReactionPresenter = CustomReactionPresenter(emojibaseProvider = FakeEmojibaseProvider()) val reactionSummaryPresenter = ReactionSummaryPresenter(room = matrixRoom) + return MessagesPresenter( room = matrixRoom, composerPresenter = messageComposerPresenter, @@ -976,11 +1072,12 @@ class MessagesPresenterTest { customReactionPresenter = customReactionPresenter, reactionSummaryPresenter = reactionSummaryPresenter, readReceiptBottomSheetPresenter = readReceiptBottomSheetPresenter, + pinnedMessagesBannerPresenter = { aLoadedPinnedMessagesBannerState() }, networkMonitor = FakeNetworkMonitor(), snackbarDispatcher = SnackbarDispatcher(), navigator = navigator, clipboardHelper = clipboardHelper, - featureFlagsService = FakeFeatureFlagService(), + featureFlagsService = featureFlagService, buildMeta = aBuildMeta(), dispatchers = coroutineDispatchers, htmlConverterProvider = FakeHtmlConverterProvider(), 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 index 9a22ced505..b304ad9178 100644 --- 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 @@ -26,12 +26,14 @@ 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.onLast import androidx.compose.ui.test.onNodeWithContentDescription import androidx.compose.ui.test.onNodeWithTag import androidx.compose.ui.test.onNodeWithText import androidx.compose.ui.test.performClick import androidx.compose.ui.test.performTouchInput import androidx.compose.ui.test.swipeRight +import androidx.compose.ui.text.AnnotatedString import androidx.test.ext.junit.runners.AndroidJUnit4 import io.element.android.emojibasebindings.Emoji import io.element.android.emojibasebindings.EmojibaseCategory @@ -42,8 +44,11 @@ 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.pinned.banner.PinnedMessagesBannerItem +import io.element.android.features.messages.impl.pinned.banner.aLoadedPinnedMessagesBannerState +import io.element.android.features.messages.impl.timeline.FOCUS_ON_PINNED_EVENT_DEBOUNCE_DURATION_IN_MILLIS +import io.element.android.features.messages.impl.timeline.TimelineEvents import io.element.android.features.messages.impl.timeline.aTimelineItemEvent -import io.element.android.features.messages.impl.timeline.aTimelineItemList import io.element.android.features.messages.impl.timeline.aTimelineItemReadReceipts import io.element.android.features.messages.impl.timeline.aTimelineRoomInfo import io.element.android.features.messages.impl.timeline.aTimelineState @@ -53,8 +58,8 @@ import io.element.android.features.messages.impl.timeline.components.reactionsum import io.element.android.features.messages.impl.timeline.components.receipt.aReadReceiptData import io.element.android.features.messages.impl.timeline.components.receipt.bottomsheet.ReadReceiptBottomSheetEvents import io.element.android.features.messages.impl.timeline.model.TimelineItem -import io.element.android.features.messages.impl.timeline.model.event.aTimelineItemTextContent import io.element.android.libraries.matrix.api.core.UserId +import io.element.android.libraries.matrix.test.AN_EVENT_ID import io.element.android.libraries.testtags.TestTags import io.element.android.libraries.ui.strings.CommonStrings import io.element.android.tests.testutils.EnsureCalledOnceWithParam @@ -73,6 +78,7 @@ import org.junit.Test import org.junit.rules.TestRule import org.junit.runner.RunWith import org.robolectric.annotation.Config +import kotlin.time.Duration.Companion.milliseconds @RunWith(AndroidJUnit4::class) class MessagesViewTest { @@ -169,16 +175,20 @@ class MessagesViewTest { userHasPermissionToRedactOwn: Boolean = false, userHasPermissionToRedactOther: Boolean = false, userHasPermissionToSendReaction: Boolean = false, + userCanPinEvent: Boolean = false, ) { val eventsRecorder = EventsRecorder() val state = aMessagesState( actionListState = anActionListState( eventSink = eventsRecorder ), - userHasPermissionToSendMessage = userHasPermissionToSendMessage, - userHasPermissionToRedactOwn = userHasPermissionToRedactOwn, - userHasPermissionToRedactOther = userHasPermissionToRedactOther, - userHasPermissionToSendReaction = userHasPermissionToSendReaction, + userEventPermissions = UserEventPermissions( + canSendMessage = userHasPermissionToSendMessage, + canRedactOwn = userHasPermissionToRedactOwn, + canRedactOther = userHasPermissionToRedactOther, + canSendReaction = userHasPermissionToSendReaction, + canPinUnpin = userCanPinEvent, + ), ) val timelineItem = state.timelineState.timelineItems.first() as TimelineItem.Event rule.setMessagesView( @@ -189,10 +199,7 @@ class MessagesViewTest { eventsRecorder.assertSingle( ActionListEvents.ComputeForMessage( event = timelineItem, - canRedactOwn = state.userHasPermissionToRedactOwn, - canRedactOther = state.userHasPermissionToRedactOther, - canSendMessage = state.userHasPermissionToSendMessage, - canSendReaction = state.userHasPermissionToSendReaction, + userEventPermissions = state.userEventPermissions, ) ) } @@ -237,9 +244,11 @@ class MessagesViewTest { private fun swipeTest(userHasPermissionToSendMessage: Boolean) { val eventsRecorder = EventsRecorder() + val canBeRepliedEvent = aTimelineItemEvent(canBeRepliedTo = true) + val cannotBeRepliedEvent = aTimelineItemEvent(canBeRepliedTo = false) val state = aMessagesState( timelineState = aTimelineState( - timelineItems = aTimelineItemList(aTimelineItemTextContent()), + timelineItems = persistentListOf(canBeRepliedEvent, cannotBeRepliedEvent), timelineRoomInfo = aTimelineRoomInfo( userHasPermissionToSendMessage = userHasPermissionToSendMessage ), @@ -249,10 +258,12 @@ class MessagesViewTest { rule.setMessagesView( state = state, ) - rule.onAllNodesWithTag(TestTags.messageBubble.value).onFirst().performTouchInput { swipeRight(endX = 200f) } + rule.onAllNodesWithTag(TestTags.messageBubble.value).apply { + onFirst().performTouchInput { swipeRight(endX = 200f) } + onLast().performTouchInput { swipeRight(endX = 200f) } + } if (userHasPermissionToSendMessage) { - val timelineItem = state.timelineState.timelineItems.first() as TimelineItem.Event - eventsRecorder.assertSingle(MessagesEvents.HandleAction(TimelineItemAction.Reply, timelineItem)) + eventsRecorder.assertSingle(MessagesEvents.HandleAction(TimelineItemAction.Reply, canBeRepliedEvent)) } else { eventsRecorder.assertEmpty() } @@ -454,6 +465,25 @@ class MessagesViewTest { customReactionStateEventsRecorder.assertSingle(CustomReactionEvents.DismissCustomReactionSheet) eventsRecorder.assertSingle(MessagesEvents.ToggleReaction(aUnicode, timelineItem.eventId!!)) } + + @Test + fun `clicking on pinned messages banner emits the expected Event`() { + val eventsRecorder = EventsRecorder() + val state = aMessagesState( + timelineState = aTimelineState(eventSink = eventsRecorder), + pinnedMessagesBannerState = aLoadedPinnedMessagesBannerState( + knownPinnedMessagesCount = 2, + currentPinnedMessageIndex = 0, + currentPinnedMessage = PinnedMessagesBannerItem( + eventId = AN_EVENT_ID, + formatted = AnnotatedString("This is a pinned message") + ), + ), + ) + rule.setMessagesView(state = state) + rule.onNodeWithText("This is a pinned message").performClick() + eventsRecorder.assertSingle(TimelineEvents.FocusOnEvent(AN_EVENT_ID, debounce = FOCUS_ON_PINNED_EVENT_DEBOUNCE_DURATION_IN_MILLIS.milliseconds)) + } } private fun AndroidComposeTestRule.setMessagesView( @@ -467,6 +497,7 @@ private fun AndroidComposeTestRule.setMessa onSendLocationClick: () -> Unit = EnsureNeverCalled(), onCreatePollClick: () -> Unit = EnsureNeverCalled(), onJoinCallClick: () -> Unit = EnsureNeverCalled(), + onViewAllPinnedMessagesClick: () -> Unit = EnsureNeverCalled(), ) { setContent { // Cannot use the RichTextEditor, so simulate a LocalInspectionMode @@ -484,6 +515,7 @@ private fun AndroidComposeTestRule.setMessa onSendLocationClick = onSendLocationClick, onCreatePollClick = onCreatePollClick, onJoinCallClick = onJoinCallClick, + onViewAllPinnedMessagesClick = onViewAllPinnedMessagesClick, ) } } diff --git a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/actionlist/ActionListPresenterTest.kt b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/actionlist/ActionListPresenterTest.kt index 76c43a9c8b..e8ea7cbbc2 100644 --- a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/actionlist/ActionListPresenterTest.kt +++ b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/actionlist/ActionListPresenterTest.kt @@ -20,6 +20,7 @@ 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.messages.impl.aUserEventPermissions import io.element.android.features.messages.impl.actionlist.model.TimelineItemAction import io.element.android.features.messages.impl.fixtures.aMessageEvent import io.element.android.features.messages.impl.timeline.aTimelineItemEvent @@ -31,7 +32,13 @@ import io.element.android.features.messages.impl.timeline.model.event.aTimelineI import io.element.android.features.messages.impl.timeline.model.event.aTimelineItemStateEventContent import io.element.android.features.messages.impl.timeline.model.event.aTimelineItemVoiceContent import io.element.android.features.poll.api.pollcontent.aPollAnswerItemList +import io.element.android.libraries.featureflag.api.FeatureFlags +import io.element.android.libraries.featureflag.test.FakeFeatureFlagService +import io.element.android.libraries.matrix.api.room.MatrixRoom +import io.element.android.libraries.matrix.test.AN_EVENT_ID import io.element.android.libraries.matrix.test.A_MESSAGE +import io.element.android.libraries.matrix.test.room.FakeMatrixRoom +import io.element.android.libraries.matrix.test.room.aRoomInfo import io.element.android.libraries.preferences.test.InMemoryAppPreferencesStore import io.element.android.tests.testutils.WarmUpRule import kotlinx.collections.immutable.persistentListOf @@ -46,7 +53,7 @@ class ActionListPresenterTest { @Test fun `present - initial state`() = runTest { - val presenter = createActionListPresenter(isDeveloperModeEnabled = true) + val presenter = createActionListPresenter(isDeveloperModeEnabled = true, isPinFeatureEnabled = true) moleculeFlow(RecompositionMode.Immediate) { presenter.present() }.test { @@ -57,7 +64,7 @@ class ActionListPresenterTest { @Test fun `present - compute for message from me redacted`() = runTest { - val presenter = createActionListPresenter(isDeveloperModeEnabled = true) + val presenter = createActionListPresenter(isDeveloperModeEnabled = true, isPinFeatureEnabled = true) moleculeFlow(RecompositionMode.Immediate) { presenter.present() }.test { @@ -66,10 +73,13 @@ class ActionListPresenterTest { initialState.eventSink.invoke( ActionListEvents.ComputeForMessage( event = messageEvent, - canRedactOwn = false, - canRedactOther = false, - canSendMessage = true, - canSendReaction = true, + userEventPermissions = aUserEventPermissions( + canRedactOwn = false, + canRedactOther = false, + canSendMessage = true, + canSendReaction = true, + canPinUnpin = true, + ) ) ) // val loadingState = awaitItem() @@ -91,7 +101,7 @@ class ActionListPresenterTest { @Test fun `present - compute for message from others redacted`() = runTest { - val presenter = createActionListPresenter(isDeveloperModeEnabled = true) + val presenter = createActionListPresenter(isDeveloperModeEnabled = true, isPinFeatureEnabled = true) moleculeFlow(RecompositionMode.Immediate) { presenter.present() }.test { @@ -104,10 +114,13 @@ class ActionListPresenterTest { initialState.eventSink.invoke( ActionListEvents.ComputeForMessage( event = messageEvent, - canRedactOwn = false, - canRedactOther = false, - canSendMessage = true, - canSendReaction = true, + userEventPermissions = aUserEventPermissions( + canRedactOwn = false, + canRedactOther = false, + canSendMessage = true, + canSendReaction = true, + canPinUnpin = true, + ) ) ) // val loadingState = awaitItem() @@ -129,7 +142,7 @@ class ActionListPresenterTest { @Test fun `present - compute for others message`() = runTest { - val presenter = createActionListPresenter(isDeveloperModeEnabled = true) + val presenter = createActionListPresenter(isDeveloperModeEnabled = true, isPinFeatureEnabled = true) moleculeFlow(RecompositionMode.Immediate) { presenter.present() }.test { @@ -142,10 +155,13 @@ class ActionListPresenterTest { initialState.eventSink.invoke( ActionListEvents.ComputeForMessage( event = messageEvent, - canRedactOwn = false, - canRedactOther = false, - canSendMessage = true, - canSendReaction = true, + userEventPermissions = aUserEventPermissions( + canRedactOwn = false, + canRedactOther = false, + canSendMessage = true, + canSendReaction = true, + canPinUnpin = true, + ) ) ) // val loadingState = awaitItem() @@ -158,6 +174,7 @@ class ActionListPresenterTest { actions = persistentListOf( TimelineItemAction.Reply, TimelineItemAction.Forward, + TimelineItemAction.Pin, TimelineItemAction.Copy, TimelineItemAction.CopyLink, TimelineItemAction.ViewSource, @@ -172,7 +189,7 @@ class ActionListPresenterTest { @Test fun `present - compute for others message cannot sent message`() = runTest { - val presenter = createActionListPresenter(isDeveloperModeEnabled = true) + val presenter = createActionListPresenter(isDeveloperModeEnabled = true, isPinFeatureEnabled = true) moleculeFlow(RecompositionMode.Immediate) { presenter.present() }.test { @@ -185,10 +202,13 @@ class ActionListPresenterTest { initialState.eventSink.invoke( ActionListEvents.ComputeForMessage( event = messageEvent, - canRedactOwn = true, - canRedactOther = false, - canSendMessage = false, - canSendReaction = true + userEventPermissions = aUserEventPermissions( + canRedactOwn = true, + canRedactOther = false, + canSendMessage = false, + canSendReaction = true, + canPinUnpin = true, + ) ) ) // val loadingState = awaitItem() @@ -200,6 +220,7 @@ class ActionListPresenterTest { displayEmojiReactions = true, actions = persistentListOf( TimelineItemAction.Forward, + TimelineItemAction.Pin, TimelineItemAction.Copy, TimelineItemAction.CopyLink, TimelineItemAction.ViewSource, @@ -214,7 +235,7 @@ class ActionListPresenterTest { @Test fun `present - compute for others message and can redact`() = runTest { - val presenter = createActionListPresenter(isDeveloperModeEnabled = true) + val presenter = createActionListPresenter(isDeveloperModeEnabled = true, isPinFeatureEnabled = true) moleculeFlow(RecompositionMode.Immediate) { presenter.present() }.test { @@ -227,10 +248,13 @@ class ActionListPresenterTest { initialState.eventSink.invoke( ActionListEvents.ComputeForMessage( event = messageEvent, - canRedactOwn = false, - canRedactOther = true, - canSendMessage = true, - canSendReaction = true, + userEventPermissions = aUserEventPermissions( + canRedactOwn = false, + canRedactOther = true, + canSendMessage = true, + canSendReaction = true, + canPinUnpin = true, + ) ) ) val successState = awaitItem() @@ -241,6 +265,7 @@ class ActionListPresenterTest { actions = persistentListOf( TimelineItemAction.Reply, TimelineItemAction.Forward, + TimelineItemAction.Pin, TimelineItemAction.Copy, TimelineItemAction.CopyLink, TimelineItemAction.ViewSource, @@ -256,7 +281,7 @@ class ActionListPresenterTest { @Test fun `present - compute for others message and cannot send reaction`() = runTest { - val presenter = createActionListPresenter(isDeveloperModeEnabled = true) + val presenter = createActionListPresenter(isDeveloperModeEnabled = true, isPinFeatureEnabled = true) moleculeFlow(RecompositionMode.Immediate) { presenter.present() }.test { @@ -269,10 +294,13 @@ class ActionListPresenterTest { initialState.eventSink.invoke( ActionListEvents.ComputeForMessage( event = messageEvent, - canRedactOwn = false, - canRedactOther = true, - canSendMessage = true, - canSendReaction = false + userEventPermissions = aUserEventPermissions( + canRedactOwn = false, + canRedactOther = true, + canSendMessage = true, + canSendReaction = false, + canPinUnpin = true, + ) ) ) val successState = awaitItem() @@ -283,6 +311,7 @@ class ActionListPresenterTest { actions = persistentListOf( TimelineItemAction.Reply, TimelineItemAction.Forward, + TimelineItemAction.Pin, TimelineItemAction.Copy, TimelineItemAction.CopyLink, TimelineItemAction.ViewSource, @@ -298,7 +327,7 @@ class ActionListPresenterTest { @Test fun `present - compute for my message`() = runTest { - val presenter = createActionListPresenter(isDeveloperModeEnabled = true) + val presenter = createActionListPresenter(isDeveloperModeEnabled = true, isPinFeatureEnabled = true) moleculeFlow(RecompositionMode.Immediate) { presenter.present() }.test { @@ -310,10 +339,13 @@ class ActionListPresenterTest { initialState.eventSink.invoke( ActionListEvents.ComputeForMessage( event = messageEvent, - canRedactOwn = true, - canRedactOther = false, - canSendMessage = true, - canSendReaction = true, + userEventPermissions = aUserEventPermissions( + canRedactOwn = true, + canRedactOther = false, + canSendMessage = true, + canSendReaction = true, + canPinUnpin = true, + ) ) ) // val loadingState = awaitItem() @@ -327,6 +359,7 @@ class ActionListPresenterTest { TimelineItemAction.Reply, TimelineItemAction.Forward, TimelineItemAction.Edit, + TimelineItemAction.Pin, TimelineItemAction.Copy, TimelineItemAction.CopyLink, TimelineItemAction.ViewSource, @@ -341,7 +374,7 @@ class ActionListPresenterTest { @Test fun `present - compute for my message cannot redact`() = runTest { - val presenter = createActionListPresenter(isDeveloperModeEnabled = true) + val presenter = createActionListPresenter(isDeveloperModeEnabled = true, isPinFeatureEnabled = true) moleculeFlow(RecompositionMode.Immediate) { presenter.present() }.test { @@ -353,10 +386,13 @@ class ActionListPresenterTest { initialState.eventSink.invoke( ActionListEvents.ComputeForMessage( event = messageEvent, - canRedactOwn = false, - canRedactOther = false, - canSendMessage = true, - canSendReaction = true, + userEventPermissions = aUserEventPermissions( + canRedactOwn = false, + canRedactOther = false, + canSendMessage = true, + canSendReaction = true, + canPinUnpin = true, + ) ) ) // val loadingState = awaitItem() @@ -370,6 +406,7 @@ class ActionListPresenterTest { TimelineItemAction.Reply, TimelineItemAction.Forward, TimelineItemAction.Edit, + TimelineItemAction.Pin, TimelineItemAction.Copy, TimelineItemAction.CopyLink, TimelineItemAction.ViewSource, @@ -383,7 +420,7 @@ class ActionListPresenterTest { @Test fun `present - compute for a media item`() = runTest { - val presenter = createActionListPresenter(isDeveloperModeEnabled = true) + val presenter = createActionListPresenter(isDeveloperModeEnabled = true, isPinFeatureEnabled = true) moleculeFlow(RecompositionMode.Immediate) { presenter.present() }.test { @@ -396,10 +433,13 @@ class ActionListPresenterTest { initialState.eventSink.invoke( ActionListEvents.ComputeForMessage( event = messageEvent, - canRedactOwn = true, - canRedactOther = false, - canSendMessage = true, - canSendReaction = true, + userEventPermissions = aUserEventPermissions( + canRedactOwn = true, + canRedactOther = false, + canSendMessage = true, + canSendReaction = true, + canPinUnpin = true, + ), ) ) // val loadingState = awaitItem() @@ -412,6 +452,7 @@ class ActionListPresenterTest { actions = persistentListOf( TimelineItemAction.Reply, TimelineItemAction.Forward, + TimelineItemAction.Pin, TimelineItemAction.CopyLink, TimelineItemAction.ViewSource, TimelineItemAction.Redact, @@ -425,7 +466,7 @@ class ActionListPresenterTest { @Test fun `present - compute for a state item in debug build`() = runTest { - val presenter = createActionListPresenter(isDeveloperModeEnabled = true) + val presenter = createActionListPresenter(isDeveloperModeEnabled = true, isPinFeatureEnabled = true) moleculeFlow(RecompositionMode.Immediate) { presenter.present() }.test { @@ -437,10 +478,13 @@ class ActionListPresenterTest { initialState.eventSink.invoke( ActionListEvents.ComputeForMessage( event = stateEvent, - canRedactOwn = false, - canRedactOther = false, - canSendMessage = true, - canSendReaction = true, + userEventPermissions = aUserEventPermissions( + canRedactOwn = false, + canRedactOther = false, + canSendMessage = true, + canSendReaction = true, + canPinUnpin = true, + ) ) ) // val loadingState = awaitItem() @@ -451,8 +495,6 @@ class ActionListPresenterTest { event = stateEvent, displayEmojiReactions = false, actions = persistentListOf( - TimelineItemAction.Copy, - TimelineItemAction.CopyLink, TimelineItemAction.ViewSource, ) ) @@ -464,7 +506,7 @@ class ActionListPresenterTest { @Test fun `present - compute for a state item in non-debuggable build`() = runTest { - val presenter = createActionListPresenter(isDeveloperModeEnabled = false) + val presenter = createActionListPresenter(isDeveloperModeEnabled = false, isPinFeatureEnabled = true) moleculeFlow(RecompositionMode.Immediate) { presenter.present() }.test { @@ -476,33 +518,24 @@ class ActionListPresenterTest { initialState.eventSink.invoke( ActionListEvents.ComputeForMessage( event = stateEvent, - canRedactOwn = false, - canRedactOther = false, - canSendMessage = true, - canSendReaction = true, + userEventPermissions = aUserEventPermissions( + canRedactOwn = false, + canRedactOther = false, + canSendMessage = true, + canSendReaction = true, + canPinUnpin = true, + ) ) ) // val loadingState = awaitItem() // assertThat(loadingState.target).isEqualTo(ActionListState.Target.Loading(messageEvent)) - val successState = awaitItem() - assertThat(successState.target).isEqualTo( - ActionListState.Target.Success( - event = stateEvent, - displayEmojiReactions = false, - actions = persistentListOf( - TimelineItemAction.Copy, - TimelineItemAction.CopyLink, - ) - ) - ) - initialState.eventSink.invoke(ActionListEvents.Clear) assertThat(awaitItem().target).isEqualTo(ActionListState.Target.None) } } @Test fun `present - compute message in non-debuggable build`() = runTest { - val presenter = createActionListPresenter(isDeveloperModeEnabled = false) + val presenter = createActionListPresenter(isDeveloperModeEnabled = false, isPinFeatureEnabled = true) moleculeFlow(RecompositionMode.Immediate) { presenter.present() }.test { @@ -514,10 +547,59 @@ class ActionListPresenterTest { initialState.eventSink.invoke( ActionListEvents.ComputeForMessage( event = messageEvent, - canRedactOwn = true, - canRedactOther = false, - canSendMessage = true, - canSendReaction = true, + userEventPermissions = aUserEventPermissions( + canRedactOwn = true, + canRedactOther = false, + canSendMessage = true, + canSendReaction = true, + canPinUnpin = true, + ) + ) + ) + // val loadingState = awaitItem() + // assertThat(loadingState.target).isEqualTo(ActionListState.Target.Loading(messageEvent)) + val successState = awaitItem() + assertThat(successState.target).isEqualTo( + ActionListState.Target.Success( + event = messageEvent, + displayEmojiReactions = true, + actions = persistentListOf( + TimelineItemAction.Reply, + TimelineItemAction.Forward, + TimelineItemAction.Edit, + TimelineItemAction.Pin, + TimelineItemAction.Copy, + TimelineItemAction.CopyLink, + TimelineItemAction.Redact, + ) + ) + ) + initialState.eventSink.invoke(ActionListEvents.Clear) + assertThat(awaitItem().target).isEqualTo(ActionListState.Target.None) + } + } + + @Test + fun `present - compute message when user can't pin`() = runTest { + val presenter = createActionListPresenter(isDeveloperModeEnabled = true, isPinFeatureEnabled = true) + moleculeFlow(RecompositionMode.Immediate) { + presenter.present() + }.test { + val initialState = awaitItem() + val messageEvent = aMessageEvent( + isMine = true, + content = TimelineItemTextContent(body = A_MESSAGE, htmlDocument = null, isEdited = false, formattedBody = null) + ) + initialState.eventSink.invoke( + ActionListEvents.ComputeForMessage( + event = messageEvent, + userEventPermissions = aUserEventPermissions( + canRedactOwn = true, + canRedactOther = false, + canSendMessage = true, + canSendReaction = true, + canPinUnpin = false, + ) ) ) // val loadingState = awaitItem() @@ -533,6 +615,61 @@ class ActionListPresenterTest { TimelineItemAction.Edit, TimelineItemAction.Copy, TimelineItemAction.CopyLink, + TimelineItemAction.ViewSource, + TimelineItemAction.Redact, + ) + ) + ) + initialState.eventSink.invoke(ActionListEvents.Clear) + assertThat(awaitItem().target).isEqualTo(ActionListState.Target.None) + } + } + + @Test + fun `present - compute message when event is already pinned`() = runTest { + val room = FakeMatrixRoom().apply { + givenRoomInfo(aRoomInfo(pinnedEventIds = listOf(AN_EVENT_ID))) + } + val presenter = createActionListPresenter( + isDeveloperModeEnabled = true, + isPinFeatureEnabled = true, + room = room + ) + moleculeFlow(RecompositionMode.Immediate) { + presenter.present() + }.test { + val initialState = awaitItem() + val messageEvent = aMessageEvent( + isMine = true, + content = TimelineItemTextContent(body = A_MESSAGE, htmlDocument = null, isEdited = false, formattedBody = null) + ) + initialState.eventSink.invoke( + ActionListEvents.ComputeForMessage( + event = messageEvent, + userEventPermissions = aUserEventPermissions( + canRedactOwn = true, + canRedactOther = false, + canSendMessage = true, + canSendReaction = true, + canPinUnpin = true, + ) + ) + ) + // val loadingState = awaitItem() + // assertThat(loadingState.target).isEqualTo(ActionListState.Target.Loading(messageEvent)) + val successState = awaitItem() + assertThat(successState.target).isEqualTo( + ActionListState.Target.Success( + event = messageEvent, + displayEmojiReactions = true, + actions = persistentListOf( + TimelineItemAction.Reply, + TimelineItemAction.Forward, + TimelineItemAction.Edit, + TimelineItemAction.Unpin, + TimelineItemAction.Copy, + TimelineItemAction.CopyLink, + TimelineItemAction.ViewSource, TimelineItemAction.Redact, ) ) @@ -544,7 +681,7 @@ class ActionListPresenterTest { @Test fun `present - compute message with no actions`() = runTest { - val presenter = createActionListPresenter(isDeveloperModeEnabled = false) + val presenter = createActionListPresenter(isDeveloperModeEnabled = false, isPinFeatureEnabled = true) moleculeFlow(RecompositionMode.Immediate) { presenter.present() }.test { @@ -561,10 +698,13 @@ class ActionListPresenterTest { initialState.eventSink.invoke( ActionListEvents.ComputeForMessage( event = messageEvent, - canRedactOwn = false, - canRedactOther = false, - canSendMessage = true, - canSendReaction = true, + userEventPermissions = aUserEventPermissions( + canRedactOwn = false, + canRedactOther = false, + canSendMessage = true, + canSendReaction = true, + canPinUnpin = true, + ) ) ) assertThat(awaitItem().target).isInstanceOf(ActionListState.Target.Success::class.java) @@ -572,10 +712,12 @@ class ActionListPresenterTest { initialState.eventSink.invoke( ActionListEvents.ComputeForMessage( event = redactedEvent, - canRedactOwn = false, - canRedactOther = false, - canSendMessage = true, - canSendReaction = true, + userEventPermissions = aUserEventPermissions( + canRedactOwn = false, + canRedactOther = false, + canSendMessage = true, + canSendReaction = true, + ) ) ) awaitItem().run { @@ -586,7 +728,7 @@ class ActionListPresenterTest { @Test fun `present - compute not sent message`() = runTest { - val presenter = createActionListPresenter(isDeveloperModeEnabled = false) + val presenter = createActionListPresenter(isDeveloperModeEnabled = false, isPinFeatureEnabled = true) moleculeFlow(RecompositionMode.Immediate) { presenter.present() }.test { @@ -595,16 +737,20 @@ class ActionListPresenterTest { // No event id, so it's not sent yet eventId = null, isMine = true, + canBeRepliedTo = false, content = TimelineItemTextContent(body = A_MESSAGE, htmlDocument = null, isEdited = false, formattedBody = null), ) initialState.eventSink.invoke( ActionListEvents.ComputeForMessage( event = messageEvent, - canRedactOwn = true, - canRedactOther = false, - canSendMessage = true, - canSendReaction = true, + userEventPermissions = aUserEventPermissions( + canRedactOwn = true, + canRedactOther = false, + canSendMessage = true, + canSendReaction = true, + canPinUnpin = true, + ) ) ) val successState = awaitItem() @@ -624,7 +770,7 @@ class ActionListPresenterTest { @Test fun `present - compute for editable poll message`() = runTest { - val presenter = createActionListPresenter(isDeveloperModeEnabled = false) + val presenter = createActionListPresenter(isDeveloperModeEnabled = false, isPinFeatureEnabled = true) moleculeFlow(RecompositionMode.Immediate) { presenter.present() }.test { @@ -637,10 +783,13 @@ class ActionListPresenterTest { initialState.eventSink.invoke( ActionListEvents.ComputeForMessage( event = messageEvent, - canRedactOwn = true, - canRedactOther = false, - canSendMessage = true, - canSendReaction = true, + userEventPermissions = aUserEventPermissions( + canRedactOwn = true, + canRedactOther = false, + canSendMessage = true, + canSendReaction = true, + canPinUnpin = true, + ) ) ) val successState = awaitItem() @@ -652,6 +801,7 @@ class ActionListPresenterTest { TimelineItemAction.Reply, TimelineItemAction.Edit, TimelineItemAction.EndPoll, + TimelineItemAction.Pin, TimelineItemAction.CopyLink, TimelineItemAction.Redact, ) @@ -662,7 +812,7 @@ class ActionListPresenterTest { @Test fun `present - compute for non-editable poll message`() = runTest { - val presenter = createActionListPresenter(isDeveloperModeEnabled = false) + val presenter = createActionListPresenter(isDeveloperModeEnabled = false, isPinFeatureEnabled = true) moleculeFlow(RecompositionMode.Immediate) { presenter.present() }.test { @@ -675,10 +825,13 @@ class ActionListPresenterTest { initialState.eventSink.invoke( ActionListEvents.ComputeForMessage( event = messageEvent, - canRedactOwn = true, - canRedactOther = false, - canSendMessage = true, - canSendReaction = true, + userEventPermissions = aUserEventPermissions( + canRedactOwn = true, + canRedactOther = false, + canSendMessage = true, + canSendReaction = true, + canPinUnpin = true + ) ) ) val successState = awaitItem() @@ -689,6 +842,7 @@ class ActionListPresenterTest { actions = persistentListOf( TimelineItemAction.Reply, TimelineItemAction.EndPoll, + TimelineItemAction.Pin, TimelineItemAction.CopyLink, TimelineItemAction.Redact, ) @@ -699,7 +853,7 @@ class ActionListPresenterTest { @Test fun `present - compute for ended poll message`() = runTest { - val presenter = createActionListPresenter(isDeveloperModeEnabled = false) + val presenter = createActionListPresenter(isDeveloperModeEnabled = false, isPinFeatureEnabled = true) moleculeFlow(RecompositionMode.Immediate) { presenter.present() }.test { @@ -712,10 +866,13 @@ class ActionListPresenterTest { initialState.eventSink.invoke( ActionListEvents.ComputeForMessage( event = messageEvent, - canRedactOwn = true, - canRedactOther = false, - canSendMessage = true, - canSendReaction = true, + userEventPermissions = aUserEventPermissions( + canRedactOwn = true, + canRedactOther = false, + canSendMessage = true, + canSendReaction = true, + canPinUnpin = true, + ) ) ) val successState = awaitItem() @@ -725,6 +882,7 @@ class ActionListPresenterTest { displayEmojiReactions = true, actions = persistentListOf( TimelineItemAction.Reply, + TimelineItemAction.Pin, TimelineItemAction.CopyLink, TimelineItemAction.Redact, ) @@ -735,22 +893,26 @@ class ActionListPresenterTest { @Test fun `present - compute for voice message`() = runTest { - val presenter = createActionListPresenter(isDeveloperModeEnabled = false) + val presenter = createActionListPresenter(isDeveloperModeEnabled = false, isPinFeatureEnabled = true) moleculeFlow(RecompositionMode.Immediate) { presenter.present() }.test { val initialState = awaitItem() val messageEvent = aMessageEvent( isMine = true, + isEditable = false, content = aTimelineItemVoiceContent(), ) initialState.eventSink.invoke( ActionListEvents.ComputeForMessage( event = messageEvent, - canRedactOwn = true, - canRedactOther = false, - canSendMessage = true, - canSendReaction = true, + userEventPermissions = aUserEventPermissions( + canRedactOwn = true, + canRedactOther = false, + canSendMessage = true, + canSendReaction = true, + canPinUnpin = true + ) ) ) val successState = awaitItem() @@ -761,6 +923,7 @@ class ActionListPresenterTest { actions = persistentListOf( TimelineItemAction.Reply, TimelineItemAction.Forward, + TimelineItemAction.Pin, TimelineItemAction.CopyLink, TimelineItemAction.Redact, ) @@ -771,7 +934,7 @@ class ActionListPresenterTest { @Test fun `present - compute for call notify`() = runTest { - val presenter = createActionListPresenter(isDeveloperModeEnabled = true) + val presenter = createActionListPresenter(isDeveloperModeEnabled = true, isPinFeatureEnabled = true) moleculeFlow(RecompositionMode.Immediate) { presenter.present() }.test { @@ -783,10 +946,12 @@ class ActionListPresenterTest { initialState.eventSink.invoke( ActionListEvents.ComputeForMessage( event = messageEvent, - canRedactOwn = true, - canRedactOther = false, - canSendMessage = true, - canSendReaction = true, + userEventPermissions = aUserEventPermissions( + canRedactOwn = true, + canRedactOther = false, + canSendMessage = true, + canSendReaction = true, + ) ) ) val successState = awaitItem() @@ -803,7 +968,20 @@ class ActionListPresenterTest { } } -private fun createActionListPresenter(isDeveloperModeEnabled: Boolean): ActionListPresenter { +private fun createActionListPresenter( + isDeveloperModeEnabled: Boolean, + isPinFeatureEnabled: Boolean, + room: MatrixRoom = FakeMatrixRoom(), +): ActionListPresenter { val preferencesStore = InMemoryAppPreferencesStore(isDeveloperModeEnabled = isDeveloperModeEnabled) - return ActionListPresenter(appPreferencesStore = preferencesStore) + val featureFlagsService = FakeFeatureFlagService( + initialState = mapOf( + FeatureFlags.PinnedEvents.key to isPinFeatureEnabled, + ) + ) + return ActionListPresenter( + appPreferencesStore = preferencesStore, + featureFlagsService = featureFlagsService, + room = room + ) } diff --git a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/fixtures/MessageEventFixtures.kt b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/fixtures/MessageEventFixtures.kt index 7f2c3cfbeb..ca805d44c7 100644 --- a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/fixtures/MessageEventFixtures.kt +++ b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/fixtures/MessageEventFixtures.kt @@ -42,6 +42,7 @@ internal fun aMessageEvent( transactionId: TransactionId? = null, isMine: Boolean = true, isEditable: Boolean = true, + canBeRepliedTo: Boolean = true, content: TimelineItemEventContent = TimelineItemTextContent(body = A_MESSAGE, htmlDocument = null, formattedBody = null, isEdited = false), inReplyTo: InReplyToDetails? = null, isThreaded: Boolean = false, @@ -58,6 +59,7 @@ internal fun aMessageEvent( sentTime = "", isMine = isMine, isEditable = isEditable, + canBeRepliedTo = canBeRepliedTo, reactionsState = aTimelineItemReactions(count = 0), readReceiptState = TimelineItemReadReceipts(emptyList().toImmutableList()), localSendState = sendState, diff --git a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/pinned/banner/PinnedMessagesBannerPresenterTest.kt b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/pinned/banner/PinnedMessagesBannerPresenterTest.kt new file mode 100644 index 0000000000..1ae4729a40 --- /dev/null +++ b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/pinned/banner/PinnedMessagesBannerPresenterTest.kt @@ -0,0 +1,203 @@ +/* + * 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 + * + * https://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.pinned.banner + +import com.google.common.truth.Truth.assertThat +import io.element.android.features.networkmonitor.api.NetworkMonitor +import io.element.android.features.networkmonitor.test.FakeNetworkMonitor +import io.element.android.libraries.eventformatter.test.FakePinnedMessagesBannerFormatter +import io.element.android.libraries.matrix.api.room.MatrixRoom +import io.element.android.libraries.matrix.api.timeline.MatrixTimelineItem +import io.element.android.libraries.matrix.test.AN_EVENT_ID +import io.element.android.libraries.matrix.test.AN_EVENT_ID_2 +import io.element.android.libraries.matrix.test.room.FakeMatrixRoom +import io.element.android.libraries.matrix.test.room.aRoomInfo +import io.element.android.libraries.matrix.test.timeline.FakeTimeline +import io.element.android.libraries.matrix.test.timeline.aMessageContent +import io.element.android.libraries.matrix.test.timeline.anEventTimelineItem +import io.element.android.tests.testutils.test +import io.element.android.tests.testutils.testCoroutineDispatchers +import kotlinx.coroutines.flow.flowOf +import kotlinx.coroutines.test.TestScope +import kotlinx.coroutines.test.runTest +import org.junit.Test + +class PinnedMessagesBannerPresenterTest { + @Test + fun `present - initial state`() = runTest { + val presenter = createPinnedMessagesBannerPresenter(isFeatureEnabled = true) + presenter.test { + val initialState = awaitItem() + assertThat(initialState).isEqualTo(PinnedMessagesBannerState.Hidden) + cancelAndIgnoreRemainingEvents() + } + } + + @Test + fun `present - feature disabled`() = runTest { + val presenter = createPinnedMessagesBannerPresenter(isFeatureEnabled = false) + presenter.test { + val initialState = awaitItem() + assertThat(initialState).isEqualTo(PinnedMessagesBannerState.Hidden) + } + } + + @Test + fun `present - loading state`() = runTest { + val room = FakeMatrixRoom( + pinnedEventsTimelineResult = { Result.success(FakeTimeline()) } + ).apply { + givenRoomInfo(aRoomInfo(pinnedEventIds = listOf(AN_EVENT_ID))) + } + val presenter = createPinnedMessagesBannerPresenter(room = room) + presenter.test { + skipItems(1) + val loadingState = awaitItem() + assertThat(loadingState).isEqualTo(PinnedMessagesBannerState.Loading(1)) + assertThat(loadingState.pinnedMessagesCount()).isEqualTo(1) + assertThat(loadingState.currentPinnedMessageIndex()).isEqualTo(0) + } + } + + @Test + fun `present - loaded state`() = runTest { + val messageContent = aMessageContent("A message") + val pinnedEventsTimeline = FakeTimeline( + timelineItems = flowOf( + listOf( + MatrixTimelineItem.Event( + uniqueId = "FAKE_UNIQUE_ID", + event = anEventTimelineItem( + eventId = AN_EVENT_ID, + content = messageContent, + ), + ) + ) + ) + ) + val room = FakeMatrixRoom( + pinnedEventsTimelineResult = { Result.success(pinnedEventsTimeline) } + ).apply { + givenRoomInfo(aRoomInfo(pinnedEventIds = listOf(AN_EVENT_ID, AN_EVENT_ID_2))) + } + val presenter = createPinnedMessagesBannerPresenter(room = room) + presenter.test { + skipItems(2) + val loadedState = awaitItem() as PinnedMessagesBannerState.Loaded + assertThat(loadedState.currentPinnedMessageIndex).isEqualTo(0) + assertThat(loadedState.loadedPinnedMessagesCount).isEqualTo(1) + assertThat(loadedState.currentPinnedMessage.formatted.text).isEqualTo(messageContent.toString()) + } + } + + @Test + fun `present - loaded state - multiple pinned messages`() = runTest { + val messageContent1 = aMessageContent("A message") + val messageContent2 = aMessageContent("Another message") + val pinnedEventsTimeline = FakeTimeline( + timelineItems = flowOf( + listOf( + MatrixTimelineItem.Event( + uniqueId = "FAKE_UNIQUE_ID", + event = anEventTimelineItem( + eventId = AN_EVENT_ID, + content = messageContent1, + ), + ), + MatrixTimelineItem.Event( + uniqueId = "FAKE_UNIQUE_ID_2", + event = anEventTimelineItem( + eventId = AN_EVENT_ID_2, + content = messageContent2, + ), + ) + ) + ) + ) + val room = FakeMatrixRoom( + pinnedEventsTimelineResult = { Result.success(pinnedEventsTimeline) } + ).apply { + givenRoomInfo(aRoomInfo(pinnedEventIds = listOf(AN_EVENT_ID, AN_EVENT_ID_2))) + } + val presenter = createPinnedMessagesBannerPresenter(room = room) + presenter.test { + skipItems(2) + awaitItem().also { loadedState -> + loadedState as PinnedMessagesBannerState.Loaded + assertThat(loadedState.currentPinnedMessageIndex).isEqualTo(1) + assertThat(loadedState.loadedPinnedMessagesCount).isEqualTo(2) + assertThat(loadedState.currentPinnedMessage.formatted.text).isEqualTo(messageContent2.toString()) + loadedState.eventSink(PinnedMessagesBannerEvents.MoveToNextPinned) + } + + awaitItem().also { loadedState -> + loadedState as PinnedMessagesBannerState.Loaded + assertThat(loadedState.currentPinnedMessageIndex).isEqualTo(0) + assertThat(loadedState.loadedPinnedMessagesCount).isEqualTo(2) + assertThat(loadedState.currentPinnedMessage.formatted.text).isEqualTo(messageContent1.toString()) + loadedState.eventSink(PinnedMessagesBannerEvents.MoveToNextPinned) + } + + awaitItem().also { loadedState -> + loadedState as PinnedMessagesBannerState.Loaded + assertThat(loadedState.currentPinnedMessageIndex).isEqualTo(1) + assertThat(loadedState.loadedPinnedMessagesCount).isEqualTo(2) + assertThat(loadedState.currentPinnedMessage.formatted.text).isEqualTo(messageContent2.toString()) + } + } + } + + @Test + fun `present - timeline failed`() = runTest { + val room = FakeMatrixRoom( + pinnedEventsTimelineResult = { Result.failure(Exception()) } + ).apply { + givenRoomInfo(aRoomInfo(pinnedEventIds = listOf(AN_EVENT_ID))) + } + val presenter = createPinnedMessagesBannerPresenter(room = room) + presenter.test { + skipItems(1) + awaitItem().also { loadingState -> + assertThat(loadingState).isEqualTo(PinnedMessagesBannerState.Loading(1)) + assertThat(loadingState.pinnedMessagesCount()).isEqualTo(1) + assertThat(loadingState.currentPinnedMessageIndex()).isEqualTo(0) + } + awaitItem().also { failedState -> + assertThat(failedState).isEqualTo(PinnedMessagesBannerState.Hidden) + } + } + } + + private fun TestScope.createPinnedMessagesBannerPresenter( + room: MatrixRoom = FakeMatrixRoom(), + itemFactory: PinnedMessagesBannerItemFactory = PinnedMessagesBannerItemFactory( + coroutineDispatchers = testCoroutineDispatchers(), + formatter = FakePinnedMessagesBannerFormatter( + formatLambda = { event -> "${event.content}" } + ) + ), + networkMonitor: NetworkMonitor = FakeNetworkMonitor(), + isFeatureEnabled: Boolean = true, + ): PinnedMessagesBannerPresenter { + return PinnedMessagesBannerPresenter( + room = room, + itemFactory = itemFactory, + isFeatureEnabled = { isFeatureEnabled }, + networkMonitor = networkMonitor, + ) + } +} diff --git a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/pinned/banner/PinnedMessagesBannerViewTest.kt b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/pinned/banner/PinnedMessagesBannerViewTest.kt new file mode 100644 index 0000000000..ed23bdfb84 --- /dev/null +++ b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/pinned/banner/PinnedMessagesBannerViewTest.kt @@ -0,0 +1,87 @@ +/* + * 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 + * + * https://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.pinned.banner + +import androidx.activity.ComponentActivity +import androidx.compose.ui.test.junit4.AndroidComposeTestRule +import androidx.compose.ui.test.junit4.createAndroidComposeRule +import androidx.compose.ui.test.onRoot +import androidx.compose.ui.test.performClick +import androidx.test.ext.junit.runners.AndroidJUnit4 +import io.element.android.libraries.matrix.api.core.EventId +import io.element.android.libraries.ui.strings.CommonStrings +import io.element.android.tests.testutils.EnsureNeverCalled +import io.element.android.tests.testutils.EnsureNeverCalledWithParam +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 org.junit.Rule +import org.junit.Test +import org.junit.rules.TestRule +import org.junit.runner.RunWith + +@RunWith(AndroidJUnit4::class) +class PinnedMessagesBannerViewTest { + @get:Rule val rule = createAndroidComposeRule() + + @Test + fun `clicking on the banner invoke expected callback`() { + val eventsRecorder = EventsRecorder() + val state = aLoadedPinnedMessagesBannerState( + eventSink = eventsRecorder + ) + val pinnedEventId = state.currentPinnedMessage.eventId + ensureCalledOnceWithParam(pinnedEventId) { callback -> + rule.setPinnedMessagesBannerView( + state = state, + onClick = callback + ) + rule.onRoot().performClick() + eventsRecorder.assertSingle(PinnedMessagesBannerEvents.MoveToNextPinned) + } + } + + @Test + fun `clicking on view all emit the expected event`() { + val eventsRecorder = EventsRecorder(expectEvents = true) + val state = aLoadedPinnedMessagesBannerState( + eventSink = eventsRecorder + ) + ensureCalledOnce { callback -> + rule.setPinnedMessagesBannerView( + state = state, + onViewAllClick = callback + ) + rule.clickOn(CommonStrings.screen_room_pinned_banner_view_all_button_title) + } + } +} + +private fun AndroidComposeTestRule.setPinnedMessagesBannerView( + state: PinnedMessagesBannerState, + onClick: (EventId) -> Unit = EnsureNeverCalledWithParam(), + onViewAllClick: () -> Unit = EnsureNeverCalled(), +) { + setContent { + PinnedMessagesBannerView( + state = state, + onClick = onClick, + onViewAllClick = onViewAllClick + ) + } +} diff --git a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/timeline/TimelinePresenterTest.kt b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/timeline/TimelinePresenterTest.kt index 5a171227e7..90c71a964a 100644 --- a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/timeline/TimelinePresenterTest.kt +++ b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/timeline/TimelinePresenterTest.kt @@ -75,6 +75,7 @@ import kotlinx.coroutines.test.runTest import org.junit.Rule import org.junit.Test import java.util.Date +import kotlin.time.Duration import kotlin.time.Duration.Companion.seconds private const val FAKE_UNIQUE_ID = "FAKE_UNIQUE_ID" @@ -496,6 +497,10 @@ private const val FAKE_UNIQUE_ID_2 = "FAKE_UNIQUE_ID_2" }.test { val initialState = awaitFirstItem() initialState.eventSink.invoke(TimelineEvents.FocusOnEvent(AN_EVENT_ID)) + awaitItem().also { state -> + assertThat(state.focusedEventId).isEqualTo(AN_EVENT_ID) + assertThat(state.focusRequestState).isEqualTo(FocusRequestState.Requested(AN_EVENT_ID, Duration.ZERO)) + } awaitItem().also { state -> assertThat(state.focusedEventId).isEqualTo(AN_EVENT_ID) assertThat(state.focusRequestState).isEqualTo(FocusRequestState.Loading(AN_EVENT_ID)) @@ -541,6 +546,10 @@ private const val FAKE_UNIQUE_ID_2 = "FAKE_UNIQUE_ID_2" }.test { val initialState = awaitFirstItem() initialState.eventSink.invoke(TimelineEvents.FocusOnEvent(AN_EVENT_ID)) + awaitItem().also { state -> + assertThat(state.focusedEventId).isEqualTo(AN_EVENT_ID) + assertThat(state.focusRequestState).isEqualTo(FocusRequestState.Requested(AN_EVENT_ID, Duration.ZERO)) + } awaitItem().also { state -> assertThat(state.focusedEventId).isEqualTo(AN_EVENT_ID) assertThat(state.focusRequestState).isEqualTo(FocusRequestState.Success(AN_EVENT_ID, 0)) @@ -564,6 +573,10 @@ private const val FAKE_UNIQUE_ID_2 = "FAKE_UNIQUE_ID_2" }.test { val initialState = awaitFirstItem() initialState.eventSink(TimelineEvents.FocusOnEvent(AN_EVENT_ID)) + awaitItem().also { state -> + assertThat(state.focusedEventId).isEqualTo(AN_EVENT_ID) + assertThat(state.focusRequestState).isEqualTo(FocusRequestState.Requested(AN_EVENT_ID, Duration.ZERO)) + } awaitItem().also { state -> assertThat(state.focusedEventId).isEqualTo(AN_EVENT_ID) assertThat(state.focusRequestState).isEqualTo(FocusRequestState.Loading(AN_EVENT_ID)) diff --git a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/timeline/groups/TimelineItemGrouperTest.kt b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/timeline/groups/TimelineItemGrouperTest.kt index ce53e05090..e044ac7e2b 100644 --- a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/timeline/groups/TimelineItemGrouperTest.kt +++ b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/timeline/groups/TimelineItemGrouperTest.kt @@ -46,6 +46,7 @@ class TimelineItemGrouperTest { readReceiptState = TimelineItemReadReceipts(emptyList().toImmutableList()), localSendState = LocalEventSendState.Sent(AN_EVENT_ID), isEditable = false, + canBeRepliedTo = false, inReplyTo = null, isThreaded = false, debugInfo = aTimelineItemDebugInfo(), diff --git a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/voicemessages/timeline/RedactedVoiceMessageManagerTest.kt b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/voicemessages/timeline/RedactedVoiceMessageManagerTest.kt index 4cabc6450a..2a54edad58 100644 --- a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/voicemessages/timeline/RedactedVoiceMessageManagerTest.kt +++ b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/voicemessages/timeline/RedactedVoiceMessageManagerTest.kt @@ -85,6 +85,7 @@ fun aRedactedMatrixTimeline(eventId: EventId) = listOf( eventId = eventId, transactionId = null, isEditable = false, + canBeRepliedTo = false, isLocal = false, isOwn = false, isRemote = false, diff --git a/features/onboarding/impl/src/main/res/values-pt-rBR/translations.xml b/features/onboarding/impl/src/main/res/values-pt-rBR/translations.xml index 04a26fe212..965c66c78c 100644 --- a/features/onboarding/impl/src/main/res/values-pt-rBR/translations.xml +++ b/features/onboarding/impl/src/main/res/values-pt-rBR/translations.xml @@ -5,4 +5,5 @@ "Criar conta" "Bem-vindo ao mais rápido %1$s de todos os tempos. Turbinado para velocidade e simplicidade." "Bem-vindo ao %1$s. Turbinado, para velocidade e simplicidade" + "Esteja no seu elemento" diff --git a/features/onboarding/impl/src/main/res/values-uz/translations.xml b/features/onboarding/impl/src/main/res/values-uz/translations.xml new file mode 100644 index 0000000000..b69af4adb7 --- /dev/null +++ b/features/onboarding/impl/src/main/res/values-uz/translations.xml @@ -0,0 +1,9 @@ + + + "Qo\'lda tizimga kiring" + "QR kod bilan tizimga kiring" + "Hisob yaratish" + "Eng tezkor %1$sga xush kelibsiz. Tezlik va oddylik uchun super zaryadlangan." + "%1$sga Xush kelibsiz. Tezlik va oddylik uchun o\'ta zaryadlangan." + "Elementingizda bo\'ling" + diff --git a/features/poll/impl/src/main/res/values-pt-rBR/translations.xml b/features/poll/impl/src/main/res/values-pt-rBR/translations.xml index 058dab7d42..90720720cd 100644 --- a/features/poll/impl/src/main/res/values-pt-rBR/translations.xml +++ b/features/poll/impl/src/main/res/values-pt-rBR/translations.xml @@ -7,6 +7,12 @@ "Pergunta ou tópico" "Sobre o que é a enquete?" "Criar enquete" + "Tem certeza de que quer deletar esta enquete?" "Excluir Enquete" "Editar enquete" + "Não foi possível encontrar nenhuma enquete em andamento." + "Não foi possível encontrar nenhuma enquete anterior." + "Em andamento" + "Anteriores" + "Enquetes" diff --git a/features/poll/impl/src/main/res/values-uz/translations.xml b/features/poll/impl/src/main/res/values-uz/translations.xml new file mode 100644 index 0000000000..ee41d67459 --- /dev/null +++ b/features/poll/impl/src/main/res/values-uz/translations.xml @@ -0,0 +1,11 @@ + + + "Variant qo\'shish" + "Natijalarni faqat soʻrov tugagandan keyin koʻrsatish" + "Ovozlarni yashirish" + "Variant%1$d" + "Savol yoki mavzu" + "So\'rovnoma nima haqida?" + "So‘rovnoma yaratish" + "So‘rovnomani tahrirlash" + diff --git a/features/preferences/impl/build.gradle.kts b/features/preferences/impl/build.gradle.kts index ead4515360..ec265d739e 100644 --- a/features/preferences/impl/build.gradle.kts +++ b/features/preferences/impl/build.gradle.kts @@ -90,6 +90,7 @@ dependencies { testImplementation(projects.features.ftue.test) testImplementation(projects.features.rageshake.test) testImplementation(projects.features.rageshake.impl) + testImplementation(projects.features.logout.test) testImplementation(projects.features.roomlist.test) testImplementation(projects.libraries.indicator.impl) testImplementation(projects.libraries.pushproviders.test) diff --git a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/developer/DeveloperSettingsEvents.kt b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/developer/DeveloperSettingsEvents.kt index 58f7ac7c02..bb0252e04d 100644 --- a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/developer/DeveloperSettingsEvents.kt +++ b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/developer/DeveloperSettingsEvents.kt @@ -21,5 +21,6 @@ import io.element.android.libraries.featureflag.ui.model.FeatureUiModel sealed interface DeveloperSettingsEvents { data class UpdateEnabledFeature(val feature: FeatureUiModel, val isEnabled: Boolean) : DeveloperSettingsEvents data class SetCustomElementCallBaseUrl(val baseUrl: String?) : DeveloperSettingsEvents + data class SetSimplifiedSlidingSyncEnabled(val isEnabled: Boolean) : DeveloperSettingsEvents data object ClearCache : DeveloperSettingsEvents } diff --git a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/developer/DeveloperSettingsPresenter.kt b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/developer/DeveloperSettingsPresenter.kt index 8295b815c9..7b95463ac8 100644 --- a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/developer/DeveloperSettingsPresenter.kt +++ b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/developer/DeveloperSettingsPresenter.kt @@ -28,6 +28,7 @@ import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.snapshots.SnapshotStateMap import io.element.android.appconfig.ElementCallConfig +import io.element.android.features.logout.api.LogoutUseCase import io.element.android.features.preferences.impl.tasks.ClearCacheUseCase import io.element.android.features.preferences.impl.tasks.ComputeCacheSizeUseCase import io.element.android.features.rageshake.api.preferences.RageshakePreferencesPresenter @@ -55,6 +56,7 @@ class DeveloperSettingsPresenter @Inject constructor( private val rageshakePresenter: RageshakePreferencesPresenter, private val appPreferencesStore: AppPreferencesStore, private val buildMeta: BuildMeta, + private val logoutUseCase: LogoutUseCase, ) : Presenter { @Composable override fun present(): DeveloperSettingsState { @@ -75,6 +77,9 @@ class DeveloperSettingsPresenter @Inject constructor( val customElementCallBaseUrl by appPreferencesStore .getCustomElementCallBaseUrlFlow() .collectAsState(initial = null) + val isSimplifiedSlidingSyncEnabled by appPreferencesStore + .isSimplifiedSlidingSyncEnabledFlow() + .collectAsState(initial = false) LaunchedEffect(Unit) { FeatureFlags.entries @@ -114,6 +119,10 @@ class DeveloperSettingsPresenter @Inject constructor( appPreferencesStore.setCustomElementCallBaseUrl(urlToSave) } DeveloperSettingsEvents.ClearCache -> coroutineScope.clearCache(clearCacheAction) + is DeveloperSettingsEvents.SetSimplifiedSlidingSyncEnabled -> coroutineScope.launch { + appPreferencesStore.setSimplifiedSlidingSyncEnabled(event.isEnabled) + logoutUseCase.logout(ignoreSdkError = true) + } } } @@ -127,6 +136,7 @@ class DeveloperSettingsPresenter @Inject constructor( defaultUrl = ElementCallConfig.DEFAULT_BASE_URL, validator = ::customElementCallUrlValidator, ), + isSimpleSlidingSyncEnabled = isSimplifiedSlidingSyncEnabled, eventSink = ::handleEvents ) } diff --git a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/developer/DeveloperSettingsState.kt b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/developer/DeveloperSettingsState.kt index 9a12823686..91cf7051c3 100644 --- a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/developer/DeveloperSettingsState.kt +++ b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/developer/DeveloperSettingsState.kt @@ -27,6 +27,7 @@ data class DeveloperSettingsState( val rageshakeState: RageshakePreferencesState, val clearCacheAction: AsyncData, val customElementCallBaseUrlState: CustomElementCallBaseUrlState, + val isSimpleSlidingSyncEnabled: Boolean, val eventSink: (DeveloperSettingsEvents) -> Unit ) diff --git a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/developer/DeveloperSettingsStateProvider.kt b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/developer/DeveloperSettingsStateProvider.kt index fb93a63ffc..01c2971777 100644 --- a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/developer/DeveloperSettingsStateProvider.kt +++ b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/developer/DeveloperSettingsStateProvider.kt @@ -39,6 +39,7 @@ open class DeveloperSettingsStateProvider : PreviewParameterProvider = AsyncData.Uninitialized, customElementCallBaseUrlState: CustomElementCallBaseUrlState = aCustomElementCallBaseUrlState(), + isSimplifiedSlidingSyncEnabled: Boolean = false, eventSink: (DeveloperSettingsEvents) -> Unit = {}, ) = DeveloperSettingsState( features = aFeatureUiModelList(), @@ -46,6 +47,7 @@ fun aDeveloperSettingsState( cacheSize = AsyncData.Success("1.2 MB"), clearCacheAction = clearCacheAction, customElementCallBaseUrlState = customElementCallBaseUrlState, + isSimpleSlidingSyncEnabled = isSimplifiedSlidingSyncEnabled, eventSink = eventSink, ) 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 dd684fcaaa..f46637e6cb 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 @@ -26,6 +26,7 @@ import io.element.android.features.preferences.impl.R import io.element.android.features.rageshake.api.preferences.RageshakePreferencesView import io.element.android.libraries.designsystem.components.preferences.PreferenceCategory import io.element.android.libraries.designsystem.components.preferences.PreferencePage +import io.element.android.libraries.designsystem.components.preferences.PreferenceSwitch import io.element.android.libraries.designsystem.components.preferences.PreferenceText import io.element.android.libraries.designsystem.components.preferences.PreferenceTextField import io.element.android.libraries.designsystem.preview.ElementPreview @@ -60,6 +61,14 @@ fun DeveloperSettingsView( title = "Configure tracing", onClick = onOpenConfigureTracing, ) + PreferenceSwitch( + title = "Enable Simplified Sliding Sync", + subtitle = "When toggled you'll be logged out of the app and will need to log in again.", + isChecked = state.isSimpleSlidingSyncEnabled, + onCheckedChange = { + state.eventSink(DeveloperSettingsEvents.SetSimplifiedSlidingSyncEnabled(it)) + } + ) } PreferenceCategory(title = "Showkase") { PreferenceText( diff --git a/features/preferences/impl/src/main/res/values-pl/translations.xml b/features/preferences/impl/src/main/res/values-pl/translations.xml index 021d7595f1..6bc66cd63c 100644 --- a/features/preferences/impl/src/main/res/values-pl/translations.xml +++ b/features/preferences/impl/src/main/res/values-pl/translations.xml @@ -3,22 +3,29 @@ "Upewnij się, że nie pominiesz żadnego połączenia. Zmień swoje ustawienia i zezwól na powiadomienia na blokadzie ekranu." "Popraw jakość swoich rozmów" "Wybierz sposób otrzymywania powiadomień" - "Tryb dewelopera" + "Tryb programisty" "Włącz, aby uzyskać dostęp do funkcji dla deweloperów." "Własny bazowy URL dla połączeń Element" "Ustaw własny bazowy URL dla połączeń Element" "Nieprawidłowy adres URL, upewnij się, że zawiera protokół (http/https) i poprawny adres." + "Dostawca powiadomień push" "Wyłącz edytor tekstu bogatego, aby pisać tekst Markdown ręcznie." + "Potwierdzenia odczytania" + "Gdy wyłączona, Twoje potwierdzenia odczytania nie zostaną wysłane. Potwierdzenia od innych wciąż będą odbierane." + "Udostępnij obecność" + "Gdy wyłączona, nie będziesz mógł wysyłać lub odbierać potwierdzeń odczytu ani powiadomień pisania." "Włącz opcję, aby wyświetlić źródło wiadomości na osi czasu." + "Nie blokujesz żadnych użytkowników" "Odblokuj" "Będziesz mógł ponownie zobaczyć wszystkie wiadomości od tego użytkownika." "Odblokuj użytkownika" + "Odblokowuję…" "Wyświetlana nazwa" "Twoja wyświetlana nazwa" "Wystąpił nieznany błąd przez co nie można było zmienić informacji." "Nie można zaktualizować profilu" "Edytuj profil" - "Aktualizowanie profilu…" + "Aktualizuję profil…" "Dodatkowe ustawienia" "Połączenia audio i wideo" "Niezgodność konfiguracji" @@ -46,4 +53,6 @@ Niektóre ustawienia mogą ulec zmianie, jeśli kontynuujesz." "ustawienia systemowe" "Powiadomienia systemowe wyłączone" "Powiadomienia" + "Rozwiązywanie problemów" + "Powiadomienia rozwiązywania problemów" diff --git a/features/preferences/impl/src/main/res/values-pt-rBR/translations.xml b/features/preferences/impl/src/main/res/values-pt-rBR/translations.xml index 2aa9704981..6255c7c2c9 100644 --- a/features/preferences/impl/src/main/res/values-pt-rBR/translations.xml +++ b/features/preferences/impl/src/main/res/values-pt-rBR/translations.xml @@ -3,10 +3,18 @@ "Escolha como receber notificações" "Modo de desenvolvedor" "Habilite para ter acesso a recursos e funcionalidades para desenvolvedores." + "URL inválida, por favor verifique se o protocolo (http/https) e o endereço correto estão presentes." "Desative o editor de rich text para digitar Markdown manualmente." + "Confirmações de leitura" + "Se desligado, suas confirmações de leitura não serão enviadas para ninguém. Você ainda receberá confirmações de leitura de outros usuários." + "Compartilhar presença" + "Se desligado, você não poderá enviar ou receber confirmações de leitura ou notificações de digitação." + "Ativar a opção de visualizar o fonte da mensagem na linha do tempo." + "Você não tem usuários bloqueados" "Desbloquear" "Você poderá ver todas as mensagens deles novamente." "Desbloquear usuário" + "Desbloqueando…" "Nome de exibição" "Seu nome de exibição" "Um erro desconhecido foi encontrado e as informações não puderam ser alteradas." @@ -29,11 +37,13 @@ Se você continuar, algumas de suas configurações poderão mudar." "Ativar notificações neste dispositivo" "A configuração não foi corrigida, tente novamente." "Bate-papos em grupo" + "Convites" "Menções" "Todos" "Menções" "Me notifique para" "Notifique-me em @room" + "Para receber notificações, altere seu %1$s." "configurações do sistema" "Notificações do sistema desativadas" "Notificações" diff --git a/features/preferences/impl/src/main/res/values-sv/translations.xml b/features/preferences/impl/src/main/res/values-sv/translations.xml index a4ce5bc50c..aa765bc080 100644 --- a/features/preferences/impl/src/main/res/values-sv/translations.xml +++ b/features/preferences/impl/src/main/res/values-sv/translations.xml @@ -1,11 +1,14 @@ + "För att säkerställa att du aldrig missar ett viktigt samtal, ändra dina inställningar för att tillåta helskärmsmeddelanden när telefonen är låst." + "Förbättra din samtalsupplevelse" "Välj hur du vill ta emot aviseringar" "Utvecklarläge" "Aktivera för att ha tillgång till funktionalitet för utvecklare." "Anpassad bas-URL för Element Call" "Ange en anpassad bas-URL för Element Call." "Ogiltig URL, se till att du inkluderar protokollet (http/https) och rätt adress." + "Pushnotisleverantör" "Inaktivera rik-text-redigeraren för att skriva Markdown manuellt." "Läskvitton" "Om det är avstängt kommer dina läskvitton inte att skickas till någon. Du kommer fortfarande att få läskvitton från andra användare." diff --git a/features/preferences/impl/src/main/res/values-uk/translations.xml b/features/preferences/impl/src/main/res/values-uk/translations.xml index 0fdf2a67ad..8905fb3366 100644 --- a/features/preferences/impl/src/main/res/values-uk/translations.xml +++ b/features/preferences/impl/src/main/res/values-uk/translations.xml @@ -1,11 +1,13 @@ + "Щоб ніколи не пропустити важливий дзвінок, змініть налаштування, щоб увімкнути повноекранні сповіщення, коли телефон заблоковано." "Виберіть спосіб отримання сповіщень" "Режим розробника" "Увімкніть доступ до функцій і можливостей для розробників." "Користувацька URL-адреса Element Call" "Встановіть URL-адресу для Element Call." "Неправильна URL-адреса, будь ласка, переконайтеся, що ви вказали протокол (http/https) та правильну адресу." + "Постачальник push-сповіщень" "Вимкніть редактор розширеного тексту, щоб вводити Markdown вручну." "Читати журнали" "Якщо вимкнено, ваші сповіщення про прочитання нікому не надсилатимуться. Ви все одно отримуватимете сповіщення про прочитання від інших користувачів." @@ -50,4 +52,6 @@ "системні налаштування" "Системні сповіщення вимкнені" "Сповіщення" + "Усунення несправностей" + "Усунення неполадок сповіщень" diff --git a/features/preferences/impl/src/main/res/values-uz/translations.xml b/features/preferences/impl/src/main/res/values-uz/translations.xml new file mode 100644 index 0000000000..21104e4ab8 --- /dev/null +++ b/features/preferences/impl/src/main/res/values-uz/translations.xml @@ -0,0 +1,42 @@ + + + "Bildirishnomalarni qanday qabul qilishni tanlang" + "Dasturchi rejimi" + "Ishlab chiquvchilar uchun xususiyatlar va funksiyalarga kirishni yoqing." + "Maxsus element qo‘ng‘iroqlar bazasi URL manzili" + "Boy matn muharriri o\'chiring Markdown bilan qo\'lda yozish uchun" + "Blokdan chiqarish" + "Ulardan kelgan barcha xabarlarni yana koʻrishingiz mumkin boʻladi." + "Foydalanuvchini blokdan chiqarish" + "Ko\'rsatiladigan ism" + "Ismingizni ko\'rsating" + "Noma\'lum xatolik yuz berdi va ma\'lumotni o\'zgartirib bo\'lmadi." + "Profilni yangilab bo‘lmadi" + "Profilni tahrirlash" + "Profil yangilanmoqda…" + "Qo\'shimcha sozlamalar" + "Audio va video qo\'ng\'iroqlar" + "Konfiguratsiya mos kelmasligi" + "Variantlarni topishni osonlashtirish uchun bildirishnomalar sozlamalarini soddalashtirdik. Ilgari siz tanlagan baʼzi shaxsiy sozlamalar bu yerda koʻrsatilmaydi, lekin ular hali ham faol. + +Davom ettirsangiz, baʼzi sozlamalaringiz oʻzgarishi mumkin." + "To\'g\'ridan-to\'g\'ri suhbatlar" + "Har bir suhbat uchun moslashtirilgan sozlama" + "Bildirishnoma sozlamalarini yangilashda xatolik yuz berdi." + "Barcha xabarlar" + "Faqat eslatmalar va kalit so\'zlar" + "To\'g\'ridan-to\'g\'ri suhbats, menga xabar bering" + "Guruh suhbatlarida menga xabar bering" + "Ushbu qurilmada bildirishnomalarni yoqing" + "Konfiguratsiya tuzatilmadi, qayta urinib ko\'ring." + "Guruh suhbatlari" + "Eslatmalar" + "Hammasi" + "Eslatmalar" + "Menga xabar bering" + "Menga @room orqali xabar bering" + "Bildirishnomalarni olish uchun, iltimos, o\'zingizni %1$singizni o\'zgartiring." + "tizim sozlamalari" + "Tizim bildirishnomalari o\'chirilgan" + "Bildirishnomalar" + diff --git a/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/developer/DeveloperSettingsPresenterTest.kt b/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/developer/DeveloperSettingsPresenterTest.kt index 113125d950..9fb1c8b37f 100644 --- a/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/developer/DeveloperSettingsPresenterTest.kt +++ b/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/developer/DeveloperSettingsPresenterTest.kt @@ -21,6 +21,7 @@ import app.cash.molecule.moleculeFlow import app.cash.turbine.test import com.google.common.truth.Truth.assertThat import io.element.android.appconfig.ElementCallConfig +import io.element.android.features.logout.test.FakeLogoutUseCase import io.element.android.features.preferences.impl.tasks.FakeClearCacheUseCase import io.element.android.features.preferences.impl.tasks.FakeComputeCacheSizeUseCase import io.element.android.features.rageshake.impl.preferences.DefaultRageshakePreferencesPresenter @@ -35,6 +36,8 @@ import io.element.android.libraries.matrix.test.core.aBuildMeta import io.element.android.libraries.preferences.test.InMemoryAppPreferencesStore import io.element.android.tests.testutils.WarmUpRule import io.element.android.tests.testutils.awaitLastSequentialItem +import io.element.android.tests.testutils.lambda.lambdaRecorder +import kotlinx.coroutines.flow.first import kotlinx.coroutines.test.runTest import org.junit.Rule import org.junit.Test @@ -55,6 +58,7 @@ class DeveloperSettingsPresenterTest { assertThat(initialState.cacheSize).isEqualTo(AsyncData.Uninitialized) assertThat(initialState.customElementCallBaseUrlState).isNotNull() assertThat(initialState.customElementCallBaseUrlState.baseUrl).isNull() + assertThat(initialState.isSimpleSlidingSyncEnabled).isFalse() val loadedState = awaitItem() assertThat(loadedState.rageshakeState.isEnabled).isFalse() assertThat(loadedState.rageshakeState.isSupported).isTrue() @@ -160,6 +164,30 @@ class DeveloperSettingsPresenterTest { } } + @Test + fun `present - toggling simplified sliding sync changes the preferences and logs out the user`() = runTest { + val logoutCallRecorder = lambdaRecorder { "" } + val logoutUseCase = FakeLogoutUseCase(logoutLambda = logoutCallRecorder) + val preferences = InMemoryAppPreferencesStore() + val presenter = createDeveloperSettingsPresenter(preferencesStore = preferences, logoutUseCase = logoutUseCase) + moleculeFlow(RecompositionMode.Immediate) { + presenter.present() + }.test { + val initialState = awaitLastSequentialItem() + assertThat(initialState.isSimpleSlidingSyncEnabled).isFalse() + + initialState.eventSink(DeveloperSettingsEvents.SetSimplifiedSlidingSyncEnabled(true)) + assertThat(awaitItem().isSimpleSlidingSyncEnabled).isTrue() + assertThat(preferences.isSimplifiedSlidingSyncEnabledFlow().first()).isTrue() + logoutCallRecorder.assertions().isCalledOnce() + + initialState.eventSink(DeveloperSettingsEvents.SetSimplifiedSlidingSyncEnabled(false)) + assertThat(awaitItem().isSimpleSlidingSyncEnabled).isFalse() + assertThat(preferences.isSimplifiedSlidingSyncEnabledFlow().first()).isFalse() + logoutCallRecorder.assertions().isCalledExactly(times = 2) + } + } + private fun createDeveloperSettingsPresenter( featureFlagService: FakeFeatureFlagService = FakeFeatureFlagService(), cacheSizeUseCase: FakeComputeCacheSizeUseCase = FakeComputeCacheSizeUseCase(), @@ -167,6 +195,7 @@ class DeveloperSettingsPresenterTest { rageshakePresenter: DefaultRageshakePreferencesPresenter = DefaultRageshakePreferencesPresenter(FakeRageShake(), FakeRageshakeDataStore()), preferencesStore: InMemoryAppPreferencesStore = InMemoryAppPreferencesStore(), buildMeta: BuildMeta = aBuildMeta(), + logoutUseCase: FakeLogoutUseCase = FakeLogoutUseCase(logoutLambda = { "" }) ): DeveloperSettingsPresenter { return DeveloperSettingsPresenter( featureFlagService = featureFlagService, @@ -175,6 +204,7 @@ class DeveloperSettingsPresenterTest { rageshakePresenter = rageshakePresenter, appPreferencesStore = preferencesStore, buildMeta = buildMeta, + logoutUseCase = logoutUseCase, ) } } diff --git a/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/developer/DeveloperSettingsViewTest.kt b/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/developer/DeveloperSettingsViewTest.kt index 7288b76d3c..aa993c39bc 100644 --- a/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/developer/DeveloperSettingsViewTest.kt +++ b/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/developer/DeveloperSettingsViewTest.kt @@ -109,6 +109,19 @@ class DeveloperSettingsViewTest { rule.onNodeWithText("Clear cache").performClick() eventsRecorder.assertSingle(DeveloperSettingsEvents.ClearCache) } + + @Config(qualifiers = "h1500dp") + @Test + fun `clicking on the simplified sliding sync switch emits the expected event`() { + val eventsRecorder = EventsRecorder() + rule.setDeveloperSettingsView( + state = aDeveloperSettingsState( + eventSink = eventsRecorder + ), + ) + rule.onNodeWithText("Enable Simplified Sliding Sync").performClick() + eventsRecorder.assertSingle(DeveloperSettingsEvents.SetSimplifiedSlidingSyncEnabled(true)) + } } private fun AndroidComposeTestRule.setDeveloperSettingsView( diff --git a/features/rageshake/api/src/main/res/values-uz/translations.xml b/features/rageshake/api/src/main/res/values-uz/translations.xml new file mode 100644 index 0000000000..96032fd65f --- /dev/null +++ b/features/rageshake/api/src/main/res/values-uz/translations.xml @@ -0,0 +1,7 @@ + + + "%1$soxirgi marta ishlatilganda qulab tushdi. Biz bilan nosozlik hisobotini baham ko\'rmoqchimisiz?" + "Siz hafsalasi pir bo\'lib telefonni silkitayotganga o\'xshaysiz. Xatolar haqida hisobot ekranini ochmoqchimisiz?" + "G\'azablanish" + "Aniqlash chegarasi" + diff --git a/features/rageshake/impl/src/main/res/values-pl/translations.xml b/features/rageshake/impl/src/main/res/values-pl/translations.xml index 04bf123498..21e8ad69c6 100644 --- a/features/rageshake/impl/src/main/res/values-pl/translations.xml +++ b/features/rageshake/impl/src/main/res/values-pl/translations.xml @@ -1,12 +1,13 @@ - "Dołącz zrzut ekranu" + "Załącz zrzut ekranu" "Możecie skontaktować się ze mną, jeśli macie jakiekolwiek dodatkowe pytania." "Napisz do mnie" "Edytuj zrzut ekranu" "Opisz problem. Co zrobiłeś? Czego oczekiwałeś? Co się stało zamiast tego. Podaj jak najwięcej szczegółów." "Opisz problem…" "Jeśli to możliwe, napisz zgłoszenje w języku angielskim." + "Opis jest zbyt krótki, podaj więcej szczegółów na temat tego co się stało. Dzięki!" "Wyślij logi awarii" "Zezwól na logi" "Wyślij zrzut ekranu" diff --git a/features/rageshake/impl/src/main/res/values-pt-rBR/translations.xml b/features/rageshake/impl/src/main/res/values-pt-rBR/translations.xml index d046391f6a..885c9a6fe6 100644 --- a/features/rageshake/impl/src/main/res/values-pt-rBR/translations.xml +++ b/features/rageshake/impl/src/main/res/values-pt-rBR/translations.xml @@ -12,4 +12,5 @@ "Enviar captura de tela" "Os registros serão incluídos com sua mensagem para garantir que tudo esteja funcionando corretamente. Para enviar sua mensagem sem registros, desative essa configuração." "%1$s fechou inesperadamente na última vez que foi usado. Gostaria de compartilhar um relatório de falhas conosco?" + "Ver registros" diff --git a/features/rageshake/impl/src/main/res/values-uz/translations.xml b/features/rageshake/impl/src/main/res/values-uz/translations.xml new file mode 100644 index 0000000000..474c775cb0 --- /dev/null +++ b/features/rageshake/impl/src/main/res/values-uz/translations.xml @@ -0,0 +1,15 @@ + + + "Ekran tasvirini biriktirish" + "Agar sizda keyingi savollar bo\'lsa, men bilan bog\'lanishingiz mumkin." + "Men bilan bog\'laning" + "Ekran tasvirini tahrirlash" + "Iltimos, muammoni tasvirlab bering. Nima qildingiz? Nima bo\'lishini kutgan edingiz? Aslida nima bo\'ldi. Iltimos, iloji boricha batafsilroq ma\'lumot bering." + "Muammoni tasvirlab bering…" + "Iloji bo\'lsa, tavsifni ingliz tilida yozing." + "Buzilish jurnallarini yuboring" + "Jurnallarga ruxsat bering" + "Ekran tasvirini yuboring " + "Har bir narsa to\'ri ishlayotganiga ishonch hosil qilish uchun xabaringizga jurnallar kiritiladi. Xabarni jurnallarsiz yuborish uchun ushbu sozlamani oʻchiring." + "%1$soxirgi marta ishlatilganda qulab tushdi. Biz bilan nosozlik hisobotini baham ko\'rmoqchimisiz?" + diff --git a/features/roomaliasresolver/impl/src/main/res/values-pl/translations.xml b/features/roomaliasresolver/impl/src/main/res/values-pl/translations.xml new file mode 100644 index 0000000000..7f830ab944 --- /dev/null +++ b/features/roomaliasresolver/impl/src/main/res/values-pl/translations.xml @@ -0,0 +1,4 @@ + + + "Nie udało się uzyskać aliasu pokoju." + diff --git a/features/roomaliasresolver/impl/src/main/res/values-sv/translations.xml b/features/roomaliasresolver/impl/src/main/res/values-sv/translations.xml new file mode 100644 index 0000000000..8bcfb3f809 --- /dev/null +++ b/features/roomaliasresolver/impl/src/main/res/values-sv/translations.xml @@ -0,0 +1,4 @@ + + + "Misslyckades med att slå upp rumsalias." + diff --git a/features/roomaliasresolver/impl/src/main/res/values-uk/translations.xml b/features/roomaliasresolver/impl/src/main/res/values-uk/translations.xml new file mode 100644 index 0000000000..0f5d40f6d8 --- /dev/null +++ b/features/roomaliasresolver/impl/src/main/res/values-uk/translations.xml @@ -0,0 +1,4 @@ + + + "Не вдалося розв\'язати псевдонім кімнати." + diff --git a/features/roomdetails/impl/src/main/res/values-el/translations.xml b/features/roomdetails/impl/src/main/res/values-el/translations.xml index 2c1886ce40..57874ff30b 100644 --- a/features/roomdetails/impl/src/main/res/values-el/translations.xml +++ b/features/roomdetails/impl/src/main/res/values-el/translations.xml @@ -63,7 +63,7 @@ "Δεν θα μπορεί να συμμετέχει ξανά σε αυτό το δωμάτιο εάν προσκληθεί." "Θες σίγουρα να αποκλείσεις αυτό το μέλος;" "Δεν υπάρχουν αποκλεισμένοι χρήστες σε αυτό το δωμάτιο." - "Αποκλεισμός του χρήστη %1$s" + "Αποκλεισμός %1$s" "%1$d άτομο" "%1$d άτομα" diff --git a/features/roomdetails/impl/src/main/res/values-pl/translations.xml b/features/roomdetails/impl/src/main/res/values-pl/translations.xml index 569e167d92..80195a14ea 100644 --- a/features/roomdetails/impl/src/main/res/values-pl/translations.xml +++ b/features/roomdetails/impl/src/main/res/values-pl/translations.xml @@ -3,10 +3,41 @@ "Wystąpił błąd podczas aktualizacji ustawienia powiadomień." "Twój serwer domowy nie wspiera tej opcji w pokojach szyfrowanych, możesz nie otrzymać powiadomień z niektórych pokoi." "Ankiety" + "Tylko administratorzy" + "Banowanie osób" + "Usuwanie wiadomości" "Wszyscy" + "Zapraszanie osób" + "Moderacja członków" + "Wiadomości i zawartość" + "Administratorzy i moderatorzy" + "Usuwanie osób" + "Zmień awatar pokoju" + "Szczegóły pokoju" + "Zmień nazwę pokoju" + "Zmień temat pokoju" + "Wysyłanie wiadomości" + "Edytuj administratorów" + "Tej akcji nie będzie można cofnąć. Promujesz użytkownika, który będzie posiadał takie same uprawnienia jak Ty." + "Dodać administratora?" + "Zdegraduj" + "Nie będzie można cofnąć tej zmiany, jeśli się zdegradujesz. Jeśli jesteś ostatnim uprzywilejowanym użytkownikiem w pokoju, nie będziesz w stanie odzyskać uprawnień." + "Zdegradować siebie?" + "%1$s (Oczekujące)" + "(Oczekujący)" + "Administratorzy automatycznie mają uprawnienia moderatora" + "Edytuj moderatorów" + "Administratorzy" + "Moderatorzy" + "Członków" + "Masz niezapisane zmiany." + "Zapisać zmiany?" "Dodaj temat" "Jest już członkiem" "Już zaproszony" + "Szyfrowany" + "Nieszyfrowany" + "Pokój publiczny" "Edytuj pokój" "Wystąpił nieznany błąd i nie można było zmienić informacji." "Nie można zaktualizować pokoju" @@ -21,18 +52,40 @@ "Niestandardowy" "Domyślny" "Powiadomienia" + "Role i uprawnienia" "Nazwa pokoju" "Bezpieczeństwo" "Udostępnij pokój" + "Informacje pokoju" "Temat" "Aktualizuję pokój…" + "Zbanuj" + "Nie będą mogli ponownie dołączyć do tego pokoju, jeśli zostaną zaproszeni." + "Czy na pewno chcesz zbanować tego członka?" + "W tym pokoju nie ma zbanowanych użytkowników." + "Banowanie %1$s" "%1$d osoba" "%1$d osoby" "%1$d osób" + "Usuń i zbanuj członka" + "Usuń z pokoju" + "Usuń i zbanuj członka" + "Tylko usuń członka" + "Usunąć członka i zablokować możliwość dołączenia w przyszłości?" + "Odbanuj" + "Będą mogli ponownie dołączyć do tego pokoju, jeśli zostaną zaproszeni." + "Odbanuj użytkownika" + "Wyświetl profil" + "Zbanowanych" + "Członków" "Oczekiwanie" + "Usuwanie %1$s…" + "Administrator" + "Moderator" "Członkowie pokoju" + "Odbanowanie %1$s" "Zezwalaj na ustawienia niestandardowe" "Włączenie tej opcji nadpisze ustawienie domyślne" "Powiadamiaj mnie o tym czacie przez" @@ -47,4 +100,18 @@ "Wszystkie wiadomości" "Tylko wzmianki i słowa kluczowe" "W tym pokoju, powiadamiaj mnie przez" + "Administratorzy" + "Zmień moją rolę" + "Zdegraduj do członka" + "Zdegraduj do moderatora" + "Moderacja członków" + "Wiadomości i zawartość" + "Moderatorzy" + "Uprawnienia" + "Resetuj uprawnienia" + "Po zresetowaniu uprawnień utracisz bieżące ustawienia." + "Zresetować uprawnienia?" + "Role" + "Szczegóły pokoju" + "Role i uprawnienia" diff --git a/features/roomdetails/impl/src/main/res/values-pt-rBR/translations.xml b/features/roomdetails/impl/src/main/res/values-pt-rBR/translations.xml index 4989168201..f7e4d5f9e0 100644 --- a/features/roomdetails/impl/src/main/res/values-pt-rBR/translations.xml +++ b/features/roomdetails/impl/src/main/res/values-pt-rBR/translations.xml @@ -1,7 +1,29 @@ "Ocorreu um erro ao atualizar a configuração de notificação." + "Enquetes" + "Somente administradores" + "Banir pessoas" + "Remover mensagens" "Todos" + "Convidar pessoas" + "Moderação de membros" + "Mensagens e conteúdo" + "Administradores e moderadores" + "Remover pessoas" + "Alterar avatar da sala" + "Detalhes da sala" + "Alterar nome da sala" + "Alterar tópico da sala" + "Enviar mensagens" + "Editar administradores" + "Adicionar administrador?" + "Editar moderadores" + "Administradores" + "Moderadores" + "Membros" + "Você tem alterações não salvas." + "Salvar alterações?" "Adicionar tópico" "Já é membro" "Já foi convidado" @@ -19,17 +41,35 @@ "Personalizado" "Padrão" "Notificações" + "Cargos e permissões" "Nome da sala" "Segurança" "Compartilhar sala" "Tópico" "Atualizando a sala…" + "Banir" + "Tem certeza de que quer banir este membro?" + "Banindo %1$s" "%1$d pessoa" "%1$d pessoas" + "Remover e banir membro" + "Remover da sala" + "Remover e banir membro" + "Somente remover membro" + "Remover membro e banir de entrar novamente no futuro?" + "Desbanir" + "Desbanir usuário" + "Ver perfil" + "Banidos" + "Membros" "Pendente" + "Removendo %1$s…" + "Administrador" + "Moderador" "Membros da sala" + "Desbanindo %1$s" "Permitir configuração personalizada" "Ativar isso substituirá sua configuração padrão" "Me notifique nesta conversa para" @@ -43,4 +83,15 @@ "Todas as mensagens" "Somente menções e palavras-chave" "Nesta sala, notifique-me para" + "Administradores" + "Alterar meu cargo" + "Moderação de membros" + "Mensagens e conteúdo" + "Moderadores" + "Permissões" + "Redefinir permissões" + "Redefinir permissões?" + "Cargos" + "Detalhes da sala" + "Cargos e permissões" diff --git a/features/roomdetails/impl/src/main/res/values-sv/translations.xml b/features/roomdetails/impl/src/main/res/values-sv/translations.xml index aec11eed32..eed1cfcbb1 100644 --- a/features/roomdetails/impl/src/main/res/values-sv/translations.xml +++ b/features/roomdetails/impl/src/main/res/values-sv/translations.xml @@ -25,6 +25,7 @@ "Degradera dig själv?" "%1$s (Väntar)" "(Väntar)" + "Administratörer har automatiskt moderatorbehörighet" "Redigera moderatorer" "Administratörer" "Moderatorer" @@ -34,6 +35,9 @@ "Lägg till ämne" "Redan medlem" "Redan inbjuden" + "Krypterat" + "Inte krypterat" + "Offentligt rum" "Redigera rummet" "Ett okänt fel uppstod och informationen kunde inte ändras." "Kunde inte uppdatera rummet" diff --git a/features/roomdetails/impl/src/main/res/values-uk/translations.xml b/features/roomdetails/impl/src/main/res/values-uk/translations.xml index b06ad30097..87251699c1 100644 --- a/features/roomdetails/impl/src/main/res/values-uk/translations.xml +++ b/features/roomdetails/impl/src/main/res/values-uk/translations.xml @@ -23,6 +23,9 @@ "Понизити" "Ви не зможете скасувати цю зміну, оскільки ви знижуєте себе, якщо ви останній привілейований користувач у кімнаті, відновити привілеї буде неможливо." "Понизити себе?" + "%1$s (Очікується)" + "(Очікується)" + "Адміністратори автоматично мають права модератора" "Керувати модераторами" "Адміністратори" "Модератори" @@ -32,6 +35,9 @@ "Додати тему" "Уже учасник" "Уже запрошені" + "Зашифровано" + "Не зашифровано" + "Публічна кімната" "Редагувати кімнату" "Сталася невідома помилка, й інформацію не вдалося змінити." "Не вдалося оновити кімнату" @@ -50,6 +56,7 @@ "Назва кімнати" "Безпека" "Поділитися кімнатою" + "Інформація про кімнату" "Тема" "Оновлення кімнати…" "Заблокувати" diff --git a/features/roomdetails/impl/src/main/res/values-uz/translations.xml b/features/roomdetails/impl/src/main/res/values-uz/translations.xml new file mode 100644 index 0000000000..a7d0642bed --- /dev/null +++ b/features/roomdetails/impl/src/main/res/values-uz/translations.xml @@ -0,0 +1,45 @@ + + + "Bildirishnoma sozlamalarini yangilashda xatolik yuz berdi." + "Har kim" + "Mavzu qo\'shish" + "Allaqachon a\'zo" + "Allaqachon taklif qilingan" + "Xonani tahrirlash" + "Nomaʼlum xatolik yuz berdi va maʼlumotni oʻzgartirib boʻlmadi." + "Xonani yangilab bo‘lmadi" + "Xabarlar qulflar bilan himoyalangan. Faqat siz va qabul qiluvchilar ularni qulfdan chiqarish uchun noyob kalitlarga ega." + "Xabarni shifrlash yoqilgan" + "Bildirishnoma sozlamalarini yuklashda xatolik yuz berdi." + "Bu xona ovozini o‘chirib bo‘lmadi, qayta urinib ko‘ring." + "Bu xonaning ovozi yoqilmadi, qayta urinib ko‘ring." + "Odamlarni taklif qiling" + "Xonani tark etish " + "Maxsus" + "Standart" + "Bildirishnomalar" + "Xona nomi" + "Xavfsizlik" + "Xonani baham ko\'ring" + "Mavzu" + "Xona yangilanmoqda…" + + "%1$dodam" + "%1$dodamlar" + + "Kutilmoqda" + "Xona a\'zolari" + "Moslashtirilgan sozlamalarga ruxsat bering" + "Buni yoqsangiz, standart sozlamalaringiz bekor qilinadi" + "Bu chatda menga xabar bering" + "Siz buni o\'zgartira olasiz o\'zingizning %1$sda." + "global sozlamalar" + "Standart sozlama" + "Maxsus sozlamani olib tashlang" + "Bildirishnoma sozlamalarini yuklashda xatolik yuz berdi." + "Standart rejimni tiklab bo‘lmadi, qaytadan urinib ko‘ring." + "Rejimni o‘rnatib bo‘lmadi, qayta urinib ko‘ring." + "Barcha xabarlar" + "Faqat eslatmalar va kalit so\'zlar" + "Bu xonada menga xabar bering" + diff --git a/features/roomdirectory/impl/src/main/res/values-pl/translations.xml b/features/roomdirectory/impl/src/main/res/values-pl/translations.xml new file mode 100644 index 0000000000..80bbffed87 --- /dev/null +++ b/features/roomdirectory/impl/src/main/res/values-pl/translations.xml @@ -0,0 +1,5 @@ + + + "Błąd wczytywania" + "Katalog pokoi" + diff --git a/features/roomdirectory/impl/src/main/res/values-pt-rBR/translations.xml b/features/roomdirectory/impl/src/main/res/values-pt-rBR/translations.xml new file mode 100644 index 0000000000..07bbad975f --- /dev/null +++ b/features/roomdirectory/impl/src/main/res/values-pt-rBR/translations.xml @@ -0,0 +1,4 @@ + + + "Diretório de salas" + diff --git a/features/roomlist/impl/src/main/res/values-pl/translations.xml b/features/roomlist/impl/src/main/res/values-pl/translations.xml index 0ae62297a1..96d91a568f 100644 --- a/features/roomlist/impl/src/main/res/values-pl/translations.xml +++ b/features/roomlist/impl/src/main/res/values-pl/translations.xml @@ -1,10 +1,10 @@ "Twoja kopia zapasowa czatu jest obecnie niezsynchronizowana. Aby zachować dostęp do kopii zapasowej czatu, musisz potwierdzić klucz odzyskiwania." - "Potwierdź klucz odzyskiwania" + "Wprowadź swój klucz przywracania" "Upewnij się, że nie pominiesz żadnego połączenia. Zmień swoje ustawienia i zezwól na powiadomienia na blokadzie ekranu." "Popraw jakość swoich rozmów" - "Czy na pewno chcesz odrzucić zaproszenie do dołączenia do %1$s?" + "Czy na pewno chcesz odrzucić zaproszenie dołączenia do %1$s?" "Odrzuć zaproszenie" "Czy na pewno chcesz odrzucić rozmowę prywatną z %1$s?" "Odrzuć czat" @@ -15,8 +15,26 @@ "Utwórz nową rozmowę lub pokój" "Wyślij komuś wiadomość, aby rozpocząć." "Brak czatów." + "Ulubione" + "Możesz dodać czat do ulubionych w ustawieniach czatu. +Na razie możesz wyczyścić filtry, aby zobaczyć pozostałe czaty" + "Nie masz jeszcze ulubionych czatów" + "Zaproszenia" + "Nie masz żadnych oczekujących zaproszeń." + "Niski priorytet" + "Wyczyść filtry, aby zobaczyć pozostałe czaty" + "Brak czatów dla podanych kryteriów" "Osoby" + "Nie masz jeszcze żadnych PW" + "Pokoje" + "Nie jesteś jeszcze w żadnym pokoju" + "Nieprzeczytane" + "Gratulacje! +Nie masz żadnych nieprzeczytanych wiadomości!" "Wszystkie czaty" + "Oznacz jako przeczytane" + "Oznacz jako nieprzeczytane" + "Przeglądaj wszystkie pokoje" "Wygląda na to, że używasz nowego urządzenia. Zweryfikuj się innym urządzeniem, aby uzyskać dostęp do zaszyfrowanych wiadomości." "Potwierdź, że to Ty" diff --git a/features/roomlist/impl/src/main/res/values-pt-rBR/translations.xml b/features/roomlist/impl/src/main/res/values-pt-rBR/translations.xml index 6765199a70..5f896a6427 100644 --- a/features/roomlist/impl/src/main/res/values-pt-rBR/translations.xml +++ b/features/roomlist/impl/src/main/res/values-pt-rBR/translations.xml @@ -12,8 +12,21 @@ "Criar uma nova conversa ou sala" "Comece enviando uma mensagem para alguém." "Ainda não há conversas." + "Favoritos" + "Você não tem nenhuma conversa favorita ainda" + "Baixa prioridade" + "Você não tem conversas para esta seleção" "Pessoas" + "Você não tem nenhum conversa privada ainda" + "Salas" + "Você não está em nenhuma sala ainda" + "Não lidos" + "Parabéns! +Você não tem nenhuma mensagem não lida!" "Conversas" + "Marcar como lido" + "Marcar como não lido" + "Navegar por todas as salas" "Parece que você está usando um novo dispositivo. Verifique com outro dispositivo para acessar suas mensagens criptografadas." "Verifique se é você" diff --git a/features/roomlist/impl/src/main/res/values-sv/translations.xml b/features/roomlist/impl/src/main/res/values-sv/translations.xml index 69d5dc7cf3..4f7b26bb52 100644 --- a/features/roomlist/impl/src/main/res/values-sv/translations.xml +++ b/features/roomlist/impl/src/main/res/values-sv/translations.xml @@ -2,6 +2,8 @@ "Din chattsäkerhetskopia är för närvarande inte synkroniserad. Du måste ange din återställningsnyckel för att behålla åtkomsten till din chattsäkerhetskopia." "Ange din återställningsnyckel" + "För att säkerställa att du aldrig missar ett viktigt samtal, ändra dina inställningar för att tillåta helskärmsmeddelanden när telefonen är låst." + "Förbättra din samtalsupplevelse" "Är du säker på att du vill tacka nej till inbjudan att gå med%1$s?" "Avböj inbjudan" "Är du säker på att du vill avböja denna privata chatt med %1$s?" @@ -17,6 +19,8 @@ "Du kan lägga till en chatt till dina favoriter i chattinställningarna. För tillfället kan du avmarkera filter för att se dina andra chattar" "Du har inga favoritchattar än" + "Inbjudningar" + "Du har inga väntande inbjudningar." "Låg prioritet" "Du kan avmarkera filter för att se dina andra chattar" "Du har inga chattar för det här valet" diff --git a/features/roomlist/impl/src/main/res/values-uk/translations.xml b/features/roomlist/impl/src/main/res/values-uk/translations.xml index a7f1c26db0..8b33aee7e4 100644 --- a/features/roomlist/impl/src/main/res/values-uk/translations.xml +++ b/features/roomlist/impl/src/main/res/values-uk/translations.xml @@ -2,6 +2,7 @@ "Ваша резервна копія чату наразі не синхронізована. Вам потрібно підтвердити ключ відновлення, щоб зберегти доступ до резервної копії чату." "Підтвердіть ключ відновлення" + "Щоб ніколи не пропустити важливий дзвінок, змініть налаштування, щоб увімкнути повноекранні сповіщення, коли телефон заблоковано." "Ви впевнені, що хочете відхилити запрошення приєднатися до %1$s?" "Відхилити запрошення" "Ви дійсно хочете відмовитися від приватного чату з %1$s?" @@ -17,6 +18,8 @@ "Ви можете додати чат до улюблених у налаштуваннях чату. Наразі ви можете зняти фільтри, щоб побачити інші ваші чати" "Ви ще не маєте улюблених чатів" + "Запрошення" + "У вас немає запрошень, що очікують на розгляд." "Низький пріоритет" "Ви можете зняти фільтри, щоб побачити інші ваші чати" "Ви не маєте чатів для цієї категорії" @@ -28,8 +31,9 @@ "Вітаємо! У вас немає непрочитаних повідомлень!" "Усі чати" - "Позначити як прочитане" - "Позначити як непрочитане" + "Позначити прочитаним" + "Позначити непрочитаним" + "Переглянути всі кімнати" "Схоже, Ви використовуєте новий пристрій. Щоб отримати доступ до зашифрованих повідомлень, підтвердьте особу за допомогою іншого пристрою." "Підтвердьте, що це Ви" diff --git a/features/roomlist/impl/src/main/res/values-uz/translations.xml b/features/roomlist/impl/src/main/res/values-uz/translations.xml new file mode 100644 index 0000000000..7ca2ae798a --- /dev/null +++ b/features/roomlist/impl/src/main/res/values-uz/translations.xml @@ -0,0 +1,18 @@ + + + "Haqiqatan ham qo\'shilish taklifini rad qilmoqchimisiz%1$s ?" + "Taklifni rad etish" + "Haqiqatan ham bu shaxsiy chatni rad qilmoqchimisiz%1$s ?" + "Chatni rad etish" + "Takliflar yo\'q" + "%1$s(%2$s ) sizni taklif qildi" + "Bu bir martalik jarayon, kutganingiz uchun rahmat." + "Hisobingiz sozlanmoqda." + "Yangi suhbat yoki xona yarating" + "Kimgadir xabar yuborishdan boshlang." + "Hozircha chatlar yo‘q." + "Odamlar" + "Suhbatlar" + "Siz yangi qurilmadan foydalanayotganga o‘xshaysiz. Shifrlangan xabarlaringizga kirish uchun boshqa qurilma bilan tasdiqlang." + "Siz ekanligingizni tasdiqlang" + diff --git a/features/roomlist/impl/src/test/kotlin/io/element/android/features/roomlist/impl/RoomListPresenterTest.kt b/features/roomlist/impl/src/test/kotlin/io/element/android/features/roomlist/impl/RoomListPresenterTest.kt index 7a9a8b2744..4bf4510d2f 100644 --- a/features/roomlist/impl/src/test/kotlin/io/element/android/features/roomlist/impl/RoomListPresenterTest.kt +++ b/features/roomlist/impl/src/test/kotlin/io/element/android/features/roomlist/impl/RoomListPresenterTest.kt @@ -95,6 +95,7 @@ import io.element.android.tests.testutils.testCoroutineDispatchers import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.SupervisorJob import kotlinx.coroutines.cancel +import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.test.TestScope import kotlinx.coroutines.test.runTest import org.junit.Rule @@ -219,7 +220,7 @@ class RoomListPresenterTest { val encryptionService = FakeEncryptionService().apply { emitRecoveryState(RecoveryState.INCOMPLETE) } - val syncService = FakeSyncService(initialState = SyncState.Running) + val syncService = FakeSyncService(MutableStateFlow(SyncState.Running)) val presenter = createRoomListPresenter( client = FakeMatrixClient(roomListService = roomListService, encryptionService = encryptionService, syncService = syncService), coroutineScope = scope, @@ -250,7 +251,7 @@ class RoomListPresenterTest { sessionVerificationService = FakeSessionVerificationService().apply { givenNeedsSessionVerification(false) }, - syncService = FakeSyncService(initialState = SyncState.Running) + syncService = FakeSyncService(MutableStateFlow(SyncState.Running)) ) val scope = CoroutineScope(context = coroutineContext + SupervisorJob()) val presenter = createRoomListPresenter( diff --git a/features/securebackup/impl/src/main/res/values-pl/translations.xml b/features/securebackup/impl/src/main/res/values-pl/translations.xml index ca1589c5ac..17a4c1a4db 100644 --- a/features/securebackup/impl/src/main/res/values-pl/translations.xml +++ b/features/securebackup/impl/src/main/res/values-pl/translations.xml @@ -6,11 +6,18 @@ "Backup" "Zmień klucz przywracania" "Wprowadź klucz przywracania" - "Backup czatu nie jest zsynchronizowany." + "Backup czatu jest niezsynchronizowany." "Skonfiguruj przywracanie" "Uzyskaj dostęp do swoich wiadomości szyfrowanych, jeśli utracisz wszystkie swoje urządzenia lub zostaniesz wylogowany z %1$s." + "Otwórz %1$s na urządzeniu stacjonarnym" + "Zaloguj się ponownie na swoje konto" + "Gdy pojawi się prośba o weryfikację urządzenia, wybierz %1$s" + "“Resetuj wszystko”" + "Postępuj zgodnie z instrukcjami, aby utworzyć nowy klucz przywracania" + "Zapisz nowy klucz przywracania w menedżerze haseł lub notatce szyfrowanej" + "Resetuj szyfrowanie swojego konta za pomocą drugiego urządzenia" "Wyłącz" - "Utracisz dostęp do wiadomości szyfrowanych, jeśli zostaniesz wylogowany ze wszystkich urządzeń." + "Jeśli wylogujesz się ze wszystkich urządzeń, stracisz wszystkie wiadomości szyfrowane." "Czy na pewno chcesz wyłączyć backup?" "Wyłączenie backupu spowoduje usunięcie kopii klucza szyfrowania i wyłączenie innych funkcji bezpieczeństwa. W takim przypadku będziesz:" "Posiadał historii wiadomości szyfrowanych na nowych urządzeniach" @@ -21,11 +28,14 @@ "Upewnij się, że klucz przywracania będzie trzymany w bezpiecznym miejscu" "Zmieniono klucz przywracania" "Zmienić klucz przywracania?" + "Utwórz nowy klucz przywracania" "Upewnij się, że nikt nie widzi tego ekranu!" "Spróbuj ponownie, aby potwierdzić dostęp do backupu czatu." "Nieprawidłowy klucz przywracania" "To też zadziała, jeśli posiadasz klucz lub frazę bezpieczeństwa." + "Klucz przywracania lub hasło" "Wprowadź…" + "Zgubiłeś swój kod przywracania?" "Potwierdzono klucz przywracania" "Wprowadź klucz przywracania" "Skopiowano klucz przywracania" diff --git a/features/securebackup/impl/src/main/res/values-pt-rBR/translations.xml b/features/securebackup/impl/src/main/res/values-pt-rBR/translations.xml index 786de3f4da..9c9ea39c24 100644 --- a/features/securebackup/impl/src/main/res/values-pt-rBR/translations.xml +++ b/features/securebackup/impl/src/main/res/values-pt-rBR/translations.xml @@ -4,7 +4,7 @@ "Ativar o backup" "O backup garante que você não perca seu histórico de mensagens. %1$s." "Backup" - "Mudar chave de recuperação" + "Alterar chave de recuperação" "Insira a chave de recuperação" "Seu backup das conversas está atualmente fora de sincronia." "Configurar a recuperação" @@ -22,10 +22,13 @@ "Chave de recuperação alterada" "Alterar chave de recuperação?" "Certifique-se de que ninguém possa ver essa tela!" + "Chave de recuperação incorreta" "Se você tiver uma chave de segurança ou frase de segurança, isso também funcionará." "Inserir…" "Chave de recuperação confirmada" "Insira sua chave de recuperação" + "Chave de recuperação copiada" + "Gerando…" "Salvar chave de recuperação" "Anote sua chave de recuperação em algum lugar seguro ou salve-a em um gerenciador de senhas." "Toque para copiar a chave de recuperação" diff --git a/features/securebackup/impl/src/main/res/values-sv/translations.xml b/features/securebackup/impl/src/main/res/values-sv/translations.xml index a1b1512031..5216a7ed96 100644 --- a/features/securebackup/impl/src/main/res/values-sv/translations.xml +++ b/features/securebackup/impl/src/main/res/values-sv/translations.xml @@ -9,6 +9,13 @@ "Din chattsäkerhetskopia är för närvarande osynkroniserad." "Ställ in återställning" "Få tillgång till dina krypterade meddelanden om du tappar bort alla dina enheter eller blir utloggad ur %1$s överallt." + "Öppna %1$s på en skrivbordsenhet" + "Logga in på ditt konto igen" + "När du ombeds att verifiera din enhet, välj %1$s" + "”Återställ alla”" + "Följ anvisningarna för att skapa en ny återställningsnyckel" + "Spara din nya återställningsnyckel i en lösenordshanterare eller krypterad anteckning" + "Återställ krypteringen för ditt konto med en annan enhet" "Stäng av" "Du kommer att förlora dina krypterade meddelanden om du loggas ut från alla enheter." "Är du säker på att du vill stänga av säkerhetskopiering?" @@ -21,11 +28,14 @@ "Se till att du kan lagra din återställningsnyckel någonstans säkert" "Återställningsnyckel ändrad" "Byt återställningsnyckel?" + "Skapa ny återställningsnyckel" "Se till att ingen kan se den här skärmen" "Vänligen pröva igen för att bekräfta åtkomsten till din chattsäkerhetskopia." "Felaktig återställningsnyckel" "Om du har en säkerhetsnyckel eller säkerhetsfras så funkar den också." + "Återställningsnyckel eller lösenkod" "Ange …" + "Blivit av med din återställningsnyckel?" "Återställningsnyckel bekräftad" "Ange din återställningsnyckel" "Kopierade återställningsnyckel" diff --git a/features/securebackup/impl/src/main/res/values-uk/translations.xml b/features/securebackup/impl/src/main/res/values-uk/translations.xml index 2a5b029a6b..1d1b9d2526 100644 --- a/features/securebackup/impl/src/main/res/values-uk/translations.xml +++ b/features/securebackup/impl/src/main/res/values-uk/translations.xml @@ -9,6 +9,13 @@ "Ваша резервна копія чату наразі не синхронізована." "Налаштувати відновлення" "Отримайте доступ до своїх зашифрованих повідомлень, якщо ви втратите всі свої пристрої або вийшли з %1$s системи." + "Відкрийте %1$s на комп\'ютері" + "Увійдіть до вашого облікового запису знову" + "Коли вас попросять підтвердити пристрій, виберіть %1$s" + "“Скинути все”" + "Дотримуйтесь інструкцій, щоб створити новий ключ відновлення" + "Збережіть новий ключ відновлення у менеджері паролів або зашифрованій нотатці" + "Скинути шифрування облікового запису за допомогою іншого пристрою" "Вимкнути" "Ви втратите зашифровані повідомлення, якщо вийдете з усіх пристроїв." "Ви впевнені, що хочете вимкнути резервне копіювання?" @@ -21,11 +28,14 @@ "Переконайтеся, що ви можете зберігати ключ відновлення в безпечному місці" "Ключ відновлення змінено" "Змінити ключ відновлення?" - "Введіть ключ відновлення, щоб підтвердити доступ до резервної копії чату." + "Створити новий ключ відновлення" + "Впевніться, що ніхто не дивиться!" "Будь ласка, спробуйте ще раз, щоб підтвердити доступ до резервної копії чату." "Неправильний ключ відновлення" - "Введіть код із 48 символів." + "Якщо у вас є ключ безпеки або фраза безпеки, це теж спрацює." + "Ключ відновлення або код допуску" "Ввести…" + "Загубили ключ відновлення?" "Ключ відновлення підтверджено" "Підтвердіть ключ відновлення" "Скопійовано ключ відновлення" diff --git a/features/securebackup/impl/src/main/res/values-uz/translations.xml b/features/securebackup/impl/src/main/res/values-uz/translations.xml new file mode 100644 index 0000000000..b5bea8f4b8 --- /dev/null +++ b/features/securebackup/impl/src/main/res/values-uz/translations.xml @@ -0,0 +1,40 @@ + + + "Zaxiralashni o\'chirib qo\'ying" + "Zaxiralashni yoqing" + "Zaxiralash xabarlar tarixini yo\'qotmaslikni ta\'minlaydi.%1$s." + "Zaxira" + "Qayta tiklash kalitini o\'zgartiring" + "Qayta tiklash kalitini kiriting" + "Sizning chat zaxirangiz hozirda sinxronlashtirilmagan." + "Qayta tiklashni sozlang" + "Agar barcha qurilmalaringizni yo‘qotib qo‘ysangiz yoki tizimdan chiqqan bo‘lsangiz, shifrlangan xabarlaringizga ruxsat oling%1$s hamma joyda." + "O\'chirish" + "Agar barcha qurilmalardan chiqqan boʻlsangiz, shifrlangan xabarlaringizni yoʻqotasiz." + "Haqiqatan ham zaxiralashni o‘chirib qo‘ymoqchimisiz?" + "Zaxiralashni o‘chirib qo‘ysangiz, joriy shifrlash kaliti zaxira nusxasi o‘chiriladi va boshqa xavfsizlik funksiyalari o‘chiriladi. Bunday holda siz:" + "Yangi qurilmalarda shifrlangan xabarlar tarixi mavjud emas" + "Agar tizimdan chiqqan boʻlsangiz, shifrlangan xabarlaringizga kirish huquqini yoʻqotasiz%1$s hamma joyda" + "Haqiqatan ham zaxiralashni o‘chirib qo‘ymoqchimisiz?" + "Mavjud kalitingizni yo\'qotgan bo\'lsangiz, yangi tiklash kalitini oling. Qayta tiklash kalitini almashtirganingizdan so\'ng, eski kalitingiz ishlamaydi." + "Yangi tiklash kalitini yarating" + "Qayta tiklash kalitingizni xavfsiz joyda saqlashingiz mumkinligiga ishonch hosil qiling" + "Qayta tiklash kaliti oʻzgartirildi" + "Qayta tiklash kaliti almashtirilsinmi?" + "Hech kim bu ekranni kora olmasligiga ishonch hosil qiling!" + "Agar sizda xavfsizlik kaliti yoki xavfsizlik iborasi bolsa, bu ham ishlaydi." + "Kirish…" + "Qayta tiklash kaliti tasdiqlandi" + "Qayta tiklash kalitingizni kiriting" + "Qayta tiklash kalitini saqlang" + "Qayta tiklash kalitingizni xavfsiz joyga yozing yoki parol menejerida saqlang." + "Qayta tiklash kalitidan nusxa olish uchun bosing" + "Zaxira kalitingizni saqlang" + "Ushbu qadamdan so‘ng siz yangi tiklash kalitingizga kira olmaysiz." + "Zaxira kalitingizni saqladingizmi?" + "Suhbatingiz zaxira nusxasi tiklash kaliti bilan himoyalangan. Agar sozlashdan keyin sizga yangi tiklash kaliti kerak boʻlsa, “Qayta tiklash kalitini oʻzgartirish”ni tanlash orqali qayta yaratishingiz mumkin." + "Qayta tiklash kalitini yarating" + "Qayta tiklash kalitingizni xavfsiz joyda saqlashingiz mumkinligiga ishonch hosil qiling" + "Qayta tiklash muvaffaqiyatli sozlandi" + "Qayta tiklashni sozlang" + diff --git a/features/signedout/impl/src/main/res/values-uz/translations.xml b/features/signedout/impl/src/main/res/values-uz/translations.xml new file mode 100644 index 0000000000..bb386ee54f --- /dev/null +++ b/features/signedout/impl/src/main/res/values-uz/translations.xml @@ -0,0 +1,8 @@ + + + "Siz boshqa seansda parolingizni o\'zgartirdingiz" + "Siz seansni boshqa seansdan o\'chirib tashladingiz" + "Serveringiz administratori ruxsatingizni bekor qildi" + "Siz quyida sanab o‘tilgan sabablardan biri tufayli tizimdan chiqqan bo‘lishingiz mumkin. Foydalanishni davom ettirish uchun qayta kiring%s ." + "Hisobingizdan chiqdingiz" + diff --git a/features/userprofile/shared/src/main/res/values-uz/translations.xml b/features/userprofile/shared/src/main/res/values-uz/translations.xml new file mode 100644 index 0000000000..5c7e50eaec --- /dev/null +++ b/features/userprofile/shared/src/main/res/values-uz/translations.xml @@ -0,0 +1,10 @@ + + + "Bloklash" + "Bloklangan foydalanuvchilar sizga xabar yubora olmaydi va ularning barcha xabarlari yashiriladi. Ularni istalgan vaqtda blokdan chiqarishingiz mumkin." + "Foydalanuvchini bloklash" + "Blokdan chiqarish" + "Ulardan kelgan barcha xabarlarni yana koʻrishingiz mumkin boʻladi." + "Foydalanuvchini blokdan chiqarish" + "Suhbatni boshlashda xatolik yuz berdi" + diff --git a/features/verifysession/impl/src/main/res/values-be/translations.xml b/features/verifysession/impl/src/main/res/values-be/translations.xml index 8b2c5e920d..cdb8cedfe0 100644 --- a/features/verifysession/impl/src/main/res/values-be/translations.xml +++ b/features/verifysession/impl/src/main/res/values-be/translations.xml @@ -1,8 +1,11 @@ + "Не можаце пацвердзіць?" "Стварыць новы ключ аднаўлення" "Пацвердзіце гэтую прыладу, каб наладзіць бяспечны абмен паведамленнямі." "Пацвердзіце, што гэта вы" + "Выкарыстоўвайце іншую прыладу" + "Выкарыстоўваць ключ аднаўлення" "Цяпер вы можаце бяспечна чытаць і адпраўляць паведамленні, і ўсе, з кім вы маеце зносіны ў чаце, таксама могуць давяраць гэтай прыладзе." "Прылада праверана" "Выкарыстоўвайце іншую прыладу" diff --git a/features/verifysession/impl/src/main/res/values-cs/translations.xml b/features/verifysession/impl/src/main/res/values-cs/translations.xml index fadcba869c..96d9aa0aa9 100644 --- a/features/verifysession/impl/src/main/res/values-cs/translations.xml +++ b/features/verifysession/impl/src/main/res/values-cs/translations.xml @@ -3,6 +3,7 @@ "Vytvoření nového klíče pro obnovení" "Ověřte toto zařízení a nastavte zabezpečené zasílání zpráv." "Potvrďte, že jste to vy" + "Použít jiné zařízení" "Nyní můžete bezpečně číst nebo odesílat zprávy, a kdokoli, s kým chatujete, může tomuto zařízení důvěřovat." "Zařízení ověřeno" "Použít jiné zařízení" diff --git a/features/verifysession/impl/src/main/res/values-de/translations.xml b/features/verifysession/impl/src/main/res/values-de/translations.xml index baad607403..a66479b3c1 100644 --- a/features/verifysession/impl/src/main/res/values-de/translations.xml +++ b/features/verifysession/impl/src/main/res/values-de/translations.xml @@ -3,6 +3,7 @@ "Erstelle einen neuen Wiederherstellungsschlüssel" "Verifiziere dieses Gerät, um sicheres Messaging einzurichten." "Bestätige, dass du es bist" + "Ein anderes Gerät verwenden" "Du kannst nun verschlüsselte Nachrichten lesen oder versenden." "Gerät verifiziert" "Ein anderes Gerät verwenden" diff --git a/features/verifysession/impl/src/main/res/values-el/translations.xml b/features/verifysession/impl/src/main/res/values-el/translations.xml index 5b0402cf50..93838717b7 100644 --- a/features/verifysession/impl/src/main/res/values-el/translations.xml +++ b/features/verifysession/impl/src/main/res/values-el/translations.xml @@ -3,6 +3,7 @@ "Δημιουργία νέου κλειδιού ανάκτησης" "Επαλήθευσε αυτήν τη συσκευή για να ρυθμίσεις την ασφαλή επικοινωνία." "Επιβεβαίωσε ότι είσαι εσύ" + "Χρήση άλλης συσκευής" "Τώρα μπορείς να διαβάζεις ή να στέλνεις μηνύματα με ασφάλεια και επίσης μπορεί να εμπιστευτεί αυτήν τη συσκευή οποιοσδήποτε με τον οποίο συνομιλείς." "Επαληθευμένη συσκευή" "Χρήση άλλης συσκευής" diff --git a/features/verifysession/impl/src/main/res/values-es/translations.xml b/features/verifysession/impl/src/main/res/values-es/translations.xml index b165818726..75773bd081 100644 --- a/features/verifysession/impl/src/main/res/values-es/translations.xml +++ b/features/verifysession/impl/src/main/res/values-es/translations.xml @@ -2,8 +2,10 @@ "Verifica este dispositivo para configurar la mensajería segura." "Confirma que eres tú" + "Usar otro dispositivo" "Ahora puedes leer o enviar mensajes de forma segura y cualquier persona con la que chatees también puede confiar en este dispositivo." "Dispositivo verificado" + "Usar otro dispositivo" "Algo no fue bien. Se agotó el tiempo de espera de la solicitud o se rechazó." "Confirma que los emojis que aparecen a continuación coinciden con los que aparecen en tu otra sesión." "Comparar emojis" diff --git a/features/verifysession/impl/src/main/res/values-et/translations.xml b/features/verifysession/impl/src/main/res/values-et/translations.xml index 219c7653e1..a9baa5bd9e 100644 --- a/features/verifysession/impl/src/main/res/values-et/translations.xml +++ b/features/verifysession/impl/src/main/res/values-et/translations.xml @@ -1,11 +1,14 @@ + "Kas kinnitamine pole võimalik?" "Loo uus taastevõti" "Krüptitud sõnumivahetuse tagamiseks verifitseeri see seade." "Kinnita, et see oled sina" + "Kasuta teist seadet" + "Kasuta taastevõtit" "Nüüd saad saata või lugeda sõnumeid turvaliselt ning kõik sinu vestluspartnerid võivad usaldada seda seadet." "Seade on verifitseeritud" - "Kasuta mõnda muud seadet" + "Kasuta teist seadet" "Ootame teise seadme järgi…" "Olukord pole päris õige. Päring kas aegus või teine osapool keeldus päringule vastamast." "Kinnita, et kõik järgnevalt kuvatud emojid on täpselt samad, mida sa näed oma teises sessioonis." diff --git a/features/verifysession/impl/src/main/res/values-fr/translations.xml b/features/verifysession/impl/src/main/res/values-fr/translations.xml index 6f7aa9982b..6750f48956 100644 --- a/features/verifysession/impl/src/main/res/values-fr/translations.xml +++ b/features/verifysession/impl/src/main/res/values-fr/translations.xml @@ -3,6 +3,7 @@ "Créer une nouvelle clé de récupération" "Vérifier cette session pour configurer votre messagerie sécurisée." "Confirmez votre identité" + "Utiliser une autre session" "Vous pouvez désormais lire ou envoyer des messages en toute sécurité, et toute personne avec qui vous discutez peut également faire confiance à cette session." "Session vérifiée" "Utiliser une autre session" diff --git a/features/verifysession/impl/src/main/res/values-hu/translations.xml b/features/verifysession/impl/src/main/res/values-hu/translations.xml index c31adb9736..3de5d84c48 100644 --- a/features/verifysession/impl/src/main/res/values-hu/translations.xml +++ b/features/verifysession/impl/src/main/res/values-hu/translations.xml @@ -1,8 +1,11 @@ + "Nem tudja megerősíteni?" "Új helyreállítási kulcs létrehozása" "A biztonságos üzenetkezelés beállításához ellenőrizze ezt az eszközt." "Erősítse meg, hogy Ön az" + "Másik eszköz használata" + "Helyreállítási kulcs használata" "Mostantól biztonságosan olvashat vagy küldhet üzeneteket, és bármelyik csevegőpartnere megbízhat ebben az eszközben." "Eszköz ellenőrizve" "Másik eszköz használata" diff --git a/features/verifysession/impl/src/main/res/values-in/translations.xml b/features/verifysession/impl/src/main/res/values-in/translations.xml index 3a3bec959e..50dc87d765 100644 --- a/features/verifysession/impl/src/main/res/values-in/translations.xml +++ b/features/verifysession/impl/src/main/res/values-in/translations.xml @@ -3,6 +3,7 @@ "Buat kunci pemulihan baru" "Verifikasi perangkat ini untuk menyiapkan perpesanan aman." "Konfirmasi bahwa ini Anda" + "Gunakan perangkat lain" "Sekarang Anda dapat membaca atau mengirim pesan dengan aman, dan siapa pun yang mengobrol dengan Anda juga dapat mempercayai perangkat ini." "Perangkat terverifikasi" "Gunakan perangkat lain" diff --git a/features/verifysession/impl/src/main/res/values-it/translations.xml b/features/verifysession/impl/src/main/res/values-it/translations.xml index 5e22712283..ac7036eebb 100644 --- a/features/verifysession/impl/src/main/res/values-it/translations.xml +++ b/features/verifysession/impl/src/main/res/values-it/translations.xml @@ -3,6 +3,7 @@ "Crea una nuova chiave di recupero" "Verifica questo dispositivo per segnare i tuoi messaggi come sicuri." "Conferma la tua identità" + "Usa un altro dispositivo" "Ora puoi leggere o inviare messaggi in tutta sicurezza e anche chi chatta con te può fidarsi di questo dispositivo." "Dispositivo verificato" "Usa un altro dispositivo" diff --git a/features/verifysession/impl/src/main/res/values-pl/translations.xml b/features/verifysession/impl/src/main/res/values-pl/translations.xml index 6f39abf905..07a3304ed9 100644 --- a/features/verifysession/impl/src/main/res/values-pl/translations.xml +++ b/features/verifysession/impl/src/main/res/values-pl/translations.xml @@ -1,11 +1,20 @@ + "Utwórz nowy klucz przywracania" + "Zweryfikuj to urządzenie, aby skonfigurować bezpieczne przesyłanie wiadomości." + "Potwierdź, że to Ty" + "Użyj innego urządzenia" + "Teraz możesz bezpiecznie czytać i wysyłać wiadomości, każdy z kim czatujesz również może ufać temu urządzeniu." + "Urządzenie zweryfikowane" + "Użyj innego urządzenia" + "Oczekiwanie na inne urządzenie…" "Coś tu nie gra. Albo upłynął limit czasu, albo żądanie zostało odrzucone." - "Upewnij się, że poniższe emotikony pasują do tych wyświetlanych na innej sesji." + "Upewnij się, że emoji poniżej pasują do tych pokazanych na innej sesji." "Porównaj emotki" "Upewnij się, że liczby poniżej pasują do tych wyświetlanych na innej sesji." "Porównaj liczby" "Twoja nowa sesja jest teraz zweryfikowana. Ma ona dostęp do Twoich zaszyfrowanych wiadomości, a inni użytkownicy będą widzieć ją jako zaufaną." + "Wprowadź klucz przywracania" "Udowodnij, że to ty, aby uzyskać dostęp do historii zaszyfrowanych wiadomości." "Otwórz istniejącą sesję" "Ponów weryfikację" diff --git a/features/verifysession/impl/src/main/res/values-pt-rBR/translations.xml b/features/verifysession/impl/src/main/res/values-pt-rBR/translations.xml index 9d4658be82..31da2e43d1 100644 --- a/features/verifysession/impl/src/main/res/values-pt-rBR/translations.xml +++ b/features/verifysession/impl/src/main/res/values-pt-rBR/translations.xml @@ -1,14 +1,21 @@ + "Usar outro dispositivo" + "Dispositivo verificado" + "Usar outro dispositivo" "Algo não parece certo. Ou a solicitação atingiu o tempo limite ou a solicitação foi negada." "Confirme se os emojis abaixo correspondem aos mostrados em sua outra sessão." "Compare os emojis" + "Confirme se os números abaixo correspondem aos mostrados em sua outra sessão." + "Comparar números" "Sua nova sessão está agora verificada. Ela tem acesso às suas mensagens criptografadas e outros usuários a verão como confiável." + "Insira a chave de recuperação" "Prove que é você para acessar seu histórico de mensagens criptografadas." "Abrir uma sessão existente" "Repetir verificação" "Estou pronto" "Esperando para combinar" + "Compare um conjunto único de emojis." "Compare os emojis únicos, garantindo que apareçam na mesma ordem." "Eles não combinam" "Eles combinam" diff --git a/features/verifysession/impl/src/main/res/values-pt/translations.xml b/features/verifysession/impl/src/main/res/values-pt/translations.xml index b563196913..a4d45ec9ef 100644 --- a/features/verifysession/impl/src/main/res/values-pt/translations.xml +++ b/features/verifysession/impl/src/main/res/values-pt/translations.xml @@ -1,8 +1,11 @@ + "Não é possível confirmar?" "Criar uma nova chave de recuperação" "Verifica este dispositivo para configurar o envio seguro de mensagens." "Confirma que és tu" + "Utilizar outro dispositivo" + "Utilizar chave de recuperação" "Agora podes ler ou enviar mensagens de forma segura, e qualquer pessoa com quem converses também pode confiar neste dispositivo." "Dispositivo verificado" "Utilizar outro dispositivo" diff --git a/features/verifysession/impl/src/main/res/values-ro/translations.xml b/features/verifysession/impl/src/main/res/values-ro/translations.xml index 91e837ddec..69bb6a20f5 100644 --- a/features/verifysession/impl/src/main/res/values-ro/translations.xml +++ b/features/verifysession/impl/src/main/res/values-ro/translations.xml @@ -3,6 +3,7 @@ "Creați o nouă cheie de recuperare" "Verificați acest dispozitiv pentru a configura mesagerie securizată." "Confirmați că sunteți dumneavoastră" + "Utilizați un alt dispozitiv" "Acum puteți citi sau trimite mesaje în siguranță, iar oricine cu care conversați poate avea încredere în acest dispozitiv." "Dispozitiv verificat" "Utilizați un alt dispozitiv" diff --git a/features/verifysession/impl/src/main/res/values-ru/translations.xml b/features/verifysession/impl/src/main/res/values-ru/translations.xml index c89077d172..fc685356d7 100644 --- a/features/verifysession/impl/src/main/res/values-ru/translations.xml +++ b/features/verifysession/impl/src/main/res/values-ru/translations.xml @@ -1,11 +1,14 @@ + "Не можете подтвердить?" "Создайте новый " "ключ восстановления" "Подтвердите это устройство, чтобы настроить безопасный обмен сообщениями." "Подтвердите, что это вы" + "Используйте другое устройство" + "Используйте recovery key" "Теперь вы можете безопасно читать и отправлять сообщения, и все, с кем вы общаетесь в чате, также могут доверять этому устройству." "Устройство проверено" "Используйте другое устройство" diff --git a/features/verifysession/impl/src/main/res/values-sk/translations.xml b/features/verifysession/impl/src/main/res/values-sk/translations.xml index b3089b7b30..a2ec2cb4b2 100644 --- a/features/verifysession/impl/src/main/res/values-sk/translations.xml +++ b/features/verifysession/impl/src/main/res/values-sk/translations.xml @@ -1,11 +1,14 @@ + "Nemôžete potvrdiť?" "Vytvoriť nový kľúč na obnovenie" "Ak chcete nastaviť zabezpečené správy, overte toto zariadenie." "Potvrďte, že ste to vy" + "Použite iné zariadenie" + "Použiť kľúč na obnovenie" "Teraz môžete bezpečne čítať alebo odosielať správy a tomuto zariadeniu môže dôverovať aj ktokoľvek, s kým konverzujete." "Zariadenie overené" - "Použiť iné zariadenie" + "Použite iné zariadenie" "Čaká sa na druhom zariadení…" "Zdá sa, že niečo nie je v poriadku. Časový limit žiadosti vypršal alebo bola žiadosť zamietnutá." "Skontrolujte, či sa emotikony uvedené nižšie zhodujú s emotikonmi zobrazenými vo vašej druhej relácii." diff --git a/features/verifysession/impl/src/main/res/values-sv/translations.xml b/features/verifysession/impl/src/main/res/values-sv/translations.xml index 392754174b..524bc02b1e 100644 --- a/features/verifysession/impl/src/main/res/values-sv/translations.xml +++ b/features/verifysession/impl/src/main/res/values-sv/translations.xml @@ -1,8 +1,11 @@ + "Kan du inte bekräfta?" "Skapa en ny återställningsnyckel" "Verifiera den här enheten för att konfigurera säkra meddelanden." "Bekräfta att det är du" + "Använd en annan enhet" + "Använd återställningsnyckel" "Nu kan du läsa eller skicka meddelanden säkert, och alla du chattar med kan också lita på den här enheten." "Enhet verifierad" "Använd en annan enhet" diff --git a/features/verifysession/impl/src/main/res/values-uk/translations.xml b/features/verifysession/impl/src/main/res/values-uk/translations.xml index 9be10a2bb0..b76304f537 100644 --- a/features/verifysession/impl/src/main/res/values-uk/translations.xml +++ b/features/verifysession/impl/src/main/res/values-uk/translations.xml @@ -1,9 +1,12 @@ + "Не можете підтвердити?" + "Створити новий ключ відновлення" "Перевірте цей пристрій, щоб налаштувати безпечний обмін повідомленнями." "Підтвердіть, що це ви" "Тепер ви можете безпечно читати або надсилати повідомлення, і кожен, з ким ви спілкуєтесь, також може довіряти цьому пристрою." "Пристрій перевірено" + "Чекає на інше пристрій…" "Щось не так. Або час очікування запиту минув, або в запиті було відмовлено." "Переконайтеся, що емодзі нижче збігаються з тими, що відображаються під час іншого сеансу." "Порівняти емодзі" diff --git a/features/verifysession/impl/src/main/res/values-uz/translations.xml b/features/verifysession/impl/src/main/res/values-uz/translations.xml new file mode 100644 index 0000000000..87b780aa1a --- /dev/null +++ b/features/verifysession/impl/src/main/res/values-uz/translations.xml @@ -0,0 +1,17 @@ + + + "Nimadir noto‘g‘ri ko‘rinadi. Yoki so‘rov muddati tugadi yoki so‘rov rad etildi." + "Quyidagi kulgichlar boshqa seansda ko‘rsatilganlarga mos kelishini tasdiqlang." + "Emojilarni solishtiring" + "Yangi seansingiz tasdiqlandi. U sizning shifrlangan xabarlaringizga kirish huquqiga ega va boshqa foydalanuvchilar uni ishonchli deb bilishadi." + "Shifrlangan xabarlar tarixiga kirish uchun shaxsingizni tasdiqlang." + "Mavjud seansni oching" + "Tasdiqlashni qaytadan urining" + "Men tayyorman" + "Mos kelishi kutilmoqda" + "Noyob emojilarni solishtiring, ular bir xil tartibda paydo bo\'lishiga ishonch hosil qiling." + "Ular mos kelmaydi" + "Ular mos keladi" + "Davom etish uchun boshqa seansda tekshirish jarayonini boshlash soʻrovini qabul qiling." + "Soʻrovni qabul qilish kutilmoqda" + diff --git a/features/verifysession/impl/src/main/res/values-zh-rTW/translations.xml b/features/verifysession/impl/src/main/res/values-zh-rTW/translations.xml index f5a26eaf33..512e806c47 100644 --- a/features/verifysession/impl/src/main/res/values-zh-rTW/translations.xml +++ b/features/verifysession/impl/src/main/res/values-zh-rTW/translations.xml @@ -3,6 +3,7 @@ "建立新的復原金鑰" "驗證這部裝置以設定安全通訊。" "確認這是你本人" + "使用另一部裝置" "您可以安全地讀取和發送訊息了,與您聊天的人也可以信任這部裝置。" "裝置已驗證" "使用另一部裝置" diff --git a/features/verifysession/impl/src/main/res/values-zh/translations.xml b/features/verifysession/impl/src/main/res/values-zh/translations.xml index 15cf93695f..b13b0e7686 100644 --- a/features/verifysession/impl/src/main/res/values-zh/translations.xml +++ b/features/verifysession/impl/src/main/res/values-zh/translations.xml @@ -3,6 +3,7 @@ "创建新的恢复密钥" "验证此设备以开始安全地收发消息。" "确认这是你" + "使用其他设备" "现在,您可以安全地阅读或发送消息,与您聊天的人也会信任此设备。" "设备已验证" "使用其他设备" diff --git a/features/verifysession/impl/src/main/res/values/localazy.xml b/features/verifysession/impl/src/main/res/values/localazy.xml index 41cd2f8dbc..45eda758a2 100644 --- a/features/verifysession/impl/src/main/res/values/localazy.xml +++ b/features/verifysession/impl/src/main/res/values/localazy.xml @@ -1,8 +1,11 @@ + "Can\'t confirm?" "Create a new recovery key" "Verify this device to set up secure messaging." "Confirm that it\'s you" + "Use another device" + "Use recovery key" "Now you can read or send messages securely, and anyone you chat with can also trust this device." "Device verified" "Use another device" diff --git a/gradle.properties b/gradle.properties index b1f6468108..2d4c31a3aa 100644 --- a/gradle.properties +++ b/gradle.properties @@ -59,6 +59,3 @@ android.enableBuildConfigAsBytecode=true # By default, the plugin applies itself to all subprojects, but we don't want that as it would cause issues with builds using local AARs dependency.analysis.autoapply=false - -# Disable new R8 shrinking for local dependencies as it causes issues with release builds -android.disableMinifyLocalDependenciesForLibraries=false diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index a1fede3e54..5afd73b9ce 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -3,9 +3,9 @@ [versions] # Project -android_gradle_plugin = "8.4.1" -kotlin = "1.9.24" -ksp = "1.9.24-1.0.20" +android_gradle_plugin = "8.5.2" +kotlin = "1.9.25" +ksp = "1.9.25-1.0.20" firebaseAppDistribution = "5.0.0" # AndroidX @@ -19,13 +19,13 @@ datastore = "1.0.0" constraintlayout = "2.1.4" constraintlayout_compose = "1.0.1" lifecycle = "2.7.0" -activity = "1.9.0" -media3 = "1.3.1" +activity = "1.9.1" +media3 = "1.4.0" camera = "1.3.4" # Compose compose_bom = "2024.06.00" -composecompiler = "1.5.14" +composecompiler = "1.5.15" # Coroutines coroutines = "1.8.1" @@ -39,12 +39,12 @@ test_core = "1.6.1" #other coil = "2.7.0" datetime = "0.6.0" -dependencyAnalysis = "1.32.0" +dependencyAnalysis = "1.33.0" serialization_json = "1.6.3" showkase = "1.0.3" appyx = "1.4.0" sqldelight = "2.0.2" -wysiwyg = "2.37.7" +wysiwyg = "2.37.8" telephoto = "0.12.1" # DI @@ -56,7 +56,7 @@ autoservice = "1.1.1" # quality androidx-test-ext-junit = "1.2.1" -kover = "0.8.0" +kover = "0.8.3" [libraries] # Project @@ -75,7 +75,7 @@ oss_licenses_plugin = "com.google.android.gms:oss-licenses-plugin:0.10.6" # AndroidX androidx_core = { module = "androidx.core:core", version.ref = "core" } androidx_corektx = { module = "androidx.core:core-ktx", version.ref = "core" } -androidx_annotationjvm = "androidx.annotation:annotation-jvm:1.8.0" +androidx_annotationjvm = "androidx.annotation:annotation-jvm:1.8.2" androidx_datastore_preferences = { module = "androidx.datastore:datastore-preferences", version.ref = "datastore" } androidx_datastore_datastore = { module = "androidx.datastore:datastore", version.ref = "datastore" } androidx_exifinterface = "androidx.exifinterface:exifinterface:1.3.7" @@ -163,7 +163,7 @@ jsoup = "org.jsoup:jsoup:1.18.1" appyx_core = { module = "com.bumble.appyx:core", version.ref = "appyx" } molecule-runtime = "app.cash.molecule:molecule-runtime:2.0.0" timber = "com.jakewharton.timber:timber:5.0.1" -matrix_sdk = "org.matrix.rustcomponents:sdk-android:0.2.34" +matrix_sdk = "org.matrix.rustcomponents:sdk-android:0.2.39" 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" } @@ -177,7 +177,7 @@ vanniktech_blurhash = "com.vanniktech:blurhash:0.3.0" telephoto_zoomableimage = { module = "me.saket.telephoto:zoomable-image-coil", version.ref = "telephoto" } telephoto_flick = { module = "me.saket.telephoto:flick-android", version.ref = "telephoto" } statemachine = "com.freeletics.flowredux:compose:1.2.2" -maplibre = "org.maplibre.gl:android-sdk:11.0.1" +maplibre = "org.maplibre.gl:android-sdk:11.1.0" maplibre_ktx = "org.maplibre.gl:android-sdk-ktx-v7:3.0.0" maplibre_annotation = "org.maplibre.gl:android-plugin-annotation-v9:3.0.0" opusencoder = "io.element.android:opusencoder:1.1.0" @@ -186,8 +186,8 @@ zxing_cpp = "io.github.zxing-cpp:android:2.2.0" play_services_oss_licenses = "com.google.android.gms:play-services-oss-licenses:17.1.0" # Analytics -posthog = "com.posthog:posthog-android:3.4.2" -sentry = "io.sentry:sentry-android:7.12.0" +posthog = "com.posthog:posthog-android:3.5.0" +sentry = "io.sentry:sentry-android:7.14.0" # main branch can be tested replacing the version with main-SNAPSHOT matrix_analytics_events = "com.github.matrix-org:matrix-analytics-events:0.23.1" diff --git a/libraries/androidutils/src/main/res/values-uz/translations.xml b/libraries/androidutils/src/main/res/values-uz/translations.xml new file mode 100644 index 0000000000..a41abbde52 --- /dev/null +++ b/libraries/androidutils/src/main/res/values-uz/translations.xml @@ -0,0 +1,4 @@ + + + "Bu amalni bajarish uchun mos ilova topilmadi." + diff --git a/libraries/designsystem/build.gradle.kts b/libraries/designsystem/build.gradle.kts index e737220961..81abc3127f 100644 --- a/libraries/designsystem/build.gradle.kts +++ b/libraries/designsystem/build.gradle.kts @@ -29,7 +29,6 @@ android { buildTypes { getByName("release") { - isMinifyEnabled = true consumerProguardFiles("consumer-rules.pro") } } diff --git a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/theme/ColorAliases.kt b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/theme/ColorAliases.kt index 5fc6fd2a23..4603541055 100644 --- a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/theme/ColorAliases.kt +++ b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/theme/ColorAliases.kt @@ -179,6 +179,14 @@ val SemanticColors.badgeNegativeBackgroundColor val SemanticColors.badgeNegativeContentColor get() = if (isLight) LightColorTokens.colorRed1100 else DarkColorTokens.colorRed1100 +@OptIn(CoreColorToken::class) +val SemanticColors.pinnedMessageBannerIndicator + get() = if (isLight) LightColorTokens.colorAlphaGray600 else DarkColorTokens.colorAlphaGray600 + +@OptIn(CoreColorToken::class) +val SemanticColors.pinnedMessageBannerBorder + get() = if (isLight) LightColorTokens.colorAlphaGray400 else DarkColorTokens.colorAlphaGray400 + @PreviewsDayNight @Composable internal fun ColorAliasesPreview() = ElementPreview { diff --git a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/utils/LazyListState.kt b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/utils/LazyListState.kt new file mode 100644 index 0000000000..7e1eb53461 --- /dev/null +++ b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/utils/LazyListState.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 + * + * https://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.foundation.lazy.LazyListState +import androidx.compose.runtime.Composable +import androidx.compose.runtime.derivedStateOf +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableIntStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue + +/** + * Returns whether the lazy list is currently scrolling up. + */ +@Composable +fun LazyListState.isScrollingUp(): Boolean { + var previousIndex by remember(this) { mutableIntStateOf(firstVisibleItemIndex) } + var previousScrollOffset by remember(this) { mutableIntStateOf(firstVisibleItemScrollOffset) } + return remember(this) { + derivedStateOf { + if (previousIndex != firstVisibleItemIndex) { + previousIndex > firstVisibleItemIndex + } else { + previousScrollOffset >= firstVisibleItemScrollOffset + }.also { + previousIndex = firstVisibleItemIndex + previousScrollOffset = firstVisibleItemScrollOffset + } + } + }.value +} diff --git a/libraries/encrypted-db/build.gradle.kts b/libraries/encrypted-db/build.gradle.kts index 40db7f7fde..f64e22875e 100644 --- a/libraries/encrypted-db/build.gradle.kts +++ b/libraries/encrypted-db/build.gradle.kts @@ -22,7 +22,7 @@ android { buildTypes { release { - isMinifyEnabled = true + isMinifyEnabled = false consumerProguardFiles("consumer-proguard-rules.pro") } } diff --git a/libraries/eventformatter/api/src/main/kotlin/io/element/android/libraries/eventformatter/api/PinnedMessagesBannerFormatter.kt b/libraries/eventformatter/api/src/main/kotlin/io/element/android/libraries/eventformatter/api/PinnedMessagesBannerFormatter.kt new file mode 100644 index 0000000000..9db3a19bd7 --- /dev/null +++ b/libraries/eventformatter/api/src/main/kotlin/io/element/android/libraries/eventformatter/api/PinnedMessagesBannerFormatter.kt @@ -0,0 +1,23 @@ +/* + * 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 + * + * https://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.eventformatter.api + +import io.element.android.libraries.matrix.api.timeline.item.event.EventTimelineItem + +interface PinnedMessagesBannerFormatter { + fun format(event: EventTimelineItem): CharSequence +} diff --git a/libraries/eventformatter/impl/src/main/kotlin/io/element/android/libraries/eventformatter/impl/DefaultPinnedMessagesBannerFormatter.kt b/libraries/eventformatter/impl/src/main/kotlin/io/element/android/libraries/eventformatter/impl/DefaultPinnedMessagesBannerFormatter.kt new file mode 100644 index 0000000000..05403e5355 --- /dev/null +++ b/libraries/eventformatter/impl/src/main/kotlin/io/element/android/libraries/eventformatter/impl/DefaultPinnedMessagesBannerFormatter.kt @@ -0,0 +1,121 @@ +/* + * 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 + * + * https://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.eventformatter.impl + +import androidx.annotation.StringRes +import androidx.compose.ui.text.AnnotatedString +import com.squareup.anvil.annotations.ContributesBinding +import io.element.android.libraries.di.SessionScope +import io.element.android.libraries.eventformatter.api.PinnedMessagesBannerFormatter +import io.element.android.libraries.matrix.api.permalink.PermalinkParser +import io.element.android.libraries.matrix.api.timeline.item.event.AudioMessageType +import io.element.android.libraries.matrix.api.timeline.item.event.EmoteMessageType +import io.element.android.libraries.matrix.api.timeline.item.event.EventTimelineItem +import io.element.android.libraries.matrix.api.timeline.item.event.FileMessageType +import io.element.android.libraries.matrix.api.timeline.item.event.ImageMessageType +import io.element.android.libraries.matrix.api.timeline.item.event.LocationMessageType +import io.element.android.libraries.matrix.api.timeline.item.event.MessageContent +import io.element.android.libraries.matrix.api.timeline.item.event.MessageType +import io.element.android.libraries.matrix.api.timeline.item.event.NoticeMessageType +import io.element.android.libraries.matrix.api.timeline.item.event.OtherMessageType +import io.element.android.libraries.matrix.api.timeline.item.event.PollContent +import io.element.android.libraries.matrix.api.timeline.item.event.RedactedContent +import io.element.android.libraries.matrix.api.timeline.item.event.StickerContent +import io.element.android.libraries.matrix.api.timeline.item.event.StickerMessageType +import io.element.android.libraries.matrix.api.timeline.item.event.TextMessageType +import io.element.android.libraries.matrix.api.timeline.item.event.UnableToDecryptContent +import io.element.android.libraries.matrix.api.timeline.item.event.VideoMessageType +import io.element.android.libraries.matrix.api.timeline.item.event.VoiceMessageType +import io.element.android.libraries.matrix.api.timeline.item.event.getDisambiguatedDisplayName +import io.element.android.libraries.matrix.ui.messages.toPlainText +import io.element.android.libraries.ui.strings.CommonStrings +import io.element.android.services.toolbox.api.strings.StringProvider +import javax.inject.Inject + +@ContributesBinding(SessionScope::class) +class DefaultPinnedMessagesBannerFormatter @Inject constructor( + private val sp: StringProvider, + private val permalinkParser: PermalinkParser, +) : PinnedMessagesBannerFormatter { + override fun format(event: EventTimelineItem): CharSequence { + return when (val content = event.content) { + is MessageContent -> processMessageContents(event, content) + is StickerContent -> { + content.body.prefixWith(CommonStrings.common_sticker) + } + is UnableToDecryptContent -> { + sp.getString(CommonStrings.common_waiting_for_decryption_key) + } + is PollContent -> { + content.question.prefixWith(CommonStrings.a11y_poll) + } + RedactedContent -> { + sp.getString(CommonStrings.common_message_removed) + } + else -> { + sp.getString(CommonStrings.common_unsupported_event) + } + } + } + + private fun processMessageContents( + event: EventTimelineItem, + messageContent: MessageContent, + ): CharSequence { + return when (val messageType: MessageType = messageContent.type) { + is EmoteMessageType -> { + val senderDisambiguatedDisplayName = event.senderProfile.getDisambiguatedDisplayName(event.sender) + "* $senderDisambiguatedDisplayName ${messageType.body}" + } + is TextMessageType -> { + messageType.toPlainText(permalinkParser) + } + is VideoMessageType -> { + messageType.body.prefixWith(CommonStrings.common_video) + } + is ImageMessageType -> { + messageType.body.prefixWith(CommonStrings.common_image) + } + is StickerMessageType -> { + messageType.body.prefixWith(CommonStrings.common_sticker) + } + is LocationMessageType -> { + messageType.body.prefixWith(CommonStrings.common_shared_location) + } + is FileMessageType -> { + messageType.body.prefixWith(CommonStrings.common_file) + } + is AudioMessageType -> { + messageType.body.prefixWith(CommonStrings.common_audio) + } + is VoiceMessageType -> { + messageType.body.prefixWith(CommonStrings.common_voice_message) + } + is OtherMessageType -> { + messageType.body + } + is NoticeMessageType -> { + messageType.body + } + } + } + + private fun CharSequence.prefixWith(@StringRes res: Int): AnnotatedString { + val prefix = sp.getString(res) + return prefixWith(prefix) + } +} diff --git a/libraries/eventformatter/impl/src/main/kotlin/io/element/android/libraries/eventformatter/impl/DefaultRoomLastMessageFormatter.kt b/libraries/eventformatter/impl/src/main/kotlin/io/element/android/libraries/eventformatter/impl/DefaultRoomLastMessageFormatter.kt index 13655c48f2..ac125b48e6 100644 --- a/libraries/eventformatter/impl/src/main/kotlin/io/element/android/libraries/eventformatter/impl/DefaultRoomLastMessageFormatter.kt +++ b/libraries/eventformatter/impl/src/main/kotlin/io/element/android/libraries/eventformatter/impl/DefaultRoomLastMessageFormatter.kt @@ -16,11 +16,6 @@ package io.element.android.libraries.eventformatter.impl -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.withStyle import com.squareup.anvil.annotations.ContributesBinding import io.element.android.libraries.di.SessionScope import io.element.android.libraries.eventformatter.api.RoomLastMessageFormatter @@ -79,7 +74,7 @@ class DefaultRoomLastMessageFormatter @Inject constructor( RedactedContent -> { val message = sp.getString(CommonStrings.common_message_removed) if (!isDmRoom) { - prefix(message, senderDisambiguatedDisplayName) + message.prefixWith(senderDisambiguatedDisplayName) } else { message } @@ -90,7 +85,7 @@ class DefaultRoomLastMessageFormatter @Inject constructor( is UnableToDecryptContent -> { val message = sp.getString(CommonStrings.common_waiting_for_decryption_key) if (!isDmRoom) { - prefix(message, senderDisambiguatedDisplayName) + message.prefixWith(senderDisambiguatedDisplayName) } else { message } @@ -113,7 +108,6 @@ class DefaultRoomLastMessageFormatter @Inject constructor( } is LegacyCallInviteContent -> sp.getString(CommonStrings.common_call_invite) is CallNotifyContent -> sp.getString(CommonStrings.common_call_started) - else -> null }?.take(MAX_SAFE_LENGTH) } @@ -168,16 +162,6 @@ class DefaultRoomLastMessageFormatter @Inject constructor( ): CharSequence = if (isDmRoom) { message } else { - prefix(message, senderDisambiguatedDisplayName) - } - - private fun prefix(message: String, senderDisambiguatedDisplayName: String): AnnotatedString { - return buildAnnotatedString { - withStyle(SpanStyle(fontWeight = FontWeight.Bold)) { - append(senderDisambiguatedDisplayName) - } - append(": ") - append(message) - } + message.prefixWith(senderDisambiguatedDisplayName) } } diff --git a/libraries/eventformatter/impl/src/main/kotlin/io/element/android/libraries/eventformatter/impl/PrefixWith.kt b/libraries/eventformatter/impl/src/main/kotlin/io/element/android/libraries/eventformatter/impl/PrefixWith.kt new file mode 100644 index 0000000000..a5991e31df --- /dev/null +++ b/libraries/eventformatter/impl/src/main/kotlin/io/element/android/libraries/eventformatter/impl/PrefixWith.kt @@ -0,0 +1,33 @@ +/* + * 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 + * + * https://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.eventformatter.impl + +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.withStyle + +internal fun CharSequence.prefixWith(prefix: String): AnnotatedString { + return buildAnnotatedString { + withStyle(SpanStyle(fontWeight = FontWeight.Bold)) { + append(prefix) + } + append(": ") + append(this@prefixWith) + } +} diff --git a/libraries/eventformatter/impl/src/main/kotlin/io/element/android/libraries/eventformatter/impl/StateContentFormatter.kt b/libraries/eventformatter/impl/src/main/kotlin/io/element/android/libraries/eventformatter/impl/StateContentFormatter.kt index ef15216a66..09cb6ef2ce 100644 --- a/libraries/eventformatter/impl/src/main/kotlin/io/element/android/libraries/eventformatter/impl/StateContentFormatter.kt +++ b/libraries/eventformatter/impl/src/main/kotlin/io/element/android/libraries/eventformatter/impl/StateContentFormatter.kt @@ -80,6 +80,15 @@ class StateContentFormatter @Inject constructor( else -> sp.getString(R.string.state_event_room_topic_removed, senderDisambiguatedDisplayName) } } + is OtherState.RoomPinnedEvents -> when (renderingMode) { + RenderingMode.RoomList -> { + Timber.v("Filtering timeline item for room state change: $content") + null + } + RenderingMode.Timeline -> { + formatRoomPinnedEvents(content, senderIsYou, senderDisambiguatedDisplayName) + } + } is OtherState.Custom -> when (renderingMode) { RenderingMode.RoomList -> { Timber.v("Filtering timeline item for room state change: $content") @@ -161,15 +170,6 @@ class StateContentFormatter @Inject constructor( "RoomJoinRules" } } - OtherState.RoomPinnedEvents -> when (renderingMode) { - RenderingMode.RoomList -> { - Timber.v("Filtering timeline item for room state change: $content") - null - } - RenderingMode.Timeline -> { - "RoomPinnedEvents" - } - } is OtherState.RoomUserPowerLevels -> when (renderingMode) { RenderingMode.RoomList -> { Timber.v("Filtering timeline item for room state change: $content") @@ -217,4 +217,23 @@ class StateContentFormatter @Inject constructor( } } } + + private fun formatRoomPinnedEvents( + content: OtherState.RoomPinnedEvents, + senderIsYou: Boolean, + senderDisambiguatedDisplayName: String + ) = when (content.change) { + OtherState.RoomPinnedEvents.Change.ADDED -> when { + senderIsYou -> sp.getString(R.string.state_event_room_pinned_events_pinned_by_you) + else -> sp.getString(R.string.state_event_room_pinned_events_pinned, senderDisambiguatedDisplayName) + } + OtherState.RoomPinnedEvents.Change.REMOVED -> when { + senderIsYou -> sp.getString(R.string.state_event_room_pinned_events_unpinned_by_you) + else -> sp.getString(R.string.state_event_room_pinned_events_unpinned, senderDisambiguatedDisplayName) + } + OtherState.RoomPinnedEvents.Change.CHANGED -> when { + senderIsYou -> sp.getString(R.string.state_event_room_pinned_events_changed_by_you) + else -> sp.getString(R.string.state_event_room_pinned_events_changed, senderDisambiguatedDisplayName) + } + } } diff --git a/libraries/eventformatter/impl/src/main/res/values-be/translations.xml b/libraries/eventformatter/impl/src/main/res/values-be/translations.xml index dcc942e4fc..5f1722ad1a 100644 --- a/libraries/eventformatter/impl/src/main/res/values-be/translations.xml +++ b/libraries/eventformatter/impl/src/main/res/values-be/translations.xml @@ -45,6 +45,12 @@ "Вы выдалілі назву пакоя" "%1$s не зрабіў(-ла) ніякіх змен" "Вы не зрабілі ніякіх змен" + "%1$s змяніў(-ла) замацаваныя паведамленні" + "Вы змянілі замацаваныя паведамленні" + "%1$s замацаваў(-ла) паведамленне" + "Вы замацавалі паведамленне" + "%1$s адмацаваў(-ла) паведамленне" + "Вы адмацавалі паведамленне" "%1$s адхіліў(-ла) запрашэнне" "Вы адхілілі запрашэнне" "%1$s выдаліў(-ла) %2$s" diff --git a/libraries/eventformatter/impl/src/main/res/values-et/translations.xml b/libraries/eventformatter/impl/src/main/res/values-et/translations.xml index 715453fbef..506f22db55 100644 --- a/libraries/eventformatter/impl/src/main/res/values-et/translations.xml +++ b/libraries/eventformatter/impl/src/main/res/values-et/translations.xml @@ -45,6 +45,12 @@ "Sina eemaldasid jututoa nime" "%1$s ei teinud ühtegi muudatust" "Sina ei teinud ühtegi muudatust" + "%1$s muutis esiletõstetud sõnumeid" + "Sina muutsid esiletõstetud sõnumeid" + "%1$s tõstis sõnumi esile" + "Sina tõstsid sõnumi esile" + "%1$s eemaldas esiletõstetud sõnumi" + "Sina eemaldasid esiletõstetud sõnumi" "%1$s lükkas kutse tagasi" "Sina lükkasid kutse tagasi" "%1$s eemaldas jututoast kasutaja %2$s" 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 c23e973217..879e21c466 100644 --- a/libraries/eventformatter/impl/src/main/res/values-hu/translations.xml +++ b/libraries/eventformatter/impl/src/main/res/values-hu/translations.xml @@ -45,6 +45,12 @@ "Eltávolította a szoba nevét" "%1$s nem változtatott semmin" "Nem változtatott semmin" + "%1$s megváltoztatta a kitűzött üzeneteket" + "Megváltoztatta a kitűzött üzeneteket" + "%1$s kitűzött egy üzenetet" + "Kitűzött egy üzenetet" + "%1$s feloldotta egy üzenet kitűzését" + "Feloldotta egy üzenet kitűzését" "%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/eventformatter/impl/src/main/res/values-pl/translations.xml b/libraries/eventformatter/impl/src/main/res/values-pl/translations.xml index 0c3bddc3c1..2efaca2b08 100644 --- a/libraries/eventformatter/impl/src/main/res/values-pl/translations.xml +++ b/libraries/eventformatter/impl/src/main/res/values-pl/translations.xml @@ -3,12 +3,16 @@ "(zdjęcie profilowe też zostało zmienione)" "%1$s zmienił swoje zdjęcie profilowe" "Zmieniłeś swoje zdjęcie profilowe" + "%1$s został zdegradowany do członka" + "%1$s został zdegradowany do moderatora" "%1$s zmienił swoją wyświetlaną nazwę z %2$s na %3$s" "Zmieniłeś swoją wyświetlaną nazwę z %1$s na %2$s" "%1$s usunął swoją wyświetlaną nazwę (byo to %2$s)" "Usunąłeś swoją wyświetlaną nazwę (było to %1$s)" "%1$s ustawił swoją wyświetlaną nazwę na %2$s" "Ustawiłeś swoją wyświetlaną nazwę na %1$s" + "%1$s został awansowany na administratora" + "%1$s został awansowany na moderatora" "%1$s zmienił zdjęcie profilowe pokoju" "Zmieniłeś zdjęcie profilowe pokoju" "%1$s usunął zdjęcie profilowe pokoju" @@ -42,7 +46,7 @@ "%1$s nie wprowadził żadnych zmian" "Nie wprowadzono żadnych zmian" "%1$s odrzucił zaproszenie" - "Odrzuciłeś(aś) zaproszenie" + "Odrzuciłeś zaproszenie" "%1$s usunął %2$s" "Usunąłeś %1$s" "%1$s wysłał zaproszenie do %2$s, aby dołączył do pokoju" diff --git a/libraries/eventformatter/impl/src/main/res/values-pt-rBR/translations.xml b/libraries/eventformatter/impl/src/main/res/values-pt-rBR/translations.xml index 8cb375f1b7..5148cc7638 100644 --- a/libraries/eventformatter/impl/src/main/res/values-pt-rBR/translations.xml +++ b/libraries/eventformatter/impl/src/main/res/values-pt-rBR/translations.xml @@ -3,12 +3,16 @@ "(o avatar também foi alterado)" "%1$s mudou seu avatar" "Você mudou seu avatar" + "%1$s foi rebaixado a membro" + "%1$s foi rebaixado a moderador" "%1$s mudou seu nome de exibição de %2$s para %3$s" "Você alterou seu nome de exibição de %1$s para %2$s" "%1$s removeu seu nome de exibição (era %2$s)" "Você removeu seu nome de exibição (era %1$s)" "%1$s definiu seu nome de exibição como %2$s" "Você definiu seu nome de exibição como %1$s" + "%1$s foi promovido a administrador" + "%1$s foi promovido a moderador" "%1$s mudou o avatar da sala" "Você mudou o avatar da sala" "%1$s removeu o avatar da sala" @@ -39,6 +43,8 @@ "Você mudou o nome da sala para: %1$s" "%1$s removeu o nome da sala" "Você removeu o nome da sala" + "%1$s não fez alterações" + "Você não fez nenhuma alteração" "%1$s rejeitou o convite" "Você rejeitou o convite" "%1$s removido %2$s" diff --git a/libraries/eventformatter/impl/src/main/res/values-pt/translations.xml b/libraries/eventformatter/impl/src/main/res/values-pt/translations.xml index 6d214ab03e..9d21c1949c 100644 --- a/libraries/eventformatter/impl/src/main/res/values-pt/translations.xml +++ b/libraries/eventformatter/impl/src/main/res/values-pt/translations.xml @@ -45,6 +45,12 @@ "Removeste o nome da sala" "%1$s não fiz nenhuma alteração" "Não fizeste nenhuma alteração" + "%1$s alterou as mensagens afixadas" + "Alteraste as mensagens afixadas" + "%1$s afixou uma mensagem" + "Afixaste uma mensagem" + "%1$s desafixou uma mensagem" + "Desafixaste uma mensagem" "%1$s rejeitou o convite" "Rejeitaste o convite" "%1$s removeu %2$s" diff --git a/libraries/eventformatter/impl/src/main/res/values-ru/translations.xml b/libraries/eventformatter/impl/src/main/res/values-ru/translations.xml index a6a339bba6..385630ef4c 100644 --- a/libraries/eventformatter/impl/src/main/res/values-ru/translations.xml +++ b/libraries/eventformatter/impl/src/main/res/values-ru/translations.xml @@ -45,6 +45,12 @@ "Вы удалили название комнаты" "%1$s ничего не изменил" "Вы не внесли никаких изменений" + "%1$s изменил закрепленные сообщения" + "Вы изменили закрепленные сообщения" + "%1$s закрепил сообщение" + "Вы закрепили сообщение" + "%1$s открепил сообщение" + "Вы открепили сообщение" "%1$s отклонил приглашение" "Вы отклонили приглашение" "%1$s удалил %2$s" diff --git a/libraries/eventformatter/impl/src/main/res/values-sk/translations.xml b/libraries/eventformatter/impl/src/main/res/values-sk/translations.xml index 9a9f41a3fb..5e9976b80a 100644 --- a/libraries/eventformatter/impl/src/main/res/values-sk/translations.xml +++ b/libraries/eventformatter/impl/src/main/res/values-sk/translations.xml @@ -45,6 +45,12 @@ "Odstránili ste názov miestnosti" "%1$s nevykonal/a žiadne zmeny" "Nevykonali ste žiadne zmeny" + "%1$s zmenil/a pripnuté správy" + "Zmenili ste pripnuté správy" + "%1$s pripol/la správu" + "Pripli ste správu" + "%1$s zrušil/a pripnutie správy" + "Zrušili ste pripnutie správy" "%1$s odmietol/a pozvánku" "Odmietli ste pozvánku" "%1$s odstránil/a %2$s" diff --git a/libraries/eventformatter/impl/src/main/res/values-sv/translations.xml b/libraries/eventformatter/impl/src/main/res/values-sv/translations.xml index 014f21ee4a..d96f722111 100644 --- a/libraries/eventformatter/impl/src/main/res/values-sv/translations.xml +++ b/libraries/eventformatter/impl/src/main/res/values-sv/translations.xml @@ -45,6 +45,12 @@ "Du tog bort rummets namn" "%1$s gjorde inga ändringar" "Du gjorde inga ändringar" + "%1$s ändrade de fästa meddelandena" + "Du ändrade de fästa meddelandena" + "%1$s fäste ett meddelande" + "Du har fäste ett meddelande" + "%1$s lossade ett meddelande" + "Du har lossade ett meddelande" "%1$s avvisade inbjudan" "Du avvisade inbjudan" "%1$s tog bort %2$s" diff --git a/libraries/eventformatter/impl/src/main/res/values-uk/translations.xml b/libraries/eventformatter/impl/src/main/res/values-uk/translations.xml index eccaa950eb..065f08cad4 100644 --- a/libraries/eventformatter/impl/src/main/res/values-uk/translations.xml +++ b/libraries/eventformatter/impl/src/main/res/values-uk/translations.xml @@ -30,7 +30,7 @@ "Ви приєдналися до кімнати" "%1$s подав (-ла) запит на приєднання" "%1$s дозволив (-ла) %2$s приєднатися" - "%1$s дозволив (-ла) Вам приєднатися" + "Ви дозволили %1$s приєднатися" "Ви подали запит на приєднання" "%1$s відхилив (-ла) запит %2$s на приєднання" "Ви відхилили запит %1$s на приєднання" @@ -45,6 +45,12 @@ "Ви видалили назву кімнати" "%1$s не внесено жодних змін" "Ви не внесли жодних змін" + "%1$s змінив(-ла) закріплені повідомлення" + "Ви змінили закріплені повідомлення" + "%1$s закріпив(-ла) повідомлення" + "Ви закріпили повідомлення" + "%1$s відкріпив(-ла) повідомлення" + "Ви відкріпили повідомлення" "%1$s відхилив (-ла) запрошення" "Ви відхилили запрошення" "%1$s вилучив (-ла) %2$s" diff --git a/libraries/eventformatter/impl/src/main/res/values-uz/translations.xml b/libraries/eventformatter/impl/src/main/res/values-uz/translations.xml new file mode 100644 index 0000000000..5afcc9b061 --- /dev/null +++ b/libraries/eventformatter/impl/src/main/res/values-uz/translations.xml @@ -0,0 +1,57 @@ + + + "(avatar ham o\'zgartirildi)" + "%1$s avatarini o\'zgartirdi" + "Siz avataringizni o\'zgartirdingiz" + "%1$s ko\'rsatiladigan nomini %2$sdan %3$sga o\'zgartirdi" + "Siz ko\'rsatiladigan nomingizni %1$s dan %2$s ga o\'zgartirdingiz" + "%1$s ko\'rinadigan nomini o\'chirib tashladi (avval %2$s bo\'lgan edi)" + "Siz ko\'rinadigan nomingizni o\'chirib tashladingiz (avval %1$s bo\'lgan edi)" + "%1$s ularning ko\'rsatiladigan nomini o\'rnating %2$s" + "Siz ko\'rsatiladigan nomingizni o\'rnating %1$s" + "%1$s xonani avatarini o\'zgartirdi" + "Siz xonani avatarini o\'zgartirdingiz" + "%1$s xonani avatarini o\'chirib tashladi" + "Siz xonani avatarini o\'chirib tashladingiz" + "%1$staqiqlangan%2$s" + "Siz taqiqlangansiz%1$s" + "%1$sxonani yaratdi" + "Siz xonani yaratdingiz" + "%1$staklif qilingan%2$s" + "%1$staklifni qabul qildi" + "Siz taklifni qabul qildingiz" + "Siz taklif qildingiz%1$s" + "%1$ssizni taklif qildi" + "%1$sxonaga qo\'shildi" + "Siz xonaga qo\'shildingiz" + "%1$s qo\'shilishni so\'radi" + "%1$s %2$sga qo\'shilishga ruxsat berdi" + "Siz %1$sga qo\'shilishaga ruxsat berdingiz" + "Siz qoʻshilishni soʻragansiz" + "%1$s %2$sning qo\'shilish haqidagi iltimosini rad etdi" + "Siz %1$sning qo\'shiliz iltimosini rad etdingiz" + "%1$s sizni qo\'shilish iltimosingizni rad etdi" + "%1$ endi qo\'shilishdan manfaatdor emas" + "Siz qoʻshilish soʻrovingizni bekor qildingiz" + "%1$sxonani tark etdi" + "Siz xonani tark etdingiz" + "%1$s xonani nomini %2$s o\'zgartirdi" + "Siz xonani nomini %1$s ga o\'zgartirdingiz" + "%1$s xonani nomini o\'chirib tashladi" + "Siz xonani nomini o\'chirib tashladingiz" + "%1$staklifni rad etdi" + "Siz taklifni rad etdingiz" + "%1$o\'chirildi%2$s" + "siz o\'chirildingiz%1$s" + "%1$s taklifnoma yubordi %2$sga xonaga qo\'shilish uchun" + "Siz taklifnoma yubordingiz %1$sga xonaga qo\'shilishi uchun" + "%1$s taklifni %2$sga xonaga qo\'shilish uchun bekor qildi" + "Siz xonaga qo\'shilish taklifini $1$s ga bekor qildingiz" + "%1$s mavzuni %2$s o\'zgartirdi" + "Siz mavzuni %1$s ga o\'zgartirdingiz" + "%1$s xonani mavzusini o\'chirib tashladi" + "Siz xonani mavzusini o\'chirib tashladingiz" + "%1$staqiqlanmagan%2$s" + "Siz %1$s taqiqini bekor qildingiz" + "%1$s aʼzoligiga nomaʼlum oʻzgarishlar kiritdi" + diff --git a/libraries/eventformatter/impl/src/main/res/values/localazy.xml b/libraries/eventformatter/impl/src/main/res/values/localazy.xml index 5e06d74e92..12dbc16a1d 100644 --- a/libraries/eventformatter/impl/src/main/res/values/localazy.xml +++ b/libraries/eventformatter/impl/src/main/res/values/localazy.xml @@ -45,6 +45,12 @@ "You removed the room name" "%1$s made no changes" "You made no changes" + "%1$s changed the pinned messages" + "You changed the pinned messages" + "%1$s pinned a message" + "You pinned a message" + "%1$s unpinned a message" + "You unpinned a message" "%1$s rejected the invitation" "You rejected the invitation" "%1$s removed %2$s" diff --git a/libraries/eventformatter/impl/src/test/kotlin/io/element/android/libraries/eventformatter/impl/DefaultRoomLastMessageFormatterTest.kt b/libraries/eventformatter/impl/src/test/kotlin/io/element/android/libraries/eventformatter/impl/DefaultRoomLastMessageFormatterTest.kt index 5465882479..3f742c0954 100644 --- a/libraries/eventformatter/impl/src/test/kotlin/io/element/android/libraries/eventformatter/impl/DefaultRoomLastMessageFormatterTest.kt +++ b/libraries/eventformatter/impl/src/test/kotlin/io/element/android/libraries/eventformatter/impl/DefaultRoomLastMessageFormatterTest.kt @@ -660,7 +660,7 @@ class DefaultRoomLastMessageFormatterTest { OtherState.RoomGuestAccess, OtherState.RoomHistoryVisibility, OtherState.RoomJoinRules, - OtherState.RoomPinnedEvents, + OtherState.RoomPinnedEvents(OtherState.RoomPinnedEvents.Change.CHANGED), OtherState.RoomUserPowerLevels(emptyMap()), OtherState.RoomServerAcl, OtherState.RoomTombstone, diff --git a/libraries/eventformatter/test/src/main/kotlin/io/element/android/libraries/eventformatter/test/FakePinnedMessagesBannerFormatter.kt b/libraries/eventformatter/test/src/main/kotlin/io/element/android/libraries/eventformatter/test/FakePinnedMessagesBannerFormatter.kt new file mode 100644 index 0000000000..668803169e --- /dev/null +++ b/libraries/eventformatter/test/src/main/kotlin/io/element/android/libraries/eventformatter/test/FakePinnedMessagesBannerFormatter.kt @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2024 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://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.eventformatter.test + +import io.element.android.libraries.eventformatter.api.PinnedMessagesBannerFormatter +import io.element.android.libraries.matrix.api.timeline.item.event.EventTimelineItem + +class FakePinnedMessagesBannerFormatter( + val formatLambda: (event: EventTimelineItem) -> CharSequence +) : PinnedMessagesBannerFormatter { + override fun format(event: EventTimelineItem): CharSequence { + return formatLambda(event) + } +} 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 616a549e63..ccc910d02c 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 @@ -120,4 +120,18 @@ enum class FeatureFlags( defaultValue = { it.buildType != BuildType.RELEASE }, isFinished = false, ), + PinnedEvents( + key = "feature.pinnedEvents", + title = "Pinned Events", + description = "Allow user to pin events in a room", + defaultValue = { false }, + isFinished = false, + ), + SyncOnPush( + key = "feature.syncOnPush", + title = "Sync on push", + description = "Subscribe to room sync when a push is received", + defaultValue = { true }, + isFinished = false, + ), } 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 378ada5b16..a469904aac 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 @@ -106,6 +106,11 @@ interface MatrixRoom : Closeable { */ suspend fun timelineFocusedOnEvent(eventId: EventId): Result + /** + * Create a new timeline for the pinned events of the room. + */ + suspend fun pinnedEventsTimeline(): Result + fun destroy() suspend fun subscribeToSync() @@ -180,6 +185,8 @@ interface MatrixRoom : Closeable { suspend fun canUserTriggerRoomNotification(userId: UserId): Result + suspend fun canUserPinUnpin(userId: UserId): Result + suspend fun canUserJoinCall(userId: UserId): Result = canUserSendState(userId, StateEventType.CALL_MEMBER) diff --git a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/MatrixRoomInfo.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/MatrixRoomInfo.kt index 70da8e7364..c7de03dac6 100644 --- a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/MatrixRoomInfo.kt +++ b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/MatrixRoomInfo.kt @@ -17,6 +17,7 @@ package io.element.android.libraries.matrix.api.room import androidx.compose.runtime.Immutable +import io.element.android.libraries.matrix.api.core.EventId import io.element.android.libraries.matrix.api.core.RoomAlias import io.element.android.libraries.matrix.api.core.RoomId import io.element.android.libraries.matrix.api.core.UserId @@ -52,4 +53,5 @@ data class MatrixRoomInfo( val hasRoomCall: Boolean, val activeRoomCallParticipants: ImmutableList, val heroes: ImmutableList, + val pinnedEventIds: ImmutableList ) diff --git a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/powerlevels/MatrixRoomPowerLevels.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/powerlevels/MatrixRoomPowerLevels.kt index ef4e6f747e..2abd42f519 100644 --- a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/powerlevels/MatrixRoomPowerLevels.kt +++ b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/powerlevels/MatrixRoomPowerLevels.kt @@ -65,3 +65,8 @@ suspend fun MatrixRoom.canRedactOwn(): Result = canUserRedactOwn(sessio * Shortcut for calling [MatrixRoom.canRedactOther] with our own user. */ suspend fun MatrixRoom.canRedactOther(): Result = canUserRedactOther(sessionId) + +/** + * Shortcut for calling [MatrixRoom.canUserPinUnpin] with our own user. + */ +suspend fun MatrixRoom.canPinUnpin(): Result = canUserPinUnpin(sessionId) diff --git a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/timeline/Timeline.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/timeline/Timeline.kt index 3d8defa252..f42ec5fbe9 100644 --- a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/timeline/Timeline.kt +++ b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/timeline/Timeline.kt @@ -169,4 +169,22 @@ interface Timeline : AutoCloseable { ): Result suspend fun loadReplyDetails(eventId: EventId): InReplyTo + + /** + * Adds a new pinned event by sending an updated `m.room.pinned_events` + * event containing the new event id. + * + * Returns `true` if we sent the request, `false` if the event was already + * pinned. + */ + suspend fun pinEvent(eventId: EventId): Result + + /** + * Adds a new pinned event by sending an updated `m.room.pinned_events` + * event without the event id we want to remove. + * + * Returns `true` if we sent the request, `false` if the event wasn't + * pinned + */ + suspend fun unpinEvent(eventId: EventId): Result } diff --git a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/timeline/item/event/EventTimelineItem.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/timeline/item/event/EventTimelineItem.kt index 170fedfa28..cc2ad701fe 100644 --- a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/timeline/item/event/EventTimelineItem.kt +++ b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/timeline/item/event/EventTimelineItem.kt @@ -26,6 +26,7 @@ data class EventTimelineItem( val eventId: EventId?, val transactionId: TransactionId?, val isEditable: Boolean, + val canBeRepliedTo: Boolean, val isLocal: Boolean, val isOwn: Boolean, val isRemote: Boolean, 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 d963b71a63..c046f6b2ae 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 @@ -32,7 +32,14 @@ sealed interface OtherState { data object RoomHistoryVisibility : OtherState data object RoomJoinRules : OtherState data class RoomName(val name: String?) : OtherState - data object RoomPinnedEvents : OtherState + data class RoomPinnedEvents(val change: Change) : OtherState { + enum class Change { + ADDED, + REMOVED, + CHANGED + } + } + data class RoomUserPowerLevels(val users: Map) : OtherState data object RoomServerAcl : OtherState data class RoomThirdPartyInvite(val displayName: String?) : OtherState diff --git a/libraries/matrix/impl/build.gradle.kts b/libraries/matrix/impl/build.gradle.kts index 523ea2fda1..c74cb6ce07 100644 --- a/libraries/matrix/impl/build.gradle.kts +++ b/libraries/matrix/impl/build.gradle.kts @@ -37,12 +37,13 @@ dependencies { debugImplementation(libs.matrix.sdk) } implementation(projects.appconfig) - implementation(projects.libraries.di) implementation(projects.libraries.androidutils) + implementation(projects.libraries.di) + implementation(projects.libraries.featureflag.api) implementation(projects.libraries.network) + implementation(projects.libraries.preferences.api) implementation(projects.services.analytics.api) implementation(projects.services.toolbox.api) - implementation(projects.libraries.featureflag.api) api(projects.libraries.matrix.api) implementation(libs.dagger) implementation(projects.libraries.core) diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/RustMatrixClientFactory.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/RustMatrixClientFactory.kt index 7ddf54a300..51e71f3855 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/RustMatrixClientFactory.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/RustMatrixClientFactory.kt @@ -23,10 +23,12 @@ import io.element.android.libraries.matrix.impl.certificates.UserCertificatesPro import io.element.android.libraries.matrix.impl.proxy.ProxyProvider import io.element.android.libraries.matrix.impl.util.anonymizedTokens import io.element.android.libraries.network.useragent.UserAgentProvider +import io.element.android.libraries.preferences.api.store.AppPreferencesStore import io.element.android.libraries.sessionstorage.api.SessionData import io.element.android.libraries.sessionstorage.api.SessionStore import io.element.android.services.toolbox.api.systemclock.SystemClock import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.flow.first import kotlinx.coroutines.withContext import org.matrix.rustcomponents.sdk.ClientBuilder import org.matrix.rustcomponents.sdk.Session @@ -46,9 +48,18 @@ class RustMatrixClientFactory @Inject constructor( private val proxyProvider: ProxyProvider, private val clock: SystemClock, private val utdTracker: UtdTracker, + private val appPreferencesStore: AppPreferencesStore, ) { suspend fun create(sessionData: SessionData): RustMatrixClient = withContext(coroutineDispatchers.io) { - val client = getBaseClientBuilder(sessionData.sessionPath, sessionData.passphrase) + val client = getBaseClientBuilder( + sessionPath = sessionData.sessionPath, + passphrase = sessionData.passphrase, + slidingSync = if (appPreferencesStore.isSimplifiedSlidingSyncEnabledFlow().first()) { + ClientBuilderSlidingSync.Simplified + } else { + ClientBuilderSlidingSync.Restored + }, + ) .homeserverUrl(sessionData.homeserverUrl) .username(sessionData.userId) .use { it.build() } @@ -79,6 +90,7 @@ class RustMatrixClientFactory @Inject constructor( sessionPath: String, passphrase: String?, slidingSyncProxy: String? = null, + slidingSync: ClientBuilderSlidingSync, ): ClientBuilder { return ClientBuilder() .sessionPath(sessionPath) @@ -88,6 +100,13 @@ class RustMatrixClientFactory @Inject constructor( .addRootCertificates(userCertificatesProvider.provides()) .autoEnableBackups(true) .autoEnableCrossSigning(true) + .run { + when (slidingSync) { + ClientBuilderSlidingSync.Restored -> this + ClientBuilderSlidingSync.Discovered -> requiresSlidingSync() + ClientBuilderSlidingSync.Simplified -> simplifiedSlidingSync(true) + } + } .run { // Workaround for non-nullable proxy parameter in the SDK, since each call to the ClientBuilder returns a new reference we need to keep proxyProvider.provides()?.let { proxy(it) } ?: this @@ -95,6 +114,17 @@ class RustMatrixClientFactory @Inject constructor( } } +enum class ClientBuilderSlidingSync { + // The proxy will be supplied when restoring the Session. + Restored, + + // A proxy must be discovered whilst building the session. + Discovered, + + // Use Simplified Sliding Sync (discovery isn't a thing yet). + Simplified, +} + private fun SessionData.toSession() = Session( accessToken = accessToken, refreshToken = refreshToken, diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/auth/RustMatrixAuthenticationService.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/auth/RustMatrixAuthenticationService.kt index 8c0546fa8b..b447dd584b 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/auth/RustMatrixAuthenticationService.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/auth/RustMatrixAuthenticationService.kt @@ -29,6 +29,7 @@ import io.element.android.libraries.matrix.api.auth.OidcDetails import io.element.android.libraries.matrix.api.auth.qrlogin.MatrixQrCodeLoginData import io.element.android.libraries.matrix.api.auth.qrlogin.QrCodeLoginStep import io.element.android.libraries.matrix.api.core.SessionId +import io.element.android.libraries.matrix.impl.ClientBuilderSlidingSync import io.element.android.libraries.matrix.impl.RustMatrixClientFactory import io.element.android.libraries.matrix.impl.auth.qrlogin.QrErrorMapper import io.element.android.libraries.matrix.impl.auth.qrlogin.SdkQrCodeLoginData @@ -59,7 +60,7 @@ import javax.inject.Inject @ContributesBinding(AppScope::class) @SingleIn(AppScope::class) class RustMatrixAuthenticationService @Inject constructor( - baseDirectory: File, + private val baseDirectory: File, private val coroutineDispatchers: CoroutineDispatchers, private val sessionStore: SessionStore, private val rustMatrixClientFactory: RustMatrixClientFactory, @@ -69,10 +70,19 @@ class RustMatrixAuthenticationService @Inject constructor( // Passphrase which will be used for new sessions. Existing sessions will use the passphrase // stored in the SessionData. private val pendingPassphrase = getDatabasePassphrase() - private val sessionPath = File(baseDirectory, UUID.randomUUID().toString()).absolutePath + + // Need to keep a copy of the current session path to eventually delete it. + // Ideally it would be possible to get the sessionPath from the Client to avoid doing this. + private var sessionPath: File? = null private var currentClient: Client? = null private var currentHomeserver = MutableStateFlow(null) + private fun rotateSessionPath(): File { + sessionPath?.deleteRecursively() + return File(baseDirectory, UUID.randomUUID().toString()) + .also { sessionPath = it } + } + override fun loggedInStateFlow(): Flow { return sessionStore.isLoggedIn() } @@ -116,8 +126,9 @@ class RustMatrixAuthenticationService @Inject constructor( override suspend fun setHomeserver(homeserver: String): Result = withContext(coroutineDispatchers.io) { + val emptySessionPath = rotateSessionPath() runCatching { - val client = getBaseClientBuilder() + val client = getBaseClientBuilder(emptySessionPath) .serverNameOrHomeserverUrl(homeserver) .build() currentClient = client @@ -134,13 +145,14 @@ class RustMatrixAuthenticationService @Inject constructor( withContext(coroutineDispatchers.io) { runCatching { val client = currentClient ?: error("You need to call `setHomeserver()` first") + val currentSessionPath = sessionPath ?: error("You need to call `setHomeserver()` first") client.login(username, password, "Element X Android", null) val sessionData = client.session() .toSessionData( isTokenValid = true, loginType = LoginType.PASSWORD, passphrase = pendingPassphrase, - sessionPath = sessionPath, + sessionPath = currentSessionPath.absolutePath, ) clear() sessionStore.storeData(sessionData) @@ -184,13 +196,14 @@ class RustMatrixAuthenticationService @Inject constructor( return withContext(coroutineDispatchers.io) { runCatching { val client = currentClient ?: error("You need to call `setHomeserver()` first") + val currentSessionPath = sessionPath ?: error("You need to call `setHomeserver()` first") val urlForOidcLogin = pendingOidcAuthorizationData ?: error("You need to call `getOidcUrl()` first") client.loginWithOidcCallback(urlForOidcLogin, callbackUrl) val sessionData = client.session().toSessionData( isTokenValid = true, loginType = LoginType.OIDC, passphrase = pendingPassphrase, - sessionPath = sessionPath, + sessionPath = currentSessionPath.absolutePath, ) clear() pendingOidcAuthorizationData?.close() @@ -205,11 +218,13 @@ class RustMatrixAuthenticationService @Inject constructor( override suspend fun loginWithQrCode(qrCodeData: MatrixQrCodeLoginData, progress: (QrCodeLoginStep) -> Unit) = withContext(coroutineDispatchers.io) { + val emptySessionPath = rotateSessionPath() runCatching { val client = rustMatrixClientFactory.getBaseClientBuilder( - sessionPath = sessionPath, + sessionPath = emptySessionPath.absolutePath, passphrase = pendingPassphrase, slidingSyncProxy = AuthenticationConfig.SLIDING_SYNC_PROXY_URL, + slidingSync = ClientBuilderSlidingSync.Discovered, ) .buildWithQrCode( qrCodeData = (qrCodeData as SdkQrCodeLoginData).rustQrCodeData, @@ -227,7 +242,7 @@ class RustMatrixAuthenticationService @Inject constructor( isTokenValid = true, loginType = LoginType.QR, passphrase = pendingPassphrase, - sessionPath = sessionPath, + sessionPath = emptySessionPath.absolutePath, ) sessionStore.storeData(sessionData) SessionId(sessionData.userId) @@ -244,15 +259,17 @@ class RustMatrixAuthenticationService @Inject constructor( } Timber.e(throwable, "Failed to login with QR code") } - } + } - private fun getBaseClientBuilder() = rustMatrixClientFactory + private fun getBaseClientBuilder( + sessionPath: File, + ) = rustMatrixClientFactory .getBaseClientBuilder( - sessionPath = sessionPath, + sessionPath = sessionPath.absolutePath, passphrase = pendingPassphrase, slidingSyncProxy = AuthenticationConfig.SLIDING_SYNC_PROXY_URL, + slidingSync = ClientBuilderSlidingSync.Discovered, ) - .requiresSlidingSync() private fun clear() { currentClient?.close() diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/MatrixRoomInfoMapper.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/MatrixRoomInfoMapper.kt index 6a87b02a2b..a7461d6b0a 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/MatrixRoomInfoMapper.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/MatrixRoomInfoMapper.kt @@ -16,6 +16,7 @@ package io.element.android.libraries.matrix.impl.room +import io.element.android.libraries.matrix.api.core.EventId import io.element.android.libraries.matrix.api.core.RoomAlias import io.element.android.libraries.matrix.api.core.RoomId import io.element.android.libraries.matrix.api.core.UserId @@ -58,7 +59,8 @@ class MatrixRoomInfoMapper { userDefinedNotificationMode = it.userDefinedNotificationMode?.map(), hasRoomCall = it.hasRoomCall, activeRoomCallParticipants = it.activeRoomCallParticipants.toImmutableList(), - heroes = it.elementHeroes().toImmutableList() + heroes = it.elementHeroes().toImmutableList(), + pinnedEventIds = it.pinnedEventIds.map(::EventId).toImmutableList(), ) } } diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/RoomSyncSubscriber.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/RoomSyncSubscriber.kt index a52d3a87ed..b149f88006 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/RoomSyncSubscriber.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/RoomSyncSubscriber.kt @@ -51,23 +51,15 @@ class RoomSyncSubscriber( includeHeroes = false, ) - suspend fun subscribe(roomId: RoomId) = mutex.withLock { - withContext(dispatchers.io) { - try { - subscribeToRoom(roomId) - } catch (exception: Exception) { - Timber.e("Failed to subscribe to room $roomId") - } - } - } - - suspend fun batchSubscribe(roomIds: List) = mutex.withLock { - withContext(dispatchers.io) { - for (roomId in roomIds) { + suspend fun subscribe(roomId: RoomId) { + mutex.withLock { + withContext(dispatchers.io) { try { - subscribeToRoom(roomId) - } catch (cancellationException: CancellationException) { - throw cancellationException + if (!isSubscribedTo(roomId)) { + Timber.d("Subscribing to room $roomId}") + roomListService.subscribeToRooms(listOf(roomId.value), settings) + } + subscribedRoomIds.add(roomId) } catch (exception: Exception) { Timber.e("Failed to subscribe to room $roomId") } @@ -75,14 +67,21 @@ class RoomSyncSubscriber( } } - private fun subscribeToRoom(roomId: RoomId) { - if (!isSubscribedTo(roomId)) { - Timber.d("Subscribing to room $roomId}") - roomListService.room(roomId.value).use { roomListItem -> - roomListItem.subscribe(settings) + suspend fun batchSubscribe(roomIds: List) = mutex.withLock { + withContext(dispatchers.io) { + try { + val roomIdsToSubscribeTo = roomIds.filterNot { isSubscribedTo(it) } + if (roomIdsToSubscribeTo.isNotEmpty()) { + Timber.d("Subscribing to rooms: $roomIds") + roomListService.subscribeToRooms(roomIdsToSubscribeTo.map { it.value }, settings) + subscribedRoomIds.addAll(roomIds) + } + } catch (cancellationException: CancellationException) { + throw cancellationException + } catch (exception: Exception) { + Timber.e(exception, "Failed to subscribe to rooms: $roomIds") } } - subscribedRoomIds.add(roomId) } fun isSubscribedTo(roomId: RoomId): Boolean { 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 b594bba5e4..111370dcc4 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 @@ -192,6 +192,21 @@ class RustMatrixRoom( } } + override suspend fun pinnedEventsTimeline(): Result { + return runCatching { + innerRoom.pinnedEventsTimeline( + internalIdPrefix = "pinned_events", + maxEventsToLoad = 100u, + ).let { inner -> + createTimeline(inner, isLive = false) + } + }.onFailure { + if (it is CancellationException) { + throw it + } + } + } + override fun destroy() { roomCoroutineScope.cancel() liveTimeline.close() @@ -403,6 +418,12 @@ class RustMatrixRoom( } } + override suspend fun canUserPinUnpin(userId: UserId): Result { + return runCatching { + innerRoom.canUserPinUnpin(userId.value) + } + } + override suspend fun sendImage( file: File, thumbnailFile: File?, diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/RustTimeline.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/RustTimeline.kt index b57efc5603..87fca3d395 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/RustTimeline.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/RustTimeline.kt @@ -525,6 +525,18 @@ class RustTimeline( } } + override suspend fun pinEvent(eventId: EventId): Result = withContext(dispatcher) { + runCatching { + inner.pinEvent(eventId = eventId.value) + } + } + + override suspend fun unpinEvent(eventId: EventId): Result = withContext(dispatcher) { + runCatching { + inner.unpinEvent(eventId = eventId.value) + } + } + private suspend fun fetchDetailsForEvent(eventId: EventId): Result { return runCatching { inner.fetchDetailsForEvent(eventId.value) diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/item/event/EventTimelineItemMapper.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/item/event/EventTimelineItemMapper.kt index f80b877baa..1c5f25a14e 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/item/event/EventTimelineItemMapper.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/item/event/EventTimelineItemMapper.kt @@ -47,6 +47,7 @@ class EventTimelineItemMapper(private val contentMapper: TimelineEventContentMap eventId = it.eventId()?.let(::EventId), transactionId = it.transactionId()?.let(::TransactionId), isEditable = it.isEditable(), + canBeRepliedTo = it.canBeRepliedTo(), isLocal = it.isLocal(), isOwn = it.isOwn(), isRemote = it.isRemote(), diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/item/event/TimelineEventContentMapper.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/item/event/TimelineEventContentMapper.kt index 6b0da71eee..6e44579d7c 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/item/event/TimelineEventContentMapper.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/item/event/TimelineEventContentMapper.kt @@ -40,6 +40,7 @@ import kotlinx.collections.immutable.toImmutableMap import org.matrix.rustcomponents.sdk.TimelineItemContent import org.matrix.rustcomponents.sdk.TimelineItemContentKind import org.matrix.rustcomponents.sdk.use +import uniffi.matrix_sdk_ui.RoomPinnedEventsChange import org.matrix.rustcomponents.sdk.EncryptedMessage as RustEncryptedMessage import org.matrix.rustcomponents.sdk.MembershipChange as RustMembershipChange import org.matrix.rustcomponents.sdk.OtherState as RustOtherState @@ -176,7 +177,7 @@ private fun RustOtherState.map(): OtherState { RustOtherState.RoomHistoryVisibility -> OtherState.RoomHistoryVisibility RustOtherState.RoomJoinRules -> OtherState.RoomJoinRules is RustOtherState.RoomName -> OtherState.RoomName(name) - RustOtherState.RoomPinnedEvents -> OtherState.RoomPinnedEvents + is RustOtherState.RoomPinnedEvents -> OtherState.RoomPinnedEvents(change.map()) is RustOtherState.RoomPowerLevels -> OtherState.RoomUserPowerLevels(users) RustOtherState.RoomServerAcl -> OtherState.RoomServerAcl is RustOtherState.RoomThirdPartyInvite -> OtherState.RoomThirdPartyInvite(displayName) @@ -187,6 +188,14 @@ private fun RustOtherState.map(): OtherState { } } +private fun RoomPinnedEventsChange.map(): OtherState.RoomPinnedEvents.Change { + return when (this) { + RoomPinnedEventsChange.ADDED -> OtherState.RoomPinnedEvents.Change.ADDED + RoomPinnedEventsChange.REMOVED -> OtherState.RoomPinnedEvents.Change.REMOVED + RoomPinnedEventsChange.CHANGED -> OtherState.RoomPinnedEvents.Change.CHANGED + } +} + private fun RustEncryptedMessage.map(): UnableToDecryptContent.Data { return when (this) { is RustEncryptedMessage.MegolmV1AesSha2 -> UnableToDecryptContent.Data.MegolmV1AesSha2(sessionId, cause.map()) diff --git a/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/roomlist/RoomSummaryListProcessorTest.kt b/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/roomlist/RoomSummaryListProcessorTest.kt index f2e2f07ad6..abaae99397 100644 --- a/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/roomlist/RoomSummaryListProcessorTest.kt +++ b/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/roomlist/RoomSummaryListProcessorTest.kt @@ -189,6 +189,8 @@ class RoomSummaryListProcessorTest { override fun syncIndicator(delayBeforeShowingInMs: UInt, delayBeforeHidingInMs: UInt, listener: RoomListServiceSyncIndicatorListener): TaskHandle { return TaskHandle(Pointer.NULL) } + + override fun subscribeToRooms(roomIds: List, settings: RoomSubscription?) = Unit } } @@ -221,6 +223,7 @@ private fun aRustRoomInfo( numUnreadMessages: ULong = 0uL, numUnreadNotifications: ULong = 0uL, numUnreadMentions: ULong = 0uL, + pinnedEventIds: List = listOf(), ) = RoomInfo( id = id, displayName = displayName, @@ -249,7 +252,8 @@ private fun aRustRoomInfo( isMarkedUnread = isMarkedUnread, numUnreadMessages = numUnreadMessages, numUnreadNotifications = numUnreadNotifications, - numUnreadMentions = numUnreadMentions + numUnreadMentions = numUnreadMentions, + pinnedEventIds = pinnedEventIds, ) class FakeRoomListItem( @@ -268,6 +272,4 @@ class FakeRoomListItem( override suspend fun latestEvent(): EventTimelineItem? { return latestEvent } - - override fun subscribe(settings: RoomSubscription?) = Unit } diff --git a/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/room/FakeMatrixRoom.kt b/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/room/FakeMatrixRoom.kt index cfd0267516..955e9b64c5 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 @@ -125,6 +125,7 @@ class FakeMatrixRoom( private val getWidgetDriverResult: (MatrixWidgetSettings) -> Result = { lambdaError() }, private val canUserTriggerRoomNotificationResult: (UserId) -> Result = { lambdaError() }, private val canUserJoinCallResult: (UserId) -> Result = { lambdaError() }, + private val canUserPinUnpinResult: (UserId) -> Result = { lambdaError() }, private val setIsFavoriteResult: (Boolean) -> Result = { lambdaError() }, private val powerLevelsResult: () -> Result = { lambdaError() }, private val updatePowerLevelsResult: () -> Result = { lambdaError() }, @@ -134,10 +135,12 @@ class FakeMatrixRoom( private val updateMembersResult: () -> Unit = { lambdaError() }, private val getMembersResult: (Int) -> Result> = { lambdaError() }, private val timelineFocusedOnEventResult: (EventId) -> Result = { lambdaError() }, + private val pinnedEventsTimelineResult: () -> Result = { lambdaError() }, private val setSendQueueEnabledLambda: (Boolean) -> Unit = { _: Boolean -> }, private val saveComposerDraftLambda: (ComposerDraft) -> Result = { _: ComposerDraft -> Result.success(Unit) }, private val loadComposerDraftLambda: () -> Result = { Result.success(null) }, private val clearComposerDraftLambda: () -> Result = { Result.success(Unit) }, + private val subscribeToSyncLambda: () -> Unit = { lambdaError() }, ) : MatrixRoom { private val _roomInfoFlow: MutableSharedFlow = MutableSharedFlow(replay = 1) override val roomInfoFlow: Flow = _roomInfoFlow @@ -180,7 +183,13 @@ class FakeMatrixRoom( timelineFocusedOnEventResult(eventId) } - override suspend fun subscribeToSync() = Unit + override suspend fun pinnedEventsTimeline(): Result = simulateLongTask { + pinnedEventsTimelineResult() + } + + override suspend fun subscribeToSync() { + subscribeToSyncLambda() + } override suspend fun powerLevels(): Result { return powerLevelsResult() @@ -289,6 +298,10 @@ class FakeMatrixRoom( return canUserJoinCallResult(userId) } + override suspend fun canUserPinUnpin(userId: UserId): Result { + return canUserPinUnpinResult(userId) + } + override suspend fun sendImage( file: File, thumbnailFile: File?, @@ -517,6 +530,7 @@ fun aRoomInfo( userPowerLevels: ImmutableMap = persistentMapOf(), activeRoomCallParticipants: List = emptyList(), heroes: List = emptyList(), + pinnedEventIds: List = emptyList(), ) = MatrixRoomInfo( id = id, name = name, @@ -542,6 +556,7 @@ fun aRoomInfo( userPowerLevels = userPowerLevels, activeRoomCallParticipants = activeRoomCallParticipants.toImmutableList(), heroes = heroes.toImmutableList(), + pinnedEventIds = pinnedEventIds.toImmutableList(), ) fun defaultRoomPowerLevels() = MatrixRoomPowerLevels( diff --git a/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/sync/FakeSyncService.kt b/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/sync/FakeSyncService.kt index ffc06e7d18..32936d166e 100644 --- a/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/sync/FakeSyncService.kt +++ b/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/sync/FakeSyncService.kt @@ -22,22 +22,16 @@ import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow class FakeSyncService( - initialState: SyncState = SyncState.Idle + syncStateFlow: MutableStateFlow = MutableStateFlow(SyncState.Idle) ) : SyncService { - private val syncStateFlow = MutableStateFlow(initialState) - - fun simulateError() { - syncStateFlow.value = SyncState.Error - } - + var startSyncLambda: () -> Result = { Result.success(Unit) } override suspend fun startSync(): Result { - syncStateFlow.value = SyncState.Running - return Result.success(Unit) + return startSyncLambda() } + var stopSyncLambda: () -> Result = { Result.success(Unit) } override suspend fun stopSync(): Result { - syncStateFlow.value = SyncState.Terminated - return Result.success(Unit) + return stopSyncLambda() } override val syncState: StateFlow = syncStateFlow diff --git a/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/timeline/FakeTimeline.kt b/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/timeline/FakeTimeline.kt index 4fa9f7a94c..ea9b353a67 100644 --- a/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/timeline/FakeTimeline.kt +++ b/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/timeline/FakeTimeline.kt @@ -33,6 +33,7 @@ import io.element.android.libraries.matrix.api.timeline.ReceiptType import io.element.android.libraries.matrix.api.timeline.Timeline import io.element.android.libraries.matrix.api.timeline.item.event.InReplyTo import io.element.android.libraries.matrix.test.media.FakeMediaUploadHandler +import io.element.android.tests.testutils.lambda.lambdaError import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.MutableStateFlow @@ -371,6 +372,16 @@ class FakeTimeline( override suspend fun loadReplyDetails(eventId: EventId) = loadReplyDetailsLambda(eventId) + var pinEventLambda: (eventId: EventId) -> Result = { lambdaError() } + override suspend fun pinEvent(eventId: EventId): Result { + return pinEventLambda(eventId) + } + + var unpinEventLambda: (eventId: EventId) -> Result = { lambdaError() } + override suspend fun unpinEvent(eventId: EventId): Result { + return unpinEventLambda(eventId) + } + var closeCounter = 0 private set diff --git a/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/timeline/TimelineFixture.kt b/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/timeline/TimelineFixture.kt index 8be4da3876..3712fb56af 100644 --- a/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/timeline/TimelineFixture.kt +++ b/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/timeline/TimelineFixture.kt @@ -47,6 +47,7 @@ fun anEventTimelineItem( eventId: EventId = AN_EVENT_ID, transactionId: TransactionId? = null, isEditable: Boolean = false, + canBeRepliedTo: Boolean = false, isLocal: Boolean = false, isOwn: Boolean = false, isRemote: Boolean = false, @@ -63,6 +64,7 @@ fun anEventTimelineItem( eventId = eventId, transactionId = transactionId, isEditable = isEditable, + canBeRepliedTo = canBeRepliedTo, isLocal = isLocal, isOwn = isOwn, isRemote = isRemote, diff --git a/libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/room/MatrixRoomState.kt b/libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/room/MatrixRoomState.kt index ab3c80a6e2..8ff8b1a894 100644 --- a/libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/room/MatrixRoomState.kt +++ b/libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/room/MatrixRoomState.kt @@ -56,6 +56,13 @@ fun MatrixRoom.canCall(updateKey: Long): State { } } +@Composable +fun MatrixRoom.canPinUnpin(updateKey: Long): State { + return produceState(initialValue = false, key1 = updateKey) { + value = canUserPinUnpin(sessionId).getOrElse { false } + } +} + @Composable fun MatrixRoom.isOwnUserAdmin(): Boolean { val roomInfo by roomInfoFlow.collectAsState(initial = null) diff --git a/libraries/matrixui/src/main/res/values-uz/translations.xml b/libraries/matrixui/src/main/res/values-uz/translations.xml new file mode 100644 index 0000000000..069f0b8372 --- /dev/null +++ b/libraries/matrixui/src/main/res/values-uz/translations.xml @@ -0,0 +1,4 @@ + + + "%1$s(%2$s ) sizni taklif qildi" + diff --git a/libraries/network/build.gradle.kts b/libraries/network/build.gradle.kts index 2b18f1e37a..36294f4c08 100644 --- a/libraries/network/build.gradle.kts +++ b/libraries/network/build.gradle.kts @@ -23,7 +23,6 @@ android { buildTypes { release { - isMinifyEnabled = true consumerProguardFiles("consumer-rules.pro") } } diff --git a/libraries/permissions/api/src/main/res/values-uz/translations.xml b/libraries/permissions/api/src/main/res/values-uz/translations.xml new file mode 100644 index 0000000000..3106daedb7 --- /dev/null +++ b/libraries/permissions/api/src/main/res/values-uz/translations.xml @@ -0,0 +1,7 @@ + + + "Ilovaga kameradan foydalanishiga ruxsat berish uchun tizim sozlamalarida ruxsat bering." + "Iltimos, tizim sozlamalarida ruxsat bering." + "Ilovaga mikrofondan foydalanishiga ruxsat berish uchun tizim sozlamalarida ruxsat bering." + "Ilova bildirishnomalarni ko\'rsatishi uchun tizim sozlamalarida ruxsat bering." + diff --git a/libraries/permissions/impl/src/main/res/values-pl/translations.xml b/libraries/permissions/impl/src/main/res/values-pl/translations.xml new file mode 100644 index 0000000000..c3f5197d95 --- /dev/null +++ b/libraries/permissions/impl/src/main/res/values-pl/translations.xml @@ -0,0 +1,5 @@ + + + "Sprawdź, czy aplikacja może wyświetlać powiadomienia." + "Sprawdź uprawnienia" + diff --git a/libraries/permissions/impl/src/main/res/values-uk/translations.xml b/libraries/permissions/impl/src/main/res/values-uk/translations.xml new file mode 100644 index 0000000000..09f8671a97 --- /dev/null +++ b/libraries/permissions/impl/src/main/res/values-uk/translations.xml @@ -0,0 +1,5 @@ + + + "Перевірте, чи програма може показувати сповіщення." + "Перевірте дозволи" + diff --git a/libraries/preferences/api/src/main/kotlin/io/element/android/libraries/preferences/api/store/AppPreferencesStore.kt b/libraries/preferences/api/src/main/kotlin/io/element/android/libraries/preferences/api/store/AppPreferencesStore.kt index 5d12adbe74..73a42a4ff4 100644 --- a/libraries/preferences/api/src/main/kotlin/io/element/android/libraries/preferences/api/store/AppPreferencesStore.kt +++ b/libraries/preferences/api/src/main/kotlin/io/element/android/libraries/preferences/api/store/AppPreferencesStore.kt @@ -28,5 +28,8 @@ interface AppPreferencesStore { suspend fun setTheme(theme: String) fun getThemeFlow(): Flow + suspend fun setSimplifiedSlidingSyncEnabled(enabled: Boolean) + fun isSimplifiedSlidingSyncEnabledFlow(): Flow + suspend fun reset() } diff --git a/libraries/preferences/impl/src/main/kotlin/io/element/android/libraries/preferences/impl/store/DefaultAppPreferencesStore.kt b/libraries/preferences/impl/src/main/kotlin/io/element/android/libraries/preferences/impl/store/DefaultAppPreferencesStore.kt index d25cda96d0..e80c6d60ad 100644 --- a/libraries/preferences/impl/src/main/kotlin/io/element/android/libraries/preferences/impl/store/DefaultAppPreferencesStore.kt +++ b/libraries/preferences/impl/src/main/kotlin/io/element/android/libraries/preferences/impl/store/DefaultAppPreferencesStore.kt @@ -38,6 +38,7 @@ private val Context.dataStore: DataStore by preferencesDataStore(na private val developerModeKey = booleanPreferencesKey("developerMode") private val customElementCallBaseUrlKey = stringPreferencesKey("elementCallBaseUrl") private val themeKey = stringPreferencesKey("theme") +private val simplifiedSlidingSyncKey = booleanPreferencesKey("useSimplifiedSlidingSync") @ContributesBinding(AppScope::class) class DefaultAppPreferencesStore @Inject constructor( @@ -87,6 +88,18 @@ class DefaultAppPreferencesStore @Inject constructor( } } + override suspend fun setSimplifiedSlidingSyncEnabled(enabled: Boolean) { + store.edit { prefs -> + prefs[simplifiedSlidingSyncKey] = enabled + } + } + + override fun isSimplifiedSlidingSyncEnabledFlow(): Flow { + return store.data.map { prefs -> + prefs[simplifiedSlidingSyncKey] ?: false + } + } + override suspend fun reset() { store.edit { it.clear() } } diff --git a/libraries/preferences/test/src/main/kotlin/io/element/android/libraries/preferences/test/InMemoryAppPreferencesStore.kt b/libraries/preferences/test/src/main/kotlin/io/element/android/libraries/preferences/test/InMemoryAppPreferencesStore.kt index c920f8c6b3..432c7a9772 100644 --- a/libraries/preferences/test/src/main/kotlin/io/element/android/libraries/preferences/test/InMemoryAppPreferencesStore.kt +++ b/libraries/preferences/test/src/main/kotlin/io/element/android/libraries/preferences/test/InMemoryAppPreferencesStore.kt @@ -24,10 +24,12 @@ class InMemoryAppPreferencesStore( isDeveloperModeEnabled: Boolean = false, customElementCallBaseUrl: String? = null, theme: String? = null, + simplifiedSlidingSyncEnabled: Boolean = false ) : AppPreferencesStore { private val isDeveloperModeEnabled = MutableStateFlow(isDeveloperModeEnabled) private val customElementCallBaseUrl = MutableStateFlow(customElementCallBaseUrl) private val theme = MutableStateFlow(theme) + private val simplifiedSlidingSyncEnabled = MutableStateFlow(simplifiedSlidingSyncEnabled) override suspend fun setDeveloperModeEnabled(enabled: Boolean) { isDeveloperModeEnabled.value = enabled @@ -53,6 +55,14 @@ class InMemoryAppPreferencesStore( return theme } + override suspend fun setSimplifiedSlidingSyncEnabled(enabled: Boolean) { + simplifiedSlidingSyncEnabled.value = enabled + } + + override fun isSimplifiedSlidingSyncEnabledFlow(): Flow { + return simplifiedSlidingSyncEnabled + } + override suspend fun reset() { // No op } diff --git a/libraries/push/impl/build.gradle.kts b/libraries/push/impl/build.gradle.kts index 8970f1e3d0..f53b4ba27c 100644 --- a/libraries/push/impl/build.gradle.kts +++ b/libraries/push/impl/build.gradle.kts @@ -56,6 +56,7 @@ dependencies { implementation(projects.libraries.uiStrings) implementation(projects.libraries.troubleshoot.api) implementation(projects.features.call.api) + implementation(projects.libraries.featureflag.api) api(projects.libraries.pushproviders.api) api(projects.libraries.pushstore.api) api(projects.libraries.push.api) @@ -81,4 +82,6 @@ dependencies { testImplementation(projects.services.appnavstate.test) testImplementation(projects.services.toolbox.impl) testImplementation(projects.services.toolbox.test) + testImplementation(projects.libraries.featureflag.test) + testImplementation(libs.kotlinx.collections.immutable) } diff --git a/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/push/OnNotifiableEventReceived.kt b/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/push/OnNotifiableEventReceived.kt index cdcc6a1d93..c7cd718925 100644 --- a/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/push/OnNotifiableEventReceived.kt +++ b/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/push/OnNotifiableEventReceived.kt @@ -32,9 +32,11 @@ interface OnNotifiableEventReceived { class DefaultOnNotifiableEventReceived @Inject constructor( private val defaultNotificationDrawerManager: DefaultNotificationDrawerManager, private val coroutineScope: CoroutineScope, + private val syncOnNotifiableEvent: SyncOnNotifiableEvent, ) : OnNotifiableEventReceived { override fun onNotifiableEventReceived(notifiableEvent: NotifiableEvent) { coroutineScope.launch { + launch { syncOnNotifiableEvent(notifiableEvent) } defaultNotificationDrawerManager.onNotifiableEventReceived(notifiableEvent) } } diff --git a/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/push/SyncOnNotifiableEvent.kt b/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/push/SyncOnNotifiableEvent.kt new file mode 100644 index 0000000000..dd72e05ed8 --- /dev/null +++ b/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/push/SyncOnNotifiableEvent.kt @@ -0,0 +1,87 @@ +/* + * 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 + * + * https://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.push.impl.push + +import io.element.android.libraries.core.coroutine.CoroutineDispatchers +import io.element.android.libraries.featureflag.api.FeatureFlagService +import io.element.android.libraries.featureflag.api.FeatureFlags +import io.element.android.libraries.matrix.api.MatrixClientProvider +import io.element.android.libraries.matrix.api.core.EventId +import io.element.android.libraries.matrix.api.room.MatrixRoom +import io.element.android.libraries.matrix.api.sync.SyncService +import io.element.android.libraries.matrix.api.timeline.MatrixTimelineItem +import io.element.android.libraries.push.impl.notifications.model.NotifiableEvent +import io.element.android.services.appnavstate.api.AppForegroundStateService +import kotlinx.coroutines.flow.first +import kotlinx.coroutines.withContext +import kotlinx.coroutines.withTimeoutOrNull +import java.util.concurrent.atomic.AtomicInteger +import javax.inject.Inject +import kotlin.time.Duration +import kotlin.time.Duration.Companion.seconds + +class SyncOnNotifiableEvent @Inject constructor( + private val matrixClientProvider: MatrixClientProvider, + private val featureFlagService: FeatureFlagService, + private val appForegroundStateService: AppForegroundStateService, + private val dispatchers: CoroutineDispatchers, +) { + private var syncCounter = AtomicInteger(0) + + suspend operator fun invoke(notifiableEvent: NotifiableEvent) = withContext(dispatchers.io) { + if (!featureFlagService.isFeatureEnabled(FeatureFlags.SyncOnPush)) { + return@withContext + } + val client = matrixClientProvider.getOrRestore(notifiableEvent.sessionId).getOrNull() ?: return@withContext + client.getRoom(notifiableEvent.roomId)?.use { room -> + room.subscribeToSync() + + // If the app is in foreground, sync is already running, so just add the subscription. + if (!appForegroundStateService.isInForeground.value) { + val syncService = client.syncService() + syncService.startSyncIfNeeded() + room.waitsUntilEventIsKnown(eventId = notifiableEvent.eventId, timeout = 10.seconds) + syncService.stopSyncIfNeeded() + } + } + } + + private suspend fun MatrixRoom.waitsUntilEventIsKnown(eventId: EventId, timeout: Duration) { + withTimeoutOrNull(timeout) { + liveTimeline.timelineItems.first { timelineItems -> + timelineItems.any { timelineItem -> + when (timelineItem) { + is MatrixTimelineItem.Event -> timelineItem.eventId == eventId + else -> false + } + } + } + } + } + + private suspend fun SyncService.startSyncIfNeeded() { + if (syncCounter.getAndIncrement() == 0) { + startSync() + } + } + + private suspend fun SyncService.stopSyncIfNeeded() { + if (syncCounter.decrementAndGet() == 0 && !appForegroundStateService.isInForeground.value) { + stopSync() + } + } +} diff --git a/libraries/push/impl/src/main/res/values-pl/translations.xml b/libraries/push/impl/src/main/res/values-pl/translations.xml index 56d65b15cb..d5f77da93e 100644 --- a/libraries/push/impl/src/main/res/values-pl/translations.xml +++ b/libraries/push/impl/src/main/res/values-pl/translations.xml @@ -34,6 +34,7 @@ "%d nowych wiadomości" "Zareagował z %1$s" + "Oznacz jako przeczytane" "Szybka odpowiedź" "Zaprosił Cię do dołączenia do pokoju" "Ja" @@ -56,4 +57,29 @@ "Synchronizacja w tle" "Usługi Google" "Nie znaleziono usług Google Play. Powiadomienia mogą nie działać prawidłowo." + "Uzyskaj nazwę bieżącego dostawcy." + "Nie wybrano dostawców push." + "Bieżący dostawca push: %1$s." + "Bieżący dostawca push" + "Upewnij się, że aplikacja ma co najmniej jednego dostawcę push." + "Nie znaleziono dostawców push." + + "Znaleziono %1$d dostawcę push: %2$s" + "Znaleziono %1$d dostawców push: %2$s" + "Znaleziono %1$d dostawców push: %2$s" + + "Wykryj dostawców powiadomień push" + "Sprawdź, czy aplikacja może wyświetlać powiadomienie." + "Powiadomienie nie zostało kliknięte." + "Nie można wyświetlić powiadomienia." + "Powiadomienie zostało kliknięte!" + "Wyświetl powiadomienie" + "Kliknij powiadomienie, aby kontynuować test." + "Upewnij się, że aplikacja otrzymuje powiadomienie push." + "Błąd: pusher odrzucił żądanie." + "Błąd: %1$s." + "Błąd, nie można przetestować push." + "Błąd, upłynął limit czasu powiadomienia push." + "Pętla powrotna push zajęła %1$d ms." + "Przetestuj pętlę Push back" diff --git a/libraries/push/impl/src/main/res/values-pt-rBR/translations.xml b/libraries/push/impl/src/main/res/values-pt-rBR/translations.xml index dbdc30a031..3d647e1acf 100644 --- a/libraries/push/impl/src/main/res/values-pt-rBR/translations.xml +++ b/libraries/push/impl/src/main/res/values-pt-rBR/translations.xml @@ -21,12 +21,14 @@ "%d convites" "Convidou você para conversar" + "Mencionou você: %1$s" "Novas mensagens" "%d nova mensagem" "%d novas mensagens" "Reagiu com %1$s" + "Marcar como lido" "Resposta rápida" "Convidou você para entrar na sala" "Eu" diff --git a/libraries/push/impl/src/main/res/values-sv/translations.xml b/libraries/push/impl/src/main/res/values-sv/translations.xml index bf4c19111a..92036e09c2 100644 --- a/libraries/push/impl/src/main/res/values-sv/translations.xml +++ b/libraries/push/impl/src/main/res/values-sv/translations.xml @@ -3,6 +3,7 @@ "Samtal" "Lyssnar efter händelser" "Högljudda aviseringar" + "Ringande samtal" "Tysta aviseringar" "%1$s: %2$d meddelande" @@ -12,6 +13,8 @@ "%d avisering" "%d aviseringar" + "notis" + "Inkommande samtal" "** Misslyckades att skicka - vänligen öppna rummet" "Gå med" "Avvisa" diff --git a/libraries/push/impl/src/main/res/values-uk/translations.xml b/libraries/push/impl/src/main/res/values-uk/translations.xml index e1a3f8bf47..b7e3df3348 100644 --- a/libraries/push/impl/src/main/res/values-uk/translations.xml +++ b/libraries/push/impl/src/main/res/values-uk/translations.xml @@ -3,6 +3,7 @@ "Виклик" "Прослуховування подій" "Гучні сповіщення" + "Дзвінки" "Тихі сповіщення" "%1$s: %2$d повідомлення" @@ -15,6 +16,7 @@ "%d сповіщень" "Сповіщення" + "Вхідний дзвінок" "** Не вдалося надіслати - будь ласка, відкрийте кімнату" "Доєднатися" "Відхилити" @@ -32,7 +34,7 @@ "%d нових повідомлень" "Відреагував (-ла) з %1$s" - "Позначити як прочитане" + "Позначити прочитаним" "Швидка відповідь" "Запросив (-ла) Вас приєднатися до кімнати" "Я" @@ -55,5 +57,27 @@ "Фонова синхронізація" "Сервіси Google" "Не знайдено дійсних сервісів Google Play. Сповіщення можуть не працювати належним чином." + "Отримує назву поточного постачальника." + "Постачальників push-сповіщень не обрано." + "Поточний постачальник: %1$s." + "Поточний провайдер push" + "Переконайтеся, що програма має принаймні один push провайдер." + "Не знайдено постачальників push-повідомлень." + + "Виявлено %1$d постачальника: %2$s" + "Виявлено %1$d постачальників: %2$s" + "Виявлено %1$d постачальників: %2$s" + + "Виявлення push-провайдерів" + "Перевірте, чи може програма відображати сповіщення." + "Ви не натиснули на сповіщення." "Не вдається відобразити сповіщення." + "Ви натиснули на сповіщення!" + "Відображення сповіщення" + "Будь ласка, натисніть на сповіщення, щоб продовжити тест." + "Переконується, що застосунок отримує push-сповіщення." + "Помилка: постачальник push-сповіщень відхилив запит." + "Помилка: %1$s." + "Помилка, неможливо перевірити push." + "Перевірка зворотного надсилання" diff --git a/libraries/push/impl/src/main/res/values-uz/translations.xml b/libraries/push/impl/src/main/res/values-uz/translations.xml new file mode 100644 index 0000000000..77e503e5c9 --- /dev/null +++ b/libraries/push/impl/src/main/res/values-uz/translations.xml @@ -0,0 +1,50 @@ + + + "Qo\'ng\'iroq" + "Voqealarni tinglash" + "Shovqinli bildirishnomalar" + "Ovozsiz bildirishnomalar" + + "%1$s:%2$d xabar" + "%1$s:%2$d xabarlar" + + + "%dbildirishnoma" + "%dbildirishnomalar" + + "Bildirishnoma" + "** Yuborilmadi - iltimos, xonani oching" + "Qo\'shilish" + "Rad etish" + + "%dtaklifnoma" + "%dtaklifnomalar" + + "Sizni suhbatga taklif qildi" + "Yangi xabarlar" + + "%dyangi xabar" + "%dyangi xabarlar" + + "%1$sbilan munosabat bildiring" + "Tez javob" + "Sizni xonaga kirishga taklif qildi" + "Men" + "Siz bildirishnomani ko\'ryapsiz! Meni bosing!" + "%1$s:%2$s" + "%1$s:%2$s%3$s" + + "%do\'qilmagan xabarnoma" + "%do\'qilmagan xabarlar" + + "%1$sva%2$s" + "%1$sichida%2$s" + "%1$sichida%2$s va%3$s" + + "%dxona" + "%dxonalar" + + "Orqa Fon sinxronizatsiyasi" + "Google xizmatlari" + "Yaroqli Google Play xizmatlari topilmadi. Bildirishnomalar to\'g\'ri ishlamasligi mumkin." + diff --git a/libraries/push/impl/src/main/res/values/localazy.xml b/libraries/push/impl/src/main/res/values/localazy.xml index e1bfa07d29..5fed2718a1 100644 --- a/libraries/push/impl/src/main/res/values/localazy.xml +++ b/libraries/push/impl/src/main/res/values/localazy.xml @@ -34,6 +34,7 @@ "Quick reply" "Invited you to join the room" "Me" + "%1$s mentioned or replied" "You are viewing the notification! Click me!" "%1$s: %2$s" "%1$s: %2$s %3$s" diff --git a/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/push/SyncOnNotifiableEventTest.kt b/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/push/SyncOnNotifiableEventTest.kt new file mode 100644 index 0000000000..2e182e81ae --- /dev/null +++ b/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/push/SyncOnNotifiableEventTest.kt @@ -0,0 +1,151 @@ +/* + * 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 + * + * https://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.push.impl.push + +import io.element.android.libraries.featureflag.api.FeatureFlags +import io.element.android.libraries.featureflag.test.FakeFeatureFlagService +import io.element.android.libraries.matrix.api.MatrixClient +import io.element.android.libraries.matrix.api.sync.SyncState +import io.element.android.libraries.matrix.api.timeline.MatrixTimelineItem +import io.element.android.libraries.matrix.test.A_ROOM_ID +import io.element.android.libraries.matrix.test.A_UNIQUE_ID +import io.element.android.libraries.matrix.test.FakeMatrixClient +import io.element.android.libraries.matrix.test.FakeMatrixClientProvider +import io.element.android.libraries.matrix.test.room.FakeMatrixRoom +import io.element.android.libraries.matrix.test.sync.FakeSyncService +import io.element.android.libraries.matrix.test.timeline.FakeTimeline +import io.element.android.libraries.matrix.test.timeline.anEventTimelineItem +import io.element.android.libraries.push.impl.notifications.fixtures.aNotifiableMessageEvent +import io.element.android.services.appnavstate.test.FakeAppForegroundStateService +import io.element.android.tests.testutils.lambda.assert +import io.element.android.tests.testutils.lambda.lambdaRecorder +import io.element.android.tests.testutils.testCoroutineDispatchers +import kotlinx.coroutines.coroutineScope +import kotlinx.coroutines.delay +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.launch +import kotlinx.coroutines.test.TestScope +import kotlinx.coroutines.test.runTest +import org.junit.Test + +class SyncOnNotifiableEventTest { + private val timelineItems = MutableStateFlow>(emptyList()) + private val syncStateFlow = MutableStateFlow(SyncState.Idle) + private val startSyncLambda = lambdaRecorder> { Result.success(Unit) } + private val stopSyncLambda = lambdaRecorder> { Result.success(Unit) } + private val subscribeToSyncLambda = lambdaRecorder { } + + private val liveTimeline = FakeTimeline( + timelineItems = timelineItems, + ) + private val room = FakeMatrixRoom( + roomId = A_ROOM_ID, + liveTimeline = liveTimeline, + subscribeToSyncLambda = subscribeToSyncLambda + ) + private val syncService = FakeSyncService(syncStateFlow).also { + it.startSyncLambda = startSyncLambda + it.stopSyncLambda = stopSyncLambda + } + + private val client = FakeMatrixClient( + syncService = syncService, + ).apply { + givenGetRoomResult(A_ROOM_ID, room) + } + + private val notifiableEvent = aNotifiableMessageEvent() + + @Test + fun `when feature flag is disabled, nothing happens`() = runTest { + val sut = createSyncOnNotifiableEvent(client = client, isSyncOnPushEnabled = false) + + sut(notifiableEvent) + + assert(startSyncLambda).isNeverCalled() + assert(stopSyncLambda).isNeverCalled() + assert(subscribeToSyncLambda).isNeverCalled() + } + + @Test + fun `when feature flag is enabled and app is in foreground, sync is not started`() = runTest { + val sut = createSyncOnNotifiableEvent(client = client, isAppInForeground = true, isSyncOnPushEnabled = true) + + sut(notifiableEvent) + + assert(startSyncLambda).isNeverCalled() + assert(stopSyncLambda).isNeverCalled() + assert(subscribeToSyncLambda).isCalledOnce() + } + + @Test + fun `when feature flag is enabled and app is in background, sync is started and stopped`() = runTest { + val sut = createSyncOnNotifiableEvent(client = client, isAppInForeground = false, isSyncOnPushEnabled = true) + + timelineItems.emit( + listOf(MatrixTimelineItem.Event(A_UNIQUE_ID, anEventTimelineItem())) + ) + syncStateFlow.emit(SyncState.Running) + sut(notifiableEvent) + + assert(startSyncLambda).isCalledOnce() + assert(stopSyncLambda).isCalledOnce() + assert(subscribeToSyncLambda).isCalledOnce() + } + + @Test + fun `when feature flag is enabled and app is in background, running multiple time only call once`() = runTest { + val sut = createSyncOnNotifiableEvent(client = client, isAppInForeground = false, isSyncOnPushEnabled = true) + + coroutineScope { + launch { sut(notifiableEvent) } + launch { sut(notifiableEvent) } + launch { + delay(1) + timelineItems.emit( + listOf(MatrixTimelineItem.Event(A_UNIQUE_ID, anEventTimelineItem())) + ) + } + } + + assert(startSyncLambda).isCalledOnce() + assert(stopSyncLambda).isCalledOnce() + assert(subscribeToSyncLambda).isCalledExactly(2) + } + + private fun TestScope.createSyncOnNotifiableEvent( + client: MatrixClient = FakeMatrixClient(), + isSyncOnPushEnabled: Boolean = true, + isAppInForeground: Boolean = true, + ): SyncOnNotifiableEvent { + val featureFlagService = FakeFeatureFlagService( + initialState = mapOf( + FeatureFlags.SyncOnPush.key to isSyncOnPushEnabled + ) + ) + val appForegroundStateService = FakeAppForegroundStateService( + initialValue = isAppInForeground + ) + val matrixClientProvider = FakeMatrixClientProvider { Result.success(client) } + return SyncOnNotifiableEvent( + matrixClientProvider = matrixClientProvider, + featureFlagService = featureFlagService, + appForegroundStateService = appForegroundStateService, + dispatchers = testCoroutineDispatchers(), + ) + } +} diff --git a/libraries/pushproviders/firebase/build.gradle.kts b/libraries/pushproviders/firebase/build.gradle.kts index 28b58b1faa..1e6d88ec53 100644 --- a/libraries/pushproviders/firebase/build.gradle.kts +++ b/libraries/pushproviders/firebase/build.gradle.kts @@ -26,7 +26,6 @@ android { buildTypes { getByName("release") { - isMinifyEnabled = true consumerProguardFiles("consumer-proguard-rules.pro") resValue( type = "string", @@ -50,7 +49,6 @@ android { ) } register("nightly") { - isMinifyEnabled = true consumerProguardFiles("consumer-proguard-rules.pro") matchingFallbacks += listOf("release") resValue( diff --git a/libraries/pushproviders/firebase/src/main/res/values-pl/translations.xml b/libraries/pushproviders/firebase/src/main/res/values-pl/translations.xml new file mode 100644 index 0000000000..7a3e164465 --- /dev/null +++ b/libraries/pushproviders/firebase/src/main/res/values-pl/translations.xml @@ -0,0 +1,11 @@ + + + "Upewnij się, że Firebase jest dostępny." + "Baza Firebase jest niedostępna." + "Baza Firebase jest dostępna." + "Sprawdź Firebase" + "Upewnij się, że token Firebase jest dostępny." + "Token Firebase nie jest znany." + "Token Firebase: %1$s." + "Sprawdź token Firebase" + diff --git a/libraries/pushproviders/firebase/src/main/res/values-uk/translations.xml b/libraries/pushproviders/firebase/src/main/res/values-uk/translations.xml new file mode 100644 index 0000000000..8024070d70 --- /dev/null +++ b/libraries/pushproviders/firebase/src/main/res/values-uk/translations.xml @@ -0,0 +1,11 @@ + + + "Переконується, що Firebase доступний." + "Firebase недоступний." + "Firebase доступний." + "Перевірка Firebase" + "Переконується, що токен Firebase доступний." + "Токен Firebase невідомий." + "Токен Firebase: %1$s." + "Перевірка токена Firebase" + diff --git a/libraries/pushproviders/unifiedpush/src/main/res/values-pl/translations.xml b/libraries/pushproviders/unifiedpush/src/main/res/values-pl/translations.xml new file mode 100644 index 0000000000..d12f81977f --- /dev/null +++ b/libraries/pushproviders/unifiedpush/src/main/res/values-pl/translations.xml @@ -0,0 +1,11 @@ + + + "Upewnij się, że dystrybutorzy UnifiedPush są dostępni." + "Nie znaleziono dystrybutorów push." + + "Znaleziono %1$d dystrybutora: %2$s." + "Znaleziono %1$d dystrybutorów: %2$s." + "Znaleziono %1$d dystrybutorów: %2$s." + + "Sprawdź UnifiedPush" + diff --git a/libraries/pushproviders/unifiedpush/src/main/res/values-uk/translations.xml b/libraries/pushproviders/unifiedpush/src/main/res/values-uk/translations.xml new file mode 100644 index 0000000000..cad17a7b69 --- /dev/null +++ b/libraries/pushproviders/unifiedpush/src/main/res/values-uk/translations.xml @@ -0,0 +1,11 @@ + + + "Переконується, що дистриб\'ютори UnifiedPush доступні." + "Дистриб\'юторів не знайдено." + + "%1$d дистриб\'ютора знайдено: %2$s." + "%1$d дистриб\'юторів знайдено: %2$s." + "%1$d дистриб\'юторів знайдено: %2$s." + + "Перевірка UnifiedPush" + 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 ba683438e6..ef2fea495e 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 @@ -64,6 +64,7 @@ import io.element.android.libraries.ui.strings.CommonStrings import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.toPersistentList +@Suppress("MultipleEmitters") // False positive @OptIn(ExperimentalMaterial3Api::class) @Composable fun RoomSelectView( diff --git a/libraries/textcomposer/impl/src/main/res/values-pl/translations.xml b/libraries/textcomposer/impl/src/main/res/values-pl/translations.xml index 484b3b622c..c48403de54 100644 --- a/libraries/textcomposer/impl/src/main/res/values-pl/translations.xml +++ b/libraries/textcomposer/impl/src/main/res/values-pl/translations.xml @@ -7,14 +7,14 @@ "Wiadomość…" "Utwórz link" "Edytuj link" - "Zastosuj pogrubiony format" - "Zastosuj format kursywy" - "Zastosuj format przekreślenia" - "Zastosuj format podkreślenia" - "Przełącz tryb pełnoekranowy" + "Zastosuj pogrubienie" + "Zastosuj kursywę" + "Zastosuj przekreślenie" + "Zastosuj podkreślenie" + "Przełącz pełny ekran" "Wcięcie" - "Zastosuj format kodu wbudowanego" - "Wstaw łącze" + "Zastosuj formatowanie kodu w wierszu" + "Wstaw link" "Przełącz listę numerowaną" "Otwórz opcje tworzenia" "Przełącz cytat" diff --git a/libraries/textcomposer/impl/src/main/res/values-pt-rBR/translations.xml b/libraries/textcomposer/impl/src/main/res/values-pt-rBR/translations.xml index 332f97e155..592050a625 100644 --- a/libraries/textcomposer/impl/src/main/res/values-pt-rBR/translations.xml +++ b/libraries/textcomposer/impl/src/main/res/values-pt-rBR/translations.xml @@ -12,12 +12,14 @@ "Aplicar formato tachado" "Aplicar sublinhado" "Alternar o modo de tela cheia" + "Identar" "Aplicar formato de código embutido" "Definir link" "Alternar lista numerada" "Abrir opções de composição" "Alternar citação" "Remover link" + "Desidentar" "Link" "Segure para gravar" diff --git a/libraries/textcomposer/impl/src/main/res/values-uz/translations.xml b/libraries/textcomposer/impl/src/main/res/values-uz/translations.xml new file mode 100644 index 0000000000..bc6cd60cb1 --- /dev/null +++ b/libraries/textcomposer/impl/src/main/res/values-uz/translations.xml @@ -0,0 +1,25 @@ + + + "Biriktirma qo\'shing" + "Belgilar roʻyxatini almashtirish" + "Formatlash parametrlarini yoping" + "Kod blokini almashtirish" + "Xabar…" + "Havola yarating" + "Havolani tahrirlash" + "Qalin formatni qo\'llang" + "Kursiv formatini qo\'llang" + "Chizilgan formatni qo\'llash" + "Pastki chiziq formatini qo\'llang" + "Toʻliq ekran rejimiga oʻtish" + "Paragraf" + "Koq formatini mos ravishda qo\'shing" + "Havolani o\'rnatish" + "Raqamlangan roʻyxatni almashtirish" + "Yozish parametrlarini oching" + "Iqtibosni almashtirish" + "Havolani olib tashlang" + "Paragrafni bekor qilish" + "Havola" + "Yozib olish uchun bosib turing" + diff --git a/libraries/troubleshoot/impl/src/main/kotlin/io/element/android/libraries/troubleshoot/impl/TroubleshootNotificationsView.kt b/libraries/troubleshoot/impl/src/main/kotlin/io/element/android/libraries/troubleshoot/impl/TroubleshootNotificationsView.kt index 26232f8d69..b48af4480f 100644 --- a/libraries/troubleshoot/impl/src/main/kotlin/io/element/android/libraries/troubleshoot/impl/TroubleshootNotificationsView.kt +++ b/libraries/troubleshoot/impl/src/main/kotlin/io/element/android/libraries/troubleshoot/impl/TroubleshootNotificationsView.kt @@ -16,6 +16,7 @@ package io.element.android.libraries.troubleshoot.impl +import androidx.compose.foundation.layout.ColumnScope import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.size import androidx.compose.foundation.progressSemantics @@ -68,7 +69,7 @@ fun TroubleshootNotificationsView( } @Composable -private fun TroubleshootTestView( +private fun ColumnScope.TroubleshootTestView( testState: NotificationTroubleshootTestState, onQuickFixClick: () -> Unit, ) { @@ -127,7 +128,7 @@ private fun TroubleshootTestView( } @Composable -private fun TroubleshootNotificationsContent(state: TroubleshootNotificationsState) { +private fun ColumnScope.TroubleshootNotificationsContent(state: TroubleshootNotificationsState) { when (state.testSuiteState.mainState) { AsyncAction.Loading, AsyncAction.Confirming, @@ -197,7 +198,7 @@ private fun RunTestButton(state: TroubleshootNotificationsState) { } @Composable -private fun TestSuiteView( +private fun ColumnScope.TestSuiteView( testSuiteState: TroubleshootTestSuiteState, onQuickFixClick: (Int) -> Unit, ) { diff --git a/libraries/troubleshoot/impl/src/main/res/values-pl/translations.xml b/libraries/troubleshoot/impl/src/main/res/values-pl/translations.xml new file mode 100644 index 0000000000..62d8e0c5d3 --- /dev/null +++ b/libraries/troubleshoot/impl/src/main/res/values-pl/translations.xml @@ -0,0 +1,11 @@ + + + "Uruchom testy" + "Uruchom testy ponownie" + "Niektóre testy się nie powiodły. Sprawdź szczegóły." + "Uruchom testy, aby wykryć potencjalne problemy z konfiguracją, jeśli powiadomienia nie działają prawidłowo." + "Spróbuj naprawić" + "Wszystkie testy przebiegły pomyślnie." + "Powiadomienia rozwiązywania problemów" + "Niektóre testy wymagają Twojej uwagi. Sprawdź szczegóły." + diff --git a/libraries/troubleshoot/impl/src/main/res/values-uk/translations.xml b/libraries/troubleshoot/impl/src/main/res/values-uk/translations.xml new file mode 100644 index 0000000000..935c6b517d --- /dev/null +++ b/libraries/troubleshoot/impl/src/main/res/values-uk/translations.xml @@ -0,0 +1,11 @@ + + + "Запустити тести" + "Запустити тести знову" + "Деякі тести не пройшли. Будь ласка, перегляньте деталі." + "Запустіть тести, щоб виявити будь-яку проблему у вашій конфігурації, через яку сповіщення можуть не працювати належним чином." + "Спробувати виправити" + "Всі тести пройшли успішно." + "Усунення неполадок сповіщень" + "Деякі тести вимагають вашої уваги. Будь ласка, перегляньте деталі." + diff --git a/libraries/ui-strings/src/main/res/values-be/translations.xml b/libraries/ui-strings/src/main/res/values-be/translations.xml index b8a46a245b..955c4eab3d 100644 --- a/libraries/ui-strings/src/main/res/values-be/translations.xml +++ b/libraries/ui-strings/src/main/res/values-be/translations.xml @@ -93,6 +93,7 @@ "Паведаміць пра памылку" "Паскардзіцца на змест" "Скінуць" + "Скінуць ідэнтыфікацыйныя дадзеныя" "Паўтарыць" "Паўтарыць расшыфроўку" "Захаваць" @@ -112,6 +113,7 @@ "Зрабіць фота" "Дакраніцеся, каб убачыць параметры" "Паўтарыць спробу" + "Адмацаваць" "Прагляд зыходнага кода" "Так" "Аб праграме" @@ -262,6 +264,7 @@ "Некаторыя паведамленні не былі адпраўлены" "Выбачце, адбылася памылка" "Сапраўднасць гэтага зашыфраванага паведамлення не можа быць гарантаваная на гэтай прыладзе." + "Не зашыфраваны." "Зашыфравана невядомай ці выдаленай прыладай." "Зашыфравана прыладай, не пацверджанай яе ўладальнікам." "Зашыфравана неправераным карыстальнікам." @@ -269,9 +272,30 @@ "Гэй, пагавары са мной у %1$s: %2$s" "%1$s Android" "Паведаміць аб памылцы з дапамогай Rageshake" + "Дадзеныя вашага ўліковага запісу, кантакты, налады і спіс чатаў будуць захаваны" + "Вы страціце існуючую гісторыю паведамленняў" + "Вам трэба будзе зноў запэўніць ўсе вашы існуючыя прылады і кантакты" + "Працягвайце, толькі калі вы ўпэўненыя, што страцілі ўсе астатнія прылады і ключ аднаўлення." + "Калі вы не ўвайшлі ў сістэму на іншых прыладах і страцілі ключ аднаўлення, вам неабходна скінуць ключы пацверджання, каб працягнуць выкарыстанне прыкладання." + "Скіньце ключы пацверджання, калі вы не можаце пацвердзіць яго іншым спосабам" "Не ўдалося выбраць носьбіт, паўтарыце спробу." "Не атрымалася апрацаваць медыяфайл для загрузкі, паспрабуйце яшчэ раз." "Не атрымалася загрузіць медыяфайлы, паспрабуйце яшчэ раз." + "Націсніце на паведамленне і абярыце «%1$s », каб уключыць сюды." + "Замацуеце важныя паведамленні, каб іх можна было лёгка знайсці" + + "%1$d Замацаванае паведамленне" + "%1$d Замацаваныя паведамленні" + "%1$d Замацаваных паведамленняў" + + "Замацаваныя паведамленні" + "Так, скінуць зараз" + "Гэты працэс незваротны." + "Вы ўпэўнены, што хочаце скінуць шыфраванне?" + "Увод…" + "Пацвердзіце, што вы хочаце скінуць шыфраванне" + "Каб працягнуць, увядзіце пароль уліковага запісу" + "Замацаваныя паведамленні" "Не атрымалася апрацаваць медыяфайл для загрузкі, паспрабуйце яшчэ раз." "Не ўдалося атрымаць інфармацыю пра карыстальніка" "Заблакіраваць" @@ -281,6 +305,10 @@ "Разблакіраваць" "Вы зноў зможаце ўбачыць усе паведамленні." "Разблакіраваць карыстальніка" + "%1$s з %2$s" + "%1$s Замацаваныя паведамленні" + "Загрузка паведамлення…" + "Паглядзець усе" "Чат" "Падзяліцца месцазнаходжаннем" "Падзяліцца маім месцазнаходжаннем" 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 84358eda6f..39e0610883 100644 --- a/libraries/ui-strings/src/main/res/values-cs/translations.xml +++ b/libraries/ui-strings/src/main/res/values-cs/translations.xml @@ -82,6 +82,7 @@ "OK" "Otevřít nastavení" "Otevřít v aplikaci" + "Pin" "Rychlá odpověď" "Citovat" "Reagovat" @@ -111,6 +112,7 @@ "Vyfotit" "Klepnutím zobrazíte možnosti" "Zkusit znovu" + "Odepnout" "Zobrazit zdroj" "Ano" "O aplikaci" @@ -260,6 +262,10 @@ Důvod: %1$s." "%1$s nemá oprávnění k přístupu k mikrofonu. Povolte přístup k nahrávání hlasové zprávy." "Některé zprávy nebyly odeslány" "Omlouváme se, došlo k chybě" + "Autenticitu této zašifrované zprávy nelze na tomto zařízení zaručit." + "Šifrováno neznámým nebo smazaným zařízením." + "Šifrováno zařízením, které nebylo ověřeno jeho vlastníkem." + "Šifrováno neověřeným uživatelem." "🔐️ Připojte se ke mně na %1$s" "Ahoj, ozvi se mi na %1$s: %2$s" "%1$s Android" @@ -276,6 +282,9 @@ Důvod: %1$s." "Odblokovat" "Znovu uvidíte všechny zprávy od nich." "Odblokovat uživatele" + "%1$s z %2$s" + "%1$s Připnuté zprávy" + "Zobrazit vše" "Chat" "Sdílet polohu" "Sdílet moji polohu" diff --git a/libraries/ui-strings/src/main/res/values-el/translations.xml b/libraries/ui-strings/src/main/res/values-el/translations.xml index c06e4f8c22..b38211a60d 100644 --- a/libraries/ui-strings/src/main/res/values-el/translations.xml +++ b/libraries/ui-strings/src/main/res/values-el/translations.xml @@ -110,6 +110,7 @@ "Τράβηξε φωτογραφία" "Πάτα για επιλογές" "Προσπάθησε ξανά" + "Ξεκαρφίτσωμα" "Προβολή πηγής" "Ναι" "Σχετικά" diff --git a/libraries/ui-strings/src/main/res/values-et/translations.xml b/libraries/ui-strings/src/main/res/values-et/translations.xml index d82d7cd5ab..31e32b2a27 100644 --- a/libraries/ui-strings/src/main/res/values-et/translations.xml +++ b/libraries/ui-strings/src/main/res/values-et/translations.xml @@ -91,6 +91,7 @@ "Teata veast" "Teata sisust haldurile" "Lähtesta" + "Lähtesta on identiteet" "Proovi uuesti" "Proovi dekrüptimist uuesti" "Salvesta" @@ -110,6 +111,7 @@ "Tee pilt" "Valikuteks klõpsa" "Proovi uuesti" + "Eemalda kinnitus" "Vaata lähtekoodi" "Jah" "Rakenduse teave" @@ -258,6 +260,7 @@ Põhjus: %1$s." "Mõned sõnumid on saatmata" "Vabandust, ilmnes viga" "Selle krüptitud sõnumi tõepärasus pole selles seadmes tagatud." + "Pole krüptitud." "Krüptitud tundmatu või kustutatud seadme poolt." "Krüptitud seadme poolt, mida tema omanik pole verifitseerinud." "Krüptitud verifitseerimata kasutaja poolt." @@ -265,9 +268,29 @@ Põhjus: %1$s." "Hei, suhtle minuga %1$s võrgus: %2$s" "%1$s Android" "Veast teatamiseks raputa nutiseadet ägedalt" + "Sinu kasutajakonto andmed, kontaktid, eelistused ja vestluste loend säiluvad" + "Sa kaotad seniste sõnumite ajaloo" + "Sa pead kõik oma olemasolevad seadmed ja kontaktid uuesti verifitseerima" + "Lähtesta oma identiteet vaid siis, kui sul pole ligipääsu mitte ühelegi oma seadmele ja sa oled kaotanud oma taastevõtme." + "Kui sa soovid jätkata selle rakenduse kasutamist ja sa pole mitte üheski seadmes sisse logitud ning oled kaotanud oma taastevõtme, siis tõesti pead lähtestama oma identiteedi. " + "Kui sa ühtegi muud võimalust ei leia, siis lähtesta oma identiteet." "Meediafaili valimine ei õnnestunud. Palun proovi uuesti." "Meediafaili töötlemine enne üleslaadimist ei õnnestunud. Palun proovi uuesti." "Meediafaili üleslaadimine ei õnnestunud. Palun proovi uuesti." + "Siia lisamiseks vajuta sõnumil ja vali „%1$s“." + "Et olulisi sõnumeid oleks lihtsam leida, tõsta nad esile" + + "%1$d esiletõstetud sõnum" + "%1$d esiletõstetud sõnumit" + + "Esiletõstetud sõnumid" + "Jah, lähtesta nüüd" + "See tegevus on tagasipöördumatu." + "Kas sa oled kindel, et soovid oma andmete krüptimist lähtestada?" + "Sisesta…" + "Palun kinnita, et soovid oma andmete krüptimist lähtestada." + "Jätkamaks sisesta oma kasutajakonto salasõna" + "Esiletõstetud sõnumid" "Meediafaili töötlemine enne üleslaadimist ei õnnestunud. Palun proovi uuesti." "Kasutaja andmete laadimine ei õnnestunud" "Blokeeri" @@ -278,7 +301,8 @@ Põhjus: %1$s." "Nüüd näed sa jälle kõiki tema sõnumeid" "Eemalda kasutajalt blokeering" "%1$s / %2$s" - "%1$s kinnitatud sõnumit" + "%1$s esiletõstetud sõnumit" + "Laadime sõnumit…" "Näita kõiki" "Vestlus" "Jaga asukohta" 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 7692711037..84e16ed265 100644 --- a/libraries/ui-strings/src/main/res/values-hu/translations.xml +++ b/libraries/ui-strings/src/main/res/values-hu/translations.xml @@ -91,6 +91,7 @@ "Hiba jelentése" "Tartalom jelentése" "Visszaállítás" + "Személyazonosság visszaállítása" "Újra" "Visszafejtés újbóli megpróbálása" "Mentés" @@ -110,6 +111,7 @@ "Fénykép készítése" "Koppintson a beállításokért" "Próbálja újra" + "Kitűzés feloldása" "Forrás megtekintése" "Igen" "Névjegy" @@ -258,6 +260,7 @@ Ok: %1$s." "Néhány üzenet nem került elküldésre" "Elnézést, hiba történt" "A titkosított üzenetek valódiságát ezen az eszközön nem lehet garantálni." + "Nincs titkosítva." "Ismeretlen vagy törölt eszköz által titkosítva." "A tulajdonos által nem ellenőrzött eszköz által titkosítva." "Nem ellenőrzött felhasználó által titkosítva." @@ -265,9 +268,22 @@ Ok: %1$s." "Beszélgessünk itt: %1$s, %2$s" "%1$s Android" "Az eszköz rázása a hibajelentéshez" + "A fiókadatok, a kapcsolatok, a beállítások és a csevegéslista megmarad" + "Elveszíti meglévő üzenetelőzményeit" + "Újból ellenőriznie kell az összes meglévő eszközét és csevegőpartnerét" + "Csak akkor állítsa vissza a személyazonosságát, ha nem fér hozzá másik bejelentkezett eszközhöz, és elvesztette a helyreállítási kulcsot." + "Ha nincs bejelentkezve más eszközre, és elvesztette a helyreállítási kulcsot, akkor az alkalmazás használatának folytatásához vissza kell állítania személyazonosságát. " + "Állítsa vissza a személyazonosságát, ha más módon nem tudja megerősíteni" "Nem sikerült kiválasztani a médiát, próbálja újra." "Nem sikerült feldolgozni a feltöltendő médiát, próbálja újra." "Nem sikerült a média feltöltése, próbálja újra." + "Igen, visszaállítás most" + "Ez a folyamat visszafordíthatatlan." + "Biztos, hogy visszaállítja a titkosítást?" + "Adja meg…" + "Erősítse meg, hogy vissza szeretné állítani a titkosítást." + "A folytatáshoz adja meg fiókja jelszavát" + "Kitűzött üzenetek" "Nem sikerült feldolgozni a feltöltendő médiát, próbálja újra." "Nem sikerült letölteni a felhasználói adatokat" "Letiltás" @@ -277,6 +293,10 @@ Ok: %1$s." "Letiltás feloldása" "Újra láthatja az összes üzenetét." "Felhasználó kitiltásának feloldása" + "%1$s / %2$s" + "%1$s kitűzött üzenet" + "Üzenet betöltése…" + "Összes megtekintése" "Csevegés" "Hely megosztása" "Saját hely megosztása" diff --git a/libraries/ui-strings/src/main/res/values-pl/translations.xml b/libraries/ui-strings/src/main/res/values-pl/translations.xml index 5580f93974..17df3fe3d7 100644 --- a/libraries/ui-strings/src/main/res/values-pl/translations.xml +++ b/libraries/ui-strings/src/main/res/values-pl/translations.xml @@ -124,7 +124,7 @@ "Rozmowa w trakcie (niewspierane)" "Rozpoczęto rozmowę" "Backup czatu" - "Copyright" + "Prawa autorskie" "Tworzenie pokoju…" "Opuścił pokój" "Ciemny" @@ -260,10 +260,14 @@ Powód: %1$s." "%1$s nie ma uprawnień dostępu do Twojego mikrofonu. Włącz dostęp, aby nagrać wiadomość głosową." "Niektóre wiadomości nie zostały wysłane" "Przepraszamy, wystąpił błąd" + "Autentyczność tej wiadomości szyfrowanej nie jest gwarantowana na tym urządzeniu." + "Zaszyfrowana przez nieznane lub usunięte urządzenie." + "Zaszyfrowana przez urządzenie niezweryfikowane przez jego właściciela." + "Zaszyfrowana przez niezweryfikowanego użytkownika." "🔐️ Dołącz do mnie na %1$s" "Hej, porozmawiajmy na %1$s: %2$s" "%1$s Android" - "Gniewne wstrząsanie, aby zgłosić błąd" + "Wstrząśnij gniewnie, aby zgłosić błąd" "Nie udało się wybrać multimediów. Spróbuj ponownie." "Przetwarzanie multimediów do przesłania nie powiodło się, spróbuj ponownie." "Przesyłanie multimediów nie powiodło się, spróbuj ponownie." @@ -272,9 +276,11 @@ Powód: %1$s." "Zablokuj" "Zablokowani użytkownicy nie będą mogli wysyłać Ci wiadomości, a wszystkie ich wiadomości zostaną ukryte. Możesz odblokować ich w dowolnym momencie." "Zablokuj użytkownika" + "Profil" "Odblokuj" "Będziesz mógł ponownie zobaczyć wszystkie wiadomości od tego użytkownika." "Odblokuj użytkownika" + "Czat" "Udostępnij lokalizację" "Udostępnij moją lokalizację" "Otwórz w Apple Maps" diff --git a/libraries/ui-strings/src/main/res/values-pt-rBR/translations.xml b/libraries/ui-strings/src/main/res/values-pt-rBR/translations.xml index 10cd8e39cf..17bfd31dc0 100644 --- a/libraries/ui-strings/src/main/res/values-pt-rBR/translations.xml +++ b/libraries/ui-strings/src/main/res/values-pt-rBR/translations.xml @@ -1,6 +1,10 @@ "Excluir" + + "%1$d dígito inserido" + "%1$d dígitos inseridos" + "Ocultar senha" "Ir para o final" "Apenas menções" @@ -14,6 +18,10 @@ "Reagir com %1$s" "Reaja com outros emojis" "Lido por %1$s e %2$s" + + "Lido por %1$s e %2$d outro" + "Lido por %1$s e %2$d outros" + "Lido por %1$s" "Toque para mostrar tudo" "Remova a reação com %1$s" @@ -186,7 +194,7 @@ "Sala" "Nome da sala" "por exemplo, o nome do seu projeto" - "Mudanças salvas" + "Alterações salvas" "Salvando" "Bloqueio de tela" "Procurar alguém" @@ -233,8 +241,8 @@ "Erro" "Sucesso" "Aviso" - "Suas mudanças não foram salvas. Tem certeza de que você quer voltar?" - "Salvar mudanças?" + "Suas alterações não foram salvas. Tem certeza de que você quer voltar?" + "Salvar alterações?" "Falha ao criar o link permanente" "%1$s não conseguiu carregar o mapa. Por favor, tente novamente mais tarde." "Falha ao carregar mensagens" @@ -243,6 +251,7 @@ "Mensagem não encontrada" "%1$s não tem permissão para acessar sua localização. Você pode ativar o acesso nas Configurações." "%1$s não tem permissão para acessar sua localização. Habilite o acesso abaixo." + "%1$s não tem permissão para acessar seu microfone. Permita o acesso para gravar uma mensagem de voz." "Algumas mensagens não foram enviadas" "Desculpe, ocorreu um erro" "Criptografada por um dispositivo desconhecido ou apagado." diff --git a/libraries/ui-strings/src/main/res/values-pt/translations.xml b/libraries/ui-strings/src/main/res/values-pt/translations.xml index 005082f743..630717a136 100644 --- a/libraries/ui-strings/src/main/res/values-pt/translations.xml +++ b/libraries/ui-strings/src/main/res/values-pt/translations.xml @@ -80,6 +80,7 @@ "OK" "Configurações" "Abrir com" + "Afixar" "Resposta rápida" "Citação" "Reagir" @@ -90,6 +91,7 @@ "Comunicar problema" "Denunciar conteúdo" "Repor" + "Repor identidade" "Tentar novamente" "Tentar decifragem novamente" "Guardar" @@ -109,6 +111,7 @@ "Tirar foto" "Toca para ver as opções" "Tentar novamente" + "Desafixar" "Ver fonte" "Sim" "Sobre" @@ -168,6 +171,7 @@ Razão: %1$s." "Sem resultados" "Sala sem nome" "Desligado" + "Licenças de código aberto" "ou" "Senha" "Pessoas" @@ -255,13 +259,29 @@ Razão: %1$s." "A %1$s não tem permissão para aceder ao teu microfone. Permite o acesso para gravar uma mensagem de voz." "Algumas mensagens não foram enviadas" "Ocorreu um erro, desculpa" + "A autenticidade desta mensagem cifrada não pode ser garantida neste dispositivo." + "Cifragem com origem num dispositivo eliminado ou desconhecido." + "Cifragem com origem num dispositivo não verificado pelo seu dono." + "Cifragem com origem num utilizador não verificado." "🔐️ Junta-te a mim na %1$s" "Alô! Fala comigo na %1$s: %2$s" "%1$s Android" "Agita o dispositivo em fúria para comunicar um problema" + "Os detalhes da tua conta, contactos, preferências e lista de conversas serão mantidos." + "Perderás o acesso ao teu histórico de mensagens existente" + "Necessitarás de verificar todos os teus dispositivos e contactos novamente." + "Repõe a tua identidade apenas se não tiveres acesso a mais nenhum dispositivo com sessão iniciada e se tiveres perdido a tua chave de recuperação." + "Se não tiveres sessão iniciada em nenhum outro dispositivo e perdeste o acesso à tua chave de recuperação, precisarás de repor a tua identidade para continuares a usar a aplicação. " + "Repõe a tua identidade caso não consigas confirmar de outra forma" "Falha ao selecionar multimédia, por favor tente novamente." "Falha ao processar multimédia para carregamento, por favor tente novamente." "Falhar ao carregar multimédia, por favor tente novamente." + "Sim, repor agora" + "Este processo é irreversível." + "Tens a certeza que pretendes repor a tua cifra?" + "Inserir…" + "Confirma que pretendes realmente repor a tua cifra." + "Insere a tua palavra-passe para continuares" "Falha ao processar multimédia para carregamento, por favor tente novamente." "Não foi possível obter os detalhes de utilizador." "Bloquear" @@ -271,6 +291,9 @@ Razão: %1$s." "Desbloquear" "Poderás voltar a ver todas as suas mensagens." "Desbloquear utilizador" + "%1$s de %2$s" + "%1$s mensagens afixadas" + "Ver todas" "Conversa" "Partilhar localização" "Partilhar a minha localização" 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 12067cbeaa..d087e9c8d3 100644 --- a/libraries/ui-strings/src/main/res/values-ru/translations.xml +++ b/libraries/ui-strings/src/main/res/values-ru/translations.xml @@ -82,6 +82,7 @@ "Ок" "Открыть настройки" "Открыть с помощью" + "Закрепить" "Быстрый ответ" "Цитата" "Реакция" @@ -92,6 +93,7 @@ "Сообщить об ошибке" "Пожаловаться на содержание" "Сбросить" + "Сбросить идентификацию" "Повторить" "Повторите расшифровку" "Сохранить" @@ -111,6 +113,7 @@ "Сделать фото" "Нажмите для просмотра вариантов" "Повторить попытку" + "Открепить" "Показать источник" "Да" "О приложении" @@ -171,6 +174,7 @@ "Ничего не найдено" "Нету названия комнаты" "Не в сети" + "Лицензии с открытым исходным кодом" "или" "Пароль" "Люди" @@ -261,13 +265,39 @@ "%1$s не имеет разрешения на доступ к вашему микрофону. Разрешите доступ к записи голосового сообщения." "Некоторые сообщения не были отправлены" "Извините, произошла ошибка" + "Подлинность этого зашифрованного сообщения не может быть гарантирована на этом устройстве." + "Не зашифровано." + "Зашифровано неизвестным или удаленным устройством." + "Зашифровано устройством, не проверенным его владельцем." + "Зашифровано непроверенным пользователем." "🔐️ Присоединяйтесь ко мне в %1$s" "Привет, поговори со мной по %1$s: %2$s" "%1$s Android" "Встряхните устройство, чтобы сообщить об ошибке" + "Данные вашей учетной записи, контакты, настройки и список чатов будут сохранены" + "Вы потеряете существующую историю сообщений" + "Вам нужно будет заново подтвердить все существующие устройства и контакты." + "Сбрасывайте данные только в том случае, если у вас нет доступа к другому устройству, на котором выполнен вход, и вы потеряли ключ восстановления." + "Если вы не вошли в систему на других устройствах и потеряли ключ восстановления, вам необходимо сбросить учетные данные, чтобы продолжить использование приложения. " + "Сбросьте ключи подтверждения, если вы не можете подтвердить свою личность другим способом." "Не удалось выбрать носитель, попробуйте еще раз." "Не удалось обработать медиафайл для загрузки, попробуйте еще раз." "Не удалось загрузить медиафайлы, попробуйте еще раз." + "Нажмите на сообщение и выберите “%1$s”, чтобы добавить его сюда." + "Закрепите важные сообщения, чтобы их можно было легко найти" + + "%1$d Закрепленное сообщение" + "%1$d Закрепленных сообщений" + "%1$d Закрепленных сообщений" + + "Закрепленные сообщения" + "Да, сбросить сейчас" + "Этот процесс необратим." + "Вы действительно хотите сбросить шифрование?" + "Ввод…" + "Подтвердите, что вы хотите сбросить шифрование." + "Введите пароль своей учетной записи, чтобы продолжить" + "Закрепленные сообщения" "Не удалось обработать медиафайл для загрузки, попробуйте еще раз." "Не удалось получить данные о пользователе" "Заблокировать" @@ -277,6 +307,10 @@ "Разблокировать" "Вы снова сможете увидеть все сообщения." "Разблокировать пользователя" + "%1$s из %2$s" + "%1$s Закрепленные сообщения" + "Загрузка сообщения…" + "Посмотреть все" "Чат" "Поделиться местоположением" "Поделиться моим местоположением" 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 1eb3fa1c47..497f2af1fb 100644 --- a/libraries/ui-strings/src/main/res/values-sk/translations.xml +++ b/libraries/ui-strings/src/main/res/values-sk/translations.xml @@ -93,6 +93,7 @@ "Nahlásiť chybu" "Nahlásiť obsah" "Obnoviť" + "Obnoviť identitu" "Skúsiť znova" "Opakovať dešifrovanie" "Uložiť" @@ -112,6 +113,7 @@ "Urobiť fotku" "Klepnutím získate možnosti" "Skúste to znova" + "Odopnúť" "Zobraziť zdroj" "Áno" "O aplikácii" @@ -262,6 +264,7 @@ Dôvod: %1$s." "Niektoré správy neboli odoslané" "Prepáčte, vyskytla sa chyba" "Pravosť tejto šifrovanej správy nie je možné zaručiť na tomto zariadení." + "Nie je šifrované." "Zašifrované neznámym alebo odstráneným zariadením." "Šifrované zariadením, ktoré nie je overené jeho majiteľom." "Šifrované neovereným používateľom." @@ -269,9 +272,30 @@ Dôvod: %1$s." "Ahoj, porozprávajte sa so mnou na %1$s: %2$s" "%1$s Android" "Zúrivo potriasť pre nahlásenie chyby" + "Údaje o vašom účte, kontakty, predvoľby a zoznam konverzácií budú zachované" + "Stratíte svoju existujúcu históriu správ" + "Budete musieť znova overiť všetky existujúce zariadenia a kontakty" + "Obnovte svoju totožnosť iba vtedy, ak nemáte prístup k inému prihlásenému zariadeniu a stratili ste kľúč na obnovenie." + "Ak nie ste prihlásení do žiadneho iného zariadenia a stratili ste kľúč na obnovenie, budete musieť znovu obnoviť svoju identitu, aby ste mohli pokračovať v používaní aplikácie. " + "Znovu nastavte svoju totožnosť v prípade, že ju nemôžete potvrdiť iným spôsobom" "Nepodarilo sa vybrať médium, skúste to prosím znova." "Nepodarilo sa spracovať médiá na odoslanie, skúste to prosím znova." "Nepodarilo sa nahrať médiá, skúste to prosím znova." + "Stlačte správu a vyberte možnosť „%1$s“, ktorú chcete zahrnúť sem." + "Pripnite dôležité správy, aby sa dali ľahko nájsť" + + "%1$d pripnutá správa" + "%1$d pripnuté správy" + "%1$d pripnutých správ" + + "Pripnuté správy" + "Áno, znovu nastaviť teraz" + "Tento proces je nezvratný." + "Naozaj chcete obnoviť svoje šifrovanie?" + "Zadajte…" + "Potvrďte, že chcete obnoviť svoje šifrovanie." + "Ak chcete pokračovať, zadajte heslo účtu" + "Pripnuté správy" "Nepodarilo sa spracovať médiá na odoslanie, skúste to prosím znova." "Nepodarilo sa získať údaje o používateľovi" "Zablokovať" @@ -283,6 +307,7 @@ Dôvod: %1$s." "Odblokovať používateľa" "%1$s z %2$s" "%1$s Pripnutých správ" + "Načítava sa správa…" "Zobraziť všetko" "Konverzácia" "Zdieľať polohu" diff --git a/libraries/ui-strings/src/main/res/values-sv/translations.xml b/libraries/ui-strings/src/main/res/values-sv/translations.xml index 144e6bda05..cca5e5b12a 100644 --- a/libraries/ui-strings/src/main/res/values-sv/translations.xml +++ b/libraries/ui-strings/src/main/res/values-sv/translations.xml @@ -34,6 +34,7 @@ "Godkänn" "Lägg till i tidslinjen" "Tillbaka" + "Ring" "Avbryt" "Välj bild" "Rensa" @@ -72,21 +73,25 @@ "Ladda mer" "Hantera konto" "Hantera enheter" + "Meddela" "Nästa" "Nej" "Inte nu" "OK" "Inställningar" "Öppna med" + "Fäst" "Snabbsvar" "Citera" "Reagera" + "Avvisa" "Ta bort" "Svara" "Svara i tråd" "Rapportera bugg" "Rapportera innehåll" "Återställ" + "Återställ identitet" "Försök igen" "Försök att avkryptera igen" "Spara" @@ -106,6 +111,7 @@ "Ta ett foto" "Tryck för alternativ" "Försök igen" + "Frigör" "Visa källkod" "Ja" "Om" @@ -117,6 +123,7 @@ "Blockerade användare" "Bubblor" "Samtal pågår (stöds inte)" + "Samtal startat" "Chattsäkerhetskopia" "Upphovsrätt" "Skapar rum …" @@ -125,12 +132,16 @@ "Avkrypteringsfel" "Utvecklaralternativ" "Direktchatt" + "Visa inte detta igen" "(redigerad)" "Redigerar" "* %1$s %2$s" "Kryptering aktiverad" "Ange din PIN-kod" "Fel" + "Ett fel inträffade, du kanske inte får aviseringar för nya meddelanden. Felsök aviseringar från inställningarna. + +Anledning:%1$s." "Alla" "Misslyckades" "Favorit" @@ -158,12 +169,15 @@ "Modernt" "Tysta" "Inga resultat" + "Inget rumsnamn" "Frånkopplad" + "Licenser för öppen källkod" "eller" "Lösenord" "Personer" "Permalänk" "Behörighet" + "Vänligen vänta …" "Är du säker på att du vill avsluta den här omröstningen?" "Omröstning: %1$s" "Totalt antal röster: %1$s" @@ -192,6 +206,7 @@ "Sökresultat" "Säkerhet" "Sett av" + "Skicka till" "Skickar …" "Misslyckades att skicka" "Skickat" @@ -200,6 +215,7 @@ "Inställningar" "Delade plats" "Loggar ut" + "Något gick fel" "Startar chatt …" "Dekal" "Lyckades" @@ -212,6 +228,7 @@ "Ämne" "Vad handlar det här rummet om?" "Kan inte avkryptera" + "Du har inte tillgång till det här meddelandet" "Inbjudan kunde inte skickas till en eller flera användare." "Kunde inte skicka inbjudningar" "Lås upp" @@ -236,18 +253,44 @@ "Misslyckades att ladda meddelanden" "%1$s kunde inte komma åt din plats. Vänligen försök igen senare." "Misslyckades med att ladda upp ditt röstmeddelande." + "Meddelandet hittades inte" "%1$s är inte behörig att komma åt din plats. Du kan aktivera åtkomst i Inställningar." "%1$s är inte behörig att komma åt din plats. Aktivera åtkomst nedan." "%1$s är inte behörig att komma åt din mikrofon. Aktivera åtkomst för att spela in ett röstmeddelande." "Vissa meddelanden har inte skickats" "Tyvärr, ett fel uppstod" + "Detta krypterade meddelandes äkthet kan inte garanteras på den här enheten." + "Inte krypterad." + "Krypterad av en okänd eller raderad enhet." + "Krypterad av en enhet som inte verifierats av ägaren." + "Krypterad av en overifierad användare." "🔐️ Häng med mig på %1$s" "Hallå, prata med mig på %1$s: %2$s" "%1$s Android" "Raseriskaka för att rapportera bugg" + "Dina kontouppgifter, kontakter, inställningar och chattlistor kommer bevaras" + "Du kommer att förlora din befintliga meddelandehistorik" + "Du måste verifiera alla dina befintliga enheter och kontakter igen" + "Återställ bara din identitet om du inte har tillgång till en annan inloggad enhet och du har tappat bort din återställningsnyckel." + "Om du inte är inloggad på någon annan enhet och du har tappat bort din återställningsnyckel måste du återställa din identitet för att fortsätta använda appen. " + "Återställ din identitet ifall du inte kan bekräfta på annat sätt" "Misslyckades att välja media, vänligen pröva igen." "Misslyckades att bearbeta media för uppladdning, vänligen pröva igen." "Misslyckades att ladda upp media, vänligen pröva igen." + "Tryck på ett meddelande och välj ”%1$s” för att inkludera det här." + "Fäst viktiga meddelanden så att de lätt kan upptäckas" + + "%1$d Fäst meddelande" + "%1$d Fästa meddelanden" + + "Fästa meddelanden" + "Ja, återställ nu" + "Denna process är irreversibel." + "Är du säker på att du vill återställa din kryptering?" + "Ange …" + "Bekräfta att du vill återställa din kryptering." + "Ange ditt kontolösenord för att fortsätta" + "Fästa meddelanden" "Misslyckades att bearbeta media för uppladdning, vänligen pröva igen." "Kunde inte hämta användarinformation" "Blockera" @@ -257,6 +300,11 @@ "Avblockera" "Du kommer att kunna se alla meddelanden från dem igen." "Avblockera användare" + "%1$s av %2$s" + "%1$s Fästa meddelanden" + "Laddar meddelande …" + "Visa alla" + "Chatt" "Dela plats" "Dela min plats" "Öppna i Apple Maps" diff --git a/libraries/ui-strings/src/main/res/values-uk/translations.xml b/libraries/ui-strings/src/main/res/values-uk/translations.xml index 4082bfb6b0..5a8ede8b04 100644 --- a/libraries/ui-strings/src/main/res/values-uk/translations.xml +++ b/libraries/ui-strings/src/main/res/values-uk/translations.xml @@ -36,6 +36,7 @@ "Прийняти" "Додати до стрічки" "Назад" + "Зателефонувати" "Скасувати" "Вибрати фото" "Очистити" @@ -74,21 +75,25 @@ "Завантажити ще" "Керування обліковим записом" "Керування пристроями" + "Написати" "Далі" "Ні" "Не зараз" "Гаразд" "Налаштування" "Відкрити за допомогою" + "Закріпити" "Швидка відповідь" "Цитувати" "Реакція" + "Відхилити" "Вилучити" "Відповісти" "Відповісти в гілці" "Повідомити про помилку" "Повідомити про вміст" "Скинути" + "Скинути ідентичність" "Спробувати ще раз" "Повторити спробу розшифрування" "Зберегти" @@ -108,6 +113,7 @@ "Зробити фото" "Натисніть, щоб переглянути параметри" "Спробуйте ще раз" + "Відкріпити" "Переглянути джерело" "Так" "Відомості" @@ -119,6 +125,7 @@ "Заблоковані користувачі" "Бульбашки" "Триває виклик (не підтримується)" + "Дзвінок розпочато" "Резервне копіювання чату" "Авторське право" "Створення кімнати…" @@ -127,12 +134,16 @@ "Помилка розшифровки" "Налаштування розробника" "Особистий чат" + "Не показувати це знову" "(відредаговано)" "Редагування" "* %1$s %2$s" "Шифрування ввімкнено" "Введіть свій PIN-код" "Помилка" + "Сталася помилка, ви можете не отримувати сповіщення про нові повідомлення. Усуньте неполадки зі сповіщеннями в налаштуваннях. + +Причина: %1$s." "Усі" "Невдало" "Улюблений" @@ -161,12 +172,15 @@ "Модерн" "Вимкнути звук" "Немає результатів" + "Немає назви кімнати" "Не в мережі" + "Ліцензії відкритого коду" "або" "Пароль" "Люди" "Постійне посилання" "Дозвіл" + "Будь ласка, зачекайте…" "Ви впевнені, що хочете закінчити це опитування?" "Опитування: %1$s" "Всього голосів: %1$s" @@ -196,6 +210,7 @@ "Результати пошуку" "Безпека" "Побачили" + "Надіслати до" "Надсилання…" "Не вдалося відправити" "Надіслано" @@ -204,6 +219,7 @@ "Налаштування" "Поширене розташування" "Вихід" + "Щось пішло не так" "Початок чату…" "Наліпка" "Успіх" @@ -216,6 +232,7 @@ "Тема" "Про що ця кімната?" "Неможливо розшифрувати" + "Ви не маєте доступу до цього повідомлення" "Не вдалося надіслати запрошення одному чи кільком користувачам." "Не вдалося надіслати запрошення" "Розблокувати" @@ -240,26 +257,48 @@ "Не вдалося завантажити повідомлення" "%1$s не вдалося отримати доступ до вашого місцезнаходження. Будь ласка, спробуйте ще раз пізніше." "Не вдалося завантажити голосове повідомлення." + "Повідомлення не знайдено" "%1$s не має дозволу на доступ до вашого місцезнаходження. Увімкнути доступ можна в Налаштуваннях." "%1$s не має дозволу на доступ до вашого місцезнаходження. Увімкніть доступ нижче." "%1$s не має доступу до вашого мікрофона. Надайте доступ, щоб записати голосове повідомлення." "Деякі повідомлення не були надіслані" "Вибачте, сталася помилка" + "Автентичність цього зашифрованого повідомлення не може бути гарантована на цьому пристрої." + "Зашифрований невідомим або видаленим пристроєм." + "Зашифровано пристроєм, який не підтверджено його власником." + "Зашифровано неперевіреним користувачем." "🔐️ Приєднуйтеся до мене в %1$s" "Привіт, пишіть мені за адресою %1$s: %2$s" "%1$s Android" "Повідомити про ваду за допомогою Rageshake" + "Дані вашого облікового запису, контакти, налаштування й чати будуть збережені" + "Ви втратите свою наявну історію повідомлень" + "Вам доведеться підтвердити всі наявні пристрої та контакти знову" + "Скидайте ідентичність тільки якщо ви не маєте доступу до інших пристроїв в обліковому записі та втратили свій ключ відновлення." + "Якщо ви не увійшли на інших пристроях та втратили свій ключ відновлення, то вам доведеться скинути свою ідентичність, щоб продовжити використовувати застосунок. " + "Скиньте свою ідентичність, якщо не можете підтвердити іншим способом" "Не вдалося вибрати медіафайл, спробуйте ще раз." "Не вдалося обробити медіафайл для завантаження, спробуйте ще раз." "Не вдалося завантажити медіафайл, спробуйте ще раз." + "Так, скинути зараз" + "Цей процес незворотний." + "Ви впевнені, що хочете скинути шифрування?" + "Ввести…" + "Підтвердьте, що ви хочете скинути шифрування." + "Введіть пароль облікового запису, щоб продовжити" "Не вдалося обробити медіафайл для завантаження, спробуйте ще раз." "Не вдалося отримати дані користувача" "Заблокувати" "Заблоковані користувачі не зможуть надсилати Вам повідомлення, і всі їхні повідомлення будуть приховані. Ви можете розблокувати їх у будь-який час." "Заблокувати користувача" + "Профіль" "Розблокувати" "Ви знову зможете бачити всі повідомлення від них." "Розблокувати користувача" + "%1$s із %2$s" + "%1$s Закріплених повідомлень" + "Переглянути всі" + "Чат" "Поділитися розташуванням" "Поділитися моїм розташуванням" "Відкрити в Apple Maps" diff --git a/libraries/ui-strings/src/main/res/values-uz/translations.xml b/libraries/ui-strings/src/main/res/values-uz/translations.xml new file mode 100644 index 0000000000..a80883710c --- /dev/null +++ b/libraries/ui-strings/src/main/res/values-uz/translations.xml @@ -0,0 +1,210 @@ + + + "Oʻchirish" + "Parolni yashirish" + "Faqat eslatmalar" + "Ovozsiz" + "Pauza" + "O\'ynang" + "So\'ro\'vnoma" + "So‘rovnoma yakunlandi" + "Fayllarni yuborish" + "Parolni ko\'rsatish" + "Foydalanuvchi menyusi" + "Ovoz yozishni amalga oshiring" + "Qabul qiling" + "Vaqt jadvaliga qo\'shing" + "Orqaga" + "Bekor qilish" + "Fotosuratni tanlang" + "Tozalash" + "Yopish" + "To\'liq tekshirish" + "Tasdiqlash" + "Davom etish" + "nusxa" + "Havolani nusxalash" + "Havolani xabaraga nusxalash" + "Yaratmoq" + "Xonani yaratish" + "Rad etish" + "Oʻchirish" + "Bajarildi" + "Tahrirlash" + "So‘rovnomani tahrirlash" + "Yoqish" + "So‘rovnomani tugatish" + "Parolni unutdingizmi?" + "Oldinga" + "Taklif qilish" + "Odamlarni taklif qiling" + "Odamlarni taklif qilish%1$s" + "Odamlarni taklif qiling%1$s" + "Takliflar" + "Qo\'shilish" + "Batafsil malumot" + "Tark etish " + "Xonani tark etish " + "Hisobni boshqarish" + "Qurilmalarni boshqarish" + "Keyingisi" + "Yo\'q" + "Hozir emas" + "Ok" + "Sozlamalar" + "Bilan oching" + "Tez javob" + "Iqtibos" + "Reaksiya qilish" + "Ochirish" + "Javob bering" + "Mavzuda javob bering" + "Xato haqida xabar berish" + "Tarkib haqida xabar berish" + "Qayta urinish" + "Shifrni ochishni qayta urinish" + "Saqlash" + "Qidirmoq" + "Yuborish" + "Xabar yuborish" + "Ulashish" + "Havolani ulashing" + "Qaytadan kiring" + "Tizimdan chiqish" + "Baribir tizimdan chiqing" + "Oʻtkazib yuborish" + "Boshlash" + "Suhbatni boshlash" + "Tasdiqlashni boshlang" + "Xaritani yuklash uchun bosing" + "Rasmga olmoq" + "Manbani korish " + "Ha" + "Haqida" + "Qabul qilinadigan foydalanish siyosati" + "Kengaytirilgan sozlamalar" + "Analitika" + "Audio" + "Pufakchalar" + "Chatning zaxira nusxasi" + "Mualliflik huquqi" + "Xona yaratilmoqda…" + "Xonani tark etdi" + "Shifrni ochish xatosi" + "Dasturchi variantlari" + "(tahrirlangan)" + "Tahrirlash" + "*%1$s%2$s" + "Shifrlash yoqilgan" + "Xato" + "Har kim" + "Fayl" + "Fayl “Yuklashlar”ga saqlandi" + "Xabarni yo\'naltirish" + "Surat" + "%1$sga Javob bering" + "APK-ni o\'rnating" + "Ushbu Matrix identifikatori topilmadi, shuning uchun taklif qabul qilinmasligi mumkin." + "Xonadan chiqish" + "Havola vaqtinchalik xotiraga nusxalandi" + "Yuklanmoqda…" + + "%1$d a\'zo" + "%1$d ishtirokchilar" + + "Xabar" + "Xabar tartibi" + "Xabar ochirib tashlandi" + "Zamonaviy" + "Ovozsiz qilish" + "Natijalar yoʻq" + "Oflayn" + "Parol" + "Odamlar" + "Doimiy havola" + "Ruxsat" + "Haqiqatan ham bu soʻrovnomani tugatmoqchimisiz?" + "So‘rov:%1$s" + "Jami ovozlar:%1$s" + "Natijalar soʻrovnoma tugagandan soʻng koʻrsatiladi" + + "%dovoz berish" + "%dovozlar" + + "Maxfiylik siyosati" + "Reaktsiya" + "reaksiyalar" + "Qayta tiklash kaliti" + "Yangilanmoqda…" + "%1$sga Javob berilmoqda" + "Xato haqida xabar bering" + "Hisobot topshirildi" + "Boy matn muharriri" + "Xona nomi" + "masalan, loyihangiz nomi" + "Kimnidir qidiring" + "Qidiruv natijalari" + "Xavfsizlik" + "Yuborilmoqda…" + "Server qo\'llab-quvvatlanmaydi" + "Server URL manzili" + "Sozlamalar" + "Joylashuvi ulashildi" + "Chat boshlanmoqda…" + "Stiker" + "Muvaffaqiyat" + "Tavsiyalar" + "Sinxronlash" + "Matn" + "Uchinchi tomon bildirishnomalari" + "Ip" + "Mavzu" + "Bu xona nima haqida?" + "Shifrni ochish imkonsiz" + "Takliflarni bir yoki bir nechta foydalanuvchiga yuborib bo‘lmadi." + "Taklif(lar)ni yuborib bo‘lmadi" + "Ovozni yoqish" + "Qo\'llab-quvvatlanmagan hodisa" + "Foydalanuvchi nomi" + "Tasdiqlash bekor qilindi" + "Tasdiqlash yakunlandi" + "Video" + "Ovozli xabar" + "Kutilmoqda…" + "Tasdiqlash" + "Xato" + "Muvaffaqiyat" + "Ogohlantirish" + "Doimiy havola yaratilmadi" + "%1$sxaritani yuklay olmadi. Iltimos keyinroq qayta urinib ko\'ring." + "Xabarlar yuklanmadi" + "%1$sjoylashuvingizga kira olmadi. Iltimos keyinroq qayta urinib ko\'ring." + "%1$sjoylashuvingizga kirishga ruxsati yo\'q. Sozlamalar orqali kirishni yoqishingiz mumkin." + "%1$sjoylashuvingizga kirishga ruxsati yo\'q. Quyida kirishni yoqing." + "Bazi xabarlar yuborilmagan" + "Kechirasiz, xatolik yuz berdi" + "🔐️ Menga qo\'shiling%1$s" + "Hey, men bilan gaplash%1$s :%2$s" + "%1$sAndroid" + "Xato haqida xabar berish uchun G\'azablanish" + "Media tanlash jarayonida xatolik yuz berdi, qayta urinib ko\'ring" + "Mediani yuklab bo‘lmadi, qayta urinib ko‘ring." + "Media yuklanmadi, qayta urinib ko‘ring." + "Mediani yuklab bo‘lmadi, qayta urinib ko‘ring." + "Foydalanuvchi tafsilotlarini olinmadi" + "Bloklash" + "Bloklangan foydalanuvchilar sizga xabar yubora olmaydi va ularning barcha xabarlari yashiriladi. Ularni istalgan vaqtda blokdan chiqarishingiz mumkin." + "Foydalanuvchini bloklash" + "Blokdan chiqarish" + "Ulardan kelgan barcha xabarlarni yana koʻrishingiz mumkin boʻladi." + "Foydalanuvchini blokdan chiqarish" + "Joylashuvni ulashish" + "Joylashuvimni ulashing" + "Apple Mapsda oching" + "Google Mapsda oching" + "OpenStreetMapda oching" + "Bu joylashuvni ulashing" + "Joylashuv" + "Versiya:%1$s (%2$s )" + "en" + diff --git a/libraries/ui-strings/src/main/res/values/localazy.xml b/libraries/ui-strings/src/main/res/values/localazy.xml index c5d8f46622..ef997755dd 100644 --- a/libraries/ui-strings/src/main/res/values/localazy.xml +++ b/libraries/ui-strings/src/main/res/values/localazy.xml @@ -91,6 +91,7 @@ "Report bug" "Report content" "Reset" + "Reset identity" "Retry" "Retry decryption" "Save" @@ -110,6 +111,7 @@ "Take photo" "Tap for options" "Try again" + "Unpin" "View source" "Yes" "About" @@ -258,6 +260,7 @@ Reason: %1$s." "Some messages have not been sent" "Sorry, an error occurred" "The authenticity of this encrypted message can\'t be guaranteed on this device." + "Not encrypted." "Encrypted by an unknown or deleted device." "Encrypted by a device not verified by its owner." "Encrypted by an unverified user." @@ -265,9 +268,29 @@ Reason: %1$s." "Hey, talk to me on %1$s: %2$s" "%1$s Android" "Rageshake to report bug" + "Your account details, contacts, preferences, and chat list will be kept" + "You will lose your existing message history" + "You will need to verify all your existing devices and contacts again" + "Only reset your identity if you don’t have access to another signed-in device and you’ve lost your recovery key." + "If you’re not signed in to any other devices and you’ve lost your recovery key, then you’ll need to reset your identity to continue using the app. " + "Reset your identity in case you can’t confirm another way" "Failed selecting media, please try again." "Failed processing media to upload, please try again." "Failed uploading media, please try again." + "Press on a message and choose “%1$s” to include here." + "Pin important messages so that they can be easily discovered" + + "%1$d Pinned message" + "%1$d Pinned messages" + + "Pinned messages" + "Yes, reset now" + "This process is irreversible." + "Are you sure you want to reset your encryption?" + "Enter…" + "Confirm that you want to reset your encryption." + "Enter your account password to continue" + "Pinned messages" "Failed processing media to upload, please try again." "Could not retrieve user details" "Block" @@ -279,6 +302,7 @@ Reason: %1$s." "Unblock user" "%1$s of %2$s" "%1$s Pinned messages" + "Loading message…" "View All" "Chat" "Share location" diff --git a/plugins/src/main/kotlin/extension/locales.kt b/plugins/src/main/kotlin/extension/locales.kt index 18cd3d5531..fcbfedf852 100644 --- a/plugins/src/main/kotlin/extension/locales.kt +++ b/plugins/src/main/kotlin/extension/locales.kt @@ -24,6 +24,7 @@ val locales = setOf( "sk", "sv", "uk", + "uz", "zh-rCN", "zh-rTW", ) diff --git a/samples/minimal/build.gradle.kts b/samples/minimal/build.gradle.kts index 91cc4bd110..f754b28a4e 100644 --- a/samples/minimal/build.gradle.kts +++ b/samples/minimal/build.gradle.kts @@ -60,6 +60,7 @@ dependencies { implementation(projects.libraries.eventformatter.impl) implementation(projects.libraries.fullscreenintent.impl) implementation(projects.libraries.preferences.impl) + implementation(projects.libraries.preferences.test) implementation(projects.libraries.indicator.impl) implementation(projects.features.invite.impl) implementation(projects.features.roomlist.impl) diff --git a/samples/minimal/src/main/kotlin/io/element/android/samples/minimal/MainActivity.kt b/samples/minimal/src/main/kotlin/io/element/android/samples/minimal/MainActivity.kt index d13cc429dc..cab4c09660 100644 --- a/samples/minimal/src/main/kotlin/io/element/android/samples/minimal/MainActivity.kt +++ b/samples/minimal/src/main/kotlin/io/element/android/samples/minimal/MainActivity.kt @@ -33,6 +33,7 @@ import io.element.android.libraries.matrix.impl.analytics.UtdTracker import io.element.android.libraries.matrix.impl.auth.OidcConfigurationProvider import io.element.android.libraries.matrix.impl.auth.RustMatrixAuthenticationService import io.element.android.libraries.network.useragent.SimpleUserAgentProvider +import io.element.android.libraries.preferences.test.InMemoryAppPreferencesStore import io.element.android.libraries.sessionstorage.api.LoggedInState import io.element.android.libraries.sessionstorage.impl.memory.InMemorySessionStore import io.element.android.services.analytics.noop.NoopAnalyticsService @@ -62,6 +63,7 @@ class MainActivity : ComponentActivity() { proxyProvider = proxyProvider, clock = DefaultSystemClock(), utdTracker = UtdTracker(NoopAnalyticsService()), + appPreferencesStore = InMemoryAppPreferencesStore(), ), passphraseGenerator = NullPassphraseGenerator(), oidcConfigurationProvider = OidcConfigurationProvider(baseDirectory), diff --git a/screenshots/de/features.joinroom.impl_JoinRoomView_Day_1_de.png b/screenshots/de/features.joinroom.impl_JoinRoomView_Day_1_de.png index 1e2a6627e9..147fc99887 100644 --- a/screenshots/de/features.joinroom.impl_JoinRoomView_Day_1_de.png +++ b/screenshots/de/features.joinroom.impl_JoinRoomView_Day_1_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:1e190af91f08cdebf55b8b1567edf71ac652b0501329853708e033d18ad4d805 -size 109003 +oid sha256:7d233e3dedc7fd2e0876243e250c24e2cf5e3bfa7ade8f3615c641e781c04ad0 +size 113116 diff --git a/screenshots/de/features.messages.impl.typing_MessagesViewWithTyping_Day_0_de.png b/screenshots/de/features.messages.impl.typing_MessagesViewWithTyping_Day_0_de.png index b680ac5200..b731d9654c 100644 --- a/screenshots/de/features.messages.impl.typing_MessagesViewWithTyping_Day_0_de.png +++ b/screenshots/de/features.messages.impl.typing_MessagesViewWithTyping_Day_0_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:82cb8a36f3d7dc08104f341c9231b645a1908f902e4badf507581989377159ca -size 53573 +oid sha256:c33d7b5f5c2eb70d8c67f715df11a1dc08f76a5874ec524db3015b56b2e75aaa +size 56141 diff --git a/screenshots/de/features.messages.impl.typing_MessagesViewWithTyping_Day_1_de.png b/screenshots/de/features.messages.impl.typing_MessagesViewWithTyping_Day_1_de.png index d36ff169e1..e52536f976 100644 --- a/screenshots/de/features.messages.impl.typing_MessagesViewWithTyping_Day_1_de.png +++ b/screenshots/de/features.messages.impl.typing_MessagesViewWithTyping_Day_1_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c031ab911290c1ba76faaf449ef9ff75b2a84ec10164ad7be8d6a6036369bcc7 -size 54561 +oid sha256:80a90ae223b2db6ef8cc9a0b52689c6aaa200753ee5efc782e480262e0c006c8 +size 57088 diff --git a/screenshots/de/features.messages.impl_MessagesView_Day_0_de.png b/screenshots/de/features.messages.impl_MessagesView_Day_0_de.png deleted file mode 100644 index 049e5856f0..0000000000 --- a/screenshots/de/features.messages.impl_MessagesView_Day_0_de.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:5fe0f0f74ddcfb738c2b9e713df22db6ef6cba28ac0f885899b83f2b9fde5620 -size 55515 diff --git a/screenshots/de/features.messages.impl_MessagesView_Day_10_de.png b/screenshots/de/features.messages.impl_MessagesView_Day_10_de.png index 119ce31df4..17746c958b 100644 --- a/screenshots/de/features.messages.impl_MessagesView_Day_10_de.png +++ b/screenshots/de/features.messages.impl_MessagesView_Day_10_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:534fafc31674c6ef6f2b8cd36de9d7e6c2b241c8bd1ce96b89b610049e828177 -size 58047 +oid sha256:8eaaf78856243a79ca9a690d5086c7150364628546ede56372fafbbc7f3d67d1 +size 59309 diff --git a/screenshots/de/features.messages.impl_MessagesView_Day_11_de.png b/screenshots/de/features.messages.impl_MessagesView_Day_11_de.png index 8eb6aa0fb2..9ef066335c 100644 --- a/screenshots/de/features.messages.impl_MessagesView_Day_11_de.png +++ b/screenshots/de/features.messages.impl_MessagesView_Day_11_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:81e572a32a20e8c261e9d42a36dc3bcb70d5aa04ef743e8a03a337f1b082a3eb -size 45887 +oid sha256:57e4e00d2044083e4c851fe39a4be5da0fa9d54f535a4b8a47ed67abfb8299cf +size 47084 diff --git a/screenshots/de/features.messages.impl_MessagesView_Day_12_de.png b/screenshots/de/features.messages.impl_MessagesView_Day_12_de.png deleted file mode 100644 index e61b55b743..0000000000 --- a/screenshots/de/features.messages.impl_MessagesView_Day_12_de.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:a580cba9e5b9c210196b961e47733b213fdcb9dff7c2198c86689a0213e76494 -size 55553 diff --git a/screenshots/de/features.messages.impl_MessagesView_Day_3_de.png b/screenshots/de/features.messages.impl_MessagesView_Day_3_de.png index e1534ddfb9..d448b125bb 100644 --- a/screenshots/de/features.messages.impl_MessagesView_Day_3_de.png +++ b/screenshots/de/features.messages.impl_MessagesView_Day_3_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a38ed5dfdf050c8084c8982ff068e1330ac2f3c4f4790678e1508c78214c45bb -size 56773 +oid sha256:ae733c65e0ebe554e6741b48f5b5b2c06fd05e4380b37cdaa827b07349d7951d +size 59978 diff --git a/screenshots/de/features.messages.impl_MessagesView_Day_4_de.png b/screenshots/de/features.messages.impl_MessagesView_Day_4_de.png index a3c82d2c02..20fe3cecf5 100644 --- a/screenshots/de/features.messages.impl_MessagesView_Day_4_de.png +++ b/screenshots/de/features.messages.impl_MessagesView_Day_4_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:fb47deea5a5883aba4428915b00d523e80315bbf1fcecc727f1568b6b925cdde -size 53538 +oid sha256:9a886fb07d1866fc6d0be8ac34cbac05930e98f8a994d666f87c2c9a4b01cb20 +size 54707 diff --git a/screenshots/de/features.messages.impl_MessagesView_Day_5_de.png b/screenshots/de/features.messages.impl_MessagesView_Day_5_de.png deleted file mode 100644 index f2daa47e63..0000000000 --- a/screenshots/de/features.messages.impl_MessagesView_Day_5_de.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:69b89fb9b9a6cac6d39f7c90e5c31500df005b878de60e2311eeb51d42daea90 -size 53339 diff --git a/screenshots/de/features.messages.impl_MessagesView_Day_6_de.png b/screenshots/de/features.messages.impl_MessagesView_Day_6_de.png index 3ae9773013..67b3c9dce1 100644 --- a/screenshots/de/features.messages.impl_MessagesView_Day_6_de.png +++ b/screenshots/de/features.messages.impl_MessagesView_Day_6_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:b76d6e2b03d78d7fe4a863cc8c086f7f09a93b574ee8308a00a92af4f7665e2c -size 53187 +oid sha256:66d6532d4d0ca266c26260ffbdd69f9957743c11f3a5fd2cae118892f119f0b6 +size 53881 diff --git a/screenshots/de/features.messages.impl_MessagesView_Day_7_de.png b/screenshots/de/features.messages.impl_MessagesView_Day_7_de.png index 5ae9252218..3143574e3f 100644 --- a/screenshots/de/features.messages.impl_MessagesView_Day_7_de.png +++ b/screenshots/de/features.messages.impl_MessagesView_Day_7_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:16cc141367a4631a5b5aa17f7373e52b330f87f74b936e58befc0aef79f0468d -size 57582 +oid sha256:290669083f6b2ab605ccd5721f19052fcefacadaeeaaeed79439d9fcd3db14a1 +size 58696 diff --git a/screenshots/de/features.messages.impl_MessagesView_Day_8_de.png b/screenshots/de/features.messages.impl_MessagesView_Day_8_de.png index f057d78f19..0488159920 100644 --- a/screenshots/de/features.messages.impl_MessagesView_Day_8_de.png +++ b/screenshots/de/features.messages.impl_MessagesView_Day_8_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:587551bf2aa184b10f9ccd3c8a4cb2e1173c7d2e18021caa6e23329d8db078ac -size 40331 +oid sha256:6869c19d03e795dcefc8056cdd267d24669ee8893394ab90b3952fccb7847bf4 +size 41557 diff --git a/screenshots/de/features.messages.impl_MessagesView_Day_9_de.png b/screenshots/de/features.messages.impl_MessagesView_Day_9_de.png index c7d3b5b1d7..67e2d5e9e0 100644 --- a/screenshots/de/features.messages.impl_MessagesView_Day_9_de.png +++ b/screenshots/de/features.messages.impl_MessagesView_Day_9_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f9db9c664487feca9f1a9e7a3a2ae2cd19129a9aa4b7fc85f8ea534af21f3adc -size 39591 +oid sha256:bd6b605f377925ca0d0511e9d8a03c83aa00ff1236537577f32c4de0521ef57c +size 40841 diff --git a/screenshots/de/features.preferences.impl.developer_DeveloperSettingsView_Day_0_de.png b/screenshots/de/features.preferences.impl.developer_DeveloperSettingsView_Day_0_de.png index 495ecadf09..8de7a0fc01 100644 --- a/screenshots/de/features.preferences.impl.developer_DeveloperSettingsView_Day_0_de.png +++ b/screenshots/de/features.preferences.impl.developer_DeveloperSettingsView_Day_0_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c52735432835df48912fe46bd060f29b67a4c0f26149d133972f1de3a2a29d10 -size 52410 +oid sha256:9ba32509532bfe046feff840c2cb1d3278690fb89797e4d12710c6d0c708d672 +size 61476 diff --git a/screenshots/de/features.preferences.impl.developer_DeveloperSettingsView_Day_1_de.png b/screenshots/de/features.preferences.impl.developer_DeveloperSettingsView_Day_1_de.png index 495ecadf09..8de7a0fc01 100644 --- a/screenshots/de/features.preferences.impl.developer_DeveloperSettingsView_Day_1_de.png +++ b/screenshots/de/features.preferences.impl.developer_DeveloperSettingsView_Day_1_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c52735432835df48912fe46bd060f29b67a4c0f26149d133972f1de3a2a29d10 -size 52410 +oid sha256:9ba32509532bfe046feff840c2cb1d3278690fb89797e4d12710c6d0c708d672 +size 61476 diff --git a/screenshots/de/features.preferences.impl.developer_DeveloperSettingsView_Day_2_de.png b/screenshots/de/features.preferences.impl.developer_DeveloperSettingsView_Day_2_de.png index 0aafaef26b..dc4b32c96a 100644 --- a/screenshots/de/features.preferences.impl.developer_DeveloperSettingsView_Day_2_de.png +++ b/screenshots/de/features.preferences.impl.developer_DeveloperSettingsView_Day_2_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f2b6105201164499016f4ca00915ae18cbe427416f3c22cd55ea26f7907c8cea -size 50143 +oid sha256:387890a1fc4f01d5ee76d702a69eeb955010c0b8d6f8adc4a5f2879d8ba50837 +size 59229 diff --git a/screenshots/html/data.js b/screenshots/html/data.js index 76259f7913..0545934f70 100644 --- a/screenshots/html/data.js +++ b/screenshots/html/data.js @@ -1,40 +1,40 @@ // Generated file, do not edit export const screenshots = [ ["en","en-dark","de",], -["features.preferences.impl.about_AboutView_Day_0_en","features.preferences.impl.about_AboutView_Night_0_en",19923,], -["features.preferences.impl.about_AboutView_Day_1_en","features.preferences.impl.about_AboutView_Night_1_en",19926,], +["features.preferences.impl.about_AboutView_Day_0_en","features.preferences.impl.about_AboutView_Night_0_en",19944,], +["features.preferences.impl.about_AboutView_Day_1_en","features.preferences.impl.about_AboutView_Night_1_en",19944,], ["features.invite.impl.response_AcceptDeclineInviteView_Day_0_en","features.invite.impl.response_AcceptDeclineInviteView_Night_0_en",0,], -["features.invite.impl.response_AcceptDeclineInviteView_Day_1_en","features.invite.impl.response_AcceptDeclineInviteView_Night_1_en",19923,], -["features.invite.impl.response_AcceptDeclineInviteView_Day_2_en","features.invite.impl.response_AcceptDeclineInviteView_Night_2_en",19923,], -["features.invite.impl.response_AcceptDeclineInviteView_Day_3_en","features.invite.impl.response_AcceptDeclineInviteView_Night_3_en",19923,], -["features.invite.impl.response_AcceptDeclineInviteView_Day_4_en","features.invite.impl.response_AcceptDeclineInviteView_Night_4_en",19923,], +["features.invite.impl.response_AcceptDeclineInviteView_Day_1_en","features.invite.impl.response_AcceptDeclineInviteView_Night_1_en",19944,], +["features.invite.impl.response_AcceptDeclineInviteView_Day_2_en","features.invite.impl.response_AcceptDeclineInviteView_Night_2_en",19944,], +["features.invite.impl.response_AcceptDeclineInviteView_Day_3_en","features.invite.impl.response_AcceptDeclineInviteView_Night_3_en",19944,], +["features.invite.impl.response_AcceptDeclineInviteView_Day_4_en","features.invite.impl.response_AcceptDeclineInviteView_Night_4_en",19944,], ["features.login.impl.accountprovider_AccountProviderView_Day_0_en","features.login.impl.accountprovider_AccountProviderView_Night_0_en",0,], ["features.login.impl.accountprovider_AccountProviderView_Day_1_en","features.login.impl.accountprovider_AccountProviderView_Night_1_en",0,], ["features.login.impl.accountprovider_AccountProviderView_Day_2_en","features.login.impl.accountprovider_AccountProviderView_Night_2_en",0,], ["features.login.impl.accountprovider_AccountProviderView_Day_3_en","features.login.impl.accountprovider_AccountProviderView_Night_3_en",0,], ["features.login.impl.accountprovider_AccountProviderView_Day_4_en","features.login.impl.accountprovider_AccountProviderView_Night_4_en",0,], -["features.createroom.impl.addpeople_AddPeopleView_Day_0_en","features.createroom.impl.addpeople_AddPeopleView_Night_0_en",19923,], -["features.createroom.impl.addpeople_AddPeopleView_Day_1_en","features.createroom.impl.addpeople_AddPeopleView_Night_1_en",19923,], -["features.createroom.impl.addpeople_AddPeopleView_Day_2_en","features.createroom.impl.addpeople_AddPeopleView_Night_2_en",19923,], -["features.createroom.impl.addpeople_AddPeopleView_Day_3_en","features.createroom.impl.addpeople_AddPeopleView_Night_3_en",19923,], -["features.preferences.impl.advanced_AdvancedSettingsView_Day_0_en","features.preferences.impl.advanced_AdvancedSettingsView_Night_0_en",19923,], -["features.preferences.impl.advanced_AdvancedSettingsView_Day_1_en","features.preferences.impl.advanced_AdvancedSettingsView_Night_1_en",19923,], -["features.preferences.impl.advanced_AdvancedSettingsView_Day_2_en","features.preferences.impl.advanced_AdvancedSettingsView_Night_2_en",19923,], -["features.preferences.impl.advanced_AdvancedSettingsView_Day_3_en","features.preferences.impl.advanced_AdvancedSettingsView_Night_3_en",19923,], -["features.analytics.impl_AnalyticsOptInView_Day_0_en","features.analytics.impl_AnalyticsOptInView_Night_0_en",19923,], -["features.analytics.api.preferences_AnalyticsPreferencesView_Day_0_en","features.analytics.api.preferences_AnalyticsPreferencesView_Night_0_en",19923,], -["features.preferences.impl.analytics_AnalyticsSettingsView_Day_0_en","features.preferences.impl.analytics_AnalyticsSettingsView_Night_0_en",19923,], -["services.apperror.impl_AppErrorView_Day_0_en","services.apperror.impl_AppErrorView_Night_0_en",19923,], +["features.createroom.impl.addpeople_AddPeopleView_Day_0_en","features.createroom.impl.addpeople_AddPeopleView_Night_0_en",19944,], +["features.createroom.impl.addpeople_AddPeopleView_Day_1_en","features.createroom.impl.addpeople_AddPeopleView_Night_1_en",19944,], +["features.createroom.impl.addpeople_AddPeopleView_Day_2_en","features.createroom.impl.addpeople_AddPeopleView_Night_2_en",19944,], +["features.createroom.impl.addpeople_AddPeopleView_Day_3_en","features.createroom.impl.addpeople_AddPeopleView_Night_3_en",19944,], +["features.preferences.impl.advanced_AdvancedSettingsView_Day_0_en","features.preferences.impl.advanced_AdvancedSettingsView_Night_0_en",19944,], +["features.preferences.impl.advanced_AdvancedSettingsView_Day_1_en","features.preferences.impl.advanced_AdvancedSettingsView_Night_1_en",19944,], +["features.preferences.impl.advanced_AdvancedSettingsView_Day_2_en","features.preferences.impl.advanced_AdvancedSettingsView_Night_2_en",19944,], +["features.preferences.impl.advanced_AdvancedSettingsView_Day_3_en","features.preferences.impl.advanced_AdvancedSettingsView_Night_3_en",19944,], +["features.analytics.impl_AnalyticsOptInView_Day_0_en","features.analytics.impl_AnalyticsOptInView_Night_0_en",19944,], +["features.analytics.api.preferences_AnalyticsPreferencesView_Day_0_en","features.analytics.api.preferences_AnalyticsPreferencesView_Night_0_en",19944,], +["features.preferences.impl.analytics_AnalyticsSettingsView_Day_0_en","features.preferences.impl.analytics_AnalyticsSettingsView_Night_0_en",19944,], +["services.apperror.impl_AppErrorView_Day_0_en","services.apperror.impl_AppErrorView_Night_0_en",19944,], ["libraries.designsystem.components.async_AsyncActionView_Day_0_en","libraries.designsystem.components.async_AsyncActionView_Night_0_en",0,], -["libraries.designsystem.components.async_AsyncActionView_Day_1_en","libraries.designsystem.components.async_AsyncActionView_Night_1_en",19923,], +["libraries.designsystem.components.async_AsyncActionView_Day_1_en","libraries.designsystem.components.async_AsyncActionView_Night_1_en",19944,], ["libraries.designsystem.components.async_AsyncActionView_Day_2_en","libraries.designsystem.components.async_AsyncActionView_Night_2_en",0,], -["libraries.designsystem.components.async_AsyncActionView_Day_3_en","libraries.designsystem.components.async_AsyncActionView_Night_3_en",19923,], +["libraries.designsystem.components.async_AsyncActionView_Day_3_en","libraries.designsystem.components.async_AsyncActionView_Night_3_en",19944,], ["libraries.designsystem.components.async_AsyncActionView_Day_4_en","libraries.designsystem.components.async_AsyncActionView_Night_4_en",0,], -["libraries.designsystem.components.async_AsyncFailure_Day_0_en","libraries.designsystem.components.async_AsyncFailure_Night_0_en",19923,], +["libraries.designsystem.components.async_AsyncFailure_Day_0_en","libraries.designsystem.components.async_AsyncFailure_Night_0_en",19944,], ["libraries.designsystem.components.async_AsyncIndicatorFailure_Day_0_en","libraries.designsystem.components.async_AsyncIndicatorFailure_Night_0_en",0,], ["libraries.designsystem.components.async_AsyncIndicatorLoading_Day_0_en","libraries.designsystem.components.async_AsyncIndicatorLoading_Night_0_en",0,], ["libraries.designsystem.components.async_AsyncLoading_Day_0_en","libraries.designsystem.components.async_AsyncLoading_Night_0_en",0,], -["features.messages.impl.messagecomposer_AttachmentSourcePickerMenu_Day_0_en","features.messages.impl.messagecomposer_AttachmentSourcePickerMenu_Night_0_en",19923,], +["features.messages.impl.messagecomposer_AttachmentSourcePickerMenu_Day_0_en","features.messages.impl.messagecomposer_AttachmentSourcePickerMenu_Night_0_en",19944,], ["libraries.matrix.ui.components_AttachmentThumbnail_Day_0_en","libraries.matrix.ui.components_AttachmentThumbnail_Night_0_en",0,], ["libraries.matrix.ui.components_AttachmentThumbnail_Day_1_en","libraries.matrix.ui.components_AttachmentThumbnail_Night_1_en",0,], ["libraries.matrix.ui.components_AttachmentThumbnail_Day_2_en","libraries.matrix.ui.components_AttachmentThumbnail_Night_2_en",0,], @@ -44,11 +44,11 @@ export const screenshots = [ ["libraries.matrix.ui.components_AttachmentThumbnail_Day_6_en","libraries.matrix.ui.components_AttachmentThumbnail_Night_6_en",0,], ["libraries.matrix.ui.components_AttachmentThumbnail_Day_7_en","libraries.matrix.ui.components_AttachmentThumbnail_Night_7_en",0,], ["libraries.matrix.ui.components_AttachmentThumbnail_Day_8_en","libraries.matrix.ui.components_AttachmentThumbnail_Night_8_en",0,], -["features.messages.impl.attachments.preview_AttachmentsView_0_en","",19923,], -["features.messages.impl.attachments.preview_AttachmentsView_1_en","",19923,], -["features.messages.impl.attachments.preview_AttachmentsView_2_en","",19923,], -["features.messages.impl.attachments.preview_AttachmentsView_3_en","",19923,], -["libraries.matrix.ui.components_AvatarActionBottomSheet_Day_0_en","libraries.matrix.ui.components_AvatarActionBottomSheet_Night_0_en",19923,], +["features.messages.impl.attachments.preview_AttachmentsView_0_en","",19944,], +["features.messages.impl.attachments.preview_AttachmentsView_1_en","",19944,], +["features.messages.impl.attachments.preview_AttachmentsView_2_en","",19944,], +["features.messages.impl.attachments.preview_AttachmentsView_3_en","",19944,], +["libraries.matrix.ui.components_AvatarActionBottomSheet_Day_0_en","libraries.matrix.ui.components_AvatarActionBottomSheet_Night_0_en",19944,], ["libraries.designsystem.components.avatar_Avatar_Avatars_0_en","",0,], ["libraries.designsystem.components.avatar_Avatar_Avatars_10_en","",0,], ["libraries.designsystem.components.avatar_Avatar_Avatars_11_en","",0,], @@ -128,13 +128,13 @@ export const screenshots = [ ["libraries.designsystem.components_Badge_Day_0_en","libraries.designsystem.components_Badge_Night_0_en",0,], ["libraries.designsystem.components_BigCheckmark_Day_0_en","libraries.designsystem.components_BigCheckmark_Night_0_en",0,], ["libraries.designsystem.components_BigIcon_Day_0_en","libraries.designsystem.components_BigIcon_Night_0_en",0,], -["features.preferences.impl.blockedusers_BlockedUsersView_Day_0_en","features.preferences.impl.blockedusers_BlockedUsersView_Night_0_en",19923,], -["features.preferences.impl.blockedusers_BlockedUsersView_Day_1_en","features.preferences.impl.blockedusers_BlockedUsersView_Night_1_en",19923,], -["features.preferences.impl.blockedusers_BlockedUsersView_Day_2_en","features.preferences.impl.blockedusers_BlockedUsersView_Night_2_en",19923,], -["features.preferences.impl.blockedusers_BlockedUsersView_Day_3_en","features.preferences.impl.blockedusers_BlockedUsersView_Night_3_en",19923,], -["features.preferences.impl.blockedusers_BlockedUsersView_Day_4_en","features.preferences.impl.blockedusers_BlockedUsersView_Night_4_en",19923,], -["features.preferences.impl.blockedusers_BlockedUsersView_Day_5_en","features.preferences.impl.blockedusers_BlockedUsersView_Night_5_en",19923,], -["features.preferences.impl.blockedusers_BlockedUsersView_Day_6_en","features.preferences.impl.blockedusers_BlockedUsersView_Night_6_en",19923,], +["features.preferences.impl.blockedusers_BlockedUsersView_Day_0_en","features.preferences.impl.blockedusers_BlockedUsersView_Night_0_en",19944,], +["features.preferences.impl.blockedusers_BlockedUsersView_Day_1_en","features.preferences.impl.blockedusers_BlockedUsersView_Night_1_en",19944,], +["features.preferences.impl.blockedusers_BlockedUsersView_Day_2_en","features.preferences.impl.blockedusers_BlockedUsersView_Night_2_en",19944,], +["features.preferences.impl.blockedusers_BlockedUsersView_Day_3_en","features.preferences.impl.blockedusers_BlockedUsersView_Night_3_en",19944,], +["features.preferences.impl.blockedusers_BlockedUsersView_Day_4_en","features.preferences.impl.blockedusers_BlockedUsersView_Night_4_en",19944,], +["features.preferences.impl.blockedusers_BlockedUsersView_Day_5_en","features.preferences.impl.blockedusers_BlockedUsersView_Night_5_en",19944,], +["features.preferences.impl.blockedusers_BlockedUsersView_Day_6_en","features.preferences.impl.blockedusers_BlockedUsersView_Night_6_en",19944,], ["libraries.designsystem.components_BloomInitials_Day_0_en","libraries.designsystem.components_BloomInitials_Night_0_en",0,], ["libraries.designsystem.components_BloomInitials_Day_1_en","libraries.designsystem.components_BloomInitials_Night_1_en",0,], ["libraries.designsystem.components_BloomInitials_Day_2_en","libraries.designsystem.components_BloomInitials_Night_2_en",0,], @@ -145,84 +145,84 @@ export const screenshots = [ ["libraries.designsystem.components_BloomInitials_Day_7_en","libraries.designsystem.components_BloomInitials_Night_7_en",0,], ["libraries.designsystem.components_Bloom_Day_0_en","libraries.designsystem.components_Bloom_Night_0_en",0,], ["libraries.designsystem.theme.components_BottomSheetDragHandle_Day_0_en","libraries.designsystem.theme.components_BottomSheetDragHandle_Night_0_en",0,], -["features.rageshake.impl.bugreport_BugReportView_Day_0_en","features.rageshake.impl.bugreport_BugReportView_Night_0_en",19923,], -["features.rageshake.impl.bugreport_BugReportView_Day_1_en","features.rageshake.impl.bugreport_BugReportView_Night_1_en",19923,], -["features.rageshake.impl.bugreport_BugReportView_Day_2_en","features.rageshake.impl.bugreport_BugReportView_Night_2_en",19923,], -["features.rageshake.impl.bugreport_BugReportView_Day_3_en","features.rageshake.impl.bugreport_BugReportView_Night_3_en",19923,], -["features.rageshake.impl.bugreport_BugReportView_Day_4_en","features.rageshake.impl.bugreport_BugReportView_Night_4_en",19923,], +["features.rageshake.impl.bugreport_BugReportView_Day_0_en","features.rageshake.impl.bugreport_BugReportView_Night_0_en",19944,], +["features.rageshake.impl.bugreport_BugReportView_Day_1_en","features.rageshake.impl.bugreport_BugReportView_Night_1_en",19944,], +["features.rageshake.impl.bugreport_BugReportView_Day_2_en","features.rageshake.impl.bugreport_BugReportView_Night_2_en",19944,], +["features.rageshake.impl.bugreport_BugReportView_Day_3_en","features.rageshake.impl.bugreport_BugReportView_Night_3_en",19944,], +["features.rageshake.impl.bugreport_BugReportView_Day_4_en","features.rageshake.impl.bugreport_BugReportView_Night_4_en",19944,], ["libraries.designsystem.atomic.molecules_ButtonColumnMolecule_Day_0_en","libraries.designsystem.atomic.molecules_ButtonColumnMolecule_Night_0_en",0,], ["libraries.designsystem.atomic.molecules_ButtonRowMolecule_Day_0_en","libraries.designsystem.atomic.molecules_ButtonRowMolecule_Night_0_en",0,], ["features.call.impl.ui_CallScreenPipView_Day_0_en","features.call.impl.ui_CallScreenPipView_Night_0_en",0,], ["features.call.impl.ui_CallScreenPipView_Day_1_en","features.call.impl.ui_CallScreenPipView_Night_1_en",0,], ["features.call.impl.ui_CallScreenView_Day_0_en","features.call.impl.ui_CallScreenView_Night_0_en",0,], -["features.call.impl.ui_CallScreenView_Day_1_en","features.call.impl.ui_CallScreenView_Night_1_en",19923,], -["features.call.impl.ui_CallScreenView_Day_2_en","features.call.impl.ui_CallScreenView_Night_2_en",19923,], -["features.login.impl.screens.changeaccountprovider_ChangeAccountProviderView_Day_0_en","features.login.impl.screens.changeaccountprovider_ChangeAccountProviderView_Night_0_en",19923,], -["features.roomdetails.impl.rolesandpermissions.changeroles_ChangeRolesView_Day_0_en","features.roomdetails.impl.rolesandpermissions.changeroles_ChangeRolesView_Night_0_en",19923,], -["features.roomdetails.impl.rolesandpermissions.changeroles_ChangeRolesView_Day_10_en","features.roomdetails.impl.rolesandpermissions.changeroles_ChangeRolesView_Night_10_en",19923,], -["features.roomdetails.impl.rolesandpermissions.changeroles_ChangeRolesView_Day_1_en","features.roomdetails.impl.rolesandpermissions.changeroles_ChangeRolesView_Night_1_en",19923,], -["features.roomdetails.impl.rolesandpermissions.changeroles_ChangeRolesView_Day_2_en","features.roomdetails.impl.rolesandpermissions.changeroles_ChangeRolesView_Night_2_en",19923,], -["features.roomdetails.impl.rolesandpermissions.changeroles_ChangeRolesView_Day_3_en","features.roomdetails.impl.rolesandpermissions.changeroles_ChangeRolesView_Night_3_en",19923,], -["features.roomdetails.impl.rolesandpermissions.changeroles_ChangeRolesView_Day_4_en","features.roomdetails.impl.rolesandpermissions.changeroles_ChangeRolesView_Night_4_en",19923,], -["features.roomdetails.impl.rolesandpermissions.changeroles_ChangeRolesView_Day_5_en","features.roomdetails.impl.rolesandpermissions.changeroles_ChangeRolesView_Night_5_en",19923,], -["features.roomdetails.impl.rolesandpermissions.changeroles_ChangeRolesView_Day_6_en","features.roomdetails.impl.rolesandpermissions.changeroles_ChangeRolesView_Night_6_en",19923,], -["features.roomdetails.impl.rolesandpermissions.changeroles_ChangeRolesView_Day_7_en","features.roomdetails.impl.rolesandpermissions.changeroles_ChangeRolesView_Night_7_en",19923,], -["features.roomdetails.impl.rolesandpermissions.changeroles_ChangeRolesView_Day_8_en","features.roomdetails.impl.rolesandpermissions.changeroles_ChangeRolesView_Night_8_en",19923,], -["features.roomdetails.impl.rolesandpermissions.changeroles_ChangeRolesView_Day_9_en","features.roomdetails.impl.rolesandpermissions.changeroles_ChangeRolesView_Night_9_en",19923,], -["features.roomdetails.impl.rolesandpermissions.permissions_ChangeRoomPermissionsView_Day_0_en","features.roomdetails.impl.rolesandpermissions.permissions_ChangeRoomPermissionsView_Night_0_en",19923,], -["features.roomdetails.impl.rolesandpermissions.permissions_ChangeRoomPermissionsView_Day_1_en","features.roomdetails.impl.rolesandpermissions.permissions_ChangeRoomPermissionsView_Night_1_en",19923,], -["features.roomdetails.impl.rolesandpermissions.permissions_ChangeRoomPermissionsView_Day_2_en","features.roomdetails.impl.rolesandpermissions.permissions_ChangeRoomPermissionsView_Night_2_en",19923,], -["features.roomdetails.impl.rolesandpermissions.permissions_ChangeRoomPermissionsView_Day_3_en","features.roomdetails.impl.rolesandpermissions.permissions_ChangeRoomPermissionsView_Night_3_en",19923,], -["features.roomdetails.impl.rolesandpermissions.permissions_ChangeRoomPermissionsView_Day_4_en","features.roomdetails.impl.rolesandpermissions.permissions_ChangeRoomPermissionsView_Night_4_en",19923,], -["features.roomdetails.impl.rolesandpermissions.permissions_ChangeRoomPermissionsView_Day_5_en","features.roomdetails.impl.rolesandpermissions.permissions_ChangeRoomPermissionsView_Night_5_en",19923,], -["features.roomdetails.impl.rolesandpermissions.permissions_ChangeRoomPermissionsView_Day_6_en","features.roomdetails.impl.rolesandpermissions.permissions_ChangeRoomPermissionsView_Night_6_en",19923,], +["features.call.impl.ui_CallScreenView_Day_1_en","features.call.impl.ui_CallScreenView_Night_1_en",19944,], +["features.call.impl.ui_CallScreenView_Day_2_en","features.call.impl.ui_CallScreenView_Night_2_en",19944,], +["features.login.impl.screens.changeaccountprovider_ChangeAccountProviderView_Day_0_en","features.login.impl.screens.changeaccountprovider_ChangeAccountProviderView_Night_0_en",19944,], +["features.roomdetails.impl.rolesandpermissions.changeroles_ChangeRolesView_Day_0_en","features.roomdetails.impl.rolesandpermissions.changeroles_ChangeRolesView_Night_0_en",19944,], +["features.roomdetails.impl.rolesandpermissions.changeroles_ChangeRolesView_Day_10_en","features.roomdetails.impl.rolesandpermissions.changeroles_ChangeRolesView_Night_10_en",19944,], +["features.roomdetails.impl.rolesandpermissions.changeroles_ChangeRolesView_Day_1_en","features.roomdetails.impl.rolesandpermissions.changeroles_ChangeRolesView_Night_1_en",19944,], +["features.roomdetails.impl.rolesandpermissions.changeroles_ChangeRolesView_Day_2_en","features.roomdetails.impl.rolesandpermissions.changeroles_ChangeRolesView_Night_2_en",19944,], +["features.roomdetails.impl.rolesandpermissions.changeroles_ChangeRolesView_Day_3_en","features.roomdetails.impl.rolesandpermissions.changeroles_ChangeRolesView_Night_3_en",19944,], +["features.roomdetails.impl.rolesandpermissions.changeroles_ChangeRolesView_Day_4_en","features.roomdetails.impl.rolesandpermissions.changeroles_ChangeRolesView_Night_4_en",19944,], +["features.roomdetails.impl.rolesandpermissions.changeroles_ChangeRolesView_Day_5_en","features.roomdetails.impl.rolesandpermissions.changeroles_ChangeRolesView_Night_5_en",19944,], +["features.roomdetails.impl.rolesandpermissions.changeroles_ChangeRolesView_Day_6_en","features.roomdetails.impl.rolesandpermissions.changeroles_ChangeRolesView_Night_6_en",19944,], +["features.roomdetails.impl.rolesandpermissions.changeroles_ChangeRolesView_Day_7_en","features.roomdetails.impl.rolesandpermissions.changeroles_ChangeRolesView_Night_7_en",19944,], +["features.roomdetails.impl.rolesandpermissions.changeroles_ChangeRolesView_Day_8_en","features.roomdetails.impl.rolesandpermissions.changeroles_ChangeRolesView_Night_8_en",19944,], +["features.roomdetails.impl.rolesandpermissions.changeroles_ChangeRolesView_Day_9_en","features.roomdetails.impl.rolesandpermissions.changeroles_ChangeRolesView_Night_9_en",19944,], +["features.roomdetails.impl.rolesandpermissions.permissions_ChangeRoomPermissionsView_Day_0_en","features.roomdetails.impl.rolesandpermissions.permissions_ChangeRoomPermissionsView_Night_0_en",19944,], +["features.roomdetails.impl.rolesandpermissions.permissions_ChangeRoomPermissionsView_Day_1_en","features.roomdetails.impl.rolesandpermissions.permissions_ChangeRoomPermissionsView_Night_1_en",19944,], +["features.roomdetails.impl.rolesandpermissions.permissions_ChangeRoomPermissionsView_Day_2_en","features.roomdetails.impl.rolesandpermissions.permissions_ChangeRoomPermissionsView_Night_2_en",19944,], +["features.roomdetails.impl.rolesandpermissions.permissions_ChangeRoomPermissionsView_Day_3_en","features.roomdetails.impl.rolesandpermissions.permissions_ChangeRoomPermissionsView_Night_3_en",19944,], +["features.roomdetails.impl.rolesandpermissions.permissions_ChangeRoomPermissionsView_Day_4_en","features.roomdetails.impl.rolesandpermissions.permissions_ChangeRoomPermissionsView_Night_4_en",19944,], +["features.roomdetails.impl.rolesandpermissions.permissions_ChangeRoomPermissionsView_Day_5_en","features.roomdetails.impl.rolesandpermissions.permissions_ChangeRoomPermissionsView_Night_5_en",19944,], +["features.roomdetails.impl.rolesandpermissions.permissions_ChangeRoomPermissionsView_Day_6_en","features.roomdetails.impl.rolesandpermissions.permissions_ChangeRoomPermissionsView_Night_6_en",19944,], ["features.login.impl.changeserver_ChangeServerView_Day_0_en","features.login.impl.changeserver_ChangeServerView_Night_0_en",0,], -["features.login.impl.changeserver_ChangeServerView_Day_1_en","features.login.impl.changeserver_ChangeServerView_Night_1_en",19923,], -["features.login.impl.changeserver_ChangeServerView_Day_2_en","features.login.impl.changeserver_ChangeServerView_Night_2_en",19923,], +["features.login.impl.changeserver_ChangeServerView_Day_1_en","features.login.impl.changeserver_ChangeServerView_Night_1_en",19944,], +["features.login.impl.changeserver_ChangeServerView_Day_2_en","features.login.impl.changeserver_ChangeServerView_Night_2_en",19944,], ["libraries.matrix.ui.components_CheckableResolvedUserRow_en","",0,], -["libraries.matrix.ui.components_CheckableUnresolvedUserRow_en","",19923,], +["libraries.matrix.ui.components_CheckableUnresolvedUserRow_en","",19944,], ["libraries.designsystem.theme.components_Checkboxes_Toggles_en","",0,], ["libraries.designsystem.theme.components_CircularProgressIndicator_Progress Indicators_en","",0,], ["libraries.designsystem.components_ClickableLinkText_Text_en","",0,], ["libraries.designsystem.theme_ColorAliases_Day_0_en","libraries.designsystem.theme_ColorAliases_Night_0_en",0,], ["libraries.textcomposer.components_ComposerOptionsButton_Day_0_en","libraries.textcomposer.components_ComposerOptionsButton_Night_0_en",0,], ["libraries.designsystem.components.avatar_CompositeAvatar_Avatars_en","",0,], -["features.createroom.impl.configureroom_ConfigureRoomView_Day_0_en","features.createroom.impl.configureroom_ConfigureRoomView_Night_0_en",19923,], -["features.createroom.impl.configureroom_ConfigureRoomView_Day_1_en","features.createroom.impl.configureroom_ConfigureRoomView_Night_1_en",19923,], +["features.createroom.impl.configureroom_ConfigureRoomView_Day_0_en","features.createroom.impl.configureroom_ConfigureRoomView_Night_0_en",19944,], +["features.createroom.impl.configureroom_ConfigureRoomView_Day_1_en","features.createroom.impl.configureroom_ConfigureRoomView_Night_1_en",19944,], ["features.preferences.impl.developer.tracing_ConfigureTracingView_Day_0_en","features.preferences.impl.developer.tracing_ConfigureTracingView_Night_0_en",0,], -["features.login.impl.screens.confirmaccountprovider_ConfirmAccountProviderView_Day_0_en","features.login.impl.screens.confirmaccountprovider_ConfirmAccountProviderView_Night_0_en",19923,], -["features.roomlist.impl.components_ConfirmRecoveryKeyBanner_Day_0_en","features.roomlist.impl.components_ConfirmRecoveryKeyBanner_Night_0_en",19923,], +["features.login.impl.screens.confirmaccountprovider_ConfirmAccountProviderView_Day_0_en","features.login.impl.screens.confirmaccountprovider_ConfirmAccountProviderView_Night_0_en",19944,], +["features.roomlist.impl.components_ConfirmRecoveryKeyBanner_Day_0_en","features.roomlist.impl.components_ConfirmRecoveryKeyBanner_Night_0_en",19944,], ["libraries.designsystem.components.dialogs_ConfirmationDialogContent_Dialogs_en","",0,], ["libraries.designsystem.components.dialogs_ConfirmationDialog_Day_0_en","libraries.designsystem.components.dialogs_ConfirmationDialog_Night_0_en",0,], ["features.networkmonitor.api.ui_ConnectivityIndicatorView_Day_0_en","features.networkmonitor.api.ui_ConnectivityIndicatorView_Night_0_en",0,], -["features.rageshake.api.crash_CrashDetectionView_Day_0_en","features.rageshake.api.crash_CrashDetectionView_Night_0_en",19923,], -["features.securebackup.impl.createkey_CreateNewRecoveryKeyView_Day_0_en","features.securebackup.impl.createkey_CreateNewRecoveryKeyView_Night_0_en",19923,], -["features.poll.impl.create_CreatePollView_Day_0_en","features.poll.impl.create_CreatePollView_Night_0_en",19923,], -["features.poll.impl.create_CreatePollView_Day_1_en","features.poll.impl.create_CreatePollView_Night_1_en",19923,], -["features.poll.impl.create_CreatePollView_Day_2_en","features.poll.impl.create_CreatePollView_Night_2_en",19923,], -["features.poll.impl.create_CreatePollView_Day_3_en","features.poll.impl.create_CreatePollView_Night_3_en",19923,], -["features.poll.impl.create_CreatePollView_Day_4_en","features.poll.impl.create_CreatePollView_Night_4_en",19923,], -["features.poll.impl.create_CreatePollView_Day_5_en","features.poll.impl.create_CreatePollView_Night_5_en",19923,], -["features.poll.impl.create_CreatePollView_Day_6_en","features.poll.impl.create_CreatePollView_Night_6_en",19923,], -["features.poll.impl.create_CreatePollView_Day_7_en","features.poll.impl.create_CreatePollView_Night_7_en",19923,], -["features.createroom.impl.root_CreateRoomRootView_Day_0_en","features.createroom.impl.root_CreateRoomRootView_Night_0_en",19923,], -["features.createroom.impl.root_CreateRoomRootView_Day_1_en","features.createroom.impl.root_CreateRoomRootView_Night_1_en",19923,], -["features.createroom.impl.root_CreateRoomRootView_Day_2_en","features.createroom.impl.root_CreateRoomRootView_Night_2_en",19923,], -["features.createroom.impl.root_CreateRoomRootView_Day_3_en","features.createroom.impl.root_CreateRoomRootView_Night_3_en",19923,], -["libraries.designsystem.theme.components.previews_DatePickerDark_DateTime pickers_en","",19923,], -["libraries.designsystem.theme.components.previews_DatePickerLight_DateTime pickers_en","",19923,], +["features.rageshake.api.crash_CrashDetectionView_Day_0_en","features.rageshake.api.crash_CrashDetectionView_Night_0_en",19944,], +["features.securebackup.impl.createkey_CreateNewRecoveryKeyView_Day_0_en","features.securebackup.impl.createkey_CreateNewRecoveryKeyView_Night_0_en",19944,], +["features.poll.impl.create_CreatePollView_Day_0_en","features.poll.impl.create_CreatePollView_Night_0_en",19944,], +["features.poll.impl.create_CreatePollView_Day_1_en","features.poll.impl.create_CreatePollView_Night_1_en",19944,], +["features.poll.impl.create_CreatePollView_Day_2_en","features.poll.impl.create_CreatePollView_Night_2_en",19944,], +["features.poll.impl.create_CreatePollView_Day_3_en","features.poll.impl.create_CreatePollView_Night_3_en",19944,], +["features.poll.impl.create_CreatePollView_Day_4_en","features.poll.impl.create_CreatePollView_Night_4_en",19944,], +["features.poll.impl.create_CreatePollView_Day_5_en","features.poll.impl.create_CreatePollView_Night_5_en",19944,], +["features.poll.impl.create_CreatePollView_Day_6_en","features.poll.impl.create_CreatePollView_Night_6_en",19944,], +["features.poll.impl.create_CreatePollView_Day_7_en","features.poll.impl.create_CreatePollView_Night_7_en",19944,], +["features.createroom.impl.root_CreateRoomRootView_Day_0_en","features.createroom.impl.root_CreateRoomRootView_Night_0_en",19944,], +["features.createroom.impl.root_CreateRoomRootView_Day_1_en","features.createroom.impl.root_CreateRoomRootView_Night_1_en",19944,], +["features.createroom.impl.root_CreateRoomRootView_Day_2_en","features.createroom.impl.root_CreateRoomRootView_Night_2_en",19944,], +["features.createroom.impl.root_CreateRoomRootView_Day_3_en","features.createroom.impl.root_CreateRoomRootView_Night_3_en",19944,], +["libraries.designsystem.theme.components.previews_DatePickerDark_DateTime pickers_en","",19944,], +["libraries.designsystem.theme.components.previews_DatePickerLight_DateTime pickers_en","",19944,], ["features.logout.impl.direct_DefaultDirectLogoutView_Day_0_en","features.logout.impl.direct_DefaultDirectLogoutView_Night_0_en",0,], -["features.logout.impl.direct_DefaultDirectLogoutView_Day_1_en","features.logout.impl.direct_DefaultDirectLogoutView_Night_1_en",19923,], -["features.logout.impl.direct_DefaultDirectLogoutView_Day_2_en","features.logout.impl.direct_DefaultDirectLogoutView_Night_2_en",19923,], -["features.logout.impl.direct_DefaultDirectLogoutView_Day_3_en","features.logout.impl.direct_DefaultDirectLogoutView_Night_3_en",19923,], +["features.logout.impl.direct_DefaultDirectLogoutView_Day_1_en","features.logout.impl.direct_DefaultDirectLogoutView_Night_1_en",19944,], +["features.logout.impl.direct_DefaultDirectLogoutView_Day_2_en","features.logout.impl.direct_DefaultDirectLogoutView_Night_2_en",19944,], +["features.logout.impl.direct_DefaultDirectLogoutView_Day_3_en","features.logout.impl.direct_DefaultDirectLogoutView_Night_3_en",19944,], ["features.logout.impl.direct_DefaultDirectLogoutView_Day_4_en","features.logout.impl.direct_DefaultDirectLogoutView_Night_4_en",0,], -["features.preferences.impl.notifications.edit_DefaultNotificationSettingOption_Day_0_en","features.preferences.impl.notifications.edit_DefaultNotificationSettingOption_Night_0_en",19923,], -["features.roomlist.impl.components_DefaultRoomListTopBarWithIndicator_Day_0_en","features.roomlist.impl.components_DefaultRoomListTopBarWithIndicator_Night_0_en",19923,], -["features.roomlist.impl.components_DefaultRoomListTopBar_Day_0_en","features.roomlist.impl.components_DefaultRoomListTopBar_Night_0_en",19923,], -["features.preferences.impl.developer_DeveloperSettingsView_Day_0_en","features.preferences.impl.developer_DeveloperSettingsView_Night_0_en",19923,], -["features.preferences.impl.developer_DeveloperSettingsView_Day_1_en","features.preferences.impl.developer_DeveloperSettingsView_Night_1_en",19923,], -["features.preferences.impl.developer_DeveloperSettingsView_Day_2_en","features.preferences.impl.developer_DeveloperSettingsView_Night_2_en",19923,], -["libraries.designsystem.atomic.molecules_DialogLikeBannerMolecule_Day_0_en","libraries.designsystem.atomic.molecules_DialogLikeBannerMolecule_Night_0_en",19923,], +["features.preferences.impl.notifications.edit_DefaultNotificationSettingOption_Day_0_en","features.preferences.impl.notifications.edit_DefaultNotificationSettingOption_Night_0_en",19944,], +["features.roomlist.impl.components_DefaultRoomListTopBarWithIndicator_Day_0_en","features.roomlist.impl.components_DefaultRoomListTopBarWithIndicator_Night_0_en",19944,], +["features.roomlist.impl.components_DefaultRoomListTopBar_Day_0_en","features.roomlist.impl.components_DefaultRoomListTopBar_Night_0_en",19944,], +["features.preferences.impl.developer_DeveloperSettingsView_Day_0_en","features.preferences.impl.developer_DeveloperSettingsView_Night_0_en",19944,], +["features.preferences.impl.developer_DeveloperSettingsView_Day_1_en","features.preferences.impl.developer_DeveloperSettingsView_Night_1_en",19944,], +["features.preferences.impl.developer_DeveloperSettingsView_Day_2_en","features.preferences.impl.developer_DeveloperSettingsView_Night_2_en",19944,], +["libraries.designsystem.atomic.molecules_DialogLikeBannerMolecule_Day_0_en","libraries.designsystem.atomic.molecules_DialogLikeBannerMolecule_Night_0_en",19944,], ["libraries.designsystem.theme.components_DialogWithDestructiveButton_Dialog with destructive button_Dialogs_en","",0,], ["libraries.designsystem.theme.components_DialogWithOnlyMessageAndOkButton_Dialog with only message and ok button_Dialogs_en","",0,], ["libraries.designsystem.theme.components_DialogWithThirdButton_Dialog with third button_Dialogs_en","",0,], @@ -234,12 +234,12 @@ export const screenshots = [ ["libraries.designsystem.text_DpScale_1_0f__en","",0,], ["libraries.designsystem.text_DpScale_1_5f__en","",0,], ["libraries.designsystem.theme.components_DropdownMenuItem_Menus_en","",0,], -["features.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_Day_0_en","features.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_Night_0_en",19923,], -["features.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_Day_1_en","features.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_Night_1_en",19923,], -["features.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_Day_2_en","features.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_Night_2_en",19923,], -["features.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_Day_3_en","features.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_Night_3_en",19923,], -["features.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_Day_4_en","features.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_Night_4_en",19923,], -["features.preferences.impl.user.editprofile_EditUserProfileView_Day_0_en","features.preferences.impl.user.editprofile_EditUserProfileView_Night_0_en",19923,], +["features.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_Day_0_en","features.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_Night_0_en",19944,], +["features.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_Day_1_en","features.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_Night_1_en",19944,], +["features.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_Day_2_en","features.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_Night_2_en",19944,], +["features.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_Day_3_en","features.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_Night_3_en",19944,], +["features.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_Day_4_en","features.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_Night_4_en",19944,], +["features.preferences.impl.user.editprofile_EditUserProfileView_Day_0_en","features.preferences.impl.user.editprofile_EditUserProfileView_Night_0_en",19944,], ["libraries.matrix.ui.components_EditableAvatarView_Day_0_en","libraries.matrix.ui.components_EditableAvatarView_Night_0_en",0,], ["libraries.matrix.ui.components_EditableAvatarView_Day_1_en","libraries.matrix.ui.components_EditableAvatarView_Night_1_en",0,], ["libraries.matrix.ui.components_EditableAvatarView_Day_2_en","libraries.matrix.ui.components_EditableAvatarView_Night_2_en",0,], @@ -249,10 +249,10 @@ export const screenshots = [ ["libraries.designsystem.atomic.atoms_ElementLogoAtomMedium_Day_0_en","libraries.designsystem.atomic.atoms_ElementLogoAtomMedium_Night_0_en",0,], ["features.messages.impl.timeline.components.customreaction_EmojiItem_Day_0_en","features.messages.impl.timeline.components.customreaction_EmojiItem_Night_0_en",0,], ["features.messages.impl.timeline.components.customreaction_EmojiPicker_Day_0_en","features.messages.impl.timeline.components.customreaction_EmojiPicker_Night_0_en",0,], -["features.messages.impl.timeline.components.virtual_EncryptedHistoryBannerView_Day_0_en","features.messages.impl.timeline.components.virtual_EncryptedHistoryBannerView_Night_0_en",19923,], -["libraries.designsystem.components.dialogs_ErrorDialogContent_Dialogs_en","",19923,], -["libraries.designsystem.components.dialogs_ErrorDialogWithDoNotShowAgain_Day_0_en","libraries.designsystem.components.dialogs_ErrorDialogWithDoNotShowAgain_Night_0_en",19923,], -["libraries.designsystem.components.dialogs_ErrorDialog_Day_0_en","libraries.designsystem.components.dialogs_ErrorDialog_Night_0_en",19923,], +["features.messages.impl.timeline.components.virtual_EncryptedHistoryBannerView_Day_0_en","features.messages.impl.timeline.components.virtual_EncryptedHistoryBannerView_Night_0_en",19944,], +["libraries.designsystem.components.dialogs_ErrorDialogContent_Dialogs_en","",19944,], +["libraries.designsystem.components.dialogs_ErrorDialogWithDoNotShowAgain_Day_0_en","libraries.designsystem.components.dialogs_ErrorDialogWithDoNotShowAgain_Night_0_en",19944,], +["libraries.designsystem.components.dialogs_ErrorDialog_Day_0_en","libraries.designsystem.components.dialogs_ErrorDialog_Night_0_en",19944,], ["features.messages.impl.timeline.debug_EventDebugInfoView_Day_0_en","features.messages.impl.timeline.debug_EventDebugInfoView_Night_0_en",0,], ["libraries.featureflag.ui_FeatureListView_Day_0_en","libraries.featureflag.ui_FeatureListView_Night_0_en",0,], ["libraries.designsystem.theme.components_FilledButtonLargeLowPadding_Buttons_en","",0,], @@ -263,15 +263,15 @@ export const screenshots = [ ["libraries.designsystem.theme.components_FloatingActionButton_Floating Action Buttons_en","",0,], ["libraries.designsystem.atomic.pages_FlowStepPage_Day_0_en","libraries.designsystem.atomic.pages_FlowStepPage_Night_0_en",0,], ["features.messages.impl.timeline.focus_FocusRequestStateView_Day_0_en","features.messages.impl.timeline.focus_FocusRequestStateView_Night_0_en",0,], -["features.messages.impl.timeline.focus_FocusRequestStateView_Day_1_en","features.messages.impl.timeline.focus_FocusRequestStateView_Night_1_en",19923,], -["features.messages.impl.timeline.focus_FocusRequestStateView_Day_2_en","features.messages.impl.timeline.focus_FocusRequestStateView_Night_2_en",19923,], -["features.messages.impl.timeline.focus_FocusRequestStateView_Day_3_en","features.messages.impl.timeline.focus_FocusRequestStateView_Night_3_en",19923,], +["features.messages.impl.timeline.focus_FocusRequestStateView_Day_1_en","features.messages.impl.timeline.focus_FocusRequestStateView_Night_1_en",19944,], +["features.messages.impl.timeline.focus_FocusRequestStateView_Day_2_en","features.messages.impl.timeline.focus_FocusRequestStateView_Night_2_en",19944,], +["features.messages.impl.timeline.focus_FocusRequestStateView_Day_3_en","features.messages.impl.timeline.focus_FocusRequestStateView_Night_3_en",19944,], ["libraries.textcomposer.components_FormattingOption_Day_0_en","libraries.textcomposer.components_FormattingOption_Night_0_en",0,], ["features.messages.impl.forward_ForwardMessagesView_Day_0_en","features.messages.impl.forward_ForwardMessagesView_Night_0_en",0,], ["features.messages.impl.forward_ForwardMessagesView_Day_1_en","features.messages.impl.forward_ForwardMessagesView_Night_1_en",0,], ["features.messages.impl.forward_ForwardMessagesView_Day_2_en","features.messages.impl.forward_ForwardMessagesView_Night_2_en",0,], -["features.messages.impl.forward_ForwardMessagesView_Day_3_en","features.messages.impl.forward_ForwardMessagesView_Night_3_en",19923,], -["features.roomlist.impl.components_FullScreenIntentPermissionBanner_Day_0_en","features.roomlist.impl.components_FullScreenIntentPermissionBanner_Night_0_en",19923,], +["features.messages.impl.forward_ForwardMessagesView_Day_3_en","features.messages.impl.forward_ForwardMessagesView_Night_3_en",19944,], +["features.roomlist.impl.components_FullScreenIntentPermissionBanner_Day_0_en","features.roomlist.impl.components_FullScreenIntentPermissionBanner_Night_0_en",19944,], ["libraries.designsystem.components.button_GradientFloatingActionButtonCircleShape_Day_0_en","libraries.designsystem.components.button_GradientFloatingActionButtonCircleShape_Night_0_en",0,], ["libraries.designsystem.components.button_GradientFloatingActionButton_Day_0_en","libraries.designsystem.components.button_GradientFloatingActionButton_Night_0_en",0,], ["features.messages.impl.timeline.components.group_GroupHeaderView_Day_0_en","features.messages.impl.timeline.components.group_GroupHeaderView_Night_0_en",0,], @@ -284,8 +284,8 @@ export const screenshots = [ ["libraries.designsystem.atomic.molecules_IconTitleSubtitleMoleculeWithResIcon_Day_0_en","libraries.designsystem.atomic.molecules_IconTitleSubtitleMoleculeWithResIcon_Night_0_en",0,], ["libraries.designsystem.atomic.molecules_IconTitleSubtitleMolecule_Day_0_en","libraries.designsystem.atomic.molecules_IconTitleSubtitleMolecule_Night_0_en",0,], ["libraries.designsystem.theme.components_IconToggleButton_Toggles_en","",0,], -["appicon.enterprise_Icon_en","",0,], ["appicon.element_Icon_en","",0,], +["appicon.enterprise_Icon_en","",0,], ["libraries.designsystem.icons_IconsCompound_Day_0_en","libraries.designsystem.icons_IconsCompound_Night_0_en",0,], ["libraries.designsystem.icons_IconsCompound_Day_1_en","libraries.designsystem.icons_IconsCompound_Night_1_en",0,], ["libraries.designsystem.icons_IconsCompound_Day_2_en","libraries.designsystem.icons_IconsCompound_Night_2_en",0,], @@ -298,37 +298,37 @@ export const screenshots = [ ["libraries.matrix.ui.messages.reply_InReplyToView_Day_1_en","libraries.matrix.ui.messages.reply_InReplyToView_Night_1_en",0,], ["libraries.matrix.ui.messages.reply_InReplyToView_Day_2_en","libraries.matrix.ui.messages.reply_InReplyToView_Night_2_en",0,], ["libraries.matrix.ui.messages.reply_InReplyToView_Day_3_en","libraries.matrix.ui.messages.reply_InReplyToView_Night_3_en",0,], -["libraries.matrix.ui.messages.reply_InReplyToView_Day_4_en","libraries.matrix.ui.messages.reply_InReplyToView_Night_4_en",19923,], +["libraries.matrix.ui.messages.reply_InReplyToView_Day_4_en","libraries.matrix.ui.messages.reply_InReplyToView_Night_4_en",19944,], ["libraries.matrix.ui.messages.reply_InReplyToView_Day_5_en","libraries.matrix.ui.messages.reply_InReplyToView_Night_5_en",0,], ["libraries.matrix.ui.messages.reply_InReplyToView_Day_6_en","libraries.matrix.ui.messages.reply_InReplyToView_Night_6_en",0,], ["libraries.matrix.ui.messages.reply_InReplyToView_Day_7_en","libraries.matrix.ui.messages.reply_InReplyToView_Night_7_en",0,], -["libraries.matrix.ui.messages.reply_InReplyToView_Day_8_en","libraries.matrix.ui.messages.reply_InReplyToView_Night_8_en",19923,], +["libraries.matrix.ui.messages.reply_InReplyToView_Day_8_en","libraries.matrix.ui.messages.reply_InReplyToView_Night_8_en",19944,], ["libraries.matrix.ui.messages.reply_InReplyToView_Day_9_en","libraries.matrix.ui.messages.reply_InReplyToView_Night_9_en",0,], -["features.call.impl.ui_IncomingCallScreen_Day_0_en","features.call.impl.ui_IncomingCallScreen_Night_0_en",19923,], +["features.call.impl.ui_IncomingCallScreen_Day_0_en","features.call.impl.ui_IncomingCallScreen_Night_0_en",19944,], ["libraries.designsystem.atomic.molecules_InfoListItemMolecule_Day_0_en","libraries.designsystem.atomic.molecules_InfoListItemMolecule_Night_0_en",0,], ["libraries.designsystem.atomic.organisms_InfoListOrganism_Day_0_en","libraries.designsystem.atomic.organisms_InfoListOrganism_Night_0_en",0,], -["libraries.matrix.ui.components_InviteSenderView_Day_0_en","libraries.matrix.ui.components_InviteSenderView_Night_0_en",19923,], +["libraries.matrix.ui.components_InviteSenderView_Day_0_en","libraries.matrix.ui.components_InviteSenderView_Night_0_en",19944,], ["features.joinroom.impl_JoinRoomView_Day_0_en","features.joinroom.impl_JoinRoomView_Night_0_en",0,], ["features.joinroom.impl_JoinRoomView_Day_10_en","features.joinroom.impl_JoinRoomView_Night_10_en",0,], -["features.joinroom.impl_JoinRoomView_Day_1_en","features.joinroom.impl_JoinRoomView_Night_1_en",19923,], -["features.joinroom.impl_JoinRoomView_Day_2_en","features.joinroom.impl_JoinRoomView_Night_2_en",19923,], -["features.joinroom.impl_JoinRoomView_Day_3_en","features.joinroom.impl_JoinRoomView_Night_3_en",19923,], -["features.joinroom.impl_JoinRoomView_Day_4_en","features.joinroom.impl_JoinRoomView_Night_4_en",19923,], -["features.joinroom.impl_JoinRoomView_Day_5_en","features.joinroom.impl_JoinRoomView_Night_5_en",19923,], -["features.joinroom.impl_JoinRoomView_Day_6_en","features.joinroom.impl_JoinRoomView_Night_6_en",19923,], -["features.joinroom.impl_JoinRoomView_Day_7_en","features.joinroom.impl_JoinRoomView_Night_7_en",19923,], -["features.joinroom.impl_JoinRoomView_Day_8_en","features.joinroom.impl_JoinRoomView_Night_8_en",19923,], -["features.joinroom.impl_JoinRoomView_Day_9_en","features.joinroom.impl_JoinRoomView_Night_9_en",19923,], +["features.joinroom.impl_JoinRoomView_Day_1_en","features.joinroom.impl_JoinRoomView_Night_1_en",19944,], +["features.joinroom.impl_JoinRoomView_Day_2_en","features.joinroom.impl_JoinRoomView_Night_2_en",19944,], +["features.joinroom.impl_JoinRoomView_Day_3_en","features.joinroom.impl_JoinRoomView_Night_3_en",19944,], +["features.joinroom.impl_JoinRoomView_Day_4_en","features.joinroom.impl_JoinRoomView_Night_4_en",19944,], +["features.joinroom.impl_JoinRoomView_Day_5_en","features.joinroom.impl_JoinRoomView_Night_5_en",19944,], +["features.joinroom.impl_JoinRoomView_Day_6_en","features.joinroom.impl_JoinRoomView_Night_6_en",19944,], +["features.joinroom.impl_JoinRoomView_Day_7_en","features.joinroom.impl_JoinRoomView_Night_7_en",19944,], +["features.joinroom.impl_JoinRoomView_Day_8_en","features.joinroom.impl_JoinRoomView_Night_8_en",19944,], +["features.joinroom.impl_JoinRoomView_Day_9_en","features.joinroom.impl_JoinRoomView_Night_9_en",19944,], ["libraries.designsystem.components_LabelledCheckbox_Toggles_en","",0,], ["libraries.designsystem.components_LabelledOutlinedTextField_Day_0_en","libraries.designsystem.components_LabelledOutlinedTextField_Night_0_en",0,], ["libraries.designsystem.components_LabelledTextField_Day_0_en","libraries.designsystem.components_LabelledTextField_Night_0_en",0,], ["features.leaveroom.api_LeaveRoomView_Day_0_en","features.leaveroom.api_LeaveRoomView_Night_0_en",0,], -["features.leaveroom.api_LeaveRoomView_Day_1_en","features.leaveroom.api_LeaveRoomView_Night_1_en",19923,], -["features.leaveroom.api_LeaveRoomView_Day_2_en","features.leaveroom.api_LeaveRoomView_Night_2_en",19923,], -["features.leaveroom.api_LeaveRoomView_Day_3_en","features.leaveroom.api_LeaveRoomView_Night_3_en",19923,], -["features.leaveroom.api_LeaveRoomView_Day_4_en","features.leaveroom.api_LeaveRoomView_Night_4_en",19923,], -["features.leaveroom.api_LeaveRoomView_Day_5_en","features.leaveroom.api_LeaveRoomView_Night_5_en",19923,], -["features.leaveroom.api_LeaveRoomView_Day_6_en","features.leaveroom.api_LeaveRoomView_Night_6_en",19923,], +["features.leaveroom.api_LeaveRoomView_Day_1_en","features.leaveroom.api_LeaveRoomView_Night_1_en",19944,], +["features.leaveroom.api_LeaveRoomView_Day_2_en","features.leaveroom.api_LeaveRoomView_Night_2_en",19944,], +["features.leaveroom.api_LeaveRoomView_Day_3_en","features.leaveroom.api_LeaveRoomView_Night_3_en",19944,], +["features.leaveroom.api_LeaveRoomView_Day_4_en","features.leaveroom.api_LeaveRoomView_Night_4_en",19944,], +["features.leaveroom.api_LeaveRoomView_Day_5_en","features.leaveroom.api_LeaveRoomView_Night_5_en",19944,], +["features.leaveroom.api_LeaveRoomView_Day_6_en","features.leaveroom.api_LeaveRoomView_Night_6_en",19944,], ["libraries.designsystem.background_LightGradientBackground_Day_0_en","libraries.designsystem.background_LightGradientBackground_Night_0_en",0,], ["libraries.designsystem.theme.components_LinearProgressIndicator_Progress Indicators_en","",0,], ["libraries.designsystem.components.dialogs_ListDialogContent_Dialogs_en","",0,], @@ -379,28 +379,28 @@ export const screenshots = [ ["libraries.designsystem.theme.components_ListSupportingTextSmallPadding_List supporting text - small padding_List sections_en","",0,], ["libraries.textcomposer.components_LiveWaveformView_Day_0_en","libraries.textcomposer.components_LiveWaveformView_Night_0_en",0,], ["appnav.room.joined_LoadingRoomNodeView_Day_0_en","appnav.room.joined_LoadingRoomNodeView_Night_0_en",0,], -["appnav.room.joined_LoadingRoomNodeView_Day_1_en","appnav.room.joined_LoadingRoomNodeView_Night_1_en",19923,], -["features.lockscreen.impl.settings_LockScreenSettingsView_Day_0_en","features.lockscreen.impl.settings_LockScreenSettingsView_Night_0_en",19923,], -["features.lockscreen.impl.settings_LockScreenSettingsView_Day_1_en","features.lockscreen.impl.settings_LockScreenSettingsView_Night_1_en",19923,], -["features.lockscreen.impl.settings_LockScreenSettingsView_Day_2_en","features.lockscreen.impl.settings_LockScreenSettingsView_Night_2_en",19923,], +["appnav.room.joined_LoadingRoomNodeView_Day_1_en","appnav.room.joined_LoadingRoomNodeView_Night_1_en",19944,], +["features.lockscreen.impl.settings_LockScreenSettingsView_Day_0_en","features.lockscreen.impl.settings_LockScreenSettingsView_Night_0_en",19944,], +["features.lockscreen.impl.settings_LockScreenSettingsView_Day_1_en","features.lockscreen.impl.settings_LockScreenSettingsView_Night_1_en",19944,], +["features.lockscreen.impl.settings_LockScreenSettingsView_Day_2_en","features.lockscreen.impl.settings_LockScreenSettingsView_Night_2_en",19944,], ["appnav.loggedin_LoggedInView_Day_0_en","appnav.loggedin_LoggedInView_Night_0_en",0,], -["appnav.loggedin_LoggedInView_Day_1_en","appnav.loggedin_LoggedInView_Night_1_en",19923,], -["appnav.loggedin_LoggedInView_Day_2_en","appnav.loggedin_LoggedInView_Night_2_en",19923,], -["features.login.impl.screens.loginpassword_LoginPasswordView_Day_0_en","features.login.impl.screens.loginpassword_LoginPasswordView_Night_0_en",19923,], -["features.login.impl.screens.loginpassword_LoginPasswordView_Day_1_en","features.login.impl.screens.loginpassword_LoginPasswordView_Night_1_en",19923,], -["features.login.impl.screens.loginpassword_LoginPasswordView_Day_2_en","features.login.impl.screens.loginpassword_LoginPasswordView_Night_2_en",19923,], -["features.logout.impl_LogoutView_Day_0_en","features.logout.impl_LogoutView_Night_0_en",19923,], -["features.logout.impl_LogoutView_Day_1_en","features.logout.impl_LogoutView_Night_1_en",19923,], -["features.logout.impl_LogoutView_Day_2_en","features.logout.impl_LogoutView_Night_2_en",19923,], -["features.logout.impl_LogoutView_Day_3_en","features.logout.impl_LogoutView_Night_3_en",19923,], -["features.logout.impl_LogoutView_Day_4_en","features.logout.impl_LogoutView_Night_4_en",19923,], -["features.logout.impl_LogoutView_Day_5_en","features.logout.impl_LogoutView_Night_5_en",19923,], -["features.logout.impl_LogoutView_Day_6_en","features.logout.impl_LogoutView_Night_6_en",19923,], -["features.logout.impl_LogoutView_Day_7_en","features.logout.impl_LogoutView_Night_7_en",19923,], -["features.logout.impl_LogoutView_Day_8_en","features.logout.impl_LogoutView_Night_8_en",19923,], -["features.logout.impl_LogoutView_Day_9_en","features.logout.impl_LogoutView_Night_9_en",19923,], +["appnav.loggedin_LoggedInView_Day_1_en","appnav.loggedin_LoggedInView_Night_1_en",19944,], +["appnav.loggedin_LoggedInView_Day_2_en","appnav.loggedin_LoggedInView_Night_2_en",19944,], +["features.login.impl.screens.loginpassword_LoginPasswordView_Day_0_en","features.login.impl.screens.loginpassword_LoginPasswordView_Night_0_en",19944,], +["features.login.impl.screens.loginpassword_LoginPasswordView_Day_1_en","features.login.impl.screens.loginpassword_LoginPasswordView_Night_1_en",19944,], +["features.login.impl.screens.loginpassword_LoginPasswordView_Day_2_en","features.login.impl.screens.loginpassword_LoginPasswordView_Night_2_en",19944,], +["features.logout.impl_LogoutView_Day_0_en","features.logout.impl_LogoutView_Night_0_en",19944,], +["features.logout.impl_LogoutView_Day_1_en","features.logout.impl_LogoutView_Night_1_en",19944,], +["features.logout.impl_LogoutView_Day_2_en","features.logout.impl_LogoutView_Night_2_en",19944,], +["features.logout.impl_LogoutView_Day_3_en","features.logout.impl_LogoutView_Night_3_en",19944,], +["features.logout.impl_LogoutView_Day_4_en","features.logout.impl_LogoutView_Night_4_en",19944,], +["features.logout.impl_LogoutView_Day_5_en","features.logout.impl_LogoutView_Night_5_en",19944,], +["features.logout.impl_LogoutView_Day_6_en","features.logout.impl_LogoutView_Night_6_en",19944,], +["features.logout.impl_LogoutView_Day_7_en","features.logout.impl_LogoutView_Night_7_en",19944,], +["features.logout.impl_LogoutView_Day_8_en","features.logout.impl_LogoutView_Night_8_en",19944,], +["features.logout.impl_LogoutView_Day_9_en","features.logout.impl_LogoutView_Night_9_en",19944,], ["libraries.designsystem.components.button_MainActionButton_Buttons_en","",0,], -["libraries.textcomposer_MarkdownTextComposerEdit_Day_0_en","libraries.textcomposer_MarkdownTextComposerEdit_Night_0_en",19923,], +["libraries.textcomposer_MarkdownTextComposerEdit_Day_0_en","libraries.textcomposer_MarkdownTextComposerEdit_Night_0_en",19944,], ["libraries.textcomposer.components.markdown_MarkdownTextInput_Day_0_en","libraries.textcomposer.components.markdown_MarkdownTextInput_Night_0_en",0,], ["libraries.matrix.ui.components_MatrixUserHeaderPlaceholder_Day_0_en","libraries.matrix.ui.components_MatrixUserHeaderPlaceholder_Night_0_en",0,], ["libraries.matrix.ui.components_MatrixUserHeader_Day_0_en","libraries.matrix.ui.components_MatrixUserHeader_Night_0_en",0,], @@ -410,7 +410,7 @@ export const screenshots = [ ["libraries.mediaviewer.api.viewer_MediaViewerView_0_en","",0,], ["libraries.mediaviewer.api.viewer_MediaViewerView_10_en","",0,], ["libraries.mediaviewer.api.viewer_MediaViewerView_1_en","",0,], -["libraries.mediaviewer.api.viewer_MediaViewerView_2_en","",19923,], +["libraries.mediaviewer.api.viewer_MediaViewerView_2_en","",19944,], ["libraries.mediaviewer.api.viewer_MediaViewerView_3_en","",0,], ["libraries.mediaviewer.api.viewer_MediaViewerView_4_en","",0,], ["libraries.mediaviewer.api.viewer_MediaViewerView_5_en","",0,], @@ -420,10 +420,10 @@ export const screenshots = [ ["libraries.mediaviewer.api.viewer_MediaViewerView_9_en","",0,], ["libraries.designsystem.theme.components_MediumTopAppBar_App Bars_en","",0,], ["libraries.textcomposer.mentions_MentionSpanTheme_Day_0_en","libraries.textcomposer.mentions_MentionSpanTheme_Night_0_en",0,], -["features.messages.impl.mentions_MentionSuggestionsPickerView_Day_0_en","features.messages.impl.mentions_MentionSuggestionsPickerView_Night_0_en",19923,], +["features.messages.impl.mentions_MentionSuggestionsPickerView_Day_0_en","features.messages.impl.mentions_MentionSuggestionsPickerView_Night_0_en",19944,], ["libraries.designsystem.theme.components.previews_Menu_Menus_en","",0,], ["features.messages.impl.messagecomposer_MessageComposerViewVoice_Day_0_en","features.messages.impl.messagecomposer_MessageComposerViewVoice_Night_0_en",0,], -["features.messages.impl.messagecomposer_MessageComposerView_Day_0_en","features.messages.impl.messagecomposer_MessageComposerView_Night_0_en",19923,], +["features.messages.impl.messagecomposer_MessageComposerView_Day_0_en","features.messages.impl.messagecomposer_MessageComposerView_Night_0_en",19944,], ["features.messages.impl.timeline.components_MessageEventBubble_Day_0_en","features.messages.impl.timeline.components_MessageEventBubble_Night_0_en",0,], ["features.messages.impl.timeline.components_MessageEventBubble_Day_10_en","features.messages.impl.timeline.components_MessageEventBubble_Night_10_en",0,], ["features.messages.impl.timeline.components_MessageEventBubble_Day_11_en","features.messages.impl.timeline.components_MessageEventBubble_Night_11_en",0,], @@ -447,25 +447,26 @@ export const screenshots = [ ["features.messages.impl.timeline.components_MessagesReactionButton_Day_1_en","features.messages.impl.timeline.components_MessagesReactionButton_Night_1_en",0,], ["features.messages.impl.timeline.components_MessagesReactionButton_Day_2_en","features.messages.impl.timeline.components_MessagesReactionButton_Night_2_en",0,], ["features.messages.impl.timeline.components_MessagesReactionButton_Day_3_en","features.messages.impl.timeline.components_MessagesReactionButton_Night_3_en",0,], -["features.messages.impl.typing_MessagesViewWithTyping_Day_0_en","features.messages.impl.typing_MessagesViewWithTyping_Night_0_en",19923,], -["features.messages.impl.typing_MessagesViewWithTyping_Day_1_en","features.messages.impl.typing_MessagesViewWithTyping_Night_1_en",19923,], +["features.messages.impl.typing_MessagesViewWithTyping_Day_0_en","features.messages.impl.typing_MessagesViewWithTyping_Night_0_en",19944,], +["features.messages.impl.typing_MessagesViewWithTyping_Day_1_en","features.messages.impl.typing_MessagesViewWithTyping_Night_1_en",19944,], ["features.messages.impl.typing_MessagesViewWithTyping_Day_2_en","features.messages.impl.typing_MessagesViewWithTyping_Night_2_en",0,], -["features.messages.impl_MessagesView_Day_0_en","features.messages.impl_MessagesView_Night_0_en",19923,], -["features.messages.impl_MessagesView_Day_10_en","features.messages.impl_MessagesView_Night_10_en",19923,], -["features.messages.impl_MessagesView_Day_11_en","features.messages.impl_MessagesView_Night_11_en",19923,], -["features.messages.impl_MessagesView_Day_12_en","features.messages.impl_MessagesView_Night_12_en",19923,], +["features.messages.impl_MessagesView_Day_0_en","features.messages.impl_MessagesView_Night_0_en",0,], +["features.messages.impl_MessagesView_Day_10_en","features.messages.impl_MessagesView_Night_10_en",19944,], +["features.messages.impl_MessagesView_Day_11_en","features.messages.impl_MessagesView_Night_11_en",19944,], +["features.messages.impl_MessagesView_Day_12_en","features.messages.impl_MessagesView_Night_12_en",0,], +["features.messages.impl_MessagesView_Day_13_en","features.messages.impl_MessagesView_Night_13_en",0,], ["features.messages.impl_MessagesView_Day_1_en","features.messages.impl_MessagesView_Night_1_en",0,], -["features.messages.impl_MessagesView_Day_2_en","features.messages.impl_MessagesView_Night_2_en",19923,], -["features.messages.impl_MessagesView_Day_3_en","features.messages.impl_MessagesView_Night_3_en",19923,], -["features.messages.impl_MessagesView_Day_4_en","features.messages.impl_MessagesView_Night_4_en",19923,], -["features.messages.impl_MessagesView_Day_5_en","features.messages.impl_MessagesView_Night_5_en",19923,], -["features.messages.impl_MessagesView_Day_6_en","features.messages.impl_MessagesView_Night_6_en",19923,], -["features.messages.impl_MessagesView_Day_7_en","features.messages.impl_MessagesView_Night_7_en",19923,], -["features.messages.impl_MessagesView_Day_8_en","features.messages.impl_MessagesView_Night_8_en",19923,], -["features.messages.impl_MessagesView_Day_9_en","features.messages.impl_MessagesView_Night_9_en",19923,], -["features.roomlist.impl.migration_MigrationScreenView_Day_0_en","features.roomlist.impl.migration_MigrationScreenView_Night_0_en",19923,], +["features.messages.impl_MessagesView_Day_2_en","features.messages.impl_MessagesView_Night_2_en",19944,], +["features.messages.impl_MessagesView_Day_3_en","features.messages.impl_MessagesView_Night_3_en",19944,], +["features.messages.impl_MessagesView_Day_4_en","features.messages.impl_MessagesView_Night_4_en",19944,], +["features.messages.impl_MessagesView_Day_5_en","features.messages.impl_MessagesView_Night_5_en",0,], +["features.messages.impl_MessagesView_Day_6_en","features.messages.impl_MessagesView_Night_6_en",19944,], +["features.messages.impl_MessagesView_Day_7_en","features.messages.impl_MessagesView_Night_7_en",19944,], +["features.messages.impl_MessagesView_Day_8_en","features.messages.impl_MessagesView_Night_8_en",19944,], +["features.messages.impl_MessagesView_Day_9_en","features.messages.impl_MessagesView_Night_9_en",19944,], +["features.roomlist.impl.migration_MigrationScreenView_Day_0_en","features.roomlist.impl.migration_MigrationScreenView_Night_0_en",19944,], ["features.migration.impl_MigrationView_Day_0_en","features.migration.impl_MigrationView_Night_0_en",0,], -["features.migration.impl_MigrationView_Day_1_en","features.migration.impl_MigrationView_Night_1_en",19923,], +["features.migration.impl_MigrationView_Day_1_en","features.migration.impl_MigrationView_Night_1_en",19944,], ["libraries.designsystem.theme.components_ModalBottomSheetDark_Bottom Sheets_en","",0,], ["libraries.designsystem.theme.components_ModalBottomSheetLight_Bottom Sheets_en","",0,], ["appicon.element_MonochromeIcon_en","",0,], @@ -474,28 +475,28 @@ export const screenshots = [ ["libraries.designsystem.components.list_MutipleSelectionListItemSelectedTrailingContent_Multiple selection List item - selection in trailing content_List items_en","",0,], ["libraries.designsystem.components.list_MutipleSelectionListItemSelected_Multiple selection List item - selection in supporting text_List items_en","",0,], ["libraries.designsystem.components.list_MutipleSelectionListItem_Multiple selection List item - no selection_List items_en","",0,], -["features.preferences.impl.notifications_NotificationSettingsView_Day_0_en","features.preferences.impl.notifications_NotificationSettingsView_Night_0_en",19923,], -["features.preferences.impl.notifications_NotificationSettingsView_Day_10_en","features.preferences.impl.notifications_NotificationSettingsView_Night_10_en",19923,], -["features.preferences.impl.notifications_NotificationSettingsView_Day_11_en","features.preferences.impl.notifications_NotificationSettingsView_Night_11_en",19923,], -["features.preferences.impl.notifications_NotificationSettingsView_Day_12_en","features.preferences.impl.notifications_NotificationSettingsView_Night_12_en",19923,], -["features.preferences.impl.notifications_NotificationSettingsView_Day_1_en","features.preferences.impl.notifications_NotificationSettingsView_Night_1_en",19923,], -["features.preferences.impl.notifications_NotificationSettingsView_Day_2_en","features.preferences.impl.notifications_NotificationSettingsView_Night_2_en",19923,], -["features.preferences.impl.notifications_NotificationSettingsView_Day_3_en","features.preferences.impl.notifications_NotificationSettingsView_Night_3_en",19923,], -["features.preferences.impl.notifications_NotificationSettingsView_Day_4_en","features.preferences.impl.notifications_NotificationSettingsView_Night_4_en",19923,], -["features.preferences.impl.notifications_NotificationSettingsView_Day_5_en","features.preferences.impl.notifications_NotificationSettingsView_Night_5_en",19923,], -["features.preferences.impl.notifications_NotificationSettingsView_Day_6_en","features.preferences.impl.notifications_NotificationSettingsView_Night_6_en",19923,], -["features.preferences.impl.notifications_NotificationSettingsView_Day_7_en","features.preferences.impl.notifications_NotificationSettingsView_Night_7_en",19923,], -["features.preferences.impl.notifications_NotificationSettingsView_Day_8_en","features.preferences.impl.notifications_NotificationSettingsView_Night_8_en",19923,], -["features.preferences.impl.notifications_NotificationSettingsView_Day_9_en","features.preferences.impl.notifications_NotificationSettingsView_Night_9_en",19923,], -["features.ftue.impl.notifications_NotificationsOptInView_Day_0_en","features.ftue.impl.notifications_NotificationsOptInView_Night_0_en",19923,], +["features.preferences.impl.notifications_NotificationSettingsView_Day_0_en","features.preferences.impl.notifications_NotificationSettingsView_Night_0_en",19944,], +["features.preferences.impl.notifications_NotificationSettingsView_Day_10_en","features.preferences.impl.notifications_NotificationSettingsView_Night_10_en",19944,], +["features.preferences.impl.notifications_NotificationSettingsView_Day_11_en","features.preferences.impl.notifications_NotificationSettingsView_Night_11_en",19944,], +["features.preferences.impl.notifications_NotificationSettingsView_Day_12_en","features.preferences.impl.notifications_NotificationSettingsView_Night_12_en",19944,], +["features.preferences.impl.notifications_NotificationSettingsView_Day_1_en","features.preferences.impl.notifications_NotificationSettingsView_Night_1_en",19944,], +["features.preferences.impl.notifications_NotificationSettingsView_Day_2_en","features.preferences.impl.notifications_NotificationSettingsView_Night_2_en",19944,], +["features.preferences.impl.notifications_NotificationSettingsView_Day_3_en","features.preferences.impl.notifications_NotificationSettingsView_Night_3_en",19944,], +["features.preferences.impl.notifications_NotificationSettingsView_Day_4_en","features.preferences.impl.notifications_NotificationSettingsView_Night_4_en",19944,], +["features.preferences.impl.notifications_NotificationSettingsView_Day_5_en","features.preferences.impl.notifications_NotificationSettingsView_Night_5_en",19944,], +["features.preferences.impl.notifications_NotificationSettingsView_Day_6_en","features.preferences.impl.notifications_NotificationSettingsView_Night_6_en",19944,], +["features.preferences.impl.notifications_NotificationSettingsView_Day_7_en","features.preferences.impl.notifications_NotificationSettingsView_Night_7_en",19944,], +["features.preferences.impl.notifications_NotificationSettingsView_Day_8_en","features.preferences.impl.notifications_NotificationSettingsView_Night_8_en",19944,], +["features.preferences.impl.notifications_NotificationSettingsView_Day_9_en","features.preferences.impl.notifications_NotificationSettingsView_Night_9_en",19944,], +["features.ftue.impl.notifications_NotificationsOptInView_Day_0_en","features.ftue.impl.notifications_NotificationsOptInView_Night_0_en",19944,], ["features.login.impl.oidc.webview_OidcView_Day_0_en","features.login.impl.oidc.webview_OidcView_Night_0_en",0,], ["features.login.impl.oidc.webview_OidcView_Day_1_en","features.login.impl.oidc.webview_OidcView_Night_1_en",0,], ["libraries.designsystem.atomic.pages_OnBoardingPage_Day_0_en","libraries.designsystem.atomic.pages_OnBoardingPage_Night_0_en",0,], -["features.onboarding.impl_OnBoardingView_Day_0_en","features.onboarding.impl_OnBoardingView_Night_0_en",19923,], -["features.onboarding.impl_OnBoardingView_Day_1_en","features.onboarding.impl_OnBoardingView_Night_1_en",19923,], -["features.onboarding.impl_OnBoardingView_Day_2_en","features.onboarding.impl_OnBoardingView_Night_2_en",19923,], -["features.onboarding.impl_OnBoardingView_Day_3_en","features.onboarding.impl_OnBoardingView_Night_3_en",19923,], -["features.onboarding.impl_OnBoardingView_Day_4_en","features.onboarding.impl_OnBoardingView_Night_4_en",19923,], +["features.onboarding.impl_OnBoardingView_Day_0_en","features.onboarding.impl_OnBoardingView_Night_0_en",19944,], +["features.onboarding.impl_OnBoardingView_Day_1_en","features.onboarding.impl_OnBoardingView_Night_1_en",19944,], +["features.onboarding.impl_OnBoardingView_Day_2_en","features.onboarding.impl_OnBoardingView_Night_2_en",19944,], +["features.onboarding.impl_OnBoardingView_Day_3_en","features.onboarding.impl_OnBoardingView_Night_3_en",19944,], +["features.onboarding.impl_OnBoardingView_Day_4_en","features.onboarding.impl_OnBoardingView_Night_4_en",19944,], ["libraries.designsystem.background_OnboardingBackground_Day_0_en","libraries.designsystem.background_OnboardingBackground_Night_0_en",0,], ["libraries.designsystem.theme.components_OutlinedButtonLargeLowPadding_Buttons_en","",0,], ["libraries.designsystem.theme.components_OutlinedButtonLarge_Buttons_en","",0,], @@ -510,47 +511,57 @@ export const screenshots = [ ["libraries.designsystem.components_PageTitleWithIconFull_Day_3_en","libraries.designsystem.components_PageTitleWithIconFull_Night_3_en",0,], ["libraries.designsystem.components_PageTitleWithIconFull_Day_4_en","libraries.designsystem.components_PageTitleWithIconFull_Night_4_en",0,], ["libraries.designsystem.components_PageTitleWithIconMinimal_Day_0_en","libraries.designsystem.components_PageTitleWithIconMinimal_Night_0_en",0,], -["features.roomdetails.impl.rolesandpermissions.changeroles_PendingMemberRowWithLongName_Day_0_en","features.roomdetails.impl.rolesandpermissions.changeroles_PendingMemberRowWithLongName_Night_0_en",19923,], -["libraries.permissions.api_PermissionsView_Day_0_en","libraries.permissions.api_PermissionsView_Night_0_en",19923,], -["libraries.permissions.api_PermissionsView_Day_1_en","libraries.permissions.api_PermissionsView_Night_1_en",19923,], -["libraries.permissions.api_PermissionsView_Day_2_en","libraries.permissions.api_PermissionsView_Night_2_en",19923,], -["libraries.permissions.api_PermissionsView_Day_3_en","libraries.permissions.api_PermissionsView_Night_3_en",19923,], +["features.roomdetails.impl.rolesandpermissions.changeroles_PendingMemberRowWithLongName_Day_0_en","features.roomdetails.impl.rolesandpermissions.changeroles_PendingMemberRowWithLongName_Night_0_en",19944,], +["libraries.permissions.api_PermissionsView_Day_0_en","libraries.permissions.api_PermissionsView_Night_0_en",19944,], +["libraries.permissions.api_PermissionsView_Day_1_en","libraries.permissions.api_PermissionsView_Night_1_en",19944,], +["libraries.permissions.api_PermissionsView_Day_2_en","libraries.permissions.api_PermissionsView_Night_2_en",19944,], +["libraries.permissions.api_PermissionsView_Day_3_en","libraries.permissions.api_PermissionsView_Night_3_en",19944,], ["features.lockscreen.impl.components_PinEntryTextField_Day_0_en","features.lockscreen.impl.components_PinEntryTextField_Night_0_en",0,], ["libraries.designsystem.components_PinIcon_Day_0_en","libraries.designsystem.components_PinIcon_Night_0_en",0,], ["features.lockscreen.impl.unlock.keypad_PinKeypad_Day_0_en","features.lockscreen.impl.unlock.keypad_PinKeypad_Night_0_en",0,], -["features.lockscreen.impl.unlock_PinUnlockViewInApp_Day_0_en","features.lockscreen.impl.unlock_PinUnlockViewInApp_Night_0_en",19923,], -["features.lockscreen.impl.unlock_PinUnlockViewInApp_Day_1_en","features.lockscreen.impl.unlock_PinUnlockViewInApp_Night_1_en",19923,], -["features.lockscreen.impl.unlock_PinUnlockViewInApp_Day_2_en","features.lockscreen.impl.unlock_PinUnlockViewInApp_Night_2_en",19923,], -["features.lockscreen.impl.unlock_PinUnlockViewInApp_Day_3_en","features.lockscreen.impl.unlock_PinUnlockViewInApp_Night_3_en",19923,], -["features.lockscreen.impl.unlock_PinUnlockViewInApp_Day_4_en","features.lockscreen.impl.unlock_PinUnlockViewInApp_Night_4_en",19923,], -["features.lockscreen.impl.unlock_PinUnlockViewInApp_Day_5_en","features.lockscreen.impl.unlock_PinUnlockViewInApp_Night_5_en",19923,], -["features.lockscreen.impl.unlock_PinUnlockViewInApp_Day_6_en","features.lockscreen.impl.unlock_PinUnlockViewInApp_Night_6_en",19923,], -["features.lockscreen.impl.unlock_PinUnlockView_Day_0_en","features.lockscreen.impl.unlock_PinUnlockView_Night_0_en",19923,], -["features.lockscreen.impl.unlock_PinUnlockView_Day_1_en","features.lockscreen.impl.unlock_PinUnlockView_Night_1_en",19923,], -["features.lockscreen.impl.unlock_PinUnlockView_Day_2_en","features.lockscreen.impl.unlock_PinUnlockView_Night_2_en",19923,], -["features.lockscreen.impl.unlock_PinUnlockView_Day_3_en","features.lockscreen.impl.unlock_PinUnlockView_Night_3_en",19923,], -["features.lockscreen.impl.unlock_PinUnlockView_Day_4_en","features.lockscreen.impl.unlock_PinUnlockView_Night_4_en",19923,], -["features.lockscreen.impl.unlock_PinUnlockView_Day_5_en","features.lockscreen.impl.unlock_PinUnlockView_Night_5_en",19923,], -["features.lockscreen.impl.unlock_PinUnlockView_Day_6_en","features.lockscreen.impl.unlock_PinUnlockView_Night_6_en",19923,], +["features.lockscreen.impl.unlock_PinUnlockViewInApp_Day_0_en","features.lockscreen.impl.unlock_PinUnlockViewInApp_Night_0_en",19944,], +["features.lockscreen.impl.unlock_PinUnlockViewInApp_Day_1_en","features.lockscreen.impl.unlock_PinUnlockViewInApp_Night_1_en",19944,], +["features.lockscreen.impl.unlock_PinUnlockViewInApp_Day_2_en","features.lockscreen.impl.unlock_PinUnlockViewInApp_Night_2_en",19944,], +["features.lockscreen.impl.unlock_PinUnlockViewInApp_Day_3_en","features.lockscreen.impl.unlock_PinUnlockViewInApp_Night_3_en",19944,], +["features.lockscreen.impl.unlock_PinUnlockViewInApp_Day_4_en","features.lockscreen.impl.unlock_PinUnlockViewInApp_Night_4_en",19944,], +["features.lockscreen.impl.unlock_PinUnlockViewInApp_Day_5_en","features.lockscreen.impl.unlock_PinUnlockViewInApp_Night_5_en",19944,], +["features.lockscreen.impl.unlock_PinUnlockViewInApp_Day_6_en","features.lockscreen.impl.unlock_PinUnlockViewInApp_Night_6_en",19944,], +["features.lockscreen.impl.unlock_PinUnlockView_Day_0_en","features.lockscreen.impl.unlock_PinUnlockView_Night_0_en",19944,], +["features.lockscreen.impl.unlock_PinUnlockView_Day_1_en","features.lockscreen.impl.unlock_PinUnlockView_Night_1_en",19944,], +["features.lockscreen.impl.unlock_PinUnlockView_Day_2_en","features.lockscreen.impl.unlock_PinUnlockView_Night_2_en",19944,], +["features.lockscreen.impl.unlock_PinUnlockView_Day_3_en","features.lockscreen.impl.unlock_PinUnlockView_Night_3_en",19944,], +["features.lockscreen.impl.unlock_PinUnlockView_Day_4_en","features.lockscreen.impl.unlock_PinUnlockView_Night_4_en",19944,], +["features.lockscreen.impl.unlock_PinUnlockView_Day_5_en","features.lockscreen.impl.unlock_PinUnlockView_Night_5_en",19944,], +["features.lockscreen.impl.unlock_PinUnlockView_Day_6_en","features.lockscreen.impl.unlock_PinUnlockView_Night_6_en",19944,], +["features.messages.impl.pinned.banner_PinnedMessagesBannerView_Day_0_en","features.messages.impl.pinned.banner_PinnedMessagesBannerView_Night_0_en",0,], +["features.messages.impl.pinned.banner_PinnedMessagesBannerView_Day_1_en","features.messages.impl.pinned.banner_PinnedMessagesBannerView_Night_1_en",0,], +["features.messages.impl.pinned.banner_PinnedMessagesBannerView_Day_2_en","features.messages.impl.pinned.banner_PinnedMessagesBannerView_Night_2_en",0,], +["features.messages.impl.pinned.banner_PinnedMessagesBannerView_Day_3_en","features.messages.impl.pinned.banner_PinnedMessagesBannerView_Night_3_en",0,], +["features.messages.impl.pinned.banner_PinnedMessagesBannerView_Day_4_en","features.messages.impl.pinned.banner_PinnedMessagesBannerView_Night_4_en",0,], +["features.messages.impl.pinned.banner_PinnedMessagesBannerView_Day_5_en","features.messages.impl.pinned.banner_PinnedMessagesBannerView_Night_5_en",0,], +["features.messages.impl.pinned.banner_PinnedMessagesBannerView_Day_6_en","features.messages.impl.pinned.banner_PinnedMessagesBannerView_Night_6_en",0,], +["features.messages.impl.pinned.banner_PinnedMessagesBannerView_Day_7_en","features.messages.impl.pinned.banner_PinnedMessagesBannerView_Night_7_en",0,], +["features.messages.impl.pinned.banner_PinnedMessagesBannerView_Day_8_en","features.messages.impl.pinned.banner_PinnedMessagesBannerView_Night_8_en",0,], +["features.messages.impl.pinned.banner_PinnedMessagesBannerView_Day_9_en","features.messages.impl.pinned.banner_PinnedMessagesBannerView_Night_9_en",0,], ["libraries.designsystem.atomic.atoms_PlaceholderAtom_Day_0_en","libraries.designsystem.atomic.atoms_PlaceholderAtom_Night_0_en",0,], -["features.poll.api.pollcontent_PollAnswerViewDisclosedNotSelected_Day_0_en","features.poll.api.pollcontent_PollAnswerViewDisclosedNotSelected_Night_0_en",19923,], -["features.poll.api.pollcontent_PollAnswerViewDisclosedSelected_Day_0_en","features.poll.api.pollcontent_PollAnswerViewDisclosedSelected_Night_0_en",19923,], -["features.poll.api.pollcontent_PollAnswerViewEndedSelected_Day_0_en","features.poll.api.pollcontent_PollAnswerViewEndedSelected_Night_0_en",19923,], -["features.poll.api.pollcontent_PollAnswerViewEndedWinnerNotSelected_Day_0_en","features.poll.api.pollcontent_PollAnswerViewEndedWinnerNotSelected_Night_0_en",19923,], -["features.poll.api.pollcontent_PollAnswerViewEndedWinnerSelected_Day_0_en","features.poll.api.pollcontent_PollAnswerViewEndedWinnerSelected_Night_0_en",19923,], +["features.poll.api.pollcontent_PollAnswerViewDisclosedNotSelected_Day_0_en","features.poll.api.pollcontent_PollAnswerViewDisclosedNotSelected_Night_0_en",19944,], +["features.poll.api.pollcontent_PollAnswerViewDisclosedSelected_Day_0_en","features.poll.api.pollcontent_PollAnswerViewDisclosedSelected_Night_0_en",19944,], +["features.poll.api.pollcontent_PollAnswerViewEndedSelected_Day_0_en","features.poll.api.pollcontent_PollAnswerViewEndedSelected_Night_0_en",19944,], +["features.poll.api.pollcontent_PollAnswerViewEndedWinnerNotSelected_Day_0_en","features.poll.api.pollcontent_PollAnswerViewEndedWinnerNotSelected_Night_0_en",19944,], +["features.poll.api.pollcontent_PollAnswerViewEndedWinnerSelected_Day_0_en","features.poll.api.pollcontent_PollAnswerViewEndedWinnerSelected_Night_0_en",19944,], ["features.poll.api.pollcontent_PollAnswerViewUndisclosedNotSelected_Day_0_en","features.poll.api.pollcontent_PollAnswerViewUndisclosedNotSelected_Night_0_en",0,], ["features.poll.api.pollcontent_PollAnswerViewUndisclosedSelected_Day_0_en","features.poll.api.pollcontent_PollAnswerViewUndisclosedSelected_Night_0_en",0,], -["features.poll.api.pollcontent_PollContentViewCreatorEditable_Day_0_en","features.poll.api.pollcontent_PollContentViewCreatorEditable_Night_0_en",19923,], -["features.poll.api.pollcontent_PollContentViewCreatorEnded_Day_0_en","features.poll.api.pollcontent_PollContentViewCreatorEnded_Night_0_en",19923,], -["features.poll.api.pollcontent_PollContentViewCreator_Day_0_en","features.poll.api.pollcontent_PollContentViewCreator_Night_0_en",19923,], -["features.poll.api.pollcontent_PollContentViewDisclosed_Day_0_en","features.poll.api.pollcontent_PollContentViewDisclosed_Night_0_en",19923,], -["features.poll.api.pollcontent_PollContentViewEnded_Day_0_en","features.poll.api.pollcontent_PollContentViewEnded_Night_0_en",19923,], -["features.poll.api.pollcontent_PollContentViewUndisclosed_Day_0_en","features.poll.api.pollcontent_PollContentViewUndisclosed_Night_0_en",19923,], -["features.poll.impl.history_PollHistoryView_Day_0_en","features.poll.impl.history_PollHistoryView_Night_0_en",19923,], -["features.poll.impl.history_PollHistoryView_Day_1_en","features.poll.impl.history_PollHistoryView_Night_1_en",19923,], -["features.poll.impl.history_PollHistoryView_Day_2_en","features.poll.impl.history_PollHistoryView_Night_2_en",19923,], -["features.poll.impl.history_PollHistoryView_Day_3_en","features.poll.impl.history_PollHistoryView_Night_3_en",19923,], -["features.poll.impl.history_PollHistoryView_Day_4_en","features.poll.impl.history_PollHistoryView_Night_4_en",19923,], +["features.poll.api.pollcontent_PollContentViewCreatorEditable_Day_0_en","features.poll.api.pollcontent_PollContentViewCreatorEditable_Night_0_en",19944,], +["features.poll.api.pollcontent_PollContentViewCreatorEnded_Day_0_en","features.poll.api.pollcontent_PollContentViewCreatorEnded_Night_0_en",19944,], +["features.poll.api.pollcontent_PollContentViewCreator_Day_0_en","features.poll.api.pollcontent_PollContentViewCreator_Night_0_en",19944,], +["features.poll.api.pollcontent_PollContentViewDisclosed_Day_0_en","features.poll.api.pollcontent_PollContentViewDisclosed_Night_0_en",19944,], +["features.poll.api.pollcontent_PollContentViewEnded_Day_0_en","features.poll.api.pollcontent_PollContentViewEnded_Night_0_en",19944,], +["features.poll.api.pollcontent_PollContentViewUndisclosed_Day_0_en","features.poll.api.pollcontent_PollContentViewUndisclosed_Night_0_en",19944,], +["features.poll.impl.history_PollHistoryView_Day_0_en","features.poll.impl.history_PollHistoryView_Night_0_en",19944,], +["features.poll.impl.history_PollHistoryView_Day_1_en","features.poll.impl.history_PollHistoryView_Night_1_en",19944,], +["features.poll.impl.history_PollHistoryView_Day_2_en","features.poll.impl.history_PollHistoryView_Night_2_en",19944,], +["features.poll.impl.history_PollHistoryView_Day_3_en","features.poll.impl.history_PollHistoryView_Night_3_en",19944,], +["features.poll.impl.history_PollHistoryView_Day_4_en","features.poll.impl.history_PollHistoryView_Night_4_en",19944,], ["libraries.designsystem.components.preferences_PreferenceCategory_Preferences_en","",0,], ["libraries.designsystem.components.preferences_PreferenceCheckbox_Preferences_en","",0,], ["libraries.designsystem.components.preferences_PreferenceDivider_Preferences_en","",0,], @@ -566,182 +577,182 @@ export const screenshots = [ ["libraries.designsystem.components.preferences_PreferenceTextLight_Preferences_en","",0,], ["libraries.designsystem.components.preferences_PreferenceTextWithEndBadgeDark_Preferences_en","",0,], ["libraries.designsystem.components.preferences_PreferenceTextWithEndBadgeLight_Preferences_en","",0,], -["features.preferences.impl.root_PreferencesRootViewDark_0_en","",19923,], -["features.preferences.impl.root_PreferencesRootViewDark_1_en","",19923,], -["features.preferences.impl.root_PreferencesRootViewLight_0_en","",19923,], -["features.preferences.impl.root_PreferencesRootViewLight_1_en","",19923,], +["features.preferences.impl.root_PreferencesRootViewDark_0_en","",19944,], +["features.preferences.impl.root_PreferencesRootViewDark_1_en","",19944,], +["features.preferences.impl.root_PreferencesRootViewLight_0_en","",19944,], +["features.preferences.impl.root_PreferencesRootViewLight_1_en","",19944,], ["features.messages.impl.timeline.components.event_ProgressButton_Day_0_en","features.messages.impl.timeline.components.event_ProgressButton_Night_0_en",0,], -["libraries.designsystem.components_ProgressDialogContent_Dialogs_en","",19923,], -["libraries.designsystem.components_ProgressDialog_Day_0_en","libraries.designsystem.components_ProgressDialog_Night_0_en",19923,], -["features.login.impl.screens.qrcode.confirmation_QrCodeConfirmationView_Day_0_en","features.login.impl.screens.qrcode.confirmation_QrCodeConfirmationView_Night_0_en",19923,], -["features.login.impl.screens.qrcode.confirmation_QrCodeConfirmationView_Day_1_en","features.login.impl.screens.qrcode.confirmation_QrCodeConfirmationView_Night_1_en",19923,], -["features.login.impl.screens.qrcode.confirmation_QrCodeConfirmationView_Day_2_en","features.login.impl.screens.qrcode.confirmation_QrCodeConfirmationView_Night_2_en",19923,], -["features.login.impl.screens.qrcode.error_QrCodeErrorView_Day_0_en","features.login.impl.screens.qrcode.error_QrCodeErrorView_Night_0_en",19923,], -["features.login.impl.screens.qrcode.error_QrCodeErrorView_Day_1_en","features.login.impl.screens.qrcode.error_QrCodeErrorView_Night_1_en",19923,], -["features.login.impl.screens.qrcode.error_QrCodeErrorView_Day_2_en","features.login.impl.screens.qrcode.error_QrCodeErrorView_Night_2_en",19923,], -["features.login.impl.screens.qrcode.error_QrCodeErrorView_Day_3_en","features.login.impl.screens.qrcode.error_QrCodeErrorView_Night_3_en",19923,], -["features.login.impl.screens.qrcode.error_QrCodeErrorView_Day_4_en","features.login.impl.screens.qrcode.error_QrCodeErrorView_Night_4_en",19923,], -["features.login.impl.screens.qrcode.error_QrCodeErrorView_Day_5_en","features.login.impl.screens.qrcode.error_QrCodeErrorView_Night_5_en",19923,], -["features.login.impl.screens.qrcode.error_QrCodeErrorView_Day_6_en","features.login.impl.screens.qrcode.error_QrCodeErrorView_Night_6_en",19923,], -["features.login.impl.screens.qrcode.intro_QrCodeIntroView_Day_0_en","features.login.impl.screens.qrcode.intro_QrCodeIntroView_Night_0_en",19923,], -["features.login.impl.screens.qrcode.intro_QrCodeIntroView_Day_1_en","features.login.impl.screens.qrcode.intro_QrCodeIntroView_Night_1_en",19923,], -["features.login.impl.screens.qrcode.scan_QrCodeScanView_Day_0_en","features.login.impl.screens.qrcode.scan_QrCodeScanView_Night_0_en",19923,], -["features.login.impl.screens.qrcode.scan_QrCodeScanView_Day_1_en","features.login.impl.screens.qrcode.scan_QrCodeScanView_Night_1_en",19923,], -["features.login.impl.screens.qrcode.scan_QrCodeScanView_Day_2_en","features.login.impl.screens.qrcode.scan_QrCodeScanView_Night_2_en",19923,], -["features.login.impl.screens.qrcode.scan_QrCodeScanView_Day_3_en","features.login.impl.screens.qrcode.scan_QrCodeScanView_Night_3_en",19923,], +["libraries.designsystem.components_ProgressDialogContent_Dialogs_en","",19944,], +["libraries.designsystem.components_ProgressDialog_Day_0_en","libraries.designsystem.components_ProgressDialog_Night_0_en",19944,], +["features.login.impl.screens.qrcode.confirmation_QrCodeConfirmationView_Day_0_en","features.login.impl.screens.qrcode.confirmation_QrCodeConfirmationView_Night_0_en",19944,], +["features.login.impl.screens.qrcode.confirmation_QrCodeConfirmationView_Day_1_en","features.login.impl.screens.qrcode.confirmation_QrCodeConfirmationView_Night_1_en",19944,], +["features.login.impl.screens.qrcode.confirmation_QrCodeConfirmationView_Day_2_en","features.login.impl.screens.qrcode.confirmation_QrCodeConfirmationView_Night_2_en",19944,], +["features.login.impl.screens.qrcode.error_QrCodeErrorView_Day_0_en","features.login.impl.screens.qrcode.error_QrCodeErrorView_Night_0_en",19944,], +["features.login.impl.screens.qrcode.error_QrCodeErrorView_Day_1_en","features.login.impl.screens.qrcode.error_QrCodeErrorView_Night_1_en",19944,], +["features.login.impl.screens.qrcode.error_QrCodeErrorView_Day_2_en","features.login.impl.screens.qrcode.error_QrCodeErrorView_Night_2_en",19944,], +["features.login.impl.screens.qrcode.error_QrCodeErrorView_Day_3_en","features.login.impl.screens.qrcode.error_QrCodeErrorView_Night_3_en",19944,], +["features.login.impl.screens.qrcode.error_QrCodeErrorView_Day_4_en","features.login.impl.screens.qrcode.error_QrCodeErrorView_Night_4_en",19944,], +["features.login.impl.screens.qrcode.error_QrCodeErrorView_Day_5_en","features.login.impl.screens.qrcode.error_QrCodeErrorView_Night_5_en",19944,], +["features.login.impl.screens.qrcode.error_QrCodeErrorView_Day_6_en","features.login.impl.screens.qrcode.error_QrCodeErrorView_Night_6_en",19944,], +["features.login.impl.screens.qrcode.intro_QrCodeIntroView_Day_0_en","features.login.impl.screens.qrcode.intro_QrCodeIntroView_Night_0_en",19944,], +["features.login.impl.screens.qrcode.intro_QrCodeIntroView_Day_1_en","features.login.impl.screens.qrcode.intro_QrCodeIntroView_Night_1_en",19944,], +["features.login.impl.screens.qrcode.scan_QrCodeScanView_Day_0_en","features.login.impl.screens.qrcode.scan_QrCodeScanView_Night_0_en",19944,], +["features.login.impl.screens.qrcode.scan_QrCodeScanView_Day_1_en","features.login.impl.screens.qrcode.scan_QrCodeScanView_Night_1_en",19944,], +["features.login.impl.screens.qrcode.scan_QrCodeScanView_Day_2_en","features.login.impl.screens.qrcode.scan_QrCodeScanView_Night_2_en",19944,], +["features.login.impl.screens.qrcode.scan_QrCodeScanView_Day_3_en","features.login.impl.screens.qrcode.scan_QrCodeScanView_Night_3_en",19944,], ["libraries.designsystem.theme.components_RadioButton_Toggles_en","",0,], -["features.rageshake.api.detection_RageshakeDialogContent_Day_0_en","features.rageshake.api.detection_RageshakeDialogContent_Night_0_en",19923,], -["features.rageshake.api.preferences_RageshakePreferencesView_Day_0_en","features.rageshake.api.preferences_RageshakePreferencesView_Night_0_en",19923,], +["features.rageshake.api.detection_RageshakeDialogContent_Day_0_en","features.rageshake.api.detection_RageshakeDialogContent_Night_0_en",19944,], +["features.rageshake.api.preferences_RageshakePreferencesView_Day_0_en","features.rageshake.api.preferences_RageshakePreferencesView_Night_0_en",19944,], ["features.rageshake.api.preferences_RageshakePreferencesView_Day_1_en","features.rageshake.api.preferences_RageshakePreferencesView_Night_1_en",0,], -["features.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_Day_0_en","features.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_Night_0_en",19923,], -["features.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_Day_1_en","features.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_Night_1_en",19923,], -["features.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_Day_2_en","features.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_Night_2_en",19923,], -["features.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_Day_3_en","features.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_Night_3_en",19923,], -["features.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_Day_4_en","features.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_Night_4_en",19923,], -["features.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_Day_5_en","features.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_Night_5_en",19923,], -["features.securebackup.impl.setup.views_RecoveryKeyView_Day_0_en","features.securebackup.impl.setup.views_RecoveryKeyView_Night_0_en",19923,], -["features.securebackup.impl.setup.views_RecoveryKeyView_Day_10_en","features.securebackup.impl.setup.views_RecoveryKeyView_Night_10_en",19923,], -["features.securebackup.impl.setup.views_RecoveryKeyView_Day_11_en","features.securebackup.impl.setup.views_RecoveryKeyView_Night_11_en",19923,], -["features.securebackup.impl.setup.views_RecoveryKeyView_Day_1_en","features.securebackup.impl.setup.views_RecoveryKeyView_Night_1_en",19923,], -["features.securebackup.impl.setup.views_RecoveryKeyView_Day_2_en","features.securebackup.impl.setup.views_RecoveryKeyView_Night_2_en",19923,], -["features.securebackup.impl.setup.views_RecoveryKeyView_Day_3_en","features.securebackup.impl.setup.views_RecoveryKeyView_Night_3_en",19923,], -["features.securebackup.impl.setup.views_RecoveryKeyView_Day_4_en","features.securebackup.impl.setup.views_RecoveryKeyView_Night_4_en",19923,], -["features.securebackup.impl.setup.views_RecoveryKeyView_Day_5_en","features.securebackup.impl.setup.views_RecoveryKeyView_Night_5_en",19923,], -["features.securebackup.impl.setup.views_RecoveryKeyView_Day_6_en","features.securebackup.impl.setup.views_RecoveryKeyView_Night_6_en",19923,], -["features.securebackup.impl.setup.views_RecoveryKeyView_Day_7_en","features.securebackup.impl.setup.views_RecoveryKeyView_Night_7_en",19923,], -["features.securebackup.impl.setup.views_RecoveryKeyView_Day_8_en","features.securebackup.impl.setup.views_RecoveryKeyView_Night_8_en",19923,], -["features.securebackup.impl.setup.views_RecoveryKeyView_Day_9_en","features.securebackup.impl.setup.views_RecoveryKeyView_Night_9_en",19923,], +["features.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_Day_0_en","features.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_Night_0_en",19944,], +["features.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_Day_1_en","features.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_Night_1_en",19944,], +["features.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_Day_2_en","features.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_Night_2_en",19944,], +["features.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_Day_3_en","features.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_Night_3_en",19944,], +["features.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_Day_4_en","features.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_Night_4_en",19944,], +["features.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_Day_5_en","features.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_Night_5_en",19944,], +["features.securebackup.impl.setup.views_RecoveryKeyView_Day_0_en","features.securebackup.impl.setup.views_RecoveryKeyView_Night_0_en",19944,], +["features.securebackup.impl.setup.views_RecoveryKeyView_Day_10_en","features.securebackup.impl.setup.views_RecoveryKeyView_Night_10_en",19944,], +["features.securebackup.impl.setup.views_RecoveryKeyView_Day_11_en","features.securebackup.impl.setup.views_RecoveryKeyView_Night_11_en",19944,], +["features.securebackup.impl.setup.views_RecoveryKeyView_Day_1_en","features.securebackup.impl.setup.views_RecoveryKeyView_Night_1_en",19944,], +["features.securebackup.impl.setup.views_RecoveryKeyView_Day_2_en","features.securebackup.impl.setup.views_RecoveryKeyView_Night_2_en",19944,], +["features.securebackup.impl.setup.views_RecoveryKeyView_Day_3_en","features.securebackup.impl.setup.views_RecoveryKeyView_Night_3_en",19944,], +["features.securebackup.impl.setup.views_RecoveryKeyView_Day_4_en","features.securebackup.impl.setup.views_RecoveryKeyView_Night_4_en",19944,], +["features.securebackup.impl.setup.views_RecoveryKeyView_Day_5_en","features.securebackup.impl.setup.views_RecoveryKeyView_Night_5_en",19944,], +["features.securebackup.impl.setup.views_RecoveryKeyView_Day_6_en","features.securebackup.impl.setup.views_RecoveryKeyView_Night_6_en",19944,], +["features.securebackup.impl.setup.views_RecoveryKeyView_Day_7_en","features.securebackup.impl.setup.views_RecoveryKeyView_Night_7_en",19944,], +["features.securebackup.impl.setup.views_RecoveryKeyView_Day_8_en","features.securebackup.impl.setup.views_RecoveryKeyView_Night_8_en",19944,], +["features.securebackup.impl.setup.views_RecoveryKeyView_Day_9_en","features.securebackup.impl.setup.views_RecoveryKeyView_Night_9_en",19944,], ["libraries.designsystem.atomic.atoms_RedIndicatorAtom_Day_0_en","libraries.designsystem.atomic.atoms_RedIndicatorAtom_Night_0_en",0,], ["features.messages.impl.timeline.components_ReplySwipeIndicator_Day_0_en","features.messages.impl.timeline.components_ReplySwipeIndicator_Night_0_en",0,], -["features.messages.impl.report_ReportMessageView_Day_0_en","features.messages.impl.report_ReportMessageView_Night_0_en",19923,], -["features.messages.impl.report_ReportMessageView_Day_1_en","features.messages.impl.report_ReportMessageView_Night_1_en",19923,], -["features.messages.impl.report_ReportMessageView_Day_2_en","features.messages.impl.report_ReportMessageView_Night_2_en",19923,], -["features.messages.impl.report_ReportMessageView_Day_3_en","features.messages.impl.report_ReportMessageView_Night_3_en",19923,], -["features.messages.impl.report_ReportMessageView_Day_4_en","features.messages.impl.report_ReportMessageView_Night_4_en",19923,], -["features.messages.impl.report_ReportMessageView_Day_5_en","features.messages.impl.report_ReportMessageView_Night_5_en",19923,], -["libraries.designsystem.components.dialogs_RetryDialogContent_Dialogs_en","",19923,], -["libraries.designsystem.components.dialogs_RetryDialog_Day_0_en","libraries.designsystem.components.dialogs_RetryDialog_Night_0_en",19923,], -["features.roomdetails.impl.rolesandpermissions_RolesAndPermissionsView_Day_0_en","features.roomdetails.impl.rolesandpermissions_RolesAndPermissionsView_Night_0_en",19923,], -["features.roomdetails.impl.rolesandpermissions_RolesAndPermissionsView_Day_1_en","features.roomdetails.impl.rolesandpermissions_RolesAndPermissionsView_Night_1_en",19923,], -["features.roomdetails.impl.rolesandpermissions_RolesAndPermissionsView_Day_2_en","features.roomdetails.impl.rolesandpermissions_RolesAndPermissionsView_Night_2_en",19923,], -["features.roomdetails.impl.rolesandpermissions_RolesAndPermissionsView_Day_3_en","features.roomdetails.impl.rolesandpermissions_RolesAndPermissionsView_Night_3_en",19923,], -["features.roomdetails.impl.rolesandpermissions_RolesAndPermissionsView_Day_4_en","features.roomdetails.impl.rolesandpermissions_RolesAndPermissionsView_Night_4_en",19923,], -["features.roomdetails.impl.rolesandpermissions_RolesAndPermissionsView_Day_5_en","features.roomdetails.impl.rolesandpermissions_RolesAndPermissionsView_Night_5_en",19923,], -["features.roomdetails.impl.rolesandpermissions_RolesAndPermissionsView_Day_6_en","features.roomdetails.impl.rolesandpermissions_RolesAndPermissionsView_Night_6_en",19923,], -["features.roomdetails.impl.rolesandpermissions_RolesAndPermissionsView_Day_7_en","features.roomdetails.impl.rolesandpermissions_RolesAndPermissionsView_Night_7_en",19923,], +["features.messages.impl.report_ReportMessageView_Day_0_en","features.messages.impl.report_ReportMessageView_Night_0_en",19944,], +["features.messages.impl.report_ReportMessageView_Day_1_en","features.messages.impl.report_ReportMessageView_Night_1_en",19944,], +["features.messages.impl.report_ReportMessageView_Day_2_en","features.messages.impl.report_ReportMessageView_Night_2_en",19944,], +["features.messages.impl.report_ReportMessageView_Day_3_en","features.messages.impl.report_ReportMessageView_Night_3_en",19944,], +["features.messages.impl.report_ReportMessageView_Day_4_en","features.messages.impl.report_ReportMessageView_Night_4_en",19944,], +["features.messages.impl.report_ReportMessageView_Day_5_en","features.messages.impl.report_ReportMessageView_Night_5_en",19944,], +["libraries.designsystem.components.dialogs_RetryDialogContent_Dialogs_en","",19944,], +["libraries.designsystem.components.dialogs_RetryDialog_Day_0_en","libraries.designsystem.components.dialogs_RetryDialog_Night_0_en",19944,], +["features.roomdetails.impl.rolesandpermissions_RolesAndPermissionsView_Day_0_en","features.roomdetails.impl.rolesandpermissions_RolesAndPermissionsView_Night_0_en",19944,], +["features.roomdetails.impl.rolesandpermissions_RolesAndPermissionsView_Day_1_en","features.roomdetails.impl.rolesandpermissions_RolesAndPermissionsView_Night_1_en",19944,], +["features.roomdetails.impl.rolesandpermissions_RolesAndPermissionsView_Day_2_en","features.roomdetails.impl.rolesandpermissions_RolesAndPermissionsView_Night_2_en",19944,], +["features.roomdetails.impl.rolesandpermissions_RolesAndPermissionsView_Day_3_en","features.roomdetails.impl.rolesandpermissions_RolesAndPermissionsView_Night_3_en",19944,], +["features.roomdetails.impl.rolesandpermissions_RolesAndPermissionsView_Day_4_en","features.roomdetails.impl.rolesandpermissions_RolesAndPermissionsView_Night_4_en",19944,], +["features.roomdetails.impl.rolesandpermissions_RolesAndPermissionsView_Day_5_en","features.roomdetails.impl.rolesandpermissions_RolesAndPermissionsView_Night_5_en",19944,], +["features.roomdetails.impl.rolesandpermissions_RolesAndPermissionsView_Day_6_en","features.roomdetails.impl.rolesandpermissions_RolesAndPermissionsView_Night_6_en",19944,], +["features.roomdetails.impl.rolesandpermissions_RolesAndPermissionsView_Day_7_en","features.roomdetails.impl.rolesandpermissions_RolesAndPermissionsView_Night_7_en",19944,], ["features.roomaliasresolver.impl_RoomAliasResolverView_Day_0_en","features.roomaliasresolver.impl_RoomAliasResolverView_Night_0_en",0,], ["features.roomaliasresolver.impl_RoomAliasResolverView_Day_1_en","features.roomaliasresolver.impl_RoomAliasResolverView_Night_1_en",0,], -["features.roomaliasresolver.impl_RoomAliasResolverView_Day_2_en","features.roomaliasresolver.impl_RoomAliasResolverView_Night_2_en",19923,], +["features.roomaliasresolver.impl_RoomAliasResolverView_Day_2_en","features.roomaliasresolver.impl_RoomAliasResolverView_Night_2_en",19944,], ["features.roomdetails.impl.components_RoomBadgeNegative_Day_0_en","features.roomdetails.impl.components_RoomBadgeNegative_Night_0_en",0,], ["features.roomdetails.impl.components_RoomBadgeNeutral_Day_0_en","features.roomdetails.impl.components_RoomBadgeNeutral_Night_0_en",0,], ["features.roomdetails.impl.components_RoomBadgePositive_Day_0_en","features.roomdetails.impl.components_RoomBadgePositive_Night_0_en",0,], -["features.roomdetails.impl_RoomDetailsDark_0_en","",19923,], -["features.roomdetails.impl_RoomDetailsDark_10_en","",19923,], -["features.roomdetails.impl_RoomDetailsDark_11_en","",19923,], -["features.roomdetails.impl_RoomDetailsDark_12_en","",19923,], -["features.roomdetails.impl_RoomDetailsDark_1_en","",19923,], -["features.roomdetails.impl_RoomDetailsDark_2_en","",19923,], -["features.roomdetails.impl_RoomDetailsDark_3_en","",19923,], -["features.roomdetails.impl_RoomDetailsDark_4_en","",19923,], -["features.roomdetails.impl_RoomDetailsDark_5_en","",19923,], -["features.roomdetails.impl_RoomDetailsDark_6_en","",19923,], -["features.roomdetails.impl_RoomDetailsDark_7_en","",19923,], -["features.roomdetails.impl_RoomDetailsDark_8_en","",19923,], -["features.roomdetails.impl_RoomDetailsDark_9_en","",19923,], -["features.roomdetails.impl.edit_RoomDetailsEditView_Day_0_en","features.roomdetails.impl.edit_RoomDetailsEditView_Night_0_en",19923,], -["features.roomdetails.impl.edit_RoomDetailsEditView_Day_1_en","features.roomdetails.impl.edit_RoomDetailsEditView_Night_1_en",19923,], -["features.roomdetails.impl.edit_RoomDetailsEditView_Day_2_en","features.roomdetails.impl.edit_RoomDetailsEditView_Night_2_en",19923,], -["features.roomdetails.impl.edit_RoomDetailsEditView_Day_3_en","features.roomdetails.impl.edit_RoomDetailsEditView_Night_3_en",19923,], -["features.roomdetails.impl.edit_RoomDetailsEditView_Day_4_en","features.roomdetails.impl.edit_RoomDetailsEditView_Night_4_en",19923,], -["features.roomdetails.impl.edit_RoomDetailsEditView_Day_5_en","features.roomdetails.impl.edit_RoomDetailsEditView_Night_5_en",19923,], -["features.roomdetails.impl.edit_RoomDetailsEditView_Day_6_en","features.roomdetails.impl.edit_RoomDetailsEditView_Night_6_en",19923,], -["features.roomdetails.impl.edit_RoomDetailsEditView_Day_7_en","features.roomdetails.impl.edit_RoomDetailsEditView_Night_7_en",19923,], -["features.roomdetails.impl_RoomDetails_0_en","",19923,], -["features.roomdetails.impl_RoomDetails_10_en","",19923,], -["features.roomdetails.impl_RoomDetails_11_en","",19923,], -["features.roomdetails.impl_RoomDetails_12_en","",19923,], -["features.roomdetails.impl_RoomDetails_1_en","",19923,], -["features.roomdetails.impl_RoomDetails_2_en","",19923,], -["features.roomdetails.impl_RoomDetails_3_en","",19923,], -["features.roomdetails.impl_RoomDetails_4_en","",19923,], -["features.roomdetails.impl_RoomDetails_5_en","",19923,], -["features.roomdetails.impl_RoomDetails_6_en","",19923,], -["features.roomdetails.impl_RoomDetails_7_en","",19923,], -["features.roomdetails.impl_RoomDetails_8_en","",19923,], -["features.roomdetails.impl_RoomDetails_9_en","",19923,], -["features.roomdirectory.impl.root_RoomDirectoryView_Day_0_en","features.roomdirectory.impl.root_RoomDirectoryView_Night_0_en",19923,], -["features.roomdirectory.impl.root_RoomDirectoryView_Day_1_en","features.roomdirectory.impl.root_RoomDirectoryView_Night_1_en",19923,], -["features.roomdirectory.impl.root_RoomDirectoryView_Day_2_en","features.roomdirectory.impl.root_RoomDirectoryView_Night_2_en",19923,], -["features.roomdetails.impl.invite_RoomInviteMembersView_Day_0_en","features.roomdetails.impl.invite_RoomInviteMembersView_Night_0_en",19923,], -["features.roomdetails.impl.invite_RoomInviteMembersView_Day_1_en","features.roomdetails.impl.invite_RoomInviteMembersView_Night_1_en",19923,], -["features.roomdetails.impl.invite_RoomInviteMembersView_Day_2_en","features.roomdetails.impl.invite_RoomInviteMembersView_Night_2_en",19923,], -["features.roomdetails.impl.invite_RoomInviteMembersView_Day_3_en","features.roomdetails.impl.invite_RoomInviteMembersView_Night_3_en",19923,], -["features.roomdetails.impl.invite_RoomInviteMembersView_Day_4_en","features.roomdetails.impl.invite_RoomInviteMembersView_Night_4_en",19923,], -["features.roomdetails.impl.invite_RoomInviteMembersView_Day_5_en","features.roomdetails.impl.invite_RoomInviteMembersView_Night_5_en",19923,], -["features.roomdetails.impl.invite_RoomInviteMembersView_Day_6_en","features.roomdetails.impl.invite_RoomInviteMembersView_Night_6_en",19923,], -["features.roomdetails.impl.invite_RoomInviteMembersView_Day_7_en","features.roomdetails.impl.invite_RoomInviteMembersView_Night_7_en",19923,], -["features.roomlist.impl.components_RoomListContentView_Day_0_en","features.roomlist.impl.components_RoomListContentView_Night_0_en",19923,], -["features.roomlist.impl.components_RoomListContentView_Day_1_en","features.roomlist.impl.components_RoomListContentView_Night_1_en",19923,], +["features.roomdetails.impl_RoomDetailsDark_0_en","",19944,], +["features.roomdetails.impl_RoomDetailsDark_10_en","",19944,], +["features.roomdetails.impl_RoomDetailsDark_11_en","",19944,], +["features.roomdetails.impl_RoomDetailsDark_12_en","",19944,], +["features.roomdetails.impl_RoomDetailsDark_1_en","",19944,], +["features.roomdetails.impl_RoomDetailsDark_2_en","",19944,], +["features.roomdetails.impl_RoomDetailsDark_3_en","",19944,], +["features.roomdetails.impl_RoomDetailsDark_4_en","",19944,], +["features.roomdetails.impl_RoomDetailsDark_5_en","",19944,], +["features.roomdetails.impl_RoomDetailsDark_6_en","",19944,], +["features.roomdetails.impl_RoomDetailsDark_7_en","",19944,], +["features.roomdetails.impl_RoomDetailsDark_8_en","",19944,], +["features.roomdetails.impl_RoomDetailsDark_9_en","",19944,], +["features.roomdetails.impl.edit_RoomDetailsEditView_Day_0_en","features.roomdetails.impl.edit_RoomDetailsEditView_Night_0_en",19944,], +["features.roomdetails.impl.edit_RoomDetailsEditView_Day_1_en","features.roomdetails.impl.edit_RoomDetailsEditView_Night_1_en",19944,], +["features.roomdetails.impl.edit_RoomDetailsEditView_Day_2_en","features.roomdetails.impl.edit_RoomDetailsEditView_Night_2_en",19944,], +["features.roomdetails.impl.edit_RoomDetailsEditView_Day_3_en","features.roomdetails.impl.edit_RoomDetailsEditView_Night_3_en",19944,], +["features.roomdetails.impl.edit_RoomDetailsEditView_Day_4_en","features.roomdetails.impl.edit_RoomDetailsEditView_Night_4_en",19944,], +["features.roomdetails.impl.edit_RoomDetailsEditView_Day_5_en","features.roomdetails.impl.edit_RoomDetailsEditView_Night_5_en",19944,], +["features.roomdetails.impl.edit_RoomDetailsEditView_Day_6_en","features.roomdetails.impl.edit_RoomDetailsEditView_Night_6_en",19944,], +["features.roomdetails.impl.edit_RoomDetailsEditView_Day_7_en","features.roomdetails.impl.edit_RoomDetailsEditView_Night_7_en",19944,], +["features.roomdetails.impl_RoomDetails_0_en","",19944,], +["features.roomdetails.impl_RoomDetails_10_en","",19944,], +["features.roomdetails.impl_RoomDetails_11_en","",19944,], +["features.roomdetails.impl_RoomDetails_12_en","",19944,], +["features.roomdetails.impl_RoomDetails_1_en","",19944,], +["features.roomdetails.impl_RoomDetails_2_en","",19944,], +["features.roomdetails.impl_RoomDetails_3_en","",19944,], +["features.roomdetails.impl_RoomDetails_4_en","",19944,], +["features.roomdetails.impl_RoomDetails_5_en","",19944,], +["features.roomdetails.impl_RoomDetails_6_en","",19944,], +["features.roomdetails.impl_RoomDetails_7_en","",19944,], +["features.roomdetails.impl_RoomDetails_8_en","",19944,], +["features.roomdetails.impl_RoomDetails_9_en","",19944,], +["features.roomdirectory.impl.root_RoomDirectoryView_Day_0_en","features.roomdirectory.impl.root_RoomDirectoryView_Night_0_en",19944,], +["features.roomdirectory.impl.root_RoomDirectoryView_Day_1_en","features.roomdirectory.impl.root_RoomDirectoryView_Night_1_en",19944,], +["features.roomdirectory.impl.root_RoomDirectoryView_Day_2_en","features.roomdirectory.impl.root_RoomDirectoryView_Night_2_en",19944,], +["features.roomdetails.impl.invite_RoomInviteMembersView_Day_0_en","features.roomdetails.impl.invite_RoomInviteMembersView_Night_0_en",19944,], +["features.roomdetails.impl.invite_RoomInviteMembersView_Day_1_en","features.roomdetails.impl.invite_RoomInviteMembersView_Night_1_en",19944,], +["features.roomdetails.impl.invite_RoomInviteMembersView_Day_2_en","features.roomdetails.impl.invite_RoomInviteMembersView_Night_2_en",19944,], +["features.roomdetails.impl.invite_RoomInviteMembersView_Day_3_en","features.roomdetails.impl.invite_RoomInviteMembersView_Night_3_en",19944,], +["features.roomdetails.impl.invite_RoomInviteMembersView_Day_4_en","features.roomdetails.impl.invite_RoomInviteMembersView_Night_4_en",19944,], +["features.roomdetails.impl.invite_RoomInviteMembersView_Day_5_en","features.roomdetails.impl.invite_RoomInviteMembersView_Night_5_en",19944,], +["features.roomdetails.impl.invite_RoomInviteMembersView_Day_6_en","features.roomdetails.impl.invite_RoomInviteMembersView_Night_6_en",19944,], +["features.roomdetails.impl.invite_RoomInviteMembersView_Day_7_en","features.roomdetails.impl.invite_RoomInviteMembersView_Night_7_en",19944,], +["features.roomlist.impl.components_RoomListContentView_Day_0_en","features.roomlist.impl.components_RoomListContentView_Night_0_en",19944,], +["features.roomlist.impl.components_RoomListContentView_Day_1_en","features.roomlist.impl.components_RoomListContentView_Night_1_en",19944,], ["features.roomlist.impl.components_RoomListContentView_Day_2_en","features.roomlist.impl.components_RoomListContentView_Night_2_en",0,], -["features.roomlist.impl.components_RoomListContentView_Day_3_en","features.roomlist.impl.components_RoomListContentView_Night_3_en",19923,], -["features.roomlist.impl.components_RoomListContentView_Day_4_en","features.roomlist.impl.components_RoomListContentView_Night_4_en",19923,], -["features.roomlist.impl.filters_RoomListFiltersView_Day_0_en","features.roomlist.impl.filters_RoomListFiltersView_Night_0_en",19923,], -["features.roomlist.impl.filters_RoomListFiltersView_Day_1_en","features.roomlist.impl.filters_RoomListFiltersView_Night_1_en",19923,], -["features.roomlist.impl_RoomListModalBottomSheetContent_Day_0_en","features.roomlist.impl_RoomListModalBottomSheetContent_Night_0_en",19923,], -["features.roomlist.impl_RoomListModalBottomSheetContent_Day_1_en","features.roomlist.impl_RoomListModalBottomSheetContent_Night_1_en",19923,], -["features.roomlist.impl_RoomListModalBottomSheetContent_Day_2_en","features.roomlist.impl_RoomListModalBottomSheetContent_Night_2_en",19923,], +["features.roomlist.impl.components_RoomListContentView_Day_3_en","features.roomlist.impl.components_RoomListContentView_Night_3_en",19944,], +["features.roomlist.impl.components_RoomListContentView_Day_4_en","features.roomlist.impl.components_RoomListContentView_Night_4_en",19944,], +["features.roomlist.impl.filters_RoomListFiltersView_Day_0_en","features.roomlist.impl.filters_RoomListFiltersView_Night_0_en",19944,], +["features.roomlist.impl.filters_RoomListFiltersView_Day_1_en","features.roomlist.impl.filters_RoomListFiltersView_Night_1_en",19944,], +["features.roomlist.impl_RoomListModalBottomSheetContent_Day_0_en","features.roomlist.impl_RoomListModalBottomSheetContent_Night_0_en",19944,], +["features.roomlist.impl_RoomListModalBottomSheetContent_Day_1_en","features.roomlist.impl_RoomListModalBottomSheetContent_Night_1_en",19944,], +["features.roomlist.impl_RoomListModalBottomSheetContent_Day_2_en","features.roomlist.impl_RoomListModalBottomSheetContent_Night_2_en",19944,], ["features.roomlist.impl.search_RoomListSearchContent_Day_0_en","features.roomlist.impl.search_RoomListSearchContent_Night_0_en",0,], -["features.roomlist.impl.search_RoomListSearchContent_Day_1_en","features.roomlist.impl.search_RoomListSearchContent_Night_1_en",19923,], -["features.roomlist.impl.search_RoomListSearchContent_Day_2_en","features.roomlist.impl.search_RoomListSearchContent_Night_2_en",19923,], -["features.roomlist.impl_RoomListView_Day_0_en","features.roomlist.impl_RoomListView_Night_0_en",19923,], +["features.roomlist.impl.search_RoomListSearchContent_Day_1_en","features.roomlist.impl.search_RoomListSearchContent_Night_1_en",19944,], +["features.roomlist.impl.search_RoomListSearchContent_Day_2_en","features.roomlist.impl.search_RoomListSearchContent_Night_2_en",19944,], +["features.roomlist.impl_RoomListView_Day_0_en","features.roomlist.impl_RoomListView_Night_0_en",19944,], ["features.roomlist.impl_RoomListView_Day_10_en","features.roomlist.impl_RoomListView_Night_10_en",0,], -["features.roomlist.impl_RoomListView_Day_1_en","features.roomlist.impl_RoomListView_Night_1_en",19923,], -["features.roomlist.impl_RoomListView_Day_2_en","features.roomlist.impl_RoomListView_Night_2_en",19923,], -["features.roomlist.impl_RoomListView_Day_3_en","features.roomlist.impl_RoomListView_Night_3_en",19923,], -["features.roomlist.impl_RoomListView_Day_4_en","features.roomlist.impl_RoomListView_Night_4_en",19923,], -["features.roomlist.impl_RoomListView_Day_5_en","features.roomlist.impl_RoomListView_Night_5_en",19923,], -["features.roomlist.impl_RoomListView_Day_6_en","features.roomlist.impl_RoomListView_Night_6_en",19923,], -["features.roomlist.impl_RoomListView_Day_7_en","features.roomlist.impl_RoomListView_Night_7_en",19923,], +["features.roomlist.impl_RoomListView_Day_1_en","features.roomlist.impl_RoomListView_Night_1_en",19944,], +["features.roomlist.impl_RoomListView_Day_2_en","features.roomlist.impl_RoomListView_Night_2_en",19944,], +["features.roomlist.impl_RoomListView_Day_3_en","features.roomlist.impl_RoomListView_Night_3_en",19944,], +["features.roomlist.impl_RoomListView_Day_4_en","features.roomlist.impl_RoomListView_Night_4_en",19944,], +["features.roomlist.impl_RoomListView_Day_5_en","features.roomlist.impl_RoomListView_Night_5_en",19944,], +["features.roomlist.impl_RoomListView_Day_6_en","features.roomlist.impl_RoomListView_Night_6_en",19944,], +["features.roomlist.impl_RoomListView_Day_7_en","features.roomlist.impl_RoomListView_Night_7_en",19944,], ["features.roomlist.impl_RoomListView_Day_8_en","features.roomlist.impl_RoomListView_Night_8_en",0,], -["features.roomlist.impl_RoomListView_Day_9_en","features.roomlist.impl_RoomListView_Night_9_en",19923,], -["features.roomdetails.impl.members_RoomMemberListViewBanned_Day_0_en","features.roomdetails.impl.members_RoomMemberListViewBanned_Night_0_en",19923,], -["features.roomdetails.impl.members_RoomMemberListViewBanned_Day_1_en","features.roomdetails.impl.members_RoomMemberListViewBanned_Night_1_en",19923,], -["features.roomdetails.impl.members_RoomMemberListViewBanned_Day_2_en","features.roomdetails.impl.members_RoomMemberListViewBanned_Night_2_en",19923,], -["features.roomdetails.impl.members_RoomMemberListView_Day_0_en","features.roomdetails.impl.members_RoomMemberListView_Night_0_en",19923,], -["features.roomdetails.impl.members_RoomMemberListView_Day_1_en","features.roomdetails.impl.members_RoomMemberListView_Night_1_en",19923,], -["features.roomdetails.impl.members_RoomMemberListView_Day_2_en","features.roomdetails.impl.members_RoomMemberListView_Night_2_en",19923,], -["features.roomdetails.impl.members_RoomMemberListView_Day_3_en","features.roomdetails.impl.members_RoomMemberListView_Night_3_en",19923,], -["features.roomdetails.impl.members_RoomMemberListView_Day_4_en","features.roomdetails.impl.members_RoomMemberListView_Night_4_en",19923,], +["features.roomlist.impl_RoomListView_Day_9_en","features.roomlist.impl_RoomListView_Night_9_en",19944,], +["features.roomdetails.impl.members_RoomMemberListViewBanned_Day_0_en","features.roomdetails.impl.members_RoomMemberListViewBanned_Night_0_en",19944,], +["features.roomdetails.impl.members_RoomMemberListViewBanned_Day_1_en","features.roomdetails.impl.members_RoomMemberListViewBanned_Night_1_en",19944,], +["features.roomdetails.impl.members_RoomMemberListViewBanned_Day_2_en","features.roomdetails.impl.members_RoomMemberListViewBanned_Night_2_en",19944,], +["features.roomdetails.impl.members_RoomMemberListView_Day_0_en","features.roomdetails.impl.members_RoomMemberListView_Night_0_en",19944,], +["features.roomdetails.impl.members_RoomMemberListView_Day_1_en","features.roomdetails.impl.members_RoomMemberListView_Night_1_en",19944,], +["features.roomdetails.impl.members_RoomMemberListView_Day_2_en","features.roomdetails.impl.members_RoomMemberListView_Night_2_en",19944,], +["features.roomdetails.impl.members_RoomMemberListView_Day_3_en","features.roomdetails.impl.members_RoomMemberListView_Night_3_en",19944,], +["features.roomdetails.impl.members_RoomMemberListView_Day_4_en","features.roomdetails.impl.members_RoomMemberListView_Night_4_en",19944,], ["features.roomdetails.impl.members_RoomMemberListView_Day_5_en","features.roomdetails.impl.members_RoomMemberListView_Night_5_en",0,], -["features.roomdetails.impl.members_RoomMemberListView_Day_6_en","features.roomdetails.impl.members_RoomMemberListView_Night_6_en",19923,], -["features.roomdetails.impl.members_RoomMemberListView_Day_7_en","features.roomdetails.impl.members_RoomMemberListView_Night_7_en",19923,], -["features.roomdetails.impl.members_RoomMemberListView_Day_8_en","features.roomdetails.impl.members_RoomMemberListView_Night_8_en",19926,], +["features.roomdetails.impl.members_RoomMemberListView_Day_6_en","features.roomdetails.impl.members_RoomMemberListView_Night_6_en",19944,], +["features.roomdetails.impl.members_RoomMemberListView_Day_7_en","features.roomdetails.impl.members_RoomMemberListView_Night_7_en",19944,], +["features.roomdetails.impl.members_RoomMemberListView_Day_8_en","features.roomdetails.impl.members_RoomMemberListView_Night_8_en",19944,], ["libraries.designsystem.atomic.molecules_RoomMembersCountMolecule_Day_0_en","libraries.designsystem.atomic.molecules_RoomMembersCountMolecule_Night_0_en",0,], -["features.roomdetails.impl.members.moderation_RoomMembersModerationView_Day_0_en","features.roomdetails.impl.members.moderation_RoomMembersModerationView_Night_0_en",19923,], -["features.roomdetails.impl.members.moderation_RoomMembersModerationView_Day_1_en","features.roomdetails.impl.members.moderation_RoomMembersModerationView_Night_1_en",19923,], -["features.roomdetails.impl.members.moderation_RoomMembersModerationView_Day_2_en","features.roomdetails.impl.members.moderation_RoomMembersModerationView_Night_2_en",19923,], -["features.roomdetails.impl.members.moderation_RoomMembersModerationView_Day_3_en","features.roomdetails.impl.members.moderation_RoomMembersModerationView_Night_3_en",19923,], -["features.roomdetails.impl.members.moderation_RoomMembersModerationView_Day_4_en","features.roomdetails.impl.members.moderation_RoomMembersModerationView_Night_4_en",19923,], -["features.roomdetails.impl.members.moderation_RoomMembersModerationView_Day_5_en","features.roomdetails.impl.members.moderation_RoomMembersModerationView_Night_5_en",19923,], -["features.roomdetails.impl.members.moderation_RoomMembersModerationView_Day_6_en","features.roomdetails.impl.members.moderation_RoomMembersModerationView_Night_6_en",19923,], -["features.roomdetails.impl.members.moderation_RoomMembersModerationView_Day_7_en","features.roomdetails.impl.members.moderation_RoomMembersModerationView_Night_7_en",19923,], -["features.roomdetails.impl.members.moderation_RoomMembersModerationView_Day_8_en","features.roomdetails.impl.members.moderation_RoomMembersModerationView_Night_8_en",19923,], +["features.roomdetails.impl.members.moderation_RoomMembersModerationView_Day_0_en","features.roomdetails.impl.members.moderation_RoomMembersModerationView_Night_0_en",19944,], +["features.roomdetails.impl.members.moderation_RoomMembersModerationView_Day_1_en","features.roomdetails.impl.members.moderation_RoomMembersModerationView_Night_1_en",19944,], +["features.roomdetails.impl.members.moderation_RoomMembersModerationView_Day_2_en","features.roomdetails.impl.members.moderation_RoomMembersModerationView_Night_2_en",19944,], +["features.roomdetails.impl.members.moderation_RoomMembersModerationView_Day_3_en","features.roomdetails.impl.members.moderation_RoomMembersModerationView_Night_3_en",19944,], +["features.roomdetails.impl.members.moderation_RoomMembersModerationView_Day_4_en","features.roomdetails.impl.members.moderation_RoomMembersModerationView_Night_4_en",19944,], +["features.roomdetails.impl.members.moderation_RoomMembersModerationView_Day_5_en","features.roomdetails.impl.members.moderation_RoomMembersModerationView_Night_5_en",19944,], +["features.roomdetails.impl.members.moderation_RoomMembersModerationView_Day_6_en","features.roomdetails.impl.members.moderation_RoomMembersModerationView_Night_6_en",19944,], +["features.roomdetails.impl.members.moderation_RoomMembersModerationView_Day_7_en","features.roomdetails.impl.members.moderation_RoomMembersModerationView_Night_7_en",19944,], +["features.roomdetails.impl.members.moderation_RoomMembersModerationView_Day_8_en","features.roomdetails.impl.members.moderation_RoomMembersModerationView_Night_8_en",19944,], ["features.roomdetails.impl.members.moderation_RoomMembersModerationView_Day_9_en","features.roomdetails.impl.members.moderation_RoomMembersModerationView_Night_9_en",0,], -["features.roomdetails.impl.notificationsettings_RoomNotificationSettingsOption_Day_0_en","features.roomdetails.impl.notificationsettings_RoomNotificationSettingsOption_Night_0_en",19923,], -["features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Day_0_en","features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Night_0_en",19923,], -["features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Day_1_en","features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Night_1_en",19923,], -["features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Day_2_en","features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Night_2_en",19923,], -["features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Day_3_en","features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Night_3_en",19923,], -["features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Day_4_en","features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Night_4_en",19923,], -["features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Day_5_en","features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Night_5_en",19923,], -["features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Day_6_en","features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Night_6_en",19923,], -["features.createroom.impl.components_RoomPrivacyOption_Day_0_en","features.createroom.impl.components_RoomPrivacyOption_Night_0_en",19923,], -["libraries.roomselect.impl_RoomSelectView_Day_0_en","libraries.roomselect.impl_RoomSelectView_Night_0_en",19923,], -["libraries.roomselect.impl_RoomSelectView_Day_1_en","libraries.roomselect.impl_RoomSelectView_Night_1_en",19923,], -["libraries.roomselect.impl_RoomSelectView_Day_2_en","libraries.roomselect.impl_RoomSelectView_Night_2_en",19923,], -["libraries.roomselect.impl_RoomSelectView_Day_3_en","libraries.roomselect.impl_RoomSelectView_Night_3_en",19923,], -["libraries.roomselect.impl_RoomSelectView_Day_4_en","libraries.roomselect.impl_RoomSelectView_Night_4_en",19923,], -["libraries.roomselect.impl_RoomSelectView_Day_5_en","libraries.roomselect.impl_RoomSelectView_Night_5_en",19923,], +["features.roomdetails.impl.notificationsettings_RoomNotificationSettingsOption_Day_0_en","features.roomdetails.impl.notificationsettings_RoomNotificationSettingsOption_Night_0_en",19944,], +["features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Day_0_en","features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Night_0_en",19944,], +["features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Day_1_en","features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Night_1_en",19944,], +["features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Day_2_en","features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Night_2_en",19944,], +["features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Day_3_en","features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Night_3_en",19944,], +["features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Day_4_en","features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Night_4_en",19944,], +["features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Day_5_en","features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Night_5_en",19944,], +["features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Day_6_en","features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Night_6_en",19944,], +["features.createroom.impl.components_RoomPrivacyOption_Day_0_en","features.createroom.impl.components_RoomPrivacyOption_Night_0_en",19944,], +["libraries.roomselect.impl_RoomSelectView_Day_0_en","libraries.roomselect.impl_RoomSelectView_Night_0_en",19944,], +["libraries.roomselect.impl_RoomSelectView_Day_1_en","libraries.roomselect.impl_RoomSelectView_Night_1_en",19944,], +["libraries.roomselect.impl_RoomSelectView_Day_2_en","libraries.roomselect.impl_RoomSelectView_Night_2_en",19944,], +["libraries.roomselect.impl_RoomSelectView_Day_3_en","libraries.roomselect.impl_RoomSelectView_Night_3_en",19944,], +["libraries.roomselect.impl_RoomSelectView_Day_4_en","libraries.roomselect.impl_RoomSelectView_Night_4_en",19944,], +["libraries.roomselect.impl_RoomSelectView_Day_5_en","libraries.roomselect.impl_RoomSelectView_Night_5_en",19944,], ["features.roomlist.impl.components_RoomSummaryPlaceholderRow_Day_0_en","features.roomlist.impl.components_RoomSummaryPlaceholderRow_Night_0_en",0,], ["features.roomlist.impl.components_RoomSummaryRow_Day_0_en","features.roomlist.impl.components_RoomSummaryRow_Night_0_en",0,], ["features.roomlist.impl.components_RoomSummaryRow_Day_10_en","features.roomlist.impl.components_RoomSummaryRow_Night_10_en",0,], @@ -764,10 +775,10 @@ export const screenshots = [ ["features.roomlist.impl.components_RoomSummaryRow_Day_26_en","features.roomlist.impl.components_RoomSummaryRow_Night_26_en",0,], ["features.roomlist.impl.components_RoomSummaryRow_Day_27_en","features.roomlist.impl.components_RoomSummaryRow_Night_27_en",0,], ["features.roomlist.impl.components_RoomSummaryRow_Day_28_en","features.roomlist.impl.components_RoomSummaryRow_Night_28_en",0,], -["features.roomlist.impl.components_RoomSummaryRow_Day_29_en","features.roomlist.impl.components_RoomSummaryRow_Night_29_en",19923,], -["features.roomlist.impl.components_RoomSummaryRow_Day_2_en","features.roomlist.impl.components_RoomSummaryRow_Night_2_en",19923,], -["features.roomlist.impl.components_RoomSummaryRow_Day_30_en","features.roomlist.impl.components_RoomSummaryRow_Night_30_en",19923,], -["features.roomlist.impl.components_RoomSummaryRow_Day_31_en","features.roomlist.impl.components_RoomSummaryRow_Night_31_en",19923,], +["features.roomlist.impl.components_RoomSummaryRow_Day_29_en","features.roomlist.impl.components_RoomSummaryRow_Night_29_en",19944,], +["features.roomlist.impl.components_RoomSummaryRow_Day_2_en","features.roomlist.impl.components_RoomSummaryRow_Night_2_en",19944,], +["features.roomlist.impl.components_RoomSummaryRow_Day_30_en","features.roomlist.impl.components_RoomSummaryRow_Night_30_en",19944,], +["features.roomlist.impl.components_RoomSummaryRow_Day_31_en","features.roomlist.impl.components_RoomSummaryRow_Night_31_en",19944,], ["features.roomlist.impl.components_RoomSummaryRow_Day_3_en","features.roomlist.impl.components_RoomSummaryRow_Night_3_en",0,], ["features.roomlist.impl.components_RoomSummaryRow_Day_4_en","features.roomlist.impl.components_RoomSummaryRow_Night_4_en",0,], ["features.roomlist.impl.components_RoomSummaryRow_Day_5_en","features.roomlist.impl.components_RoomSummaryRow_Night_5_en",0,], @@ -775,64 +786,64 @@ export const screenshots = [ ["features.roomlist.impl.components_RoomSummaryRow_Day_7_en","features.roomlist.impl.components_RoomSummaryRow_Night_7_en",0,], ["features.roomlist.impl.components_RoomSummaryRow_Day_8_en","features.roomlist.impl.components_RoomSummaryRow_Night_8_en",0,], ["features.roomlist.impl.components_RoomSummaryRow_Day_9_en","features.roomlist.impl.components_RoomSummaryRow_Night_9_en",0,], -["appnav.root_RootView_Day_0_en","appnav.root_RootView_Night_0_en",19923,], -["appnav.root_RootView_Day_1_en","appnav.root_RootView_Night_1_en",19923,], -["appnav.root_RootView_Day_2_en","appnav.root_RootView_Night_2_en",19923,], -["appicon.enterprise_RoundIcon_en","",0,], +["appnav.root_RootView_Day_0_en","appnav.root_RootView_Night_0_en",19944,], +["appnav.root_RootView_Day_1_en","appnav.root_RootView_Night_1_en",19944,], +["appnav.root_RootView_Day_2_en","appnav.root_RootView_Night_2_en",19944,], ["appicon.element_RoundIcon_en","",0,], +["appicon.enterprise_RoundIcon_en","",0,], ["libraries.designsystem.atomic.atoms_RoundedIconAtom_Day_0_en","libraries.designsystem.atomic.atoms_RoundedIconAtom_Night_0_en",0,], -["features.verifysession.impl.emoji_SasEmojis_Day_0_en","features.verifysession.impl.emoji_SasEmojis_Night_0_en",19923,], -["features.login.impl.screens.searchaccountprovider_SearchAccountProviderView_Day_0_en","features.login.impl.screens.searchaccountprovider_SearchAccountProviderView_Night_0_en",19923,], -["features.login.impl.screens.searchaccountprovider_SearchAccountProviderView_Day_1_en","features.login.impl.screens.searchaccountprovider_SearchAccountProviderView_Night_1_en",19923,], +["features.verifysession.impl.emoji_SasEmojis_Day_0_en","features.verifysession.impl.emoji_SasEmojis_Night_0_en",19944,], +["features.login.impl.screens.searchaccountprovider_SearchAccountProviderView_Day_0_en","features.login.impl.screens.searchaccountprovider_SearchAccountProviderView_Night_0_en",19944,], +["features.login.impl.screens.searchaccountprovider_SearchAccountProviderView_Day_1_en","features.login.impl.screens.searchaccountprovider_SearchAccountProviderView_Night_1_en",19944,], ["libraries.designsystem.theme.components_SearchBarActiveNoneQuery_Search views_en","",0,], ["libraries.designsystem.theme.components_SearchBarActiveWithContent_Search views_en","",0,], -["libraries.designsystem.theme.components_SearchBarActiveWithNoResults_Search views_en","",19923,], +["libraries.designsystem.theme.components_SearchBarActiveWithNoResults_Search views_en","",19944,], ["libraries.designsystem.theme.components_SearchBarActiveWithQueryNoBackButton_Search views_en","",0,], ["libraries.designsystem.theme.components_SearchBarActiveWithQuery_Search views_en","",0,], ["libraries.designsystem.theme.components_SearchBarInactive_Search views_en","",0,], -["features.createroom.impl.components_SearchMultipleUsersResultItem_en","",19923,], -["features.createroom.impl.components_SearchSingleUserResultItem_en","",19923,], -["features.securebackup.impl.disable_SecureBackupDisableView_Day_0_en","features.securebackup.impl.disable_SecureBackupDisableView_Night_0_en",19923,], -["features.securebackup.impl.disable_SecureBackupDisableView_Day_1_en","features.securebackup.impl.disable_SecureBackupDisableView_Night_1_en",19923,], -["features.securebackup.impl.disable_SecureBackupDisableView_Day_2_en","features.securebackup.impl.disable_SecureBackupDisableView_Night_2_en",19923,], -["features.securebackup.impl.disable_SecureBackupDisableView_Day_3_en","features.securebackup.impl.disable_SecureBackupDisableView_Night_3_en",19923,], -["features.securebackup.impl.enable_SecureBackupEnableView_Day_0_en","features.securebackup.impl.enable_SecureBackupEnableView_Night_0_en",19923,], -["features.securebackup.impl.enable_SecureBackupEnableView_Day_1_en","features.securebackup.impl.enable_SecureBackupEnableView_Night_1_en",19923,], -["features.securebackup.impl.enable_SecureBackupEnableView_Day_2_en","features.securebackup.impl.enable_SecureBackupEnableView_Night_2_en",19923,], -["features.securebackup.impl.enter_SecureBackupEnterRecoveryKeyView_Day_0_en","features.securebackup.impl.enter_SecureBackupEnterRecoveryKeyView_Night_0_en",19923,], -["features.securebackup.impl.enter_SecureBackupEnterRecoveryKeyView_Day_1_en","features.securebackup.impl.enter_SecureBackupEnterRecoveryKeyView_Night_1_en",19923,], -["features.securebackup.impl.enter_SecureBackupEnterRecoveryKeyView_Day_2_en","features.securebackup.impl.enter_SecureBackupEnterRecoveryKeyView_Night_2_en",19923,], -["features.securebackup.impl.enter_SecureBackupEnterRecoveryKeyView_Day_3_en","features.securebackup.impl.enter_SecureBackupEnterRecoveryKeyView_Night_3_en",19923,], -["features.securebackup.impl.root_SecureBackupRootView_Day_0_en","features.securebackup.impl.root_SecureBackupRootView_Night_0_en",19923,], -["features.securebackup.impl.root_SecureBackupRootView_Day_1_en","features.securebackup.impl.root_SecureBackupRootView_Night_1_en",19923,], -["features.securebackup.impl.root_SecureBackupRootView_Day_2_en","features.securebackup.impl.root_SecureBackupRootView_Night_2_en",19923,], -["features.securebackup.impl.root_SecureBackupRootView_Day_3_en","features.securebackup.impl.root_SecureBackupRootView_Night_3_en",19923,], -["features.securebackup.impl.root_SecureBackupRootView_Day_4_en","features.securebackup.impl.root_SecureBackupRootView_Night_4_en",19923,], -["features.securebackup.impl.root_SecureBackupRootView_Day_5_en","features.securebackup.impl.root_SecureBackupRootView_Night_5_en",19923,], -["features.securebackup.impl.root_SecureBackupRootView_Day_6_en","features.securebackup.impl.root_SecureBackupRootView_Night_6_en",19923,], -["features.securebackup.impl.root_SecureBackupRootView_Day_7_en","features.securebackup.impl.root_SecureBackupRootView_Night_7_en",19923,], -["features.securebackup.impl.root_SecureBackupRootView_Day_8_en","features.securebackup.impl.root_SecureBackupRootView_Night_8_en",19923,], -["features.securebackup.impl.setup_SecureBackupSetupViewChange_Day_0_en","features.securebackup.impl.setup_SecureBackupSetupViewChange_Night_0_en",19923,], -["features.securebackup.impl.setup_SecureBackupSetupViewChange_Day_1_en","features.securebackup.impl.setup_SecureBackupSetupViewChange_Night_1_en",19923,], -["features.securebackup.impl.setup_SecureBackupSetupViewChange_Day_2_en","features.securebackup.impl.setup_SecureBackupSetupViewChange_Night_2_en",19923,], -["features.securebackup.impl.setup_SecureBackupSetupViewChange_Day_3_en","features.securebackup.impl.setup_SecureBackupSetupViewChange_Night_3_en",19923,], -["features.securebackup.impl.setup_SecureBackupSetupViewChange_Day_4_en","features.securebackup.impl.setup_SecureBackupSetupViewChange_Night_4_en",19923,], -["features.securebackup.impl.setup_SecureBackupSetupView_Day_0_en","features.securebackup.impl.setup_SecureBackupSetupView_Night_0_en",19923,], -["features.securebackup.impl.setup_SecureBackupSetupView_Day_1_en","features.securebackup.impl.setup_SecureBackupSetupView_Night_1_en",19923,], -["features.securebackup.impl.setup_SecureBackupSetupView_Day_2_en","features.securebackup.impl.setup_SecureBackupSetupView_Night_2_en",19923,], -["features.securebackup.impl.setup_SecureBackupSetupView_Day_3_en","features.securebackup.impl.setup_SecureBackupSetupView_Night_3_en",19923,], -["features.securebackup.impl.setup_SecureBackupSetupView_Day_4_en","features.securebackup.impl.setup_SecureBackupSetupView_Night_4_en",19923,], +["features.createroom.impl.components_SearchMultipleUsersResultItem_en","",19944,], +["features.createroom.impl.components_SearchSingleUserResultItem_en","",19944,], +["features.securebackup.impl.disable_SecureBackupDisableView_Day_0_en","features.securebackup.impl.disable_SecureBackupDisableView_Night_0_en",19944,], +["features.securebackup.impl.disable_SecureBackupDisableView_Day_1_en","features.securebackup.impl.disable_SecureBackupDisableView_Night_1_en",19944,], +["features.securebackup.impl.disable_SecureBackupDisableView_Day_2_en","features.securebackup.impl.disable_SecureBackupDisableView_Night_2_en",19944,], +["features.securebackup.impl.disable_SecureBackupDisableView_Day_3_en","features.securebackup.impl.disable_SecureBackupDisableView_Night_3_en",19944,], +["features.securebackup.impl.enable_SecureBackupEnableView_Day_0_en","features.securebackup.impl.enable_SecureBackupEnableView_Night_0_en",19944,], +["features.securebackup.impl.enable_SecureBackupEnableView_Day_1_en","features.securebackup.impl.enable_SecureBackupEnableView_Night_1_en",19944,], +["features.securebackup.impl.enable_SecureBackupEnableView_Day_2_en","features.securebackup.impl.enable_SecureBackupEnableView_Night_2_en",19944,], +["features.securebackup.impl.enter_SecureBackupEnterRecoveryKeyView_Day_0_en","features.securebackup.impl.enter_SecureBackupEnterRecoveryKeyView_Night_0_en",19944,], +["features.securebackup.impl.enter_SecureBackupEnterRecoveryKeyView_Day_1_en","features.securebackup.impl.enter_SecureBackupEnterRecoveryKeyView_Night_1_en",19944,], +["features.securebackup.impl.enter_SecureBackupEnterRecoveryKeyView_Day_2_en","features.securebackup.impl.enter_SecureBackupEnterRecoveryKeyView_Night_2_en",19944,], +["features.securebackup.impl.enter_SecureBackupEnterRecoveryKeyView_Day_3_en","features.securebackup.impl.enter_SecureBackupEnterRecoveryKeyView_Night_3_en",19944,], +["features.securebackup.impl.root_SecureBackupRootView_Day_0_en","features.securebackup.impl.root_SecureBackupRootView_Night_0_en",19944,], +["features.securebackup.impl.root_SecureBackupRootView_Day_1_en","features.securebackup.impl.root_SecureBackupRootView_Night_1_en",19944,], +["features.securebackup.impl.root_SecureBackupRootView_Day_2_en","features.securebackup.impl.root_SecureBackupRootView_Night_2_en",19944,], +["features.securebackup.impl.root_SecureBackupRootView_Day_3_en","features.securebackup.impl.root_SecureBackupRootView_Night_3_en",19944,], +["features.securebackup.impl.root_SecureBackupRootView_Day_4_en","features.securebackup.impl.root_SecureBackupRootView_Night_4_en",19944,], +["features.securebackup.impl.root_SecureBackupRootView_Day_5_en","features.securebackup.impl.root_SecureBackupRootView_Night_5_en",19944,], +["features.securebackup.impl.root_SecureBackupRootView_Day_6_en","features.securebackup.impl.root_SecureBackupRootView_Night_6_en",19944,], +["features.securebackup.impl.root_SecureBackupRootView_Day_7_en","features.securebackup.impl.root_SecureBackupRootView_Night_7_en",19944,], +["features.securebackup.impl.root_SecureBackupRootView_Day_8_en","features.securebackup.impl.root_SecureBackupRootView_Night_8_en",19944,], +["features.securebackup.impl.setup_SecureBackupSetupViewChange_Day_0_en","features.securebackup.impl.setup_SecureBackupSetupViewChange_Night_0_en",19944,], +["features.securebackup.impl.setup_SecureBackupSetupViewChange_Day_1_en","features.securebackup.impl.setup_SecureBackupSetupViewChange_Night_1_en",19944,], +["features.securebackup.impl.setup_SecureBackupSetupViewChange_Day_2_en","features.securebackup.impl.setup_SecureBackupSetupViewChange_Night_2_en",19944,], +["features.securebackup.impl.setup_SecureBackupSetupViewChange_Day_3_en","features.securebackup.impl.setup_SecureBackupSetupViewChange_Night_3_en",19944,], +["features.securebackup.impl.setup_SecureBackupSetupViewChange_Day_4_en","features.securebackup.impl.setup_SecureBackupSetupViewChange_Night_4_en",19944,], +["features.securebackup.impl.setup_SecureBackupSetupView_Day_0_en","features.securebackup.impl.setup_SecureBackupSetupView_Night_0_en",19944,], +["features.securebackup.impl.setup_SecureBackupSetupView_Day_1_en","features.securebackup.impl.setup_SecureBackupSetupView_Night_1_en",19944,], +["features.securebackup.impl.setup_SecureBackupSetupView_Day_2_en","features.securebackup.impl.setup_SecureBackupSetupView_Night_2_en",19944,], +["features.securebackup.impl.setup_SecureBackupSetupView_Day_3_en","features.securebackup.impl.setup_SecureBackupSetupView_Night_3_en",19944,], +["features.securebackup.impl.setup_SecureBackupSetupView_Day_4_en","features.securebackup.impl.setup_SecureBackupSetupView_Night_4_en",19944,], ["libraries.matrix.ui.components_SelectedRoom_Day_0_en","libraries.matrix.ui.components_SelectedRoom_Night_0_en",0,], ["libraries.matrix.ui.components_SelectedRoom_Day_1_en","libraries.matrix.ui.components_SelectedRoom_Night_1_en",0,], ["libraries.matrix.ui.components_SelectedUserCannotRemove_Day_0_en","libraries.matrix.ui.components_SelectedUserCannotRemove_Night_0_en",0,], ["libraries.matrix.ui.components_SelectedUser_Day_0_en","libraries.matrix.ui.components_SelectedUser_Night_0_en",0,], ["libraries.matrix.ui.components_SelectedUsersRowList_Day_0_en","libraries.matrix.ui.components_SelectedUsersRowList_Night_0_en",0,], ["libraries.textcomposer.components_SendButton_Day_0_en","libraries.textcomposer.components_SendButton_Night_0_en",0,], -["features.location.impl.send_SendLocationView_Day_0_en","features.location.impl.send_SendLocationView_Night_0_en",19923,], -["features.location.impl.send_SendLocationView_Day_1_en","features.location.impl.send_SendLocationView_Night_1_en",19923,], -["features.location.impl.send_SendLocationView_Day_2_en","features.location.impl.send_SendLocationView_Night_2_en",19923,], -["features.location.impl.send_SendLocationView_Day_3_en","features.location.impl.send_SendLocationView_Night_3_en",19923,], -["features.location.impl.send_SendLocationView_Day_4_en","features.location.impl.send_SendLocationView_Night_4_en",19923,], +["features.location.impl.send_SendLocationView_Day_0_en","features.location.impl.send_SendLocationView_Night_0_en",19944,], +["features.location.impl.send_SendLocationView_Day_1_en","features.location.impl.send_SendLocationView_Night_1_en",19944,], +["features.location.impl.send_SendLocationView_Day_2_en","features.location.impl.send_SendLocationView_Night_2_en",19944,], +["features.location.impl.send_SendLocationView_Day_3_en","features.location.impl.send_SendLocationView_Night_3_en",19944,], +["features.location.impl.send_SendLocationView_Day_4_en","features.location.impl.send_SendLocationView_Night_4_en",19944,], ["libraries.matrix.ui.messages.sender_SenderName_Day_0_en","libraries.matrix.ui.messages.sender_SenderName_Night_0_en",0,], ["libraries.matrix.ui.messages.sender_SenderName_Day_1_en","libraries.matrix.ui.messages.sender_SenderName_Night_1_en",0,], ["libraries.matrix.ui.messages.sender_SenderName_Day_2_en","libraries.matrix.ui.messages.sender_SenderName_Night_2_en",0,], @@ -842,37 +853,37 @@ export const screenshots = [ ["libraries.matrix.ui.messages.sender_SenderName_Day_6_en","libraries.matrix.ui.messages.sender_SenderName_Night_6_en",0,], ["libraries.matrix.ui.messages.sender_SenderName_Day_7_en","libraries.matrix.ui.messages.sender_SenderName_Night_7_en",0,], ["libraries.matrix.ui.messages.sender_SenderName_Day_8_en","libraries.matrix.ui.messages.sender_SenderName_Night_8_en",0,], -["features.lockscreen.impl.setup.biometric_SetupBiometricView_Day_0_en","features.lockscreen.impl.setup.biometric_SetupBiometricView_Night_0_en",19923,], -["features.lockscreen.impl.setup.pin_SetupPinView_Day_0_en","features.lockscreen.impl.setup.pin_SetupPinView_Night_0_en",19923,], -["features.lockscreen.impl.setup.pin_SetupPinView_Day_1_en","features.lockscreen.impl.setup.pin_SetupPinView_Night_1_en",19923,], -["features.lockscreen.impl.setup.pin_SetupPinView_Day_2_en","features.lockscreen.impl.setup.pin_SetupPinView_Night_2_en",19923,], -["features.lockscreen.impl.setup.pin_SetupPinView_Day_3_en","features.lockscreen.impl.setup.pin_SetupPinView_Night_3_en",19923,], -["features.lockscreen.impl.setup.pin_SetupPinView_Day_4_en","features.lockscreen.impl.setup.pin_SetupPinView_Night_4_en",19923,], +["features.lockscreen.impl.setup.biometric_SetupBiometricView_Day_0_en","features.lockscreen.impl.setup.biometric_SetupBiometricView_Night_0_en",19944,], +["features.lockscreen.impl.setup.pin_SetupPinView_Day_0_en","features.lockscreen.impl.setup.pin_SetupPinView_Night_0_en",19944,], +["features.lockscreen.impl.setup.pin_SetupPinView_Day_1_en","features.lockscreen.impl.setup.pin_SetupPinView_Night_1_en",19944,], +["features.lockscreen.impl.setup.pin_SetupPinView_Day_2_en","features.lockscreen.impl.setup.pin_SetupPinView_Night_2_en",19944,], +["features.lockscreen.impl.setup.pin_SetupPinView_Day_3_en","features.lockscreen.impl.setup.pin_SetupPinView_Night_3_en",19944,], +["features.lockscreen.impl.setup.pin_SetupPinView_Day_4_en","features.lockscreen.impl.setup.pin_SetupPinView_Night_4_en",19944,], ["features.share.impl_ShareView_Day_0_en","features.share.impl_ShareView_Night_0_en",0,], ["features.share.impl_ShareView_Day_1_en","features.share.impl_ShareView_Night_1_en",0,], ["features.share.impl_ShareView_Day_2_en","features.share.impl_ShareView_Night_2_en",0,], -["features.share.impl_ShareView_Day_3_en","features.share.impl_ShareView_Night_3_en",19923,], -["features.messages.impl.actionlist_SheetContent_Day_0_en","features.messages.impl.actionlist_SheetContent_Night_0_en",0,], +["features.share.impl_ShareView_Day_3_en","features.share.impl_ShareView_Night_3_en",19944,], ["features.messages.impl.timeline.components.reactionsummary_SheetContent_Day_0_en","features.messages.impl.timeline.components.reactionsummary_SheetContent_Night_0_en",0,], -["features.messages.impl.actionlist_SheetContent_Day_10_en","features.messages.impl.actionlist_SheetContent_Night_10_en",19923,], +["features.messages.impl.actionlist_SheetContent_Day_0_en","features.messages.impl.actionlist_SheetContent_Night_0_en",0,], +["features.messages.impl.actionlist_SheetContent_Day_10_en","features.messages.impl.actionlist_SheetContent_Night_10_en",19944,], ["features.messages.impl.actionlist_SheetContent_Day_1_en","features.messages.impl.actionlist_SheetContent_Night_1_en",0,], -["features.messages.impl.actionlist_SheetContent_Day_2_en","features.messages.impl.actionlist_SheetContent_Night_2_en",19923,], -["features.messages.impl.actionlist_SheetContent_Day_3_en","features.messages.impl.actionlist_SheetContent_Night_3_en",19923,], -["features.messages.impl.actionlist_SheetContent_Day_4_en","features.messages.impl.actionlist_SheetContent_Night_4_en",19923,], -["features.messages.impl.actionlist_SheetContent_Day_5_en","features.messages.impl.actionlist_SheetContent_Night_5_en",19923,], -["features.messages.impl.actionlist_SheetContent_Day_6_en","features.messages.impl.actionlist_SheetContent_Night_6_en",19923,], -["features.messages.impl.actionlist_SheetContent_Day_7_en","features.messages.impl.actionlist_SheetContent_Night_7_en",19923,], -["features.messages.impl.actionlist_SheetContent_Day_8_en","features.messages.impl.actionlist_SheetContent_Night_8_en",19923,], -["features.messages.impl.actionlist_SheetContent_Day_9_en","features.messages.impl.actionlist_SheetContent_Night_9_en",19923,], -["features.location.impl.show_ShowLocationView_Day_0_en","features.location.impl.show_ShowLocationView_Night_0_en",19923,], -["features.location.impl.show_ShowLocationView_Day_1_en","features.location.impl.show_ShowLocationView_Night_1_en",19923,], -["features.location.impl.show_ShowLocationView_Day_2_en","features.location.impl.show_ShowLocationView_Night_2_en",19923,], -["features.location.impl.show_ShowLocationView_Day_3_en","features.location.impl.show_ShowLocationView_Night_3_en",19923,], -["features.location.impl.show_ShowLocationView_Day_4_en","features.location.impl.show_ShowLocationView_Night_4_en",19923,], -["features.location.impl.show_ShowLocationView_Day_5_en","features.location.impl.show_ShowLocationView_Night_5_en",19923,], -["features.location.impl.show_ShowLocationView_Day_6_en","features.location.impl.show_ShowLocationView_Night_6_en",19923,], -["features.location.impl.show_ShowLocationView_Day_7_en","features.location.impl.show_ShowLocationView_Night_7_en",19923,], -["features.signedout.impl_SignedOutView_Day_0_en","features.signedout.impl_SignedOutView_Night_0_en",19923,], +["features.messages.impl.actionlist_SheetContent_Day_2_en","features.messages.impl.actionlist_SheetContent_Night_2_en",19944,], +["features.messages.impl.actionlist_SheetContent_Day_3_en","features.messages.impl.actionlist_SheetContent_Night_3_en",19944,], +["features.messages.impl.actionlist_SheetContent_Day_4_en","features.messages.impl.actionlist_SheetContent_Night_4_en",19944,], +["features.messages.impl.actionlist_SheetContent_Day_5_en","features.messages.impl.actionlist_SheetContent_Night_5_en",19944,], +["features.messages.impl.actionlist_SheetContent_Day_6_en","features.messages.impl.actionlist_SheetContent_Night_6_en",19944,], +["features.messages.impl.actionlist_SheetContent_Day_7_en","features.messages.impl.actionlist_SheetContent_Night_7_en",19944,], +["features.messages.impl.actionlist_SheetContent_Day_8_en","features.messages.impl.actionlist_SheetContent_Night_8_en",19944,], +["features.messages.impl.actionlist_SheetContent_Day_9_en","features.messages.impl.actionlist_SheetContent_Night_9_en",19944,], +["features.location.impl.show_ShowLocationView_Day_0_en","features.location.impl.show_ShowLocationView_Night_0_en",19944,], +["features.location.impl.show_ShowLocationView_Day_1_en","features.location.impl.show_ShowLocationView_Night_1_en",19944,], +["features.location.impl.show_ShowLocationView_Day_2_en","features.location.impl.show_ShowLocationView_Night_2_en",19944,], +["features.location.impl.show_ShowLocationView_Day_3_en","features.location.impl.show_ShowLocationView_Night_3_en",19944,], +["features.location.impl.show_ShowLocationView_Day_4_en","features.location.impl.show_ShowLocationView_Night_4_en",19944,], +["features.location.impl.show_ShowLocationView_Day_5_en","features.location.impl.show_ShowLocationView_Night_5_en",19944,], +["features.location.impl.show_ShowLocationView_Day_6_en","features.location.impl.show_ShowLocationView_Night_6_en",19944,], +["features.location.impl.show_ShowLocationView_Day_7_en","features.location.impl.show_ShowLocationView_Night_7_en",19944,], +["features.signedout.impl_SignedOutView_Day_0_en","features.signedout.impl_SignedOutView_Night_0_en",19944,], ["libraries.designsystem.components.dialogs_SingleSelectionDialogContent_Dialogs_en","",0,], ["libraries.designsystem.components.dialogs_SingleSelectionDialog_Day_0_en","libraries.designsystem.components.dialogs_SingleSelectionDialog_Night_0_en",0,], ["libraries.designsystem.components.list_SingleSelectionListItemCustomFormattert_Single selection List item - custom formatter_List items_en","",0,], @@ -881,7 +892,7 @@ export const screenshots = [ ["libraries.designsystem.components.list_SingleSelectionListItemUnselectedWithSupportingText_Single selection List item - no selection, supporting text_List items_en","",0,], ["libraries.designsystem.components.list_SingleSelectionListItem_Single selection List item - no selection_List items_en","",0,], ["libraries.designsystem.theme.components_Sliders_Sliders_en","",0,], -["features.login.impl.dialogs_SlidingSyncNotSupportedDialog_Day_0_en","features.login.impl.dialogs_SlidingSyncNotSupportedDialog_Night_0_en",19923,], +["features.login.impl.dialogs_SlidingSyncNotSupportedDialog_Day_0_en","features.login.impl.dialogs_SlidingSyncNotSupportedDialog_Night_0_en",19944,], ["libraries.designsystem.theme.components_SnackbarWithActionAndCloseButton_Snackbar with action and close button_Snackbars_en","",0,], ["libraries.designsystem.theme.components_SnackbarWithActionOnNewLineAndCloseButton_Snackbar with action and close button on new line_Snackbars_en","",0,], ["libraries.designsystem.theme.components_SnackbarWithActionOnNewLine_Snackbar with action on new line_Snackbars_en","",0,], @@ -891,36 +902,36 @@ export const screenshots = [ ["libraries.designsystem.modifiers_SquareSizeModifierLargeHeight_en","",0,], ["libraries.designsystem.modifiers_SquareSizeModifierLargeWidth_en","",0,], ["features.location.api.internal_StaticMapPlaceholder_Day_0_en","features.location.api.internal_StaticMapPlaceholder_Night_0_en",0,], -["features.location.api.internal_StaticMapPlaceholder_Day_1_en","features.location.api.internal_StaticMapPlaceholder_Night_1_en",19923,], +["features.location.api.internal_StaticMapPlaceholder_Day_1_en","features.location.api.internal_StaticMapPlaceholder_Night_1_en",19944,], ["features.location.api_StaticMapView_Day_0_en","features.location.api_StaticMapView_Night_0_en",0,], ["libraries.designsystem.atomic.pages_SunsetPage_Day_0_en","libraries.designsystem.atomic.pages_SunsetPage_Night_0_en",0,], ["libraries.designsystem.components.button_SuperButton_Day_0_en","libraries.designsystem.components.button_SuperButton_Night_0_en",0,], ["libraries.designsystem.theme.components_Surface_en","",0,], ["libraries.designsystem.theme.components_Switch_Toggles_en","",0,], -["appnav.loggedin_SyncStateView_Day_0_en","appnav.loggedin_SyncStateView_Night_0_en",19923,], +["appnav.loggedin_SyncStateView_Day_0_en","appnav.loggedin_SyncStateView_Night_0_en",19944,], ["libraries.designsystem.theme.components_TextButtonLargeLowPadding_Buttons_en","",0,], ["libraries.designsystem.theme.components_TextButtonLarge_Buttons_en","",0,], ["libraries.designsystem.theme.components_TextButtonMediumLowPadding_Buttons_en","",0,], ["libraries.designsystem.theme.components_TextButtonMedium_Buttons_en","",0,], ["libraries.designsystem.theme.components_TextButtonSmall_Buttons_en","",0,], -["libraries.textcomposer_TextComposerEdit_Day_0_en","libraries.textcomposer_TextComposerEdit_Night_0_en",19923,], -["libraries.textcomposer_TextComposerFormatting_Day_0_en","libraries.textcomposer_TextComposerFormatting_Night_0_en",19923,], -["libraries.textcomposer_TextComposerLinkDialogCreateLinkWithoutText_Day_0_en","libraries.textcomposer_TextComposerLinkDialogCreateLinkWithoutText_Night_0_en",19923,], -["libraries.textcomposer_TextComposerLinkDialogCreateLink_Day_0_en","libraries.textcomposer_TextComposerLinkDialogCreateLink_Night_0_en",19923,], -["libraries.textcomposer_TextComposerLinkDialogEditLink_Day_0_en","libraries.textcomposer_TextComposerLinkDialogEditLink_Night_0_en",19923,], -["libraries.textcomposer_TextComposerReply_Day_0_en","libraries.textcomposer_TextComposerReply_Night_0_en",19923,], -["libraries.textcomposer_TextComposerReply_Day_10_en","libraries.textcomposer_TextComposerReply_Night_10_en",19923,], -["libraries.textcomposer_TextComposerReply_Day_11_en","libraries.textcomposer_TextComposerReply_Night_11_en",19923,], -["libraries.textcomposer_TextComposerReply_Day_1_en","libraries.textcomposer_TextComposerReply_Night_1_en",19923,], -["libraries.textcomposer_TextComposerReply_Day_2_en","libraries.textcomposer_TextComposerReply_Night_2_en",19923,], -["libraries.textcomposer_TextComposerReply_Day_3_en","libraries.textcomposer_TextComposerReply_Night_3_en",19923,], -["libraries.textcomposer_TextComposerReply_Day_4_en","libraries.textcomposer_TextComposerReply_Night_4_en",19923,], -["libraries.textcomposer_TextComposerReply_Day_5_en","libraries.textcomposer_TextComposerReply_Night_5_en",19923,], -["libraries.textcomposer_TextComposerReply_Day_6_en","libraries.textcomposer_TextComposerReply_Night_6_en",19923,], -["libraries.textcomposer_TextComposerReply_Day_7_en","libraries.textcomposer_TextComposerReply_Night_7_en",19923,], -["libraries.textcomposer_TextComposerReply_Day_8_en","libraries.textcomposer_TextComposerReply_Night_8_en",19923,], -["libraries.textcomposer_TextComposerReply_Day_9_en","libraries.textcomposer_TextComposerReply_Night_9_en",19923,], -["libraries.textcomposer_TextComposerSimple_Day_0_en","libraries.textcomposer_TextComposerSimple_Night_0_en",19923,], +["libraries.textcomposer_TextComposerEdit_Day_0_en","libraries.textcomposer_TextComposerEdit_Night_0_en",19944,], +["libraries.textcomposer_TextComposerFormatting_Day_0_en","libraries.textcomposer_TextComposerFormatting_Night_0_en",19944,], +["libraries.textcomposer_TextComposerLinkDialogCreateLinkWithoutText_Day_0_en","libraries.textcomposer_TextComposerLinkDialogCreateLinkWithoutText_Night_0_en",19944,], +["libraries.textcomposer_TextComposerLinkDialogCreateLink_Day_0_en","libraries.textcomposer_TextComposerLinkDialogCreateLink_Night_0_en",19944,], +["libraries.textcomposer_TextComposerLinkDialogEditLink_Day_0_en","libraries.textcomposer_TextComposerLinkDialogEditLink_Night_0_en",19944,], +["libraries.textcomposer_TextComposerReply_Day_0_en","libraries.textcomposer_TextComposerReply_Night_0_en",19944,], +["libraries.textcomposer_TextComposerReply_Day_10_en","libraries.textcomposer_TextComposerReply_Night_10_en",19944,], +["libraries.textcomposer_TextComposerReply_Day_11_en","libraries.textcomposer_TextComposerReply_Night_11_en",19944,], +["libraries.textcomposer_TextComposerReply_Day_1_en","libraries.textcomposer_TextComposerReply_Night_1_en",19944,], +["libraries.textcomposer_TextComposerReply_Day_2_en","libraries.textcomposer_TextComposerReply_Night_2_en",19944,], +["libraries.textcomposer_TextComposerReply_Day_3_en","libraries.textcomposer_TextComposerReply_Night_3_en",19944,], +["libraries.textcomposer_TextComposerReply_Day_4_en","libraries.textcomposer_TextComposerReply_Night_4_en",19944,], +["libraries.textcomposer_TextComposerReply_Day_5_en","libraries.textcomposer_TextComposerReply_Night_5_en",19944,], +["libraries.textcomposer_TextComposerReply_Day_6_en","libraries.textcomposer_TextComposerReply_Night_6_en",19944,], +["libraries.textcomposer_TextComposerReply_Day_7_en","libraries.textcomposer_TextComposerReply_Night_7_en",19944,], +["libraries.textcomposer_TextComposerReply_Day_8_en","libraries.textcomposer_TextComposerReply_Night_8_en",19944,], +["libraries.textcomposer_TextComposerReply_Day_9_en","libraries.textcomposer_TextComposerReply_Night_9_en",19944,], +["libraries.textcomposer_TextComposerSimple_Day_0_en","libraries.textcomposer_TextComposerSimple_Night_0_en",19944,], ["libraries.textcomposer_TextComposerVoice_Day_0_en","libraries.textcomposer_TextComposerVoice_Night_0_en",0,], ["libraries.designsystem.theme.components_TextDark_Text_en","",0,], ["libraries.designsystem.theme.components_TextFieldDark_TextFields_en","",0,], @@ -932,38 +943,38 @@ export const screenshots = [ ["libraries.designsystem.theme.components_TextFieldValueTextFieldDark_TextFields_en","",0,], ["libraries.textcomposer.components_TextFormatting_Day_0_en","libraries.textcomposer.components_TextFormatting_Night_0_en",0,], ["libraries.designsystem.theme.components_TextLight_Text_en","",0,], -["libraries.designsystem.theme.components.previews_TimePickerHorizontal_DateTime pickers_en","",19923,], -["libraries.designsystem.theme.components.previews_TimePickerVerticalDark_DateTime pickers_en","",19923,], -["libraries.designsystem.theme.components.previews_TimePickerVerticalLight_DateTime pickers_en","",19923,], +["libraries.designsystem.theme.components.previews_TimePickerHorizontal_DateTime pickers_en","",19944,], +["libraries.designsystem.theme.components.previews_TimePickerVerticalDark_DateTime pickers_en","",19944,], +["libraries.designsystem.theme.components.previews_TimePickerVerticalLight_DateTime pickers_en","",19944,], ["features.messages.impl.timeline.components_TimelineEventTimestampView_Day_0_en","features.messages.impl.timeline.components_TimelineEventTimestampView_Night_0_en",0,], ["features.messages.impl.timeline.components_TimelineEventTimestampView_Day_1_en","features.messages.impl.timeline.components_TimelineEventTimestampView_Night_1_en",0,], ["features.messages.impl.timeline.components_TimelineEventTimestampView_Day_2_en","features.messages.impl.timeline.components_TimelineEventTimestampView_Night_2_en",0,], -["features.messages.impl.timeline.components_TimelineEventTimestampView_Day_3_en","features.messages.impl.timeline.components_TimelineEventTimestampView_Night_3_en",19923,], -["features.messages.impl.timeline.components_TimelineEventTimestampView_Day_4_en","features.messages.impl.timeline.components_TimelineEventTimestampView_Night_4_en",19923,], +["features.messages.impl.timeline.components_TimelineEventTimestampView_Day_3_en","features.messages.impl.timeline.components_TimelineEventTimestampView_Night_3_en",19944,], +["features.messages.impl.timeline.components_TimelineEventTimestampView_Day_4_en","features.messages.impl.timeline.components_TimelineEventTimestampView_Night_4_en",19944,], ["features.messages.impl.timeline.components.event_TimelineImageWithCaptionRow_Day_0_en","features.messages.impl.timeline.components.event_TimelineImageWithCaptionRow_Night_0_en",0,], ["features.messages.impl.timeline.components.event_TimelineItemAudioView_Day_0_en","features.messages.impl.timeline.components.event_TimelineItemAudioView_Night_0_en",0,], ["features.messages.impl.timeline.components.event_TimelineItemAudioView_Day_1_en","features.messages.impl.timeline.components.event_TimelineItemAudioView_Night_1_en",0,], ["features.messages.impl.timeline.components.event_TimelineItemAudioView_Day_2_en","features.messages.impl.timeline.components.event_TimelineItemAudioView_Night_2_en",0,], -["features.messages.impl.timeline.components_TimelineItemCallNotifyView_Day_0_en","features.messages.impl.timeline.components_TimelineItemCallNotifyView_Night_0_en",19923,], +["features.messages.impl.timeline.components_TimelineItemCallNotifyView_Day_0_en","features.messages.impl.timeline.components_TimelineItemCallNotifyView_Night_0_en",19944,], ["features.messages.impl.timeline.components.virtual_TimelineItemDaySeparatorView_Day_0_en","features.messages.impl.timeline.components.virtual_TimelineItemDaySeparatorView_Night_0_en",0,], ["features.messages.impl.timeline.components.virtual_TimelineItemDaySeparatorView_Day_1_en","features.messages.impl.timeline.components.virtual_TimelineItemDaySeparatorView_Night_1_en",0,], -["features.messages.impl.timeline.components.event_TimelineItemEncryptedView_Day_0_en","features.messages.impl.timeline.components.event_TimelineItemEncryptedView_Night_0_en",19923,], -["features.messages.impl.timeline.components.event_TimelineItemEncryptedView_Day_1_en","features.messages.impl.timeline.components.event_TimelineItemEncryptedView_Night_1_en",19923,], -["features.messages.impl.timeline.components.event_TimelineItemEncryptedView_Day_2_en","features.messages.impl.timeline.components.event_TimelineItemEncryptedView_Night_2_en",19923,], +["features.messages.impl.timeline.components.event_TimelineItemEncryptedView_Day_0_en","features.messages.impl.timeline.components.event_TimelineItemEncryptedView_Night_0_en",19944,], +["features.messages.impl.timeline.components.event_TimelineItemEncryptedView_Day_1_en","features.messages.impl.timeline.components.event_TimelineItemEncryptedView_Night_1_en",19944,], +["features.messages.impl.timeline.components.event_TimelineItemEncryptedView_Day_2_en","features.messages.impl.timeline.components.event_TimelineItemEncryptedView_Night_2_en",19944,], ["features.messages.impl.timeline.components_TimelineItemEventRowDisambiguated_Day_0_en","features.messages.impl.timeline.components_TimelineItemEventRowDisambiguated_Night_0_en",0,], ["features.messages.impl.timeline.components_TimelineItemEventRowForDirectRoom_Day_0_en","features.messages.impl.timeline.components_TimelineItemEventRowForDirectRoom_Night_0_en",0,], ["features.messages.impl.timeline.components_TimelineItemEventRowLongSenderName_en","",0,], ["features.messages.impl.timeline.components_TimelineItemEventRowTimestamp_Day_0_en","features.messages.impl.timeline.components_TimelineItemEventRowTimestamp_Night_0_en",0,], ["features.messages.impl.timeline.components_TimelineItemEventRowTimestamp_Day_1_en","features.messages.impl.timeline.components_TimelineItemEventRowTimestamp_Night_1_en",0,], ["features.messages.impl.timeline.components_TimelineItemEventRowTimestamp_Day_2_en","features.messages.impl.timeline.components_TimelineItemEventRowTimestamp_Night_2_en",0,], -["features.messages.impl.timeline.components_TimelineItemEventRowTimestamp_Day_3_en","features.messages.impl.timeline.components_TimelineItemEventRowTimestamp_Night_3_en",19923,], -["features.messages.impl.timeline.components_TimelineItemEventRowTimestamp_Day_4_en","features.messages.impl.timeline.components_TimelineItemEventRowTimestamp_Night_4_en",19923,], -["features.messages.impl.timeline.components_TimelineItemEventRowWithManyReactions_Day_0_en","features.messages.impl.timeline.components_TimelineItemEventRowWithManyReactions_Night_0_en",19923,], +["features.messages.impl.timeline.components_TimelineItemEventRowTimestamp_Day_3_en","features.messages.impl.timeline.components_TimelineItemEventRowTimestamp_Night_3_en",19944,], +["features.messages.impl.timeline.components_TimelineItemEventRowTimestamp_Day_4_en","features.messages.impl.timeline.components_TimelineItemEventRowTimestamp_Night_4_en",19944,], +["features.messages.impl.timeline.components_TimelineItemEventRowWithManyReactions_Day_0_en","features.messages.impl.timeline.components_TimelineItemEventRowWithManyReactions_Night_0_en",19944,], ["features.messages.impl.timeline.components_TimelineItemEventRowWithRR_Day_0_en","features.messages.impl.timeline.components_TimelineItemEventRowWithRR_Night_0_en",0,], ["features.messages.impl.timeline.components_TimelineItemEventRowWithRR_Day_1_en","features.messages.impl.timeline.components_TimelineItemEventRowWithRR_Night_1_en",0,], ["features.messages.impl.timeline.components_TimelineItemEventRowWithRR_Day_2_en","features.messages.impl.timeline.components_TimelineItemEventRowWithRR_Night_2_en",0,], -["features.messages.impl.timeline.components_TimelineItemEventRowWithReplyInformative_Day_0_en","features.messages.impl.timeline.components_TimelineItemEventRowWithReplyInformative_Night_0_en",19923,], -["features.messages.impl.timeline.components_TimelineItemEventRowWithReplyInformative_Day_1_en","features.messages.impl.timeline.components_TimelineItemEventRowWithReplyInformative_Night_1_en",19923,], +["features.messages.impl.timeline.components_TimelineItemEventRowWithReplyInformative_Day_0_en","features.messages.impl.timeline.components_TimelineItemEventRowWithReplyInformative_Night_0_en",19944,], +["features.messages.impl.timeline.components_TimelineItemEventRowWithReplyInformative_Day_1_en","features.messages.impl.timeline.components_TimelineItemEventRowWithReplyInformative_Night_1_en",19944,], ["features.messages.impl.timeline.components_TimelineItemEventRowWithReplyOther_Day_0_en","features.messages.impl.timeline.components_TimelineItemEventRowWithReplyOther_Night_0_en",0,], ["features.messages.impl.timeline.components_TimelineItemEventRowWithReplyOther_Day_1_en","features.messages.impl.timeline.components_TimelineItemEventRowWithReplyOther_Night_1_en",0,], ["features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Day_0_en","features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Night_0_en",0,], @@ -972,36 +983,36 @@ export const screenshots = [ ["features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Day_1_en","features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Night_1_en",0,], ["features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Day_2_en","features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Night_2_en",0,], ["features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Day_3_en","features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Night_3_en",0,], -["features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Day_4_en","features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Night_4_en",19923,], +["features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Day_4_en","features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Night_4_en",19944,], ["features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Day_5_en","features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Night_5_en",0,], ["features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Day_6_en","features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Night_6_en",0,], ["features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Day_7_en","features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Night_7_en",0,], -["features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Day_8_en","features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Night_8_en",19923,], +["features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Day_8_en","features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Night_8_en",19944,], ["features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Day_9_en","features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Night_9_en",0,], ["features.messages.impl.timeline.components_TimelineItemEventRow_Day_0_en","features.messages.impl.timeline.components_TimelineItemEventRow_Night_0_en",0,], -["features.messages.impl.timeline.components_TimelineItemEventTimestampBelow_en","",19923,], +["features.messages.impl.timeline.components_TimelineItemEventTimestampBelow_en","",19944,], ["features.messages.impl.timeline.components.event_TimelineItemFileView_Day_0_en","features.messages.impl.timeline.components.event_TimelineItemFileView_Night_0_en",0,], ["features.messages.impl.timeline.components.event_TimelineItemFileView_Day_1_en","features.messages.impl.timeline.components.event_TimelineItemFileView_Night_1_en",0,], ["features.messages.impl.timeline.components.event_TimelineItemFileView_Day_2_en","features.messages.impl.timeline.components.event_TimelineItemFileView_Night_2_en",0,], -["features.messages.impl.timeline.components_TimelineItemGroupedEventsRowContentCollapse_Day_0_en","features.messages.impl.timeline.components_TimelineItemGroupedEventsRowContentCollapse_Night_0_en",19923,], -["features.messages.impl.timeline.components_TimelineItemGroupedEventsRowContentExpanded_Day_0_en","features.messages.impl.timeline.components_TimelineItemGroupedEventsRowContentExpanded_Night_0_en",19923,], +["features.messages.impl.timeline.components_TimelineItemGroupedEventsRowContentCollapse_Day_0_en","features.messages.impl.timeline.components_TimelineItemGroupedEventsRowContentCollapse_Night_0_en",19944,], +["features.messages.impl.timeline.components_TimelineItemGroupedEventsRowContentExpanded_Day_0_en","features.messages.impl.timeline.components_TimelineItemGroupedEventsRowContentExpanded_Night_0_en",19944,], ["features.messages.impl.timeline.components.event_TimelineItemImageView_Day_0_en","features.messages.impl.timeline.components.event_TimelineItemImageView_Night_0_en",0,], ["features.messages.impl.timeline.components.event_TimelineItemImageView_Day_1_en","features.messages.impl.timeline.components.event_TimelineItemImageView_Night_1_en",0,], ["features.messages.impl.timeline.components.event_TimelineItemImageView_Day_2_en","features.messages.impl.timeline.components.event_TimelineItemImageView_Night_2_en",0,], ["features.messages.impl.timeline.components.event_TimelineItemInformativeView_Day_0_en","features.messages.impl.timeline.components.event_TimelineItemInformativeView_Night_0_en",0,], -["features.messages.impl.timeline.components.event_TimelineItemLegacyCallInviteView_Day_0_en","features.messages.impl.timeline.components.event_TimelineItemLegacyCallInviteView_Night_0_en",19923,], +["features.messages.impl.timeline.components.event_TimelineItemLegacyCallInviteView_Day_0_en","features.messages.impl.timeline.components.event_TimelineItemLegacyCallInviteView_Night_0_en",19944,], ["features.messages.impl.timeline.components.event_TimelineItemLocationView_Day_0_en","features.messages.impl.timeline.components.event_TimelineItemLocationView_Night_0_en",0,], ["features.messages.impl.timeline.components.event_TimelineItemLocationView_Day_1_en","features.messages.impl.timeline.components.event_TimelineItemLocationView_Night_1_en",0,], -["features.messages.impl.timeline.components.event_TimelineItemPollView_Day_0_en","features.messages.impl.timeline.components.event_TimelineItemPollView_Night_0_en",19923,], -["features.messages.impl.timeline.components.event_TimelineItemPollView_Day_1_en","features.messages.impl.timeline.components.event_TimelineItemPollView_Night_1_en",19923,], -["features.messages.impl.timeline.components.event_TimelineItemPollView_Day_2_en","features.messages.impl.timeline.components.event_TimelineItemPollView_Night_2_en",19923,], -["features.messages.impl.timeline.components.event_TimelineItemPollView_Day_3_en","features.messages.impl.timeline.components.event_TimelineItemPollView_Night_3_en",19923,], -["features.messages.impl.timeline.components_TimelineItemReactionsLayout_Day_0_en","features.messages.impl.timeline.components_TimelineItemReactionsLayout_Night_0_en",19923,], +["features.messages.impl.timeline.components.event_TimelineItemPollView_Day_0_en","features.messages.impl.timeline.components.event_TimelineItemPollView_Night_0_en",19944,], +["features.messages.impl.timeline.components.event_TimelineItemPollView_Day_1_en","features.messages.impl.timeline.components.event_TimelineItemPollView_Night_1_en",19944,], +["features.messages.impl.timeline.components.event_TimelineItemPollView_Day_2_en","features.messages.impl.timeline.components.event_TimelineItemPollView_Night_2_en",19944,], +["features.messages.impl.timeline.components.event_TimelineItemPollView_Day_3_en","features.messages.impl.timeline.components.event_TimelineItemPollView_Night_3_en",19944,], +["features.messages.impl.timeline.components_TimelineItemReactionsLayout_Day_0_en","features.messages.impl.timeline.components_TimelineItemReactionsLayout_Night_0_en",19944,], ["features.messages.impl.timeline.components_TimelineItemReactionsViewFew_Day_0_en","features.messages.impl.timeline.components_TimelineItemReactionsViewFew_Night_0_en",0,], -["features.messages.impl.timeline.components_TimelineItemReactionsViewIncoming_Day_0_en","features.messages.impl.timeline.components_TimelineItemReactionsViewIncoming_Night_0_en",19923,], -["features.messages.impl.timeline.components_TimelineItemReactionsViewOutgoing_Day_0_en","features.messages.impl.timeline.components_TimelineItemReactionsViewOutgoing_Night_0_en",19923,], +["features.messages.impl.timeline.components_TimelineItemReactionsViewIncoming_Day_0_en","features.messages.impl.timeline.components_TimelineItemReactionsViewIncoming_Night_0_en",19944,], +["features.messages.impl.timeline.components_TimelineItemReactionsViewOutgoing_Day_0_en","features.messages.impl.timeline.components_TimelineItemReactionsViewOutgoing_Night_0_en",19944,], ["features.messages.impl.timeline.components_TimelineItemReactionsView_Day_0_en","features.messages.impl.timeline.components_TimelineItemReactionsView_Night_0_en",0,], -["features.messages.impl.timeline.components.virtual_TimelineItemReadMarkerView_Day_0_en","features.messages.impl.timeline.components.virtual_TimelineItemReadMarkerView_Night_0_en",19923,], +["features.messages.impl.timeline.components.virtual_TimelineItemReadMarkerView_Day_0_en","features.messages.impl.timeline.components.virtual_TimelineItemReadMarkerView_Night_0_en",19944,], ["features.messages.impl.timeline.components.receipt_TimelineItemReadReceiptView_Day_0_en","features.messages.impl.timeline.components.receipt_TimelineItemReadReceiptView_Night_0_en",0,], ["features.messages.impl.timeline.components.receipt_TimelineItemReadReceiptView_Day_1_en","features.messages.impl.timeline.components.receipt_TimelineItemReadReceiptView_Night_1_en",0,], ["features.messages.impl.timeline.components.receipt_TimelineItemReadReceiptView_Day_2_en","features.messages.impl.timeline.components.receipt_TimelineItemReadReceiptView_Night_2_en",0,], @@ -1010,8 +1021,8 @@ export const screenshots = [ ["features.messages.impl.timeline.components.receipt_TimelineItemReadReceiptView_Day_5_en","features.messages.impl.timeline.components.receipt_TimelineItemReadReceiptView_Night_5_en",0,], ["features.messages.impl.timeline.components.receipt_TimelineItemReadReceiptView_Day_6_en","features.messages.impl.timeline.components.receipt_TimelineItemReadReceiptView_Night_6_en",0,], ["features.messages.impl.timeline.components.receipt_TimelineItemReadReceiptView_Day_7_en","features.messages.impl.timeline.components.receipt_TimelineItemReadReceiptView_Night_7_en",0,], -["features.messages.impl.timeline.components.event_TimelineItemRedactedView_Day_0_en","features.messages.impl.timeline.components.event_TimelineItemRedactedView_Night_0_en",19923,], -["features.messages.impl.timeline.components.virtual_TimelineItemRoomBeginningView_Day_0_en","features.messages.impl.timeline.components.virtual_TimelineItemRoomBeginningView_Night_0_en",19923,], +["features.messages.impl.timeline.components.event_TimelineItemRedactedView_Day_0_en","features.messages.impl.timeline.components.event_TimelineItemRedactedView_Night_0_en",19944,], +["features.messages.impl.timeline.components.virtual_TimelineItemRoomBeginningView_Day_0_en","features.messages.impl.timeline.components.virtual_TimelineItemRoomBeginningView_Night_0_en",19944,], ["features.messages.impl.timeline.components_TimelineItemStateEventRow_Day_0_en","features.messages.impl.timeline.components_TimelineItemStateEventRow_Night_0_en",0,], ["features.messages.impl.timeline.components.event_TimelineItemStateView_Day_0_en","features.messages.impl.timeline.components.event_TimelineItemStateView_Night_0_en",0,], ["features.messages.impl.timeline.components.event_TimelineItemStickerView_Day_0_en","features.messages.impl.timeline.components.event_TimelineItemStickerView_Night_0_en",0,], @@ -1023,7 +1034,7 @@ export const screenshots = [ ["features.messages.impl.timeline.components.event_TimelineItemTextView_Day_3_en","features.messages.impl.timeline.components.event_TimelineItemTextView_Night_3_en",0,], ["features.messages.impl.timeline.components.event_TimelineItemTextView_Day_4_en","features.messages.impl.timeline.components.event_TimelineItemTextView_Night_4_en",0,], ["features.messages.impl.timeline.components.event_TimelineItemTextView_Day_5_en","features.messages.impl.timeline.components.event_TimelineItemTextView_Night_5_en",0,], -["features.messages.impl.timeline.components.event_TimelineItemUnknownView_Day_0_en","features.messages.impl.timeline.components.event_TimelineItemUnknownView_Night_0_en",19923,], +["features.messages.impl.timeline.components.event_TimelineItemUnknownView_Day_0_en","features.messages.impl.timeline.components.event_TimelineItemUnknownView_Night_0_en",19944,], ["features.messages.impl.timeline.components.event_TimelineItemVideoView_Day_0_en","features.messages.impl.timeline.components.event_TimelineItemVideoView_Night_0_en",0,], ["features.messages.impl.timeline.components.event_TimelineItemVideoView_Day_1_en","features.messages.impl.timeline.components.event_TimelineItemVideoView_Night_1_en",0,], ["features.messages.impl.timeline.components.event_TimelineItemVideoView_Day_2_en","features.messages.impl.timeline.components.event_TimelineItemVideoView_Night_2_en",0,], @@ -1045,79 +1056,79 @@ export const screenshots = [ ["features.messages.impl.timeline.components.event_TimelineItemVoiceView_Day_9_en","features.messages.impl.timeline.components.event_TimelineItemVoiceView_Night_9_en",0,], ["features.messages.impl.timeline.components.virtual_TimelineLoadingMoreIndicator_Day_0_en","features.messages.impl.timeline.components.virtual_TimelineLoadingMoreIndicator_Night_0_en",0,], ["features.messages.impl.timeline.components.event_TimelineVideoWithCaptionRow_Day_0_en","features.messages.impl.timeline.components.event_TimelineVideoWithCaptionRow_Night_0_en",0,], -["features.messages.impl.timeline_TimelineView_Day_0_en","features.messages.impl.timeline_TimelineView_Night_0_en",19923,], +["features.messages.impl.timeline_TimelineView_Day_0_en","features.messages.impl.timeline_TimelineView_Night_0_en",19944,], ["features.messages.impl.timeline_TimelineView_Day_10_en","features.messages.impl.timeline_TimelineView_Night_10_en",0,], -["features.messages.impl.timeline_TimelineView_Day_11_en","features.messages.impl.timeline_TimelineView_Night_11_en",19923,], -["features.messages.impl.timeline_TimelineView_Day_12_en","features.messages.impl.timeline_TimelineView_Night_12_en",19923,], -["features.messages.impl.timeline_TimelineView_Day_13_en","features.messages.impl.timeline_TimelineView_Night_13_en",19923,], -["features.messages.impl.timeline_TimelineView_Day_14_en","features.messages.impl.timeline_TimelineView_Night_14_en",19923,], -["features.messages.impl.timeline_TimelineView_Day_15_en","features.messages.impl.timeline_TimelineView_Night_15_en",19923,], -["features.messages.impl.timeline_TimelineView_Day_16_en","features.messages.impl.timeline_TimelineView_Night_16_en",19923,], -["features.messages.impl.timeline_TimelineView_Day_1_en","features.messages.impl.timeline_TimelineView_Night_1_en",19923,], +["features.messages.impl.timeline_TimelineView_Day_11_en","features.messages.impl.timeline_TimelineView_Night_11_en",19944,], +["features.messages.impl.timeline_TimelineView_Day_12_en","features.messages.impl.timeline_TimelineView_Night_12_en",19944,], +["features.messages.impl.timeline_TimelineView_Day_13_en","features.messages.impl.timeline_TimelineView_Night_13_en",19944,], +["features.messages.impl.timeline_TimelineView_Day_14_en","features.messages.impl.timeline_TimelineView_Night_14_en",19944,], +["features.messages.impl.timeline_TimelineView_Day_15_en","features.messages.impl.timeline_TimelineView_Night_15_en",19944,], +["features.messages.impl.timeline_TimelineView_Day_16_en","features.messages.impl.timeline_TimelineView_Night_16_en",19944,], +["features.messages.impl.timeline_TimelineView_Day_1_en","features.messages.impl.timeline_TimelineView_Night_1_en",19944,], ["features.messages.impl.timeline_TimelineView_Day_2_en","features.messages.impl.timeline_TimelineView_Night_2_en",0,], ["features.messages.impl.timeline_TimelineView_Day_3_en","features.messages.impl.timeline_TimelineView_Night_3_en",0,], -["features.messages.impl.timeline_TimelineView_Day_4_en","features.messages.impl.timeline_TimelineView_Night_4_en",19923,], +["features.messages.impl.timeline_TimelineView_Day_4_en","features.messages.impl.timeline_TimelineView_Night_4_en",19944,], ["features.messages.impl.timeline_TimelineView_Day_5_en","features.messages.impl.timeline_TimelineView_Night_5_en",0,], -["features.messages.impl.timeline_TimelineView_Day_6_en","features.messages.impl.timeline_TimelineView_Night_6_en",19923,], +["features.messages.impl.timeline_TimelineView_Day_6_en","features.messages.impl.timeline_TimelineView_Night_6_en",19944,], ["features.messages.impl.timeline_TimelineView_Day_7_en","features.messages.impl.timeline_TimelineView_Night_7_en",0,], -["features.messages.impl.timeline_TimelineView_Day_8_en","features.messages.impl.timeline_TimelineView_Night_8_en",19923,], +["features.messages.impl.timeline_TimelineView_Day_8_en","features.messages.impl.timeline_TimelineView_Night_8_en",19944,], ["features.messages.impl.timeline_TimelineView_Day_9_en","features.messages.impl.timeline_TimelineView_Night_9_en",0,], ["libraries.designsystem.theme.components_TopAppBar_App Bars_en","",0,], -["libraries.troubleshoot.impl_TroubleshootNotificationsView_Day_0_en","libraries.troubleshoot.impl_TroubleshootNotificationsView_Night_0_en",19923,], -["libraries.troubleshoot.impl_TroubleshootNotificationsView_Day_1_en","libraries.troubleshoot.impl_TroubleshootNotificationsView_Night_1_en",19923,], -["libraries.troubleshoot.impl_TroubleshootNotificationsView_Day_2_en","libraries.troubleshoot.impl_TroubleshootNotificationsView_Night_2_en",19923,], -["libraries.troubleshoot.impl_TroubleshootNotificationsView_Day_3_en","libraries.troubleshoot.impl_TroubleshootNotificationsView_Night_3_en",19923,], -["libraries.troubleshoot.impl_TroubleshootNotificationsView_Day_4_en","libraries.troubleshoot.impl_TroubleshootNotificationsView_Night_4_en",19923,], -["libraries.troubleshoot.impl_TroubleshootNotificationsView_Day_5_en","libraries.troubleshoot.impl_TroubleshootNotificationsView_Night_5_en",19923,], -["libraries.troubleshoot.impl_TroubleshootNotificationsView_Day_6_en","libraries.troubleshoot.impl_TroubleshootNotificationsView_Night_6_en",19923,], -["libraries.troubleshoot.impl_TroubleshootNotificationsView_Day_7_en","libraries.troubleshoot.impl_TroubleshootNotificationsView_Night_7_en",19923,], +["libraries.troubleshoot.impl_TroubleshootNotificationsView_Day_0_en","libraries.troubleshoot.impl_TroubleshootNotificationsView_Night_0_en",19944,], +["libraries.troubleshoot.impl_TroubleshootNotificationsView_Day_1_en","libraries.troubleshoot.impl_TroubleshootNotificationsView_Night_1_en",19944,], +["libraries.troubleshoot.impl_TroubleshootNotificationsView_Day_2_en","libraries.troubleshoot.impl_TroubleshootNotificationsView_Night_2_en",19944,], +["libraries.troubleshoot.impl_TroubleshootNotificationsView_Day_3_en","libraries.troubleshoot.impl_TroubleshootNotificationsView_Night_3_en",19944,], +["libraries.troubleshoot.impl_TroubleshootNotificationsView_Day_4_en","libraries.troubleshoot.impl_TroubleshootNotificationsView_Night_4_en",19944,], +["libraries.troubleshoot.impl_TroubleshootNotificationsView_Day_5_en","libraries.troubleshoot.impl_TroubleshootNotificationsView_Night_5_en",19944,], +["libraries.troubleshoot.impl_TroubleshootNotificationsView_Day_6_en","libraries.troubleshoot.impl_TroubleshootNotificationsView_Night_6_en",19944,], +["libraries.troubleshoot.impl_TroubleshootNotificationsView_Day_7_en","libraries.troubleshoot.impl_TroubleshootNotificationsView_Night_7_en",19944,], ["features.messages.impl.typing_TypingNotificationView_Day_0_en","features.messages.impl.typing_TypingNotificationView_Night_0_en",0,], -["features.messages.impl.typing_TypingNotificationView_Day_1_en","features.messages.impl.typing_TypingNotificationView_Night_1_en",19923,], -["features.messages.impl.typing_TypingNotificationView_Day_2_en","features.messages.impl.typing_TypingNotificationView_Night_2_en",19923,], -["features.messages.impl.typing_TypingNotificationView_Day_3_en","features.messages.impl.typing_TypingNotificationView_Night_3_en",19923,], -["features.messages.impl.typing_TypingNotificationView_Day_4_en","features.messages.impl.typing_TypingNotificationView_Night_4_en",19923,], -["features.messages.impl.typing_TypingNotificationView_Day_5_en","features.messages.impl.typing_TypingNotificationView_Night_5_en",19923,], -["features.messages.impl.typing_TypingNotificationView_Day_6_en","features.messages.impl.typing_TypingNotificationView_Night_6_en",19923,], +["features.messages.impl.typing_TypingNotificationView_Day_1_en","features.messages.impl.typing_TypingNotificationView_Night_1_en",19944,], +["features.messages.impl.typing_TypingNotificationView_Day_2_en","features.messages.impl.typing_TypingNotificationView_Night_2_en",19944,], +["features.messages.impl.typing_TypingNotificationView_Day_3_en","features.messages.impl.typing_TypingNotificationView_Night_3_en",19944,], +["features.messages.impl.typing_TypingNotificationView_Day_4_en","features.messages.impl.typing_TypingNotificationView_Night_4_en",19944,], +["features.messages.impl.typing_TypingNotificationView_Day_5_en","features.messages.impl.typing_TypingNotificationView_Night_5_en",19944,], +["features.messages.impl.typing_TypingNotificationView_Day_6_en","features.messages.impl.typing_TypingNotificationView_Night_6_en",19944,], ["features.messages.impl.typing_TypingNotificationView_Day_7_en","features.messages.impl.typing_TypingNotificationView_Night_7_en",0,], ["features.messages.impl.typing_TypingNotificationView_Day_8_en","features.messages.impl.typing_TypingNotificationView_Night_8_en",0,], ["libraries.designsystem.atomic.atoms_UnreadIndicatorAtom_Day_0_en","libraries.designsystem.atomic.atoms_UnreadIndicatorAtom_Night_0_en",0,], -["libraries.matrix.ui.components_UnresolvedUserRow_en","",19923,], +["libraries.matrix.ui.components_UnresolvedUserRow_en","",19944,], ["libraries.matrix.ui.components_UnsavedAvatar_Day_0_en","libraries.matrix.ui.components_UnsavedAvatar_Night_0_en",0,], ["libraries.designsystem.components.avatar_UserAvatarColors_Day_0_en","libraries.designsystem.components.avatar_UserAvatarColors_Night_0_en",0,], -["features.roomdetails.impl.notificationsettings_UserDefinedRoomNotificationSettingsView_Day_0_en","features.roomdetails.impl.notificationsettings_UserDefinedRoomNotificationSettingsView_Night_0_en",19923,], -["features.createroom.impl.components_UserListView_Day_0_en","features.createroom.impl.components_UserListView_Night_0_en",19923,], -["features.createroom.impl.components_UserListView_Day_1_en","features.createroom.impl.components_UserListView_Night_1_en",19923,], -["features.createroom.impl.components_UserListView_Day_2_en","features.createroom.impl.components_UserListView_Night_2_en",19923,], +["features.roomdetails.impl.notificationsettings_UserDefinedRoomNotificationSettingsView_Day_0_en","features.roomdetails.impl.notificationsettings_UserDefinedRoomNotificationSettingsView_Night_0_en",19944,], +["features.createroom.impl.components_UserListView_Day_0_en","features.createroom.impl.components_UserListView_Night_0_en",19944,], +["features.createroom.impl.components_UserListView_Day_1_en","features.createroom.impl.components_UserListView_Night_1_en",19944,], +["features.createroom.impl.components_UserListView_Day_2_en","features.createroom.impl.components_UserListView_Night_2_en",19944,], ["features.createroom.impl.components_UserListView_Day_3_en","features.createroom.impl.components_UserListView_Night_3_en",0,], ["features.createroom.impl.components_UserListView_Day_4_en","features.createroom.impl.components_UserListView_Night_4_en",0,], ["features.createroom.impl.components_UserListView_Day_5_en","features.createroom.impl.components_UserListView_Night_5_en",0,], ["features.createroom.impl.components_UserListView_Day_6_en","features.createroom.impl.components_UserListView_Night_6_en",0,], -["features.createroom.impl.components_UserListView_Day_7_en","features.createroom.impl.components_UserListView_Night_7_en",19923,], +["features.createroom.impl.components_UserListView_Day_7_en","features.createroom.impl.components_UserListView_Night_7_en",19944,], ["features.createroom.impl.components_UserListView_Day_8_en","features.createroom.impl.components_UserListView_Night_8_en",0,], -["features.createroom.impl.components_UserListView_Day_9_en","features.createroom.impl.components_UserListView_Night_9_en",19923,], +["features.createroom.impl.components_UserListView_Day_9_en","features.createroom.impl.components_UserListView_Night_9_en",19944,], ["features.preferences.impl.user_UserPreferences_Day_0_en","features.preferences.impl.user_UserPreferences_Night_0_en",0,], ["features.preferences.impl.user_UserPreferences_Day_1_en","features.preferences.impl.user_UserPreferences_Night_1_en",0,], ["features.preferences.impl.user_UserPreferences_Day_2_en","features.preferences.impl.user_UserPreferences_Night_2_en",0,], ["features.userprofile.shared_UserProfileHeaderSection_Day_0_en","features.userprofile.shared_UserProfileHeaderSection_Night_0_en",0,], -["features.userprofile.shared_UserProfileView_Day_0_en","features.userprofile.shared_UserProfileView_Night_0_en",19923,], -["features.userprofile.shared_UserProfileView_Day_1_en","features.userprofile.shared_UserProfileView_Night_1_en",19923,], -["features.userprofile.shared_UserProfileView_Day_2_en","features.userprofile.shared_UserProfileView_Night_2_en",19923,], -["features.userprofile.shared_UserProfileView_Day_3_en","features.userprofile.shared_UserProfileView_Night_3_en",19923,], -["features.userprofile.shared_UserProfileView_Day_4_en","features.userprofile.shared_UserProfileView_Night_4_en",19923,], -["features.userprofile.shared_UserProfileView_Day_5_en","features.userprofile.shared_UserProfileView_Night_5_en",19923,], -["features.userprofile.shared_UserProfileView_Day_6_en","features.userprofile.shared_UserProfileView_Night_6_en",19923,], -["features.userprofile.shared_UserProfileView_Day_7_en","features.userprofile.shared_UserProfileView_Night_7_en",19923,], -["features.userprofile.shared_UserProfileView_Day_8_en","features.userprofile.shared_UserProfileView_Night_8_en",19923,], -["features.verifysession.impl_VerifySelfSessionView_Day_0_en","features.verifysession.impl_VerifySelfSessionView_Night_0_en",19923,], -["features.verifysession.impl_VerifySelfSessionView_Day_1_en","features.verifysession.impl_VerifySelfSessionView_Night_1_en",19923,], -["features.verifysession.impl_VerifySelfSessionView_Day_2_en","features.verifysession.impl_VerifySelfSessionView_Night_2_en",19923,], -["features.verifysession.impl_VerifySelfSessionView_Day_3_en","features.verifysession.impl_VerifySelfSessionView_Night_3_en",19923,], -["features.verifysession.impl_VerifySelfSessionView_Day_4_en","features.verifysession.impl_VerifySelfSessionView_Night_4_en",19923,], -["features.verifysession.impl_VerifySelfSessionView_Day_5_en","features.verifysession.impl_VerifySelfSessionView_Night_5_en",19923,], -["features.verifysession.impl_VerifySelfSessionView_Day_6_en","features.verifysession.impl_VerifySelfSessionView_Night_6_en",19923,], -["features.verifysession.impl_VerifySelfSessionView_Day_7_en","features.verifysession.impl_VerifySelfSessionView_Night_7_en",19923,], -["features.verifysession.impl_VerifySelfSessionView_Day_8_en","features.verifysession.impl_VerifySelfSessionView_Night_8_en",19923,], -["features.verifysession.impl_VerifySelfSessionView_Day_9_en","features.verifysession.impl_VerifySelfSessionView_Night_9_en",19923,], +["features.userprofile.shared_UserProfileView_Day_0_en","features.userprofile.shared_UserProfileView_Night_0_en",19944,], +["features.userprofile.shared_UserProfileView_Day_1_en","features.userprofile.shared_UserProfileView_Night_1_en",19944,], +["features.userprofile.shared_UserProfileView_Day_2_en","features.userprofile.shared_UserProfileView_Night_2_en",19944,], +["features.userprofile.shared_UserProfileView_Day_3_en","features.userprofile.shared_UserProfileView_Night_3_en",19944,], +["features.userprofile.shared_UserProfileView_Day_4_en","features.userprofile.shared_UserProfileView_Night_4_en",19944,], +["features.userprofile.shared_UserProfileView_Day_5_en","features.userprofile.shared_UserProfileView_Night_5_en",19944,], +["features.userprofile.shared_UserProfileView_Day_6_en","features.userprofile.shared_UserProfileView_Night_6_en",19944,], +["features.userprofile.shared_UserProfileView_Day_7_en","features.userprofile.shared_UserProfileView_Night_7_en",19944,], +["features.userprofile.shared_UserProfileView_Day_8_en","features.userprofile.shared_UserProfileView_Night_8_en",19944,], +["features.verifysession.impl_VerifySelfSessionView_Day_0_en","features.verifysession.impl_VerifySelfSessionView_Night_0_en",19944,], +["features.verifysession.impl_VerifySelfSessionView_Day_1_en","features.verifysession.impl_VerifySelfSessionView_Night_1_en",19944,], +["features.verifysession.impl_VerifySelfSessionView_Day_2_en","features.verifysession.impl_VerifySelfSessionView_Night_2_en",19944,], +["features.verifysession.impl_VerifySelfSessionView_Day_3_en","features.verifysession.impl_VerifySelfSessionView_Night_3_en",19944,], +["features.verifysession.impl_VerifySelfSessionView_Day_4_en","features.verifysession.impl_VerifySelfSessionView_Night_4_en",19944,], +["features.verifysession.impl_VerifySelfSessionView_Day_5_en","features.verifysession.impl_VerifySelfSessionView_Night_5_en",19944,], +["features.verifysession.impl_VerifySelfSessionView_Day_6_en","features.verifysession.impl_VerifySelfSessionView_Night_6_en",19944,], +["features.verifysession.impl_VerifySelfSessionView_Day_7_en","features.verifysession.impl_VerifySelfSessionView_Night_7_en",19944,], +["features.verifysession.impl_VerifySelfSessionView_Day_8_en","features.verifysession.impl_VerifySelfSessionView_Night_8_en",19944,], +["features.verifysession.impl_VerifySelfSessionView_Day_9_en","features.verifysession.impl_VerifySelfSessionView_Night_9_en",19944,], ["libraries.designsystem.ruler_VerticalRuler_Day_0_en","libraries.designsystem.ruler_VerticalRuler_Night_0_en",0,], ["features.viewfolder.impl.file_ViewFileView_Day_0_en","features.viewfolder.impl.file_ViewFileView_Night_0_en",0,], ["features.viewfolder.impl.file_ViewFileView_Day_1_en","features.viewfolder.impl.file_ViewFileView_Night_1_en",0,], @@ -1131,12 +1142,12 @@ export const screenshots = [ ["libraries.textcomposer.components_VoiceMessageRecorderButton_Day_0_en","libraries.textcomposer.components_VoiceMessageRecorderButton_Night_0_en",0,], ["libraries.textcomposer.components_VoiceMessageRecording_Day_0_en","libraries.textcomposer.components_VoiceMessageRecording_Night_0_en",0,], ["libraries.textcomposer.components_VoiceMessage_Day_0_en","libraries.textcomposer.components_VoiceMessage_Night_0_en",0,], -["features.login.impl.screens.waitlistscreen_WaitListView_Day_0_en","features.login.impl.screens.waitlistscreen_WaitListView_Night_0_en",19923,], -["features.login.impl.screens.waitlistscreen_WaitListView_Day_1_en","features.login.impl.screens.waitlistscreen_WaitListView_Night_1_en",19923,], -["features.login.impl.screens.waitlistscreen_WaitListView_Day_2_en","features.login.impl.screens.waitlistscreen_WaitListView_Night_2_en",19923,], -["features.login.impl.screens.waitlistscreen_WaitListView_Day_3_en","features.login.impl.screens.waitlistscreen_WaitListView_Night_3_en",19923,], -["features.login.impl.screens.waitlistscreen_WaitListView_Day_4_en","features.login.impl.screens.waitlistscreen_WaitListView_Night_4_en",19923,], +["features.login.impl.screens.waitlistscreen_WaitListView_Day_0_en","features.login.impl.screens.waitlistscreen_WaitListView_Night_0_en",19944,], +["features.login.impl.screens.waitlistscreen_WaitListView_Day_1_en","features.login.impl.screens.waitlistscreen_WaitListView_Night_1_en",19944,], +["features.login.impl.screens.waitlistscreen_WaitListView_Day_2_en","features.login.impl.screens.waitlistscreen_WaitListView_Night_2_en",19944,], +["features.login.impl.screens.waitlistscreen_WaitListView_Day_3_en","features.login.impl.screens.waitlistscreen_WaitListView_Night_3_en",19944,], +["features.login.impl.screens.waitlistscreen_WaitListView_Day_4_en","features.login.impl.screens.waitlistscreen_WaitListView_Night_4_en",19944,], ["libraries.designsystem.components.media_WaveformPlaybackView_Day_0_en","libraries.designsystem.components.media_WaveformPlaybackView_Night_0_en",0,], -["features.ftue.impl.welcome_WelcomeView_Day_0_en","features.ftue.impl.welcome_WelcomeView_Night_0_en",19923,], +["features.ftue.impl.welcome_WelcomeView_Day_0_en","features.ftue.impl.welcome_WelcomeView_Night_0_en",19944,], ["libraries.designsystem.ruler_WithRulers_Day_0_en","libraries.designsystem.ruler_WithRulers_Night_0_en",0,], ]; diff --git a/services/appnavstate/impl/src/test/kotlin/io/element/android/services/appnavstate/impl/DefaultNavigationStateServiceTest.kt b/services/appnavstate/impl/src/test/kotlin/io/element/android/services/appnavstate/impl/DefaultNavigationStateServiceTest.kt index 713839ee86..8f2abeeed5 100644 --- a/services/appnavstate/impl/src/test/kotlin/io/element/android/services/appnavstate/impl/DefaultNavigationStateServiceTest.kt +++ b/services/appnavstate/impl/src/test/kotlin/io/element/android/services/appnavstate/impl/DefaultNavigationStateServiceTest.kt @@ -31,6 +31,7 @@ import io.element.android.services.appnavstate.test.A_ROOM_OWNER import io.element.android.services.appnavstate.test.A_SESSION_OWNER import io.element.android.services.appnavstate.test.A_SPACE_OWNER import io.element.android.services.appnavstate.test.A_THREAD_OWNER +import io.element.android.services.appnavstate.test.FakeAppForegroundStateService import io.element.android.tests.testutils.runCancellableScopeTest import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.first diff --git a/services/appnavstate/impl/src/test/kotlin/io/element/android/services/appnavstate/impl/FakeAppForegroundStateService.kt b/services/appnavstate/test/src/main/kotlin/io/element/android/services/appnavstate/test/FakeAppForegroundStateService.kt similarity index 95% rename from services/appnavstate/impl/src/test/kotlin/io/element/android/services/appnavstate/impl/FakeAppForegroundStateService.kt rename to services/appnavstate/test/src/main/kotlin/io/element/android/services/appnavstate/test/FakeAppForegroundStateService.kt index 4e3c012b48..6af17c78f3 100644 --- a/services/appnavstate/impl/src/test/kotlin/io/element/android/services/appnavstate/impl/FakeAppForegroundStateService.kt +++ b/services/appnavstate/test/src/main/kotlin/io/element/android/services/appnavstate/test/FakeAppForegroundStateService.kt @@ -14,7 +14,7 @@ * limitations under the License. */ -package io.element.android.services.appnavstate.impl +package io.element.android.services.appnavstate.test import io.element.android.services.appnavstate.api.AppForegroundStateService import kotlinx.coroutines.flow.MutableStateFlow diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.pinned.banner_PinnedMessagesBannerView_Day_0_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.pinned.banner_PinnedMessagesBannerView_Day_0_en.png new file mode 100644 index 0000000000..1b6fb4bab8 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.pinned.banner_PinnedMessagesBannerView_Day_0_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:96a867cb12498cbdc97957bee07855dfaa13602baddaf933aff2b666ef4c7650 +size 3642 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.pinned.banner_PinnedMessagesBannerView_Day_1_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.pinned.banner_PinnedMessagesBannerView_Day_1_en.png new file mode 100644 index 0000000000..98720535b6 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.pinned.banner_PinnedMessagesBannerView_Day_1_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d5b71d416128b5b4791cec79ed7cdf963574c8fa66b32844ec798f55ddf62f42 +size 7960 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.pinned.banner_PinnedMessagesBannerView_Day_2_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.pinned.banner_PinnedMessagesBannerView_Day_2_en.png new file mode 100644 index 0000000000..336a9a5ad1 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.pinned.banner_PinnedMessagesBannerView_Day_2_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:720d657356e7fff0d0994a11fb95152b896b9e1de04dd50023b85c4d72cde6af +size 11414 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.pinned.banner_PinnedMessagesBannerView_Day_3_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.pinned.banner_PinnedMessagesBannerView_Day_3_en.png new file mode 100644 index 0000000000..558c81c8b7 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.pinned.banner_PinnedMessagesBannerView_Day_3_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7114202a1de9860547c525c0dadc110ce9e2e198465218ac2c33cf65f2f0eaa2 +size 9496 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.pinned.banner_PinnedMessagesBannerView_Day_4_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.pinned.banner_PinnedMessagesBannerView_Day_4_en.png new file mode 100644 index 0000000000..3d77277fec --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.pinned.banner_PinnedMessagesBannerView_Day_4_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:8e6b5fd9ecc2b01cc8a83f3fe8e34352de1792a82db85c396377a18246adad1a +size 12953 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.pinned.banner_PinnedMessagesBannerView_Day_5_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.pinned.banner_PinnedMessagesBannerView_Day_5_en.png new file mode 100644 index 0000000000..575d07a9f1 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.pinned.banner_PinnedMessagesBannerView_Day_5_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:743c950b885f3831034dab99571e19660a608eb8cc93218c939b570c1925e8f7 +size 12926 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.pinned.banner_PinnedMessagesBannerView_Day_6_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.pinned.banner_PinnedMessagesBannerView_Day_6_en.png new file mode 100644 index 0000000000..cfd32bb09c --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.pinned.banner_PinnedMessagesBannerView_Day_6_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:14ca5901134299e801e204e280d731e7de4072f1d522b076eb41c5f806897ed2 +size 12905 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.pinned.banner_PinnedMessagesBannerView_Day_7_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.pinned.banner_PinnedMessagesBannerView_Day_7_en.png new file mode 100644 index 0000000000..40ed099f5b --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.pinned.banner_PinnedMessagesBannerView_Day_7_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:bb206284c642dd665290d5d553491e622b8e15a64df7bb2dbd91ea5d3a13e19a +size 13041 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.pinned.banner_PinnedMessagesBannerView_Day_8_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.pinned.banner_PinnedMessagesBannerView_Day_8_en.png new file mode 100644 index 0000000000..15a58d4763 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.pinned.banner_PinnedMessagesBannerView_Day_8_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a1940c4ee1e07c6a0198682460af1a6558fcaf14cb69ff061831cb591eb7aec3 +size 13066 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.pinned.banner_PinnedMessagesBannerView_Day_9_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.pinned.banner_PinnedMessagesBannerView_Day_9_en.png new file mode 100644 index 0000000000..ac3fb40ad1 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.pinned.banner_PinnedMessagesBannerView_Day_9_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:fee5c1dbcdf7929f4762b2915584fe45b7f39916a949663f03e8d7e85e991b4b +size 12988 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.pinned.banner_PinnedMessagesBannerView_Night_0_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.pinned.banner_PinnedMessagesBannerView_Night_0_en.png new file mode 100644 index 0000000000..d6fd8eeb70 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.pinned.banner_PinnedMessagesBannerView_Night_0_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:5bb36ccd718f3fec5b04f1bc812dc7718b5ea7fa4619c8b031466297a8d016fd +size 3659 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.pinned.banner_PinnedMessagesBannerView_Night_1_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.pinned.banner_PinnedMessagesBannerView_Night_1_en.png new file mode 100644 index 0000000000..7c8404b2d7 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.pinned.banner_PinnedMessagesBannerView_Night_1_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ff5e3562e981f2675a78e1cdf6cb7599471ad91030059fc8ff429165e1178131 +size 7873 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.pinned.banner_PinnedMessagesBannerView_Night_2_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.pinned.banner_PinnedMessagesBannerView_Night_2_en.png new file mode 100644 index 0000000000..a45ab0dc23 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.pinned.banner_PinnedMessagesBannerView_Night_2_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:86caf295341ae9f5ae5cf99b39539a31afb0286c213e20b528078fc3fb3532e0 +size 10874 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.pinned.banner_PinnedMessagesBannerView_Night_3_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.pinned.banner_PinnedMessagesBannerView_Night_3_en.png new file mode 100644 index 0000000000..625e940b9e --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.pinned.banner_PinnedMessagesBannerView_Night_3_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:16658495b889654f152ba80a52111164f9682009b96abf1f3f20e660bd7c2407 +size 9297 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.pinned.banner_PinnedMessagesBannerView_Night_4_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.pinned.banner_PinnedMessagesBannerView_Night_4_en.png new file mode 100644 index 0000000000..3de9e45d12 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.pinned.banner_PinnedMessagesBannerView_Night_4_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:43651c4a7f10406f1a6a4b995467ba292d4a43bc198dcf352ae2e66694154de2 +size 12340 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.pinned.banner_PinnedMessagesBannerView_Night_5_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.pinned.banner_PinnedMessagesBannerView_Night_5_en.png new file mode 100644 index 0000000000..743791eeaa --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.pinned.banner_PinnedMessagesBannerView_Night_5_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:634006a41aee47e783bd8dcce295aa816f16e8d892f8967debeced863e4cc18b +size 12333 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.pinned.banner_PinnedMessagesBannerView_Night_6_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.pinned.banner_PinnedMessagesBannerView_Night_6_en.png new file mode 100644 index 0000000000..b320ff09e6 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.pinned.banner_PinnedMessagesBannerView_Night_6_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:cca8ebb1ec12497de7e2efc1725a2e4427eecd1d340ae8176d10f914def0af25 +size 12297 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.pinned.banner_PinnedMessagesBannerView_Night_7_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.pinned.banner_PinnedMessagesBannerView_Night_7_en.png new file mode 100644 index 0000000000..8299ed3a1c --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.pinned.banner_PinnedMessagesBannerView_Night_7_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:37bf00fbf548b7ba3d601af1ca489e07e25059c2f5a68abf9b85f4c656cf482c +size 12425 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.pinned.banner_PinnedMessagesBannerView_Night_8_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.pinned.banner_PinnedMessagesBannerView_Night_8_en.png new file mode 100644 index 0000000000..533f421f11 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.pinned.banner_PinnedMessagesBannerView_Night_8_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ed813a7003eb01a06667b10191990ed5bb3f75ee6a447cc4d52510b7e13b3724 +size 12448 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.pinned.banner_PinnedMessagesBannerView_Night_9_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.pinned.banner_PinnedMessagesBannerView_Night_9_en.png new file mode 100644 index 0000000000..a3b1d03bce --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.pinned.banner_PinnedMessagesBannerView_Night_9_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6fa556ff7f6757c69c24e47520e08ccfd1b009d8e49a704c36d7fc4ca4186cbf +size 12378 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.typing_MessagesViewWithTyping_Day_0_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.typing_MessagesViewWithTyping_Day_0_en.png index 309c2bd605..0cb73c33e9 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.typing_MessagesViewWithTyping_Day_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.typing_MessagesViewWithTyping_Day_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:40960e8da93791449132dcc4c77a0ee4ca711358ea8f184c080bb4dddbe01724 -size 53669 +oid sha256:5c96744ce341811ece23e037fe15bdeeb48c7c6d9a0e931fec1bbd9993679aed +size 56230 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.typing_MessagesViewWithTyping_Day_1_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.typing_MessagesViewWithTyping_Day_1_en.png index 97450096ad..9f9598a575 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.typing_MessagesViewWithTyping_Day_1_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.typing_MessagesViewWithTyping_Day_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:e3505a9a29ca2636dbf201b1bdfb0a52d05ec885b5b14709dca3f3d1184cf258 -size 54547 +oid sha256:bb81645a873e815d96ec14efe0f84a2ff354093e62fb4957878bfc6ae214b9b8 +size 57067 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.typing_MessagesViewWithTyping_Day_2_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.typing_MessagesViewWithTyping_Day_2_en.png index 106395dcc2..a615304e7f 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.typing_MessagesViewWithTyping_Day_2_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.typing_MessagesViewWithTyping_Day_2_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c495a8d5d9d4cef2f258d39decc7c841b2bee5196a330944e745d78af42b046c -size 50595 +oid sha256:4886e89da091d3869bfedb4e6f50009976fcab59f9617b8a4083c00e7027459a +size 53118 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.typing_MessagesViewWithTyping_Night_0_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.typing_MessagesViewWithTyping_Night_0_en.png index fdd5741b35..fa8b564c04 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.typing_MessagesViewWithTyping_Night_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.typing_MessagesViewWithTyping_Night_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:43e55acf964c3bde105c3b00eaa9d67d9cdeb3334f0d641d18c5c2476a178655 -size 54416 +oid sha256:bc69aaab31d3f7e63b0481818b0c91c90aef44afc21ee06591ba69cdf45b978a +size 56712 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.typing_MessagesViewWithTyping_Night_1_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.typing_MessagesViewWithTyping_Night_1_en.png index 0e7b362a1c..c0d8ccb194 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.typing_MessagesViewWithTyping_Night_1_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.typing_MessagesViewWithTyping_Night_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:1c749a0dff6fa96383268514cc330e02d13c1f50e5e6d238539c612cad7ba54d -size 55283 +oid sha256:0123a32464a8ca8ca3f85af8bfde18aca054c63e91ec1264a54e0177c58f0d4b +size 57539 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.typing_MessagesViewWithTyping_Night_2_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.typing_MessagesViewWithTyping_Night_2_en.png index 9f47f82ec1..5d5d4daf56 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.typing_MessagesViewWithTyping_Night_2_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.typing_MessagesViewWithTyping_Night_2_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:d741537e51e539a627aaee9a567a52a5a96207c8dfb7d69ce799438179ad6c29 -size 51388 +oid sha256:d5b8ff0e7e06516a29694c46cd22c5f09f029725cc3556c92a4491c00868151f +size 53662 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_0_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_0_en.png index fb3f6bcbad..315f5a6852 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ff311eba5365bb2a726eb59b71ecc40295032003dd5e03587efed086bdca79ec -size 55228 +oid sha256:277463b454876b3bff870e27deafd2b1d7affcdb5b72efcbb33bc4bfeac0a961 +size 56838 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_10_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_10_en.png index 3b7df7988e..8707889672 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_10_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_10_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a24bfa8d881fac3d302898f7721c202c4cdedb37d4a75277cdc551a3a4e6ab80 -size 56882 +oid sha256:50517ad2782539a02ad2ac302e15da20f70e48f7b3ceab9438f41f4cb590d35a +size 58414 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_11_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_11_en.png index 8fdd7ef2a3..c1ff22b537 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_11_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_11_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:6bca01015488a95b5a7daf277fe2e8114012e26ddacad195ddffba6c30edb080 -size 47104 +oid sha256:d5f6843d5976f1b476f36a01e6db8cce729862a5d138f23b2053f4a2f085d6df +size 48527 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_12_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_12_en.png index 5f698df606..2d5a682ca0 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_12_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_12_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:b2b13b08c823c492457daf9b54ae17616845154af22a58880cd1081ab38b304c -size 55264 +oid sha256:3f2e8218de84709a8f42a9b4594c92da51a0427651de3c85885e8f147527bad9 +size 56860 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_13_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_13_en.png new file mode 100644 index 0000000000..c1200f26b4 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_13_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:35761e520dcd7ad01d3913a98479314a1df645bdf141214e3a180fe150d2e8fd +size 59959 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_1_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_1_en.png index c50c0cac8b..aa177b86a8 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_1_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:8424c63cd12ce518c096d62c8aeeffc5d7f7308fed1c1612dca7ad8e832606c4 -size 54790 +oid sha256:26490a489101d7718b08a7a85982af6dc1458dd01a1b9491903278d66724d0b6 +size 55998 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_3_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_3_en.png index 6f7fa71e13..670b6e71d2 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_3_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_3_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:8292a8b339592e3caf7118a16584ca41754900f03a8fa89bbc2424d2c3a6c9f1 -size 57701 +oid sha256:b3d185905f72389bd4edbed4d2ec7b6f4547465004174a1c798e604e83f84363 +size 59845 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_4_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_4_en.png index ff5fb09de4..d8eb4d59a7 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_4_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_4_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:21f6c7ac3951f1aca51d6a2eabca7fdbdb1e00b3b3a3c44c96dae180bbee3623 -size 53216 +oid sha256:60cb1e0ab614fd719991e6c27ffdec3f68b6d9c6a7e0c5a8294eab3e4e51fa89 +size 54618 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_5_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_5_en.png index 50322c59cf..3fca9380fb 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_5_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_5_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:d6db28acda62e4343ba7b4f64f31070253fe968f6ed8464afb1bb54506353278 -size 53081 +oid sha256:28615c037c99b201dd987faa83b4d184b7c593d0f3871c8f731d681ee6795a1d +size 54688 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_6_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_6_en.png index 69801a6993..850098bf34 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_6_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_6_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:806695481b7fe30e0c315b2e46c6fe48c21a1cedbfaf21736ad2716a41212473 -size 53645 +oid sha256:b6c85d42e90ea4c60d2cd4e0ac96fc38cb45504e1d863a4283f157f23e790899 +size 54346 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_7_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_7_en.png index 45e3b40177..ac7ade1342 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_7_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_7_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c46f2842388c3d2d14cddae957ccc74c4a108faceff36846f5ca7daa00b9f593 -size 56398 +oid sha256:e5cbd166edeaec6ab06a5da87a0a023adfbb6f2e9727b4471c5586a2b897dbab +size 57729 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_8_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_8_en.png index fe804c04af..176a8a9941 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_8_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_8_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:7e85f80a115c90586f81127b87aa5874a2f811d15c6af443bc0f0d7078c85f4e -size 38280 +oid sha256:8170faa5461e703c09803966cb25be7da37cbad08d6c8e21584c75eccf8a7d29 +size 39873 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_9_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_9_en.png index c344a1583e..04baf108ba 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_9_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_9_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a9ae1d25882c0c05723b68c61f97ac4ff2423750913f1f3186a6dad48e845e8e -size 37557 +oid sha256:1362fddcca30b31f92575d3e8020b4dc1c415ed0afefe29c56d5f2179d6a35f1 +size 39043 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_0_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_0_en.png index ae3271ee83..becc913996 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:1e1974d0ec89208a55b0faeb230c89fc3ed10c1d4bead234dc39c06169ab24ca -size 55060 +oid sha256:16afa707859ef41a8420eec52f3e7e2e2c0d2dcf4b438e068468dcaa77fd4200 +size 56547 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_10_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_10_en.png index 439ce25005..2c0cfc57da 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_10_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_10_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:74a2c962831b6468dbff878d6f55460a5cdbc3d06c7566cecfb89b7bcf049b18 -size 56600 +oid sha256:ce3e8d221e1a4c9557fabd5902dd507d3c9a6774c4185612b708ef80499e13d3 +size 58015 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_11_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_11_en.png index c74b552192..b5146ab82b 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_11_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_11_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:e468164817c0e6302c1f8cacecb24daed2fe65eb5453723186651dc7bc1851cf -size 43297 +oid sha256:4dbd737eaa65c834550ab421e4e3ee5c77701ab58ce06197048dbf8e044c548a +size 44487 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_12_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_12_en.png index 7c09af645a..a39a656f25 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_12_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_12_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ad336e1b96ac2528cd1d7573fda649e5fe09235b72d555d79f32cca4eb8c1c05 -size 55084 +oid sha256:0bdec5d25d991452633e77e4d5c2468d4b48cd880fbfb713a6c3b897cbdde921 +size 56587 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_13_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_13_en.png new file mode 100644 index 0000000000..704ea5bb60 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_13_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:acd2cf24e0a894936d6ed0896fb4ebcdba3529437e595ca54aa13a6f8ee79a5f +size 59327 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_1_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_1_en.png index b935cc06e7..08e5acbbc8 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_1_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:d5b9fe533cfad8892708a609a79fa1f8bed95ad8fb20b979993da9b2d1ea380d -size 54511 +oid sha256:872853bf96c32e0f375d6ec772437e27e21d16506f7fa2f7853ef91cd274bb28 +size 55440 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_3_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_3_en.png index 0cc32b0dbf..0e7a7f783c 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_3_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_3_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a4d0b4ab8e2234e08ca7c67d4653729abcf2c4ed055b983fdde15589daaf0124 -size 57234 +oid sha256:86a3e684d4a794915344963c4dd26e1e68729e7e5d9c4091c7824cf0901684b3 +size 59342 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_4_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_4_en.png index b513f8b897..4776d19372 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_4_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_4_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a4a32531adceea6b03b25291435fb2df753868571b3edf3ea29f00353d07087e -size 49544 +oid sha256:c446a2b24ae180496649f518f53f15f939c1e166093b82e479d2d7f1a8a7829d +size 50742 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_5_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_5_en.png index bb7da5784e..70caedc0cf 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_5_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_5_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:534490ea60a6078200761864dd112f54be124647f818ccec77fb986ea71582a8 -size 52689 +oid sha256:3df1d346ea653cfafea9e2e13a7ff47017a480ce593d1c959553e7b8073f0250 +size 54217 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_6_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_6_en.png index 1eb51aad8a..6cc5a72d24 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_6_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_6_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:2063163a5ac3c78398df388b9e471362a32244d5bdf4790409358640b5cfb15f -size 53399 +oid sha256:6dcf842a6bc3abfc9168b0e30354f3de2f72bddb04b203dcf9d211c77155bcfd +size 53901 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_7_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_7_en.png index a8c890d748..bcc10ece2a 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_7_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_7_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:5d0d0b885ae157ff456d7113707bc72f3ced9ab74c895cdf7377adc1bc8c48db -size 52373 +oid sha256:8639bc9d5728e8bf5b1b3ab76aff16aacf89ff15397770f08c5211dc9342fa78 +size 53545 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_8_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_8_en.png index ecdeb0c387..2d560199c1 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_8_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_8_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:828b9893e06b168b16b42950f42b89ecc51b73c9b425732d379a72d737f04491 -size 36126 +oid sha256:310862ba0323270901b3a554ff230931a75de56a77487c7b0e63137f90cc0214 +size 37398 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_9_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_9_en.png index 5920916813..df43160511 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_9_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_9_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f251ca0e5c4f98b7c5889b42161e4d52f3faf37850c242122aac2d124a1357b1 -size 35393 +oid sha256:5abde960f15c7d28e6fc538f5450f277e89ee17893e12daaba004ca7a0f09974 +size 36656 diff --git a/tests/uitests/src/test/snapshots/images/features.preferences.impl.developer_DeveloperSettingsView_Day_0_en.png b/tests/uitests/src/test/snapshots/images/features.preferences.impl.developer_DeveloperSettingsView_Day_0_en.png index e3a0f6e67e..d46d57762d 100644 --- a/tests/uitests/src/test/snapshots/images/features.preferences.impl.developer_DeveloperSettingsView_Day_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.preferences.impl.developer_DeveloperSettingsView_Day_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:db1631ff53075b31c674cde4bf25cc2876cda8053ffcb593bf6c497c5c41d0c4 -size 49825 +oid sha256:fb9971d6aa7f0734f9a30f83b25a03519f97789618219f0c79efa87d4430ca0f +size 58918 diff --git a/tests/uitests/src/test/snapshots/images/features.preferences.impl.developer_DeveloperSettingsView_Day_1_en.png b/tests/uitests/src/test/snapshots/images/features.preferences.impl.developer_DeveloperSettingsView_Day_1_en.png index e3a0f6e67e..d46d57762d 100644 --- a/tests/uitests/src/test/snapshots/images/features.preferences.impl.developer_DeveloperSettingsView_Day_1_en.png +++ b/tests/uitests/src/test/snapshots/images/features.preferences.impl.developer_DeveloperSettingsView_Day_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:db1631ff53075b31c674cde4bf25cc2876cda8053ffcb593bf6c497c5c41d0c4 -size 49825 +oid sha256:fb9971d6aa7f0734f9a30f83b25a03519f97789618219f0c79efa87d4430ca0f +size 58918 diff --git a/tests/uitests/src/test/snapshots/images/features.preferences.impl.developer_DeveloperSettingsView_Day_2_en.png b/tests/uitests/src/test/snapshots/images/features.preferences.impl.developer_DeveloperSettingsView_Day_2_en.png index df320f9fd7..5119090213 100644 --- a/tests/uitests/src/test/snapshots/images/features.preferences.impl.developer_DeveloperSettingsView_Day_2_en.png +++ b/tests/uitests/src/test/snapshots/images/features.preferences.impl.developer_DeveloperSettingsView_Day_2_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:d7f5ea92f8413f6b6dc92d074038727036912ef1828210d0c4d6e36fb0f7e5d3 -size 48352 +oid sha256:f44fc0dc3cd92839a7b176b086be75b082a238b9c8cd197f7273b33e7f01c591 +size 57495 diff --git a/tests/uitests/src/test/snapshots/images/features.preferences.impl.developer_DeveloperSettingsView_Night_0_en.png b/tests/uitests/src/test/snapshots/images/features.preferences.impl.developer_DeveloperSettingsView_Night_0_en.png index 91914c2851..2294fd4c8a 100644 --- a/tests/uitests/src/test/snapshots/images/features.preferences.impl.developer_DeveloperSettingsView_Night_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.preferences.impl.developer_DeveloperSettingsView_Night_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ead9e1fe98bc9ffd33d3768e6983964768edbf3bb4c75cd78a82da5ec0eae03b -size 48275 +oid sha256:93a6d6723bc89b9660a440848461c1568004d312599d7d2d2b94299d6aa47c0a +size 57037 diff --git a/tests/uitests/src/test/snapshots/images/features.preferences.impl.developer_DeveloperSettingsView_Night_1_en.png b/tests/uitests/src/test/snapshots/images/features.preferences.impl.developer_DeveloperSettingsView_Night_1_en.png index 91914c2851..2294fd4c8a 100644 --- a/tests/uitests/src/test/snapshots/images/features.preferences.impl.developer_DeveloperSettingsView_Night_1_en.png +++ b/tests/uitests/src/test/snapshots/images/features.preferences.impl.developer_DeveloperSettingsView_Night_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ead9e1fe98bc9ffd33d3768e6983964768edbf3bb4c75cd78a82da5ec0eae03b -size 48275 +oid sha256:93a6d6723bc89b9660a440848461c1568004d312599d7d2d2b94299d6aa47c0a +size 57037 diff --git a/tests/uitests/src/test/snapshots/images/features.preferences.impl.developer_DeveloperSettingsView_Night_2_en.png b/tests/uitests/src/test/snapshots/images/features.preferences.impl.developer_DeveloperSettingsView_Night_2_en.png index c3c8c2ac12..1e6522216a 100644 --- a/tests/uitests/src/test/snapshots/images/features.preferences.impl.developer_DeveloperSettingsView_Night_2_en.png +++ b/tests/uitests/src/test/snapshots/images/features.preferences.impl.developer_DeveloperSettingsView_Night_2_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ee30083ec3b87ba84a34bdee7b10d50939f31c596c3358bdca9b914ba001d198 -size 46843 +oid sha256:bd7e58a29f370733af1e35531f428d5d2a732c70b9156d66ba590c9c5203f5d6 +size 55689 diff --git a/tools/sdk/build_rust_sdk.sh b/tools/sdk/build_rust_sdk.sh index 2e4be2e6aa..06662a36e6 100755 --- a/tools/sdk/build_rust_sdk.sh +++ b/tools/sdk/build_rust_sdk.sh @@ -7,7 +7,12 @@ set -e read -p "Do you want to build the Rust SDK from local source (yes/no) default to yes? " buildLocal buildLocal=${buildLocal:-yes} -date=$(gdate +%Y%m%d%H%M%S) +if [[ "$OSTYPE" == "linux-gnu"* ]]; then + date=$(date +%Y%m%d%H%M%S) +else + date=$(gdate +%Y%m%d%H%M%S) +fi + elementPwd=$(pwd) # Ask for the Rust SDK local source path