From 5f29446f758b18eee39d53b6fea7a6a799bf2d98 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jorge=20Mart=C3=ADn?= Date: Tue, 24 Feb 2026 18:14:24 +0100 Subject: [PATCH 01/60] Changelog for version 26.03.0 --- CHANGES.md | 57 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/CHANGES.md b/CHANGES.md index 9d16fcaed5..db83dedb33 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,3 +1,60 @@ +Changes in Element X v26.03.0 +============================= + + + +## What's Changed +### ✨ Features +* Let enterprise build be able to use a different notification channel for noisy notification. by @bmarty in https://github.com/element-hq/element-x-android/pull/6177 +### 🙌 Improvements +* Notification fallback counter by @bmarty in https://github.com/element-hq/element-x-android/pull/6181 +* Sort audio device by device type before sending the list to Element Call by @bmarty in https://github.com/element-hq/element-x-android/pull/6160 +### 🐛 Bugfixes +* Fix stack overflow when quickly going back on a `Space` screen by @jmartinesp in https://github.com/element-hq/element-x-android/pull/6180 +* Rely on the SessionObserver to detect a sign out. by @bmarty in https://github.com/element-hq/element-x-android/pull/6182 +* When linkifying, adjust the `URLSpan`'s url too by @jmartinesp in https://github.com/element-hq/element-x-android/pull/6188 +* Fix call button color and ensure call can always be declined from the notification by @bmarty in https://github.com/element-hq/element-x-android/pull/6195 +* Try to fix common issue with the top app bar by @jmartinesp in https://github.com/element-hq/element-x-android/pull/6187 +* Limit the max number of opened rooms in the backstack by @jmartinesp in https://github.com/element-hq/element-x-android/pull/6215 +* Remove all video metadata from externally shared videos by @jmartinesp in https://github.com/element-hq/element-x-android/pull/6224 +* Remove `runBlocking` call to restore sessions when the app starts by @jmartinesp in https://github.com/element-hq/element-x-android/pull/6193 +* Catch exceptions when changing the audio communication device by @jmartinesp in https://github.com/element-hq/element-x-android/pull/6226 +### 🗣 Translations +* Sync Strings by @ElementBot in https://github.com/element-hq/element-x-android/pull/6207 +### 🧱 Build +* Fix Maestro tests again by @jmartinesp in https://github.com/element-hq/element-x-android/pull/6167 +* Add free disk space action to CI actions by @jmartinesp in https://github.com/element-hq/element-x-android/pull/6212 +### 🚧 In development 🚧 +* Ensure that Element X can use the service from Element Classic. by @bmarty in https://github.com/element-hq/element-x-android/pull/6238 +### Dependency upgrades +* fix(deps): update activity to v1.12.4 by @renovate[bot] in https://github.com/element-hq/element-x-android/pull/6184 +* Update roborazzi to v1.59.0 by @renovate[bot] in https://github.com/element-hq/element-x-android/pull/6179 +* Update dependency androidx.compose:compose-bom to v2026.02.00 by @renovate[bot] in https://github.com/element-hq/element-x-android/pull/6172 +* Remove explicit dependency `androix.compose.material` by @jmartinesp in https://github.com/element-hq/element-x-android/pull/6199 +* Update metro to v0.10.4 by @renovate[bot] in https://github.com/element-hq/element-x-android/pull/6202 +* Update dependency org.matrix.rustcomponents:sdk-android to v26.2.16 by @renovate[bot] in https://github.com/element-hq/element-x-android/pull/6211 +* Update dependency com.posthog:posthog-android to v3.32.0 by @renovate[bot] in https://github.com/element-hq/element-x-android/pull/6210 +* Update dependency io.sentry:sentry-android to v8.33.0 by @renovate[bot] in https://github.com/element-hq/element-x-android/pull/6223 +* Update dependency org.matrix.rustcomponents:sdk-android to v26.02.19 by @renovate[bot] in https://github.com/element-hq/element-x-android/pull/6229 +* Update dependency org.unifiedpush.android:connector to v3.3.1 by @renovate[bot] in https://github.com/element-hq/element-x-android/pull/6214 +* Update dependency com.posthog:posthog-android to v3.32.2 by @renovate[bot] in https://github.com/element-hq/element-x-android/pull/6230 +* Update dependency io.github.zxing-cpp:android to v3 by @renovate[bot] in https://github.com/element-hq/element-x-android/pull/6170 +* Update kotlin to v2.3.6 by @renovate[bot] in https://github.com/element-hq/element-x-android/pull/6218 +* Update dependency org.matrix.rustcomponents:sdk-android to v26.03.0 by @renovate[bot] in https://github.com/element-hq/element-x-android/pull/6242 +### Others +* Remove `NavigationState.Space`. by @bmarty in https://github.com/element-hq/element-x-android/pull/6185 +* Fallback notification cleanup by @bmarty in https://github.com/element-hq/element-x-android/pull/6190 +* Use fade animation when replacing Placeholder by @ganfra in https://github.com/element-hq/element-x-android/pull/6216 +* request audio focus when recording voice messages by @vmfunc in https://github.com/element-hq/element-x-android/pull/6194 +* Disable the cross-process lock in the SDK by @jmartinesp in https://github.com/element-hq/element-x-android/pull/6231 +* Improve element gallery header by @bmarty in https://github.com/element-hq/element-x-android/pull/6239 +* Add extra analytics for notification performance by @jmartinesp in https://github.com/element-hq/element-x-android/pull/6237 + +## New Contributors +* @vmfunc made their first contribution in https://github.com/element-hq/element-x-android/pull/6194 + +**Full Changelog**: https://github.com/element-hq/element-x-android/compare/v26.02.0...v26.03.0 + Changes in Element X v26.02.0 ============================= From 4e6255eaccfc24aa204320c6b7eb46f8a9d6f85f Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 24 Feb 2026 21:06:57 +0000 Subject: [PATCH 02/60] Update coil to v3.4.0 --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 1ea2c839f7..068ba1bc83 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -39,7 +39,7 @@ datetime = "0.7.1" serialization_json = "1.10.0" #other -coil = "3.3.0" +coil = "3.4.0" # Rollback to 1.0.4, 1.0.5 has this issue: https://github.com/airbnb/Showkase/issues/420 showkase = "1.0.5" # There is some custom logic in `RootFlowNode` that may break because it reuses some Appyx internal APIs. From dc11430a73ba2f54c5c6a84d92efc41eda009709 Mon Sep 17 00:00:00 2001 From: Jorge Martin Espinosa Date: Wed, 25 Feb 2026 12:59:21 +0100 Subject: [PATCH 03/60] Add some DB optimizations (#6249) * Set a maximum journal size limit (WAL file size) of 25MB The previous value was null, which meant unlimited growth. This can affect performance, since the WAL file performance as a cache will worsen the larger it is * When scheduling the vacuum task, make sure the user has enough free disk storage, since vacuuming can duplicate the DB sizes in disk --- .../libraries/matrix/impl/storage/SqliteStoreBuilder.kt | 6 ++++-- .../PerformDatabaseVacuumWorkManagerRequest.kt | 8 +++++++- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/storage/SqliteStoreBuilder.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/storage/SqliteStoreBuilder.kt index 7b5d9fb31c..84f124868e 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/storage/SqliteStoreBuilder.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/storage/SqliteStoreBuilder.kt @@ -7,6 +7,8 @@ package io.element.android.libraries.matrix.impl.storage +import io.element.android.libraries.core.data.ByteUnit +import io.element.android.libraries.core.data.megaBytes import io.element.android.libraries.matrix.impl.paths.SessionPaths import org.matrix.rustcomponents.sdk.ClientBuilder import org.matrix.rustcomponents.sdk.SqliteStoreBuilder as SdkSqliteStoreBuilder @@ -17,12 +19,12 @@ interface SqliteStoreBuilder { } class RustSqliteStoreBuilder( - private val sessionPaths: SessionPaths, + sessionPaths: SessionPaths, ) : SqliteStoreBuilder { private var inner = SdkSqliteStoreBuilder( dataPath = sessionPaths.fileDirectory.absolutePath, cachePath = sessionPaths.cacheDirectory.absolutePath, - ) + ).journalSizeLimit(25.megaBytes.into(ByteUnit.BYTES).toUInt()) override fun passphrase(passphrase: String?): SqliteStoreBuilder { inner = inner.passphrase(passphrase) diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/workmanager/PerformDatabaseVacuumWorkManagerRequest.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/workmanager/PerformDatabaseVacuumWorkManagerRequest.kt index 9c192bd96d..a8636eb5d9 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/workmanager/PerformDatabaseVacuumWorkManagerRequest.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/workmanager/PerformDatabaseVacuumWorkManagerRequest.kt @@ -32,7 +32,13 @@ class PerformDatabaseVacuumWorkManagerRequest( .addTag(workManagerTag(sessionId, WorkManagerRequestType.DB_VACUUM)) .setInputData(data) // Only run when the device is idle to avoid impacting user experience - .setConstraints(Constraints.Builder().setRequiresDeviceIdle(true).build()) + .setConstraints( + Constraints.Builder() + .setRequiresDeviceIdle(true) + // Vacuuming can duplicate the DB sizes in disk + .setRequiresStorageNotLow(true) + .build() + ) .build() return Result.success(listOf(workRequest)) From fe4554703cd3f4768fbef42acf5a5da091257723 Mon Sep 17 00:00:00 2001 From: Jorge Martin Espinosa Date: Wed, 25 Feb 2026 13:04:07 +0100 Subject: [PATCH 04/60] Check if network access if blocked when fetching notifications (#6247) * Add `NetworkMonitor.isNetworkBlocked()`, use it to check if Doze prevented us from loading notifications * Only check if network is blocked after checking if we have a network available, otherwise it's always `true` * Extract `NetworkBlockedChecker` to handle deprecations more carefully --- .../networkmonitor/api/NetworkMonitor.kt | 5 +++ .../impl/DefaultNetworkMonitor.kt | 3 ++ .../impl/NetworkBlockedChecker.kt | 31 ++++++++++++++ .../networkmonitor/test/FakeNetworkMonitor.kt | 6 ++- .../workmanager/FetchNotificationsWorker.kt | 41 +++++++++++++------ 5 files changed, 72 insertions(+), 14 deletions(-) create mode 100644 features/networkmonitor/impl/src/main/kotlin/io/element/android/features/networkmonitor/impl/NetworkBlockedChecker.kt diff --git a/features/networkmonitor/api/src/main/kotlin/io/element/android/features/networkmonitor/api/NetworkMonitor.kt b/features/networkmonitor/api/src/main/kotlin/io/element/android/features/networkmonitor/api/NetworkMonitor.kt index 484a210380..7adc5ac102 100644 --- a/features/networkmonitor/api/src/main/kotlin/io/element/android/features/networkmonitor/api/NetworkMonitor.kt +++ b/features/networkmonitor/api/src/main/kotlin/io/element/android/features/networkmonitor/api/NetworkMonitor.kt @@ -20,4 +20,9 @@ interface NetworkMonitor { * A flow containing the current network connectivity status. */ val connectivity: StateFlow + + /** + * Checks if the active network is being blocked by Doze, even if it's available. + */ + fun isNetworkBlocked(): Boolean } diff --git a/features/networkmonitor/impl/src/main/kotlin/io/element/android/features/networkmonitor/impl/DefaultNetworkMonitor.kt b/features/networkmonitor/impl/src/main/kotlin/io/element/android/features/networkmonitor/impl/DefaultNetworkMonitor.kt index 8e10ceeabf..ebe5d6ed62 100644 --- a/features/networkmonitor/impl/src/main/kotlin/io/element/android/features/networkmonitor/impl/DefaultNetworkMonitor.kt +++ b/features/networkmonitor/impl/src/main/kotlin/io/element/android/features/networkmonitor/impl/DefaultNetworkMonitor.kt @@ -43,6 +43,9 @@ class DefaultNetworkMonitor( appCoroutineScope: CoroutineScope, ) : NetworkMonitor { private val connectivityManager: ConnectivityManager = context.getSystemService(ConnectivityManager::class.java) + private val blockedNetworkBlockedChecker = NetworkBlockedChecker(connectivityManager) + + override fun isNetworkBlocked(): Boolean = blockedNetworkBlockedChecker.isNetworkBlocked() override val connectivity: StateFlow = callbackFlow { diff --git a/features/networkmonitor/impl/src/main/kotlin/io/element/android/features/networkmonitor/impl/NetworkBlockedChecker.kt b/features/networkmonitor/impl/src/main/kotlin/io/element/android/features/networkmonitor/impl/NetworkBlockedChecker.kt new file mode 100644 index 0000000000..624f1ce6c7 --- /dev/null +++ b/features/networkmonitor/impl/src/main/kotlin/io/element/android/features/networkmonitor/impl/NetworkBlockedChecker.kt @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2026 Element Creations Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial. + * Please see LICENSE files in the repository root for full details. + */ + +@file:Suppress("DEPRECATION") + +package io.element.android.features.networkmonitor.impl + +import android.annotation.SuppressLint +import android.net.ConnectivityManager +import android.net.NetworkInfo + +/** + * Helper to check if the active network in [ConnectivityManager] is blocked. + * + * This is extracted to its own class because it uses deprecated APIs (but the only ones that are reliable) + * and we don't want to suppress deprecations everywhere. + */ +class NetworkBlockedChecker( + private val connectivityManager: ConnectivityManager, +) { + // The permission is granted by the manifest, false positive + @SuppressLint("MissingPermission") + fun isNetworkBlocked(): Boolean { + // This call is deprecated, but it seems like it's the only reliable way to tell if doze has blocked network access + return connectivityManager.activeNetworkInfo?.detailedState == NetworkInfo.DetailedState.BLOCKED + } +} diff --git a/features/networkmonitor/test/src/main/kotlin/io/element/android/features/networkmonitor/test/FakeNetworkMonitor.kt b/features/networkmonitor/test/src/main/kotlin/io/element/android/features/networkmonitor/test/FakeNetworkMonitor.kt index 37d569dbc6..d501eb5b5c 100644 --- a/features/networkmonitor/test/src/main/kotlin/io/element/android/features/networkmonitor/test/FakeNetworkMonitor.kt +++ b/features/networkmonitor/test/src/main/kotlin/io/element/android/features/networkmonitor/test/FakeNetworkMonitor.kt @@ -12,6 +12,10 @@ import io.element.android.features.networkmonitor.api.NetworkMonitor import io.element.android.features.networkmonitor.api.NetworkStatus import kotlinx.coroutines.flow.MutableStateFlow -class FakeNetworkMonitor(initialStatus: NetworkStatus = NetworkStatus.Connected) : NetworkMonitor { +class FakeNetworkMonitor( + initialStatus: NetworkStatus = NetworkStatus.Connected, + private val isNetworkBlockedLambda: () -> Boolean = { false }, +) : NetworkMonitor { override val connectivity = MutableStateFlow(initialStatus) + override fun isNetworkBlocked(): Boolean = isNetworkBlockedLambda() } diff --git a/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/workmanager/FetchNotificationsWorker.kt b/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/workmanager/FetchNotificationsWorker.kt index 72c3768deb..25517f9e91 100644 --- a/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/workmanager/FetchNotificationsWorker.kt +++ b/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/workmanager/FetchNotificationsWorker.kt @@ -34,6 +34,7 @@ import io.element.android.services.analytics.api.AnalyticsLongRunningTransaction import io.element.android.services.analytics.api.AnalyticsService import io.element.android.services.analytics.api.finishLongRunningTransaction import io.element.android.services.analytics.api.recordTransaction +import io.element.android.services.analyticsproviders.api.AnalyticsTransaction import io.element.android.services.toolbox.api.sdk.BuildVersionSdkIntProvider import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.first @@ -57,28 +58,21 @@ class FetchNotificationsWorker( override suspend fun doWork(): Result { Timber.d("FetchNotificationsWorker started") val requests = workerDataConverter.deserialize(inputData) ?: return Result.failure() - // Wait for network to be available, but not more than 10 seconds + val networkTimeoutSpans = requests.mapNotNull { request -> val parent = analyticsService.getLongRunningTransaction(AnalyticsLongRunningTransaction.PushToWorkManager(request.eventId.value)) parent?.startChild("Waiting for network connectivity", "await_network") } + + // Wait for network to be available, but not more than 10 seconds val hasNetwork = withTimeoutOrNull(10.seconds) { networkMonitor.connectivity.first { it == NetworkStatus.Connected } } != null - for (span in networkTimeoutSpans) { - span.finish() - } + networkTimeoutSpans.finish() - if (!hasNetwork) { - Timber.w("No network, retrying later") - for (request in requests) { - val eventId = request.eventId.value - analyticsService.finishLongRunningTransaction(AnalyticsLongRunningTransaction.PushToWorkManager(eventId)) - val parent = analyticsService.getLongRunningTransaction(AnalyticsLongRunningTransaction.PushToNotification(eventId)) - // Since we're retrying, start a new transaction - analyticsService.startLongRunningTransaction(AnalyticsLongRunningTransaction.PushToWorkManager(eventId), parent) - } + // If there is a problem with the updated network values, report it and retry if needed + if (reportConnectivityError(requests = requests, hasNetwork = hasNetwork, isNetworkBlocked = networkMonitor.isNetworkBlocked())) { return Result.retry() } @@ -157,6 +151,25 @@ class FetchNotificationsWorker( return Result.success() } + private fun reportConnectivityError(requests: List, hasNetwork: Boolean, isNetworkBlocked: Boolean): Boolean { + return if (!hasNetwork || isNetworkBlocked) { + for (request in requests) { + val eventId = request.eventId.value + analyticsService.finishLongRunningTransaction(AnalyticsLongRunningTransaction.PushToWorkManager(eventId)) { + it.putExtraData("has_network_connection", hasNetwork.toString()) + it.putExtraData("is_network_blocked", isNetworkBlocked.toString()) + } + val parent = analyticsService.getLongRunningTransaction(AnalyticsLongRunningTransaction.PushToNotification(eventId)) + // Since we're retrying, start a new transaction + analyticsService.startLongRunningTransaction(AnalyticsLongRunningTransaction.PushToWorkManager(eventId), parent) + } + Timber.w("FetchNotificationsWorker will retry. Has network connectivity: $hasNetwork. Is network blocked: $isNetworkBlocked") + true + } else { + false + } + } + private suspend fun performOpportunisticSyncIfNeeded( groupedRequests: Map>, ) { @@ -174,3 +187,5 @@ class FetchNotificationsWorker( @AssistedFactory interface Factory : MetroWorkerFactory.WorkerInstanceFactory } + +private fun Collection.finish() = forEach { it.finish() } From b4ee3b1dd6246990ab2cbde0825b090495e68471 Mon Sep 17 00:00:00 2001 From: chelsea Date: Mon, 12 Jan 2026 20:27:58 +0000 Subject: [PATCH 05/60] Use floating toolbar on homepage --- .../android/features/home/impl/HomeState.kt | 1 - .../android/features/home/impl/HomeView.kt | 82 ++++++++++--------- .../home/impl/components/HomeTopBar.kt | 23 +----- gradle/libs.versions.toml | 2 +- 4 files changed, 48 insertions(+), 60 deletions(-) diff --git a/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/HomeState.kt b/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/HomeState.kt index dbb994e23e..934dac831e 100644 --- a/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/HomeState.kt +++ b/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/HomeState.kt @@ -33,7 +33,6 @@ data class HomeState( val eventSink: (HomeEvent) -> Unit, ) { val isBackHandlerEnabled = currentHomeNavigationBarItem != HomeNavigationBarItem.Chats || roomListState.spaceFiltersState is SpaceFiltersState.Selected - val displayActions = currentHomeNavigationBarItem == HomeNavigationBarItem.Chats val displayRoomListFilters = currentHomeNavigationBarItem == HomeNavigationBarItem.Chats && roomListState.displayFilters val showNavigationBar = homeSpacesState.canCreateSpaces || homeSpacesState.spaceRooms.isNotEmpty() } diff --git a/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/HomeView.kt b/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/HomeView.kt index eee6f49db3..a57d8c8278 100644 --- a/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/HomeView.kt +++ b/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/HomeView.kt @@ -13,6 +13,7 @@ package io.element.android.features.home.impl import androidx.activity.compose.BackHandler import androidx.compose.foundation.background import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.calculateEndPadding import androidx.compose.foundation.layout.calculateStartPadding @@ -21,19 +22,25 @@ import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.padding import androidx.compose.foundation.lazy.rememberLazyListState import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi +import androidx.compose.material3.FabPosition +import androidx.compose.material3.FloatingToolbarDefaults.ScreenOffset +import androidx.compose.material3.HorizontalFloatingToolbar +import androidx.compose.material3.IconButton import androidx.compose.material3.TopAppBarDefaults import androidx.compose.material3.rememberTopAppBarState import androidx.compose.runtime.Composable import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope +import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.graphics.Color import androidx.compose.ui.input.nestedscroll.nestedScroll import androidx.compose.ui.platform.LocalLayoutDirection import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.PreviewParameter import androidx.compose.ui.unit.dp +import androidx.compose.ui.zIndex import dev.chrisbanes.haze.hazeEffect import dev.chrisbanes.haze.hazeSource import dev.chrisbanes.haze.materials.ExperimentalHazeMaterialsApi @@ -59,14 +66,11 @@ import io.element.android.libraries.designsystem.preview.ElementPreview import io.element.android.libraries.designsystem.preview.PreviewsDayNight import io.element.android.libraries.designsystem.theme.components.FloatingActionButton import io.element.android.libraries.designsystem.theme.components.Icon -import io.element.android.libraries.designsystem.theme.components.NavigationBar -import io.element.android.libraries.designsystem.theme.components.NavigationBarIcon -import io.element.android.libraries.designsystem.theme.components.NavigationBarItem -import io.element.android.libraries.designsystem.theme.components.NavigationBarText import io.element.android.libraries.designsystem.theme.components.Scaffold import io.element.android.libraries.designsystem.utils.snackbar.SnackbarHost import io.element.android.libraries.designsystem.utils.snackbar.rememberSnackbarHostState import io.element.android.libraries.matrix.api.core.RoomId +import io.element.android.libraries.ui.strings.CommonStrings import kotlinx.coroutines.launch @Composable @@ -198,7 +202,7 @@ private fun HomeScaffold( ) ) }, - bottomBar = { + floatingActionButton = { if (state.showNavigationBar) { val coroutineScope = rememberCoroutineScope() HomeBottomBar( @@ -222,13 +226,16 @@ private fun HomeScaffold( state.eventSink(HomeEvent.SelectHomeNavigationBarItem(item)) } }, - modifier = Modifier.hazeEffect( - state = hazeState, - style = HazeMaterials.thick(), - ) + floatingActionButton = { + when (state.currentHomeNavigationBarItem) { + HomeNavigationBarItem.Chats -> HomeFloatingActionButton(onStartChatClick, CommonStrings.action_create_a_room) + HomeNavigationBarItem.Spaces -> HomeFloatingActionButton(onCreateSpaceClick, CommonStrings.action_create_space) + } + } ) } }, + floatingActionButtonPosition = FabPosition.Center, content = { padding -> when (state.currentHomeNavigationBarItem) { HomeNavigationBarItem.Chats -> { @@ -286,50 +293,51 @@ private fun HomeScaffold( } } }, - floatingActionButton = { - if (state.displayActions) { - FloatingActionButton( - onClick = onStartChatClick, - ) { - Icon( - imageVector = CompoundIcons.Plus(), - contentDescription = stringResource(id = R.string.screen_roomlist_a11y_create_message), - ) - } - } - }, snackbarHost = { SnackbarHost(snackbarHostState) }, ) } +@Composable +private fun HomeFloatingActionButton( + onClick: () -> Unit, + contentDescription: Int, + modifier: Modifier = Modifier, +) { + FloatingActionButton(onClick = onClick, modifier = modifier) { + Icon( + imageVector = CompoundIcons.Plus(), + contentDescription = stringResource(id = contentDescription), + ) + } +} + +@OptIn(ExperimentalMaterial3ExpressiveApi::class, ExperimentalMaterial3Api::class) @Composable private fun HomeBottomBar( currentHomeNavigationBarItem: HomeNavigationBarItem, onItemClick: (HomeNavigationBarItem) -> Unit, + floatingActionButton: @Composable () -> Unit, modifier: Modifier = Modifier, ) { - NavigationBar( - containerColor = Color.Transparent, + HorizontalFloatingToolbar( + expanded = true, + floatingActionButton = floatingActionButton, modifier = modifier + .padding(bottom = ScreenOffset) + .zIndex(1f), ) { HomeNavigationBarItem.entries.forEach { item -> val isSelected = currentHomeNavigationBarItem == item - NavigationBarItem( - selected = isSelected, - onClick = { - onItemClick(item) - }, - icon = { - NavigationBarIcon( + IconButton( + onClick = { onItemClick(item) }, + ) { + Column(horizontalAlignment = Alignment.CenterHorizontally) { + Icon( imageVector = item.icon(isSelected), - ) - }, - label = { - NavigationBarText( - text = stringResource(item.labelRes), + contentDescription = stringResource(item.labelRes), ) } - ) + } } } } diff --git a/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/components/HomeTopBar.kt b/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/components/HomeTopBar.kt index 69547db58a..afba2e1b82 100644 --- a/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/components/HomeTopBar.kt +++ b/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/components/HomeTopBar.kt @@ -134,17 +134,13 @@ fun HomeTopBar( ) }, actions = { - when (selectedNavigationItem) { - HomeNavigationBarItem.Chats -> RoomListMenuItems( + if (selectedNavigationItem == HomeNavigationBarItem.Chats) { + RoomListMenuItems( onToggleSearch = onToggleSearch, onMenuActionClick = onMenuActionClick, canReportBug = canReportBug, spaceFiltersState = spaceFiltersState, ) - HomeNavigationBarItem.Spaces -> SpacesMenuItems( - canCreateSpaces = canCreateSpaces, - onCreateSpace = onCreateSpace - ) } }, // We want a 16dp left padding for the navigationIcon : @@ -230,21 +226,6 @@ private fun RoomListMenuItems( } } -@Composable -private fun SpacesMenuItems( - canCreateSpaces: Boolean, - onCreateSpace: () -> Unit -) { - if (canCreateSpaces) { - IconButton(onClick = onCreateSpace) { - Icon( - imageVector = CompoundIcons.Plus(), - contentDescription = stringResource(CommonStrings.action_create_space) - ) - } - } -} - @Composable private fun SpaceFilterButton( spaceFiltersState: SpaceFiltersState, diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 1ea2c839f7..45d8517fa8 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -120,7 +120,7 @@ androidx_preference = "androidx.preference:preference:1.2.1" androidx_webkit = "androidx.webkit:webkit:1.15.0" androidx_compose_bom = { module = "androidx.compose:compose-bom", version.ref = "compose_bom" } -androidx_compose_material3 = { module = "androidx.compose.material3:material3" } +androidx_compose_material3 = { module = "androidx.compose.material3:material3", version = '1.5.0-alpha11' } androidx_compose_material3_windowsizeclass = { module = "androidx.compose.material3:material3-window-size-class" } androidx_compose_material3_adaptive = "androidx.compose.material3:material3-adaptive-android:1.0.0-alpha06" androidx_compose_ui = { module = "androidx.compose.ui:ui" } From ed3a56cb9096cedfe6d54cd3bb16a35c4a6ca6c1 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 4 Feb 2026 17:33:19 +0100 Subject: [PATCH 06/60] Fix deprecation issue --- .../libraries/designsystem/theme/components/ListItem.kt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/theme/components/ListItem.kt b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/theme/components/ListItem.kt index 0da086725d..bbc97301dd 100644 --- a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/theme/components/ListItem.kt +++ b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/theme/components/ListItem.kt @@ -107,10 +107,10 @@ fun ListItem( onClick: (() -> Unit)? = null, ) { // We cannot just pass the disabled colors, they must be set manually: https://issuetracker.google.com/issues/280480132 - val headlineColor = if (enabled) colors.headlineColor else colors.disabledHeadlineColor - val supportingColor = if (enabled) colors.supportingTextColor else colors.disabledHeadlineColor.copy(alpha = 0.80f) - val leadingContentColor = if (enabled) colors.leadingIconColor else colors.disabledLeadingIconColor - val trailingContentColor = if (enabled) colors.trailingIconColor else colors.disabledTrailingIconColor + val headlineColor = if (enabled) colors.contentColor else colors.disabledContentColor + val supportingColor = if (enabled) colors.supportingContentColor else colors.disabledContentColor.copy(alpha = 0.80f) + val leadingContentColor = if (enabled) colors.leadingContentColor else colors.disabledLeadingContentColor + val trailingContentColor = if (enabled) colors.trailingContentColor else colors.disabledTrailingContentColor val decoratedHeadlineContent: @Composable () -> Unit = { CompositionLocalProvider( From afd7fc51c4372e6c6c50a1caf82c0d84a19315df Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 4 Feb 2026 17:48:02 +0100 Subject: [PATCH 07/60] Create HorizontalFloatingToolbar wrapper in our components. --- .../android/features/home/impl/HomeView.kt | 54 +++-- .../home/impl/components/HomeTopBar.kt | 10 - .../components/HorizontalFloatingToolbar.kt | 223 ++++++++++++++++++ 3 files changed, 252 insertions(+), 35 deletions(-) create mode 100644 libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/theme/components/HorizontalFloatingToolbar.kt diff --git a/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/HomeView.kt b/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/HomeView.kt index a57d8c8278..240307414b 100644 --- a/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/HomeView.kt +++ b/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/HomeView.kt @@ -13,7 +13,6 @@ package io.element.android.features.home.impl import androidx.activity.compose.BackHandler import androidx.compose.foundation.background import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.calculateEndPadding import androidx.compose.foundation.layout.calculateStartPadding @@ -25,14 +24,11 @@ import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi import androidx.compose.material3.FabPosition import androidx.compose.material3.FloatingToolbarDefaults.ScreenOffset -import androidx.compose.material3.HorizontalFloatingToolbar -import androidx.compose.material3.IconButton import androidx.compose.material3.TopAppBarDefaults import androidx.compose.material3.rememberTopAppBarState import androidx.compose.runtime.Composable import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope -import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.input.nestedscroll.nestedScroll import androidx.compose.ui.platform.LocalLayoutDirection @@ -65,6 +61,9 @@ import io.element.android.libraries.androidutils.throttler.FirstThrottler import io.element.android.libraries.designsystem.preview.ElementPreview import io.element.android.libraries.designsystem.preview.PreviewsDayNight import io.element.android.libraries.designsystem.theme.components.FloatingActionButton +import io.element.android.libraries.designsystem.theme.components.HorizontalFloatingToolbar +import io.element.android.libraries.designsystem.theme.components.HorizontalFloatingToolbarItem +import io.element.android.libraries.designsystem.theme.components.HorizontalFloatingToolbarSeparator import io.element.android.libraries.designsystem.theme.components.Icon import io.element.android.libraries.designsystem.theme.components.Scaffold import io.element.android.libraries.designsystem.utils.snackbar.SnackbarHost @@ -189,12 +188,10 @@ private fun HomeScaffold( onAccountSwitch = { state.eventSink(HomeEvent.SwitchToAccount(it)) }, - onCreateSpace = onCreateSpaceClick, scrollBehavior = scrollBehavior, displayFilters = state.displayRoomListFilters, filtersState = roomListState.filtersState, spaceFiltersState = roomListState.spaceFiltersState, - canCreateSpaces = state.homeSpacesState.canCreateSpaces, canReportBug = state.canReportBug, modifier = Modifier.hazeEffect( state = hazeState, @@ -226,12 +223,21 @@ private fun HomeScaffold( state.eventSink(HomeEvent.SelectHomeNavigationBarItem(item)) } }, - floatingActionButton = { - when (state.currentHomeNavigationBarItem) { - HomeNavigationBarItem.Chats -> HomeFloatingActionButton(onStartChatClick, CommonStrings.action_create_a_room) - HomeNavigationBarItem.Spaces -> HomeFloatingActionButton(onCreateSpaceClick, CommonStrings.action_create_space) + floatingActionButton = when (state.currentHomeNavigationBarItem) { + HomeNavigationBarItem.Chats -> { + { + HomeFloatingActionButton(onStartChatClick, CommonStrings.action_create_room) + } } - } + HomeNavigationBarItem.Spaces -> if (state.homeSpacesState.canCreateSpaces) { + { + HomeFloatingActionButton(onCreateSpaceClick, CommonStrings.action_create_space) + } + } else { + // No FAB for spaces if we cannot create spaces + null + } + }, ) } }, @@ -311,33 +317,31 @@ private fun HomeFloatingActionButton( } } -@OptIn(ExperimentalMaterial3ExpressiveApi::class, ExperimentalMaterial3Api::class) +@OptIn(ExperimentalMaterial3ExpressiveApi::class) @Composable private fun HomeBottomBar( currentHomeNavigationBarItem: HomeNavigationBarItem, onItemClick: (HomeNavigationBarItem) -> Unit, - floatingActionButton: @Composable () -> Unit, + floatingActionButton: (@Composable () -> Unit)?, modifier: Modifier = Modifier, ) { HorizontalFloatingToolbar( - expanded = true, floatingActionButton = floatingActionButton, modifier = modifier .padding(bottom = ScreenOffset) .zIndex(1f), ) { - HomeNavigationBarItem.entries.forEach { item -> - val isSelected = currentHomeNavigationBarItem == item - IconButton( - onClick = { onItemClick(item) }, - ) { - Column(horizontalAlignment = Alignment.CenterHorizontally) { - Icon( - imageVector = item.icon(isSelected), - contentDescription = stringResource(item.labelRes), - ) - } + HomeNavigationBarItem.entries.forEachIndexed { index, item -> + if (index > 0) { + HorizontalFloatingToolbarSeparator() } + val isSelected = currentHomeNavigationBarItem == item + HorizontalFloatingToolbarItem( + icon = item.icon(isSelected), + tooltipLabel = stringResource(item.labelRes), + isSelected = isSelected, + onClick = { onItemClick(item) }, + ) } } } diff --git a/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/components/HomeTopBar.kt b/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/components/HomeTopBar.kt index afba2e1b82..c6fed9b2f5 100644 --- a/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/components/HomeTopBar.kt +++ b/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/components/HomeTopBar.kt @@ -87,9 +87,7 @@ fun HomeTopBar( onMenuActionClick: (RoomListMenuAction) -> Unit, onOpenSettings: () -> Unit, onAccountSwitch: (SessionId) -> Unit, - onCreateSpace: () -> Unit, scrollBehavior: TopAppBarScrollBehavior, - canCreateSpaces: Boolean, canReportBug: Boolean, displayFilters: Boolean, filtersState: RoomListFiltersState, @@ -346,8 +344,6 @@ internal fun HomeTopBarPreview() = ElementPreview { onOpenSettings = {}, onAccountSwitch = {}, onToggleSearch = {}, - onCreateSpace = {}, - canCreateSpaces = true, canReportBug = true, displayFilters = true, filtersState = aRoomListFiltersState(), @@ -392,8 +388,6 @@ internal fun HomeTopBarSpacesPreview() = ElementPreview { onOpenSettings = {}, onAccountSwitch = {}, onToggleSearch = {}, - onCreateSpace = {}, - canCreateSpaces = true, canReportBug = true, displayFilters = false, filtersState = aRoomListFiltersState(), @@ -415,8 +409,6 @@ internal fun HomeTopBarWithIndicatorPreview() = ElementPreview { onOpenSettings = {}, onAccountSwitch = {}, onToggleSearch = {}, - onCreateSpace = {}, - canCreateSpaces = true, canReportBug = true, displayFilters = true, filtersState = aRoomListFiltersState(), @@ -438,8 +430,6 @@ internal fun HomeTopBarMultiAccountPreview() = ElementPreview { onOpenSettings = {}, onAccountSwitch = {}, onToggleSearch = {}, - onCreateSpace = {}, - canCreateSpaces = true, canReportBug = true, displayFilters = true, filtersState = aRoomListFiltersState(), diff --git a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/theme/components/HorizontalFloatingToolbar.kt b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/theme/components/HorizontalFloatingToolbar.kt new file mode 100644 index 0000000000..8cdb320d30 --- /dev/null +++ b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/theme/components/HorizontalFloatingToolbar.kt @@ -0,0 +1,223 @@ +/* + * Copyright (c) 2026 Element Creations Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial. + * Please see LICENSE files in the repository root for full details. + */ + +package io.element.android.libraries.designsystem.theme.components + +import androidx.compose.animation.core.FiniteAnimationSpec +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.PaddingValues +import androidx.compose.foundation.layout.RowScope +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.width +import androidx.compose.foundation.layout.widthIn +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi +import androidx.compose.material3.FilledIconButton +import androidx.compose.material3.FloatingToolbarColors +import androidx.compose.material3.FloatingToolbarDefaults +import androidx.compose.material3.FloatingToolbarHorizontalFabPosition +import androidx.compose.material3.FloatingToolbarScrollBehavior +import androidx.compose.material3.IconButtonDefaults +import androidx.compose.material3.TooltipAnchorPosition +import androidx.compose.material3.TooltipDefaults +import androidx.compose.material3.rememberTooltipState +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.Shape +import androidx.compose.ui.graphics.vector.ImageVector +import androidx.compose.ui.unit.Dp +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.atomic.atoms.CounterAtom +import io.element.android.libraries.designsystem.components.tooltip.PlainTooltip +import io.element.android.libraries.designsystem.components.tooltip.TooltipBox +import io.element.android.libraries.designsystem.preview.ElementPreview +import io.element.android.libraries.designsystem.preview.PreviewsDayNight + +/** + * Ref: https://www.figma.com/design/G1xy0HDZKJf5TCRFmKb5d5/Compound-Android-Components?node-id=4457-1136 + */ +@OptIn(ExperimentalMaterial3ExpressiveApi::class, ExperimentalMaterial3Api::class) +@Composable +fun HorizontalFloatingToolbar( + modifier: Modifier = Modifier, + expanded: Boolean = true, + floatingActionButton: (@Composable () -> Unit)? = null, + colors: FloatingToolbarColors = FloatingToolbarDefaults.standardFloatingToolbarColors().copy( + toolbarContainerColor = ElementTheme.colors.bgSubtleSecondary, + ), + contentPadding: PaddingValues = PaddingValues( + vertical = 8.dp, + horizontal = 12.dp, + ), + scrollBehavior: FloatingToolbarScrollBehavior? = null, + shape: Shape = FloatingToolbarDefaults.ContainerShape, + leadingContent: @Composable (RowScope.() -> Unit)? = null, + trailingContent: @Composable (RowScope.() -> Unit)? = null, + floatingActionButtonPosition: FloatingToolbarHorizontalFabPosition = + FloatingToolbarHorizontalFabPosition.End, + animationSpec: FiniteAnimationSpec = FloatingToolbarDefaults.animationSpec(), + expandedShadowElevation: Dp = 8.dp, + collapsedShadowElevation: Dp = if (floatingActionButton == null) { + FloatingToolbarDefaults.ContainerCollapsedElevation + } else { + FloatingToolbarDefaults.ContainerCollapsedElevationWithFab + }, + content: @Composable RowScope.() -> Unit, +) { + if (floatingActionButton == null) { + androidx.compose.material3.HorizontalFloatingToolbar( + expanded = expanded, + modifier = modifier, + colors = colors, + contentPadding = contentPadding, + scrollBehavior = scrollBehavior, + shape = shape, + leadingContent = leadingContent, + trailingContent = trailingContent, + expandedShadowElevation = expandedShadowElevation, + collapsedShadowElevation = collapsedShadowElevation, + content = content, + ) + } else { + androidx.compose.material3.HorizontalFloatingToolbar( + expanded = expanded, + floatingActionButton = floatingActionButton, + modifier = modifier, + colors = colors, + contentPadding = contentPadding, + scrollBehavior = scrollBehavior, + shape = shape, + floatingActionButtonPosition = floatingActionButtonPosition, + animationSpec = animationSpec, + expandedShadowElevation = expandedShadowElevation, + collapsedShadowElevation = collapsedShadowElevation, + content = content, + ) + } +} + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun HorizontalFloatingToolbarItem( + icon: ImageVector, + tooltipLabel: String, + isSelected: Boolean, + onClick: () -> Unit, + modifier: Modifier = Modifier, + counter: Int? = null, + forceRenderingTooltip: Boolean = false, +) { + TooltipBox( + positionProvider = + TooltipDefaults.rememberTooltipPositionProvider( + TooltipAnchorPosition.Above + ), + tooltip = { PlainTooltip { Text(tooltipLabel) } }, + state = rememberTooltipState( + initialIsVisible = forceRenderingTooltip, + ), + modifier = modifier, + ) { + val colors = if (isSelected) { + IconButtonDefaults.filledIconButtonColors().copy( + containerColor = ElementTheme.colors.bgCanvasDefault, + contentColor = ElementTheme.colors.iconPrimary, + ) + } else { + IconButtonDefaults.filledIconButtonColors().copy( + containerColor = Color.Transparent, + contentColor = ElementTheme.colors.iconSecondary, + ) + } + Box { + FilledIconButton( + modifier = Modifier.widthIn(min = 56.dp), + colors = colors, + onClick = onClick, + ) { + Icon( + modifier = Modifier.size(24.dp), + imageVector = icon, + contentDescription = tooltipLabel, + ) + } + if (counter != null) { + CounterAtom( + modifier = Modifier + .align(Alignment.TopEnd) + .padding(top = 6.dp, end = 3.dp), + count = counter, + textStyle = ElementTheme.typography.fontBodyXsMedium, + ) + } + } + } +} + +@Composable +fun HorizontalFloatingToolbarSeparator(modifier: Modifier = Modifier) { + Spacer(modifier = modifier.width(16.dp)) +} + +@PreviewsDayNight +@Composable +internal fun HorizontalFloatingToolbarPreview() = ElementPreview { + ContentToPreview( + floatingActionButton = { + FloatingActionButton( + onClick = {}, + ) { + Icon( + imageVector = CompoundIcons.Plus(), + contentDescription = null, + ) + } + } + ) +} + +@PreviewsDayNight +@Composable +internal fun HorizontalFloatingToolbarNoFabPreview() = ElementPreview { + ContentToPreview( + floatingActionButton = null, + ) +} + +@OptIn(ExperimentalMaterial3ExpressiveApi::class, ExperimentalMaterial3Api::class) +@Composable +private fun ContentToPreview( + floatingActionButton: (@Composable () -> Unit)?, +) { + HorizontalFloatingToolbar( + modifier = Modifier.padding(28.dp), + floatingActionButton = floatingActionButton, + ) { + listOf( + CompoundIcons.ChatSolid(), + CompoundIcons.Space(), + ).forEachIndexed { index, icon -> + if (index > 0) { + HorizontalFloatingToolbarSeparator() + } + HorizontalFloatingToolbarItem( + icon = icon, + tooltipLabel = "Label", + isSelected = index == 0, + counter = if (index == 0) 6 else null, + forceRenderingTooltip = true, + onClick = { }, + ) + } + } +} From 0f499567f9253c930cc45cd169e9b8491c0ccc97 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 5 Feb 2026 18:21:33 +0100 Subject: [PATCH 08/60] Fix Konsist test. --- .../io/element/android/tests/konsist/KonsistComposableTest.kt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/konsist/src/test/kotlin/io/element/android/tests/konsist/KonsistComposableTest.kt b/tests/konsist/src/test/kotlin/io/element/android/tests/konsist/KonsistComposableTest.kt index dcd689c14a..b37b64638f 100644 --- a/tests/konsist/src/test/kotlin/io/element/android/tests/konsist/KonsistComposableTest.kt +++ b/tests/konsist/src/test/kotlin/io/element/android/tests/konsist/KonsistComposableTest.kt @@ -47,6 +47,8 @@ class KonsistComposableTest { "CompoundSemanticColorsLightHc", "CompoundSemanticColorsDark", "CompoundSemanticColorsDarkHc", + "HorizontalFloatingToolbarItem", + "HorizontalFloatingToolbarSeparator", ) .assertTrue( additionalMessage = From 6665a80f9eea4afbf66a091f91a5aefd8d83491f Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 5 Feb 2026 21:33:41 +0100 Subject: [PATCH 09/60] Fix compilation issue after rebase. --- .../element/android/features/home/impl/components/HomeTopBar.kt | 2 -- 1 file changed, 2 deletions(-) diff --git a/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/components/HomeTopBar.kt b/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/components/HomeTopBar.kt index c6fed9b2f5..ff0fc00496 100644 --- a/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/components/HomeTopBar.kt +++ b/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/components/HomeTopBar.kt @@ -365,8 +365,6 @@ internal fun HomeTopBarSpaceFiltersSelectedPreview() = ElementPreview { onOpenSettings = {}, onAccountSwitch = {}, onToggleSearch = {}, - onCreateSpace = {}, - canCreateSpaces = true, canReportBug = true, displayFilters = true, filtersState = aRoomListFiltersState(), From 2ccfbec842b75a5648a53f351c0683a8ec95c7a9 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Fri, 6 Feb 2026 09:42:26 +0100 Subject: [PATCH 10/60] Fix lint issue. `floatingActionButton` must be the last parameter. --- .../kotlin/io/element/android/features/home/impl/HomeView.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/HomeView.kt b/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/HomeView.kt index 240307414b..6465eb9a38 100644 --- a/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/HomeView.kt +++ b/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/HomeView.kt @@ -322,8 +322,8 @@ private fun HomeFloatingActionButton( private fun HomeBottomBar( currentHomeNavigationBarItem: HomeNavigationBarItem, onItemClick: (HomeNavigationBarItem) -> Unit, - floatingActionButton: (@Composable () -> Unit)?, modifier: Modifier = Modifier, + floatingActionButton: (@Composable () -> Unit)?, ) { HorizontalFloatingToolbar( floatingActionButton = floatingActionButton, From f0f6b92b5e088dec28f1b05e824929f660de86f7 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Mon, 9 Feb 2026 09:43:25 +0100 Subject: [PATCH 11/60] Add Preview for the case empty space. --- .../android/features/home/impl/HomeStateProvider.kt | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/HomeStateProvider.kt b/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/HomeStateProvider.kt index 2c4c76fabe..ea9ff7a234 100644 --- a/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/HomeStateProvider.kt +++ b/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/HomeStateProvider.kt @@ -45,7 +45,12 @@ open class HomeStateProvider : PreviewParameterProvider { ), ) + RoomListStateProvider().values.map { aHomeState(roomListState = it) - } + } + aHomeState( + currentHomeNavigationBarItem = HomeNavigationBarItem.Spaces, + homeSpacesState = aHomeSpacesState( + spaceRooms = emptyList(), + ), + ) } internal fun aHomeState( From 56165b2fafcf42e6bb94a8085ea5d2af819f2e9f Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Mon, 9 Feb 2026 11:39:48 +0100 Subject: [PATCH 12/60] Fix navigation bar overlapping buttons in empty space view. --- .../features/home/impl/spaces/HomeSpacesView.kt | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/spaces/HomeSpacesView.kt b/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/spaces/HomeSpacesView.kt index b1000ecc39..4e93cec22d 100644 --- a/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/spaces/HomeSpacesView.kt +++ b/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/spaces/HomeSpacesView.kt @@ -115,6 +115,9 @@ fun HomeSpacesView( } } +/** + * Ref: https://www.figma.com/design/pDlJZGBsri47FNTXMnEdXB/Compound-Android-Templates?node-id=1763-74215&t=9IGKMXHDfTGAqzQK-4 + */ @Composable private fun EmptySpaceHomeView( onCreateSpaceClick: () -> Unit, @@ -144,7 +147,10 @@ private fun EmptySpaceHomeView( } }, footer = { - ButtonColumnMolecule { + ButtonColumnMolecule( + // Add a padding bottom for the navigation bar + modifier = Modifier.padding(bottom = 112.dp) + ) { Button( modifier = Modifier.fillMaxWidth(), text = stringResource(CommonStrings.action_create_space), @@ -159,8 +165,7 @@ private fun EmptySpaceHomeView( } } } - ) { - } + ) } @PreviewsDayNight From 42308f46bd1c88fccc47f9e2026111e845737dd4 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Mon, 9 Feb 2026 12:47:24 +0100 Subject: [PATCH 13/60] Increase content padding, and apply it to the space tab too. --- .../element/android/features/home/impl/HomeView.kt | 14 +++++--------- .../features/home/impl/spaces/HomeSpacesView.kt | 13 +++++++------ 2 files changed, 12 insertions(+), 15 deletions(-) diff --git a/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/HomeView.kt b/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/HomeView.kt index 6465eb9a38..ca5740e646 100644 --- a/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/HomeView.kt +++ b/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/HomeView.kt @@ -243,6 +243,9 @@ private fun HomeScaffold( }, floatingActionButtonPosition = FabPosition.Center, content = { padding -> + val contentPadding = PaddingValues( + bottom = 112.dp, + ) when (state.currentHomeNavigationBarItem) { HomeNavigationBarItem.Chats -> { RoomListContentView( @@ -256,15 +259,7 @@ private fun HomeScaffold( onConfirmRecoveryKeyClick = onConfirmRecoveryKeyClick, onRoomClick = ::onRoomClick, onCreateRoomClick = onStartChatClick, - contentPadding = PaddingValues( - // FAB height is 56dp, bottom padding is 16dp, we add 8dp as extra margin -> 56+16+8 = 80, - // and include provided bottom padding - // Disable contentPadding due to navigation issue using the keyboard - // See https://issuetracker.google.com/issues/436432313 - bottom = 80.dp, - // bottom = 80.dp + padding.calculateBottomPadding(), - // top = padding.calculateTopPadding() - ), + contentPadding = contentPadding, modifier = Modifier .padding( PaddingValues( @@ -287,6 +282,7 @@ private fun HomeScaffold( .padding(padding) .consumeWindowInsets(padding) .hazeSource(state = hazeState), + contentPadding = contentPadding, state = state.homeSpacesState, lazyListState = spacesLazyListState, onSpaceClick = { spaceId -> diff --git a/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/spaces/HomeSpacesView.kt b/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/spaces/HomeSpacesView.kt index 4e93cec22d..c563e6eb26 100644 --- a/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/spaces/HomeSpacesView.kt +++ b/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/spaces/HomeSpacesView.kt @@ -10,6 +10,7 @@ package io.element.android.features.home.impl.spaces import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.foundation.lazy.LazyColumn @@ -48,6 +49,7 @@ import kotlinx.collections.immutable.toImmutableList fun HomeSpacesView( state: HomeSpacesState, lazyListState: LazyListState, + contentPadding: PaddingValues, onSpaceClick: (RoomId) -> Unit, onCreateSpaceClick: () -> Unit, onExploreClick: () -> Unit, @@ -55,7 +57,7 @@ fun HomeSpacesView( ) { if (state.canCreateSpaces && state.spaceRooms.isEmpty()) { EmptySpaceHomeView( - modifier = modifier, + modifier = modifier.padding(contentPadding), onCreateSpaceClick = onCreateSpaceClick, onExploreClick = onExploreClick, canExploreSpaces = state.canExploreSpaces, @@ -63,7 +65,8 @@ fun HomeSpacesView( } else { LazyColumn( modifier = modifier, - state = lazyListState + state = lazyListState, + contentPadding = contentPadding, ) { val space = state.space when (space) { @@ -147,10 +150,7 @@ private fun EmptySpaceHomeView( } }, footer = { - ButtonColumnMolecule( - // Add a padding bottom for the navigation bar - modifier = Modifier.padding(bottom = 112.dp) - ) { + ButtonColumnMolecule { Button( modifier = Modifier.fillMaxWidth(), text = stringResource(CommonStrings.action_create_space), @@ -179,5 +179,6 @@ internal fun HomeSpacesViewPreview( onSpaceClick = {}, onCreateSpaceClick = {}, onExploreClick = {}, + contentPadding = PaddingValues(bottom = 112.dp), ) } From 89a6f5a7bfb8cfb141b7ea4285f71de62b5ed03a Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 25 Feb 2026 16:19:47 +0100 Subject: [PATCH 14/60] Update metro to v0.11.0 (#6245) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Update metro to v0.11.0 * Fix `@AssistedInject` usages Now the injected variables in the factories must match the names in the constructors --------- Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Co-authored-by: Jorge Martín --- .../impl/configureroom/ConfigureRoomPresenter.kt | 2 +- .../features/poll/impl/create/CreatePollNode.kt | 2 +- .../features/poll/impl/create/CreatePollPresenter.kt | 2 +- .../edit/EditDefaultNotificationSettingPresenter.kt | 2 +- .../features/viewfolder/impl/file/ViewFilePresenter.kt | 8 ++++---- gradle/libs.versions.toml | 2 +- .../matrix/impl/workmanager/VacuumDatabaseWorker.kt | 4 ++-- .../impl/gallery/voice/VoiceMessagePresenter.kt | 10 +++++----- .../push/impl/workmanager/FetchNotificationsWorker.kt | 4 ++-- .../impl/workmanager/FetchNotificationWorkerTest.kt | 2 +- .../voiceplayer/impl/VoiceMessageMediaRepo.kt | 8 ++++---- 11 files changed, 23 insertions(+), 23 deletions(-) diff --git a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomPresenter.kt b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomPresenter.kt index 91cc660333..38d6132e14 100644 --- a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomPresenter.kt +++ b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomPresenter.kt @@ -76,7 +76,7 @@ class ConfigureRoomPresenter( ) : Presenter { @AssistedFactory interface Factory { - fun create(isSpace: Boolean, parentSpaceId: RoomId?): ConfigureRoomPresenter + fun create(isSpace: Boolean, initialParentSpaceId: RoomId?): ConfigureRoomPresenter } private val cameraPermissionPresenter: PermissionsPresenter = permissionsPresenterFactory.create(android.Manifest.permission.CAMERA) diff --git a/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/create/CreatePollNode.kt b/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/create/CreatePollNode.kt index 9e08b58839..6c08549193 100644 --- a/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/create/CreatePollNode.kt +++ b/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/create/CreatePollNode.kt @@ -41,7 +41,7 @@ class CreatePollNode( private var isNavigatingUp = AtomicBoolean(false) private val presenter = presenterFactory.create( - backNavigator = { + navigateUp = { if (isNavigatingUp.compareAndSet(false, true)) { navigateUp() } diff --git a/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/create/CreatePollPresenter.kt b/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/create/CreatePollPresenter.kt index 6138bab2ae..8e01f1a3e4 100644 --- a/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/create/CreatePollPresenter.kt +++ b/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/create/CreatePollPresenter.kt @@ -50,7 +50,7 @@ class CreatePollPresenter( fun interface Factory { fun create( timelineMode: Timeline.Mode, - backNavigator: () -> Unit, + navigateUp: () -> Unit, mode: CreatePollMode ): CreatePollPresenter } diff --git a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/edit/EditDefaultNotificationSettingPresenter.kt b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/edit/EditDefaultNotificationSettingPresenter.kt index df5247188a..178f7033f3 100644 --- a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/edit/EditDefaultNotificationSettingPresenter.kt +++ b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/edit/EditDefaultNotificationSettingPresenter.kt @@ -47,7 +47,7 @@ class EditDefaultNotificationSettingPresenter( ) : Presenter { @AssistedFactory interface Factory { - fun create(oneToOne: Boolean): EditDefaultNotificationSettingPresenter + fun create(isOneToOne: Boolean): EditDefaultNotificationSettingPresenter } private val collator = Collator.getInstance().apply { diff --git a/features/viewfolder/impl/src/main/kotlin/io/element/android/features/viewfolder/impl/file/ViewFilePresenter.kt b/features/viewfolder/impl/src/main/kotlin/io/element/android/features/viewfolder/impl/file/ViewFilePresenter.kt index 615b77e10b..dd294bd53c 100644 --- a/features/viewfolder/impl/src/main/kotlin/io/element/android/features/viewfolder/impl/file/ViewFilePresenter.kt +++ b/features/viewfolder/impl/src/main/kotlin/io/element/android/features/viewfolder/impl/file/ViewFilePresenter.kt @@ -25,8 +25,8 @@ import kotlinx.coroutines.launch @AssistedInject class ViewFilePresenter( - @Assisted("path") val path: String, - @Assisted("name") val name: String, + @Assisted val path: String, + @Assisted val name: String, private val fileContentReader: FileContentReader, private val fileShare: FileShare, private val fileSave: FileSave, @@ -34,8 +34,8 @@ class ViewFilePresenter( @AssistedFactory interface Factory { fun create( - @Assisted("path") path: String, - @Assisted("name") name: String, + path: String, + name: String, ): ViewFilePresenter } diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 1ea2c839f7..e182dfa3f2 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -54,7 +54,7 @@ haze = "1.7.2" dependencyAnalysis = "3.5.1" # DI -metro = "0.10.4" +metro = "0.11.0" # Auto service autoservice = "1.1.1" diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/workmanager/VacuumDatabaseWorker.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/workmanager/VacuumDatabaseWorker.kt index d52edddbb4..a32fbabf9d 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/workmanager/VacuumDatabaseWorker.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/workmanager/VacuumDatabaseWorker.kt @@ -27,11 +27,11 @@ import timber.log.Timber @AssistedInject class VacuumDatabaseWorker( - @Assisted workerParams: WorkerParameters, + @Assisted params: WorkerParameters, @ApplicationContext private val context: Context, private val matrixClientProvider: MatrixClientProvider, private val analyticsService: AnalyticsService, -) : CoroutineWorker(context, workerParams) { +) : CoroutineWorker(context, params) { companion object { const val SESSION_ID_PARAM = "session_id" } diff --git a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/voice/VoiceMessagePresenter.kt b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/voice/VoiceMessagePresenter.kt index 4eac5a5ce3..32a9b0f74c 100644 --- a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/voice/VoiceMessagePresenter.kt +++ b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/voice/VoiceMessagePresenter.kt @@ -37,7 +37,7 @@ interface VoiceMessagePresenterModule { @AssistedInject class VoiceMessagePresenter( voiceMessagePresenterFactory: VoiceMessagePresenterFactory, - @Assisted private val item: MediaItem.Voice, + @Assisted private val content: MediaItem.Voice, ) : Presenter { @AssistedFactory fun interface Factory : MediaItemPresenterFactory { @@ -45,10 +45,10 @@ class VoiceMessagePresenter( } private val presenter = voiceMessagePresenterFactory.createVoiceMessagePresenter( - eventId = item.eventId, - mediaSource = item.mediaSource, - mimeType = item.mediaInfo.mimeType, - filename = item.mediaInfo.filename, + eventId = content.eventId, + mediaSource = content.mediaSource, + mimeType = content.mediaInfo.mimeType, + filename = content.mediaInfo.filename, // TODO Get the duration for the fallback? duration = Duration.ZERO, ) diff --git a/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/workmanager/FetchNotificationsWorker.kt b/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/workmanager/FetchNotificationsWorker.kt index 25517f9e91..23220cf366 100644 --- a/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/workmanager/FetchNotificationsWorker.kt +++ b/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/workmanager/FetchNotificationsWorker.kt @@ -44,7 +44,7 @@ import kotlin.time.Duration.Companion.seconds @AssistedInject class FetchNotificationsWorker( - @Assisted workerParams: WorkerParameters, + @Assisted params: WorkerParameters, @ApplicationContext private val context: Context, private val networkMonitor: NetworkMonitor, private val eventResolver: NotifiableEventResolver, @@ -54,7 +54,7 @@ class FetchNotificationsWorker( private val workerDataConverter: SyncNotificationsWorkerDataConverter, private val buildVersionSdkIntProvider: BuildVersionSdkIntProvider, private val analyticsService: AnalyticsService, -) : CoroutineWorker(context, workerParams) { +) : CoroutineWorker(context, params) { override suspend fun doWork(): Result { Timber.d("FetchNotificationsWorker started") val requests = workerDataConverter.deserialize(inputData) ?: return Result.failure() diff --git a/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/workmanager/FetchNotificationWorkerTest.kt b/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/workmanager/FetchNotificationWorkerTest.kt index c1e5d3c92f..99451027a8 100644 --- a/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/workmanager/FetchNotificationWorkerTest.kt +++ b/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/workmanager/FetchNotificationWorkerTest.kt @@ -170,7 +170,7 @@ class FetchNotificationWorkerTest { syncOnNotifiableEvent: SyncOnNotifiableEvent = SyncOnNotifiableEvent {}, analyticsService: FakeAnalyticsService = FakeAnalyticsService(), ) = FetchNotificationsWorker( - workerParams = createWorkerParams(workDataOf("requests" to input)), + params = createWorkerParams(workDataOf("requests" to input)), context = InstrumentationRegistry.getInstrumentation().context, networkMonitor = networkMonitor, eventResolver = eventResolver, diff --git a/libraries/voiceplayer/impl/src/main/kotlin/io/element/android/libraries/voiceplayer/impl/VoiceMessageMediaRepo.kt b/libraries/voiceplayer/impl/src/main/kotlin/io/element/android/libraries/voiceplayer/impl/VoiceMessageMediaRepo.kt index 310120c9fe..7cc09c4009 100644 --- a/libraries/voiceplayer/impl/src/main/kotlin/io/element/android/libraries/voiceplayer/impl/VoiceMessageMediaRepo.kt +++ b/libraries/voiceplayer/impl/src/main/kotlin/io/element/android/libraries/voiceplayer/impl/VoiceMessageMediaRepo.kt @@ -63,16 +63,16 @@ class DefaultVoiceMessageMediaRepo( mxcTools: MxcTools, private val matrixMediaLoader: MatrixMediaLoader, @Assisted private val mediaSource: MediaSource, - @Assisted("mimeType") private val mimeType: String?, - @Assisted("filename") private val filename: String?, + @Assisted private val mimeType: String?, + @Assisted private val filename: String?, ) : VoiceMessageMediaRepo { @ContributesBinding(RoomScope::class) @AssistedFactory fun interface Factory : VoiceMessageMediaRepo.Factory { override fun create( mediaSource: MediaSource, - @Assisted("mimeType") mimeType: String?, - @Assisted("filename") filename: String?, + @Assisted mimeType: String?, + @Assisted filename: String?, ): DefaultVoiceMessageMediaRepo } From f6537ea48a5317fca8c8fdb5213d567cc60d3888 Mon Sep 17 00:00:00 2001 From: ElementBot Date: Wed, 25 Feb 2026 15:49:13 +0000 Subject: [PATCH 15/60] Update screenshots --- ...eatures.home.impl.components_HomeTopBarSpaces_Day_0_en.png | 4 ++-- ...tures.home.impl.components_HomeTopBarSpaces_Night_0_en.png | 4 ++-- .../features.home.impl.spaces_HomeSpacesView_Day_0_en.png | 4 ++-- .../features.home.impl.spaces_HomeSpacesView_Day_1_en.png | 4 ++-- .../features.home.impl.spaces_HomeSpacesView_Day_2_en.png | 4 ++-- .../features.home.impl.spaces_HomeSpacesView_Day_3_en.png | 4 ++-- .../features.home.impl.spaces_HomeSpacesView_Night_0_en.png | 4 ++-- .../features.home.impl.spaces_HomeSpacesView_Night_1_en.png | 4 ++-- .../features.home.impl.spaces_HomeSpacesView_Night_2_en.png | 4 ++-- .../features.home.impl.spaces_HomeSpacesView_Night_3_en.png | 4 ++-- .../snapshots/images/features.home.impl_HomeViewA11y_en.png | 4 ++-- .../snapshots/images/features.home.impl_HomeView_Day_0_en.png | 4 ++-- .../images/features.home.impl_HomeView_Day_10_en.png | 4 ++-- .../images/features.home.impl_HomeView_Day_11_en.png | 4 ++-- .../images/features.home.impl_HomeView_Day_13_en.png | 4 ++-- .../images/features.home.impl_HomeView_Day_14_en.png | 4 ++-- .../images/features.home.impl_HomeView_Day_15_en.png | 4 ++-- .../images/features.home.impl_HomeView_Day_16_en.png | 3 +++ .../snapshots/images/features.home.impl_HomeView_Day_1_en.png | 4 ++-- .../snapshots/images/features.home.impl_HomeView_Day_2_en.png | 4 ++-- .../snapshots/images/features.home.impl_HomeView_Day_3_en.png | 4 ++-- .../snapshots/images/features.home.impl_HomeView_Day_4_en.png | 4 ++-- .../snapshots/images/features.home.impl_HomeView_Day_5_en.png | 4 ++-- .../snapshots/images/features.home.impl_HomeView_Day_9_en.png | 4 ++-- .../images/features.home.impl_HomeView_Night_0_en.png | 4 ++-- .../images/features.home.impl_HomeView_Night_10_en.png | 4 ++-- .../images/features.home.impl_HomeView_Night_11_en.png | 4 ++-- .../images/features.home.impl_HomeView_Night_13_en.png | 4 ++-- .../images/features.home.impl_HomeView_Night_14_en.png | 4 ++-- .../images/features.home.impl_HomeView_Night_15_en.png | 4 ++-- .../images/features.home.impl_HomeView_Night_16_en.png | 3 +++ .../images/features.home.impl_HomeView_Night_1_en.png | 4 ++-- .../images/features.home.impl_HomeView_Night_2_en.png | 4 ++-- .../images/features.home.impl_HomeView_Night_3_en.png | 4 ++-- .../images/features.home.impl_HomeView_Night_4_en.png | 4 ++-- .../images/features.home.impl_HomeView_Night_5_en.png | 4 ++-- .../images/features.home.impl_HomeView_Night_9_en.png | 4 ++-- ...eme.components_HorizontalFloatingToolbarNoFab_Day_0_en.png | 3 +++ ...e.components_HorizontalFloatingToolbarNoFab_Night_0_en.png | 3 +++ ...em.theme.components_HorizontalFloatingToolbar_Day_0_en.png | 3 +++ ....theme.components_HorizontalFloatingToolbar_Night_0_en.png | 3 +++ 41 files changed, 88 insertions(+), 70 deletions(-) create mode 100644 tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Day_16_en.png create mode 100644 tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Night_16_en.png create mode 100644 tests/uitests/src/test/snapshots/images/libraries.designsystem.theme.components_HorizontalFloatingToolbarNoFab_Day_0_en.png create mode 100644 tests/uitests/src/test/snapshots/images/libraries.designsystem.theme.components_HorizontalFloatingToolbarNoFab_Night_0_en.png create mode 100644 tests/uitests/src/test/snapshots/images/libraries.designsystem.theme.components_HorizontalFloatingToolbar_Day_0_en.png create mode 100644 tests/uitests/src/test/snapshots/images/libraries.designsystem.theme.components_HorizontalFloatingToolbar_Night_0_en.png diff --git a/tests/uitests/src/test/snapshots/images/features.home.impl.components_HomeTopBarSpaces_Day_0_en.png b/tests/uitests/src/test/snapshots/images/features.home.impl.components_HomeTopBarSpaces_Day_0_en.png index d90561efe5..690fad4569 100644 --- a/tests/uitests/src/test/snapshots/images/features.home.impl.components_HomeTopBarSpaces_Day_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.home.impl.components_HomeTopBarSpaces_Day_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:bf07c13a8f8b7da568e59441c7597de071f5d4ca728930a7cfba67500d981efd -size 12334 +oid sha256:499d48e33c188e42e066e30644d2ce4d1a2516b6b26d15c385d613234777d738 +size 12105 diff --git a/tests/uitests/src/test/snapshots/images/features.home.impl.components_HomeTopBarSpaces_Night_0_en.png b/tests/uitests/src/test/snapshots/images/features.home.impl.components_HomeTopBarSpaces_Night_0_en.png index 9fb1073d22..82f1da2494 100644 --- a/tests/uitests/src/test/snapshots/images/features.home.impl.components_HomeTopBarSpaces_Night_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.home.impl.components_HomeTopBarSpaces_Night_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:81bfe2cfe21bb21a41579e0cf81e020997de0c0f12b66b6db172d71120f72b90 -size 11420 +oid sha256:1f9d7c7900c41fbc10b27a68bf079e4750c28cfdcc4d96db35a79f3606cd5796 +size 11205 diff --git a/tests/uitests/src/test/snapshots/images/features.home.impl.spaces_HomeSpacesView_Day_0_en.png b/tests/uitests/src/test/snapshots/images/features.home.impl.spaces_HomeSpacesView_Day_0_en.png index 7034cfecc2..e91dd8db4d 100644 --- a/tests/uitests/src/test/snapshots/images/features.home.impl.spaces_HomeSpacesView_Day_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.home.impl.spaces_HomeSpacesView_Day_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:711645c8cd9bcd04105d2f0d1cf37376691d574340b815e5d9b98e9ecc8b8b23 -size 85538 +oid sha256:f3ac57efcab393ce13794dde2ad7e0d60757c0ef7fd0b09ff0a3c338de9a9edd +size 85467 diff --git a/tests/uitests/src/test/snapshots/images/features.home.impl.spaces_HomeSpacesView_Day_1_en.png b/tests/uitests/src/test/snapshots/images/features.home.impl.spaces_HomeSpacesView_Day_1_en.png index 35baea3173..de0717ece9 100644 --- a/tests/uitests/src/test/snapshots/images/features.home.impl.spaces_HomeSpacesView_Day_1_en.png +++ b/tests/uitests/src/test/snapshots/images/features.home.impl.spaces_HomeSpacesView_Day_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:67a160a71f24d46778cf03d7011d98ac6094b6efd1ba47845c4c36114fcec932 -size 38969 +oid sha256:f0567c1fe44efb4f9e188252a6840c228eb03e8d7954c95b79c693ac31451cd2 +size 38840 diff --git a/tests/uitests/src/test/snapshots/images/features.home.impl.spaces_HomeSpacesView_Day_2_en.png b/tests/uitests/src/test/snapshots/images/features.home.impl.spaces_HomeSpacesView_Day_2_en.png index 35baea3173..de0717ece9 100644 --- a/tests/uitests/src/test/snapshots/images/features.home.impl.spaces_HomeSpacesView_Day_2_en.png +++ b/tests/uitests/src/test/snapshots/images/features.home.impl.spaces_HomeSpacesView_Day_2_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:67a160a71f24d46778cf03d7011d98ac6094b6efd1ba47845c4c36114fcec932 -size 38969 +oid sha256:f0567c1fe44efb4f9e188252a6840c228eb03e8d7954c95b79c693ac31451cd2 +size 38840 diff --git a/tests/uitests/src/test/snapshots/images/features.home.impl.spaces_HomeSpacesView_Day_3_en.png b/tests/uitests/src/test/snapshots/images/features.home.impl.spaces_HomeSpacesView_Day_3_en.png index e60a137157..03d7d97186 100644 --- a/tests/uitests/src/test/snapshots/images/features.home.impl.spaces_HomeSpacesView_Day_3_en.png +++ b/tests/uitests/src/test/snapshots/images/features.home.impl.spaces_HomeSpacesView_Day_3_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:30b3ee70ad7dbd0b4f2db3b00b1edacecbbf3e2370798c60dc7696fe75cc843d -size 24704 +oid sha256:ecd79d3f8c4efbb54efa6a5b8dee79274ae9957b01146025dab42a45fc328fc0 +size 24740 diff --git a/tests/uitests/src/test/snapshots/images/features.home.impl.spaces_HomeSpacesView_Night_0_en.png b/tests/uitests/src/test/snapshots/images/features.home.impl.spaces_HomeSpacesView_Night_0_en.png index 6931ca307a..b27caf0acf 100644 --- a/tests/uitests/src/test/snapshots/images/features.home.impl.spaces_HomeSpacesView_Night_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.home.impl.spaces_HomeSpacesView_Night_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:45296f7e74f888e3b84f56f45b0d926970363013704ceb62df2afa132f81cbd5 -size 83671 +oid sha256:0f8a54913bd0c207088cec3c0fff9bcab4dca084884493a32a615fa728c40625 +size 83659 diff --git a/tests/uitests/src/test/snapshots/images/features.home.impl.spaces_HomeSpacesView_Night_1_en.png b/tests/uitests/src/test/snapshots/images/features.home.impl.spaces_HomeSpacesView_Night_1_en.png index 191da538c2..950cf73f60 100644 --- a/tests/uitests/src/test/snapshots/images/features.home.impl.spaces_HomeSpacesView_Night_1_en.png +++ b/tests/uitests/src/test/snapshots/images/features.home.impl.spaces_HomeSpacesView_Night_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:b9b9a37c8ed9650d16f498c3f00a182a83dc53892cbc8558c30138e0de56ad94 -size 37669 +oid sha256:949b1843a373b86fde0bb5a0a0637f938e87aeb3d36b8c146052e99874dfb4dd +size 37667 diff --git a/tests/uitests/src/test/snapshots/images/features.home.impl.spaces_HomeSpacesView_Night_2_en.png b/tests/uitests/src/test/snapshots/images/features.home.impl.spaces_HomeSpacesView_Night_2_en.png index 191da538c2..950cf73f60 100644 --- a/tests/uitests/src/test/snapshots/images/features.home.impl.spaces_HomeSpacesView_Night_2_en.png +++ b/tests/uitests/src/test/snapshots/images/features.home.impl.spaces_HomeSpacesView_Night_2_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:b9b9a37c8ed9650d16f498c3f00a182a83dc53892cbc8558c30138e0de56ad94 -size 37669 +oid sha256:949b1843a373b86fde0bb5a0a0637f938e87aeb3d36b8c146052e99874dfb4dd +size 37667 diff --git a/tests/uitests/src/test/snapshots/images/features.home.impl.spaces_HomeSpacesView_Night_3_en.png b/tests/uitests/src/test/snapshots/images/features.home.impl.spaces_HomeSpacesView_Night_3_en.png index 5259debb28..049aa93a8a 100644 --- a/tests/uitests/src/test/snapshots/images/features.home.impl.spaces_HomeSpacesView_Night_3_en.png +++ b/tests/uitests/src/test/snapshots/images/features.home.impl.spaces_HomeSpacesView_Night_3_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:b4649d1e05ab3b05d3bd730bc69a5e4398a0cb024027e9720be3bee2f49a4d01 -size 23757 +oid sha256:0fd37517b8913e2bac3275f717aa15bed18055a7525e0404b25b43cb8bd8422d +size 23840 diff --git a/tests/uitests/src/test/snapshots/images/features.home.impl_HomeViewA11y_en.png b/tests/uitests/src/test/snapshots/images/features.home.impl_HomeViewA11y_en.png index 49aba2ed82..8fdb3bb4e4 100644 --- a/tests/uitests/src/test/snapshots/images/features.home.impl_HomeViewA11y_en.png +++ b/tests/uitests/src/test/snapshots/images/features.home.impl_HomeViewA11y_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:86696c9ef71c5cf5edddf908e477d1e392fc9b3334a390df0fd2c2419c703de1 -size 142152 +oid sha256:c4bd92f12e7926f39cf7bb74fedd85b8295bff34da08e45229e2e1a8f83956c3 +size 144306 diff --git a/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Day_0_en.png b/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Day_0_en.png index fa17158336..e1a5813252 100644 --- a/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Day_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Day_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:dc87652e8e0ab0a215ca08ad64def6eb59a3c44a66af0f837cbeb7e1fd06701d -size 65071 +oid sha256:5f106b4672b1d96665fe731de28b7ccbb98f986580fd95cc6609a7b64348c60e +size 67665 diff --git a/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Day_10_en.png b/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Day_10_en.png index ab44f145fe..c52665e0ba 100644 --- a/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Day_10_en.png +++ b/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Day_10_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:7bdf23256bdc64325fab24411b39abc9fa62ced7f0bda1b24a4df387917064df -size 33352 +oid sha256:763715d657faecd68e201b7a110d022c04e27592bff499355662848455e2adc3 +size 36373 diff --git a/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Day_11_en.png b/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Day_11_en.png index 4119ce85b2..03ef9f63a7 100644 --- a/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Day_11_en.png +++ b/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Day_11_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:6eca672ad59f17058a552f712ce0fb27cca807bf2fcd1a96962fbf799861b5d3 -size 28046 +oid sha256:b0ecffc6b05c1bc3d0c6ba578d7ca7d50ac9c7a4948c53fe96d427c3ad6b4e4e +size 32289 diff --git a/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Day_13_en.png b/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Day_13_en.png index 7e43896431..5e008d0c1a 100644 --- a/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Day_13_en.png +++ b/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Day_13_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:583da21c83fff6ec3e81c3602b2cb8c1c3e5753f32892ab7ae70633ef6cf59e9 -size 83978 +oid sha256:b659de7521274ae555f962639d7e1652a22958c4b066dae3f2dd1aa70d93b78e +size 89194 diff --git a/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Day_14_en.png b/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Day_14_en.png index f68d68ce4c..7da3602182 100644 --- a/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Day_14_en.png +++ b/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Day_14_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:7ca16a8b022e217c954b322f463bf4cad125eed488a67d64712aefe04276a34e -size 82657 +oid sha256:bd11e404d07f8d790b1554c760f24e4e82614a331e16219c67c326b0375313f9 +size 84336 diff --git a/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Day_15_en.png b/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Day_15_en.png index 966a4a15f3..95177de294 100644 --- a/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Day_15_en.png +++ b/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Day_15_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f5f1c19e5c138ba9b4573041c11e771b74c6916faf7fec505cd9d545556d1583 -size 51083 +oid sha256:5406580880491251a8d61fc2fe26dab90153e6337f95dae3d6e4b1c5df7ac8f4 +size 53764 diff --git a/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Day_16_en.png b/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Day_16_en.png new file mode 100644 index 0000000000..ce51cc83f5 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Day_16_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:750a7b57fd2fd99f3cd0ad6e970692cdd8a7ad191dfb8fff0b5d0935461789db +size 42594 diff --git a/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Day_1_en.png b/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Day_1_en.png index fa17158336..e1a5813252 100644 --- a/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Day_1_en.png +++ b/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Day_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:dc87652e8e0ab0a215ca08ad64def6eb59a3c44a66af0f837cbeb7e1fd06701d -size 65071 +oid sha256:5f106b4672b1d96665fe731de28b7ccbb98f986580fd95cc6609a7b64348c60e +size 67665 diff --git a/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Day_2_en.png b/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Day_2_en.png index fa17158336..e1a5813252 100644 --- a/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Day_2_en.png +++ b/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Day_2_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:dc87652e8e0ab0a215ca08ad64def6eb59a3c44a66af0f837cbeb7e1fd06701d -size 65071 +oid sha256:5f106b4672b1d96665fe731de28b7ccbb98f986580fd95cc6609a7b64348c60e +size 67665 diff --git a/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Day_3_en.png b/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Day_3_en.png index 5f1c843c90..757e4d9506 100644 --- a/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Day_3_en.png +++ b/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Day_3_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:11e49c75d058dde6b661ed69684b679b0a86832e1f51e097ed96df03af29ef3f -size 61748 +oid sha256:f8bdb8d3e2dbb468115c4077f5bce6415a7708cbd04f825225139c1a2cbf788d +size 64647 diff --git a/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Day_4_en.png b/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Day_4_en.png index a822f082ad..be286098b3 100644 --- a/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Day_4_en.png +++ b/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Day_4_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:d31d6ae0f15ca0b2db8425cdd0588ee1be0ccae543588be32b34dda5d9d4246f -size 52454 +oid sha256:1ed6905e2833c7e927c84f0407a6218a4859a28f5a36a34c3a9b92f66347308a +size 56117 diff --git a/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Day_5_en.png b/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Day_5_en.png index fa17158336..e1a5813252 100644 --- a/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Day_5_en.png +++ b/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Day_5_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:dc87652e8e0ab0a215ca08ad64def6eb59a3c44a66af0f837cbeb7e1fd06701d -size 65071 +oid sha256:5f106b4672b1d96665fe731de28b7ccbb98f986580fd95cc6609a7b64348c60e +size 67665 diff --git a/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Day_9_en.png b/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Day_9_en.png index 4a071d692e..41552d0bf3 100644 --- a/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Day_9_en.png +++ b/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Day_9_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:7ca4ab313876d1c530d0829433b6a2c998afc4e761a1061364e3dbb457487646 -size 82515 +oid sha256:521e3b0b36dbed830eab8cd884a1924381bd9a50c189ff9ef074ed468aaf9b23 +size 84195 diff --git a/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Night_0_en.png b/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Night_0_en.png index abd3e3177f..d981f52759 100644 --- a/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Night_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Night_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:5dd233a5b5a17dfcdd16f70c354d33e74b6eb24180cc2235b41019684a1ab7fc -size 61852 +oid sha256:00af046190654a77e02d1152e8d44f538302b2fecfbd31b8790cdfa6f202dc1b +size 62502 diff --git a/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Night_10_en.png b/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Night_10_en.png index e20de845d2..beea74ec9f 100644 --- a/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Night_10_en.png +++ b/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Night_10_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ae78be15862aef18f0fe889c4df469cc7a3d77ebffbcf09c4b4c7baebb177e2f -size 30332 +oid sha256:86305c47144ed620efd27045239c0ca66f11cb5f2088b4df8e7f9e7a254576fa +size 31166 diff --git a/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Night_11_en.png b/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Night_11_en.png index 8920fb25c5..a7590f793b 100644 --- a/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Night_11_en.png +++ b/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Night_11_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ab5ddcdbb507c6c0953cd8b3bbddb73d9e98733d8edee5be37e012275a594db1 -size 24749 +oid sha256:cee0eefc4639ede46fd6539da213f0398de0611fc1e6f2002c6e014318c04380 +size 26665 diff --git a/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Night_13_en.png b/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Night_13_en.png index 36d5d025e9..a98cfc0be9 100644 --- a/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Night_13_en.png +++ b/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Night_13_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:5fc942ea686b3a58d930266a5cc7a9f663ff634512397be6f06850956f419b1e -size 79978 +oid sha256:1605040770a4b5d8928b41afab2e2f970f18283942659b2b869451e5c04d3d5b +size 83224 diff --git a/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Night_14_en.png b/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Night_14_en.png index 3512f168ba..b6f89c6e0f 100644 --- a/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Night_14_en.png +++ b/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Night_14_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:74ac553cb7d2bc0883cc1cc5f12d692dcaa63df6c1f6d84cf6e5cb099ad15159 -size 78750 +oid sha256:90bf5140e04bd22af001ed9d23513b26d555f2d73864d9012c8e05f452659fd8 +size 78641 diff --git a/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Night_15_en.png b/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Night_15_en.png index cf62a17e93..75156df8d2 100644 --- a/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Night_15_en.png +++ b/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Night_15_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:03ed724447496e01989773821c20594325c738389f61fd2af162e2d7d82b2651 -size 47386 +oid sha256:828d2d972c03e2cdb837e591c957c93fd61c1f49e3e4fcf19a8bf18963d4eb95 +size 48307 diff --git a/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Night_16_en.png b/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Night_16_en.png new file mode 100644 index 0000000000..ba6d02cb65 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Night_16_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:b1d6080fd17d90e63b4aae91c6a2c93bd16314eacc6007f57073e981c4dfb1c6 +size 37378 diff --git a/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Night_1_en.png b/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Night_1_en.png index abd3e3177f..d981f52759 100644 --- a/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Night_1_en.png +++ b/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Night_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:5dd233a5b5a17dfcdd16f70c354d33e74b6eb24180cc2235b41019684a1ab7fc -size 61852 +oid sha256:00af046190654a77e02d1152e8d44f538302b2fecfbd31b8790cdfa6f202dc1b +size 62502 diff --git a/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Night_2_en.png b/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Night_2_en.png index abd3e3177f..d981f52759 100644 --- a/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Night_2_en.png +++ b/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Night_2_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:5dd233a5b5a17dfcdd16f70c354d33e74b6eb24180cc2235b41019684a1ab7fc -size 61852 +oid sha256:00af046190654a77e02d1152e8d44f538302b2fecfbd31b8790cdfa6f202dc1b +size 62502 diff --git a/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Night_3_en.png b/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Night_3_en.png index 1c3d5da1bc..57b492b81d 100644 --- a/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Night_3_en.png +++ b/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Night_3_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:3c966a3f7d1fe4ba6e1fe73ca5fad71ef818433bc5fc35cc77b537f875dde0af -size 58907 +oid sha256:71e33566c0404f1930831b846a2e78952dd33138ffde5257c3d413739e225040 +size 60212 diff --git a/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Night_4_en.png b/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Night_4_en.png index bf037a7ab8..7f3194855d 100644 --- a/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Night_4_en.png +++ b/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Night_4_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:7c889d00a2dedf3f6ad596a819709daf9d6537314679a72143efbc2932d687da -size 50622 +oid sha256:363efc8054e6a1e04d0482e5351d7e190febf55167a0358d4251101ee6ebd659 +size 50942 diff --git a/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Night_5_en.png b/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Night_5_en.png index abd3e3177f..d981f52759 100644 --- a/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Night_5_en.png +++ b/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Night_5_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:5dd233a5b5a17dfcdd16f70c354d33e74b6eb24180cc2235b41019684a1ab7fc -size 61852 +oid sha256:00af046190654a77e02d1152e8d44f538302b2fecfbd31b8790cdfa6f202dc1b +size 62502 diff --git a/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Night_9_en.png b/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Night_9_en.png index 4e8afc6ddd..33074b9c42 100644 --- a/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Night_9_en.png +++ b/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Night_9_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f4dbf6e03444e3d28756abd6985be2f394317cc9e982a0b059f10fdc2d562d50 -size 78607 +oid sha256:465ffe0ea53fe7bde74c9dddb1be5e9f2861436b5292956f889dcf60db621af2 +size 78499 diff --git a/tests/uitests/src/test/snapshots/images/libraries.designsystem.theme.components_HorizontalFloatingToolbarNoFab_Day_0_en.png b/tests/uitests/src/test/snapshots/images/libraries.designsystem.theme.components_HorizontalFloatingToolbarNoFab_Day_0_en.png new file mode 100644 index 0000000000..ee5c582240 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/libraries.designsystem.theme.components_HorizontalFloatingToolbarNoFab_Day_0_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:75de341f705bb22955f9399180519b65ad59c2e1917317d56e50ea4db78f35bc +size 12102 diff --git a/tests/uitests/src/test/snapshots/images/libraries.designsystem.theme.components_HorizontalFloatingToolbarNoFab_Night_0_en.png b/tests/uitests/src/test/snapshots/images/libraries.designsystem.theme.components_HorizontalFloatingToolbarNoFab_Night_0_en.png new file mode 100644 index 0000000000..fedead0fa8 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/libraries.designsystem.theme.components_HorizontalFloatingToolbarNoFab_Night_0_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4811667dec0f32accc5e2c8a5dd5c0b34017fcff8d1e0376ee7a4708426bca0f +size 9838 diff --git a/tests/uitests/src/test/snapshots/images/libraries.designsystem.theme.components_HorizontalFloatingToolbar_Day_0_en.png b/tests/uitests/src/test/snapshots/images/libraries.designsystem.theme.components_HorizontalFloatingToolbar_Day_0_en.png new file mode 100644 index 0000000000..83302d6ba4 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/libraries.designsystem.theme.components_HorizontalFloatingToolbar_Day_0_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:16dee1dfe746cd40dac9fe8f0af3ecb42cd14bab5cc490917b589beed065ed1b +size 14686 diff --git a/tests/uitests/src/test/snapshots/images/libraries.designsystem.theme.components_HorizontalFloatingToolbar_Night_0_en.png b/tests/uitests/src/test/snapshots/images/libraries.designsystem.theme.components_HorizontalFloatingToolbar_Night_0_en.png new file mode 100644 index 0000000000..687e0d436a --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/libraries.designsystem.theme.components_HorizontalFloatingToolbar_Night_0_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d57df7110371c9224e232b707d6a1b10ce14afcb56c803a78220792f2a0d4cf2 +size 11354 From 8baa8b1c9de09ca4f1e29b141237e01caae1cbda Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 25 Feb 2026 18:45:08 +0100 Subject: [PATCH 16/60] Update dependency com.posthog:posthog-android to v3.34.0 (#6251) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index e182dfa3f2..8e2cb9e865 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -219,7 +219,7 @@ haze_materials = { module = "dev.chrisbanes.haze:haze-materials", version.ref = color_picker = "io.mhssn:colorpicker:1.0.0" # Analytics -posthog = "com.posthog:posthog-android:3.32.2" +posthog = "com.posthog:posthog-android:3.34.0" sentry = "io.sentry:sentry-android:8.33.0" # main branch can be tested replacing the version with main-SNAPSHOT matrix_analytics_events = "com.github.matrix-org:matrix-analytics-events:0.29.2" From 57f63eedbd592a9cf228a2231679943a92543b29 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 26 Feb 2026 05:57:36 +0000 Subject: [PATCH 17/60] Update metro to v0.11.1 --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 8e2cb9e865..992a8226c6 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -54,7 +54,7 @@ haze = "1.7.2" dependencyAnalysis = "3.5.1" # DI -metro = "0.11.0" +metro = "0.11.1" # Auto service autoservice = "1.1.1" From f0fb6248759d6dfa3fa6e90483f7c04d6fbb485f Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 26 Feb 2026 18:04:41 +0100 Subject: [PATCH 18/60] Update dependency io.element.android:element-call-embedded to v0.17.0 (#6244) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 8cf4face12..1ff5023900 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -232,7 +232,7 @@ sigpwned_emoji4j = "com.sigpwned:emoji4j-core:16.0.0" metro_runtime = { module = "dev.zacsweers.metro:runtime", version.ref = "metro" } # Element Call -element_call_embedded = "io.element.android:element-call-embedded:0.16.3" +element_call_embedded = "io.element.android:element-call-embedded:0.17.0" # Auto services google_autoservice = { module = "com.google.auto.service:auto-service", version.ref = "autoservice" } From e578336c4977e5b3815cf080e5abf2a8c7fb14b7 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 26 Feb 2026 18:05:07 +0100 Subject: [PATCH 19/60] Update dependency com.posthog:posthog-android to v3.34.2 (#6254) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 1ff5023900..dc3b3fb4f1 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -219,7 +219,7 @@ haze_materials = { module = "dev.chrisbanes.haze:haze-materials", version.ref = color_picker = "io.mhssn:colorpicker:1.0.0" # Analytics -posthog = "com.posthog:posthog-android:3.34.0" +posthog = "com.posthog:posthog-android:3.34.2" sentry = "io.sentry:sentry-android:8.33.0" # main branch can be tested replacing the version with main-SNAPSHOT matrix_analytics_events = "com.github.matrix-org:matrix-analytics-events:0.29.2" From 992a1133c96299e6f13e4c1f2495387d77c9d74b Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 26 Feb 2026 18:05:34 +0100 Subject: [PATCH 20/60] Update dependencyAnalysis to v3.6.0 (#6256) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index dc3b3fb4f1..8a3c055ad9 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -51,7 +51,7 @@ telephoto = "0.18.0" haze = "1.7.2" # Dependency analysis -dependencyAnalysis = "3.5.1" +dependencyAnalysis = "3.6.0" # DI metro = "0.11.1" From 7fe0cc4d450c753bc237eaf6a1ffccc978cf222e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jorge=20Mart=C3=ADn?= Date: Mon, 19 Jan 2026 09:55:45 +0100 Subject: [PATCH 21/60] Add `MediaSource.withCleanUrl` method that removes invalid fragment data from MXC urls We've seen some MXC urls in the wild having some `mxc://foo/bar#auto` fragment suffix, which is invalid, but the URL before that fragment part is valid and can be displayed --- .../libraries/matrix/api/media/MediaSource.kt | 23 +++++++++++++++++++ .../matrix/impl/media/RustMediaLoader.kt | 3 ++- .../matrix/ui/media/CoilMediaFetcher.kt | 17 +++++++++----- 3 files changed, 36 insertions(+), 7 deletions(-) diff --git a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/media/MediaSource.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/media/MediaSource.kt index 56e32ba2fc..9d0ea7fd13 100644 --- a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/media/MediaSource.kt +++ b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/media/MediaSource.kt @@ -9,6 +9,7 @@ package io.element.android.libraries.matrix.api.media import android.os.Parcelable +import androidx.core.net.toUri import kotlinx.parcelize.Parcelize @Parcelize @@ -22,3 +23,25 @@ data class MediaSource( */ val json: String? = null, ) : Parcelable + +/** + * Returns a new [MediaSource] with a valid URL. + */ +fun MediaSource.withCleanUrl(): MediaSource { + val uri = this.url.toUri() + if (uri.scheme != "mxc") return this + + // We've seen some MXC urls in the wild having some `mxc://foo/bar#auto` fragment suffix, which is invalid + val cleanedUrl = buildString { + append(uri.scheme) + if (!this.endsWith("://")) { + append("://") + } + append(uri.host) + if (uri.path != null) { + append(uri.path) + } + } + + return this.copy(url = cleanedUrl) +} diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/media/RustMediaLoader.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/media/RustMediaLoader.kt index 892c99f64a..653b4d055d 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/media/RustMediaLoader.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/media/RustMediaLoader.kt @@ -14,6 +14,7 @@ import io.element.android.libraries.core.mimetype.MimeTypes import io.element.android.libraries.matrix.api.media.MatrixMediaLoader import io.element.android.libraries.matrix.api.media.MediaFile import io.element.android.libraries.matrix.api.media.MediaSource +import io.element.android.libraries.matrix.api.media.withCleanUrl import kotlinx.coroutines.withContext import org.matrix.rustcomponents.sdk.Client import org.matrix.rustcomponents.sdk.use @@ -91,7 +92,7 @@ class RustMediaLoader( return if (json != null) { RustMediaSource.fromJson(json) } else { - RustMediaSource.fromUrl(url) + RustMediaSource.fromUrl(withCleanUrl().url) } } } diff --git a/libraries/matrixmedia/impl/src/main/kotlin/io/element/android/libraries/matrix/ui/media/CoilMediaFetcher.kt b/libraries/matrixmedia/impl/src/main/kotlin/io/element/android/libraries/matrix/ui/media/CoilMediaFetcher.kt index 06321f64a9..e08746f8df 100644 --- a/libraries/matrixmedia/impl/src/main/kotlin/io/element/android/libraries/matrix/ui/media/CoilMediaFetcher.kt +++ b/libraries/matrixmedia/impl/src/main/kotlin/io/element/android/libraries/matrix/ui/media/CoilMediaFetcher.kt @@ -16,6 +16,7 @@ import coil3.fetch.SourceFetchResult import io.element.android.libraries.matrix.api.media.MatrixMediaLoader import io.element.android.libraries.matrix.api.media.MediaSource import io.element.android.libraries.matrix.api.media.toFile +import io.element.android.libraries.matrix.api.media.withCleanUrl import okio.Buffer import okio.FileSystem import okio.Path.Companion.toOkioPath @@ -28,14 +29,18 @@ internal class CoilMediaFetcher( ) : Fetcher { override suspend fun fetch(): FetchResult? { val source = mediaData.source - if (source == null) { - Timber.e("MediaData source is null") - return null + val mediaSource = when { + source == null -> { + Timber.e("MediaData source is null") + return null + } + source.url.startsWith("mxc:") -> source.withCleanUrl() + else -> source } return when (val kind = mediaData.kind) { - is MediaRequestData.Kind.Content -> fetchContent(source) - is MediaRequestData.Kind.Thumbnail -> fetchThumbnail(source, kind) - is MediaRequestData.Kind.File -> fetchFile(source, kind) + is MediaRequestData.Kind.Content -> fetchContent(mediaSource) + is MediaRequestData.Kind.Thumbnail -> fetchThumbnail(mediaSource, kind) + is MediaRequestData.Kind.File -> fetchFile(mediaSource, kind) } } From cdd850d4dd5606587c948e76fa3c964993997b91 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jorge=20Mart=C3=ADn?= Date: Fri, 27 Feb 2026 09:33:03 +0100 Subject: [PATCH 22/60] Apply suggestion: - Added `MediaSource.safeUrl` property replacing `withCleanUrl` method. - Made `url` private so it can't be used externally. - Reverted code in `CoilMediaFetcher` - Also add tests --- .../model/event/TimelineItemStickerContent.kt | 2 +- .../libraries/matrix/api/media/MediaSource.kt | 35 +++++++------------ .../matrix/api/media/MediaSourceTest.kt | 26 ++++++++++++++ .../matrix/impl/media/RustMediaLoader.kt | 3 +- .../matrix/ui/media/CoilMediaFetcher.kt | 13 +++---- .../matrix/ui/media/MediaRequestDataKeyer.kt | 2 +- .../impl/viewer/MediaViewerDataSource.kt | 6 ++-- .../notifications/NotificationMediaRepo.kt | 2 +- .../voiceplayer/impl/VoiceMessageMediaRepo.kt | 2 +- 9 files changed, 50 insertions(+), 41 deletions(-) create mode 100644 libraries/matrix/api/src/test/kotlin/io/element/android/libraries/matrix/api/media/MediaSourceTest.kt diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/model/event/TimelineItemStickerContent.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/model/event/TimelineItemStickerContent.kt index d333c0b6e7..9e2f08d5c7 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/model/event/TimelineItemStickerContent.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/model/event/TimelineItemStickerContent.kt @@ -30,5 +30,5 @@ data class TimelineItemStickerContent( /* Stickers are supposed to be small images so we allow using the mediaSource (unless the url is empty) */ - val preferredMediaSource = if (mediaSource.url.isEmpty()) thumbnailSource else mediaSource + val preferredMediaSource = if (mediaSource.safeUrl.isEmpty()) thumbnailSource else mediaSource } diff --git a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/media/MediaSource.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/media/MediaSource.kt index 9d0ea7fd13..2f7fff84ef 100644 --- a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/media/MediaSource.kt +++ b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/media/MediaSource.kt @@ -9,7 +9,7 @@ package io.element.android.libraries.matrix.api.media import android.os.Parcelable -import androidx.core.net.toUri +import kotlinx.parcelize.IgnoredOnParcel import kotlinx.parcelize.Parcelize @Parcelize @@ -17,31 +17,20 @@ data class MediaSource( /** * Url of the media. */ - val url: String, + private val url: String, /** * This is used to hold data for encrypted media. */ val json: String? = null, -) : Parcelable - -/** - * Returns a new [MediaSource] with a valid URL. - */ -fun MediaSource.withCleanUrl(): MediaSource { - val uri = this.url.toUri() - if (uri.scheme != "mxc") return this - - // We've seen some MXC urls in the wild having some `mxc://foo/bar#auto` fragment suffix, which is invalid - val cleanedUrl = buildString { - append(uri.scheme) - if (!this.endsWith("://")) { - append("://") - } - append(uri.host) - if (uri.path != null) { - append(uri.path) - } +) : Parcelable { + /** + * A URL with invalid parts (like `#fragment`, if it's an MXC url) removed. + */ + @IgnoredOnParcel + val safeUrl = if (url.startsWith("mxc")) { + // We've seen some MXC urls in the wild having some `mxc://foo/bar#auto` fragment suffix, which is invalid + url.substringBefore("#") + } else { + url } - - return this.copy(url = cleanedUrl) } diff --git a/libraries/matrix/api/src/test/kotlin/io/element/android/libraries/matrix/api/media/MediaSourceTest.kt b/libraries/matrix/api/src/test/kotlin/io/element/android/libraries/matrix/api/media/MediaSourceTest.kt new file mode 100644 index 0000000000..55c1381a4d --- /dev/null +++ b/libraries/matrix/api/src/test/kotlin/io/element/android/libraries/matrix/api/media/MediaSourceTest.kt @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2026 Element Creations Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial. + * Please see LICENSE files in the repository root for full details. + */ + +package io.element.android.libraries.matrix.api.media + +import com.google.common.truth.Truth.assertThat +import io.element.android.libraries.matrix.test.media.aMediaSource +import org.junit.Test + +class MediaSourceTest { + @Test + fun `safeUrl removes the fragment part in MXC urls`() { + val mediaSource = aMediaSource(url = "mxc://matrix.org/url#fragment") + assertThat(mediaSource.safeUrl).isEqualTo("mxc://matrix.org/url") + } + + @Test + fun `safeUrl keeps the fragment part in a non-MXC url`() { + val mediaSource = aMediaSource(url = "https://matrix.org/url#fragment") + assertThat(mediaSource.safeUrl).isEqualTo("https://matrix.org/url#fragment") + } +} diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/media/RustMediaLoader.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/media/RustMediaLoader.kt index 653b4d055d..81946980e3 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/media/RustMediaLoader.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/media/RustMediaLoader.kt @@ -14,7 +14,6 @@ import io.element.android.libraries.core.mimetype.MimeTypes import io.element.android.libraries.matrix.api.media.MatrixMediaLoader import io.element.android.libraries.matrix.api.media.MediaFile import io.element.android.libraries.matrix.api.media.MediaSource -import io.element.android.libraries.matrix.api.media.withCleanUrl import kotlinx.coroutines.withContext import org.matrix.rustcomponents.sdk.Client import org.matrix.rustcomponents.sdk.use @@ -92,7 +91,7 @@ class RustMediaLoader( return if (json != null) { RustMediaSource.fromJson(json) } else { - RustMediaSource.fromUrl(withCleanUrl().url) + RustMediaSource.fromUrl(safeUrl) } } } diff --git a/libraries/matrixmedia/impl/src/main/kotlin/io/element/android/libraries/matrix/ui/media/CoilMediaFetcher.kt b/libraries/matrixmedia/impl/src/main/kotlin/io/element/android/libraries/matrix/ui/media/CoilMediaFetcher.kt index e08746f8df..39f67b41d7 100644 --- a/libraries/matrixmedia/impl/src/main/kotlin/io/element/android/libraries/matrix/ui/media/CoilMediaFetcher.kt +++ b/libraries/matrixmedia/impl/src/main/kotlin/io/element/android/libraries/matrix/ui/media/CoilMediaFetcher.kt @@ -16,7 +16,6 @@ import coil3.fetch.SourceFetchResult import io.element.android.libraries.matrix.api.media.MatrixMediaLoader import io.element.android.libraries.matrix.api.media.MediaSource import io.element.android.libraries.matrix.api.media.toFile -import io.element.android.libraries.matrix.api.media.withCleanUrl import okio.Buffer import okio.FileSystem import okio.Path.Companion.toOkioPath @@ -28,14 +27,10 @@ internal class CoilMediaFetcher( private val mediaData: MediaRequestData, ) : Fetcher { override suspend fun fetch(): FetchResult? { - val source = mediaData.source - val mediaSource = when { - source == null -> { - Timber.e("MediaData source is null") - return null - } - source.url.startsWith("mxc:") -> source.withCleanUrl() - else -> source + val mediaSource = mediaData.source + if (mediaSource == null) { + Timber.e("MediaData source is null") + return null } return when (val kind = mediaData.kind) { is MediaRequestData.Kind.Content -> fetchContent(mediaSource) diff --git a/libraries/matrixmedia/impl/src/main/kotlin/io/element/android/libraries/matrix/ui/media/MediaRequestDataKeyer.kt b/libraries/matrixmedia/impl/src/main/kotlin/io/element/android/libraries/matrix/ui/media/MediaRequestDataKeyer.kt index 488803e933..660b80500a 100644 --- a/libraries/matrixmedia/impl/src/main/kotlin/io/element/android/libraries/matrix/ui/media/MediaRequestDataKeyer.kt +++ b/libraries/matrixmedia/impl/src/main/kotlin/io/element/android/libraries/matrix/ui/media/MediaRequestDataKeyer.kt @@ -25,5 +25,5 @@ internal class MediaRequestDataKeyer : Keyer { } private fun MediaRequestData.toKey(): String? { - return source?.let { "${it.url}_$kind" } + return source?.let { "${it.safeUrl}_$kind" } } diff --git a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerDataSource.kt b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerDataSource.kt index ae7b54ccdd..928e5d9ca8 100644 --- a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerDataSource.kt +++ b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerDataSource.kt @@ -126,7 +126,7 @@ class MediaViewerDataSource( when (mediaItem) { is MediaItem.DateSeparator -> Unit is MediaItem.Event -> { - val sourceUrl = mediaItem.mediaSource().url + val sourceUrl = mediaItem.mediaSource().safeUrl val localMedia = localMediaStates.getOrPut(sourceUrl) { mutableStateOf(AsyncData.Uninitialized) } @@ -153,7 +153,7 @@ class MediaViewerDataSource( }.toImmutableList() fun clearLoadingError(data: MediaViewerPageData.MediaViewerData) { - localMediaStates[data.mediaSource.url]?.value = AsyncData.Uninitialized + localMediaStates[data.mediaSource.safeUrl]?.value = AsyncData.Uninitialized } suspend fun loadMore(direction: Timeline.PaginationDirection) { @@ -162,7 +162,7 @@ class MediaViewerDataSource( suspend fun loadMedia(data: MediaViewerPageData.MediaViewerData) { Timber.d("loadMedia for ${data.eventId}") - val localMediaState = localMediaStates.getOrPut(data.mediaSource.url) { + val localMediaState = localMediaStates.getOrPut(data.mediaSource.safeUrl) { mutableStateOf(AsyncData.Uninitialized) } localMediaState.value = AsyncData.Loading() diff --git a/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/notifications/NotificationMediaRepo.kt b/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/notifications/NotificationMediaRepo.kt index f309f754c3..39b3f3fda2 100644 --- a/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/notifications/NotificationMediaRepo.kt +++ b/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/notifications/NotificationMediaRepo.kt @@ -101,7 +101,7 @@ class DefaultNotificationMediaRepo( } } - private fun MediaSource.cachedFile(): File? = mxcTools.mxcUri2FilePath(url)?.let { + private fun MediaSource.cachedFile(): File? = mxcTools.mxcUri2FilePath(safeUrl)?.let { File("${cacheDir.path}/$CACHE_NOTIFICATION_SUBDIR/$it") } } diff --git a/libraries/voiceplayer/impl/src/main/kotlin/io/element/android/libraries/voiceplayer/impl/VoiceMessageMediaRepo.kt b/libraries/voiceplayer/impl/src/main/kotlin/io/element/android/libraries/voiceplayer/impl/VoiceMessageMediaRepo.kt index 7cc09c4009..2d1c9f7277 100644 --- a/libraries/voiceplayer/impl/src/main/kotlin/io/element/android/libraries/voiceplayer/impl/VoiceMessageMediaRepo.kt +++ b/libraries/voiceplayer/impl/src/main/kotlin/io/element/android/libraries/voiceplayer/impl/VoiceMessageMediaRepo.kt @@ -95,7 +95,7 @@ class DefaultVoiceMessageMediaRepo( } } - private val cachedFile: File? = mxcTools.mxcUri2FilePath(mediaSource.url)?.let { + private val cachedFile: File? = mxcTools.mxcUri2FilePath(mediaSource.safeUrl)?.let { File("${cacheDir.path}/$CACHE_VOICE_SUBDIR/$it") } } From 5547b532b16e6438a1b5d6eb1adaee45bac986f3 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 27 Feb 2026 09:55:47 +0100 Subject: [PATCH 23/60] Update GitHub Artifact Actions (#6260) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .github/workflows/build.yml | 2 +- .github/workflows/build_enterprise.yml | 2 +- .github/workflows/maestro-local.yml | 6 +++--- .github/workflows/nightlyReports.yml | 4 ++-- .github/workflows/quality.yml | 10 +++++----- .github/workflows/release.yml | 6 +++--- .github/workflows/tests.yml | 4 ++-- 7 files changed, 17 insertions(+), 17 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index eb9ee609cb..300a8ceb8d 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -68,7 +68,7 @@ jobs: run: ./gradlew :app:assembleGplayDebug app:assembleFDroidDebug -PallWarningsAsErrors=true $CI_GRADLE_ARG_PROPERTIES - name: Upload debug APKs if: ${{ matrix.variant == 'debug' }} - uses: actions/upload-artifact@v6 + uses: actions/upload-artifact@v7 with: name: elementx-debug path: | diff --git a/.github/workflows/build_enterprise.yml b/.github/workflows/build_enterprise.yml index 9968a54592..dd945d46cb 100644 --- a/.github/workflows/build_enterprise.yml +++ b/.github/workflows/build_enterprise.yml @@ -76,7 +76,7 @@ jobs: run: ./gradlew :app:assembleGplayDebug -PallWarningsAsErrors=true $CI_GRADLE_ARG_PROPERTIES - name: Upload debug Enterprise APKs if: ${{ matrix.variant == 'debug' }} - uses: actions/upload-artifact@v6 + uses: actions/upload-artifact@v7 with: name: elementx-enterprise-debug path: | diff --git a/.github/workflows/maestro-local.yml b/.github/workflows/maestro-local.yml index ac85c66ed1..aca0edd7c8 100644 --- a/.github/workflows/maestro-local.yml +++ b/.github/workflows/maestro-local.yml @@ -57,7 +57,7 @@ jobs: ELEMENT_ANDROID_MAPTILER_LIGHT_MAP_ID: ${{ secrets.MAPTILER_LIGHT_MAP_ID }} ELEMENT_ANDROID_MAPTILER_DARK_MAP_ID: ${{ secrets.MAPTILER_DARK_MAP_ID }} - name: Upload APK as artifact - uses: actions/upload-artifact@v6 + uses: actions/upload-artifact@v7 with: name: elementx-apk-maestro path: | @@ -82,7 +82,7 @@ jobs: # https://github.com/actions/checkout/issues/881 ref: ${{ github.ref }} - name: Download APK artifact from previous job - uses: actions/download-artifact@v7 + uses: actions/download-artifact@v8 with: name: elementx-apk-maestro - name: Enable KVM group perms @@ -115,7 +115,7 @@ jobs: script: | .github/workflows/scripts/maestro/maestro-local-with-screen-recording.sh app-gplay-x86_64-debug.apk - name: Upload test results - uses: actions/upload-artifact@v6 + uses: actions/upload-artifact@v7 with: name: test-results path: | diff --git a/.github/workflows/nightlyReports.yml b/.github/workflows/nightlyReports.yml index bf6322ff2b..77646aa972 100644 --- a/.github/workflows/nightlyReports.yml +++ b/.github/workflows/nightlyReports.yml @@ -56,7 +56,7 @@ jobs: - name: ✅ Upload kover report if: always() - uses: actions/upload-artifact@v6 + uses: actions/upload-artifact@v7 with: name: kover-results path: | @@ -88,7 +88,7 @@ jobs: run: ./gradlew dependencyCheckAnalyze $CI_GRADLE_ARG_PROPERTIES - name: Upload dependency analysis if: always() - uses: actions/upload-artifact@v6 + uses: actions/upload-artifact@v7 with: name: dependency-analysis path: build/reports/dependency-check-report.html diff --git a/.github/workflows/quality.yml b/.github/workflows/quality.yml index 33d2eac94b..c7ce19f5d7 100644 --- a/.github/workflows/quality.yml +++ b/.github/workflows/quality.yml @@ -111,7 +111,7 @@ jobs: run: ./gradlew :tests:konsist:testDebugUnitTest $CI_GRADLE_ARG_PROPERTIES --no-daemon - name: Upload reports if: always() - uses: actions/upload-artifact@v6 + uses: actions/upload-artifact@v7 with: name: konsist-report path: | @@ -188,7 +188,7 @@ jobs: run: ./gradlew :app:lintGplayDebug :app:lintFdroidDebug lintDebug $CI_GRADLE_ARG_PROPERTIES --continue - name: Upload reports if: always() - uses: actions/upload-artifact@v6 + uses: actions/upload-artifact@v7 with: name: linting-report path: | @@ -228,7 +228,7 @@ jobs: run: ./gradlew detekt $CI_GRADLE_ARG_PROPERTIES --no-daemon - name: Upload reports if: always() - uses: actions/upload-artifact@v6 + uses: actions/upload-artifact@v7 with: name: detekt-report path: | @@ -268,7 +268,7 @@ jobs: run: ./gradlew ktlintCheck $CI_GRADLE_ARG_PROPERTIES - name: Upload reports if: always() - uses: actions/upload-artifact@v6 + uses: actions/upload-artifact@v7 with: name: ktlint-report path: | @@ -331,7 +331,7 @@ jobs: # https://github.com/actions/checkout/issues/881 ref: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.sha || github.ref }} - name: Download reports from previous jobs - uses: actions/download-artifact@v7 + uses: actions/download-artifact@v8 - name: Prepare Danger if: always() run: | diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index fac72d4f7c..b089226f9f 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -53,7 +53,7 @@ jobs: ELEMENT_CALL_RAGESHAKE_URL: ${{ secrets.ELEMENT_CALL_RAGESHAKE_URL }} run: ./gradlew bundleGplayRelease $CI_GRADLE_ARG_PROPERTIES - name: Upload bundle as artifact - uses: actions/upload-artifact@v6 + uses: actions/upload-artifact@v7 with: name: elementx-app-gplay-bundle-unsigned path: | @@ -89,7 +89,7 @@ jobs: ELEMENT_ANDROID_MAPTILER_DARK_MAP_ID: ${{ secrets.MAPTILER_DARK_MAP_ID }} run: ./gradlew bundleGplayRelease $CI_GRADLE_ARG_PROPERTIES - name: Upload bundle as artifact - uses: actions/upload-artifact@v6 + uses: actions/upload-artifact@v7 with: name: elementx-enterprise-app-gplay-bundle-unsigned path: | @@ -131,7 +131,7 @@ jobs: ELEMENT_ANDROID_MAPTILER_DARK_MAP_ID: ${{ secrets.MAPTILER_DARK_MAP_ID }} run: ./gradlew assembleFdroidRelease $CI_GRADLE_ARG_PROPERTIES - name: Upload apks as artifact - uses: actions/upload-artifact@v6 + uses: actions/upload-artifact@v7 with: name: elementx-app-fdroid-apks-unsigned path: | diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 12b2fa17f2..68339e8443 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -75,7 +75,7 @@ jobs: - name: 🚫 Upload kover failed coverage reports if: failure() - uses: actions/upload-artifact@v6 + uses: actions/upload-artifact@v7 with: name: kover-error-report path: | @@ -87,7 +87,7 @@ jobs: - name: 🚫 Upload test results on error if: failure() - uses: actions/upload-artifact@v6 + uses: actions/upload-artifact@v7 with: name: tests-and-screenshot-tests-results path: | From 99ddadd0fa8e82e5886e22cd58ecb119b0189149 Mon Sep 17 00:00:00 2001 From: Jorge Martin Espinosa Date: Fri, 27 Feb 2026 10:31:50 +0100 Subject: [PATCH 24/60] Fix nightly CI issues (#6263) * Reduce max heap size from 9GB to 8GB for all CI jobs using gradle --- .github/workflows/build.yml | 2 +- .github/workflows/build_enterprise.yml | 2 +- .github/workflows/maestro-local.yml | 2 +- .github/workflows/nightly.yml | 2 +- .github/workflows/nightlyReports.yml | 2 +- .github/workflows/quality.yml | 2 +- .github/workflows/recordScreenshots.yml | 2 +- .github/workflows/release.yml | 2 +- .github/workflows/sonar.yml | 2 +- 9 files changed, 9 insertions(+), 9 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 300a8ceb8d..f607e06765 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -9,7 +9,7 @@ on: # Enrich gradle.properties for CI/CD env: - GRADLE_OPTS: -Dorg.gradle.jvmargs=-Xmx9g -XX:MaxMetaspaceSize=512m -Dfile.encoding=UTF-8 -XX:+HeapDumpOnOutOfMemoryError -XX:+UseG1GC -Dkotlin.daemon.jvm.options=-Xmx4g + GRADLE_OPTS: -Dorg.gradle.jvmargs=-Xmx8g -XX:MaxMetaspaceSize=512m -Dfile.encoding=UTF-8 -XX:+HeapDumpOnOutOfMemoryError -XX:+UseG1GC -Dkotlin.daemon.jvm.options=-Xmx4g CI_GRADLE_ARG_PROPERTIES: --stacktrace -Dsonar.gradle.skipCompile=true --no-configuration-cache jobs: diff --git a/.github/workflows/build_enterprise.yml b/.github/workflows/build_enterprise.yml index dd945d46cb..a6eb60d958 100644 --- a/.github/workflows/build_enterprise.yml +++ b/.github/workflows/build_enterprise.yml @@ -9,7 +9,7 @@ on: # Enrich gradle.properties for CI/CD env: - GRADLE_OPTS: -Dorg.gradle.jvmargs=-Xmx9g -XX:MaxMetaspaceSize=512m -Dfile.encoding=UTF-8 -XX:+HeapDumpOnOutOfMemoryError -XX:+UseG1GC -Dkotlin.daemon.jvm.options=-Xmx4g + GRADLE_OPTS: -Dorg.gradle.jvmargs=-Xmx8g -XX:MaxMetaspaceSize=512m -Dfile.encoding=UTF-8 -XX:+HeapDumpOnOutOfMemoryError -XX:+UseG1GC -Dkotlin.daemon.jvm.options=-Xmx4g CI_GRADLE_ARG_PROPERTIES: --stacktrace -Dsonar.gradle.skipCompile=true --no-configuration-cache jobs: diff --git a/.github/workflows/maestro-local.yml b/.github/workflows/maestro-local.yml index aca0edd7c8..9ff6f578c9 100644 --- a/.github/workflows/maestro-local.yml +++ b/.github/workflows/maestro-local.yml @@ -7,7 +7,7 @@ on: # Enrich gradle.properties for CI/CD env: - GRADLE_OPTS: -Dorg.gradle.jvmargs=-Xmx9g -XX:MaxMetaspaceSize=512m -Dfile.encoding=UTF-8 -XX:+HeapDumpOnOutOfMemoryError -XX:+UseG1GC -Dkotlin.daemon.jvm.options=-Xmx4g + GRADLE_OPTS: -Dorg.gradle.jvmargs=-Xmx8g -XX:MaxMetaspaceSize=512m -Dfile.encoding=UTF-8 -XX:+HeapDumpOnOutOfMemoryError -XX:+UseG1GC -Dkotlin.daemon.jvm.options=-Xmx4g CI_GRADLE_ARG_PROPERTIES: --stacktrace --no-daemon -Dsonar.gradle.skipCompile=true --no-configuration-cache ARCH: x86_64 DEVICE: pixel_7_pro diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index 933301cc49..fa3a7c52a2 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -7,7 +7,7 @@ on: - cron: "0 4 * * *" env: - GRADLE_OPTS: -Dorg.gradle.jvmargs=-Xmx9g -XX:MaxMetaspaceSize=512m -Dfile.encoding=UTF-8 -XX:+HeapDumpOnOutOfMemoryError -XX:+UseG1GC -Dkotlin.daemon.jvm.options=-Xmx4g + GRADLE_OPTS: -Dorg.gradle.jvmargs=-Xmx8g -XX:MaxMetaspaceSize=512m -Dfile.encoding=UTF-8 -XX:+HeapDumpOnOutOfMemoryError -XX:+UseG1GC -Dkotlin.daemon.jvm.options=-Xmx4g CI_GRADLE_ARG_PROPERTIES: --stacktrace --no-daemon -Dsonar.gradle.skipCompile=true --no-configuration-cache jobs: diff --git a/.github/workflows/nightlyReports.yml b/.github/workflows/nightlyReports.yml index 77646aa972..5c704abd7e 100644 --- a/.github/workflows/nightlyReports.yml +++ b/.github/workflows/nightlyReports.yml @@ -8,7 +8,7 @@ on: # Enrich gradle.properties for CI/CD env: - GRADLE_OPTS: -Dorg.gradle.jvmargs=-Xmx9g -XX:MaxMetaspaceSize=512m -Dfile.encoding=UTF-8 -XX:+HeapDumpOnOutOfMemoryError -XX:+UseG1GC -Dkotlin.daemon.jvm.options=-Xmx4g + GRADLE_OPTS: -Dorg.gradle.jvmargs=-Xmx8g -XX:MaxMetaspaceSize=512m -Dfile.encoding=UTF-8 -XX:+HeapDumpOnOutOfMemoryError -XX:+UseG1GC -Dkotlin.daemon.jvm.options=-Xmx4g CI_GRADLE_ARG_PROPERTIES: --stacktrace -Dsonar.gradle.skipCompile=true --no-configuration-cache jobs: diff --git a/.github/workflows/quality.yml b/.github/workflows/quality.yml index c7ce19f5d7..c3274261d3 100644 --- a/.github/workflows/quality.yml +++ b/.github/workflows/quality.yml @@ -9,7 +9,7 @@ on: # Enrich gradle.properties for CI/CD env: - GRADLE_OPTS: -Dorg.gradle.jvmargs=-Xmx9g -XX:MaxMetaspaceSize=512m -Dfile.encoding=UTF-8 -XX:+HeapDumpOnOutOfMemoryError -XX:+UseG1GC -Dkotlin.daemon.jvm.options=-Xmx4g + GRADLE_OPTS: -Dorg.gradle.jvmargs=-Xmx8g -XX:MaxMetaspaceSize=512m -Dfile.encoding=UTF-8 -XX:+HeapDumpOnOutOfMemoryError -XX:+UseG1GC -Dkotlin.daemon.jvm.options=-Xmx4g CI_GRADLE_ARG_PROPERTIES: --stacktrace --no-daemon -Dsonar.gradle.skipCompile=true --no-configuration-cache jobs: diff --git a/.github/workflows/recordScreenshots.yml b/.github/workflows/recordScreenshots.yml index 5ac4a2f350..4bd203ccd2 100644 --- a/.github/workflows/recordScreenshots.yml +++ b/.github/workflows/recordScreenshots.yml @@ -7,7 +7,7 @@ on: # Enrich gradle.properties for CI/CD env: - GRADLE_OPTS: -Dorg.gradle.jvmargs=-Xmx9g -XX:MaxMetaspaceSize=512m -Dfile.encoding=UTF-8 -XX:+HeapDumpOnOutOfMemoryError -XX:+UseG1GC -Dkotlin.daemon.jvm.options=-Xmx4g -Dsonar.gradle.skipCompile=true + GRADLE_OPTS: -Dorg.gradle.jvmargs=-Xmx8g -XX:MaxMetaspaceSize=512m -Dfile.encoding=UTF-8 -XX:+HeapDumpOnOutOfMemoryError -XX:+UseG1GC -Dkotlin.daemon.jvm.options=-Xmx4g -Dsonar.gradle.skipCompile=true CI_GRADLE_ARG_PROPERTIES: --no-configuration-cache jobs: diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index b089226f9f..acb6a62ec4 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -7,7 +7,7 @@ on: # Enrich gradle.properties for CI/CD env: - GRADLE_OPTS: -Dorg.gradle.jvmargs=-Xmx9g -XX:MaxMetaspaceSize=512m -Dfile.encoding=UTF-8 -XX:+HeapDumpOnOutOfMemoryError -XX:+UseG1GC -Dkotlin.daemon.jvm.options=-Xmx4g + GRADLE_OPTS: -Dorg.gradle.jvmargs=-Xmx8g -XX:MaxMetaspaceSize=512m -Dfile.encoding=UTF-8 -XX:+HeapDumpOnOutOfMemoryError -XX:+UseG1GC -Dkotlin.daemon.jvm.options=-Xmx4g CI_GRADLE_ARG_PROPERTIES: --stacktrace --no-daemon -Dsonar.gradle.skipCompile=true --no-configuration-cache jobs: diff --git a/.github/workflows/sonar.yml b/.github/workflows/sonar.yml index 1b8b6b61a5..715033a1dd 100644 --- a/.github/workflows/sonar.yml +++ b/.github/workflows/sonar.yml @@ -9,7 +9,7 @@ on: # Enrich gradle.properties for CI/CD env: - GRADLE_OPTS: -Dorg.gradle.jvmargs=-Xmx9g -XX:MaxMetaspaceSize=512m -Dfile.encoding=UTF-8 -XX:+HeapDumpOnOutOfMemoryError -XX:+UseG1GC -Dkotlin.daemon.jvm.options=-Xmx4g + GRADLE_OPTS: -Dorg.gradle.jvmargs=-Xmx8g -XX:MaxMetaspaceSize=512m -Dfile.encoding=UTF-8 -XX:+HeapDumpOnOutOfMemoryError -XX:+UseG1GC -Dkotlin.daemon.jvm.options=-Xmx4g CI_GRADLE_ARG_PROPERTIES: --stacktrace --warn -Dsonar.gradle.skipCompile=true --no-configuration-cache GROUP: ${{ format('sonar-{0}', github.ref) }} From b84970edc55b463530271b35d3eafbb70b871a99 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Fri, 27 Feb 2026 12:02:20 +0100 Subject: [PATCH 25/60] Ensure FAB is displayed when navigation bar is not --- .../kotlin/io/element/android/features/home/impl/HomeView.kt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/HomeView.kt b/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/HomeView.kt index ca5740e646..ae2d7fb6a5 100644 --- a/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/HomeView.kt +++ b/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/HomeView.kt @@ -239,9 +239,11 @@ private fun HomeScaffold( } }, ) + } else { + HomeFloatingActionButton(onStartChatClick, CommonStrings.action_create_room) } }, - floatingActionButtonPosition = FabPosition.Center, + floatingActionButtonPosition = if (state.showNavigationBar) FabPosition.Center else FabPosition.End, content = { padding -> val contentPadding = PaddingValues( bottom = 112.dp, From c7ba6ce4ed96ed33abc258af6ba2cc8496ad5a00 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Fri, 27 Feb 2026 12:04:13 +0100 Subject: [PATCH 26/60] Navigation bar: reduce bottom padding. --- .../kotlin/io/element/android/features/home/impl/HomeView.kt | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/HomeView.kt b/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/HomeView.kt index ae2d7fb6a5..ddf8b1c499 100644 --- a/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/HomeView.kt +++ b/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/HomeView.kt @@ -23,7 +23,6 @@ import androidx.compose.foundation.lazy.rememberLazyListState import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi import androidx.compose.material3.FabPosition -import androidx.compose.material3.FloatingToolbarDefaults.ScreenOffset import androidx.compose.material3.TopAppBarDefaults import androidx.compose.material3.rememberTopAppBarState import androidx.compose.runtime.Composable @@ -246,7 +245,7 @@ private fun HomeScaffold( floatingActionButtonPosition = if (state.showNavigationBar) FabPosition.Center else FabPosition.End, content = { padding -> val contentPadding = PaddingValues( - bottom = 112.dp, + bottom = 96.dp, ) when (state.currentHomeNavigationBarItem) { HomeNavigationBarItem.Chats -> { @@ -326,7 +325,6 @@ private fun HomeBottomBar( HorizontalFloatingToolbar( floatingActionButton = floatingActionButton, modifier = modifier - .padding(bottom = ScreenOffset) .zIndex(1f), ) { HomeNavigationBarItem.entries.forEachIndexed { index, item -> From ae42df9507bd6cb49bbecd3ce55825dbbf1d652b Mon Sep 17 00:00:00 2001 From: ElementBot Date: Fri, 27 Feb 2026 12:08:24 +0000 Subject: [PATCH 27/60] Update screenshots --- .../snapshots/images/features.home.impl_HomeViewA11y_en.png | 4 ++-- .../snapshots/images/features.home.impl_HomeView_Day_0_en.png | 4 ++-- .../images/features.home.impl_HomeView_Day_10_en.png | 4 ++-- .../images/features.home.impl_HomeView_Day_11_en.png | 4 ++-- .../images/features.home.impl_HomeView_Day_13_en.png | 4 ++-- .../images/features.home.impl_HomeView_Day_14_en.png | 4 ++-- .../images/features.home.impl_HomeView_Day_15_en.png | 4 ++-- .../images/features.home.impl_HomeView_Day_16_en.png | 4 ++-- .../snapshots/images/features.home.impl_HomeView_Day_1_en.png | 4 ++-- .../snapshots/images/features.home.impl_HomeView_Day_2_en.png | 4 ++-- .../snapshots/images/features.home.impl_HomeView_Day_3_en.png | 4 ++-- .../snapshots/images/features.home.impl_HomeView_Day_4_en.png | 4 ++-- .../snapshots/images/features.home.impl_HomeView_Day_5_en.png | 4 ++-- .../snapshots/images/features.home.impl_HomeView_Day_9_en.png | 4 ++-- .../images/features.home.impl_HomeView_Night_0_en.png | 4 ++-- .../images/features.home.impl_HomeView_Night_10_en.png | 4 ++-- .../images/features.home.impl_HomeView_Night_11_en.png | 4 ++-- .../images/features.home.impl_HomeView_Night_13_en.png | 4 ++-- .../images/features.home.impl_HomeView_Night_14_en.png | 4 ++-- .../images/features.home.impl_HomeView_Night_15_en.png | 4 ++-- .../images/features.home.impl_HomeView_Night_16_en.png | 4 ++-- .../images/features.home.impl_HomeView_Night_1_en.png | 4 ++-- .../images/features.home.impl_HomeView_Night_2_en.png | 4 ++-- .../images/features.home.impl_HomeView_Night_3_en.png | 4 ++-- .../images/features.home.impl_HomeView_Night_4_en.png | 4 ++-- .../images/features.home.impl_HomeView_Night_5_en.png | 4 ++-- .../images/features.home.impl_HomeView_Night_9_en.png | 4 ++-- 27 files changed, 54 insertions(+), 54 deletions(-) diff --git a/tests/uitests/src/test/snapshots/images/features.home.impl_HomeViewA11y_en.png b/tests/uitests/src/test/snapshots/images/features.home.impl_HomeViewA11y_en.png index 8fdb3bb4e4..1bec9cf123 100644 --- a/tests/uitests/src/test/snapshots/images/features.home.impl_HomeViewA11y_en.png +++ b/tests/uitests/src/test/snapshots/images/features.home.impl_HomeViewA11y_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c4bd92f12e7926f39cf7bb74fedd85b8295bff34da08e45229e2e1a8f83956c3 -size 144306 +oid sha256:2f2357a181fcea22deb153e4d4c570421354cbc74f3e272a6e94c7795cf29c4c +size 144183 diff --git a/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Day_0_en.png b/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Day_0_en.png index e1a5813252..3a262e8d47 100644 --- a/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Day_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Day_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:5f106b4672b1d96665fe731de28b7ccbb98f986580fd95cc6609a7b64348c60e -size 67665 +oid sha256:96ce82255e49c97179a216124ccfcbc6726a8053acef767041ba44304e7f4735 +size 67756 diff --git a/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Day_10_en.png b/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Day_10_en.png index c52665e0ba..f106244405 100644 --- a/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Day_10_en.png +++ b/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Day_10_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:763715d657faecd68e201b7a110d022c04e27592bff499355662848455e2adc3 -size 36373 +oid sha256:c393b13532fba4d4ef25dda45b6ca3e1f6da6d49c5b2de412beded261a4f9311 +size 36164 diff --git a/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Day_11_en.png b/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Day_11_en.png index 03ef9f63a7..6eed7b2e94 100644 --- a/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Day_11_en.png +++ b/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Day_11_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:b0ecffc6b05c1bc3d0c6ba578d7ca7d50ac9c7a4948c53fe96d427c3ad6b4e4e -size 32289 +oid sha256:2339985aba8128dd562491d6575b92338be2338c090d978f553a1e50b44b24f6 +size 32073 diff --git a/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Day_13_en.png b/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Day_13_en.png index 5e008d0c1a..c9096ac918 100644 --- a/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Day_13_en.png +++ b/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Day_13_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:b659de7521274ae555f962639d7e1652a22958c4b066dae3f2dd1aa70d93b78e -size 89194 +oid sha256:37c34086d1939b266d9f0825da480c8de53c18c68c4eb420829111759b1d995a +size 89216 diff --git a/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Day_14_en.png b/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Day_14_en.png index 7da3602182..da72b71928 100644 --- a/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Day_14_en.png +++ b/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Day_14_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:bd11e404d07f8d790b1554c760f24e4e82614a331e16219c67c326b0375313f9 -size 84336 +oid sha256:5b54ba16e7e2413dd994bedcc31e5ffdf6c291487ccc5ae17178d2572a4fb0ea +size 87282 diff --git a/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Day_15_en.png b/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Day_15_en.png index 95177de294..edf07a66f3 100644 --- a/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Day_15_en.png +++ b/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Day_15_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:5406580880491251a8d61fc2fe26dab90153e6337f95dae3d6e4b1c5df7ac8f4 -size 53764 +oid sha256:af36d0e3383935d256b3730e6f955e858ae42a82f54485b879e7a6a71fc25f6c +size 55237 diff --git a/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Day_16_en.png b/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Day_16_en.png index ce51cc83f5..aa313049f5 100644 --- a/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Day_16_en.png +++ b/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Day_16_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:750a7b57fd2fd99f3cd0ad6e970692cdd8a7ad191dfb8fff0b5d0935461789db -size 42594 +oid sha256:e55407ac7116b3127a979f630777d0d528a349c38d37829d8bc0c37a316c7c5b +size 42526 diff --git a/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Day_1_en.png b/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Day_1_en.png index e1a5813252..3a262e8d47 100644 --- a/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Day_1_en.png +++ b/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Day_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:5f106b4672b1d96665fe731de28b7ccbb98f986580fd95cc6609a7b64348c60e -size 67665 +oid sha256:96ce82255e49c97179a216124ccfcbc6726a8053acef767041ba44304e7f4735 +size 67756 diff --git a/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Day_2_en.png b/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Day_2_en.png index e1a5813252..3a262e8d47 100644 --- a/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Day_2_en.png +++ b/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Day_2_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:5f106b4672b1d96665fe731de28b7ccbb98f986580fd95cc6609a7b64348c60e -size 67665 +oid sha256:96ce82255e49c97179a216124ccfcbc6726a8053acef767041ba44304e7f4735 +size 67756 diff --git a/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Day_3_en.png b/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Day_3_en.png index 757e4d9506..5c05d6e633 100644 --- a/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Day_3_en.png +++ b/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Day_3_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f8bdb8d3e2dbb468115c4077f5bce6415a7708cbd04f825225139c1a2cbf788d -size 64647 +oid sha256:69fd2195c4d0203b602ba91b822c5e9dc0e902b77dcf1352daabaf91aaea1768 +size 65301 diff --git a/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Day_4_en.png b/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Day_4_en.png index be286098b3..beb2054ef2 100644 --- a/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Day_4_en.png +++ b/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Day_4_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:1ed6905e2833c7e927c84f0407a6218a4859a28f5a36a34c3a9b92f66347308a -size 56117 +oid sha256:303d13645d55db4f9dcb31d68e49d21254778c500daa887694a6d402735ceac2 +size 57175 diff --git a/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Day_5_en.png b/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Day_5_en.png index e1a5813252..3a262e8d47 100644 --- a/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Day_5_en.png +++ b/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Day_5_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:5f106b4672b1d96665fe731de28b7ccbb98f986580fd95cc6609a7b64348c60e -size 67665 +oid sha256:96ce82255e49c97179a216124ccfcbc6726a8053acef767041ba44304e7f4735 +size 67756 diff --git a/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Day_9_en.png b/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Day_9_en.png index 41552d0bf3..36b337448b 100644 --- a/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Day_9_en.png +++ b/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Day_9_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:521e3b0b36dbed830eab8cd884a1924381bd9a50c189ff9ef074ed468aaf9b23 -size 84195 +oid sha256:bcd14b5720ecc9a80f6f2cc7133d6c8695096b9c90d3504380464c46c91048c8 +size 87131 diff --git a/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Night_0_en.png b/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Night_0_en.png index d981f52759..63ff6e0ae9 100644 --- a/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Night_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Night_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:00af046190654a77e02d1152e8d44f538302b2fecfbd31b8790cdfa6f202dc1b -size 62502 +oid sha256:e8518ca0e40ddff8b8f8cd1960a5cc8c4419a7f7381459f2bca782df80cb0094 +size 62676 diff --git a/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Night_10_en.png b/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Night_10_en.png index beea74ec9f..420cb7c631 100644 --- a/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Night_10_en.png +++ b/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Night_10_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:86305c47144ed620efd27045239c0ca66f11cb5f2088b4df8e7f9e7a254576fa -size 31166 +oid sha256:d56c1af9fc73f4aaeed33dd8b6113ec64ddbfdf63506aa31ae6996732870baa2 +size 31127 diff --git a/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Night_11_en.png b/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Night_11_en.png index a7590f793b..ad828b778a 100644 --- a/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Night_11_en.png +++ b/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Night_11_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:cee0eefc4639ede46fd6539da213f0398de0611fc1e6f2002c6e014318c04380 -size 26665 +oid sha256:14d762574470814f5b37cc05a2167d546f92460bd016206e71ba43026d00f9cc +size 26743 diff --git a/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Night_13_en.png b/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Night_13_en.png index a98cfc0be9..50a4131bfc 100644 --- a/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Night_13_en.png +++ b/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Night_13_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:1605040770a4b5d8928b41afab2e2f970f18283942659b2b869451e5c04d3d5b -size 83224 +oid sha256:bd10af4fb01aa715a0f913f590980da266a9d3a68b5f2222a5f329f98069277c +size 83328 diff --git a/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Night_14_en.png b/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Night_14_en.png index b6f89c6e0f..280257f53d 100644 --- a/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Night_14_en.png +++ b/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Night_14_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:90bf5140e04bd22af001ed9d23513b26d555f2d73864d9012c8e05f452659fd8 -size 78641 +oid sha256:7e841a58c50c98444bcc48316654ee5c664cf845e3c38f4bd02e80ce8d3c9366 +size 81261 diff --git a/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Night_15_en.png b/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Night_15_en.png index 75156df8d2..2691d1c1df 100644 --- a/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Night_15_en.png +++ b/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Night_15_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:828d2d972c03e2cdb837e591c957c93fd61c1f49e3e4fcf19a8bf18963d4eb95 -size 48307 +oid sha256:66d241a4270bef0a1f80c62c302cb5b40b4370f73e8175a746d32c90d1f98208 +size 49882 diff --git a/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Night_16_en.png b/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Night_16_en.png index ba6d02cb65..451ca0c3ec 100644 --- a/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Night_16_en.png +++ b/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Night_16_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:b1d6080fd17d90e63b4aae91c6a2c93bd16314eacc6007f57073e981c4dfb1c6 -size 37378 +oid sha256:1838a9839badf62d4d427a66a15a7d220996bdb0b60f0373249d62e4afae2910 +size 37390 diff --git a/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Night_1_en.png b/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Night_1_en.png index d981f52759..63ff6e0ae9 100644 --- a/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Night_1_en.png +++ b/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Night_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:00af046190654a77e02d1152e8d44f538302b2fecfbd31b8790cdfa6f202dc1b -size 62502 +oid sha256:e8518ca0e40ddff8b8f8cd1960a5cc8c4419a7f7381459f2bca782df80cb0094 +size 62676 diff --git a/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Night_2_en.png b/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Night_2_en.png index d981f52759..63ff6e0ae9 100644 --- a/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Night_2_en.png +++ b/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Night_2_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:00af046190654a77e02d1152e8d44f538302b2fecfbd31b8790cdfa6f202dc1b -size 62502 +oid sha256:e8518ca0e40ddff8b8f8cd1960a5cc8c4419a7f7381459f2bca782df80cb0094 +size 62676 diff --git a/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Night_3_en.png b/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Night_3_en.png index 57b492b81d..a709ce6a75 100644 --- a/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Night_3_en.png +++ b/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Night_3_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:71e33566c0404f1930831b846a2e78952dd33138ffde5257c3d413739e225040 -size 60212 +oid sha256:c10e44c82a7412fd51a651a69b9c643a7b1eafcc4251227009e44a47e9649bb5 +size 60656 diff --git a/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Night_4_en.png b/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Night_4_en.png index 7f3194855d..01f74fdbc5 100644 --- a/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Night_4_en.png +++ b/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Night_4_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:363efc8054e6a1e04d0482e5351d7e190febf55167a0358d4251101ee6ebd659 -size 50942 +oid sha256:f38bf5504ece28cfe2bdaf5e958ecf8af30a1a3e97b3b2d9c43924c362673402 +size 52181 diff --git a/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Night_5_en.png b/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Night_5_en.png index d981f52759..63ff6e0ae9 100644 --- a/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Night_5_en.png +++ b/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Night_5_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:00af046190654a77e02d1152e8d44f538302b2fecfbd31b8790cdfa6f202dc1b -size 62502 +oid sha256:e8518ca0e40ddff8b8f8cd1960a5cc8c4419a7f7381459f2bca782df80cb0094 +size 62676 diff --git a/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Night_9_en.png b/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Night_9_en.png index 33074b9c42..a408245bae 100644 --- a/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Night_9_en.png +++ b/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Night_9_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:465ffe0ea53fe7bde74c9dddb1be5e9f2861436b5292956f889dcf60db621af2 -size 78499 +oid sha256:0b09c1c639b12b0521da9e4b403530d4bd33f6e79823903091870fba56477153 +size 81113 From 9e42a1c4291a692b2d08f455d66a8070525dbe0d Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 27 Feb 2026 13:24:41 +0000 Subject: [PATCH 28/60] Update dependency com.google.firebase:firebase-bom to v34.10.0 --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 8a3c055ad9..de9d0bbc1a 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -80,7 +80,7 @@ kotlinpoet-ksp = { module = "com.squareup:kotlinpoet-ksp", version.ref = "kotlin kover_gradle_plugin = { module = "org.jetbrains.kotlinx:kover-gradle-plugin", version.ref = "kover" } ksp_gradle_plugin = { module = "com.google.devtools.ksp:com.google.devtools.ksp.gradle.plugin", version.ref = "ksp" } # https://firebase.google.com/docs/android/setup#available-libraries -google_firebase_bom = "com.google.firebase:firebase-bom:34.9.0" +google_firebase_bom = "com.google.firebase:firebase-bom:34.10.0" firebase_appdistribution_gradle = { module = "com.google.firebase:firebase-appdistribution-gradle", version.ref = "firebaseAppDistribution" } autonomousapps_dependencyanalysis_plugin = { module = "com.autonomousapps:dependency-analysis-gradle-plugin", version.ref = "dependencyAnalysis" } ksp_plugin = { module = "com.google.devtools.ksp:symbol-processing-api", version.ref = "ksp" } From 1d0978c52b14bab74162f4b379b8d88f0998c838 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 28 Feb 2026 01:41:00 +0000 Subject: [PATCH 29/60] Update dependency androidx.compose:compose-bom to v2026.02.01 --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 8a3c055ad9..6d3d6edf69 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -22,7 +22,7 @@ camera = "1.5.3" work = "2.11.1" # Compose -compose_bom = "2026.02.00" +compose_bom = "2026.02.01" # Coroutines coroutines = "1.10.2" From b3b22033aafdc3def88a050a16d4a37fead4085b Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Tue, 24 Feb 2026 12:38:20 +0100 Subject: [PATCH 30/60] Handle EventRedacted case. Fixes #5569 --- .../api/exception/NotificationResolverException.kt | 5 +++++ .../impl/notification/RustNotificationService.kt | 4 ++++ .../libraries/push/impl/push/DefaultPushHandler.kt | 12 ++++++++++++ 3 files changed, 21 insertions(+) diff --git a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/exception/NotificationResolverException.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/exception/NotificationResolverException.kt index fd3adf2592..a83fbd1e23 100644 --- a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/exception/NotificationResolverException.kt +++ b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/exception/NotificationResolverException.kt @@ -22,6 +22,11 @@ sealed class NotificationResolverException : Exception() { */ data object EventFilteredOut : NotificationResolverException() + /** + * The event was found but it has been redacted. + */ + data object EventRedacted : NotificationResolverException() + /** * An unexpected error occurred while trying to resolve the event. */ diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/notification/RustNotificationService.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/notification/RustNotificationService.kt index 59d95af05b..238a8d988c 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/notification/RustNotificationService.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/notification/RustNotificationService.kt @@ -66,6 +66,10 @@ class RustNotificationService( Timber.d("Could not retrieve event for notification with $eventId - event filtered out") put(eventId, Result.failure(NotificationResolverException.EventFilteredOut)) } + NotificationStatus.EventRedacted -> { + Timber.d("Could not retrieve event for notification with $eventId - event redacted") + put(eventId, Result.failure(NotificationResolverException.EventRedacted)) + } } } is BatchNotificationResult.Error -> { diff --git a/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/push/DefaultPushHandler.kt b/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/push/DefaultPushHandler.kt index 3f13f33818..0053a18838 100644 --- a/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/push/DefaultPushHandler.kt +++ b/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/push/DefaultPushHandler.kt @@ -124,6 +124,14 @@ class DefaultPushHandler( sessionId = request.sessionId, comment = "Push handled successfully but notification was filtered out", ) + } else if (exception is NotificationResolverException.EventRedacted) { + pushHistoryService.onSuccess( + providerInfo = request.providerInfo, + eventId = request.eventId, + roomId = request.roomId, + sessionId = request.sessionId, + comment = "Push handled successfully but event has been redacted", + ) } else { val reason = when (exception) { is NotificationResolverException.EventNotFound -> "Event not found" @@ -155,6 +163,10 @@ class DefaultPushHandler( // Do nothing, we don't want to show a notification for filtered out events null } + is NotificationResolverException.EventRedacted -> { + // Do nothing, we don't want to show a notification for redacted events + null + } else -> { Timber.tag(loggerTag.value).e(exception, "Failed to resolve push event") ResolvedPushEvent.Event( From 47d132ef1bb5f8a5efdb9b9c3e4c688eadf2122e Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 27 Feb 2026 14:47:41 +0000 Subject: [PATCH 31/60] Update dependency org.matrix.rustcomponents:sdk-android to v26.03.1 --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 8a3c055ad9..08fdf33946 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -178,7 +178,7 @@ test_detekt_test = { module = "io.gitlab.arturbosch.detekt:detekt-test", version # https://github.com/matrix-org/matrix-rust-components-kotlin/commits/main/sdk/sdk-android/src/main/kotlin/org/matrix/rustcomponents/sdk/matrix_sdk_ffi.kt # All new features should not be implemented in the pull request that upgrades the version, developers should # only fix API breaks and may add some TODOs. -matrix_sdk = "org.matrix.rustcomponents:sdk-android:26.03.0" +matrix_sdk = "org.matrix.rustcomponents:sdk-android:26.03.1" # Others coil = { module = "io.coil-kt.coil3:coil", version.ref = "coil" } From 286aa5614514300a9e0e05e701071ae123720a9a Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Mon, 2 Mar 2026 09:18:43 +0100 Subject: [PATCH 32/60] Fix API break. --- .../matrix/impl/timeline/RoomTimelineExtensions.kt | 6 +++--- .../android/libraries/matrix/impl/timeline/RustTimeline.kt | 6 +++--- .../libraries/matrix/impl/fixtures/fakes/FakeFfiTimeline.kt | 4 ++-- .../libraries/matrix/impl/timeline/RustTimelineTest.kt | 6 +++--- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/RoomTimelineExtensions.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/RoomTimelineExtensions.kt index bc0e5eed99..c932230217 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/RoomTimelineExtensions.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/RoomTimelineExtensions.kt @@ -21,11 +21,11 @@ import org.matrix.rustcomponents.sdk.TimelineDiff import org.matrix.rustcomponents.sdk.TimelineInterface import org.matrix.rustcomponents.sdk.TimelineListener import timber.log.Timber -import uniffi.matrix_sdk.RoomPaginationStatus +import uniffi.matrix_sdk.PaginationStatus -internal fun TimelineInterface.liveBackPaginationStatus(): Flow = callbackFlow { +internal fun TimelineInterface.liveBackPaginationStatus(): Flow = callbackFlow { val listener = object : PaginationStatusListener { - override fun onUpdate(status: RoomPaginationStatus) { + override fun onUpdate(status: PaginationStatus) { trySend(status) } } 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 391349b52d..0ee7239933 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 @@ -71,7 +71,7 @@ import org.matrix.rustcomponents.sdk.UploadParameters import org.matrix.rustcomponents.sdk.UploadSource import org.matrix.rustcomponents.sdk.use import timber.log.Timber -import uniffi.matrix_sdk.RoomPaginationStatus +import uniffi.matrix_sdk.PaginationStatus import java.io.File import org.matrix.rustcomponents.sdk.EventOrTransactionId as RustEventOrTransactionId import org.matrix.rustcomponents.sdk.Timeline as InnerTimeline @@ -147,8 +147,8 @@ class RustTimeline( .onEach { backPaginationStatus -> updatePaginationStatus(Timeline.PaginationDirection.BACKWARDS) { when (backPaginationStatus) { - is RoomPaginationStatus.Idle -> it.copy(isPaginating = false, hasMoreToLoad = !backPaginationStatus.hitTimelineStart) - is RoomPaginationStatus.Paginating -> it.copy(isPaginating = true, hasMoreToLoad = true) + is PaginationStatus.Idle -> it.copy(isPaginating = false, hasMoreToLoad = !backPaginationStatus.hitTimelineStart) + is PaginationStatus.Paginating -> it.copy(isPaginating = true, hasMoreToLoad = true) } } } diff --git a/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/fixtures/fakes/FakeFfiTimeline.kt b/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/fixtures/fakes/FakeFfiTimeline.kt index d45330bd3f..1c65ab00f2 100644 --- a/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/fixtures/fakes/FakeFfiTimeline.kt +++ b/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/fixtures/fakes/FakeFfiTimeline.kt @@ -14,7 +14,7 @@ import org.matrix.rustcomponents.sdk.TaskHandle import org.matrix.rustcomponents.sdk.Timeline import org.matrix.rustcomponents.sdk.TimelineDiff import org.matrix.rustcomponents.sdk.TimelineListener -import uniffi.matrix_sdk.RoomPaginationStatus +import uniffi.matrix_sdk.PaginationStatus class FakeFfiTimeline : Timeline(NoHandle) { private var listener: TimelineListener? = null @@ -33,7 +33,7 @@ class FakeFfiTimeline : Timeline(NoHandle) { return FakeFfiTaskHandle() } - fun emitPaginationStatus(status: RoomPaginationStatus) { + fun emitPaginationStatus(status: PaginationStatus) { paginationStatusListener!!.onUpdate(status) } diff --git a/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/timeline/RustTimelineTest.kt b/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/timeline/RustTimelineTest.kt index ab46e8aa5f..4c96800cd0 100644 --- a/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/timeline/RustTimelineTest.kt +++ b/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/timeline/RustTimelineTest.kt @@ -32,7 +32,7 @@ import kotlinx.coroutines.test.runCurrent import kotlinx.coroutines.test.runTest import org.junit.Test import org.matrix.rustcomponents.sdk.TimelineDiff -import uniffi.matrix_sdk.RoomPaginationStatus +import uniffi.matrix_sdk.PaginationStatus import org.matrix.rustcomponents.sdk.Timeline as InnerTimeline class RustTimelineTest { @@ -68,10 +68,10 @@ class RustTimelineTest { // Start pagination sut.paginate(Timeline.PaginationDirection.BACKWARDS) // Simulate SDK starting pagination - inner.emitPaginationStatus(RoomPaginationStatus.Paginating) + inner.emitPaginationStatus(PaginationStatus.Paginating) // No new events received // Simulate SDK stopping pagination, more event to load - inner.emitPaginationStatus(RoomPaginationStatus.Idle(hitTimelineStart = false)) + inner.emitPaginationStatus(PaginationStatus.Idle(hitTimelineStart = false)) // expect an item to be emitted, with an updated timestamp with(awaitItem()) { assertThat(size).isEqualTo(2) From 6e72454c1c76b596517ccb1b38c33bf7433f48a6 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Mon, 2 Mar 2026 09:40:42 +0100 Subject: [PATCH 33/60] Fix API break. --- .../impl/LinkNewDeviceFlowNode.kt | 6 +++- .../matrix/api/linknewdevice/ErrorType.kt | 30 +++++++++++++++---- .../HumanQrGrantLoginExceptionExtension.kt | 6 +++- 3 files changed, 35 insertions(+), 7 deletions(-) diff --git a/features/linknewdevice/impl/src/main/kotlin/io/element/android/features/linknewdevice/impl/LinkNewDeviceFlowNode.kt b/features/linknewdevice/impl/src/main/kotlin/io/element/android/features/linknewdevice/impl/LinkNewDeviceFlowNode.kt index 52e93d4992..79a476ff04 100644 --- a/features/linknewdevice/impl/src/main/kotlin/io/element/android/features/linknewdevice/impl/LinkNewDeviceFlowNode.kt +++ b/features/linknewdevice/impl/src/main/kotlin/io/element/android/features/linknewdevice/impl/LinkNewDeviceFlowNode.kt @@ -189,9 +189,13 @@ class LinkNewDeviceFlowNode( is ErrorType.InvalidCheckCode -> ErrorScreenType.InsecureChannelDetected is ErrorType.MissingSecretsBackup -> ErrorScreenType.UnknownError is ErrorType.NotFound -> ErrorScreenType.Expired - is ErrorType.UnableToCreateDevice -> ErrorScreenType.UnknownError + is ErrorType.DeviceNotFound -> ErrorScreenType.UnknownError is ErrorType.Unknown -> ErrorScreenType.UnknownError is ErrorType.UnsupportedProtocol -> ErrorScreenType.UnknownError + is ErrorType.Cancelled -> ErrorScreenType.UnknownError + is ErrorType.ConnectionInsecure -> ErrorScreenType.InsecureChannelDetected + is ErrorType.Expired -> ErrorScreenType.Expired + is ErrorType.OtherDeviceAlreadySignedIn -> ErrorScreenType.UnknownError } // It is OK to push on backstack, since when user leaves the error screen, a new root will be set, // or the whole flow will be popped. diff --git a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/linknewdevice/ErrorType.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/linknewdevice/ErrorType.kt index 0f61007d47..21c0d521c9 100644 --- a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/linknewdevice/ErrorType.kt +++ b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/linknewdevice/ErrorType.kt @@ -33,13 +33,33 @@ sealed class ErrorType(message: String) : Exception(message) { */ class NotFound(message: String) : ErrorType(message) - /** - * The device could not be created. - */ - class UnableToCreateDevice(message: String) : ErrorType(message) - /** * An unknown error has happened. */ class Unknown(message: String) : ErrorType(message) + + /** + * The requested device was not returned by the homeserver. + */ + class DeviceNotFound(message: String) : ErrorType(message) + + /** + * The other device is already signed in and so does not need to sign in. + */ + class OtherDeviceAlreadySignedIn(message: String) : ErrorType(message) + + /** + * The sign in was cancelled. + */ + class Cancelled(message: String) : ErrorType(message) + + /** + * The sign in was not completed in the required time. + */ + class Expired(message: String) : ErrorType(message) + + /** + * A secure connection could not have been established between the two devices. + */ + class ConnectionInsecure(message: String) : ErrorType(message) } diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/linknewdevice/HumanQrGrantLoginExceptionExtension.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/linknewdevice/HumanQrGrantLoginExceptionExtension.kt index 2d47b60def..4027ee507b 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/linknewdevice/HumanQrGrantLoginExceptionExtension.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/linknewdevice/HumanQrGrantLoginExceptionExtension.kt @@ -15,7 +15,11 @@ internal fun HumanQrGrantLoginException.map() = when (this) { is HumanQrGrantLoginException.InvalidCheckCode -> ErrorType.InvalidCheckCode(message.orEmpty()) is HumanQrGrantLoginException.MissingSecretsBackup -> ErrorType.MissingSecretsBackup(message.orEmpty()) is HumanQrGrantLoginException.NotFound -> ErrorType.NotFound(message.orEmpty()) - is HumanQrGrantLoginException.UnableToCreateDevice -> ErrorType.UnableToCreateDevice(message.orEmpty()) + is HumanQrGrantLoginException.Cancelled -> ErrorType.Cancelled(message.orEmpty()) + is HumanQrGrantLoginException.ConnectionInsecure -> ErrorType.ConnectionInsecure(message.orEmpty()) + is HumanQrGrantLoginException.DeviceNotFound -> ErrorType.DeviceNotFound(message.orEmpty()) + is HumanQrGrantLoginException.Expired -> ErrorType.Expired(message.orEmpty()) + is HumanQrGrantLoginException.OtherDeviceAlreadySignedIn -> ErrorType.OtherDeviceAlreadySignedIn(message.orEmpty()) is HumanQrGrantLoginException.Unknown -> ErrorType.Unknown(message.orEmpty()) is HumanQrGrantLoginException.UnsupportedProtocol -> ErrorType.UnsupportedProtocol(message.orEmpty()) } From 494e425de0ea4ccc8017d978bb8bb210ec628cc8 Mon Sep 17 00:00:00 2001 From: Jorge Martin Espinosa Date: Mon, 2 Mar 2026 11:23:41 +0100 Subject: [PATCH 34/60] CI: Add failed tests to summary (#6271) * Fix maestro CI flow not writing the successful summary * Add the test failures to the summary of the `test` CI flow --- .github/workflows/maestro-local.yml | 2 +- .../workflows/scripts/parse_test_failures.py | 77 +++++++++++++++++++ .github/workflows/tests.yml | 9 +++ 3 files changed, 87 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/scripts/parse_test_failures.py diff --git a/.github/workflows/maestro-local.yml b/.github/workflows/maestro-local.yml index 9ff6f578c9..0c7dcc0418 100644 --- a/.github/workflows/maestro-local.yml +++ b/.github/workflows/maestro-local.yml @@ -126,7 +126,7 @@ jobs: - name: Update summary (success) if: steps.maestro_test.outcome == 'success' run: | - echo "### Maestro tests worked :rocket:!" + echo "### Maestro tests worked :rocket:!" >> $GITHUB_STEP_SUMMARY - name: Update summary (failure) if: steps.maestro_test.outcome != 'success' run: | diff --git a/.github/workflows/scripts/parse_test_failures.py b/.github/workflows/scripts/parse_test_failures.py new file mode 100644 index 0000000000..eb0a0ecafa --- /dev/null +++ b/.github/workflows/scripts/parse_test_failures.py @@ -0,0 +1,77 @@ +#!/usr/bin/env python3 +import xml.etree.ElementTree as ET +import sys +import glob + +screenshot_test_failures = [] +output = [] + +def parse_test_failures(xml_file): + """Parse XML test results and print failures.""" + tree = ET.parse(xml_file) + root = tree.getroot() + + # Find all testcase elements with failure children + if root.get("failures", "0") == "0": + return + + name = root.get('name', 'Test Suite') + is_screenshot_test = name.startswith('ui.Preview') + + if not is_screenshot_test: + output.append(f"## {name}") + + for testcase in root.findall('.//testcase'): + failure = testcase.find('failure') + if failure is not None: + # Get testcase attributes + classname = testcase.get('classname', '') + name = testcase.get('name', '') + + if is_screenshot_test: + # For screenshot tests, we want to display the classname as well + screenshot_test_failures.append(f"{classname}.{name}") + else: + # Get failure content (text inside the failure element) + failure_message = failure.get('message', '') + failure_content = failure.text if failure.text else '' + + # Print in the requested format + output.append(f"### {name}") + output.append("```") + output.append(failure_message) + output.append("```") + output.append("
Stacktrace") + output.append(f"
{failure_content}
") + output.append("
") + output.append("\n") + +if __name__ == "__main__": + if len(sys.argv) < 2: + output.append("Usage: parse_test_failures.py ", file=sys.stderr) + sys.exit(1) + + file = sys.argv[1] + + if file.endswith('xml'): + parse_test_failures(file) + else: + files = glob.glob("**/build/test-results/*UnitTest/*.xml", root_dir = file, recursive = True) + for file in files: + parse_test_failures(file) + + if screenshot_test_failures: + output.append("## Screenshot Test Failures") + output.append("```") + for failure in screenshot_test_failures: + output.append(failure) + output.append("```") + + text_output = '\n'.join(output) + # Trim output larger than 1MB to avoid GitHub Action log limits + while len(text_output.encode('utf-8')) > 1_040_000: + output.pop(-2) + output.append("## !!! Truncated output due to size limits. !!!") + text_output = '\n'.join(output) + + print(text_output) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 68339e8443..522de31daf 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -95,6 +95,15 @@ jobs: **/build/roborazzi/failures/ **/build/reports/tests/*UnitTest/ + - name: 🚫 Modify summary on error + if: failure() + run: | + echo """## Tests failed! + + """ >> $GITHUB_STEP_SUMMARY + python3 .github/workflows/scripts/parse_test_failures.py . >> $GITHUB_STEP_SUMMARY + echo "---" >> $GITHUB_STEP_SUMMARY + # https://github.com/codecov/codecov-action - name: ☂️ Upload coverage reports to codecov uses: codecov/codecov-action@671740ac38dd9b0130fbe1cec585b89eea48d3de # v5.5.2 From 22fb9b7cc13fbe12d5a601aae97dd93f356fc2b3 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Mon, 2 Mar 2026 12:40:33 +0100 Subject: [PATCH 35/60] Import compound token v6.10.1 ./tools/compound/import_tokens.sh -b v6.10.1 --- .../compound/src/main/assets/theme.iife.js | 2 +- .../tokens/generated/CompoundIcons.kt | 87 ++++++++++++++++++- .../tokens/generated/SemanticColors.kt | 14 ++- .../tokens/generated/SemanticColorsDark.kt | 12 ++- .../tokens/generated/SemanticColorsDarkHc.kt | 12 ++- .../tokens/generated/SemanticColorsLight.kt | 12 ++- .../tokens/generated/SemanticColorsLightHc.kt | 12 ++- .../tokens/generated/TypographyTokens.kt | 2 +- .../generated/internal/DarkColorTokens.kt | 2 +- .../generated/internal/DarkHcColorTokens.kt | 2 +- .../generated/internal/LightColorTokens.kt | 2 +- .../generated/internal/LightHcColorTokens.kt | 2 +- .../ic_compound_advanced_settings.xml | 14 +++ .../res/drawable/ic_compound_backspace.xml | 14 +-- .../drawable/ic_compound_backspace_solid.xml | 5 +- .../src/main/res/drawable/ic_compound_bug.xml | 9 ++ .../src/main/res/drawable/ic_compound_mac.xml | 2 +- .../res/drawable/ic_compound_re_order.xml | 9 ++ .../res/drawable/ic_compound_rotate_left.xml | 9 ++ .../res/drawable/ic_compound_rotate_right.xml | 13 +++ .../main/res/drawable/ic_compound_section.xml | 9 ++ .../main/res/drawable/ic_compound_stop.xml | 9 ++ .../res/drawable/ic_compound_stop_solid.xml | 9 ++ .../main/res/drawable/ic_compound_theme.xml | 9 ++ .../res/drawable/ic_compound_translate.xml | 10 +++ .../main/res/drawable/ic_compound_tree.xml | 9 ++ .../ic_compound_video_call_outgoing_solid.xml | 11 +++ .../res/drawable/ic_compound_voice_call.xml | 12 +-- .../ic_compound_voice_call_declined_solid.xml | 10 +++ .../ic_compound_voice_call_missed_solid.xml | 13 +++ .../ic_compound_voice_call_outgoing_solid.xml | 13 +++ .../main/res/drawable/ic_compound_zoom_in.xml | 23 +++++ .../res/drawable/ic_compound_zoom_out.xml | 13 +++ tools/compound/addAutoMirrored.py | 4 + 34 files changed, 328 insertions(+), 62 deletions(-) create mode 100644 libraries/compound/src/main/res/drawable/ic_compound_advanced_settings.xml create mode 100644 libraries/compound/src/main/res/drawable/ic_compound_bug.xml create mode 100644 libraries/compound/src/main/res/drawable/ic_compound_re_order.xml create mode 100644 libraries/compound/src/main/res/drawable/ic_compound_rotate_left.xml create mode 100644 libraries/compound/src/main/res/drawable/ic_compound_rotate_right.xml create mode 100644 libraries/compound/src/main/res/drawable/ic_compound_section.xml create mode 100644 libraries/compound/src/main/res/drawable/ic_compound_stop.xml create mode 100644 libraries/compound/src/main/res/drawable/ic_compound_stop_solid.xml create mode 100644 libraries/compound/src/main/res/drawable/ic_compound_theme.xml create mode 100644 libraries/compound/src/main/res/drawable/ic_compound_translate.xml create mode 100644 libraries/compound/src/main/res/drawable/ic_compound_tree.xml create mode 100644 libraries/compound/src/main/res/drawable/ic_compound_video_call_outgoing_solid.xml create mode 100644 libraries/compound/src/main/res/drawable/ic_compound_voice_call_declined_solid.xml create mode 100644 libraries/compound/src/main/res/drawable/ic_compound_voice_call_missed_solid.xml create mode 100644 libraries/compound/src/main/res/drawable/ic_compound_voice_call_outgoing_solid.xml create mode 100644 libraries/compound/src/main/res/drawable/ic_compound_zoom_in.xml create mode 100644 libraries/compound/src/main/res/drawable/ic_compound_zoom_out.xml diff --git a/libraries/compound/src/main/assets/theme.iife.js b/libraries/compound/src/main/assets/theme.iife.js index 71ce6b0013..1dd693cbd4 100644 --- a/libraries/compound/src/main/assets/theme.iife.js +++ b/libraries/compound/src/main/assets/theme.iife.js @@ -1 +1 @@ -var CompoundTheme=(function(Fe){"use strict";const Xe=(e,t=0,r=1)=>Zt(Jt(t,e),r),Yt=e=>{e._clipped=!1,e._unclipped=e.slice(0);for(let t=0;t<=3;t++)t<3?((e[t]<0||e[t]>255)&&(e._clipped=!0),e[t]=Xe(e[t],0,255)):t===3&&(e[t]=Xe(e[t],0,1));return e},co={};for(let e of["Boolean","Number","String","Function","Array","Date","RegExp","Undefined","Null"])co[`[object ${e}]`]=e.toLowerCase();function P(e){return co[Object.prototype.toString.call(e)]||"object"}const j=(e,t=null)=>e.length>=3?Array.prototype.slice.call(e):P(e[0])=="object"&&t?t.split("").filter(r=>e[0][r]!==void 0).map(r=>e[0][r]):e[0],pt=e=>{if(e.length<2)return null;const t=e.length-1;return P(e[t])=="string"?e[t].toLowerCase():null},{PI:mt,min:Zt,max:Jt}=Math,we=mt*2,Wt=mt/3,Ac=mt/180,Lc=180/mt,L={format:{},autodetect:[]};let $=class{constructor(...t){const r=this;if(P(t[0])==="object"&&t[0].constructor&&t[0].constructor===this.constructor)return t[0];let n=pt(t),o=!1;if(!n){o=!0,L.sorted||(L.autodetect=L.autodetect.sort((a,s)=>s.p-a.p),L.sorted=!0);for(let a of L.autodetect)if(n=a.test(...t),n)break}if(L.format[n]){const a=L.format[n].apply(null,o?t:t.slice(0,-1));r._rgb=Yt(a)}else throw new Error("unknown format: "+t);r._rgb.length===3&&r._rgb.push(1)}toString(){return P(this.hex)=="function"?this.hex():`[${this._rgb.join(",")}]`}};const Ec="2.6.0",O=(...e)=>new O.Color(...e);O.Color=$,O.version=Ec;const Tc=(...e)=>{e=j(e,"cmyk");const[t,r,n,o]=e,a=e.length>4?e[4]:1;return o===1?[0,0,0,a]:[t>=1?0:255*(1-t)*(1-o),r>=1?0:255*(1-r)*(1-o),n>=1?0:255*(1-n)*(1-o),a]},{max:io}=Math,Sc=(...e)=>{let[t,r,n]=j(e,"rgb");t=t/255,r=r/255,n=n/255;const o=1-io(t,io(r,n)),a=o<1?1/(1-o):0,s=(1-t-o)*a,c=(1-r-o)*a,i=(1-n-o)*a;return[s,c,i,o]};$.prototype.cmyk=function(){return Sc(this._rgb)},O.cmyk=(...e)=>new $(...e,"cmyk"),L.format.cmyk=Tc,L.autodetect.push({p:2,test:(...e)=>{if(e=j(e,"cmyk"),P(e)==="array"&&e.length===4)return"cmyk"}});const Ut=e=>Math.round(e*100)/100,Pc=(...e)=>{const t=j(e,"hsla");let r=pt(e)||"lsa";return t[0]=Ut(t[0]||0),t[1]=Ut(t[1]*100)+"%",t[2]=Ut(t[2]*100)+"%",r==="hsla"||t.length>3&&t[3]<1?(t[3]=t.length>3?t[3]:1,r="hsla"):t.length=3,`${r}(${t.join(",")})`},uo=(...e)=>{e=j(e,"rgba");let[t,r,n]=e;t/=255,r/=255,n/=255;const o=Zt(t,r,n),a=Jt(t,r,n),s=(a+o)/2;let c,i;return a===o?(c=0,i=Number.NaN):c=s<.5?(a-o)/(a+o):(a-o)/(2-a-o),t==a?i=(r-n)/(a-o):r==a?i=2+(n-t)/(a-o):n==a&&(i=4+(t-r)/(a-o)),i*=60,i<0&&(i+=360),e.length>3&&e[3]!==void 0?[i,c,s,e[3]]:[i,c,s]},{round:Qt}=Math,jc=(...e)=>{const t=j(e,"rgba");let r=pt(e)||"rgb";return r.substr(0,3)=="hsl"?Pc(uo(t),r):(t[0]=Qt(t[0]),t[1]=Qt(t[1]),t[2]=Qt(t[2]),(r==="rgba"||t.length>3&&t[3]<1)&&(t[3]=t.length>3?t[3]:1,r="rgba"),`${r}(${t.slice(0,r==="rgb"?3:4).join(",")})`)},{round:er}=Math,tr=(...e)=>{e=j(e,"hsl");const[t,r,n]=e;let o,a,s;if(r===0)o=a=s=n*255;else{const c=[0,0,0],i=[0,0,0],u=n<.5?n*(1+r):n+r-n*r,l=2*n-u,f=t/360;c[0]=f+1/3,c[1]=f,c[2]=f-1/3;for(let h=0;h<3;h++)c[h]<0&&(c[h]+=1),c[h]>1&&(c[h]-=1),6*c[h]<1?i[h]=l+(u-l)*6*c[h]:2*c[h]<1?i[h]=u:3*c[h]<2?i[h]=l+(u-l)*(2/3-c[h])*6:i[h]=l;[o,a,s]=[er(i[0]*255),er(i[1]*255),er(i[2]*255)]}return e.length>3?[o,a,s,e[3]]:[o,a,s,1]},fo=/^rgb\(\s*(-?\d+),\s*(-?\d+)\s*,\s*(-?\d+)\s*\)$/,lo=/^rgba\(\s*(-?\d+),\s*(-?\d+)\s*,\s*(-?\d+)\s*,\s*([01]|[01]?\.\d+)\)$/,ho=/^rgb\(\s*(-?\d+(?:\.\d+)?)%,\s*(-?\d+(?:\.\d+)?)%\s*,\s*(-?\d+(?:\.\d+)?)%\s*\)$/,bo=/^rgba\(\s*(-?\d+(?:\.\d+)?)%,\s*(-?\d+(?:\.\d+)?)%\s*,\s*(-?\d+(?:\.\d+)?)%\s*,\s*([01]|[01]?\.\d+)\)$/,po=/^hsl\(\s*(-?\d+(?:\.\d+)?),\s*(-?\d+(?:\.\d+)?)%\s*,\s*(-?\d+(?:\.\d+)?)%\s*\)$/,mo=/^hsla\(\s*(-?\d+(?:\.\d+)?),\s*(-?\d+(?:\.\d+)?)%\s*,\s*(-?\d+(?:\.\d+)?)%\s*,\s*([01]|[01]?\.\d+)\)$/,{round:go}=Math,rr=e=>{e=e.toLowerCase().trim();let t;if(L.format.named)try{return L.format.named(e)}catch{}if(t=e.match(fo)){const r=t.slice(1,4);for(let n=0;n<3;n++)r[n]=+r[n];return r[3]=1,r}if(t=e.match(lo)){const r=t.slice(1,5);for(let n=0;n<4;n++)r[n]=+r[n];return r}if(t=e.match(ho)){const r=t.slice(1,4);for(let n=0;n<3;n++)r[n]=go(r[n]*2.55);return r[3]=1,r}if(t=e.match(bo)){const r=t.slice(1,5);for(let n=0;n<3;n++)r[n]=go(r[n]*2.55);return r[3]=+r[3],r}if(t=e.match(po)){const r=t.slice(1,4);r[1]*=.01,r[2]*=.01;const n=tr(r);return n[3]=1,n}if(t=e.match(mo)){const r=t.slice(1,4);r[1]*=.01,r[2]*=.01;const n=tr(r);return n[3]=+t[4],n}};rr.test=e=>fo.test(e)||lo.test(e)||ho.test(e)||bo.test(e)||po.test(e)||mo.test(e),$.prototype.css=function(e){return jc(this._rgb,e)},O.css=(...e)=>new $(...e,"css"),L.format.css=rr,L.autodetect.push({p:5,test:(e,...t)=>{if(!t.length&&P(e)==="string"&&rr.test(e))return"css"}}),L.format.gl=(...e)=>{const t=j(e,"rgba");return t[0]*=255,t[1]*=255,t[2]*=255,t},O.gl=(...e)=>new $(...e,"gl"),$.prototype.gl=function(){const e=this._rgb;return[e[0]/255,e[1]/255,e[2]/255,e[3]]};const{floor:Bc}=Math,Gc=(...e)=>{e=j(e,"hcg");let[t,r,n]=e,o,a,s;n=n*255;const c=r*255;if(r===0)o=a=s=n;else{t===360&&(t=0),t>360&&(t-=360),t<0&&(t+=360),t/=60;const i=Bc(t),u=t-i,l=n*(1-r),f=l+c*(1-u),h=l+c*u,d=l+c;switch(i){case 0:[o,a,s]=[d,h,l];break;case 1:[o,a,s]=[f,d,l];break;case 2:[o,a,s]=[l,d,h];break;case 3:[o,a,s]=[l,f,d];break;case 4:[o,a,s]=[h,l,d];break;case 5:[o,a,s]=[d,l,f];break}}return[o,a,s,e.length>3?e[3]:1]},Ic=(...e)=>{const[t,r,n]=j(e,"rgb"),o=Zt(t,r,n),a=Jt(t,r,n),s=a-o,c=s*100/255,i=o/(255-s)*100;let u;return s===0?u=Number.NaN:(t===a&&(u=(r-n)/s),r===a&&(u=2+(n-t)/s),n===a&&(u=4+(t-r)/s),u*=60,u<0&&(u+=360)),[u,c,i]};$.prototype.hcg=function(){return Ic(this._rgb)},O.hcg=(...e)=>new $(...e,"hcg"),L.format.hcg=Gc,L.autodetect.push({p:1,test:(...e)=>{if(e=j(e,"hcg"),P(e)==="array"&&e.length===3)return"hcg"}});const zc=/^#?([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/,Fc=/^#?([A-Fa-f0-9]{8}|[A-Fa-f0-9]{4})$/,vo=e=>{if(e.match(zc)){(e.length===4||e.length===7)&&(e=e.substr(1)),e.length===3&&(e=e.split(""),e=e[0]+e[0]+e[1]+e[1]+e[2]+e[2]);const t=parseInt(e,16),r=t>>16,n=t>>8&255,o=t&255;return[r,n,o,1]}if(e.match(Fc)){(e.length===5||e.length===9)&&(e=e.substr(1)),e.length===4&&(e=e.split(""),e=e[0]+e[0]+e[1]+e[1]+e[2]+e[2]+e[3]+e[3]);const t=parseInt(e,16),r=t>>24&255,n=t>>16&255,o=t>>8&255,a=Math.round((t&255)/255*100)/100;return[r,n,o,a]}throw new Error(`unknown hex color: ${e}`)},{round:gt}=Math,_o=(...e)=>{let[t,r,n,o]=j(e,"rgba"),a=pt(e)||"auto";o===void 0&&(o=1),a==="auto"&&(a=o<1?"rgba":"rgb"),t=gt(t),r=gt(r),n=gt(n);let c="000000"+(t<<16|r<<8|n).toString(16);c=c.substr(c.length-6);let i="0"+gt(o*255).toString(16);switch(i=i.substr(i.length-2),a.toLowerCase()){case"rgba":return`#${c}${i}`;case"argb":return`#${i}${c}`;default:return`#${c}`}};$.prototype.hex=function(e){return _o(this._rgb,e)},O.hex=(...e)=>new $(...e,"hex"),L.format.hex=vo,L.autodetect.push({p:4,test:(e,...t)=>{if(!t.length&&P(e)==="string"&&[3,4,5,6,7,8,9].indexOf(e.length)>=0)return"hex"}});const{cos:Ke}=Math,Xc=(...e)=>{e=j(e,"hsi");let[t,r,n]=e,o,a,s;return isNaN(t)&&(t=0),isNaN(r)&&(r=0),t>360&&(t-=360),t<0&&(t+=360),t/=360,t<1/3?(s=(1-r)/3,o=(1+r*Ke(we*t)/Ke(Wt-we*t))/3,a=1-(s+o)):t<2/3?(t-=1/3,o=(1-r)/3,a=(1+r*Ke(we*t)/Ke(Wt-we*t))/3,s=1-(o+a)):(t-=2/3,a=(1-r)/3,s=(1+r*Ke(we*t)/Ke(Wt-we*t))/3,o=1-(a+s)),o=Xe(n*o*3),a=Xe(n*a*3),s=Xe(n*s*3),[o*255,a*255,s*255,e.length>3?e[3]:1]},{min:Kc,sqrt:Dc,acos:Vc}=Math,Yc=(...e)=>{let[t,r,n]=j(e,"rgb");t/=255,r/=255,n/=255;let o;const a=Kc(t,r,n),s=(t+r+n)/3,c=s>0?1-a/s:0;return c===0?o=NaN:(o=(t-r+(t-n))/2,o/=Dc((t-r)*(t-r)+(t-n)*(r-n)),o=Vc(o),n>r&&(o=we-o),o/=we),[o*360,c,s]};$.prototype.hsi=function(){return Yc(this._rgb)},O.hsi=(...e)=>new $(...e,"hsi"),L.format.hsi=Xc,L.autodetect.push({p:2,test:(...e)=>{if(e=j(e,"hsi"),P(e)==="array"&&e.length===3)return"hsi"}}),$.prototype.hsl=function(){return uo(this._rgb)},O.hsl=(...e)=>new $(...e,"hsl"),L.format.hsl=tr,L.autodetect.push({p:2,test:(...e)=>{if(e=j(e,"hsl"),P(e)==="array"&&e.length===3)return"hsl"}});const{floor:Zc}=Math,Jc=(...e)=>{e=j(e,"hsv");let[t,r,n]=e,o,a,s;if(n*=255,r===0)o=a=s=n;else{t===360&&(t=0),t>360&&(t-=360),t<0&&(t+=360),t/=60;const c=Zc(t),i=t-c,u=n*(1-r),l=n*(1-r*i),f=n*(1-r*(1-i));switch(c){case 0:[o,a,s]=[n,f,u];break;case 1:[o,a,s]=[l,n,u];break;case 2:[o,a,s]=[u,n,f];break;case 3:[o,a,s]=[u,l,n];break;case 4:[o,a,s]=[f,u,n];break;case 5:[o,a,s]=[n,u,l];break}}return[o,a,s,e.length>3?e[3]:1]},{min:Wc,max:Uc}=Math,Qc=(...e)=>{e=j(e,"rgb");let[t,r,n]=e;const o=Wc(t,r,n),a=Uc(t,r,n),s=a-o;let c,i,u;return u=a/255,a===0?(c=Number.NaN,i=0):(i=s/a,t===a&&(c=(r-n)/s),r===a&&(c=2+(n-t)/s),n===a&&(c=4+(t-r)/s),c*=60,c<0&&(c+=360)),[c,i,u]};$.prototype.hsv=function(){return Qc(this._rgb)},O.hsv=(...e)=>new $(...e,"hsv"),L.format.hsv=Jc,L.autodetect.push({p:2,test:(...e)=>{if(e=j(e,"hsv"),P(e)==="array"&&e.length===3)return"hsv"}});const se={Kn:18,Xn:.95047,Yn:1,Zn:1.08883,t0:.137931034,t1:.206896552,t2:.12841855,t3:.008856452},{pow:e0}=Math,yo=(...e)=>{e=j(e,"lab");const[t,r,n]=e;let o,a,s,c,i,u;return a=(t+16)/116,o=isNaN(r)?a:a+r/500,s=isNaN(n)?a:a-n/200,a=se.Yn*or(a),o=se.Xn*or(o),s=se.Zn*or(s),c=nr(3.2404542*o-1.5371385*a-.4985314*s),i=nr(-.969266*o+1.8760108*a+.041556*s),u=nr(.0556434*o-.2040259*a+1.0572252*s),[c,i,u,e.length>3?e[3]:1]},nr=e=>255*(e<=.00304?12.92*e:1.055*e0(e,1/2.4)-.055),or=e=>e>se.t1?e*e*e:se.t2*(e-se.t0),{pow:wo}=Math,ko=(...e)=>{const[t,r,n]=j(e,"rgb"),[o,a,s]=t0(t,r,n),c=116*a-16;return[c<0?0:c,500*(o-a),200*(a-s)]},sr=e=>(e/=255)<=.04045?e/12.92:wo((e+.055)/1.055,2.4),ar=e=>e>se.t3?wo(e,1/3):e/se.t2+se.t0,t0=(e,t,r)=>{e=sr(e),t=sr(t),r=sr(r);const n=ar((.4124564*e+.3575761*t+.1804375*r)/se.Xn),o=ar((.2126729*e+.7151522*t+.072175*r)/se.Yn),a=ar((.0193339*e+.119192*t+.9503041*r)/se.Zn);return[n,o,a]};$.prototype.lab=function(){return ko(this._rgb)},O.lab=(...e)=>new $(...e,"lab"),L.format.lab=yo,L.autodetect.push({p:2,test:(...e)=>{if(e=j(e,"lab"),P(e)==="array"&&e.length===3)return"lab"}});const{sin:r0,cos:n0}=Math,$o=(...e)=>{let[t,r,n]=j(e,"lch");return isNaN(n)&&(n=0),n=n*Ac,[t,n0(n)*r,r0(n)*r]},Co=(...e)=>{e=j(e,"lch");const[t,r,n]=e,[o,a,s]=$o(t,r,n),[c,i,u]=yo(o,a,s);return[c,i,u,e.length>3?e[3]:1]},o0=(...e)=>{const t=j(e,"hcl").reverse();return Co(...t)},{sqrt:s0,atan2:a0,round:c0}=Math,xo=(...e)=>{const[t,r,n]=j(e,"lab"),o=s0(r*r+n*n);let a=(a0(n,r)*Lc+360)%360;return c0(o*1e4)===0&&(a=Number.NaN),[t,o,a]},Ro=(...e)=>{const[t,r,n]=j(e,"rgb"),[o,a,s]=ko(t,r,n);return xo(o,a,s)};$.prototype.lch=function(){return Ro(this._rgb)},$.prototype.hcl=function(){return Ro(this._rgb).reverse()},O.lch=(...e)=>new $(...e,"lch"),O.hcl=(...e)=>new $(...e,"hcl"),L.format.lch=Co,L.format.hcl=o0,["lch","hcl"].forEach(e=>L.autodetect.push({p:2,test:(...t)=>{if(t=j(t,e),P(t)==="array"&&t.length===3)return e}}));const De={aliceblue:"#f0f8ff",antiquewhite:"#faebd7",aqua:"#00ffff",aquamarine:"#7fffd4",azure:"#f0ffff",beige:"#f5f5dc",bisque:"#ffe4c4",black:"#000000",blanchedalmond:"#ffebcd",blue:"#0000ff",blueviolet:"#8a2be2",brown:"#a52a2a",burlywood:"#deb887",cadetblue:"#5f9ea0",chartreuse:"#7fff00",chocolate:"#d2691e",coral:"#ff7f50",cornflowerblue:"#6495ed",cornsilk:"#fff8dc",crimson:"#dc143c",cyan:"#00ffff",darkblue:"#00008b",darkcyan:"#008b8b",darkgoldenrod:"#b8860b",darkgray:"#a9a9a9",darkgreen:"#006400",darkgrey:"#a9a9a9",darkkhaki:"#bdb76b",darkmagenta:"#8b008b",darkolivegreen:"#556b2f",darkorange:"#ff8c00",darkorchid:"#9932cc",darkred:"#8b0000",darksalmon:"#e9967a",darkseagreen:"#8fbc8f",darkslateblue:"#483d8b",darkslategray:"#2f4f4f",darkslategrey:"#2f4f4f",darkturquoise:"#00ced1",darkviolet:"#9400d3",deeppink:"#ff1493",deepskyblue:"#00bfff",dimgray:"#696969",dimgrey:"#696969",dodgerblue:"#1e90ff",firebrick:"#b22222",floralwhite:"#fffaf0",forestgreen:"#228b22",fuchsia:"#ff00ff",gainsboro:"#dcdcdc",ghostwhite:"#f8f8ff",gold:"#ffd700",goldenrod:"#daa520",gray:"#808080",green:"#008000",greenyellow:"#adff2f",grey:"#808080",honeydew:"#f0fff0",hotpink:"#ff69b4",indianred:"#cd5c5c",indigo:"#4b0082",ivory:"#fffff0",khaki:"#f0e68c",laserlemon:"#ffff54",lavender:"#e6e6fa",lavenderblush:"#fff0f5",lawngreen:"#7cfc00",lemonchiffon:"#fffacd",lightblue:"#add8e6",lightcoral:"#f08080",lightcyan:"#e0ffff",lightgoldenrod:"#fafad2",lightgoldenrodyellow:"#fafad2",lightgray:"#d3d3d3",lightgreen:"#90ee90",lightgrey:"#d3d3d3",lightpink:"#ffb6c1",lightsalmon:"#ffa07a",lightseagreen:"#20b2aa",lightskyblue:"#87cefa",lightslategray:"#778899",lightslategrey:"#778899",lightsteelblue:"#b0c4de",lightyellow:"#ffffe0",lime:"#00ff00",limegreen:"#32cd32",linen:"#faf0e6",magenta:"#ff00ff",maroon:"#800000",maroon2:"#7f0000",maroon3:"#b03060",mediumaquamarine:"#66cdaa",mediumblue:"#0000cd",mediumorchid:"#ba55d3",mediumpurple:"#9370db",mediumseagreen:"#3cb371",mediumslateblue:"#7b68ee",mediumspringgreen:"#00fa9a",mediumturquoise:"#48d1cc",mediumvioletred:"#c71585",midnightblue:"#191970",mintcream:"#f5fffa",mistyrose:"#ffe4e1",moccasin:"#ffe4b5",navajowhite:"#ffdead",navy:"#000080",oldlace:"#fdf5e6",olive:"#808000",olivedrab:"#6b8e23",orange:"#ffa500",orangered:"#ff4500",orchid:"#da70d6",palegoldenrod:"#eee8aa",palegreen:"#98fb98",paleturquoise:"#afeeee",palevioletred:"#db7093",papayawhip:"#ffefd5",peachpuff:"#ffdab9",peru:"#cd853f",pink:"#ffc0cb",plum:"#dda0dd",powderblue:"#b0e0e6",purple:"#800080",purple2:"#7f007f",purple3:"#a020f0",rebeccapurple:"#663399",red:"#ff0000",rosybrown:"#bc8f8f",royalblue:"#4169e1",saddlebrown:"#8b4513",salmon:"#fa8072",sandybrown:"#f4a460",seagreen:"#2e8b57",seashell:"#fff5ee",sienna:"#a0522d",silver:"#c0c0c0",skyblue:"#87ceeb",slateblue:"#6a5acd",slategray:"#708090",slategrey:"#708090",snow:"#fffafa",springgreen:"#00ff7f",steelblue:"#4682b4",tan:"#d2b48c",teal:"#008080",thistle:"#d8bfd8",tomato:"#ff6347",turquoise:"#40e0d0",violet:"#ee82ee",wheat:"#f5deb3",white:"#ffffff",whitesmoke:"#f5f5f5",yellow:"#ffff00",yellowgreen:"#9acd32"};$.prototype.name=function(){const e=_o(this._rgb,"rgb");for(let t of Object.keys(De))if(De[t]===e)return t.toLowerCase();return e},L.format.named=e=>{if(e=e.toLowerCase(),De[e])return vo(De[e]);throw new Error("unknown color name: "+e)},L.autodetect.push({p:5,test:(e,...t)=>{if(!t.length&&P(e)==="string"&&De[e.toLowerCase()])return"named"}});const i0=e=>{if(P(e)=="number"&&e>=0&&e<=16777215){const t=e>>16,r=e>>8&255,n=e&255;return[t,r,n,1]}throw new Error("unknown num color: "+e)},u0=(...e)=>{const[t,r,n]=j(e,"rgb");return(t<<16)+(r<<8)+n};$.prototype.num=function(){return u0(this._rgb)},O.num=(...e)=>new $(...e,"num"),L.format.num=i0,L.autodetect.push({p:5,test:(...e)=>{if(e.length===1&&P(e[0])==="number"&&e[0]>=0&&e[0]<=16777215)return"num"}});const{round:Ho}=Math;$.prototype.rgb=function(e=!0){return e===!1?this._rgb.slice(0,3):this._rgb.slice(0,3).map(Ho)},$.prototype.rgba=function(e=!0){return this._rgb.slice(0,4).map((t,r)=>r<3?e===!1?t:Ho(t):t)},O.rgb=(...e)=>new $(...e,"rgb"),L.format.rgb=(...e)=>{const t=j(e,"rgba");return t[3]===void 0&&(t[3]=1),t},L.autodetect.push({p:3,test:(...e)=>{if(e=j(e,"rgba"),P(e)==="array"&&(e.length===3||e.length===4&&P(e[3])=="number"&&e[3]>=0&&e[3]<=1))return"rgb"}});const{log:vt}=Math,qo=e=>{const t=e/100;let r,n,o;return t<66?(r=255,n=t<6?0:-155.25485562709179-.44596950469579133*(n=t-2)+104.49216199393888*vt(n),o=t<20?0:-254.76935184120902+.8274096064007395*(o=t-10)+115.67994401066147*vt(o)):(r=351.97690566805693+.114206453784165*(r=t-55)-40.25366309332127*vt(r),n=325.4494125711974+.07943456536662342*(n=t-50)-28.0852963507957*vt(n),o=255),[r,n,o,1]},{round:f0}=Math,l0=(...e)=>{const t=j(e,"rgb"),r=t[0],n=t[2];let o=1e3,a=4e4;const s=.4;let c;for(;a-o>s;){c=(a+o)*.5;const i=qo(c);i[2]/i[0]>=n/r?a=c:o=c}return f0(c)};$.prototype.temp=$.prototype.kelvin=$.prototype.temperature=function(){return l0(this._rgb)},O.temp=O.kelvin=O.temperature=(...e)=>new $(...e,"temp"),L.format.temp=L.format.kelvin=L.format.temperature=qo;const{pow:_t,sign:h0}=Math,Mo=(...e)=>{e=j(e,"lab");const[t,r,n]=e,o=_t(t+.3963377774*r+.2158037573*n,3),a=_t(t-.1055613458*r-.0638541728*n,3),s=_t(t-.0894841775*r-1.291485548*n,3);return[255*cr(4.0767416621*o-3.3077115913*a+.2309699292*s),255*cr(-1.2684380046*o+2.6097574011*a-.3413193965*s),255*cr(-.0041960863*o-.7034186147*a+1.707614701*s),e.length>3?e[3]:1]};function cr(e){const t=Math.abs(e);return t>.0031308?(h0(e)||1)*(1.055*_t(t,.4166666666666667)-.055):e*12.92}const{cbrt:ir,pow:d0,sign:b0}=Math,Oo=(...e)=>{const[t,r,n]=j(e,"rgb"),[o,a,s]=[ur(t/255),ur(r/255),ur(n/255)],c=ir(.4122214708*o+.5363325363*a+.0514459929*s),i=ir(.2119034982*o+.6806995451*a+.1073969566*s),u=ir(.0883024619*o+.2817188376*a+.6299787005*s);return[.2104542553*c+.793617785*i-.0040720468*u,1.9779984951*c-2.428592205*i+.4505937099*u,.0259040371*c+.7827717662*i-.808675766*u]};function ur(e){const t=Math.abs(e);return t<.04045?e/12.92:(b0(e)||1)*d0((t+.055)/1.055,2.4)}$.prototype.oklab=function(){return Oo(this._rgb)},O.oklab=(...e)=>new $(...e,"oklab"),L.format.oklab=Mo,L.autodetect.push({p:3,test:(...e)=>{if(e=j(e,"oklab"),P(e)==="array"&&e.length===3)return"oklab"}});const p0=(...e)=>{e=j(e,"lch");const[t,r,n]=e,[o,a,s]=$o(t,r,n),[c,i,u]=Mo(o,a,s);return[c,i,u,e.length>3?e[3]:1]},m0=(...e)=>{const[t,r,n]=j(e,"rgb"),[o,a,s]=Oo(t,r,n);return xo(o,a,s)};$.prototype.oklch=function(){return m0(this._rgb)},O.oklch=(...e)=>new $(...e,"oklch"),L.format.oklch=p0,L.autodetect.push({p:3,test:(...e)=>{if(e=j(e,"oklch"),P(e)==="array"&&e.length===3)return"oklch"}}),$.prototype.alpha=function(e,t=!1){return e!==void 0&&P(e)==="number"?t?(this._rgb[3]=e,this):new $([this._rgb[0],this._rgb[1],this._rgb[2],e],"rgb"):this._rgb[3]},$.prototype.clipped=function(){return this._rgb._clipped||!1},$.prototype.darken=function(e=1){const t=this,r=t.lab();return r[0]-=se.Kn*e,new $(r,"lab").alpha(t.alpha(),!0)},$.prototype.brighten=function(e=1){return this.darken(-e)},$.prototype.darker=$.prototype.darken,$.prototype.brighter=$.prototype.brighten,$.prototype.get=function(e){const[t,r]=e.split("."),n=this[t]();if(r){const o=t.indexOf(r)-(t.substr(0,2)==="ok"?2:0);if(o>-1)return n[o];throw new Error(`unknown channel ${r} in mode ${t}`)}else return n};const{pow:g0}=Math,v0=1e-7,_0=20;$.prototype.luminance=function(e,t="rgb"){if(e!==void 0&&P(e)==="number"){if(e===0)return new $([0,0,0,this._rgb[3]],"rgb");if(e===1)return new $([255,255,255,this._rgb[3]],"rgb");let r=this.luminance(),n=_0;const o=(s,c)=>{const i=s.interpolate(c,.5,t),u=i.luminance();return Math.abs(e-u)e?o(s,i):o(i,c)},a=(r>e?o(new $([0,0,0]),this):o(this,new $([255,255,255]))).rgb();return new $([...a,this._rgb[3]])}return y0(...this._rgb.slice(0,3))};const y0=(e,t,r)=>(e=fr(e),t=fr(t),r=fr(r),.2126*e+.7152*t+.0722*r),fr=e=>(e/=255,e<=.03928?e/12.92:g0((e+.055)/1.055,2.4)),re={},ct=(e,t,r=.5,...n)=>{let o=n[0]||"lrgb";if(!re[o]&&!n.length&&(o=Object.keys(re)[0]),!re[o])throw new Error(`interpolation mode ${o} is not defined`);return P(e)!=="object"&&(e=new $(e)),P(t)!=="object"&&(t=new $(t)),re[o](e,t,r).alpha(e.alpha()+r*(t.alpha()-e.alpha()))};$.prototype.mix=$.prototype.interpolate=function(e,t=.5,...r){return ct(this,e,t,...r)},$.prototype.premultiply=function(e=!1){const t=this._rgb,r=t[3];return e?(this._rgb=[t[0]*r,t[1]*r,t[2]*r,r],this):new $([t[0]*r,t[1]*r,t[2]*r,r],"rgb")},$.prototype.saturate=function(e=1){const t=this,r=t.lch();return r[1]+=se.Kn*e,r[1]<0&&(r[1]=0),new $(r,"lch").alpha(t.alpha(),!0)},$.prototype.desaturate=function(e=1){return this.saturate(-e)},$.prototype.set=function(e,t,r=!1){const[n,o]=e.split("."),a=this[n]();if(o){const s=n.indexOf(o)-(n.substr(0,2)==="ok"?2:0);if(s>-1){if(P(t)=="string")switch(t.charAt(0)){case"+":a[s]+=+t;break;case"-":a[s]+=+t;break;case"*":a[s]*=+t.substr(1);break;case"/":a[s]/=+t.substr(1);break;default:a[s]=+t}else if(P(t)==="number")a[s]=t;else throw new Error("unsupported value for Color.set");const c=new $(a,n);return r?(this._rgb=c._rgb,this):c}throw new Error(`unknown channel ${o} in mode ${n}`)}else return a},$.prototype.tint=function(e=.5,...t){return ct(this,"white",e,...t)},$.prototype.shade=function(e=.5,...t){return ct(this,"black",e,...t)};const w0=(e,t,r)=>{const n=e._rgb,o=t._rgb;return new $(n[0]+r*(o[0]-n[0]),n[1]+r*(o[1]-n[1]),n[2]+r*(o[2]-n[2]),"rgb")};re.rgb=w0;const{sqrt:lr,pow:Ve}=Math,k0=(e,t,r)=>{const[n,o,a]=e._rgb,[s,c,i]=t._rgb;return new $(lr(Ve(n,2)*(1-r)+Ve(s,2)*r),lr(Ve(o,2)*(1-r)+Ve(c,2)*r),lr(Ve(a,2)*(1-r)+Ve(i,2)*r),"rgb")};re.lrgb=k0;const $0=(e,t,r)=>{const n=e.lab(),o=t.lab();return new $(n[0]+r*(o[0]-n[0]),n[1]+r*(o[1]-n[1]),n[2]+r*(o[2]-n[2]),"lab")};re.lab=$0;const Ye=(e,t,r,n)=>{let o,a;n==="hsl"?(o=e.hsl(),a=t.hsl()):n==="hsv"?(o=e.hsv(),a=t.hsv()):n==="hcg"?(o=e.hcg(),a=t.hcg()):n==="hsi"?(o=e.hsi(),a=t.hsi()):n==="lch"||n==="hcl"?(n="hcl",o=e.hcl(),a=t.hcl()):n==="oklch"&&(o=e.oklch().reverse(),a=t.oklch().reverse());let s,c,i,u,l,f;(n.substr(0,1)==="h"||n==="oklch")&&([s,i,l]=o,[c,u,f]=a);let h,d,b,_;return!isNaN(s)&&!isNaN(c)?(c>s&&c-s>180?_=c-(s+360):c180?_=c+360-s:_=c-s,d=s+r*_):isNaN(s)?isNaN(c)?d=Number.NaN:(d=c,(l==1||l==0)&&n!="hsv"&&(h=u)):(d=s,(f==1||f==0)&&n!="hsv"&&(h=i)),h===void 0&&(h=i+r*(u-i)),b=l+r*(f-l),n==="oklch"?new $([b,h,d],n):new $([d,h,b],n)},No=(e,t,r)=>Ye(e,t,r,"lch");re.lch=No,re.hcl=No;const C0=(e,t,r)=>{const n=e.num(),o=t.num();return new $(n+r*(o-n),"num")};re.num=C0;const x0=(e,t,r)=>Ye(e,t,r,"hcg");re.hcg=x0;const R0=(e,t,r)=>Ye(e,t,r,"hsi");re.hsi=R0;const H0=(e,t,r)=>Ye(e,t,r,"hsl");re.hsl=H0;const q0=(e,t,r)=>Ye(e,t,r,"hsv");re.hsv=q0;const M0=(e,t,r)=>{const n=e.oklab(),o=t.oklab();return new $(n[0]+r*(o[0]-n[0]),n[1]+r*(o[1]-n[1]),n[2]+r*(o[2]-n[2]),"oklab")};re.oklab=M0;const O0=(e,t,r)=>Ye(e,t,r,"oklch");re.oklch=O0;const{pow:hr,sqrt:dr,PI:br,cos:Ao,sin:Lo,atan2:N0}=Math,A0=(e,t="lrgb",r=null)=>{const n=e.length;r||(r=Array.from(new Array(n)).map(()=>1));const o=n/r.reduce(function(f,h){return f+h});if(r.forEach((f,h)=>{r[h]*=o}),e=e.map(f=>new $(f)),t==="lrgb")return L0(e,r);const a=e.shift(),s=a.get(t),c=[];let i=0,u=0;for(let f=0;f{const d=f.get(t);l+=f.alpha()*r[h+1];for(let b=0;b=360;)h-=360;s[f]=h}else s[f]=s[f]/c[f];return l/=n,new $(s,t).alpha(l>.99999?1:l,!0)},L0=(e,t)=>{const r=e.length,n=[0,0,0,0];for(let o=0;o.9999999&&(n[3]=1),new $(Yt(n))},{pow:E0}=Math;function yt(e){let t="rgb",r=O("#ccc"),n=0,o=[0,1],a=[],s=[0,0],c=!1,i=[],u=!1,l=0,f=1,h=!1,d={},b=!0,_=1;const g=function(m){if(m=m||["#fff","#000"],m&&P(m)==="string"&&O.brewer&&O.brewer[m.toLowerCase()]&&(m=O.brewer[m.toLowerCase()]),P(m)==="array"){m.length===1&&(m=[m[0],m[0]]),m=m.slice(0);for(let p=0;p=c[y];)y++;return y-1}return 0};let H=m=>m,x=m=>m;const N=function(m,p){let y,w;if(p==null&&(p=!1),isNaN(m)||m===null)return r;p?w=m:c&&c.length>2?w=v(m)/(c.length-2):f!==l?w=(m-l)/(f-l):w=1,w=x(w),p||(w=H(w)),_!==1&&(w=E0(w,_)),w=s[0]+w*(1-s[0]-s[1]),w=Xe(w,0,1);const C=Math.floor(w*1e4);if(b&&d[C])y=d[C];else{if(P(i)==="array")for(let q=0;q=M&&q===a.length-1){y=i[q];break}if(w>M&&wd={};g(e);const R=function(m){const p=O(N(m));return u&&p[u]?p[u]():p};return R.classes=function(m){if(m!=null){if(P(m)==="array")c=m,o=[m[0],m[m.length-1]];else{const p=O.analyze(o);m===0?c=[p.min,p.max]:c=O.limits(p,"e",m)}return R}return c},R.domain=function(m){if(!arguments.length)return o;l=m[0],f=m[m.length-1],a=[];const p=i.length;if(m.length===p&&l!==f)for(let y of Array.from(m))a.push((y-l)/(f-l));else{for(let y=0;y2){const y=m.map((C,q)=>q/(m.length-1)),w=m.map(C=>(C-l)/(f-l));w.every((C,q)=>y[q]===C)||(x=C=>{if(C<=0||C>=1)return C;let q=0;for(;C>=w[q+1];)q++;const M=(C-w[q])/(w[q+1]-w[q]);return y[q]+M*(y[q+1]-y[q])})}}return o=[l,f],R},R.mode=function(m){return arguments.length?(t=m,A(),R):t},R.range=function(m,p){return g(m),R},R.out=function(m){return u=m,R},R.spread=function(m){return arguments.length?(n=m,R):n},R.correctLightness=function(m){return m==null&&(m=!0),h=m,A(),h?H=function(p){const y=N(0,!0).lab()[0],w=N(1,!0).lab()[0],C=y>w;let q=N(p,!0).lab()[0];const M=y+(w-y)*p;let S=q-M,X=0,D=1,U=20;for(;Math.abs(S)>.01&&U-- >0;)(function(){return C&&(S*=-1),S<0?(X=p,p+=(D-p)*.5):(D=p,p+=(X-p)*.5),q=N(p,!0).lab()[0],S=q-M})();return p}:H=p=>p,R},R.padding=function(m){return m!=null?(P(m)==="number"&&(m=[m,m]),s=m,R):s},R.colors=function(m,p){arguments.length<2&&(p="hex");let y=[];if(arguments.length===0)y=i.slice(0);else if(m===1)y=[R(.5)];else if(m>1){const w=o[0],C=o[1]-w;y=T0(0,m).map(q=>R(w+q/(m-1)*C))}else{e=[];let w=[];if(c&&c.length>2)for(let C=1,q=c.length,M=1<=q;M?Cq;M?C++:C--)w.push((c[C-1]+c[C])*.5);else w=o;y=w.map(C=>R(C))}return O[p]&&(y=y.map(w=>w[p]())),y},R.cache=function(m){return m!=null?(b=m,R):b},R.gamma=function(m){return m!=null?(_=m,R):_},R.nodata=function(m){return m!=null?(r=O(m),R):r},R}function T0(e,t,r){let n=[],o=ea;o?s++:s--)n.push(s);return n}const S0=function(e){let t=[1,1];for(let r=1;rnew $(a)),e.length===2)[r,n]=e.map(a=>a.lab()),t=function(a){const s=[0,1,2].map(c=>r[c]+a*(n[c]-r[c]));return new $(s,"lab")};else if(e.length===3)[r,n,o]=e.map(a=>a.lab()),t=function(a){const s=[0,1,2].map(c=>(1-a)*(1-a)*r[c]+2*(1-a)*a*n[c]+a*a*o[c]);return new $(s,"lab")};else if(e.length===4){let a;[r,n,o,a]=e.map(s=>s.lab()),t=function(s){const c=[0,1,2].map(i=>(1-s)*(1-s)*(1-s)*r[i]+3*(1-s)*(1-s)*s*n[i]+3*(1-s)*s*s*o[i]+s*s*s*a[i]);return new $(c,"lab")}}else if(e.length>=5){let a,s,c;a=e.map(i=>i.lab()),c=e.length-1,s=S0(c),t=function(i){const u=1-i,l=[0,1,2].map(f=>a.reduce((h,d,b)=>h+s[b]*u**(c-b)*i**b*d[f],0));return new $(l,"lab")}}else throw new RangeError("No point in running bezier with only one color.");return t},j0=e=>{const t=P0(e);return t.scale=()=>yt(t),t},de=(e,t,r)=>{if(!de[r])throw new Error("unknown blend mode "+r);return de[r](e,t)},Ne=e=>(t,r)=>{const n=O(r).rgb(),o=O(t).rgb();return O.rgb(e(n,o))},Ae=e=>(t,r)=>{const n=[];return n[0]=e(t[0],r[0]),n[1]=e(t[1],r[1]),n[2]=e(t[2],r[2]),n},B0=e=>e,G0=(e,t)=>e*t/255,I0=(e,t)=>e>t?t:e,z0=(e,t)=>e>t?e:t,F0=(e,t)=>255*(1-(1-e/255)*(1-t/255)),X0=(e,t)=>t<128?2*e*t/255:255*(1-2*(1-e/255)*(1-t/255)),K0=(e,t)=>255*(1-(1-t/255)/(e/255)),D0=(e,t)=>e===255?255:(e=255*(t/255)/(1-e/255),e>255?255:e);de.normal=Ne(Ae(B0)),de.multiply=Ne(Ae(G0)),de.screen=Ne(Ae(F0)),de.overlay=Ne(Ae(X0)),de.darken=Ne(Ae(I0)),de.lighten=Ne(Ae(z0)),de.dodge=Ne(Ae(D0)),de.burn=Ne(Ae(K0));const{pow:V0,sin:Y0,cos:Z0}=Math;function J0(e=300,t=-1.5,r=1,n=1,o=[0,1]){let a=0,s;P(o)==="array"?s=o[1]-o[0]:(s=0,o=[o,o]);const c=function(i){const u=we*((e+120)/360+t*i),l=V0(o[0]+s*i,n),h=(a!==0?r[0]+i*a:r)*l*(1-l)/2,d=Z0(u),b=Y0(u),_=l+h*(-.14861*d+1.78277*b),g=l+h*(-.29227*d-.90649*b),v=l+h*(1.97294*d);return O(Yt([_*255,g*255,v*255,1]))};return c.start=function(i){return i==null?e:(e=i,c)},c.rotations=function(i){return i==null?t:(t=i,c)},c.gamma=function(i){return i==null?n:(n=i,c)},c.hue=function(i){return i==null?r:(r=i,P(r)==="array"?(a=r[1]-r[0],a===0&&(r=r[1])):a=0,c)},c.lightness=function(i){return i==null?o:(P(i)==="array"?(o=i,s=i[1]-i[0]):(o=[i,i],s=0),c)},c.scale=()=>O.scale(c),c.hue(r),c}const W0="0123456789abcdef",{floor:U0,random:Q0}=Math,ei=()=>{let e="#";for(let t=0;t<6;t++)e+=W0.charAt(U0(Q0()*16));return new $(e,"hex")},{log:Eo,pow:ti,floor:ri,abs:ni}=Math;function To(e,t=null){const r={min:Number.MAX_VALUE,max:Number.MAX_VALUE*-1,sum:0,values:[],count:0};return P(e)==="object"&&(e=Object.values(e)),e.forEach(n=>{t&&P(n)==="object"&&(n=n[t]),n!=null&&!isNaN(n)&&(r.values.push(n),r.sum+=n,nr.max&&(r.max=n),r.count+=1)}),r.domain=[r.min,r.max],r.limits=(n,o)=>So(r,n,o),r}function So(e,t="equal",r=7){P(e)=="array"&&(e=To(e));const{min:n,max:o}=e,a=e.values.sort((c,i)=>c-i);if(r===1)return[n,o];const s=[];if(t.substr(0,1)==="c"&&(s.push(n),s.push(o)),t.substr(0,1)==="e"){s.push(n);for(let c=1;c 0");const c=Math.LOG10E*Eo(n),i=Math.LOG10E*Eo(o);s.push(n);for(let u=1;u200&&(f=!1)}const b={};for(let g=0;gg-v),s.push(_[0]);for(let g=1;g<_.length;g+=2){const v=_[g];!isNaN(v)&&s.indexOf(v)===-1&&s.push(v)}}return s}const oi=(e,t)=>{e=new $(e),t=new $(t);const r=e.luminance(),n=t.luminance();return r>n?(r+.05)/(n+.05):(n+.05)/(r+.05)},{sqrt:ke,pow:V,min:si,max:ai,atan2:Po,abs:jo,cos:wt,sin:Bo,exp:ci,PI:Go}=Math;function ii(e,t,r=1,n=1,o=1){var a=function(he){return 360*he/(2*Go)},s=function(he){return 2*Go*he/360};e=new $(e),t=new $(t);const[c,i,u]=Array.from(e.lab()),[l,f,h]=Array.from(t.lab()),d=(c+l)/2,b=ke(V(i,2)+V(u,2)),_=ke(V(f,2)+V(h,2)),g=(b+_)/2,v=.5*(1-ke(V(g,7)/(V(g,7)+V(25,7)))),H=i*(1+v),x=f*(1+v),N=ke(V(H,2)+V(u,2)),A=ke(V(x,2)+V(h,2)),R=(N+A)/2,m=a(Po(u,H)),p=a(Po(h,x)),y=m>=0?m:m+360,w=p>=0?p:p+360,C=jo(y-w)>180?(y+w+360)/2:(y+w)/2,q=1-.17*wt(s(C-30))+.24*wt(s(2*C))+.32*wt(s(3*C+6))-.2*wt(s(4*C-63));let M=w-y;M=jo(M)<=180?M:w<=y?M+360:M-360,M=2*ke(N*A)*Bo(s(M)/2);const S=l-c,X=A-N,D=1+.015*V(d-50,2)/ke(20+V(d-50,2)),U=1+.045*R,ce=1+.015*R*q,ye=30*ci(-V((C-275)/25,2)),le=-(2*ke(V(R,7)/(V(R,7)+V(25,7))))*Bo(2*s(ye)),qe=ke(V(S/(r*D),2)+V(X/(n*U),2)+V(M/(o*ce),2)+le*(X/(n*U))*(M/(o*ce)));return ai(0,si(100,qe))}function ui(e,t,r="lab"){e=new $(e),t=new $(t);const n=e.get(r),o=t.get(r);let a=0;for(let s in n){const c=(n[s]||0)-(o[s]||0);a+=c*c}return Math.sqrt(a)}const fi=(...e)=>{try{return new $(...e),!0}catch{return!1}},li={cool(){return yt([O.hsl(180,1,.9),O.hsl(250,.7,.4)])},hot(){return yt(["#000","#f00","#ff0","#fff"]).mode("rgb")}},kt={OrRd:["#fff7ec","#fee8c8","#fdd49e","#fdbb84","#fc8d59","#ef6548","#d7301f","#b30000","#7f0000"],PuBu:["#fff7fb","#ece7f2","#d0d1e6","#a6bddb","#74a9cf","#3690c0","#0570b0","#045a8d","#023858"],BuPu:["#f7fcfd","#e0ecf4","#bfd3e6","#9ebcda","#8c96c6","#8c6bb1","#88419d","#810f7c","#4d004b"],Oranges:["#fff5eb","#fee6ce","#fdd0a2","#fdae6b","#fd8d3c","#f16913","#d94801","#a63603","#7f2704"],BuGn:["#f7fcfd","#e5f5f9","#ccece6","#99d8c9","#66c2a4","#41ae76","#238b45","#006d2c","#00441b"],YlOrBr:["#ffffe5","#fff7bc","#fee391","#fec44f","#fe9929","#ec7014","#cc4c02","#993404","#662506"],YlGn:["#ffffe5","#f7fcb9","#d9f0a3","#addd8e","#78c679","#41ab5d","#238443","#006837","#004529"],Reds:["#fff5f0","#fee0d2","#fcbba1","#fc9272","#fb6a4a","#ef3b2c","#cb181d","#a50f15","#67000d"],RdPu:["#fff7f3","#fde0dd","#fcc5c0","#fa9fb5","#f768a1","#dd3497","#ae017e","#7a0177","#49006a"],Greens:["#f7fcf5","#e5f5e0","#c7e9c0","#a1d99b","#74c476","#41ab5d","#238b45","#006d2c","#00441b"],YlGnBu:["#ffffd9","#edf8b1","#c7e9b4","#7fcdbb","#41b6c4","#1d91c0","#225ea8","#253494","#081d58"],Purples:["#fcfbfd","#efedf5","#dadaeb","#bcbddc","#9e9ac8","#807dba","#6a51a3","#54278f","#3f007d"],GnBu:["#f7fcf0","#e0f3db","#ccebc5","#a8ddb5","#7bccc4","#4eb3d3","#2b8cbe","#0868ac","#084081"],Greys:["#ffffff","#f0f0f0","#d9d9d9","#bdbdbd","#969696","#737373","#525252","#252525","#000000"],YlOrRd:["#ffffcc","#ffeda0","#fed976","#feb24c","#fd8d3c","#fc4e2a","#e31a1c","#bd0026","#800026"],PuRd:["#f7f4f9","#e7e1ef","#d4b9da","#c994c7","#df65b0","#e7298a","#ce1256","#980043","#67001f"],Blues:["#f7fbff","#deebf7","#c6dbef","#9ecae1","#6baed6","#4292c6","#2171b5","#08519c","#08306b"],PuBuGn:["#fff7fb","#ece2f0","#d0d1e6","#a6bddb","#67a9cf","#3690c0","#02818a","#016c59","#014636"],Viridis:["#440154","#482777","#3f4a8a","#31678e","#26838f","#1f9d8a","#6cce5a","#b6de2b","#fee825"],Spectral:["#9e0142","#d53e4f","#f46d43","#fdae61","#fee08b","#ffffbf","#e6f598","#abdda4","#66c2a5","#3288bd","#5e4fa2"],RdYlGn:["#a50026","#d73027","#f46d43","#fdae61","#fee08b","#ffffbf","#d9ef8b","#a6d96a","#66bd63","#1a9850","#006837"],RdBu:["#67001f","#b2182b","#d6604d","#f4a582","#fddbc7","#f7f7f7","#d1e5f0","#92c5de","#4393c3","#2166ac","#053061"],PiYG:["#8e0152","#c51b7d","#de77ae","#f1b6da","#fde0ef","#f7f7f7","#e6f5d0","#b8e186","#7fbc41","#4d9221","#276419"],PRGn:["#40004b","#762a83","#9970ab","#c2a5cf","#e7d4e8","#f7f7f7","#d9f0d3","#a6dba0","#5aae61","#1b7837","#00441b"],RdYlBu:["#a50026","#d73027","#f46d43","#fdae61","#fee090","#ffffbf","#e0f3f8","#abd9e9","#74add1","#4575b4","#313695"],BrBG:["#543005","#8c510a","#bf812d","#dfc27d","#f6e8c3","#f5f5f5","#c7eae5","#80cdc1","#35978f","#01665e","#003c30"],RdGy:["#67001f","#b2182b","#d6604d","#f4a582","#fddbc7","#ffffff","#e0e0e0","#bababa","#878787","#4d4d4d","#1a1a1a"],PuOr:["#7f3b08","#b35806","#e08214","#fdb863","#fee0b6","#f7f7f7","#d8daeb","#b2abd2","#8073ac","#542788","#2d004b"],Set2:["#66c2a5","#fc8d62","#8da0cb","#e78ac3","#a6d854","#ffd92f","#e5c494","#b3b3b3"],Accent:["#7fc97f","#beaed4","#fdc086","#ffff99","#386cb0","#f0027f","#bf5b17","#666666"],Set1:["#e41a1c","#377eb8","#4daf4a","#984ea3","#ff7f00","#ffff33","#a65628","#f781bf","#999999"],Set3:["#8dd3c7","#ffffb3","#bebada","#fb8072","#80b1d3","#fdb462","#b3de69","#fccde5","#d9d9d9","#bc80bd","#ccebc5","#ffed6f"],Dark2:["#1b9e77","#d95f02","#7570b3","#e7298a","#66a61e","#e6ab02","#a6761d","#666666"],Paired:["#a6cee3","#1f78b4","#b2df8a","#33a02c","#fb9a99","#e31a1c","#fdbf6f","#ff7f00","#cab2d6","#6a3d9a","#ffff99","#b15928"],Pastel2:["#b3e2cd","#fdcdac","#cbd5e8","#f4cae4","#e6f5c9","#fff2ae","#f1e2cc","#cccccc"],Pastel1:["#fbb4ae","#b3cde3","#ccebc5","#decbe4","#fed9a6","#ffffcc","#e5d8bd","#fddaec","#f2f2f2"]};for(let e of Object.keys(kt))kt[e.toLowerCase()]=kt[e];Object.assign(O,{average:A0,bezier:j0,blend:de,cubehelix:J0,mix:ct,interpolate:ct,random:ei,scale:yt,analyze:To,contrast:oi,deltaE:ii,distance:ui,limits:So,valid:fi,scales:li,input:L,colors:De,brewer:kt});function pr(e){return e&&e.__esModule&&Object.prototype.hasOwnProperty.call(e,"default")?e.default:e}var mr,Io;function hi(){if(Io)return mr;Io=1;var e=e||{};e.Geometry=function(){},e.Geometry.intersectLineLine=function(r,n){var o=(r.intercept-n.intercept)/(n.slope-r.slope),a=r.slope*o+r.intercept;return{x:o,y:a}},e.Geometry.distanceFromOrigin=function(r){return Math.sqrt(Math.pow(r.x,2)+Math.pow(r.y,2))},e.Geometry.distanceLineFromOrigin=function(r){return Math.abs(r.intercept)/Math.sqrt(Math.pow(r.slope,2)+1)},e.Geometry.perpendicularThroughPoint=function(r,n){var o=-1/r.slope,a=n.y-o*n.x;return{slope:o,intercept:a}},e.Geometry.angleFromOrigin=function(r){return Math.atan2(r.y,r.x)},e.Geometry.normalizeAngle=function(r){var n=2*Math.PI;return(r%n+n)%n},e.Geometry.lengthOfRayUntilIntersect=function(r,n){return n.intercept/(Math.sin(r)-n.slope*Math.cos(r))},e.Hsluv=function(){},e.Hsluv.getBounds=function(r){for(var n=[],o=Math.pow(r+16,3)/1560896,a=o>e.Hsluv.epsilon?o:r/e.Hsluv.kappa,s=0;s<3;)for(var c=s++,i=e.Hsluv.m[c][0],u=e.Hsluv.m[c][1],l=e.Hsluv.m[c][2],f=0;f<2;){var h=f++,d=(284517*i-94839*l)*a,b=(838422*l+769860*u+731718*i)*r*a-769860*h*r,_=(632260*l-126452*u)*a+126452*h;n.push({slope:d/_,intercept:b/_})}return n},e.Hsluv.maxSafeChromaForL=function(r){for(var n=e.Hsluv.getBounds(r),o=1/0,a=0;a=0&&(s=Math.min(s,u))}return s},e.Hsluv.dotProduct=function(r,n){for(var o=0,a=0,s=r.length;a.04045?Math.pow((r+.055)/1.055,2.4):r/12.92},e.Hsluv.xyzToRgb=function(r){return[e.Hsluv.fromLinear(e.Hsluv.dotProduct(e.Hsluv.m[0],r)),e.Hsluv.fromLinear(e.Hsluv.dotProduct(e.Hsluv.m[1],r)),e.Hsluv.fromLinear(e.Hsluv.dotProduct(e.Hsluv.m[2],r))]},e.Hsluv.rgbToXyz=function(r){var n=[e.Hsluv.toLinear(r[0]),e.Hsluv.toLinear(r[1]),e.Hsluv.toLinear(r[2])];return[e.Hsluv.dotProduct(e.Hsluv.minv[0],n),e.Hsluv.dotProduct(e.Hsluv.minv[1],n),e.Hsluv.dotProduct(e.Hsluv.minv[2],n)]},e.Hsluv.yToL=function(r){return r<=e.Hsluv.epsilon?r/e.Hsluv.refY*e.Hsluv.kappa:116*Math.pow(r/e.Hsluv.refY,.3333333333333333)-16},e.Hsluv.lToY=function(r){return r<=8?e.Hsluv.refY*r/e.Hsluv.kappa:e.Hsluv.refY*Math.pow((r+16)/116,3)},e.Hsluv.xyzToLuv=function(r){var n=r[0],o=r[1],a=r[2],s=n+15*o+3*a,c=4*n,i=9*o;s!=0?(c/=s,i/=s):(c=NaN,i=NaN);var u=e.Hsluv.yToL(o);if(u==0)return[0,0,0];var l=13*u*(c-e.Hsluv.refU),f=13*u*(i-e.Hsluv.refV);return[u,l,f]},e.Hsluv.luvToXyz=function(r){var n=r[0],o=r[1],a=r[2];if(n==0)return[0,0,0];var s=o/(13*n)+e.Hsluv.refU,c=a/(13*n)+e.Hsluv.refV,i=e.Hsluv.lToY(n),u=0-9*i*s/((s-4)*c-s*c),l=(9*i-15*c*i-c*u)/(3*c);return[u,i,l]},e.Hsluv.luvToLch=function(r){var n=r[0],o=r[1],a=r[2],s=Math.sqrt(o*o+a*a),c;if(s<1e-8)c=0;else{var i=Math.atan2(a,o);c=i*180/Math.PI,c<0&&(c=360+c)}return[n,s,c]},e.Hsluv.lchToLuv=function(r){var n=r[0],o=r[1],a=r[2],s=a/360*2*Math.PI,c=Math.cos(s)*o,i=Math.sin(s)*o;return[n,c,i]},e.Hsluv.hsluvToLch=function(r){var n=r[0],o=r[1],a=r[2];if(a>99.9999999)return[100,0,n];if(a<1e-8)return[0,0,n];var s=e.Hsluv.maxChromaForLH(a,n),c=s/100*o;return[a,c,n]},e.Hsluv.lchToHsluv=function(r){var n=r[0],o=r[1],a=r[2];if(n>99.9999999)return[a,0,100];if(n<1e-8)return[a,0,0];var s=e.Hsluv.maxChromaForLH(n,a),c=o/s*100;return[a,c,n]},e.Hsluv.hpluvToLch=function(r){var n=r[0],o=r[1],a=r[2];if(a>99.9999999)return[100,0,n];if(a<1e-8)return[0,0,n];var s=e.Hsluv.maxSafeChromaForL(a),c=s/100*o;return[a,c,n]},e.Hsluv.lchToHpluv=function(r){var n=r[0],o=r[1],a=r[2];if(n>99.9999999)return[a,0,100];if(n<1e-8)return[a,0,0];var s=e.Hsluv.maxSafeChromaForL(n),c=o/s*100;return[a,c,n]},e.Hsluv.rgbToHex=function(r){for(var n="#",o=0;o<3;){var a=o++,s=r[a],c=Math.round(s*255),i=c%16,u=(c-i)/16|0;n+=e.Hsluv.hexChars.charAt(u)+e.Hsluv.hexChars.charAt(i)}return n},e.Hsluv.hexToRgb=function(r){r=r.toLowerCase();for(var n=[],o=0;o<3;){var a=o++,s=e.Hsluv.hexChars.indexOf(r.charAt(a*2+1)),c=e.Hsluv.hexChars.indexOf(r.charAt(a*2+2)),i=s*16+c;n.push(i/255)}return n},e.Hsluv.lchToRgb=function(r){return e.Hsluv.xyzToRgb(e.Hsluv.luvToXyz(e.Hsluv.lchToLuv(r)))},e.Hsluv.rgbToLch=function(r){return e.Hsluv.luvToLch(e.Hsluv.xyzToLuv(e.Hsluv.rgbToXyz(r)))},e.Hsluv.hsluvToRgb=function(r){return e.Hsluv.lchToRgb(e.Hsluv.hsluvToLch(r))},e.Hsluv.rgbToHsluv=function(r){return e.Hsluv.lchToHsluv(e.Hsluv.rgbToLch(r))},e.Hsluv.hpluvToRgb=function(r){return e.Hsluv.lchToRgb(e.Hsluv.hpluvToLch(r))},e.Hsluv.rgbToHpluv=function(r){return e.Hsluv.lchToHpluv(e.Hsluv.rgbToLch(r))},e.Hsluv.hsluvToHex=function(r){return e.Hsluv.rgbToHex(e.Hsluv.hsluvToRgb(r))},e.Hsluv.hpluvToHex=function(r){return e.Hsluv.rgbToHex(e.Hsluv.hpluvToRgb(r))},e.Hsluv.hexToHsluv=function(r){return e.Hsluv.rgbToHsluv(e.Hsluv.hexToRgb(r))},e.Hsluv.hexToHpluv=function(r){return e.Hsluv.rgbToHpluv(e.Hsluv.hexToRgb(r))},e.Hsluv.m=[[3.240969941904521,-1.537383177570093,-.498610760293],[-.96924363628087,1.87596750150772,.041555057407175],[.055630079696993,-.20397695888897,1.056971514242878]],e.Hsluv.minv=[[.41239079926595,.35758433938387,.18048078840183],[.21263900587151,.71516867876775,.072192315360733],[.019330818715591,.11919477979462,.95053215224966]],e.Hsluv.refY=1,e.Hsluv.refU=.19783000664283,e.Hsluv.refV=.46831999493879,e.Hsluv.kappa=903.2962962,e.Hsluv.epsilon=.0088564516,e.Hsluv.hexChars="0123456789abcdef";var t={hsluvToRgb:e.Hsluv.hsluvToRgb,rgbToHsluv:e.Hsluv.rgbToHsluv,hpluvToRgb:e.Hsluv.hpluvToRgb,rgbToHpluv:e.Hsluv.rgbToHpluv,hsluvToHex:e.Hsluv.hsluvToHex,hexToHsluv:e.Hsluv.hexToHsluv,hpluvToHex:e.Hsluv.hpluvToHex,hexToHpluv:e.Hsluv.hexToHpluv,lchToHpluv:e.Hsluv.lchToHpluv,hpluvToLch:e.Hsluv.hpluvToLch,lchToHsluv:e.Hsluv.lchToHsluv,hsluvToLch:e.Hsluv.hsluvToLch,lchToLuv:e.Hsluv.lchToLuv,luvToLch:e.Hsluv.luvToLch,xyzToLuv:e.Hsluv.xyzToLuv,luvToXyz:e.Hsluv.luvToXyz,xyzToRgb:e.Hsluv.xyzToRgb,rgbToXyz:e.Hsluv.rgbToXyz,lchToRgb:e.Hsluv.lchToRgb,rgbToLch:e.Hsluv.rgbToLch};return mr=t,mr}var di=hi();const gr=pr(di);var $t={exports:{}},vr,zo;function it(){if(zo)return vr;zo=1;function e(t,r){return Object.prototype.hasOwnProperty.call(t,r)}return vr=e,vr}var _r,Fo;function yr(){if(Fo)return _r;Fo=1;var e=it(),t,r;function n(){r=["toString","toLocaleString","valueOf","hasOwnProperty","isPrototypeOf","propertyIsEnumerable","constructor"],t=!0;for(var s in{toString:null})t=!1}function o(s,c,i){var u,l=0;t==null&&n();for(u in s)if(a(c,s,u,i)===!1)break;if(t)for(var f=s.constructor,h=!!f&&s===f.prototype;(u=r[l++])&&!((u!=="constructor"||!h&&e(s,u))&&s[u]!==Object.prototype[u]&&a(c,s,u,i)===!1););}function a(s,c,i,u){return s.call(u,c[i],i,c)}return _r=o,_r}var wr,Xo;function Ko(){if(Xo)return wr;Xo=1;var e=yr();function t(r){var n=[];return e(r,function(o,a){typeof o=="function"&&n.push(a)}),n.sort()}return wr=t,wr}var kr,Do;function ut(){if(Do)return kr;Do=1;function e(t,r,n){var o=t.length;r==null?r=0:r<0?r=Math.max(o+r,0):r=Math.min(r,o),n==null?n=o:n<0?n=Math.max(o+n,0):n=Math.min(n,o);for(var a=[];r1?n(arguments,1):e(a);r(c,function(i){a[i]=t(a[i],a)})}return Rr=o,Rr}var Hr,Jo;function Q(){if(Jo)return Hr;Jo=1;var e=it(),t=yr();function r(n,o,a){t(n,function(s,c){if(e(n,c))return o.call(a,n[c],c,n)})}return Hr=r,Hr}var qr,Wo;function mi(){if(Wo)return qr;Wo=1;function e(t){return t}return qr=e,qr}var Mr,Uo;function Qo(){if(Uo)return Mr;Uo=1;function e(t){return function(r){return r[t]}}return Mr=e,Mr}var Or,es;function Nr(){if(es)return Or;es=1;var e=/^\[object (.*)\]$/,t=Object.prototype.toString,r;function n(o){return o===null?"Null":o===r?"Undefined":e.exec(t.call(o))[1]}return Or=n,Or}var Ar,ts;function Lr(){if(ts)return Ar;ts=1;var e=Nr();function t(r,n){return e(r)===n}return Ar=t,Ar}var Er,rs;function gi(){if(rs)return Er;rs=1;var e=Lr(),t=Array.isArray||function(r){return e(r,"Array")};return Er=t,Er}var Tr,ns;function os(){if(ns)return Tr;ns=1;var e=Q(),t=gi();function r(s,c){for(var i=-1,u=s.length;++is&&(s=i,a=c);return a}return rn=t,rn}var nn,Ns;function on(){if(Ns)return nn;Ns=1;var e=Q();function t(r){var n=[];return e(r,function(o,a){n.push(o)}),n}return nn=t,nn}var sn,As;function Mi(){if(As)return sn;As=1;var e=qi(),t=on();function r(n,o){return e(t(n),o)}return sn=r,sn}var an,Ls;function Es(){if(Ls)return an;Ls=1;var e=Q();function t(n,o){for(var a=0,s=arguments.length,c;++a2;if(!t(n)&&!c)throw new Error("reduce of empty object with no initial value");return e(n,function(i,u,l){c?a=o.call(s,a,i,u,l):(a=i,c=!0)}),a}return yn=r,yn}var wn,Js;function Ii(){if(Js)return wn;Js=1;var e=_s(),t=Le();function r(n,o,a){return o=t(o,a),e(n,function(s,c,i){return!o(s,c,i)},a)}return wn=r,wn}var kn,Ws;function zi(){if(Ws)return kn;Ws=1;var e=Lr();function t(r){return e(r,"Function")}return kn=t,kn}var $n,Us;function Fi(){if(Us)return $n;Us=1;var e=zi();function t(r,n){var o=r[n];if(o!==void 0)return e(o)?o.call(r):o}return $n=t,$n}var Cn,Qs;function Xi(){if(Qs)return Cn;Qs=1;var e=Is();function t(r,n,o){var a=/^(.+)\.(.+)$/.exec(n);a?e(r,a[1])[a[2]]=o:r[n]=o}return Cn=t,Cn}var xn,ea;function Ki(){if(ea)return xn;ea=1;var e=xs();function t(r,n){if(e(r,n)){for(var o=n.split("."),a=o.pop();n=o.shift();)r=r[n];return delete r[a]}else return!0}return xn=t,xn}var Rn,ta;function Hn(){return ta||(ta=1,Rn={bindAll:pi(),contains:vi(),deepFillIn:_i(),deepMatches:os(),deepMixIn:yi(),equals:ki(),every:hs(),fillIn:$i(),filter:_s(),find:Ci(),flatten:xi(),forIn:yr(),forOwn:Q(),functions:Ko(),get:$s(),has:xs(),hasOwn:it(),keys:Ri(),map:qs(),matches:Hi(),max:Mi(),merge:Ai(),min:Ei(),mixIn:Es(),namespace:Is(),omit:Pi(),pick:ji(),pluck:Bi(),reduce:Gi(),reject:Ii(),result:Fi(),set:Xi(),size:Ys(),some:jr(),unset:Ki(),values:on()}),Rn}var ra;function na(){return ra||(ra=1,(function(e,t){Object.defineProperty(t,"__esModule",{value:!0});var r=Hn(),n={A:{x:.44758,y:.40745},C:{x:.31006,y:.31616},D50:{x:.34567,y:.35851},D65:{x:.31272,y:.32903},D55:{x:.33243,y:.34744},D75:{x:.29903,y:.31488}},o=(0,r.map)(n,function(a){var s=100*(a.x/a.y),c=100,i=100*(1-a.x-a.y)/a.y;return[s,c,i]});t.default=o,e.exports=t.default})($t,$t.exports)),$t.exports}var Ct={exports:{}},oa;function sa(){return oa||(oa=1,(function(e,t){Object.defineProperty(t,"__esModule",{value:!0});var r=Math,n=r.pow,o=r.sign,a=r.abs,s={decode:function(f){return f<=.04045?f/12.92:n((f+.055)/1.055,2.4)},encode:function(f){return f<=.0031308?12.92*f:1.055*n(f,1/2.4)-.055}},c={encode:function(f){return f<.001953125?16*f:n(f,1/1.8)},decode:function(f){return f<16*.001953125?f/16:n(f,1.8)}};function i(l){return{decode:function(h){return o(h)*n(a(h),l)},encode:function(h){return o(h)*n(a(h),1/l)}}}var u={sRGB:{r:{x:.64,y:.33},g:{x:.3,y:.6},b:{x:.15,y:.06},gamma:s},"Adobe RGB":{r:{x:.64,y:.33},g:{x:.21,y:.71},b:{x:.15,y:.06},gamma:i(2.2)},"Wide Gamut RGB":{r:{x:.7347,y:.2653},g:{x:.1152,y:.8264},b:{x:.1566,y:.0177},gamma:i(563/256)},"ProPhoto RGB":{r:{x:.7347,y:.2653},g:{x:.1596,y:.8404},b:{x:.0366,y:1e-4},gamma:c}};t.default=u,e.exports=t.default})(Ct,Ct.exports)),Ct.exports}var $e={},aa;function ca(){if(aa)return $e;aa=1,Object.defineProperty($e,"__esModule",{value:!0});function e(s){return[[s[0][0],s[1][0],s[2][0]],[s[0][1],s[1][1],s[2][1]],[s[0][2],s[1][2],s[2][2]]]}function t(s){return s[0][0]*(s[2][2]*s[1][1]-s[2][1]*s[1][2])+s[1][0]*(s[2][1]*s[0][2]-s[2][2]*s[0][1])+s[2][0]*(s[1][2]*s[0][1]-s[1][1]*s[0][2])}function r(s){var c=1/t(s);return[[(s[2][2]*s[1][1]-s[2][1]*s[1][2])*c,(s[2][1]*s[0][2]-s[2][2]*s[0][1])*c,(s[1][2]*s[0][1]-s[1][1]*s[0][2])*c],[(s[2][0]*s[1][2]-s[2][2]*s[1][0])*c,(s[2][2]*s[0][0]-s[2][0]*s[0][2])*c,(s[1][0]*s[0][2]-s[1][2]*s[0][0])*c],[(s[2][1]*s[1][0]-s[2][0]*s[1][1])*c,(s[2][0]*s[0][1]-s[2][1]*s[0][0])*c,(s[1][1]*s[0][0]-s[1][0]*s[0][1])*c]]}function n(s,c){return[s[0][0]*c[0]+s[0][1]*c[1]+s[0][2]*c[2],s[1][0]*c[0]+s[1][1]*c[1]+s[1][2]*c[2],s[2][0]*c[0]+s[2][1]*c[1]+s[2][2]*c[2]]}function o(s,c){return[[s[0][0]*c[0],s[0][1]*c[1],s[0][2]*c[2]],[s[1][0]*c[0],s[1][1]*c[1],s[1][2]*c[2]],[s[2][0]*c[0],s[2][1]*c[1],s[2][2]*c[2]]]}function a(s,c){return[[s[0][0]*c[0][0]+s[0][1]*c[1][0]+s[0][2]*c[2][0],s[0][0]*c[0][1]+s[0][1]*c[1][1]+s[0][2]*c[2][1],s[0][0]*c[0][2]+s[0][1]*c[1][2]+s[0][2]*c[2][2]],[s[1][0]*c[0][0]+s[1][1]*c[1][0]+s[1][2]*c[2][0],s[1][0]*c[0][1]+s[1][1]*c[1][1]+s[1][2]*c[2][1],s[1][0]*c[0][2]+s[1][1]*c[1][2]+s[1][2]*c[2][2]],[s[2][0]*c[0][0]+s[2][1]*c[1][0]+s[2][2]*c[2][0],s[2][0]*c[0][1]+s[2][1]*c[1][1]+s[2][2]*c[2][1],s[2][0]*c[0][2]+s[2][1]*c[1][2]+s[2][2]*c[2][2]]]}return $e.transpose=e,$e.determinant=t,$e.inverse=r,$e.multiply=n,$e.scalar=o,$e.product=a,$e}var lt={},ia;function Di(){if(ia)return lt;ia=1,Object.defineProperty(lt,"__esModule",{value:!0});var e=Math,t=e.PI;function r(o){for(var a=o*180/t;a<0;)a+=360;for(;a>360;)a-=360;return a}function n(o){for(var a=t*o/180;a<0;)a+=2*t;for(;a>2*t;)a-=2*t;return a}return lt.fromRadian=r,lt.toRadian=n,lt}var ht={},ua;function Vi(){if(ua)return ht;ua=1,Object.defineProperty(ht,"__esModule",{value:!0});var e=Math,t=e.round;function r(o){return o[0]=="#"&&(o=o.slice(1)),o.length<6&&(o=o.split("").map(function(a){return a+a}).join("")),o.match(/../g).map(function(a){return parseInt(a,16)/255})}function n(o){var a=o.map(function(s){return s=t(255*s).toString(16),s.length<2&&(s="0"+s),s}).join("");return"#"+a}return ht.fromHex=r,ht.toHex=n,ht}var xt={exports:{}},fa;function Yi(){return fa||(fa=1,(function(e,t){Object.defineProperty(t,"__esModule",{value:!0});var r=ca(),n=u(r),o=na(),a=i(o),s=sa(),c=i(s);function i(f){return f&&f.__esModule?f:{default:f}}function u(f){if(f&&f.__esModule)return f;var h={};if(f!=null)for(var d in f)Object.prototype.hasOwnProperty.call(f,d)&&(h[d]=f[d]);return h.default=f,h}function l(){var f=arguments.length<=0||arguments[0]===void 0?c.default.sRGB:arguments[0],h=arguments.length<=1||arguments[1]===void 0?a.default.D65:arguments[1],d=[f.r,f.g,f.b],b=n.transpose(d.map(function(x){var N=x.x/x.y,A=1,R=(1-x.x-x.y)/x.y;return[N,A,R]})),_=f.gamma,g=n.multiply(n.inverse(b),h),v=n.scalar(b,g),H=n.inverse(v);return{fromRgb:function(N){return n.multiply(v,N.map(_.decode))},toRgb:function(N){return n.multiply(H,N).map(_.encode)}}}t.default=l,e.exports=t.default})(xt,xt.exports)),xt.exports}var qn,la;function Rt(){if(la)return qn;la=1;var e=na(),t=sa(),r=ca(),n=Di(),o=Vi(),a=Yi();return qn={illuminant:e,workspace:t,matrix:r,degree:n,rgb:o,xyz:a},qn}var Zi=Rt();const Ht=pr(Zi);var be={},ha;function qt(){if(ha)return be;ha=1,Object.defineProperty(be,"__esModule",{value:!0}),be.cfs=be.distance=be.lerp=be.corLerp=void 0;var e=Hn();function t(h,d,b){return d in h?Object.defineProperty(h,d,{value:b,enumerable:!0,configurable:!0,writable:!0}):h[d]=b,h}function r(h){if(Array.isArray(h)){for(var d=0,b=Array(h.length);dg/2&&(h>d?d+=g:h+=g)}return((1-b)*h+b*d)%(g||1/0)}function u(h,d,b){var _={};for(var g in h)_[g]=i(h[g],d[g],b,g);return _}function l(h,d){var b=0;for(var _ in h)b+=a(h[_]-d[_],2);return s(b)}function f(h){return e.merge.apply(void 0,r(h.split("").map(function(d){return t({},d,!0)})))}return be.corLerp=i,be.lerp=u,be.distance=l,be.cfs=f,be}var Mt={exports:{}},da;function Ji(){return da||(da=1,(function(e,t){var r=(function(){function s(c,i){var u=[],l=!0,f=!1,h=void 0;try{for(var d=c[Symbol.iterator](),b;!(l=(b=d.next()).done)&&(u.push(b.value),!(i&&u.length===i));l=!0);}catch(_){f=!0,h=_}finally{try{!l&&d.return&&d.return()}finally{if(f)throw h}}return u}return function(c,i){if(Array.isArray(c))return c;if(Symbol.iterator in Object(c))return s(c,i);throw new TypeError("Invalid attempt to destructure non-iterable instance")}})();Object.defineProperty(t,"__esModule",{value:!0});var n=Rt(),o=qt();function a(s,c){var i=arguments.length<=2||arguments[2]===void 0?1e-6:arguments[2],u=-i,l=1+i,f=Math,h=f.min,d=f.max,b=["000","fff"].map(function(R){return c.fromXyz(s.fromRgb(n.rgb.fromHex(R)))}),_=r(b,2),g=_[0],v=_[1];function H(R){var m=s.toRgb(c.toXyz(R)),p=m.map(function(y){return y>=u&&y<=l}).reduce(function(y,w){return y&&w},!0);return[p,m]}function x(R,m){for(var p=arguments.length<=2||arguments[2]===void 0?.001:arguments[2];(0,o.distance)(R,m)>p;){var y=(0,o.lerp)(R,m,.5),w=H(y),C=r(w,1),q=C[0];q?R=y:m=y}return R}function N(R){return(0,o.lerp)(g,v,R)}function A(R){return R.map(function(m){return d(u,h(l,m))})}return{contains:H,limit:x,spine:N,crop:A}}t.default=a,e.exports=t.default})(Mt,Mt.exports)),Mt.exports}var Ot={exports:{}},pe={},ba;function pa(){if(ba)return pe;ba=1;var e=(function(){function f(h,d){var b=[],_=!0,g=!1,v=void 0;try{for(var H=h[Symbol.iterator](),x;!(_=(x=H.next()).done)&&(b.push(x.value),!(d&&b.length===d));_=!0);}catch(N){g=!0,v=N}finally{try{!_&&H.return&&H.return()}finally{if(g)throw v}}return b}return function(h,d){if(Array.isArray(h))return h;if(Symbol.iterator in Object(h))return f(h,d);throw new TypeError("Invalid attempt to destructure non-iterable instance")}})();Object.defineProperty(pe,"__esModule",{value:!0}),pe.toNotation=pe.fromNotation=pe.toHue=pe.fromHue=void 0;var t=qt(),r=Math,n=r.floor,o=[{s:"R",h:20.14,e:.8,H:0},{s:"Y",h:90,e:.7,H:100},{s:"G",h:164.25,e:1,H:200},{s:"B",h:237.53,e:1.2,H:300},{s:"R",h:380.14,e:.8,H:400}],a=o.map(function(f){return f.s}).slice(0,-1).join("");function s(f){f50){var _=[d,h];h=_[0],d=_[1],b=100-b}return b<1?a[h]:a[h]+b.toFixed()+a[d]}return pe.fromHue=s,pe.toHue=c,pe.fromNotation=u,pe.toNotation=l,pe}var ma;function Wi(){return ma||(ma=1,(function(e,t){var r=(function(){function S(X,D){var U=[],ce=!0,ye=!1,st=void 0;try{for(var le=X[Symbol.iterator](),qe;!(ce=(qe=le.next()).done)&&(U.push(qe.value),!(D&&U.length===D));ce=!0);}catch(he){ye=!0,st=he}finally{try{!ce&&le.return&&le.return()}finally{if(ye)throw st}}return U}return function(X,D){if(Array.isArray(X))return X;if(Symbol.iterator in Object(X))return S(X,D);throw new TypeError("Invalid attempt to destructure non-iterable instance")}})();Object.defineProperty(t,"__esModule",{value:!0});var n=Rt(),o=pa(),a=i(o),s=qt(),c=Hn();function i(S){if(S&&S.__esModule)return S;var X={};if(S!=null)for(var D in S)Object.prototype.hasOwnProperty.call(S,D)&&(X[D]=S[D]);return X.default=S,X}var u=Math,l=u.pow,f=u.sqrt,h=u.exp,d=u.abs,b=u.sign,_=Math,g=_.sin,v=_.cos,H=_.atan2,x={average:{F:1,c:.69,N_c:1},dim:{F:.9,c:.59,N_c:.9},dark:{F:.8,c:.535,N_c:.8}},N=[[.7328,.4296,-.1624],[-.7036,1.6975,.0061],[.003,.0136,.9834]],A=[[.38971,.68898,-.07868],[-.22981,1.1834,.04641],[0,0,1]],R=N,m=n.matrix.inverse(N),p=n.matrix.product(A,n.matrix.inverse(N)),y=n.matrix.product(N,n.matrix.inverse(A)),w={whitePoint:n.illuminant.D65,adaptingLuminance:40,backgroundLuminance:20,surroundType:"average",discounting:!1},C=(0,s.cfs)("QJMCshH"),q=(0,s.cfs)("JCh");function M(){var S=arguments.length<=0||arguments[0]===void 0?{}:arguments[0],X=arguments.length<=1||arguments[1]===void 0?C:arguments[1];S=(0,c.merge)(w,S);var D=S.whitePoint,U=S.adaptingLuminance,ce=S.backgroundLuminance,ye=x[S.surroundType],st=ye.F,le=ye.c,qe=ye.N_c,he=D[1],wc=1/(5*U+1),Ge=.2*l(wc,4)*5*U+.1*l(1-l(wc,4),2)*l(5*U,1/3),Xt=ce/he,no=.725*l(1/Xt,.2),kc=no,$c=1.48+f(Xt),Cc=S.discounting?1:st*(1-1/3.6*h(-(U+42)/92)),$l=n.matrix.multiply(N,D),Cl=$l.map(function(I){return Cc*he/I+1-Cc}),oo=r(Cl,3),xc=oo[0],Rc=oo[1],Hc=oo[2],xl=qc(D),Rl=Mc(xl),Kt=Oc(Rl);function qc(I){var z=n.matrix.multiply(R,I),F=r(z,3),ee=F[0],W=F[1],ie=F[2];return[xc*ee,Rc*W,Hc*ie]}function Hl(I){var z=r(I,3),F=z[0],ee=z[1],W=z[2];return n.matrix.multiply(m,[F/xc,ee/Rc,W/Hc])}function Mc(I){return n.matrix.multiply(p,I).map(function(z){var F=l(Ge*d(z)/100,.42);return b(z)*400*F/(27.13+F)+.1})}function ql(I){return n.matrix.multiply(y,I.map(function(z){var F=z-.1;return b(F)*100/Ge*l(27.13*d(F)/(400-d(F)),2.380952380952381)}))}function Oc(I){var z=r(I,3),F=z[0],ee=z[1],W=z[2];return(F*2+ee+W/20-.305)*no}function so(I){return 4/le*f(I/100)*(Kt+4)*l(Ge,.25)}function Ml(I){return 6.25*l(le*I/((Kt+4)*l(Ge,.25)),2)}function Nc(I){return I*l(Ge,.25)}function Ol(I,z){return l(I/100,2)*z/l(Ge,.25)}function Nl(I){return I/l(Ge,.25)}function Al(I,z){return 100*f(I/z)}function ao(I,z){var F=z.Q,ee=z.J,W=z.M,ie=z.C,ve=z.s,Me=z.h,Oe=z.H,te={};return I.J&&(te.J=isNaN(ee)?Ml(F):ee),I.C&&(isNaN(ie)?isNaN(W)?(F=isNaN(F)?so(ee):F,te.C=Ol(ve,F)):te.C=Nl(W):te.C=z.C),I.h&&(te.h=isNaN(Me)?a.toHue(Oe):Me),I.Q&&(te.Q=isNaN(F)?so(ee):F),I.M&&(te.M=isNaN(W)?Nc(ie):W),I.s&&(isNaN(ve)?(F=isNaN(F)?so(ee):F,W=isNaN(W)?Nc(ie):W,te.s=Al(W,F)):te.s=ve),I.H&&(te.H=isNaN(Oe)?a.fromHue(Me):Oe),te}function Ll(I){var z=qc(I),F=Mc(z),ee=r(F,3),W=ee[0],ie=ee[1],ve=ee[2],Me=W-ie*12/11+ve/11,Oe=(W+ie-2*ve)/9,te=H(Oe,Me),at=n.degree.fromRadian(te),Dt=1/4*(v(te+2)+3.8),Vt=Oc(F),bt=100*l(Vt/Kt,le*$c),Pe=5e4/13*qe*kc*Dt*f(Me*Me+Oe*Oe)/(W+ie+21/20*ve),je=l(Pe,.9)*f(bt/100)*l(1.64-l(.29,Xt),.73);return ao(X,{J:bt,C:je,h:at})}function El(I){var z=ao(q,I),F=z.J,ee=z.C,W=z.h,ie=n.degree.toRadian(W),ve=l(ee/(f(F/100)*l(1.64-l(.29,Xt),.73)),10/9),Me=1/4*(v(ie+2)+3.8),Oe=Kt*l(F/100,1/le/$c),te=5e4/13*qe*kc*Me/ve,at=Oe/no+.305,Dt=at*61/20*460/1403,Vt=61/20*220/1403,bt=21/20*6300/1403-27/1403,Pe=g(ie),je=v(ie),Ie,ze;ve===0||isNaN(ve)?Ie=ze=0:d(Pe)>=d(je)?(ze=Dt/(te/Pe+Vt*je/Pe+bt),Ie=ze*je/Pe):(Ie=Dt/(te/je+Vt+bt*Pe/je),ze=Ie*Pe/je);var Tl=[20/61*at+451/1403*Ie+288/1403*ze,20/61*at-891/1403*Ie-261/1403*ze,20/61*at-220/1403*Ie-6300/1403*ze],Sl=ql(Tl),Pl=Hl(Sl);return Pl}return{fromXyz:Ll,toXyz:El,fillOut:ao}}t.default=M,e.exports=t.default})(Ot,Ot.exports)),Ot.exports}var Nt={exports:{}},ga;function Ui(){return ga||(ga=1,(function(e,t){Object.defineProperty(t,"__esModule",{value:!0});var r=Rt(),n=Math,o=n.sqrt,a=n.pow,s=n.exp,c=n.log,i=n.cos,u=n.sin,l=n.atan2,f={LCD:{K_L:.77,c_1:.007,c_2:.0053},SCD:{K_L:1.24,c_1:.007,c_2:.0363},UCS:{K_L:1,c_1:.007,c_2:.0228}};function h(){var d=arguments.length<=0||arguments[0]===void 0?"UCS":arguments[0],b=f[d],_=b.K_L,g=b.c_1,v=b.c_2;function H(A){var R=A.J,m=A.M,p=A.h,y=r.degree.toRadian(p),w=(1+100*g)*R/(1+g*R),C=1/v*c(1+v*m),q=C*i(y),M=C*u(y);return{J_p:w,a_p:q,b_p:M}}function x(A){var R=A.J_p,m=A.a_p,p=A.b_p,y=-R/(g*R-100*g-1),w=o(a(m,2)+a(p,2)),C=(s(v*w)-1)/v,q=l(p,m),M=r.degree.fromRadian(q);return{J:y,M:C,h:M}}function N(A,R){return o(a((A.J_p-R.J_p)/_,2)+a(A.a_p-R.a_p,2)+a(A.b_p-R.b_p,2))}return{fromCam:H,toCam:x,distance:N}}t.default=h,e.exports=t.default})(Nt,Nt.exports)),Nt.exports}var Mn,va;function Qi(){if(va)return Mn;va=1;var e=qt(),t=Ji(),r=Wi(),n=Ui(),o=pa();return Mn={gamut:t,cfs:e.cfs,lerp:e.lerp,cam:r,ucs:n,hq:o},Mn}var eu=Qi();const _a=pr(eu),ya=_a.cam({whitePoint:Ht.illuminant.D65,adaptingLuminance:40,backgroundLuminance:20,surroundType:"average",discounting:!1},_a.cfs("JCh")),wa=Ht.xyz(Ht.workspace.sRGB,Ht.illuminant.D65),ka=e=>wa.toRgb(ya.toXyz({J:e[0],C:e[1],h:e[2]})),On=e=>{const t=ya.fromXyz(wa.fromRgb(e));return[t.J,t.C,t.h]},[tu,ru]=(()=>{const e={k_l:1,c1:.007,c2:.0228},t=Math.PI,r=64/t/5,n=1/(5*r+1),o=.2*n**4*(5*r)+.1*(1-n**4)**2*(5*r)**(1/3);return[a=>{const[s,c,i]=a,u=c*o**.25;let l=(1+100*e.c1)*s/(1+e.c1*s);l/=e.k_l;const f=1/e.c2*Math.log(1+e.c2*u),h=f*Math.cos(i*(t/180)),d=f*Math.sin(i*(t/180));return[l,h,d]},a=>{const[s,c,i]=a,u=Math.sqrt(c*c+i*i),l=(Math.exp(u*e.c2)-1)/e.c2,f=(180/t*Math.atan2(i,c)+360)%360,h=l/o**.25;return[s/(1+e.c1*(100-s)),h,f]}]})(),nu=e=>ka(ru(e)),$a=e=>tu(On(e)),At=console;At.color=(e,t="")=>{const n=O(e).luminance();At.log(`%c${e} ${t}`,`background-color: ${e};padding: 5px; border-radius: 5px; color: ${n>.5?"#000":"#fff"}`)},At.ramp=(e,t=1)=>{At.log("%c ",`font-size: 1px;line-height: 16px;background: ${O.getCSSGradient(e,t)};padding: 0 0 0 200px; border-radius: 2px;`)};const Ca=(e,t,r,n,o,a,s=.1)=>{if(e===r||t===n)return!0;const c=(n-t)/(r-e),i=(a+o/c-t+c*e)/(c+1/c),u=a+o/c-i/c;return(o-i)**2+(a-u)**2{const o=(t[0]+r[0])/2,a=e(o);return Ca(...t,...r,o,a,n)?null:[o,a]},Nn=(e,t,r,n=.1)=>{const o=(r-t)/10,a=[];for(let s=t;sMath.round(e*10**t)/10**t,su=(e,t=1,r=90,n=.005)=>{const o=Nn(i=>e(i).gl()[0],0,t,n),a=Nn(i=>e(i).gl()[1],0,t,n),s=Nn(i=>e(i).gl()[2],0,t,n),c=Array.from(new Set([...o.map(i=>Lt(i[0])),...a.map(i=>Lt(i[0])),...s.map(i=>Lt(i[0]))].sort((i,u)=>i-u)));return`linear-gradient(${r}deg, ${c.map(i=>`${e(i).hex()} ${Lt(i*100)}%`).join()});`},au=e=>{e.Color.prototype.jch=function(){return On(this._rgb.slice(0,3).map(o=>o/255))},e.jch=(...o)=>new e.Color(...ka(o).map(a=>Math.floor(a*255)),"rgb"),e.Color.prototype.jab=function(){return $a(this._rgb.slice(0,3).map(o=>o/255))},e.jab=(...o)=>new e.Color(...nu(o).map(a=>Math.floor(a*255)),"rgb"),e.Color.prototype.hsluv=function(){return gr.rgbToHsluv(this._rgb.slice(0,3).map(o=>o/255))},e.hsluv=(...o)=>new e.Color(...gr.hsluvToRgb(o).map(a=>Math.floor(a*255)),"rgb");const t=e.interpolate,r={jch:On,jab:$a,hsluv:gr.rgbToHsluv},n=(o,a,s)=>(Math.abs(o-a)>360/2&&(o>a?a+=360:o+=360),((1-s)*o+s*a)%360);e.interpolate=(o,a,s=.5,c="lrgb")=>{if(r[c]){typeof o!="object"&&(o=new e.Color(o)),typeof a!="object"&&(a=new e.Color(a));const i=r[c](o.gl()),u=r[c](a.gl()),l=Number.isNaN(o.hsl()[0]),f=Number.isNaN(a.hsl()[0]);let h,d,b;switch(c){case"hsluv":i[1]<1e-10&&(i[0]=u[0]),i[1]===0&&(i[1]=u[1]),u[1]<1e-10&&(u[0]=i[0]),u[1]===0&&(u[1]=i[1]),h=n(i[0],u[0],s),d=i[1]+(u[1]-i[1])*s,b=i[2]+(u[2]-i[2])*s;break;case"jch":l&&(i[2]=u[2]),f&&(u[2]=i[2]),h=i[0]+(u[0]-i[0])*s,d=i[1]+(u[1]-i[1])*s,b=n(i[2],u[2],s);break;default:h=i[0]+(u[0]-i[0])*s,d=i[1]+(u[1]-i[1])*s,b=i[2]+(u[2]-i[2])*s}return e[c](h,d,b).alpha(o.alpha()+s*(a.alpha()-o.alpha()))}return t(o,a,s,c)},e.getCSSGradient=su};const Y={mainTRC:2.4,sRco:.2126729,sGco:.7151522,sBco:.072175,normBG:.56,normTXT:.57,revTXT:.62,revBG:.65,blkThrs:.022,blkClmp:1.414,scaleBoW:1.14,scaleWoB:1.14,loBoWoffset:.027,loWoBoffset:.027,deltaYmin:5e-4,loClip:.1};function xa(e,t,r=-1){const n=[0,1.1];if(isNaN(e)||isNaN(t)||Math.min(e,t)n[1])return 0;let o=0,a=0,s="BoW";return e=e>Y.blkThrs?e:e+Math.pow(Y.blkThrs-e,Y.blkClmp),t=t>Y.blkThrs?t:t+Math.pow(Y.blkThrs-t,Y.blkClmp),Math.abs(t-e)e?(o=(Math.pow(t,Y.normBG)-Math.pow(e,Y.normTXT))*Y.scaleBoW,a=o-.1?0:o+Y.loWoBoffset),r<0?a*100:r==0?Math.round(Math.abs(a)*100)+""+s+"":Number.isInteger(r)?(a*100).toFixed(r):0)}function Et(e=[0,0,0]){function t(r){return Math.pow(r/255,Y.mainTRC)}return Y.sRco*t(e[0])+Y.sGco*t(e[1])+Y.sBco*t(e[2])}const Ra=(e,t,r,n,o,a,s,c,i)=>{const u=1-i,l=u*u,f=l*u,d=i*i*i,b=f*e+l*3*i*r+u*3*i*i*o+d*s,_=f*t+l*3*i*n+u*3*i*i*a+d*c;return{x:b,y:_}},cu=(e,t)=>{const r=[];let n={x:+e[0],y:+e[1]};for(let o=0,a=e.length;a-2*!0>o;o+=2){const s=[{x:+e[o-2],y:+e[o-1]},{x:+e[o],y:+e[o+1]},{x:+e[o+2],y:+e[o+3]},{x:+e[o+4],y:+e[o+5]}];a-4===o?s[3]=s[2]:o||(s[0]={x:+e[o],y:+e[o+1]}),r.push([n.x,n.y,(-s[0].x+6*s[1].x+s[2].x)/6,(-s[0].y+6*s[1].y+s[2].y)/6,(s[1].x+6*s[2].x-s[3].x)/6,(s[1].y+6*s[2].y-s[3].y)/6,s[2].x,s[2].y]),n=s[2]}return r},iu=(e,t,r,n,o,a,s,c)=>{let u=e,l=t,f=0;for(let h=1;h<5;h++){const{x:d,y:b}=Ra(e,t,r,n,o,a,s,c,h/5);f+=Math.hypot(d-u,b-l),u=d,l=b}return f+=Math.hypot(s-u,c-l),f},uu=(e,t,r,n,o,a,s,c)=>{const i=Math.floor(iu(e,t,r,n,o,a,s,c)*.75),u=[];let l=0;for(let f=0;f<=i;f++){const h=f/i,d=Ra(e,t,r,n,o,a,s,c,h),b=Math.round(d.x);if(u[b]=d.y,b-l>1){const _=u[l],g=u[b];for(let v=l+1;vu[Math.round(f)]||null},Ze={CAM02:"jab",CAM02p:"jch",HEX:"hex",HSL:"hsl",HSLuv:"hsluv",HSV:"hsv",LAB:"lab",LCH:"lch",RGB:"rgb",OKLAB:"oklab",OKLCH:"oklch"};function Ee(e,t=0){const r=10**t;return Math.round(e*r)/r}function fu(e,t){let r;return e>1?r=(e-1)*t+1:e<-1?r=(e+1)*t-1:r=1,Ee(r,2)}function lu(e){return O(String(e)).jch()}function hu(e){return O(String(e)).hsluv()}function du(e,t,r){const n=[[],[],[]];if(e.forEach((a,s)=>n.forEach((c,i)=>c.push(t[s],a[i]))),r==="hcl"){const a=n[1];for(let s=1;s{const s=[];for(let c=1;c{a[i]=a[c]}),s.length=0;break}if(s.length){const c=O("#ccc").jch()[2];s.forEach(i=>{a[i]=c})}s.length=0;for(let c=a.length-1;c>0;c-=2)if(Number.isNaN(a[c]))s.push(c);else{s.forEach(i=>{a[i]=a[c]});break}for(let c=1;ccu(a).map(s=>uu(...s)));return a=>{const s=o.map(c=>{for(let i=0;in*a**e+o}function An({swatches:e,colorKeys:t,colorspace:r="LAB",shift:n=1,fullScale:o=!0,smooth:a=!1,distributeLightness:s="linear",sortColor:c=!0,asFun:i=!1}={}){const u=Ze[r];if(!u)throw new Error(`Colorspace “${r}” not supported`);if(!t)throw new Error(`Colorkeys missing: returned “${t}”`);let l;if(o)l=t.map(H=>e-e*(O(H).jch()[0]/100)).sort((H,x)=>H-x).concat(e),l.unshift(0);else{let H=t.map(A=>O(A).jch()[0]/100),x=Math.min(...H),N=Math.max(...H);l=H.map(A=>A===0||isNaN((A-x)/(N-x))?0:e-(A-x)/(N-x)*e).sort((A,R)=>A-R)}let f=bu(n,[1,e],[1,e]);if(f=l.map(H=>Math.max(0,f(H))),l=f,s==="polynomial"){const H=A=>Math.sqrt(Math.sqrt((Math.pow(A,2.25)+Math.pow(A,4))/2));l=f.map(A=>A/e).map(A=>H(A)*e)}const h=t.map((H,x)=>({colorKeys:lu(H),index:x})).sort((H,x)=>x.colorKeys[0]-H.colorKeys[0]).map(H=>t[H.index]);let d=[],b;if(o){const H=u==="lch"?O.lch(...O("#fff").lch()):"#ffffff",x=u==="lch"?O.lch(...O("#000").lch()):"#000000";d=[H,...h,x]}else c?d=h:d=t;let _;if(a){const H=d;if(d=d.map(x=>O(String(x))[u]()),u==="hcl"&&d.forEach(x=>{x[1]=Number.isNaN(x[1])?0:x[1]}),u==="jch")for(let x=0;xb(N))}else b=O.scale(d.map(H=>typeof H=="object"&&H.constructor===O.Color?H:String(H))).domain(l).mode(u);return i?b:(!a||a===!1?b.colors(e):_).filter(H=>H!=null)}function pu(e,t){const r=[],n={};return Object.keys(e).forEach(s=>{n[e[s][t]]=e[s]}),Object.keys(n).forEach(s=>r.push(n[s])),r}function mu(e){return Number.isNaN(e)?0:e}function Ln(e,t,r=!1){if(!e)throw new Error(`Cannot convert color value of “${e}”`);if(!Ze[t])throw new Error(`Cannot convert to colorspace “${t}”`);const n=Ze[t],o=O(String(e))[n]();if(t==="HSL"&&o.pop(),t==="HEX"){if(r){const u=O(String(e)).rgb();return{r:u[0],g:u[1],b:u[2]}}return o}const a={};let s=o.map(mu);s=s.map((u,l)=>{let f=Ee(u),h=l;n==="hsluv"&&(h+=2);let d=n.charAt(h);return n==="jch"&&d==="c"&&(d="C"),a[d==="j"?"J":d]=f,n in{lab:1,lch:1,jab:1,jch:1}?r||((d==="l"||d==="j")&&(f+="%"),d==="h"&&(f+="deg")):n!=="hsluv"&&(d==="s"||d==="l"||d==="v"?(a[d]=Ee(u,2),r||(f=Ee(u*100),f+="%")):d==="h"&&!r&&(f+="deg")),f});const i=`${n}(${s.join(", ")})`;return r?a:i}function Ha(e,t,r){const n=[e,t,r].map(o=>(o/=255,o<=.03928?o/12.92:((o+.055)/1.055)**2.4));return n[0]*.2126+n[1]*.7152+n[2]*.0722}function gu(e,t,r,n="wcag2"){if(r===void 0){const o=O.rgb(...t).hsluv()[2];r=Ee(o/100,2)}if(n==="wcag2"){const o=Ha(e[0],e[1],e[2]),a=Ha(t[0],t[1],t[2]),s=(o+.05)/(a+.05),c=(a+.05)/(o+.05);return r<.5?s>=1?s:-c:s<1?c:s===1?s:-s}else{if(n==="wcag3")return r<.5?xa(Et(e),Et(t))*-1:xa(Et(e),Et(t));throw new Error(`Contrast calculation method ${n} unsupported; use 'wcag2' or 'wcag3'`)}}function vu(e,t){if(!e)throw new Error("Array undefined");if(!Array.isArray(e))throw new Error("Passed object is not an array");const r=t==="wcag2"?0:1;return Math.min(...e.filter(n=>n>=r))}function _u(e,t){if(!e)throw new Error("Ratios undefined");e=e.sort((c,i)=>c-i);const r=vu(e,t),n=e.indexOf(r),o=[],a=e.slice(0,n),s=e.slice(n,e.length);for(let c=0;cc-i),o}const yu=(e,t,r,n,o)=>{const s=An({swatches:3e3,colorKeys:e._modifiedKeys,colorspace:e._colorspace,shift:1,smooth:e._smooth,asFun:!0}),c={},i=f=>{if(c[f])return c[f];const h=O(s(f)).rgb(),d=gu(h,t,r,o);return c[f]=d,d},u=f=>{const h=i(0),d=i(3e3),b=h_&&x;)x--,g/=2,Hl.push(s(u(+f)))),l};let ae=class{constructor({name:t,colorKeys:r,colorspace:n="RGB",ratios:o,smooth:a=!1,output:s="HEX",saturation:c=100}){if(this._name=t,this._colorKeys=r,this._modifiedKeys=r,this._colorspace=n,this._ratios=o,this._smooth=a,this._output=s,this._saturation=c,!this._name)throw new Error("Color missing name");if(!this._colorKeys)throw new Error("Color Keys are undefined");if(!Ze[this._colorspace])throw new Error(`Colorspace “${n}” not supported`);if(!Ze[this._output])throw new Error(`Output “${n}” not supported`);for(let i=0;i{let n=O(`${r}`).oklch(),a=n[1]*(this._saturation/100),s=O.oklch(n[0],a,n[2]),c=O.rgb(s).hex();t.push(c)}),this._modifiedKeys=t,this._generateColorScale()}_generateColorScale(){this._colorScale=An({swatches:3e3,colorKeys:this._modifiedKeys,colorspace:this._colorspace,shift:1,smooth:this._smooth,asFun:!0})}};class qa extends ae{get backgroundColorScale(){return this._backgroundColorScale||this._generateColorScale(),this._backgroundColorScale}_generateColorScale(){ae.prototype._generateColorScale.call(this);const t=An({swatches:1e3,colorKeys:this._colorKeys,colorspace:this._colorspace,shift:1,smooth:this._smooth});t.push(...this.colorKeys);const r=t.map((a,s)=>({value:Math.round(hu(a)[2]),index:s})),o=pu(r,"value").map(a=>t[a.index]);return o.length>=101&&(o.length=100,o.push("#ffffff")),this._backgroundColorScale=o.map(a=>Ln(a,this._output)),this._backgroundColorScale}}class wu{constructor({colors:t,backgroundColor:r,lightness:n,contrast:o=1,saturation:a=100,output:s="HEX",formula:c="wcag2"}){if(this._output=s,this._colors=t,this._lightness=n,this._saturation=a,this._formula=c,this._setBackgroundColor(r),this._setBackgroundColorValue(),this._contrast=o,!this._colors)throw new Error("No colors are defined");if(!this._backgroundColor)throw new Error("Background color is undefined");if(t.forEach(i=>{if(!i.ratios)throw new Error(`Color ${i.name}'s ratios are undefined`)}),!Ze[this._output])throw new Error(`Output “${s}” not supported`);this._saturation<100&&this._updateColorSaturation(this._saturation),this._findContrastColors(),this._findContrastColorPairs(),this._findContrastColorValues()}set formula(t){this._formula=t,this._findContrastColors()}get formula(){return this._formula}set contrast(t){this._contrast=t,this._findContrastColors()}get contrast(){return this._contrast}set lightness(t){this._lightness=t,this._setBackgroundColor(this._backgroundColor),this._findContrastColors()}get lightness(){return this._lightness}set saturation(t){this._saturation=t,this._updateColorSaturation(t),this._findContrastColors()}get saturation(){return this._saturation}set backgroundColor(t){this._setBackgroundColor(t),this._findContrastColors()}get backgroundColorValue(){return this._backgroundColorValue}get backgroundColor(){return this._backgroundColor}set colors(t){this._colors=t,this._findContrastColors()}get colors(){return this._colors}set addColor(t){this._colors.push(t),this._findContrastColors()}set removeColor(t){const r=this._colors.filter(n=>n.name!==t.name);this._colors=r,this._findContrastColors()}set updateColor(t){if(Array.isArray(t))for(let r=0;rs.name===t[r].color);n=n[0];let o=this._colors.indexOf(n);const a=this._colors.filter(s=>s.name!==t[r].color);t[r].name&&(n.name=t[r].name),t[r].colorKeys&&(n.colorKeys=t[r].colorKeys),t[r].ratios&&(n.ratios=t[r].ratios),t[r].colorspace&&(n.colorspace=t[r].colorspace),t[r].smooth&&(n.smooth=t[r].smooth),n._generateColorScale(),a.splice(o,0,n),this._colors=a}else{let r=this._colors.filter(a=>a.name===t.color);r=r[0];let n=this._colors.indexOf(r);const o=this._colors.filter(a=>a.name!==t.color);t.name&&(r.name=t.name),t.colorKeys&&(r.colorKeys=t.colorKeys),t.ratios&&(r.ratios=t.ratios),t.colorspace&&(r.colorspace=t.colorspace),t.smooth&&(r.smooth=t.smooth),r._generateColorScale(),o.splice(n,0,r),this._colors=o}this._findContrastColors()}set output(t){this._output=t,this._colors.forEach(r=>{r.output=this._output}),this._backgroundColor.output=this._output,this._findContrastColors()}get output(){return this._output}get contrastColors(){return this._contrastColors}get contrastColorPairs(){return this._contrastColorPairs}get contrastColorValues(){return this._contrastColorValues}_setBackgroundColor(t){if(typeof t=="string"){const r=new qa({name:"background",colorKeys:[t],output:"RGB"}),n=Ee(O(String(t)).hsluv()[2]);this._backgroundColor=r,this._lightness=n,this._backgroundColorValue=r[this._lightness]}else{t.output="RGB";const r=t.backgroundColorScale[this._lightness];this._backgroundColor=t,this._backgroundColorValue=r}}_setBackgroundColorValue(){this._backgroundColorValue=this._backgroundColor.backgroundColorScale[this._lightness]}_updateColorSaturation(t){this._colors.map(r=>{r.saturation=t})}_findContrastColors(){const t=O(String(this._backgroundColorValue)).rgb(),r=this._lightness/100,o={background:Ln(this._backgroundColorValue,this._output)},a=[],s=[],c={...o};return a.push(o),this._colors.map(i=>{if(i.ratios!==void 0){let u;const l=[],f={name:i.name,values:l};let h;Array.isArray(i.ratios)?h=i.ratios:Array.isArray(i.ratios)||(u=Object.keys(i.ratios),h=Object.values(i.ratios)),h=h.map(b=>fu(+b,this._contrast));const d=yu(i,t,r,h,this._formula).map(b=>Ln(b,this._output));for(let b=0;bku($u(t,e),r),En=e=>{e._clipped=!1,e._unclipped=e.slice(0);for(let t=0;t<=3;t++)t<3?((e[t]<0||e[t]>255)&&(e._clipped=!0),e[t]=Be(e[t],0,255)):t===3&&(e[t]=Be(e[t],0,1));return e},Ma={};for(let e of["Boolean","Number","String","Function","Array","Date","RegExp","Undefined","Null"])Ma[`[object ${e}]`]=e.toLowerCase();function B(e){return Ma[Object.prototype.toString.call(e)]||"object"}const T=(e,t=null)=>e.length>=3?Array.prototype.slice.call(e):B(e[0])=="object"&&t?t.split("").filter(r=>e[0][r]!==void 0).map(r=>e[0][r]):e[0].slice(0),Je=e=>{if(e.length<2)return null;const t=e.length-1;return B(e[t])=="string"?e[t].toLowerCase():null},{PI:Tt,min:Oa,max:Na}=Math,ue=e=>Math.round(e*100)/100,Tn=e=>Math.round(e*100)/100,Ce=Tt*2,Sn=Tt/3,Cu=Tt/180,xu=180/Tt;function Aa(e){return[...e.slice(0,3).reverse(),...e.slice(3)]}const E={format:{},autodetect:[]};class k{constructor(...t){const r=this;if(B(t[0])==="object"&&t[0].constructor&&t[0].constructor===this.constructor)return t[0];let n=Je(t),o=!1;if(!n){o=!0,E.sorted||(E.autodetect=E.autodetect.sort((a,s)=>s.p-a.p),E.sorted=!0);for(let a of E.autodetect)if(n=a.test(...t),n)break}if(E.format[n]){const a=E.format[n].apply(null,o?t:t.slice(0,-1));r._rgb=En(a)}else throw new Error("unknown format: "+t);r._rgb.length===3&&r._rgb.push(1)}toString(){return B(this.hex)=="function"?this.hex():`[${this._rgb.join(",")}]`}}const Ru="3.2.0",G=(...e)=>new k(...e);G.version=Ru;const We={aliceblue:"#f0f8ff",antiquewhite:"#faebd7",aqua:"#00ffff",aquamarine:"#7fffd4",azure:"#f0ffff",beige:"#f5f5dc",bisque:"#ffe4c4",black:"#000000",blanchedalmond:"#ffebcd",blue:"#0000ff",blueviolet:"#8a2be2",brown:"#a52a2a",burlywood:"#deb887",cadetblue:"#5f9ea0",chartreuse:"#7fff00",chocolate:"#d2691e",coral:"#ff7f50",cornflowerblue:"#6495ed",cornsilk:"#fff8dc",crimson:"#dc143c",cyan:"#00ffff",darkblue:"#00008b",darkcyan:"#008b8b",darkgoldenrod:"#b8860b",darkgray:"#a9a9a9",darkgreen:"#006400",darkgrey:"#a9a9a9",darkkhaki:"#bdb76b",darkmagenta:"#8b008b",darkolivegreen:"#556b2f",darkorange:"#ff8c00",darkorchid:"#9932cc",darkred:"#8b0000",darksalmon:"#e9967a",darkseagreen:"#8fbc8f",darkslateblue:"#483d8b",darkslategray:"#2f4f4f",darkslategrey:"#2f4f4f",darkturquoise:"#00ced1",darkviolet:"#9400d3",deeppink:"#ff1493",deepskyblue:"#00bfff",dimgray:"#696969",dimgrey:"#696969",dodgerblue:"#1e90ff",firebrick:"#b22222",floralwhite:"#fffaf0",forestgreen:"#228b22",fuchsia:"#ff00ff",gainsboro:"#dcdcdc",ghostwhite:"#f8f8ff",gold:"#ffd700",goldenrod:"#daa520",gray:"#808080",green:"#008000",greenyellow:"#adff2f",grey:"#808080",honeydew:"#f0fff0",hotpink:"#ff69b4",indianred:"#cd5c5c",indigo:"#4b0082",ivory:"#fffff0",khaki:"#f0e68c",laserlemon:"#ffff54",lavender:"#e6e6fa",lavenderblush:"#fff0f5",lawngreen:"#7cfc00",lemonchiffon:"#fffacd",lightblue:"#add8e6",lightcoral:"#f08080",lightcyan:"#e0ffff",lightgoldenrod:"#fafad2",lightgoldenrodyellow:"#fafad2",lightgray:"#d3d3d3",lightgreen:"#90ee90",lightgrey:"#d3d3d3",lightpink:"#ffb6c1",lightsalmon:"#ffa07a",lightseagreen:"#20b2aa",lightskyblue:"#87cefa",lightslategray:"#778899",lightslategrey:"#778899",lightsteelblue:"#b0c4de",lightyellow:"#ffffe0",lime:"#00ff00",limegreen:"#32cd32",linen:"#faf0e6",magenta:"#ff00ff",maroon:"#800000",maroon2:"#7f0000",maroon3:"#b03060",mediumaquamarine:"#66cdaa",mediumblue:"#0000cd",mediumorchid:"#ba55d3",mediumpurple:"#9370db",mediumseagreen:"#3cb371",mediumslateblue:"#7b68ee",mediumspringgreen:"#00fa9a",mediumturquoise:"#48d1cc",mediumvioletred:"#c71585",midnightblue:"#191970",mintcream:"#f5fffa",mistyrose:"#ffe4e1",moccasin:"#ffe4b5",navajowhite:"#ffdead",navy:"#000080",oldlace:"#fdf5e6",olive:"#808000",olivedrab:"#6b8e23",orange:"#ffa500",orangered:"#ff4500",orchid:"#da70d6",palegoldenrod:"#eee8aa",palegreen:"#98fb98",paleturquoise:"#afeeee",palevioletred:"#db7093",papayawhip:"#ffefd5",peachpuff:"#ffdab9",peru:"#cd853f",pink:"#ffc0cb",plum:"#dda0dd",powderblue:"#b0e0e6",purple:"#800080",purple2:"#7f007f",purple3:"#a020f0",rebeccapurple:"#663399",red:"#ff0000",rosybrown:"#bc8f8f",royalblue:"#4169e1",saddlebrown:"#8b4513",salmon:"#fa8072",sandybrown:"#f4a460",seagreen:"#2e8b57",seashell:"#fff5ee",sienna:"#a0522d",silver:"#c0c0c0",skyblue:"#87ceeb",slateblue:"#6a5acd",slategray:"#708090",slategrey:"#708090",snow:"#fffafa",springgreen:"#00ff7f",steelblue:"#4682b4",tan:"#d2b48c",teal:"#008080",thistle:"#d8bfd8",tomato:"#ff6347",turquoise:"#40e0d0",violet:"#ee82ee",wheat:"#f5deb3",white:"#ffffff",whitesmoke:"#f5f5f5",yellow:"#ffff00",yellowgreen:"#9acd32"},Hu=/^#?([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/,qu=/^#?([A-Fa-f0-9]{8}|[A-Fa-f0-9]{4})$/,La=e=>{if(e.match(Hu)){(e.length===4||e.length===7)&&(e=e.substr(1)),e.length===3&&(e=e.split(""),e=e[0]+e[0]+e[1]+e[1]+e[2]+e[2]);const t=parseInt(e,16),r=t>>16,n=t>>8&255,o=t&255;return[r,n,o,1]}if(e.match(qu)){(e.length===5||e.length===9)&&(e=e.substr(1)),e.length===4&&(e=e.split(""),e=e[0]+e[0]+e[1]+e[1]+e[2]+e[2]+e[3]+e[3]);const t=parseInt(e,16),r=t>>24&255,n=t>>16&255,o=t>>8&255,a=Math.round((t&255)/255*100)/100;return[r,n,o,a]}throw new Error(`unknown hex color: ${e}`)},{round:St}=Math,Ea=(...e)=>{let[t,r,n,o]=T(e,"rgba"),a=Je(e)||"auto";o===void 0&&(o=1),a==="auto"&&(a=o<1?"rgba":"rgb"),t=St(t),r=St(r),n=St(n);let c="000000"+(t<<16|r<<8|n).toString(16);c=c.substr(c.length-6);let i="0"+St(o*255).toString(16);switch(i=i.substr(i.length-2),a.toLowerCase()){case"rgba":return`#${c}${i}`;case"argb":return`#${i}${c}`;default:return`#${c}`}};k.prototype.name=function(){const e=Ea(this._rgb,"rgb");for(let t of Object.keys(We))if(We[t]===e)return t.toLowerCase();return e},E.format.named=e=>{if(e=e.toLowerCase(),We[e])return La(We[e]);throw new Error("unknown color name: "+e)},E.autodetect.push({p:5,test:(e,...t)=>{if(!t.length&&B(e)==="string"&&We[e.toLowerCase()])return"named"}}),k.prototype.alpha=function(e,t=!1){return e!==void 0&&B(e)==="number"?t?(this._rgb[3]=e,this):new k([this._rgb[0],this._rgb[1],this._rgb[2],e],"rgb"):this._rgb[3]},k.prototype.clipped=function(){return this._rgb._clipped||!1};const _e={Kn:18,labWhitePoint:"d65",Xn:.95047,Yn:1,Zn:1.08883,kE:216/24389,kKE:8,kK:24389/27,RefWhiteRGB:{X:.95047,Y:1,Z:1.08883},MtxRGB2XYZ:{m00:.4124564390896922,m01:.21267285140562253,m02:.0193338955823293,m10:.357576077643909,m11:.715152155287818,m12:.11919202588130297,m20:.18043748326639894,m21:.07217499330655958,m22:.9503040785363679},MtxXYZ2RGB:{m00:3.2404541621141045,m01:-.9692660305051868,m02:.055643430959114726,m10:-1.5371385127977166,m11:1.8760108454466942,m12:-.2040259135167538,m20:-.498531409556016,m21:.041556017530349834,m22:1.0572251882231791},As:.9414285350000001,Bs:1.040417467,Cs:1.089532651,MtxAdaptMa:{m00:.8951,m01:-.7502,m02:.0389,m10:.2664,m11:1.7135,m12:-.0685,m20:-.1614,m21:.0367,m22:1.0296},MtxAdaptMaI:{m00:.9869929054667123,m01:.43230526972339456,m02:-.008528664575177328,m10:-.14705425642099013,m11:.5183602715367776,m12:.04004282165408487,m20:.15996265166373125,m21:.0492912282128556,m22:.9684866957875502}},Mu=new Map([["a",[1.0985,.35585]],["b",[1.0985,.35585]],["c",[.98074,1.18232]],["d50",[.96422,.82521]],["d55",[.95682,.92149]],["d65",[.95047,1.08883]],["e",[1,1,1]],["f2",[.99186,.67393]],["f7",[.95041,1.08747]],["f11",[1.00962,.6435]],["icc",[.96422,.82521]]]);function xe(e){const t=Mu.get(String(e).toLowerCase());if(!t)throw new Error("unknown Lab illuminant "+e);_e.labWhitePoint=e,_e.Xn=t[0],_e.Zn=t[1]}function dt(){return _e.labWhitePoint}const Pn=(...e)=>{e=T(e,"lab");const[t,r,n]=e,[o,a,s]=Ou(t,r,n),[c,i,u]=Ta(o,a,s);return[c,i,u,e.length>3?e[3]:1]},Ou=(e,t,r)=>{const{kE:n,kK:o,kKE:a,Xn:s,Yn:c,Zn:i}=_e,u=(e+16)/116,l=.002*t+u,f=u-.005*r,h=l*l*l,d=f*f*f,b=h>n?h:(116*l-16)/o,_=e>a?Math.pow((e+16)/116,3):e/o,g=d>n?d:(116*f-16)/o,v=b*s,H=_*c,x=g*i;return[v,H,x]},jn=e=>{const t=Math.sign(e);return e=Math.abs(e),(e<=.0031308?e*12.92:1.055*Math.pow(e,1/2.4)-.055)*t},Ta=(e,t,r)=>{const{MtxAdaptMa:n,MtxAdaptMaI:o,MtxXYZ2RGB:a,RefWhiteRGB:s,Xn:c,Yn:i,Zn:u}=_e,l=c*n.m00+i*n.m10+u*n.m20,f=c*n.m01+i*n.m11+u*n.m21,h=c*n.m02+i*n.m12+u*n.m22,d=s.X*n.m00+s.Y*n.m10+s.Z*n.m20,b=s.X*n.m01+s.Y*n.m11+s.Z*n.m21,_=s.X*n.m02+s.Y*n.m12+s.Z*n.m22,g=(e*n.m00+t*n.m10+r*n.m20)*(d/l),v=(e*n.m01+t*n.m11+r*n.m21)*(b/f),H=(e*n.m02+t*n.m12+r*n.m22)*(_/h),x=g*o.m00+v*o.m10+H*o.m20,N=g*o.m01+v*o.m11+H*o.m21,A=g*o.m02+v*o.m12+H*o.m22,R=jn(x*a.m00+N*a.m10+A*a.m20),m=jn(x*a.m01+N*a.m11+A*a.m21),p=jn(x*a.m02+N*a.m12+A*a.m22);return[R*255,m*255,p*255]},Bn=(...e)=>{const[t,r,n,...o]=T(e,"rgb"),[a,s,c]=Sa(t,r,n),[i,u,l]=Nu(a,s,c);return[i,u,l,...o.length>0&&o[0]<1?[o[0]]:[]]};function Nu(e,t,r){const{Xn:n,Yn:o,Zn:a,kE:s,kK:c}=_e,i=e/n,u=t/o,l=r/a,f=i>s?Math.pow(i,1/3):(c*i+16)/116,h=u>s?Math.pow(u,1/3):(c*u+16)/116,d=l>s?Math.pow(l,1/3):(c*l+16)/116;return[116*h-16,500*(f-h),200*(h-d)]}function Gn(e){const t=Math.sign(e);return e=Math.abs(e),(e<=.04045?e/12.92:Math.pow((e+.055)/1.055,2.4))*t}const Sa=(e,t,r)=>{e=Gn(e/255),t=Gn(t/255),r=Gn(r/255);const{MtxRGB2XYZ:n,MtxAdaptMa:o,MtxAdaptMaI:a,Xn:s,Yn:c,Zn:i,As:u,Bs:l,Cs:f}=_e;let h=e*n.m00+t*n.m10+r*n.m20,d=e*n.m01+t*n.m11+r*n.m21,b=e*n.m02+t*n.m12+r*n.m22;const _=s*o.m00+c*o.m10+i*o.m20,g=s*o.m01+c*o.m11+i*o.m21,v=s*o.m02+c*o.m12+i*o.m22;let H=h*o.m00+d*o.m10+b*o.m20,x=h*o.m01+d*o.m11+b*o.m21,N=h*o.m02+d*o.m12+b*o.m22;return H*=_/u,x*=g/l,N*=v/f,h=H*a.m00+x*a.m10+N*a.m20,d=H*a.m01+x*a.m11+N*a.m21,b=H*a.m02+x*a.m12+N*a.m22,[h,d,b]};k.prototype.lab=function(){return Bn(this._rgb)},Object.assign(G,{lab:(...e)=>new k(...e,"lab"),getLabWhitePoint:dt,setLabWhitePoint:xe}),E.format.lab=Pn,E.autodetect.push({p:2,test:(...e)=>{if(e=T(e,"lab"),B(e)==="array"&&e.length===3)return"lab"}}),k.prototype.darken=function(e=1){const t=this,r=t.lab();return r[0]-=_e.Kn*e,new k(r,"lab").alpha(t.alpha(),!0)},k.prototype.brighten=function(e=1){return this.darken(-e)},k.prototype.darker=k.prototype.darken,k.prototype.brighter=k.prototype.brighten,k.prototype.get=function(e){const[t,r]=e.split("."),n=this[t]();if(r){const o=t.indexOf(r)-(t.substr(0,2)==="ok"?2:0);if(o>-1)return n[o];throw new Error(`unknown channel ${r} in mode ${t}`)}else return n};const{pow:Au}=Math,Lu=1e-7,Eu=20;k.prototype.luminance=function(e,t="rgb"){if(e!==void 0&&B(e)==="number"){if(e===0)return new k([0,0,0,this._rgb[3]],"rgb");if(e===1)return new k([255,255,255,this._rgb[3]],"rgb");let r=this.luminance(),n=Eu;const o=(s,c)=>{const i=s.interpolate(c,.5,t),u=i.luminance();return Math.abs(e-u)e?o(s,i):o(i,c)},a=(r>e?o(new k([0,0,0]),this):o(this,new k([255,255,255]))).rgb();return new k([...a,this._rgb[3]])}return Tu(...this._rgb.slice(0,3))};const Tu=(e,t,r)=>(e=In(e),t=In(t),r=In(r),.2126*e+.7152*t+.0722*r),In=e=>(e/=255,e<=.03928?e/12.92:Au((e+.055)/1.055,2.4)),ne={},Ue=(e,t,r=.5,...n)=>{let o=n[0]||"lrgb";if(!ne[o]&&!n.length&&(o=Object.keys(ne)[0]),!ne[o])throw new Error(`interpolation mode ${o} is not defined`);return B(e)!=="object"&&(e=new k(e)),B(t)!=="object"&&(t=new k(t)),ne[o](e,t,r).alpha(e.alpha()+r*(t.alpha()-e.alpha()))};k.prototype.mix=k.prototype.interpolate=function(e,t=.5,...r){return Ue(this,e,t,...r)},k.prototype.premultiply=function(e=!1){const t=this._rgb,r=t[3];return e?(this._rgb=[t[0]*r,t[1]*r,t[2]*r,r],this):new k([t[0]*r,t[1]*r,t[2]*r,r],"rgb")};const{sin:Su,cos:Pu}=Math,Pa=(...e)=>{let[t,r,n]=T(e,"lch");return isNaN(n)&&(n=0),n=n*Cu,[t,Pu(n)*r,Su(n)*r]},zn=(...e)=>{e=T(e,"lch");const[t,r,n]=e,[o,a,s]=Pa(t,r,n),[c,i,u]=Pn(o,a,s);return[c,i,u,e.length>3?e[3]:1]},ju=(...e)=>{const t=Aa(T(e,"hcl"));return zn(...t)},{sqrt:Bu,atan2:Gu,round:Iu}=Math,ja=(...e)=>{const[t,r,n]=T(e,"lab"),o=Bu(r*r+n*n);let a=(Gu(n,r)*xu+360)%360;return Iu(o*1e4)===0&&(a=Number.NaN),[t,o,a]},Fn=(...e)=>{const[t,r,n,...o]=T(e,"rgb"),[a,s,c]=Bn(t,r,n),[i,u,l]=ja(a,s,c);return[i,u,l,...o.length>0&&o[0]<1?[o[0]]:[]]};k.prototype.lch=function(){return Fn(this._rgb)},k.prototype.hcl=function(){return Aa(Fn(this._rgb))},Object.assign(G,{lch:(...e)=>new k(...e,"lch"),hcl:(...e)=>new k(...e,"hcl")}),E.format.lch=zn,E.format.hcl=ju,["lch","hcl"].forEach(e=>E.autodetect.push({p:2,test:(...t)=>{if(t=T(t,e),B(t)==="array"&&t.length===3)return e}})),k.prototype.saturate=function(e=1){const t=this,r=t.lch();return r[1]+=_e.Kn*e,r[1]<0&&(r[1]=0),new k(r,"lch").alpha(t.alpha(),!0)},k.prototype.desaturate=function(e=1){return this.saturate(-e)},k.prototype.set=function(e,t,r=!1){const[n,o]=e.split("."),a=this[n]();if(o){const s=n.indexOf(o)-(n.substr(0,2)==="ok"?2:0);if(s>-1){if(B(t)=="string")switch(t.charAt(0)){case"+":a[s]+=+t;break;case"-":a[s]+=+t;break;case"*":a[s]*=+t.substr(1);break;case"/":a[s]/=+t.substr(1);break;default:a[s]=+t}else if(B(t)==="number")a[s]=t;else throw new Error("unsupported value for Color.set");const c=new k(a,n);return r?(this._rgb=c._rgb,this):c}throw new Error(`unknown channel ${o} in mode ${n}`)}else return a},k.prototype.tint=function(e=.5,...t){return Ue(this,"white",e,...t)},k.prototype.shade=function(e=.5,...t){return Ue(this,"black",e,...t)};const zu=(e,t,r)=>{const n=e._rgb,o=t._rgb;return new k(n[0]+r*(o[0]-n[0]),n[1]+r*(o[1]-n[1]),n[2]+r*(o[2]-n[2]),"rgb")};ne.rgb=zu;const{sqrt:Xn,pow:Qe}=Math,Fu=(e,t,r)=>{const[n,o,a]=e._rgb,[s,c,i]=t._rgb;return new k(Xn(Qe(n,2)*(1-r)+Qe(s,2)*r),Xn(Qe(o,2)*(1-r)+Qe(c,2)*r),Xn(Qe(a,2)*(1-r)+Qe(i,2)*r),"rgb")};ne.lrgb=Fu;const Xu=(e,t,r)=>{const n=e.lab(),o=t.lab();return new k(n[0]+r*(o[0]-n[0]),n[1]+r*(o[1]-n[1]),n[2]+r*(o[2]-n[2]),"lab")};ne.lab=Xu;const et=(e,t,r,n)=>{let o,a;n==="hsl"?(o=e.hsl(),a=t.hsl()):n==="hsv"?(o=e.hsv(),a=t.hsv()):n==="hcg"?(o=e.hcg(),a=t.hcg()):n==="hsi"?(o=e.hsi(),a=t.hsi()):n==="lch"||n==="hcl"?(n="hcl",o=e.hcl(),a=t.hcl()):n==="oklch"&&(o=e.oklch().reverse(),a=t.oklch().reverse());let s,c,i,u,l,f;(n.substr(0,1)==="h"||n==="oklch")&&([s,i,l]=o,[c,u,f]=a);let h,d,b,_;return!isNaN(s)&&!isNaN(c)?(c>s&&c-s>180?_=c-(s+360):c180?_=c+360-s:_=c-s,d=s+r*_):isNaN(s)?isNaN(c)?d=Number.NaN:(d=c,(l==1||l==0)&&n!="hsv"&&(h=u)):(d=s,(f==1||f==0)&&n!="hsv"&&(h=i)),h===void 0&&(h=i+r*(u-i)),b=l+r*(f-l),n==="oklch"?new k([b,h,d],n):new k([d,h,b],n)},Ba=(e,t,r)=>et(e,t,r,"lch");ne.lch=Ba,ne.hcl=Ba;const Ku=e=>{if(B(e)=="number"&&e>=0&&e<=16777215){const t=e>>16,r=e>>8&255,n=e&255;return[t,r,n,1]}throw new Error("unknown num color: "+e)},Du=(...e)=>{const[t,r,n]=T(e,"rgb");return(t<<16)+(r<<8)+n};k.prototype.num=function(){return Du(this._rgb)},Object.assign(G,{num:(...e)=>new k(...e,"num")}),E.format.num=Ku,E.autodetect.push({p:5,test:(...e)=>{if(e.length===1&&B(e[0])==="number"&&e[0]>=0&&e[0]<=16777215)return"num"}});const Vu=(e,t,r)=>{const n=e.num(),o=t.num();return new k(n+r*(o-n),"num")};ne.num=Vu;const{floor:Yu}=Math,Zu=(...e)=>{e=T(e,"hcg");let[t,r,n]=e,o,a,s;n=n*255;const c=r*255;if(r===0)o=a=s=n;else{t===360&&(t=0),t>360&&(t-=360),t<0&&(t+=360),t/=60;const i=Yu(t),u=t-i,l=n*(1-r),f=l+c*(1-u),h=l+c*u,d=l+c;switch(i){case 0:[o,a,s]=[d,h,l];break;case 1:[o,a,s]=[f,d,l];break;case 2:[o,a,s]=[l,d,h];break;case 3:[o,a,s]=[l,f,d];break;case 4:[o,a,s]=[h,l,d];break;case 5:[o,a,s]=[d,l,f];break}}return[o,a,s,e.length>3?e[3]:1]},Ju=(...e)=>{const[t,r,n]=T(e,"rgb"),o=Oa(t,r,n),a=Na(t,r,n),s=a-o,c=s*100/255,i=o/(255-s)*100;let u;return s===0?u=Number.NaN:(t===a&&(u=(r-n)/s),r===a&&(u=2+(n-t)/s),n===a&&(u=4+(t-r)/s),u*=60,u<0&&(u+=360)),[u,c,i]};k.prototype.hcg=function(){return Ju(this._rgb)};const Wu=(...e)=>new k(...e,"hcg");G.hcg=Wu,E.format.hcg=Zu,E.autodetect.push({p:1,test:(...e)=>{if(e=T(e,"hcg"),B(e)==="array"&&e.length===3)return"hcg"}});const Uu=(e,t,r)=>et(e,t,r,"hcg");ne.hcg=Uu;const{cos:tt}=Math,Qu=(...e)=>{e=T(e,"hsi");let[t,r,n]=e,o,a,s;return isNaN(t)&&(t=0),isNaN(r)&&(r=0),t>360&&(t-=360),t<0&&(t+=360),t/=360,t<1/3?(s=(1-r)/3,o=(1+r*tt(Ce*t)/tt(Sn-Ce*t))/3,a=1-(s+o)):t<2/3?(t-=1/3,o=(1-r)/3,a=(1+r*tt(Ce*t)/tt(Sn-Ce*t))/3,s=1-(o+a)):(t-=2/3,a=(1-r)/3,s=(1+r*tt(Ce*t)/tt(Sn-Ce*t))/3,o=1-(a+s)),o=Be(n*o*3),a=Be(n*a*3),s=Be(n*s*3),[o*255,a*255,s*255,e.length>3?e[3]:1]},{min:ef,sqrt:tf,acos:rf}=Math,nf=(...e)=>{let[t,r,n]=T(e,"rgb");t/=255,r/=255,n/=255;let o;const a=ef(t,r,n),s=(t+r+n)/3,c=s>0?1-a/s:0;return c===0?o=NaN:(o=(t-r+(t-n))/2,o/=tf((t-r)*(t-r)+(t-n)*(r-n)),o=rf(o),n>r&&(o=Ce-o),o/=Ce),[o*360,c,s]};k.prototype.hsi=function(){return nf(this._rgb)};const of=(...e)=>new k(...e,"hsi");G.hsi=of,E.format.hsi=Qu,E.autodetect.push({p:2,test:(...e)=>{if(e=T(e,"hsi"),B(e)==="array"&&e.length===3)return"hsi"}});const sf=(e,t,r)=>et(e,t,r,"hsi");ne.hsi=sf;const Kn=(...e)=>{e=T(e,"hsl");const[t,r,n]=e;let o,a,s;if(r===0)o=a=s=n*255;else{const c=[0,0,0],i=[0,0,0],u=n<.5?n*(1+r):n+r-n*r,l=2*n-u,f=t/360;c[0]=f+1/3,c[1]=f,c[2]=f-1/3;for(let h=0;h<3;h++)c[h]<0&&(c[h]+=1),c[h]>1&&(c[h]-=1),6*c[h]<1?i[h]=l+(u-l)*6*c[h]:2*c[h]<1?i[h]=u:3*c[h]<2?i[h]=l+(u-l)*(2/3-c[h])*6:i[h]=l;[o,a,s]=[i[0]*255,i[1]*255,i[2]*255]}return e.length>3?[o,a,s,e[3]]:[o,a,s,1]},Ga=(...e)=>{e=T(e,"rgba");let[t,r,n]=e;t/=255,r/=255,n/=255;const o=Oa(t,r,n),a=Na(t,r,n),s=(a+o)/2;let c,i;return a===o?(c=0,i=Number.NaN):c=s<.5?(a-o)/(a+o):(a-o)/(2-a-o),t==a?i=(r-n)/(a-o):r==a?i=2+(n-t)/(a-o):n==a&&(i=4+(t-r)/(a-o)),i*=60,i<0&&(i+=360),e.length>3&&e[3]!==void 0?[i,c,s,e[3]]:[i,c,s]};k.prototype.hsl=function(){return Ga(this._rgb)};const af=(...e)=>new k(...e,"hsl");G.hsl=af,E.format.hsl=Kn,E.autodetect.push({p:2,test:(...e)=>{if(e=T(e,"hsl"),B(e)==="array"&&e.length===3)return"hsl"}});const cf=(e,t,r)=>et(e,t,r,"hsl");ne.hsl=cf;const{floor:uf}=Math,ff=(...e)=>{e=T(e,"hsv");let[t,r,n]=e,o,a,s;if(n*=255,r===0)o=a=s=n;else{t===360&&(t=0),t>360&&(t-=360),t<0&&(t+=360),t/=60;const c=uf(t),i=t-c,u=n*(1-r),l=n*(1-r*i),f=n*(1-r*(1-i));switch(c){case 0:[o,a,s]=[n,f,u];break;case 1:[o,a,s]=[l,n,u];break;case 2:[o,a,s]=[u,n,f];break;case 3:[o,a,s]=[u,l,n];break;case 4:[o,a,s]=[f,u,n];break;case 5:[o,a,s]=[n,u,l];break}}return[o,a,s,e.length>3?e[3]:1]},{min:lf,max:hf}=Math,df=(...e)=>{e=T(e,"rgb");let[t,r,n]=e;const o=lf(t,r,n),a=hf(t,r,n),s=a-o;let c,i,u;return u=a/255,a===0?(c=Number.NaN,i=0):(i=s/a,t===a&&(c=(r-n)/s),r===a&&(c=2+(n-t)/s),n===a&&(c=4+(t-r)/s),c*=60,c<0&&(c+=360)),[c,i,u]};k.prototype.hsv=function(){return df(this._rgb)};const bf=(...e)=>new k(...e,"hsv");G.hsv=bf,E.format.hsv=ff,E.autodetect.push({p:2,test:(...e)=>{if(e=T(e,"hsv"),B(e)==="array"&&e.length===3)return"hsv"}});const pf=(e,t,r)=>et(e,t,r,"hsv");ne.hsv=pf;function Pt(e,t){let r=e.length;Array.isArray(e[0])||(e=[e]),Array.isArray(t[0])||(t=t.map(s=>[s]));let n=t[0].length,o=t[0].map((s,c)=>t.map(i=>i[c])),a=e.map(s=>o.map(c=>Array.isArray(s)?s.reduce((i,u,l)=>i+u*(c[l]||0),0):c.reduce((i,u)=>i+u*s,0)));return r===1&&(a=a[0]),n===1?a.map(s=>s[0]):a}const Dn=(...e)=>{e=T(e,"lab");const[t,r,n,...o]=e,[a,s,c]=mf([t,r,n]),[i,u,l]=Ta(a,s,c);return[i,u,l,...o.length>0&&o[0]<1?[o[0]]:[]]};function mf(e){var t=[[1.2268798758459243,-.5578149944602171,.2813910456659647],[-.0405757452148008,1.112286803280317,-.0717110580655164],[-.0763729366746601,-.4214933324022432,1.5869240198367816]],r=[[1,.3963377773761749,.2158037573099136],[1,-.1055613458156586,-.0638541728258133],[1,-.0894841775298119,-1.2914855480194092]],n=Pt(r,e);return Pt(t,n.map(o=>o**3))}const Vn=(...e)=>{const[t,r,n,...o]=T(e,"rgb"),a=Sa(t,r,n);return[...gf(a),...o.length>0&&o[0]<1?[o[0]]:[]]};function gf(e){const t=[[.819022437996703,.3619062600528904,-.1288737815209879],[.0329836539323885,.9292868615863434,.0361446663506424],[.0481771893596242,.2642395317527308,.6335478284694309]],r=[[.210454268309314,.7936177747023054,-.0040720430116193],[1.9779985324311684,-2.42859224204858,.450593709617411],[.0259040424655478,.7827717124575296,-.8086757549230774]],n=Pt(t,e);return Pt(r,n.map(o=>Math.cbrt(o)))}k.prototype.oklab=function(){return Vn(this._rgb)},Object.assign(G,{oklab:(...e)=>new k(...e,"oklab")}),E.format.oklab=Dn,E.autodetect.push({p:2,test:(...e)=>{if(e=T(e,"oklab"),B(e)==="array"&&e.length===3)return"oklab"}});const vf=(e,t,r)=>{const n=e.oklab(),o=t.oklab();return new k(n[0]+r*(o[0]-n[0]),n[1]+r*(o[1]-n[1]),n[2]+r*(o[2]-n[2]),"oklab")};ne.oklab=vf;const _f=(e,t,r)=>et(e,t,r,"oklch");ne.oklch=_f;const{pow:Yn,sqrt:Zn,PI:Jn,cos:Ia,sin:za,atan2:yf}=Math,wf=(e,t="lrgb",r=null)=>{const n=e.length;r||(r=Array.from(new Array(n)).map(()=>1));const o=n/r.reduce(function(f,h){return f+h});if(r.forEach((f,h)=>{r[h]*=o}),e=e.map(f=>new k(f)),t==="lrgb")return kf(e,r);const a=e.shift(),s=a.get(t),c=[];let i=0,u=0;for(let f=0;f{const d=f.get(t);l+=f.alpha()*r[h+1];for(let b=0;b=360;)h-=360;s[f]=h}else s[f]=s[f]/c[f];return l/=n,new k(s,t).alpha(l>.99999?1:l,!0)},kf=(e,t)=>{const r=e.length,n=[0,0,0,0];for(let o=0;o.9999999&&(n[3]=1),new k(En(n))},{pow:$f}=Math;function jt(e){let t="rgb",r=G("#ccc"),n=0,o=[0,1],a=[0,1],s=[],c=[0,0],i=!1,u=[],l=!1,f=0,h=1,d=!1,b={},_=!0,g=1;const v=function(p){if(p=p||["#fff","#000"],p&&B(p)==="string"&&G.brewer&&G.brewer[p.toLowerCase()]&&(p=G.brewer[p.toLowerCase()]),B(p)==="array"){p.length===1&&(p=[p[0],p[0]]),p=p.slice(0);for(let y=0;y=i[w];)w++;return w-1}return 0};let x=p=>p,N=p=>p;const A=function(p,y){let w,C;if(y==null&&(y=!1),isNaN(p)||p===null)return r;y?C=p:i&&i.length>2?C=H(p)/(i.length-2):h!==f?C=(p-f)/(h-f):C=1,C=N(C),y||(C=x(C)),g!==1&&(C=$f(C,g)),C=c[0]+C*(1-c[0]-c[1]),C=Be(C,0,1);const q=Math.floor(C*1e4);if(_&&b[q])w=b[q];else{if(B(u)==="array")for(let M=0;M=S&&M===s.length-1){w=u[M];break}if(C>S&&Cb={};v(e);const m=function(p){const y=G(A(p));return l&&y[l]?y[l]():y};return m.classes=function(p){if(p!=null){if(B(p)==="array")i=p,o=[p[0],p[p.length-1]];else{const y=G.analyze(o);p===0?i=[y.min,y.max]:i=G.limits(y,"e",p)}return m}return i},m.domain=function(p){if(!arguments.length)return a;a=p.slice(0),f=p[0],h=p[p.length-1],s=[];const y=u.length;if(p.length===y&&f!==h)for(let w of Array.from(p))s.push((w-f)/(h-f));else{for(let w=0;w2){const w=p.map((q,M)=>M/(p.length-1)),C=p.map(q=>(q-f)/(h-f));C.every((q,M)=>w[M]===q)||(N=q=>{if(q<=0||q>=1)return q;let M=0;for(;q>=C[M+1];)M++;const S=(q-C[M])/(C[M+1]-C[M]);return w[M]+S*(w[M+1]-w[M])})}}return o=[f,h],m},m.mode=function(p){return arguments.length?(t=p,R(),m):t},m.range=function(p,y){return v(p),m},m.out=function(p){return l=p,m},m.spread=function(p){return arguments.length?(n=p,m):n},m.correctLightness=function(p){return p==null&&(p=!0),d=p,R(),d?x=function(y){const w=A(0,!0).lab()[0],C=A(1,!0).lab()[0],q=w>C;let M=A(y,!0).lab()[0];const S=w+(C-w)*y;let X=M-S,D=0,U=1,ce=20;for(;Math.abs(X)>.01&&ce-- >0;)(function(){return q&&(X*=-1),X<0?(D=y,y+=(U-y)*.5):(U=y,y+=(D-y)*.5),M=A(y,!0).lab()[0],X=M-S})();return y}:x=y=>y,m},m.padding=function(p){return p!=null?(B(p)==="number"&&(p=[p,p]),c=p,m):c},m.colors=function(p,y){arguments.length<2&&(y="hex");let w=[];if(arguments.length===0)w=u.slice(0);else if(p===1)w=[m(.5)];else if(p>1){const C=o[0],q=o[1]-C;w=Cf(0,p).map(M=>m(C+M/(p-1)*q))}else{e=[];let C=[];if(i&&i.length>2)for(let q=1,M=i.length,S=1<=M;S?qM;S?q++:q--)C.push((i[q-1]+i[q])*.5);else C=o;w=C.map(q=>m(q))}return G[y]&&(w=w.map(C=>C[y]())),w},m.cache=function(p){return p!=null?(_=p,m):_},m.gamma=function(p){return p!=null?(g=p,m):g},m.nodata=function(p){return p!=null?(r=G(p),m):r},m}function Cf(e,t,r){let n=[],o=ea;o?s++:s--)n.push(s);return n}const xf=function(e){let t=[1,1];for(let r=1;rnew k(a)),e.length===2)[r,n]=e.map(a=>a.lab()),t=function(a){const s=[0,1,2].map(c=>r[c]+a*(n[c]-r[c]));return new k(s,"lab")};else if(e.length===3)[r,n,o]=e.map(a=>a.lab()),t=function(a){const s=[0,1,2].map(c=>(1-a)*(1-a)*r[c]+2*(1-a)*a*n[c]+a*a*o[c]);return new k(s,"lab")};else if(e.length===4){let a;[r,n,o,a]=e.map(s=>s.lab()),t=function(s){const c=[0,1,2].map(i=>(1-s)*(1-s)*(1-s)*r[i]+3*(1-s)*(1-s)*s*n[i]+3*(1-s)*s*s*o[i]+s*s*s*a[i]);return new k(c,"lab")}}else if(e.length>=5){let a,s,c;a=e.map(i=>i.lab()),c=e.length-1,s=xf(c),t=function(i){const u=1-i,l=[0,1,2].map(f=>a.reduce((h,d,b)=>h+s[b]*u**(c-b)*i**b*d[f],0));return new k(l,"lab")}}else throw new RangeError("No point in running bezier with only one color.");return t},Hf=e=>{const t=Rf(e);return t.scale=()=>jt(t),t},{round:Fa}=Math;k.prototype.rgb=function(e=!0){return e===!1?this._rgb.slice(0,3):this._rgb.slice(0,3).map(Fa)},k.prototype.rgba=function(e=!0){return this._rgb.slice(0,4).map((t,r)=>r<3?e===!1?t:Fa(t):t)},Object.assign(G,{rgb:(...e)=>new k(...e,"rgb")}),E.format.rgb=(...e)=>{const t=T(e,"rgba");return t[3]===void 0&&(t[3]=1),t},E.autodetect.push({p:3,test:(...e)=>{if(e=T(e,"rgba"),B(e)==="array"&&(e.length===3||e.length===4&&B(e[3])=="number"&&e[3]>=0&&e[3]<=1))return"rgb"}});const me=(e,t,r)=>{if(!me[r])throw new Error("unknown blend mode "+r);return me[r](e,t)},Te=e=>(t,r)=>{const n=G(r).rgb(),o=G(t).rgb();return G.rgb(e(n,o))},Se=e=>(t,r)=>{const n=[];return n[0]=e(t[0],r[0]),n[1]=e(t[1],r[1]),n[2]=e(t[2],r[2]),n},qf=e=>e,Mf=(e,t)=>e*t/255,Of=(e,t)=>e>t?t:e,Nf=(e,t)=>e>t?e:t,Af=(e,t)=>255*(1-(1-e/255)*(1-t/255)),Lf=(e,t)=>t<128?2*e*t/255:255*(1-2*(1-e/255)*(1-t/255)),Ef=(e,t)=>255*(1-(1-t/255)/(e/255)),Tf=(e,t)=>e===255?255:(e=255*(t/255)/(1-e/255),e>255?255:e);me.normal=Te(Se(qf)),me.multiply=Te(Se(Mf)),me.screen=Te(Se(Af)),me.overlay=Te(Se(Lf)),me.darken=Te(Se(Of)),me.lighten=Te(Se(Nf)),me.dodge=Te(Se(Tf)),me.burn=Te(Se(Ef));const{pow:Sf,sin:Pf,cos:jf}=Math;function Bf(e=300,t=-1.5,r=1,n=1,o=[0,1]){let a=0,s;B(o)==="array"?s=o[1]-o[0]:(s=0,o=[o,o]);const c=function(i){const u=Ce*((e+120)/360+t*i),l=Sf(o[0]+s*i,n),h=(a!==0?r[0]+i*a:r)*l*(1-l)/2,d=jf(u),b=Pf(u),_=l+h*(-.14861*d+1.78277*b),g=l+h*(-.29227*d-.90649*b),v=l+h*(1.97294*d);return G(En([_*255,g*255,v*255,1]))};return c.start=function(i){return i==null?e:(e=i,c)},c.rotations=function(i){return i==null?t:(t=i,c)},c.gamma=function(i){return i==null?n:(n=i,c)},c.hue=function(i){return i==null?r:(r=i,B(r)==="array"?(a=r[1]-r[0],a===0&&(r=r[1])):a=0,c)},c.lightness=function(i){return i==null?o:(B(i)==="array"?(o=i,s=i[1]-i[0]):(o=[i,i],s=0),c)},c.scale=()=>G.scale(c),c.hue(r),c}const Gf="0123456789abcdef",{floor:If,random:zf}=Math,Ff=(e=zf)=>{let t="#";for(let r=0;r<6;r++)t+=Gf.charAt(If(e()*16));return new k(t,"hex")},{log:Xa,pow:Xf,floor:Kf,abs:Df}=Math;function Ka(e,t=null){const r={min:Number.MAX_VALUE,max:Number.MAX_VALUE*-1,sum:0,values:[],count:0};return B(e)==="object"&&(e=Object.values(e)),e.forEach(n=>{t&&B(n)==="object"&&(n=n[t]),n!=null&&!isNaN(n)&&(r.values.push(n),r.sum+=n,nr.max&&(r.max=n),r.count+=1)}),r.domain=[r.min,r.max],r.limits=(n,o)=>Da(r,n,o),r}function Da(e,t="equal",r=7){B(e)=="array"&&(e=Ka(e));const{min:n,max:o}=e,a=e.values.sort((c,i)=>c-i);if(r===1)return[n,o];const s=[];if(t.substr(0,1)==="c"&&(s.push(n),s.push(o)),t.substr(0,1)==="e"){s.push(n);for(let c=1;c 0");const c=Math.LOG10E*Xa(n),i=Math.LOG10E*Xa(o);s.push(n);for(let u=1;u200&&(f=!1)}const b={};for(let g=0;gg-v),s.push(_[0]);for(let g=1;g<_.length;g+=2){const v=_[g];!isNaN(v)&&s.indexOf(v)===-1&&s.push(v)}}return s}const Vf=(e,t)=>{e=new k(e),t=new k(t);const r=e.luminance(),n=t.luminance();return r>n?(r+.05)/(n+.05):(n+.05)/(r+.05)};const Va=.027,Yf=5e-4,Zf=.1,Ya=1.14,Bt=.022,Za=1.414,Jf=(e,t)=>{e=new k(e),t=new k(t),e.alpha()<1&&(e=Ue(t,e,e.alpha(),"rgb"));const r=Ja(...e.rgb()),n=Ja(...t.rgb()),o=r>=Bt?r:r+Math.pow(Bt-r,Za),a=n>=Bt?n:n+Math.pow(Bt-n,Za),s=Math.pow(a,.56)-Math.pow(o,.57),c=Math.pow(a,.65)-Math.pow(o,.62),i=Math.abs(a-o)0?i-Va:i+Va)*100};function Ja(e,t,r){return .2126729*Math.pow(e/255,2.4)+.7151522*Math.pow(t/255,2.4)+.072175*Math.pow(r/255,2.4)}const{sqrt:Re,pow:Z,min:Wf,max:Uf,atan2:Wa,abs:Ua,cos:Gt,sin:Qa,exp:Qf,PI:ec}=Math;function el(e,t,r=1,n=1,o=1){var a=function(he){return 360*he/(2*ec)},s=function(he){return 2*ec*he/360};e=new k(e),t=new k(t);const[c,i,u]=Array.from(e.lab()),[l,f,h]=Array.from(t.lab()),d=(c+l)/2,b=Re(Z(i,2)+Z(u,2)),_=Re(Z(f,2)+Z(h,2)),g=(b+_)/2,v=.5*(1-Re(Z(g,7)/(Z(g,7)+Z(25,7)))),H=i*(1+v),x=f*(1+v),N=Re(Z(H,2)+Z(u,2)),A=Re(Z(x,2)+Z(h,2)),R=(N+A)/2,m=a(Wa(u,H)),p=a(Wa(h,x)),y=m>=0?m:m+360,w=p>=0?p:p+360,C=Ua(y-w)>180?(y+w+360)/2:(y+w)/2,q=1-.17*Gt(s(C-30))+.24*Gt(s(2*C))+.32*Gt(s(3*C+6))-.2*Gt(s(4*C-63));let M=w-y;M=Ua(M)<=180?M:w<=y?M+360:M-360,M=2*Re(N*A)*Qa(s(M)/2);const S=l-c,X=A-N,D=1+.015*Z(d-50,2)/Re(20+Z(d-50,2)),U=1+.045*R,ce=1+.015*R*q,ye=30*Qf(-Z((C-275)/25,2)),le=-(2*Re(Z(R,7)/(Z(R,7)+Z(25,7))))*Qa(2*s(ye)),qe=Re(Z(S/(r*D),2)+Z(X/(n*U),2)+Z(M/(o*ce),2)+le*(X/(n*U))*(M/(o*ce)));return Uf(0,Wf(100,qe))}function tl(e,t,r="lab"){e=new k(e),t=new k(t);const n=e.get(r),o=t.get(r);let a=0;for(let s in n){const c=(n[s]||0)-(o[s]||0);a+=c*c}return Math.sqrt(a)}const rl=(...e)=>{try{return new k(...e),!0}catch{return!1}},nl={cool(){return jt([G.hsl(180,1,.9),G.hsl(250,.7,.4)])},hot(){return jt(["#000","#f00","#ff0","#fff"]).mode("rgb")}},Wn={OrRd:["#fff7ec","#fee8c8","#fdd49e","#fdbb84","#fc8d59","#ef6548","#d7301f","#b30000","#7f0000"],PuBu:["#fff7fb","#ece7f2","#d0d1e6","#a6bddb","#74a9cf","#3690c0","#0570b0","#045a8d","#023858"],BuPu:["#f7fcfd","#e0ecf4","#bfd3e6","#9ebcda","#8c96c6","#8c6bb1","#88419d","#810f7c","#4d004b"],Oranges:["#fff5eb","#fee6ce","#fdd0a2","#fdae6b","#fd8d3c","#f16913","#d94801","#a63603","#7f2704"],BuGn:["#f7fcfd","#e5f5f9","#ccece6","#99d8c9","#66c2a4","#41ae76","#238b45","#006d2c","#00441b"],YlOrBr:["#ffffe5","#fff7bc","#fee391","#fec44f","#fe9929","#ec7014","#cc4c02","#993404","#662506"],YlGn:["#ffffe5","#f7fcb9","#d9f0a3","#addd8e","#78c679","#41ab5d","#238443","#006837","#004529"],Reds:["#fff5f0","#fee0d2","#fcbba1","#fc9272","#fb6a4a","#ef3b2c","#cb181d","#a50f15","#67000d"],RdPu:["#fff7f3","#fde0dd","#fcc5c0","#fa9fb5","#f768a1","#dd3497","#ae017e","#7a0177","#49006a"],Greens:["#f7fcf5","#e5f5e0","#c7e9c0","#a1d99b","#74c476","#41ab5d","#238b45","#006d2c","#00441b"],YlGnBu:["#ffffd9","#edf8b1","#c7e9b4","#7fcdbb","#41b6c4","#1d91c0","#225ea8","#253494","#081d58"],Purples:["#fcfbfd","#efedf5","#dadaeb","#bcbddc","#9e9ac8","#807dba","#6a51a3","#54278f","#3f007d"],GnBu:["#f7fcf0","#e0f3db","#ccebc5","#a8ddb5","#7bccc4","#4eb3d3","#2b8cbe","#0868ac","#084081"],Greys:["#ffffff","#f0f0f0","#d9d9d9","#bdbdbd","#969696","#737373","#525252","#252525","#000000"],YlOrRd:["#ffffcc","#ffeda0","#fed976","#feb24c","#fd8d3c","#fc4e2a","#e31a1c","#bd0026","#800026"],PuRd:["#f7f4f9","#e7e1ef","#d4b9da","#c994c7","#df65b0","#e7298a","#ce1256","#980043","#67001f"],Blues:["#f7fbff","#deebf7","#c6dbef","#9ecae1","#6baed6","#4292c6","#2171b5","#08519c","#08306b"],PuBuGn:["#fff7fb","#ece2f0","#d0d1e6","#a6bddb","#67a9cf","#3690c0","#02818a","#016c59","#014636"],Viridis:["#440154","#482777","#3f4a8a","#31678e","#26838f","#1f9d8a","#6cce5a","#b6de2b","#fee825"],Spectral:["#9e0142","#d53e4f","#f46d43","#fdae61","#fee08b","#ffffbf","#e6f598","#abdda4","#66c2a5","#3288bd","#5e4fa2"],RdYlGn:["#a50026","#d73027","#f46d43","#fdae61","#fee08b","#ffffbf","#d9ef8b","#a6d96a","#66bd63","#1a9850","#006837"],RdBu:["#67001f","#b2182b","#d6604d","#f4a582","#fddbc7","#f7f7f7","#d1e5f0","#92c5de","#4393c3","#2166ac","#053061"],PiYG:["#8e0152","#c51b7d","#de77ae","#f1b6da","#fde0ef","#f7f7f7","#e6f5d0","#b8e186","#7fbc41","#4d9221","#276419"],PRGn:["#40004b","#762a83","#9970ab","#c2a5cf","#e7d4e8","#f7f7f7","#d9f0d3","#a6dba0","#5aae61","#1b7837","#00441b"],RdYlBu:["#a50026","#d73027","#f46d43","#fdae61","#fee090","#ffffbf","#e0f3f8","#abd9e9","#74add1","#4575b4","#313695"],BrBG:["#543005","#8c510a","#bf812d","#dfc27d","#f6e8c3","#f5f5f5","#c7eae5","#80cdc1","#35978f","#01665e","#003c30"],RdGy:["#67001f","#b2182b","#d6604d","#f4a582","#fddbc7","#ffffff","#e0e0e0","#bababa","#878787","#4d4d4d","#1a1a1a"],PuOr:["#7f3b08","#b35806","#e08214","#fdb863","#fee0b6","#f7f7f7","#d8daeb","#b2abd2","#8073ac","#542788","#2d004b"],Set2:["#66c2a5","#fc8d62","#8da0cb","#e78ac3","#a6d854","#ffd92f","#e5c494","#b3b3b3"],Accent:["#7fc97f","#beaed4","#fdc086","#ffff99","#386cb0","#f0027f","#bf5b17","#666666"],Set1:["#e41a1c","#377eb8","#4daf4a","#984ea3","#ff7f00","#ffff33","#a65628","#f781bf","#999999"],Set3:["#8dd3c7","#ffffb3","#bebada","#fb8072","#80b1d3","#fdb462","#b3de69","#fccde5","#d9d9d9","#bc80bd","#ccebc5","#ffed6f"],Dark2:["#1b9e77","#d95f02","#7570b3","#e7298a","#66a61e","#e6ab02","#a6761d","#666666"],Paired:["#a6cee3","#1f78b4","#b2df8a","#33a02c","#fb9a99","#e31a1c","#fdbf6f","#ff7f00","#cab2d6","#6a3d9a","#ffff99","#b15928"],Pastel2:["#b3e2cd","#fdcdac","#cbd5e8","#f4cae4","#e6f5c9","#fff2ae","#f1e2cc","#cccccc"],Pastel1:["#fbb4ae","#b3cde3","#ccebc5","#decbe4","#fed9a6","#ffffcc","#e5d8bd","#fddaec","#f2f2f2"]},tc=Object.keys(Wn),rc=new Map(tc.map(e=>[e.toLowerCase(),e])),ol=typeof Proxy=="function"?new Proxy(Wn,{get(e,t){const r=t.toLowerCase();if(rc.has(r))return e[rc.get(r)]},getOwnPropertyNames(){return Object.getOwnPropertyNames(tc)}}):Wn,sl=(...e)=>{e=T(e,"cmyk");const[t,r,n,o]=e,a=e.length>4?e[4]:1;return o===1?[0,0,0,a]:[t>=1?0:255*(1-t)*(1-o),r>=1?0:255*(1-r)*(1-o),n>=1?0:255*(1-n)*(1-o),a]},{max:nc}=Math,al=(...e)=>{let[t,r,n]=T(e,"rgb");t=t/255,r=r/255,n=n/255;const o=1-nc(t,nc(r,n)),a=o<1?1/(1-o):0,s=(1-t-o)*a,c=(1-r-o)*a,i=(1-n-o)*a;return[s,c,i,o]};k.prototype.cmyk=function(){return al(this._rgb)},Object.assign(G,{cmyk:(...e)=>new k(...e,"cmyk")}),E.format.cmyk=sl,E.autodetect.push({p:2,test:(...e)=>{if(e=T(e,"cmyk"),B(e)==="array"&&e.length===4)return"cmyk"}});const cl=(...e)=>{const t=T(e,"hsla");let r=Je(e)||"lsa";return t[0]=ue(t[0]||0)+"deg",t[1]=ue(t[1]*100)+"%",t[2]=ue(t[2]*100)+"%",r==="hsla"||t.length>3&&t[3]<1?(t[3]="/ "+(t.length>3?t[3]:1),r="hsla"):t.length=3,`${r.substr(0,3)}(${t.join(" ")})`},il=(...e)=>{const t=T(e,"lab");let r=Je(e)||"lab";return t[0]=ue(t[0])+"%",t[1]=ue(t[1]),t[2]=ue(t[2]),r==="laba"||t.length>3&&t[3]<1?t[3]="/ "+(t.length>3?t[3]:1):t.length=3,`lab(${t.join(" ")})`},ul=(...e)=>{const t=T(e,"lch");let r=Je(e)||"lab";return t[0]=ue(t[0])+"%",t[1]=ue(t[1]),t[2]=isNaN(t[2])?"none":ue(t[2])+"deg",r==="lcha"||t.length>3&&t[3]<1?t[3]="/ "+(t.length>3?t[3]:1):t.length=3,`lch(${t.join(" ")})`},fl=(...e)=>{const t=T(e,"lab");return t[0]=ue(t[0]*100)+"%",t[1]=Tn(t[1]),t[2]=Tn(t[2]),t.length>3&&t[3]<1?t[3]="/ "+(t.length>3?t[3]:1):t.length=3,`oklab(${t.join(" ")})`},oc=(...e)=>{const[t,r,n,...o]=T(e,"rgb"),[a,s,c]=Vn(t,r,n),[i,u,l]=ja(a,s,c);return[i,u,l,...o.length>0&&o[0]<1?[o[0]]:[]]},ll=(...e)=>{const t=T(e,"lch");return t[0]=ue(t[0]*100)+"%",t[1]=Tn(t[1]),t[2]=isNaN(t[2])?"none":ue(t[2])+"deg",t.length>3&&t[3]<1?t[3]="/ "+(t.length>3?t[3]:1):t.length=3,`oklch(${t.join(" ")})`},{round:Un}=Math,hl=(...e)=>{const t=T(e,"rgba");let r=Je(e)||"rgb";if(r.substr(0,3)==="hsl")return cl(Ga(t),r);if(r.substr(0,3)==="lab"){const n=dt();xe("d50");const o=il(Bn(t),r);return xe(n),o}if(r.substr(0,3)==="lch"){const n=dt();xe("d50");const o=ul(Fn(t),r);return xe(n),o}return r.substr(0,5)==="oklab"?fl(Vn(t)):r.substr(0,5)==="oklch"?ll(oc(t)):(t[0]=Un(t[0]),t[1]=Un(t[1]),t[2]=Un(t[2]),(r==="rgba"||t.length>3&&t[3]<1)&&(t[3]="/ "+(t.length>3?t[3]:1),r="rgba"),`${r.substr(0,3)}(${t.slice(0,r==="rgb"?3:4).join(" ")})`)},sc=(...e)=>{e=T(e,"lch");const[t,r,n,...o]=e,[a,s,c]=Pa(t,r,n),[i,u,l]=Dn(a,s,c);return[i,u,l,...o.length>0&&o[0]<1?[o[0]]:[]]},He=/((?:-?\d+)|(?:-?\d+(?:\.\d+)?)%|none)/.source,ge=/((?:-?(?:\d+(?:\.\d*)?|\.\d+)%?)|none)/.source,It=/((?:-?(?:\d+(?:\.\d*)?|\.\d+)%)|none)/.source,fe=/\s*/.source,rt=/\s+/.source,Qn=/\s*,\s*/.source,zt=/((?:-?(?:\d+(?:\.\d*)?|\.\d+)(?:deg)?)|none)/.source,nt=/\s*(?:\/\s*((?:[01]|[01]?\.\d+)|\d+(?:\.\d+)?%))?/.source,ac=new RegExp("^rgba?\\("+fe+[He,He,He].join(rt)+nt+"\\)$"),cc=new RegExp("^rgb\\("+fe+[He,He,He].join(Qn)+fe+"\\)$"),ic=new RegExp("^rgba\\("+fe+[He,He,He,ge].join(Qn)+fe+"\\)$"),uc=new RegExp("^hsla?\\("+fe+[zt,It,It].join(rt)+nt+"\\)$"),fc=new RegExp("^hsl?\\("+fe+[zt,It,It].join(Qn)+fe+"\\)$"),lc=/^hsla\(\s*(-?\d+(?:\.\d+)?),\s*(-?\d+(?:\.\d+)?)%\s*,\s*(-?\d+(?:\.\d+)?)%\s*,\s*([01]|[01]?\.\d+)\)$/,hc=new RegExp("^lab\\("+fe+[ge,ge,ge].join(rt)+nt+"\\)$"),dc=new RegExp("^lch\\("+fe+[ge,ge,zt].join(rt)+nt+"\\)$"),bc=new RegExp("^oklab\\("+fe+[ge,ge,ge].join(rt)+nt+"\\)$"),pc=new RegExp("^oklch\\("+fe+[ge,ge,zt].join(rt)+nt+"\\)$"),{round:mc}=Math,ot=e=>e.map((t,r)=>r<=2?Be(mc(t),0,255):t),J=(e,t=0,r=100,n=!1)=>(typeof e=="string"&&e.endsWith("%")&&(e=parseFloat(e.substring(0,e.length-1))/100,n?e=t+(e+1)*.5*(r-t):e=t+e*(r-t)),+e),oe=(e,t)=>e==="none"?t:e,eo=e=>{if(e=e.toLowerCase().trim(),e==="transparent")return[0,0,0,0];let t;if(E.format.named)try{return E.format.named(e)}catch{}if((t=e.match(ac))||(t=e.match(cc))){let r=t.slice(1,4);for(let o=0;o<3;o++)r[o]=+J(oe(r[o],0),0,255);r=ot(r);const n=t[4]!==void 0?+J(t[4],0,1):1;return r[3]=n,r}if(t=e.match(ic)){const r=t.slice(1,5);for(let n=0;n<4;n++)r[n]=+J(r[n],0,255);return r}if((t=e.match(uc))||(t=e.match(fc))){const r=t.slice(1,4);r[0]=+oe(r[0].replace("deg",""),0),r[1]=+J(oe(r[1],0),0,100)*.01,r[2]=+J(oe(r[2],0),0,100)*.01;const n=ot(Kn(r)),o=t[4]!==void 0?+J(t[4],0,1):1;return n[3]=o,n}if(t=e.match(lc)){const r=t.slice(1,4);r[1]*=.01,r[2]*=.01;const n=Kn(r);for(let o=0;o<3;o++)n[o]=mc(n[o]);return n[3]=+t[4],n}if(t=e.match(hc)){const r=t.slice(1,4);r[0]=J(oe(r[0],0),0,100),r[1]=J(oe(r[1],0),-125,125,!0),r[2]=J(oe(r[2],0),-125,125,!0);const n=dt();xe("d50");const o=ot(Pn(r));xe(n);const a=t[4]!==void 0?+J(t[4],0,1):1;return o[3]=a,o}if(t=e.match(dc)){const r=t.slice(1,4);r[0]=J(r[0],0,100),r[1]=J(oe(r[1],0),0,150,!1),r[2]=+oe(r[2].replace("deg",""),0);const n=dt();xe("d50");const o=ot(zn(r));xe(n);const a=t[4]!==void 0?+J(t[4],0,1):1;return o[3]=a,o}if(t=e.match(bc)){const r=t.slice(1,4);r[0]=J(oe(r[0],0),0,1),r[1]=J(oe(r[1],0),-.4,.4,!0),r[2]=J(oe(r[2],0),-.4,.4,!0);const n=ot(Dn(r)),o=t[4]!==void 0?+J(t[4],0,1):1;return n[3]=o,n}if(t=e.match(pc)){const r=t.slice(1,4);r[0]=J(oe(r[0],0),0,1),r[1]=J(oe(r[1],0),0,.4,!1),r[2]=+oe(r[2].replace("deg",""),0);const n=ot(sc(r)),o=t[4]!==void 0?+J(t[4],0,1):1;return n[3]=o,n}};eo.test=e=>ac.test(e)||uc.test(e)||hc.test(e)||dc.test(e)||bc.test(e)||pc.test(e)||cc.test(e)||ic.test(e)||fc.test(e)||lc.test(e)||e==="transparent",k.prototype.css=function(e){return hl(this._rgb,e)};const dl=(...e)=>new k(...e,"css");G.css=dl,E.format.css=eo,E.autodetect.push({p:5,test:(e,...t)=>{if(!t.length&&B(e)==="string"&&eo.test(e))return"css"}}),E.format.gl=(...e)=>{const t=T(e,"rgba");return t[0]*=255,t[1]*=255,t[2]*=255,t};const bl=(...e)=>new k(...e,"gl");G.gl=bl,k.prototype.gl=function(){const e=this._rgb;return[e[0]/255,e[1]/255,e[2]/255,e[3]]},k.prototype.hex=function(e){return Ea(this._rgb,e)};const pl=(...e)=>new k(...e,"hex");G.hex=pl,E.format.hex=La,E.autodetect.push({p:4,test:(e,...t)=>{if(!t.length&&B(e)==="string"&&[3,4,5,6,7,8,9].indexOf(e.length)>=0)return"hex"}});const{log:Ft}=Math,gc=e=>{const t=e/100;let r,n,o;return t<66?(r=255,n=t<6?0:-155.25485562709179-.44596950469579133*(n=t-2)+104.49216199393888*Ft(n),o=t<20?0:-254.76935184120902+.8274096064007395*(o=t-10)+115.67994401066147*Ft(o)):(r=351.97690566805693+.114206453784165*(r=t-55)-40.25366309332127*Ft(r),n=325.4494125711974+.07943456536662342*(n=t-50)-28.0852963507957*Ft(n),o=255),[r,n,o,1]},{round:ml}=Math,gl=(...e)=>{const t=T(e,"rgb"),r=t[0],n=t[2];let o=1e3,a=4e4;const s=.4;let c;for(;a-o>s;){c=(a+o)*.5;const i=gc(c);i[2]/i[0]>=n/r?a=c:o=c}return ml(c)};k.prototype.temp=k.prototype.kelvin=k.prototype.temperature=function(){return gl(this._rgb)};const to=(...e)=>new k(...e,"temp");Object.assign(G,{temp:to,kelvin:to,temperature:to}),E.format.temp=E.format.kelvin=E.format.temperature=gc,k.prototype.oklch=function(){return oc(this._rgb)},Object.assign(G,{oklch:(...e)=>new k(...e,"oklch")}),E.format.oklch=sc,E.autodetect.push({p:2,test:(...e)=>{if(e=T(e,"oklch"),B(e)==="array"&&e.length===3)return"oklch"}}),Object.assign(G,{analyze:Ka,average:wf,bezier:Hf,blend:me,brewer:ol,Color:k,colors:We,contrast:Vf,contrastAPCA:Jf,cubehelix:Bf,deltaE:el,distance:tl,input:E,interpolate:Ue,limits:Da,mix:Ue,random:Ff,scale:jt,scales:nl,valid:rl});function vl(e){return+`${Math.ceil(`${e}e+2`)}e-2`}const vc=e=>{const t=/^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(e);return[Number.parseInt(t[1],16),Number.parseInt(t[2],16),Number.parseInt(t[3],16)]},_c=(e,t,r)=>{const n=e/255,o=t/255,a=r/255,s=Math.min(n,o,a),c=Math.max(n,o,a),i=c-s;let u=0,l=0,f=0;return i===0?u=0:c===n?u=(o-a)/i%6:c===o?u=(a-n)/i+2:u=(n-o)/i+4,u=Math.round(u*60),u<0&&(u+=360),f=(c+s)/2,l=i===0?0:i/(1-Math.abs(2*f-1)),l=+(l*100).toFixed(1),f=+(f*100).toFixed(1),[u,l,Math.round(f)]},_l=(e,t,r,n)=>{const o=r/100,a=t*Math.min(o,1-o)/100,s=d=>{const b=(d+e/30)%12,_=o-a*Math.max(Math.min(b-3,9-b,1),-1);return Math.round(255*_).toString(16).padStart(2,"0").toUpperCase()},c=s(0),i=s(8),u=s(4),f=((d,b,_)=>Math.min(Math.max(d,b),_))(n,0,1),h=Math.round(f*255).toString(16).padStart(2,"0").toUpperCase();return`#${c}${i}${u}${h}`},yl=(e,t,r=1)=>{const n=vc(e),o=vc(t==="white"?"#FFFFFF":t==="black"?"#000000":t),a=n.map((u,l)=>[(u-o[l])/(255-o[l]),(u-o[l])/(0-o[l])]),s=vl(Math.max(...a.flat().filter(u=>/^-?\d+\.?\d*$/.test(u)))),c=n.map((u,l)=>Math.round((u-o[l]+o[l]*s)/s));if(c.includes(Number.NaN)){const u=_c(n[0],n[1],n[2]);return{h:u[0],s:Math.round(u[1]*r),l:u[2],a:1}}const i=_c(c[0],c[1],c[2]);return{h:i[0],s:Math.round(i[1]*r),l:i[2],a:s}},ro={backgroundColor:"gray",colorSpace:"OKLCH",colorSmoothing:!1,formula:"wcag2",output:"HEX",colors:{gray:[K(215,20,90),K(215,8,50),K(215,6,25)],red:[K(358,100,58),K(350,100,30)],orange:[K(32,100,48),K(12,100,30)],yellow:[K(50,100,50),K(25,100,20)],lime:[K(100,68,50),K(115,86,25)],green:[K(163,87,42),K(168,100,25)],cyan:[K(185,80,45),K(200,98,35)],blue:[K(212,98,46),K(222,95,25)],purple:[K(258,94,64),K(265,100,35)],fuchsia:[K(295,56,50),K(285,80,25)],pink:[K(334,90,50),K(330,91,25)]},themes:{light:{ratios:[1.03,1.06,1.12,1.25,1.5,1.75,2.25,3.5,5.25,6.5,8,10.5,13.75,16.75],contrast:1,lightness:100,saturation:100},dark:{ratios:[1.03,1.06,1.12,1.25,1.5,1.75,2.25,3.5,5.25,6.5,8,10.5,13.75,16],contrast:1,lightness:6,saturation:97},lightHc:{ratios:[1.06,1.12,1.25,1.37,1.75,2.25,3.25,4.75,8.87,10,11.75,13.25,16,17],contrast:1,lightness:100,saturation:100},darkHc:{ratios:[1.06,1.12,1.25,1.37,1.75,2.25,3.25,4.75,8.87,10,11.75,13.25,16,17],contrast:1,lightness:6,saturation:97}}};function K(e,t,r){return G.hsl(e,t/100,r/100).hex()}function wl(e,t){const r=e.colorSpace,n=e.colorSmoothing,o=e.themes[t].ratios,a=new qa({name:"gray",colorKeys:e.colors.gray,colorspace:r,ratios:o,smooth:n}),s=new ae({name:"blue",colorKeys:e.colors.blue,colorspace:r,ratios:o,smooth:n}),c=new ae({name:"cyan",colorKeys:e.colors.cyan,colorspace:r,ratios:o,smooth:n}),i=new ae({name:"fuchsia",colorKeys:e.colors.fuchsia,colorspace:r,ratios:o,smooth:n}),u=new ae({name:"green",colorKeys:e.colors.green,colorspace:r,ratios:o,smooth:n}),l=new ae({name:"lime",colorKeys:e.colors.lime,colorspace:r,ratios:o,smooth:n}),f=new ae({name:"orange",colorKeys:e.colors.orange,colorspace:r,ratios:o,smooth:n}),h=new ae({name:"pink",colorKeys:e.colors.pink,colorspace:r,ratios:o,smooth:n}),d=new ae({name:"purple",colorKeys:e.colors.purple,colorspace:r,ratios:o,smooth:n}),b=new ae({name:"red",colorKeys:e.colors.red,colorspace:r,ratios:o,smooth:n}),_=new ae({name:"yellow",colorKeys:e.colors.yellow,colorspace:r,ratios:o,smooth:n}),g={gray:a,red:b,orange:f,yellow:_,lime:l,green:u,cyan:c,blue:s,purple:d,fuchsia:i,pink:h};return e.colors.custom&&(g.custom=new ae({name:"custom",colorKeys:e.colors.custom,colorspace:r,ratios:o,smooth:n})),new wu({colors:Object.values(g),backgroundColor:g[e.backgroundColor],contrast:e.themes[t].contrast,lightness:e.themes[t].lightness,saturation:e.themes[t].saturation,output:e.output,formula:e.formula}).contrastColors}function yc(e){const t={};for(const r of Object.keys(e.themes))t[r]=wl(e,r);return t}function kl(e){ro.colors.custom=[e];const t=yc(ro);return Object.fromEntries(Object.entries(t).map(([r,n])=>{const o=n.find(s=>s&&s.name==="custom"),a=Object.fromEntries(o.values.map(({name:s,value:c})=>[s,c]));for(const[s,c]of Object.entries(a)){const i=yl(c,n[0].background);a[`alpha${s.charAt(0).toUpperCase()+s.slice(1)}`]=_l(i.h,i.s,i.l,i.a)}return[r,a]}))}return Fe.generateCustomColors=kl,Fe.generateThemesJson=yc,Fe.hslToHex=K,Fe.leonardoConfig=ro,Object.defineProperty(Fe,Symbol.toStringTag,{value:"Module"}),Fe})({}); +var CompoundTheme=(function($t){"use strict";const{min:oi,max:si}=Math,qt=(e,t=0,r=1)=>oi(si(t,e),r),xe=e=>{e._clipped=!1,e._unclipped=e.slice(0);for(let t=0;t<=3;t++)t<3?((e[t]<0||e[t]>255)&&(e._clipped=!0),e[t]=qt(e[t],0,255)):t===3&&(e[t]=qt(e[t],0,1));return e},fn={};for(let e of["Boolean","Number","String","Function","Array","Date","RegExp","Undefined","Null"])fn[`[object ${e}]`]=e.toLowerCase();function N(e){return fn[Object.prototype.toString.call(e)]||"object"}const E=(e,t=null)=>e.length>=3?Array.prototype.slice.call(e):N(e[0])=="object"&&t?t.split("").filter(r=>e[0][r]!==void 0).map(r=>e[0][r]):e[0].slice(0),Et=e=>{if(e.length<2)return null;const t=e.length-1;return N(e[t])=="string"?e[t].toLowerCase():null},{PI:Wt,min:hn,max:dn}=Math,et=e=>Math.round(e*100)/100,Ce=e=>Math.round(e*100)/100,ft=Wt*2,ke=Wt/3,ii=Wt/180,ai=180/Wt;function bn(e){return[...e.slice(0,3).reverse(),...e.slice(3)]}const $={format:{},autodetect:[]};let _=class{constructor(...t){const r=this;if(N(t[0])==="object"&&t[0].constructor&&t[0].constructor===this.constructor)return t[0];let n=Et(t),o=!1;if(!n){o=!0,$.sorted||($.autodetect=$.autodetect.sort((i,s)=>s.p-i.p),$.sorted=!0);for(let i of $.autodetect)if(n=i.test(...t),n)break}if($.format[n]){const i=$.format[n].apply(null,o?t:t.slice(0,-1));r._rgb=xe(i)}else throw new Error("unknown format: "+t);r._rgb.length===3&&r._rgb.push(1)}toString(){return N(this.hex)=="function"?this.hex():`[${this._rgb.join(",")}]`}};const ci="3.2.0",k=(...e)=>new _(...e);k.version=ci;const Lt={aliceblue:"#f0f8ff",antiquewhite:"#faebd7",aqua:"#00ffff",aquamarine:"#7fffd4",azure:"#f0ffff",beige:"#f5f5dc",bisque:"#ffe4c4",black:"#000000",blanchedalmond:"#ffebcd",blue:"#0000ff",blueviolet:"#8a2be2",brown:"#a52a2a",burlywood:"#deb887",cadetblue:"#5f9ea0",chartreuse:"#7fff00",chocolate:"#d2691e",coral:"#ff7f50",cornflowerblue:"#6495ed",cornsilk:"#fff8dc",crimson:"#dc143c",cyan:"#00ffff",darkblue:"#00008b",darkcyan:"#008b8b",darkgoldenrod:"#b8860b",darkgray:"#a9a9a9",darkgreen:"#006400",darkgrey:"#a9a9a9",darkkhaki:"#bdb76b",darkmagenta:"#8b008b",darkolivegreen:"#556b2f",darkorange:"#ff8c00",darkorchid:"#9932cc",darkred:"#8b0000",darksalmon:"#e9967a",darkseagreen:"#8fbc8f",darkslateblue:"#483d8b",darkslategray:"#2f4f4f",darkslategrey:"#2f4f4f",darkturquoise:"#00ced1",darkviolet:"#9400d3",deeppink:"#ff1493",deepskyblue:"#00bfff",dimgray:"#696969",dimgrey:"#696969",dodgerblue:"#1e90ff",firebrick:"#b22222",floralwhite:"#fffaf0",forestgreen:"#228b22",fuchsia:"#ff00ff",gainsboro:"#dcdcdc",ghostwhite:"#f8f8ff",gold:"#ffd700",goldenrod:"#daa520",gray:"#808080",green:"#008000",greenyellow:"#adff2f",grey:"#808080",honeydew:"#f0fff0",hotpink:"#ff69b4",indianred:"#cd5c5c",indigo:"#4b0082",ivory:"#fffff0",khaki:"#f0e68c",laserlemon:"#ffff54",lavender:"#e6e6fa",lavenderblush:"#fff0f5",lawngreen:"#7cfc00",lemonchiffon:"#fffacd",lightblue:"#add8e6",lightcoral:"#f08080",lightcyan:"#e0ffff",lightgoldenrod:"#fafad2",lightgoldenrodyellow:"#fafad2",lightgray:"#d3d3d3",lightgreen:"#90ee90",lightgrey:"#d3d3d3",lightpink:"#ffb6c1",lightsalmon:"#ffa07a",lightseagreen:"#20b2aa",lightskyblue:"#87cefa",lightslategray:"#778899",lightslategrey:"#778899",lightsteelblue:"#b0c4de",lightyellow:"#ffffe0",lime:"#00ff00",limegreen:"#32cd32",linen:"#faf0e6",magenta:"#ff00ff",maroon:"#800000",maroon2:"#7f0000",maroon3:"#b03060",mediumaquamarine:"#66cdaa",mediumblue:"#0000cd",mediumorchid:"#ba55d3",mediumpurple:"#9370db",mediumseagreen:"#3cb371",mediumslateblue:"#7b68ee",mediumspringgreen:"#00fa9a",mediumturquoise:"#48d1cc",mediumvioletred:"#c71585",midnightblue:"#191970",mintcream:"#f5fffa",mistyrose:"#ffe4e1",moccasin:"#ffe4b5",navajowhite:"#ffdead",navy:"#000080",oldlace:"#fdf5e6",olive:"#808000",olivedrab:"#6b8e23",orange:"#ffa500",orangered:"#ff4500",orchid:"#da70d6",palegoldenrod:"#eee8aa",palegreen:"#98fb98",paleturquoise:"#afeeee",palevioletred:"#db7093",papayawhip:"#ffefd5",peachpuff:"#ffdab9",peru:"#cd853f",pink:"#ffc0cb",plum:"#dda0dd",powderblue:"#b0e0e6",purple:"#800080",purple2:"#7f007f",purple3:"#a020f0",rebeccapurple:"#663399",red:"#ff0000",rosybrown:"#bc8f8f",royalblue:"#4169e1",saddlebrown:"#8b4513",salmon:"#fa8072",sandybrown:"#f4a460",seagreen:"#2e8b57",seashell:"#fff5ee",sienna:"#a0522d",silver:"#c0c0c0",skyblue:"#87ceeb",slateblue:"#6a5acd",slategray:"#708090",slategrey:"#708090",snow:"#fffafa",springgreen:"#00ff7f",steelblue:"#4682b4",tan:"#d2b48c",teal:"#008080",thistle:"#d8bfd8",tomato:"#ff6347",turquoise:"#40e0d0",violet:"#ee82ee",wheat:"#f5deb3",white:"#ffffff",whitesmoke:"#f5f5f5",yellow:"#ffff00",yellowgreen:"#9acd32"},ui=/^#?([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/,li=/^#?([A-Fa-f0-9]{8}|[A-Fa-f0-9]{4})$/,pn=e=>{if(e.match(ui)){(e.length===4||e.length===7)&&(e=e.substr(1)),e.length===3&&(e=e.split(""),e=e[0]+e[0]+e[1]+e[1]+e[2]+e[2]);const t=parseInt(e,16),r=t>>16,n=t>>8&255,o=t&255;return[r,n,o,1]}if(e.match(li)){(e.length===5||e.length===9)&&(e=e.substr(1)),e.length===4&&(e=e.split(""),e=e[0]+e[0]+e[1]+e[1]+e[2]+e[2]+e[3]+e[3]);const t=parseInt(e,16),r=t>>24&255,n=t>>16&255,o=t>>8&255,i=Math.round((t&255)/255*100)/100;return[r,n,o,i]}throw new Error(`unknown hex color: ${e}`)},{round:Ut}=Math,mn=(...e)=>{let[t,r,n,o]=E(e,"rgba"),i=Et(e)||"auto";o===void 0&&(o=1),i==="auto"&&(i=o<1?"rgba":"rgb"),t=Ut(t),r=Ut(r),n=Ut(n);let a="000000"+(t<<16|r<<8|n).toString(16);a=a.substr(a.length-6);let c="0"+Ut(o*255).toString(16);switch(c=c.substr(c.length-2),i.toLowerCase()){case"rgba":return`#${a}${c}`;case"argb":return`#${c}${a}`;default:return`#${a}`}};_.prototype.name=function(){const e=mn(this._rgb,"rgb");for(let t of Object.keys(Lt))if(Lt[t]===e)return t.toLowerCase();return e},$.format.named=e=>{if(e=e.toLowerCase(),Lt[e])return pn(Lt[e]);throw new Error("unknown color name: "+e)},$.autodetect.push({p:5,test:(e,...t)=>{if(!t.length&&N(e)==="string"&&Lt[e.toLowerCase()])return"named"}}),_.prototype.alpha=function(e,t=!1){return e!==void 0&&N(e)==="number"?t?(this._rgb[3]=e,this):new _([this._rgb[0],this._rgb[1],this._rgb[2],e],"rgb"):this._rgb[3]},_.prototype.clipped=function(){return this._rgb._clipped||!1};const ct={Kn:18,labWhitePoint:"d65",Xn:.95047,Yn:1,Zn:1.08883,kE:216/24389,kKE:8,kK:24389/27,RefWhiteRGB:{X:.95047,Y:1,Z:1.08883},MtxRGB2XYZ:{m00:.4124564390896922,m01:.21267285140562253,m02:.0193338955823293,m10:.357576077643909,m11:.715152155287818,m12:.11919202588130297,m20:.18043748326639894,m21:.07217499330655958,m22:.9503040785363679},MtxXYZ2RGB:{m00:3.2404541621141045,m01:-.9692660305051868,m02:.055643430959114726,m10:-1.5371385127977166,m11:1.8760108454466942,m12:-.2040259135167538,m20:-.498531409556016,m21:.041556017530349834,m22:1.0572251882231791},As:.9414285350000001,Bs:1.040417467,Cs:1.089532651,MtxAdaptMa:{m00:.8951,m01:-.7502,m02:.0389,m10:.2664,m11:1.7135,m12:-.0685,m20:-.1614,m21:.0367,m22:1.0296},MtxAdaptMaI:{m00:.9869929054667123,m01:.43230526972339456,m02:-.008528664575177328,m10:-.14705425642099013,m11:.5183602715367776,m12:.04004282165408487,m20:.15996265166373125,m21:.0492912282128556,m22:.9684866957875502}},fi=new Map([["a",[1.0985,.35585]],["b",[1.0985,.35585]],["c",[.98074,1.18232]],["d50",[.96422,.82521]],["d55",[.95682,.92149]],["d65",[.95047,1.08883]],["e",[1,1,1]],["f2",[.99186,.67393]],["f7",[.95041,1.08747]],["f11",[1.00962,.6435]],["icc",[.96422,.82521]]]);function ht(e){const t=fi.get(String(e).toLowerCase());if(!t)throw new Error("unknown Lab illuminant "+e);ct.labWhitePoint=e,ct.Xn=t[0],ct.Zn=t[1]}function Kt(){return ct.labWhitePoint}const Re=(...e)=>{e=E(e,"lab");const[t,r,n]=e,[o,i,s]=hi(t,r,n),[a,c,u]=gn(o,i,s);return[a,c,u,e.length>3?e[3]:1]},hi=(e,t,r)=>{const{kE:n,kK:o,kKE:i,Xn:s,Yn:a,Zn:c}=ct,u=(e+16)/116,f=.002*t+u,l=u-.005*r,h=f*f*f,d=l*l*l,b=h>n?h:(116*f-16)/o,g=e>i?Math.pow((e+16)/116,3):e/o,m=d>n?d:(116*l-16)/o,y=b*s,L=g*a,w=m*c;return[y,L,w]},qe=e=>{const t=Math.sign(e);return e=Math.abs(e),(e<=.0031308?e*12.92:1.055*Math.pow(e,1/2.4)-.055)*t},gn=(e,t,r)=>{const{MtxAdaptMa:n,MtxAdaptMaI:o,MtxXYZ2RGB:i,RefWhiteRGB:s,Xn:a,Yn:c,Zn:u}=ct,f=a*n.m00+c*n.m10+u*n.m20,l=a*n.m01+c*n.m11+u*n.m21,h=a*n.m02+c*n.m12+u*n.m22,d=s.X*n.m00+s.Y*n.m10+s.Z*n.m20,b=s.X*n.m01+s.Y*n.m11+s.Z*n.m21,g=s.X*n.m02+s.Y*n.m12+s.Z*n.m22,m=(e*n.m00+t*n.m10+r*n.m20)*(d/f),y=(e*n.m01+t*n.m11+r*n.m21)*(b/l),L=(e*n.m02+t*n.m12+r*n.m22)*(g/h),w=m*o.m00+y*o.m10+L*o.m20,x=m*o.m01+y*o.m11+L*o.m21,S=m*o.m02+y*o.m12+L*o.m22,R=qe(w*i.m00+x*i.m10+S*i.m20),M=qe(w*i.m01+x*i.m11+S*i.m21),p=qe(w*i.m02+x*i.m12+S*i.m22);return[R*255,M*255,p*255]},Me=(...e)=>{const[t,r,n,...o]=E(e,"rgb"),[i,s,a]=_n(t,r,n),[c,u,f]=di(i,s,a);return[c,u,f,...o.length>0&&o[0]<1?[o[0]]:[]]};function di(e,t,r){const{Xn:n,Yn:o,Zn:i,kE:s,kK:a}=ct,c=e/n,u=t/o,f=r/i,l=c>s?Math.pow(c,1/3):(a*c+16)/116,h=u>s?Math.pow(u,1/3):(a*u+16)/116,d=f>s?Math.pow(f,1/3):(a*f+16)/116;return[116*h-16,500*(l-h),200*(h-d)]}function Oe(e){const t=Math.sign(e);return e=Math.abs(e),(e<=.04045?e/12.92:Math.pow((e+.055)/1.055,2.4))*t}const _n=(e,t,r)=>{e=Oe(e/255),t=Oe(t/255),r=Oe(r/255);const{MtxRGB2XYZ:n,MtxAdaptMa:o,MtxAdaptMaI:i,Xn:s,Yn:a,Zn:c,As:u,Bs:f,Cs:l}=ct;let h=e*n.m00+t*n.m10+r*n.m20,d=e*n.m01+t*n.m11+r*n.m21,b=e*n.m02+t*n.m12+r*n.m22;const g=s*o.m00+a*o.m10+c*o.m20,m=s*o.m01+a*o.m11+c*o.m21,y=s*o.m02+a*o.m12+c*o.m22;let L=h*o.m00+d*o.m10+b*o.m20,w=h*o.m01+d*o.m11+b*o.m21,x=h*o.m02+d*o.m12+b*o.m22;return L*=g/u,w*=m/f,x*=y/l,h=L*i.m00+w*i.m10+x*i.m20,d=L*i.m01+w*i.m11+x*i.m21,b=L*i.m02+w*i.m12+x*i.m22,[h,d,b]};_.prototype.lab=function(){return Me(this._rgb)},Object.assign(k,{lab:(...e)=>new _(...e,"lab"),getLabWhitePoint:Kt,setLabWhitePoint:ht}),$.format.lab=Re,$.autodetect.push({p:2,test:(...e)=>{if(e=E(e,"lab"),N(e)==="array"&&e.length===3)return"lab"}}),_.prototype.darken=function(e=1){const t=this,r=t.lab();return r[0]-=ct.Kn*e,new _(r,"lab").alpha(t.alpha(),!0)},_.prototype.brighten=function(e=1){return this.darken(-e)},_.prototype.darker=_.prototype.darken,_.prototype.brighter=_.prototype.brighten,_.prototype.get=function(e){const[t,r]=e.split("."),n=this[t]();if(r){const o=t.indexOf(r)-(t.substr(0,2)==="ok"?2:0);if(o>-1)return n[o];throw new Error(`unknown channel ${r} in mode ${t}`)}else return n};const{pow:bi}=Math,pi=1e-7,mi=20;_.prototype.luminance=function(e,t="rgb"){if(e!==void 0&&N(e)==="number"){if(e===0)return new _([0,0,0,this._rgb[3]],"rgb");if(e===1)return new _([255,255,255,this._rgb[3]],"rgb");let r=this.luminance(),n=mi;const o=(s,a)=>{const c=s.interpolate(a,.5,t),u=c.luminance();return Math.abs(e-u)e?o(s,c):o(c,a)},i=(r>e?o(new _([0,0,0]),this):o(this,new _([255,255,255]))).rgb();return new _([...i,this._rgb[3]])}return gi(...this._rgb.slice(0,3))};const gi=(e,t,r)=>(e=Ae(e),t=Ae(t),r=Ae(r),.2126*e+.7152*t+.0722*r),Ae=e=>(e/=255,e<=.03928?e/12.92:bi((e+.055)/1.055,2.4)),H={},Nt=(e,t,r=.5,...n)=>{let o=n[0]||"lrgb";if(!H[o]&&!n.length&&(o=Object.keys(H)[0]),!H[o])throw new Error(`interpolation mode ${o} is not defined`);return N(e)!=="object"&&(e=new _(e)),N(t)!=="object"&&(t=new _(t)),H[o](e,t,r).alpha(e.alpha()+r*(t.alpha()-e.alpha()))};_.prototype.mix=_.prototype.interpolate=function(e,t=.5,...r){return Nt(this,e,t,...r)},_.prototype.premultiply=function(e=!1){const t=this._rgb,r=t[3];return e?(this._rgb=[t[0]*r,t[1]*r,t[2]*r,r],this):new _([t[0]*r,t[1]*r,t[2]*r,r],"rgb")};const{sin:_i,cos:vi}=Math,vn=(...e)=>{let[t,r,n]=E(e,"lch");return isNaN(n)&&(n=0),n=n*ii,[t,vi(n)*r,_i(n)*r]},Se=(...e)=>{e=E(e,"lch");const[t,r,n]=e,[o,i,s]=vn(t,r,n),[a,c,u]=Re(o,i,s);return[a,c,u,e.length>3?e[3]:1]},yi=(...e)=>{const t=bn(E(e,"hcl"));return Se(...t)},{sqrt:wi,atan2:xi,round:Ci}=Math,yn=(...e)=>{const[t,r,n]=E(e,"lab"),o=wi(r*r+n*n);let i=(xi(n,r)*ai+360)%360;return Ci(o*1e4)===0&&(i=Number.NaN),[t,o,i]},$e=(...e)=>{const[t,r,n,...o]=E(e,"rgb"),[i,s,a]=Me(t,r,n),[c,u,f]=yn(i,s,a);return[c,u,f,...o.length>0&&o[0]<1?[o[0]]:[]]};_.prototype.lch=function(){return $e(this._rgb)},_.prototype.hcl=function(){return bn($e(this._rgb))},Object.assign(k,{lch:(...e)=>new _(...e,"lch"),hcl:(...e)=>new _(...e,"hcl")}),$.format.lch=Se,$.format.hcl=yi,["lch","hcl"].forEach(e=>$.autodetect.push({p:2,test:(...t)=>{if(t=E(t,e),N(t)==="array"&&t.length===3)return e}})),_.prototype.saturate=function(e=1){const t=this,r=t.lch();return r[1]+=ct.Kn*e,r[1]<0&&(r[1]=0),new _(r,"lch").alpha(t.alpha(),!0)},_.prototype.desaturate=function(e=1){return this.saturate(-e)},_.prototype.set=function(e,t,r=!1){const[n,o]=e.split("."),i=this[n]();if(o){const s=n.indexOf(o)-(n.substr(0,2)==="ok"?2:0);if(s>-1){if(N(t)=="string")switch(t.charAt(0)){case"+":i[s]+=+t;break;case"-":i[s]+=+t;break;case"*":i[s]*=+t.substr(1);break;case"/":i[s]/=+t.substr(1);break;default:i[s]=+t}else if(N(t)==="number")i[s]=t;else throw new Error("unsupported value for Color.set");const a=new _(i,n);return r?(this._rgb=a._rgb,this):a}throw new Error(`unknown channel ${o} in mode ${n}`)}else return i},_.prototype.tint=function(e=.5,...t){return Nt(this,"white",e,...t)},_.prototype.shade=function(e=.5,...t){return Nt(this,"black",e,...t)};const ki=(e,t,r)=>{const n=e._rgb,o=t._rgb;return new _(n[0]+r*(o[0]-n[0]),n[1]+r*(o[1]-n[1]),n[2]+r*(o[2]-n[2]),"rgb")};H.rgb=ki;const{sqrt:Ee,pow:Tt}=Math,Ri=(e,t,r)=>{const[n,o,i]=e._rgb,[s,a,c]=t._rgb;return new _(Ee(Tt(n,2)*(1-r)+Tt(s,2)*r),Ee(Tt(o,2)*(1-r)+Tt(a,2)*r),Ee(Tt(i,2)*(1-r)+Tt(c,2)*r),"rgb")};H.lrgb=Ri;const qi=(e,t,r)=>{const n=e.lab(),o=t.lab();return new _(n[0]+r*(o[0]-n[0]),n[1]+r*(o[1]-n[1]),n[2]+r*(o[2]-n[2]),"lab")};H.lab=qi;const jt=(e,t,r,n)=>{let o,i;n==="hsl"?(o=e.hsl(),i=t.hsl()):n==="hsv"?(o=e.hsv(),i=t.hsv()):n==="hcg"?(o=e.hcg(),i=t.hcg()):n==="hsi"?(o=e.hsi(),i=t.hsi()):n==="lch"||n==="hcl"?(n="hcl",o=e.hcl(),i=t.hcl()):n==="oklch"&&(o=e.oklch().reverse(),i=t.oklch().reverse());let s,a,c,u,f,l;(n.substr(0,1)==="h"||n==="oklch")&&([s,c,f]=o,[a,u,l]=i);let h,d,b,g;return!isNaN(s)&&!isNaN(a)?(a>s&&a-s>180?g=a-(s+360):a180?g=a+360-s:g=a-s,d=s+r*g):isNaN(s)?isNaN(a)?d=Number.NaN:(d=a,(f==1||f==0)&&n!="hsv"&&(h=u)):(d=s,(l==1||l==0)&&n!="hsv"&&(h=c)),h===void 0&&(h=c+r*(u-c)),b=f+r*(l-f),n==="oklch"?new _([b,h,d],n):new _([d,h,b],n)},wn=(e,t,r)=>jt(e,t,r,"lch");H.lch=wn,H.hcl=wn;const Mi=e=>{if(N(e)=="number"&&e>=0&&e<=16777215){const t=e>>16,r=e>>8&255,n=e&255;return[t,r,n,1]}throw new Error("unknown num color: "+e)},Oi=(...e)=>{const[t,r,n]=E(e,"rgb");return(t<<16)+(r<<8)+n};_.prototype.num=function(){return Oi(this._rgb)},Object.assign(k,{num:(...e)=>new _(...e,"num")}),$.format.num=Mi,$.autodetect.push({p:5,test:(...e)=>{if(e.length===1&&N(e[0])==="number"&&e[0]>=0&&e[0]<=16777215)return"num"}});const Ai=(e,t,r)=>{const n=e.num(),o=t.num();return new _(n+r*(o-n),"num")};H.num=Ai;const{floor:Si}=Math,$i=(...e)=>{e=E(e,"hcg");let[t,r,n]=e,o,i,s;n=n*255;const a=r*255;if(r===0)o=i=s=n;else{t===360&&(t=0),t>360&&(t-=360),t<0&&(t+=360),t/=60;const c=Si(t),u=t-c,f=n*(1-r),l=f+a*(1-u),h=f+a*u,d=f+a;switch(c){case 0:[o,i,s]=[d,h,f];break;case 1:[o,i,s]=[l,d,f];break;case 2:[o,i,s]=[f,d,h];break;case 3:[o,i,s]=[f,l,d];break;case 4:[o,i,s]=[h,f,d];break;case 5:[o,i,s]=[d,f,l];break}}return[o,i,s,e.length>3?e[3]:1]},Ei=(...e)=>{const[t,r,n]=E(e,"rgb"),o=hn(t,r,n),i=dn(t,r,n),s=i-o,a=s*100/255,c=o/(255-s)*100;let u;return s===0?u=Number.NaN:(t===i&&(u=(r-n)/s),r===i&&(u=2+(n-t)/s),n===i&&(u=4+(t-r)/s),u*=60,u<0&&(u+=360)),[u,a,c]};_.prototype.hcg=function(){return Ei(this._rgb)};const Li=(...e)=>new _(...e,"hcg");k.hcg=Li,$.format.hcg=$i,$.autodetect.push({p:1,test:(...e)=>{if(e=E(e,"hcg"),N(e)==="array"&&e.length===3)return"hcg"}});const Ni=(e,t,r)=>jt(e,t,r,"hcg");H.hcg=Ni;const{cos:Pt}=Math,Ti=(...e)=>{e=E(e,"hsi");let[t,r,n]=e,o,i,s;return isNaN(t)&&(t=0),isNaN(r)&&(r=0),t>360&&(t-=360),t<0&&(t+=360),t/=360,t<1/3?(s=(1-r)/3,o=(1+r*Pt(ft*t)/Pt(ke-ft*t))/3,i=1-(s+o)):t<2/3?(t-=1/3,o=(1-r)/3,i=(1+r*Pt(ft*t)/Pt(ke-ft*t))/3,s=1-(o+i)):(t-=2/3,i=(1-r)/3,s=(1+r*Pt(ft*t)/Pt(ke-ft*t))/3,o=1-(i+s)),o=qt(n*o*3),i=qt(n*i*3),s=qt(n*s*3),[o*255,i*255,s*255,e.length>3?e[3]:1]},{min:ji,sqrt:Pi,acos:zi}=Math,Bi=(...e)=>{let[t,r,n]=E(e,"rgb");t/=255,r/=255,n/=255;let o;const i=ji(t,r,n),s=(t+r+n)/3,a=s>0?1-i/s:0;return a===0?o=NaN:(o=(t-r+(t-n))/2,o/=Pi((t-r)*(t-r)+(t-n)*(r-n)),o=zi(o),n>r&&(o=ft-o),o/=ft),[o*360,a,s]};_.prototype.hsi=function(){return Bi(this._rgb)};const Ii=(...e)=>new _(...e,"hsi");k.hsi=Ii,$.format.hsi=Ti,$.autodetect.push({p:2,test:(...e)=>{if(e=E(e,"hsi"),N(e)==="array"&&e.length===3)return"hsi"}});const Gi=(e,t,r)=>jt(e,t,r,"hsi");H.hsi=Gi;const Le=(...e)=>{e=E(e,"hsl");const[t,r,n]=e;let o,i,s;if(r===0)o=i=s=n*255;else{const a=[0,0,0],c=[0,0,0],u=n<.5?n*(1+r):n+r-n*r,f=2*n-u,l=t/360;a[0]=l+1/3,a[1]=l,a[2]=l-1/3;for(let h=0;h<3;h++)a[h]<0&&(a[h]+=1),a[h]>1&&(a[h]-=1),6*a[h]<1?c[h]=f+(u-f)*6*a[h]:2*a[h]<1?c[h]=u:3*a[h]<2?c[h]=f+(u-f)*(2/3-a[h])*6:c[h]=f;[o,i,s]=[c[0]*255,c[1]*255,c[2]*255]}return e.length>3?[o,i,s,e[3]]:[o,i,s,1]},xn=(...e)=>{e=E(e,"rgba");let[t,r,n]=e;t/=255,r/=255,n/=255;const o=hn(t,r,n),i=dn(t,r,n),s=(i+o)/2;let a,c;return i===o?(a=0,c=Number.NaN):a=s<.5?(i-o)/(i+o):(i-o)/(2-i-o),t==i?c=(r-n)/(i-o):r==i?c=2+(n-t)/(i-o):n==i&&(c=4+(t-r)/(i-o)),c*=60,c<0&&(c+=360),e.length>3&&e[3]!==void 0?[c,a,s,e[3]]:[c,a,s]};_.prototype.hsl=function(){return xn(this._rgb)};const Fi=(...e)=>new _(...e,"hsl");k.hsl=Fi,$.format.hsl=Le,$.autodetect.push({p:2,test:(...e)=>{if(e=E(e,"hsl"),N(e)==="array"&&e.length===3)return"hsl"}});const Ki=(e,t,r)=>jt(e,t,r,"hsl");H.hsl=Ki;const{floor:Xi}=Math,Di=(...e)=>{e=E(e,"hsv");let[t,r,n]=e,o,i,s;if(n*=255,r===0)o=i=s=n;else{t===360&&(t=0),t>360&&(t-=360),t<0&&(t+=360),t/=60;const a=Xi(t),c=t-a,u=n*(1-r),f=n*(1-r*c),l=n*(1-r*(1-c));switch(a){case 0:[o,i,s]=[n,l,u];break;case 1:[o,i,s]=[f,n,u];break;case 2:[o,i,s]=[u,n,l];break;case 3:[o,i,s]=[u,f,n];break;case 4:[o,i,s]=[l,u,n];break;case 5:[o,i,s]=[n,u,f];break}}return[o,i,s,e.length>3?e[3]:1]},{min:Vi,max:Yi}=Math,Zi=(...e)=>{e=E(e,"rgb");let[t,r,n]=e;const o=Vi(t,r,n),i=Yi(t,r,n),s=i-o;let a,c,u;return u=i/255,i===0?(a=Number.NaN,c=0):(c=s/i,t===i&&(a=(r-n)/s),r===i&&(a=2+(n-t)/s),n===i&&(a=4+(t-r)/s),a*=60,a<0&&(a+=360)),[a,c,u]};_.prototype.hsv=function(){return Zi(this._rgb)};const Ji=(...e)=>new _(...e,"hsv");k.hsv=Ji,$.format.hsv=Di,$.autodetect.push({p:2,test:(...e)=>{if(e=E(e,"hsv"),N(e)==="array"&&e.length===3)return"hsv"}});const Hi=(e,t,r)=>jt(e,t,r,"hsv");H.hsv=Hi;function Qt(e,t){let r=e.length;Array.isArray(e[0])||(e=[e]),Array.isArray(t[0])||(t=t.map(s=>[s]));let n=t[0].length,o=t[0].map((s,a)=>t.map(c=>c[a])),i=e.map(s=>o.map(a=>Array.isArray(s)?s.reduce((c,u,f)=>c+u*(a[f]||0),0):a.reduce((c,u)=>c+u*s,0)));return r===1&&(i=i[0]),n===1?i.map(s=>s[0]):i}const Ne=(...e)=>{e=E(e,"lab");const[t,r,n,...o]=e,[i,s,a]=Wi([t,r,n]),[c,u,f]=gn(i,s,a);return[c,u,f,...o.length>0&&o[0]<1?[o[0]]:[]]};function Wi(e){var t=[[1.2268798758459243,-.5578149944602171,.2813910456659647],[-.0405757452148008,1.112286803280317,-.0717110580655164],[-.0763729366746601,-.4214933324022432,1.5869240198367816]],r=[[1,.3963377773761749,.2158037573099136],[1,-.1055613458156586,-.0638541728258133],[1,-.0894841775298119,-1.2914855480194092]],n=Qt(r,e);return Qt(t,n.map(o=>o**3))}const Te=(...e)=>{const[t,r,n,...o]=E(e,"rgb"),i=_n(t,r,n);return[...Ui(i),...o.length>0&&o[0]<1?[o[0]]:[]]};function Ui(e){const t=[[.819022437996703,.3619062600528904,-.1288737815209879],[.0329836539323885,.9292868615863434,.0361446663506424],[.0481771893596242,.2642395317527308,.6335478284694309]],r=[[.210454268309314,.7936177747023054,-.0040720430116193],[1.9779985324311684,-2.42859224204858,.450593709617411],[.0259040424655478,.7827717124575296,-.8086757549230774]],n=Qt(t,e);return Qt(r,n.map(o=>Math.cbrt(o)))}_.prototype.oklab=function(){return Te(this._rgb)},Object.assign(k,{oklab:(...e)=>new _(...e,"oklab")}),$.format.oklab=Ne,$.autodetect.push({p:2,test:(...e)=>{if(e=E(e,"oklab"),N(e)==="array"&&e.length===3)return"oklab"}});const Qi=(e,t,r)=>{const n=e.oklab(),o=t.oklab();return new _(n[0]+r*(o[0]-n[0]),n[1]+r*(o[1]-n[1]),n[2]+r*(o[2]-n[2]),"oklab")};H.oklab=Qi;const ta=(e,t,r)=>jt(e,t,r,"oklch");H.oklch=ta;const{pow:je,sqrt:Pe,PI:ze,cos:Cn,sin:kn,atan2:ea}=Math,ra=(e,t="lrgb",r=null)=>{const n=e.length;r||(r=Array.from(new Array(n)).map(()=>1));const o=n/r.reduce(function(l,h){return l+h});if(r.forEach((l,h)=>{r[h]*=o}),e=e.map(l=>new _(l)),t==="lrgb")return na(e,r);const i=e.shift(),s=i.get(t),a=[];let c=0,u=0;for(let l=0;l{const d=l.get(t);f+=l.alpha()*r[h+1];for(let b=0;b=360;)h-=360;s[l]=h}else s[l]=s[l]/a[l];return f/=n,new _(s,t).alpha(f>.99999?1:f,!0)},na=(e,t)=>{const r=e.length,n=[0,0,0,0];for(let o=0;o.9999999&&(n[3]=1),new _(xe(n))},{pow:oa}=Math;function te(e){let t="rgb",r=k("#ccc"),n=0,o=[0,1],i=[0,1],s=[],a=[0,0],c=!1,u=[],f=!1,l=0,h=1,d=!1,b={},g=!0,m=1;const y=function(p){if(p=p||["#fff","#000"],p&&N(p)==="string"&&k.brewer&&k.brewer[p.toLowerCase()]&&(p=k.brewer[p.toLowerCase()]),N(p)==="array"){p.length===1&&(p=[p[0],p[0]]),p=p.slice(0);for(let C=0;C=c[O];)O++;return O-1}return 0};let w=p=>p,x=p=>p;const S=function(p,C){let O,q;if(C==null&&(C=!1),isNaN(p)||p===null)return r;C?q=p:c&&c.length>2?q=L(p)/(c.length-2):h!==l?q=(p-l)/(h-l):q=1,q=x(q),C||(q=w(q)),m!==1&&(q=oa(q,m)),q=a[0]+q*(1-a[0]-a[1]),q=qt(q,0,1);const T=Math.floor(q*1e4);if(g&&b[T])O=b[T];else{if(N(u)==="array")for(let A=0;A=P&&A===s.length-1){O=u[A];break}if(q>P&&qb={};y(e);const M=function(p){const C=k(S(p));return f&&C[f]?C[f]():C};return M.classes=function(p){if(p!=null){if(N(p)==="array")c=p,o=[p[0],p[p.length-1]];else{const C=k.analyze(o);p===0?c=[C.min,C.max]:c=k.limits(C,"e",p)}return M}return c},M.domain=function(p){if(!arguments.length)return i;i=p.slice(0),l=p[0],h=p[p.length-1],s=[];const C=u.length;if(p.length===C&&l!==h)for(let O of Array.from(p))s.push((O-l)/(h-l));else{for(let O=0;O2){const O=p.map((T,A)=>A/(p.length-1)),q=p.map(T=>(T-l)/(h-l));q.every((T,A)=>O[A]===T)||(x=T=>{if(T<=0||T>=1)return T;let A=0;for(;T>=q[A+1];)A++;const P=(T-q[A])/(q[A+1]-q[A]);return O[A]+P*(O[A+1]-O[A])})}}return o=[l,h],M},M.mode=function(p){return arguments.length?(t=p,R(),M):t},M.range=function(p,C){return y(p),M},M.out=function(p){return f=p,M},M.spread=function(p){return arguments.length?(n=p,M):n},M.correctLightness=function(p){return p==null&&(p=!0),d=p,R(),d?w=function(C){const O=S(0,!0).lab()[0],q=S(1,!0).lab()[0],T=O>q;let A=S(C,!0).lab()[0];const P=O+(q-O)*C;let G=A-P,Y=0,U=1,ut=20;for(;Math.abs(G)>.01&&ut-- >0;)(function(){return T&&(G*=-1),G<0?(Y=C,C+=(U-C)*.5):(U=C,C+=(Y-C)*.5),A=S(C,!0).lab()[0],G=A-P})();return C}:w=C=>C,M},M.padding=function(p){return p!=null?(N(p)==="number"&&(p=[p,p]),a=p,M):a},M.colors=function(p,C){arguments.length<2&&(C="hex");let O=[];if(arguments.length===0)O=u.slice(0);else if(p===1)O=[M(.5)];else if(p>1){const q=o[0],T=o[1]-q;O=sa(0,p).map(A=>M(q+A/(p-1)*T))}else{e=[];let q=[];if(c&&c.length>2)for(let T=1,A=c.length,P=1<=A;P?TA;P?T++:T--)q.push((c[T-1]+c[T])*.5);else q=o;O=q.map(T=>M(T))}return k[C]&&(O=O.map(q=>q[C]())),O},M.cache=function(p){return p!=null?(g=p,M):g},M.gamma=function(p){return p!=null?(m=p,M):m},M.nodata=function(p){return p!=null?(r=k(p),M):r},M}function sa(e,t,r){let n=[],o=ei;o?s++:s--)n.push(s);return n}const ia=function(e){let t=[1,1];for(let r=1;rnew _(i)),e.length===2)[r,n]=e.map(i=>i.lab()),t=function(i){const s=[0,1,2].map(a=>r[a]+i*(n[a]-r[a]));return new _(s,"lab")};else if(e.length===3)[r,n,o]=e.map(i=>i.lab()),t=function(i){const s=[0,1,2].map(a=>(1-i)*(1-i)*r[a]+2*(1-i)*i*n[a]+i*i*o[a]);return new _(s,"lab")};else if(e.length===4){let i;[r,n,o,i]=e.map(s=>s.lab()),t=function(s){const a=[0,1,2].map(c=>(1-s)*(1-s)*(1-s)*r[c]+3*(1-s)*(1-s)*s*n[c]+3*(1-s)*s*s*o[c]+s*s*s*i[c]);return new _(a,"lab")}}else if(e.length>=5){let i,s,a;i=e.map(c=>c.lab()),a=e.length-1,s=ia(a),t=function(c){const u=1-c,f=[0,1,2].map(l=>i.reduce((h,d,b)=>h+s[b]*u**(a-b)*c**b*d[l],0));return new _(f,"lab")}}else throw new RangeError("No point in running bezier with only one color.");return t},ca=e=>{const t=aa(e);return t.scale=()=>te(t),t},{round:Rn}=Math;_.prototype.rgb=function(e=!0){return e===!1?this._rgb.slice(0,3):this._rgb.slice(0,3).map(Rn)},_.prototype.rgba=function(e=!0){return this._rgb.slice(0,4).map((t,r)=>r<3?e===!1?t:Rn(t):t)},Object.assign(k,{rgb:(...e)=>new _(...e,"rgb")}),$.format.rgb=(...e)=>{const t=E(e,"rgba");return t[3]===void 0&&(t[3]=1),t},$.autodetect.push({p:3,test:(...e)=>{if(e=E(e,"rgba"),N(e)==="array"&&(e.length===3||e.length===4&&N(e[3])=="number"&&e[3]>=0&&e[3]<=1))return"rgb"}});const nt=(e,t,r)=>{if(!nt[r])throw new Error("unknown blend mode "+r);return nt[r](e,t)},_t=e=>(t,r)=>{const n=k(r).rgb(),o=k(t).rgb();return k.rgb(e(n,o))},vt=e=>(t,r)=>{const n=[];return n[0]=e(t[0],r[0]),n[1]=e(t[1],r[1]),n[2]=e(t[2],r[2]),n},ua=e=>e,la=(e,t)=>e*t/255,fa=(e,t)=>e>t?t:e,ha=(e,t)=>e>t?e:t,da=(e,t)=>255*(1-(1-e/255)*(1-t/255)),ba=(e,t)=>t<128?2*e*t/255:255*(1-2*(1-e/255)*(1-t/255)),pa=(e,t)=>255*(1-(1-t/255)/(e/255)),ma=(e,t)=>e===255?255:(e=255*(t/255)/(1-e/255),e>255?255:e);nt.normal=_t(vt(ua)),nt.multiply=_t(vt(la)),nt.screen=_t(vt(da)),nt.overlay=_t(vt(ba)),nt.darken=_t(vt(fa)),nt.lighten=_t(vt(ha)),nt.dodge=_t(vt(ma)),nt.burn=_t(vt(pa));const{pow:ga,sin:_a,cos:va}=Math;function ya(e=300,t=-1.5,r=1,n=1,o=[0,1]){let i=0,s;N(o)==="array"?s=o[1]-o[0]:(s=0,o=[o,o]);const a=function(c){const u=ft*((e+120)/360+t*c),f=ga(o[0]+s*c,n),h=(i!==0?r[0]+c*i:r)*f*(1-f)/2,d=va(u),b=_a(u),g=f+h*(-.14861*d+1.78277*b),m=f+h*(-.29227*d-.90649*b),y=f+h*(1.97294*d);return k(xe([g*255,m*255,y*255,1]))};return a.start=function(c){return c==null?e:(e=c,a)},a.rotations=function(c){return c==null?t:(t=c,a)},a.gamma=function(c){return c==null?n:(n=c,a)},a.hue=function(c){return c==null?r:(r=c,N(r)==="array"?(i=r[1]-r[0],i===0&&(r=r[1])):i=0,a)},a.lightness=function(c){return c==null?o:(N(c)==="array"?(o=c,s=c[1]-c[0]):(o=[c,c],s=0),a)},a.scale=()=>k.scale(a),a.hue(r),a}const wa="0123456789abcdef",{floor:xa,random:Ca}=Math,ka=(e=Ca)=>{let t="#";for(let r=0;r<6;r++)t+=wa.charAt(xa(e()*16));return new _(t,"hex")},{log:qn,pow:Ra,floor:qa,abs:Ma}=Math;function Mn(e,t=null){const r={min:Number.MAX_VALUE,max:Number.MAX_VALUE*-1,sum:0,values:[],count:0};return N(e)==="object"&&(e=Object.values(e)),e.forEach(n=>{t&&N(n)==="object"&&(n=n[t]),n!=null&&!isNaN(n)&&(r.values.push(n),r.sum+=n,nr.max&&(r.max=n),r.count+=1)}),r.domain=[r.min,r.max],r.limits=(n,o)=>On(r,n,o),r}function On(e,t="equal",r=7){N(e)=="array"&&(e=Mn(e));const{min:n,max:o}=e,i=e.values.sort((a,c)=>a-c);if(r===1)return[n,o];const s=[];if(t.substr(0,1)==="c"&&(s.push(n),s.push(o)),t.substr(0,1)==="e"){s.push(n);for(let a=1;a 0");const a=Math.LOG10E*qn(n),c=Math.LOG10E*qn(o);s.push(n);for(let u=1;u200&&(l=!1)}const b={};for(let m=0;mm-y),s.push(g[0]);for(let m=1;m{e=new _(e),t=new _(t);const r=e.luminance(),n=t.luminance();return r>n?(r+.05)/(n+.05):(n+.05)/(r+.05)};const An=.027,Aa=5e-4,Sa=.1,Sn=1.14,ee=.022,$n=1.414,$a=(e,t)=>{e=new _(e),t=new _(t),e.alpha()<1&&(e=Nt(t,e,e.alpha(),"rgb"));const r=En(...e.rgb()),n=En(...t.rgb()),o=r>=ee?r:r+Math.pow(ee-r,$n),i=n>=ee?n:n+Math.pow(ee-n,$n),s=Math.pow(i,.56)-Math.pow(o,.57),a=Math.pow(i,.65)-Math.pow(o,.62),c=Math.abs(i-o)0?c-An:c+An)*100};function En(e,t,r){return .2126729*Math.pow(e/255,2.4)+.7151522*Math.pow(t/255,2.4)+.072175*Math.pow(r/255,2.4)}const{sqrt:dt,pow:F,min:Ea,max:La,atan2:Ln,abs:Nn,cos:re,sin:Tn,exp:Na,PI:jn}=Math;function Ta(e,t,r=1,n=1,o=1){var i=function(Ct){return 360*Ct/(2*jn)},s=function(Ct){return 2*jn*Ct/360};e=new _(e),t=new _(t);const[a,c,u]=Array.from(e.lab()),[f,l,h]=Array.from(t.lab()),d=(a+f)/2,b=dt(F(c,2)+F(u,2)),g=dt(F(l,2)+F(h,2)),m=(b+g)/2,y=.5*(1-dt(F(m,7)/(F(m,7)+F(25,7)))),L=c*(1+y),w=l*(1+y),x=dt(F(L,2)+F(u,2)),S=dt(F(w,2)+F(h,2)),R=(x+S)/2,M=i(Ln(u,L)),p=i(Ln(h,w)),C=M>=0?M:M+360,O=p>=0?p:p+360,q=Nn(C-O)>180?(C+O+360)/2:(C+O)/2,T=1-.17*re(s(q-30))+.24*re(s(2*q))+.32*re(s(3*q+6))-.2*re(s(4*q-63));let A=O-C;A=Nn(A)<=180?A:O<=C?A+360:A-360,A=2*dt(x*S)*Tn(s(A)/2);const P=f-a,G=S-x,Y=1+.015*F(d-50,2)/dt(20+F(d-50,2)),U=1+.045*R,ut=1+.015*R*T,xt=30*Na(-F((q-275)/25,2)),lt=-(2*dt(F(R,7)/(F(R,7)+F(25,7))))*Tn(2*s(xt)),Mt=dt(F(P/(r*Y),2)+F(G/(n*U),2)+F(A/(o*ut),2)+lt*(G/(n*U))*(A/(o*ut)));return La(0,Ea(100,Mt))}function ja(e,t,r="lab"){e=new _(e),t=new _(t);const n=e.get(r),o=t.get(r);let i=0;for(let s in n){const a=(n[s]||0)-(o[s]||0);i+=a*a}return Math.sqrt(i)}const Pa=(...e)=>{try{return new _(...e),!0}catch{return!1}},za={cool(){return te([k.hsl(180,1,.9),k.hsl(250,.7,.4)])},hot(){return te(["#000","#f00","#ff0","#fff"]).mode("rgb")}},Be={OrRd:["#fff7ec","#fee8c8","#fdd49e","#fdbb84","#fc8d59","#ef6548","#d7301f","#b30000","#7f0000"],PuBu:["#fff7fb","#ece7f2","#d0d1e6","#a6bddb","#74a9cf","#3690c0","#0570b0","#045a8d","#023858"],BuPu:["#f7fcfd","#e0ecf4","#bfd3e6","#9ebcda","#8c96c6","#8c6bb1","#88419d","#810f7c","#4d004b"],Oranges:["#fff5eb","#fee6ce","#fdd0a2","#fdae6b","#fd8d3c","#f16913","#d94801","#a63603","#7f2704"],BuGn:["#f7fcfd","#e5f5f9","#ccece6","#99d8c9","#66c2a4","#41ae76","#238b45","#006d2c","#00441b"],YlOrBr:["#ffffe5","#fff7bc","#fee391","#fec44f","#fe9929","#ec7014","#cc4c02","#993404","#662506"],YlGn:["#ffffe5","#f7fcb9","#d9f0a3","#addd8e","#78c679","#41ab5d","#238443","#006837","#004529"],Reds:["#fff5f0","#fee0d2","#fcbba1","#fc9272","#fb6a4a","#ef3b2c","#cb181d","#a50f15","#67000d"],RdPu:["#fff7f3","#fde0dd","#fcc5c0","#fa9fb5","#f768a1","#dd3497","#ae017e","#7a0177","#49006a"],Greens:["#f7fcf5","#e5f5e0","#c7e9c0","#a1d99b","#74c476","#41ab5d","#238b45","#006d2c","#00441b"],YlGnBu:["#ffffd9","#edf8b1","#c7e9b4","#7fcdbb","#41b6c4","#1d91c0","#225ea8","#253494","#081d58"],Purples:["#fcfbfd","#efedf5","#dadaeb","#bcbddc","#9e9ac8","#807dba","#6a51a3","#54278f","#3f007d"],GnBu:["#f7fcf0","#e0f3db","#ccebc5","#a8ddb5","#7bccc4","#4eb3d3","#2b8cbe","#0868ac","#084081"],Greys:["#ffffff","#f0f0f0","#d9d9d9","#bdbdbd","#969696","#737373","#525252","#252525","#000000"],YlOrRd:["#ffffcc","#ffeda0","#fed976","#feb24c","#fd8d3c","#fc4e2a","#e31a1c","#bd0026","#800026"],PuRd:["#f7f4f9","#e7e1ef","#d4b9da","#c994c7","#df65b0","#e7298a","#ce1256","#980043","#67001f"],Blues:["#f7fbff","#deebf7","#c6dbef","#9ecae1","#6baed6","#4292c6","#2171b5","#08519c","#08306b"],PuBuGn:["#fff7fb","#ece2f0","#d0d1e6","#a6bddb","#67a9cf","#3690c0","#02818a","#016c59","#014636"],Viridis:["#440154","#482777","#3f4a8a","#31678e","#26838f","#1f9d8a","#6cce5a","#b6de2b","#fee825"],Spectral:["#9e0142","#d53e4f","#f46d43","#fdae61","#fee08b","#ffffbf","#e6f598","#abdda4","#66c2a5","#3288bd","#5e4fa2"],RdYlGn:["#a50026","#d73027","#f46d43","#fdae61","#fee08b","#ffffbf","#d9ef8b","#a6d96a","#66bd63","#1a9850","#006837"],RdBu:["#67001f","#b2182b","#d6604d","#f4a582","#fddbc7","#f7f7f7","#d1e5f0","#92c5de","#4393c3","#2166ac","#053061"],PiYG:["#8e0152","#c51b7d","#de77ae","#f1b6da","#fde0ef","#f7f7f7","#e6f5d0","#b8e186","#7fbc41","#4d9221","#276419"],PRGn:["#40004b","#762a83","#9970ab","#c2a5cf","#e7d4e8","#f7f7f7","#d9f0d3","#a6dba0","#5aae61","#1b7837","#00441b"],RdYlBu:["#a50026","#d73027","#f46d43","#fdae61","#fee090","#ffffbf","#e0f3f8","#abd9e9","#74add1","#4575b4","#313695"],BrBG:["#543005","#8c510a","#bf812d","#dfc27d","#f6e8c3","#f5f5f5","#c7eae5","#80cdc1","#35978f","#01665e","#003c30"],RdGy:["#67001f","#b2182b","#d6604d","#f4a582","#fddbc7","#ffffff","#e0e0e0","#bababa","#878787","#4d4d4d","#1a1a1a"],PuOr:["#7f3b08","#b35806","#e08214","#fdb863","#fee0b6","#f7f7f7","#d8daeb","#b2abd2","#8073ac","#542788","#2d004b"],Set2:["#66c2a5","#fc8d62","#8da0cb","#e78ac3","#a6d854","#ffd92f","#e5c494","#b3b3b3"],Accent:["#7fc97f","#beaed4","#fdc086","#ffff99","#386cb0","#f0027f","#bf5b17","#666666"],Set1:["#e41a1c","#377eb8","#4daf4a","#984ea3","#ff7f00","#ffff33","#a65628","#f781bf","#999999"],Set3:["#8dd3c7","#ffffb3","#bebada","#fb8072","#80b1d3","#fdb462","#b3de69","#fccde5","#d9d9d9","#bc80bd","#ccebc5","#ffed6f"],Dark2:["#1b9e77","#d95f02","#7570b3","#e7298a","#66a61e","#e6ab02","#a6761d","#666666"],Paired:["#a6cee3","#1f78b4","#b2df8a","#33a02c","#fb9a99","#e31a1c","#fdbf6f","#ff7f00","#cab2d6","#6a3d9a","#ffff99","#b15928"],Pastel2:["#b3e2cd","#fdcdac","#cbd5e8","#f4cae4","#e6f5c9","#fff2ae","#f1e2cc","#cccccc"],Pastel1:["#fbb4ae","#b3cde3","#ccebc5","#decbe4","#fed9a6","#ffffcc","#e5d8bd","#fddaec","#f2f2f2"]},Pn=Object.keys(Be),zn=new Map(Pn.map(e=>[e.toLowerCase(),e])),Ba=typeof Proxy=="function"?new Proxy(Be,{get(e,t){const r=t.toLowerCase();if(zn.has(r))return e[zn.get(r)]},getOwnPropertyNames(){return Object.getOwnPropertyNames(Pn)}}):Be,Ia=(...e)=>{e=E(e,"cmyk");const[t,r,n,o]=e,i=e.length>4?e[4]:1;return o===1?[0,0,0,i]:[t>=1?0:255*(1-t)*(1-o),r>=1?0:255*(1-r)*(1-o),n>=1?0:255*(1-n)*(1-o),i]},{max:Bn}=Math,Ga=(...e)=>{let[t,r,n]=E(e,"rgb");t=t/255,r=r/255,n=n/255;const o=1-Bn(t,Bn(r,n)),i=o<1?1/(1-o):0,s=(1-t-o)*i,a=(1-r-o)*i,c=(1-n-o)*i;return[s,a,c,o]};_.prototype.cmyk=function(){return Ga(this._rgb)},Object.assign(k,{cmyk:(...e)=>new _(...e,"cmyk")}),$.format.cmyk=Ia,$.autodetect.push({p:2,test:(...e)=>{if(e=E(e,"cmyk"),N(e)==="array"&&e.length===4)return"cmyk"}});const Fa=(...e)=>{const t=E(e,"hsla");let r=Et(e)||"lsa";return t[0]=et(t[0]||0)+"deg",t[1]=et(t[1]*100)+"%",t[2]=et(t[2]*100)+"%",r==="hsla"||t.length>3&&t[3]<1?(t[3]="/ "+(t.length>3?t[3]:1),r="hsla"):t.length=3,`${r.substr(0,3)}(${t.join(" ")})`},Ka=(...e)=>{const t=E(e,"lab");let r=Et(e)||"lab";return t[0]=et(t[0])+"%",t[1]=et(t[1]),t[2]=et(t[2]),r==="laba"||t.length>3&&t[3]<1?t[3]="/ "+(t.length>3?t[3]:1):t.length=3,`lab(${t.join(" ")})`},Xa=(...e)=>{const t=E(e,"lch");let r=Et(e)||"lab";return t[0]=et(t[0])+"%",t[1]=et(t[1]),t[2]=isNaN(t[2])?"none":et(t[2])+"deg",r==="lcha"||t.length>3&&t[3]<1?t[3]="/ "+(t.length>3?t[3]:1):t.length=3,`lch(${t.join(" ")})`},Da=(...e)=>{const t=E(e,"lab");return t[0]=et(t[0]*100)+"%",t[1]=Ce(t[1]),t[2]=Ce(t[2]),t.length>3&&t[3]<1?t[3]="/ "+(t.length>3?t[3]:1):t.length=3,`oklab(${t.join(" ")})`},In=(...e)=>{const[t,r,n,...o]=E(e,"rgb"),[i,s,a]=Te(t,r,n),[c,u,f]=yn(i,s,a);return[c,u,f,...o.length>0&&o[0]<1?[o[0]]:[]]},Va=(...e)=>{const t=E(e,"lch");return t[0]=et(t[0]*100)+"%",t[1]=Ce(t[1]),t[2]=isNaN(t[2])?"none":et(t[2])+"deg",t.length>3&&t[3]<1?t[3]="/ "+(t.length>3?t[3]:1):t.length=3,`oklch(${t.join(" ")})`},{round:Ie}=Math,Ya=(...e)=>{const t=E(e,"rgba");let r=Et(e)||"rgb";if(r.substr(0,3)==="hsl")return Fa(xn(t),r);if(r.substr(0,3)==="lab"){const n=Kt();ht("d50");const o=Ka(Me(t),r);return ht(n),o}if(r.substr(0,3)==="lch"){const n=Kt();ht("d50");const o=Xa($e(t),r);return ht(n),o}return r.substr(0,5)==="oklab"?Da(Te(t)):r.substr(0,5)==="oklch"?Va(In(t)):(t[0]=Ie(t[0]),t[1]=Ie(t[1]),t[2]=Ie(t[2]),(r==="rgba"||t.length>3&&t[3]<1)&&(t[3]="/ "+(t.length>3?t[3]:1),r="rgba"),`${r.substr(0,3)}(${t.slice(0,r==="rgb"?3:4).join(" ")})`)},Gn=(...e)=>{e=E(e,"lch");const[t,r,n,...o]=e,[i,s,a]=vn(t,r,n),[c,u,f]=Ne(i,s,a);return[c,u,f,...o.length>0&&o[0]<1?[o[0]]:[]]},bt=/((?:-?\d+)|(?:-?\d+(?:\.\d+)?)%|none)/.source,ot=/((?:-?(?:\d+(?:\.\d*)?|\.\d+)%?)|none)/.source,ne=/((?:-?(?:\d+(?:\.\d*)?|\.\d+)%)|none)/.source,rt=/\s*/.source,zt=/\s+/.source,Ge=/\s*,\s*/.source,oe=/((?:-?(?:\d+(?:\.\d*)?|\.\d+)(?:deg)?)|none)/.source,Bt=/\s*(?:\/\s*((?:[01]|[01]?\.\d+)|\d+(?:\.\d+)?%))?/.source,Fn=new RegExp("^rgba?\\("+rt+[bt,bt,bt].join(zt)+Bt+"\\)$"),Kn=new RegExp("^rgb\\("+rt+[bt,bt,bt].join(Ge)+rt+"\\)$"),Xn=new RegExp("^rgba\\("+rt+[bt,bt,bt,ot].join(Ge)+rt+"\\)$"),Dn=new RegExp("^hsla?\\("+rt+[oe,ne,ne].join(zt)+Bt+"\\)$"),Vn=new RegExp("^hsl?\\("+rt+[oe,ne,ne].join(Ge)+rt+"\\)$"),Yn=/^hsla\(\s*(-?\d+(?:\.\d+)?),\s*(-?\d+(?:\.\d+)?)%\s*,\s*(-?\d+(?:\.\d+)?)%\s*,\s*([01]|[01]?\.\d+)\)$/,Zn=new RegExp("^lab\\("+rt+[ot,ot,ot].join(zt)+Bt+"\\)$"),Jn=new RegExp("^lch\\("+rt+[ot,ot,oe].join(zt)+Bt+"\\)$"),Hn=new RegExp("^oklab\\("+rt+[ot,ot,ot].join(zt)+Bt+"\\)$"),Wn=new RegExp("^oklch\\("+rt+[ot,ot,oe].join(zt)+Bt+"\\)$"),{round:Un}=Math,It=e=>e.map((t,r)=>r<=2?qt(Un(t),0,255):t),K=(e,t=0,r=100,n=!1)=>(typeof e=="string"&&e.endsWith("%")&&(e=parseFloat(e.substring(0,e.length-1))/100,n?e=t+(e+1)*.5*(r-t):e=t+e*(r-t)),+e),W=(e,t)=>e==="none"?t:e,Fe=e=>{if(e=e.toLowerCase().trim(),e==="transparent")return[0,0,0,0];let t;if($.format.named)try{return $.format.named(e)}catch{}if((t=e.match(Fn))||(t=e.match(Kn))){let r=t.slice(1,4);for(let o=0;o<3;o++)r[o]=+K(W(r[o],0),0,255);r=It(r);const n=t[4]!==void 0?+K(t[4],0,1):1;return r[3]=n,r}if(t=e.match(Xn)){const r=t.slice(1,5);for(let n=0;n<4;n++)r[n]=+K(r[n],0,255);return r}if((t=e.match(Dn))||(t=e.match(Vn))){const r=t.slice(1,4);r[0]=+W(r[0].replace("deg",""),0),r[1]=+K(W(r[1],0),0,100)*.01,r[2]=+K(W(r[2],0),0,100)*.01;const n=It(Le(r)),o=t[4]!==void 0?+K(t[4],0,1):1;return n[3]=o,n}if(t=e.match(Yn)){const r=t.slice(1,4);r[1]*=.01,r[2]*=.01;const n=Le(r);for(let o=0;o<3;o++)n[o]=Un(n[o]);return n[3]=+t[4],n}if(t=e.match(Zn)){const r=t.slice(1,4);r[0]=K(W(r[0],0),0,100),r[1]=K(W(r[1],0),-125,125,!0),r[2]=K(W(r[2],0),-125,125,!0);const n=Kt();ht("d50");const o=It(Re(r));ht(n);const i=t[4]!==void 0?+K(t[4],0,1):1;return o[3]=i,o}if(t=e.match(Jn)){const r=t.slice(1,4);r[0]=K(r[0],0,100),r[1]=K(W(r[1],0),0,150,!1),r[2]=+W(r[2].replace("deg",""),0);const n=Kt();ht("d50");const o=It(Se(r));ht(n);const i=t[4]!==void 0?+K(t[4],0,1):1;return o[3]=i,o}if(t=e.match(Hn)){const r=t.slice(1,4);r[0]=K(W(r[0],0),0,1),r[1]=K(W(r[1],0),-.4,.4,!0),r[2]=K(W(r[2],0),-.4,.4,!0);const n=It(Ne(r)),o=t[4]!==void 0?+K(t[4],0,1):1;return n[3]=o,n}if(t=e.match(Wn)){const r=t.slice(1,4);r[0]=K(W(r[0],0),0,1),r[1]=K(W(r[1],0),0,.4,!1),r[2]=+W(r[2].replace("deg",""),0);const n=It(Gn(r)),o=t[4]!==void 0?+K(t[4],0,1):1;return n[3]=o,n}};Fe.test=e=>Fn.test(e)||Dn.test(e)||Zn.test(e)||Jn.test(e)||Hn.test(e)||Wn.test(e)||Kn.test(e)||Xn.test(e)||Vn.test(e)||Yn.test(e)||e==="transparent",_.prototype.css=function(e){return Ya(this._rgb,e)};const Za=(...e)=>new _(...e,"css");k.css=Za,$.format.css=Fe,$.autodetect.push({p:5,test:(e,...t)=>{if(!t.length&&N(e)==="string"&&Fe.test(e))return"css"}}),$.format.gl=(...e)=>{const t=E(e,"rgba");return t[0]*=255,t[1]*=255,t[2]*=255,t};const Ja=(...e)=>new _(...e,"gl");k.gl=Ja,_.prototype.gl=function(){const e=this._rgb;return[e[0]/255,e[1]/255,e[2]/255,e[3]]},_.prototype.hex=function(e){return mn(this._rgb,e)};const Ha=(...e)=>new _(...e,"hex");k.hex=Ha,$.format.hex=pn,$.autodetect.push({p:4,test:(e,...t)=>{if(!t.length&&N(e)==="string"&&[3,4,5,6,7,8,9].indexOf(e.length)>=0)return"hex"}});const{log:se}=Math,Qn=e=>{const t=e/100;let r,n,o;return t<66?(r=255,n=t<6?0:-155.25485562709179-.44596950469579133*(n=t-2)+104.49216199393888*se(n),o=t<20?0:-254.76935184120902+.8274096064007395*(o=t-10)+115.67994401066147*se(o)):(r=351.97690566805693+.114206453784165*(r=t-55)-40.25366309332127*se(r),n=325.4494125711974+.07943456536662342*(n=t-50)-28.0852963507957*se(n),o=255),[r,n,o,1]},{round:Wa}=Math,Ua=(...e)=>{const t=E(e,"rgb"),r=t[0],n=t[2];let o=1e3,i=4e4;const s=.4;let a;for(;i-o>s;){a=(i+o)*.5;const c=Qn(a);c[2]/c[0]>=n/r?i=a:o=a}return Wa(a)};_.prototype.temp=_.prototype.kelvin=_.prototype.temperature=function(){return Ua(this._rgb)};const Ke=(...e)=>new _(...e,"temp");Object.assign(k,{temp:Ke,kelvin:Ke,temperature:Ke}),$.format.temp=$.format.kelvin=$.format.temperature=Qn,_.prototype.oklch=function(){return In(this._rgb)},Object.assign(k,{oklch:(...e)=>new _(...e,"oklch")}),$.format.oklch=Gn,$.autodetect.push({p:2,test:(...e)=>{if(e=E(e,"oklch"),N(e)==="array"&&e.length===3)return"oklch"}}),Object.assign(k,{analyze:Mn,average:ra,bezier:ca,blend:nt,brewer:Ba,Color:_,colors:Lt,contrast:Oa,contrastAPCA:$a,cubehelix:ya,deltaE:Ta,distance:ja,input:$,interpolate:Nt,limits:On,mix:Nt,random:ka,scale:te,scales:za,valid:Pa});class v{constructor(){this.hex="#000000",this.rgb_r=0,this.rgb_g=0,this.rgb_b=0,this.xyz_x=0,this.xyz_y=0,this.xyz_z=0,this.luv_l=0,this.luv_u=0,this.luv_v=0,this.lch_l=0,this.lch_c=0,this.lch_h=0,this.hsluv_h=0,this.hsluv_s=0,this.hsluv_l=0,this.hpluv_h=0,this.hpluv_p=0,this.hpluv_l=0,this.r0s=0,this.r0i=0,this.r1s=0,this.r1i=0,this.g0s=0,this.g0i=0,this.g1s=0,this.g1i=0,this.b0s=0,this.b0i=0,this.b1s=0,this.b1i=0}static fromLinear(t){return t<=.0031308?12.92*t:1.055*Math.pow(t,.4166666666666667)-.055}static toLinear(t){return t>.04045?Math.pow((t+.055)/1.055,2.4):t/12.92}static yToL(t){return t<=v.epsilon?t/v.refY*v.kappa:116*Math.pow(t/v.refY,.3333333333333333)-16}static lToY(t){return t<=8?v.refY*t/v.kappa:v.refY*Math.pow((t+16)/116,3)}static rgbChannelToHex(t){const r=Math.round(t*255),n=r%16,o=(r-n)/16|0;return v.hexChars.charAt(o)+v.hexChars.charAt(n)}static hexToRgbChannel(t,r){const n=v.hexChars.indexOf(t.charAt(r)),o=v.hexChars.indexOf(t.charAt(r+1));return(n*16+o)/255}static distanceFromOriginAngle(t,r,n){const o=r/(Math.sin(n)-t*Math.cos(n));return o<0?1/0:o}static distanceFromOrigin(t,r){return Math.abs(r)/Math.sqrt(Math.pow(t,2)+1)}static min6(t,r,n,o,i,s){return Math.min(t,Math.min(r,Math.min(n,Math.min(o,Math.min(i,s)))))}rgbToHex(){this.hex="#",this.hex+=v.rgbChannelToHex(this.rgb_r),this.hex+=v.rgbChannelToHex(this.rgb_g),this.hex+=v.rgbChannelToHex(this.rgb_b)}hexToRgb(){this.hex=this.hex.toLowerCase(),this.rgb_r=v.hexToRgbChannel(this.hex,1),this.rgb_g=v.hexToRgbChannel(this.hex,3),this.rgb_b=v.hexToRgbChannel(this.hex,5)}xyzToRgb(){this.rgb_r=v.fromLinear(v.m_r0*this.xyz_x+v.m_r1*this.xyz_y+v.m_r2*this.xyz_z),this.rgb_g=v.fromLinear(v.m_g0*this.xyz_x+v.m_g1*this.xyz_y+v.m_g2*this.xyz_z),this.rgb_b=v.fromLinear(v.m_b0*this.xyz_x+v.m_b1*this.xyz_y+v.m_b2*this.xyz_z)}rgbToXyz(){const t=v.toLinear(this.rgb_r),r=v.toLinear(this.rgb_g),n=v.toLinear(this.rgb_b);this.xyz_x=.41239079926595*t+.35758433938387*r+.18048078840183*n,this.xyz_y=.21263900587151*t+.71516867876775*r+.072192315360733*n,this.xyz_z=.019330818715591*t+.11919477979462*r+.95053215224966*n}xyzToLuv(){const t=this.xyz_x+15*this.xyz_y+3*this.xyz_z;let r=4*this.xyz_x,n=9*this.xyz_y;t!==0?(r/=t,n/=t):(r=NaN,n=NaN),this.luv_l=v.yToL(this.xyz_y),this.luv_l===0?(this.luv_u=0,this.luv_v=0):(this.luv_u=13*this.luv_l*(r-v.refU),this.luv_v=13*this.luv_l*(n-v.refV))}luvToXyz(){if(this.luv_l===0){this.xyz_x=0,this.xyz_y=0,this.xyz_z=0;return}const t=this.luv_u/(13*this.luv_l)+v.refU,r=this.luv_v/(13*this.luv_l)+v.refV;this.xyz_y=v.lToY(this.luv_l),this.xyz_x=0-9*this.xyz_y*t/((t-4)*r-t*r),this.xyz_z=(9*this.xyz_y-15*r*this.xyz_y-r*this.xyz_x)/(3*r)}luvToLch(){if(this.lch_l=this.luv_l,this.lch_c=Math.sqrt(this.luv_u*this.luv_u+this.luv_v*this.luv_v),this.lch_c<1e-8)this.lch_h=0;else{const t=Math.atan2(this.luv_v,this.luv_u);this.lch_h=t*180/Math.PI,this.lch_h<0&&(this.lch_h=360+this.lch_h)}}lchToLuv(){const t=this.lch_h/180*Math.PI;this.luv_l=this.lch_l,this.luv_u=Math.cos(t)*this.lch_c,this.luv_v=Math.sin(t)*this.lch_c}calculateBoundingLines(t){const r=Math.pow(t+16,3)/1560896,n=r>v.epsilon?r:t/v.kappa,o=n*(284517*v.m_r0-94839*v.m_r2),i=n*(838422*v.m_r2+769860*v.m_r1+731718*v.m_r0),s=n*(632260*v.m_r2-126452*v.m_r1),a=n*(284517*v.m_g0-94839*v.m_g2),c=n*(838422*v.m_g2+769860*v.m_g1+731718*v.m_g0),u=n*(632260*v.m_g2-126452*v.m_g1),f=n*(284517*v.m_b0-94839*v.m_b2),l=n*(838422*v.m_b2+769860*v.m_b1+731718*v.m_b0),h=n*(632260*v.m_b2-126452*v.m_b1);this.r0s=o/s,this.r0i=i*t/s,this.r1s=o/(s+126452),this.r1i=(i-769860)*t/(s+126452),this.g0s=a/u,this.g0i=c*t/u,this.g1s=a/(u+126452),this.g1i=(c-769860)*t/(u+126452),this.b0s=f/h,this.b0i=l*t/h,this.b1s=f/(h+126452),this.b1i=(l-769860)*t/(h+126452)}calcMaxChromaHpluv(){const t=v.distanceFromOrigin(this.r0s,this.r0i),r=v.distanceFromOrigin(this.r1s,this.r1i),n=v.distanceFromOrigin(this.g0s,this.g0i),o=v.distanceFromOrigin(this.g1s,this.g1i),i=v.distanceFromOrigin(this.b0s,this.b0i),s=v.distanceFromOrigin(this.b1s,this.b1i);return v.min6(t,r,n,o,i,s)}calcMaxChromaHsluv(t){const r=t/360*Math.PI*2,n=v.distanceFromOriginAngle(this.r0s,this.r0i,r),o=v.distanceFromOriginAngle(this.r1s,this.r1i,r),i=v.distanceFromOriginAngle(this.g0s,this.g0i,r),s=v.distanceFromOriginAngle(this.g1s,this.g1i,r),a=v.distanceFromOriginAngle(this.b0s,this.b0i,r),c=v.distanceFromOriginAngle(this.b1s,this.b1i,r);return v.min6(n,o,i,s,a,c)}hsluvToLch(){if(this.hsluv_l>99.9999999)this.lch_l=100,this.lch_c=0;else if(this.hsluv_l<1e-8)this.lch_l=0,this.lch_c=0;else{this.lch_l=this.hsluv_l,this.calculateBoundingLines(this.hsluv_l);const t=this.calcMaxChromaHsluv(this.hsluv_h);this.lch_c=t/100*this.hsluv_s}this.lch_h=this.hsluv_h}lchToHsluv(){if(this.lch_l>99.9999999)this.hsluv_s=0,this.hsluv_l=100;else if(this.lch_l<1e-8)this.hsluv_s=0,this.hsluv_l=0;else{this.calculateBoundingLines(this.lch_l);const t=this.calcMaxChromaHsluv(this.lch_h);this.hsluv_s=this.lch_c/t*100,this.hsluv_l=this.lch_l}this.hsluv_h=this.lch_h}hpluvToLch(){if(this.hpluv_l>99.9999999)this.lch_l=100,this.lch_c=0;else if(this.hpluv_l<1e-8)this.lch_l=0,this.lch_c=0;else{this.lch_l=this.hpluv_l,this.calculateBoundingLines(this.hpluv_l);const t=this.calcMaxChromaHpluv();this.lch_c=t/100*this.hpluv_p}this.lch_h=this.hpluv_h}lchToHpluv(){if(this.lch_l>99.9999999)this.hpluv_p=0,this.hpluv_l=100;else if(this.lch_l<1e-8)this.hpluv_p=0,this.hpluv_l=0;else{this.calculateBoundingLines(this.lch_l);const t=this.calcMaxChromaHpluv();this.hpluv_p=this.lch_c/t*100,this.hpluv_l=this.lch_l}this.hpluv_h=this.lch_h}hsluvToRgb(){this.hsluvToLch(),this.lchToLuv(),this.luvToXyz(),this.xyzToRgb()}hpluvToRgb(){this.hpluvToLch(),this.lchToLuv(),this.luvToXyz(),this.xyzToRgb()}hsluvToHex(){this.hsluvToRgb(),this.rgbToHex()}hpluvToHex(){this.hpluvToRgb(),this.rgbToHex()}rgbToHsluv(){this.rgbToXyz(),this.xyzToLuv(),this.luvToLch(),this.lchToHpluv(),this.lchToHsluv()}rgbToHpluv(){this.rgbToXyz(),this.xyzToLuv(),this.luvToLch(),this.lchToHpluv(),this.lchToHpluv()}hexToHsluv(){this.hexToRgb(),this.rgbToHsluv()}hexToHpluv(){this.hexToRgb(),this.rgbToHpluv()}}v.hexChars="0123456789abcdef",v.refY=1,v.refU=.19783000664283,v.refV=.46831999493879,v.kappa=903.2962962,v.epsilon=.0088564516,v.m_r0=3.240969941904521,v.m_r1=-1.537383177570093,v.m_r2=-.498610760293,v.m_g0=-.96924363628087,v.m_g1=1.87596750150772,v.m_g2=.041555057407175,v.m_b0=.055630079696993,v.m_b1=-.20397695888897,v.m_b2=1.056971514242878;function to(e){return e&&e.__esModule&&Object.prototype.hasOwnProperty.call(e,"default")?e.default:e}var ie={exports:{}},Xe,eo;function Xt(){if(eo)return Xe;eo=1;function e(t,r){return Object.prototype.hasOwnProperty.call(t,r)}return Xe=e,Xe}var De,ro;function Ve(){if(ro)return De;ro=1;var e=Xt(),t,r;function n(){r=["toString","toLocaleString","valueOf","hasOwnProperty","isPrototypeOf","propertyIsEnumerable","constructor"],t=!0;for(var s in{toString:null})t=!1}function o(s,a,c){var u,f=0;t==null&&n();for(u in s)if(i(a,s,u,c)===!1)break;if(t)for(var l=s.constructor,h=!!l&&s===l.prototype;(u=r[f++])&&!((u!=="constructor"||!h&&e(s,u))&&s[u]!==Object.prototype[u]&&i(a,s,u,c)===!1););}function i(s,a,c,u){return s.call(u,a[c],c,a)}return De=o,De}var Ye,no;function oo(){if(no)return Ye;no=1;var e=Ve();function t(r){var n=[];return e(r,function(o,i){typeof o=="function"&&n.push(i)}),n.sort()}return Ye=t,Ye}var Ze,so;function Dt(){if(so)return Ze;so=1;function e(t,r,n){var o=t.length;r==null?r=0:r<0?r=Math.max(o+r,0):r=Math.min(r,o),n==null?n=o:n<0?n=Math.max(o+n,0):n=Math.min(n,o);for(var i=[];r1?n(arguments,1):e(i);r(a,function(c){i[c]=t(i[c],i)})}return Ue=o,Ue}var Qe,uo;function V(){if(uo)return Qe;uo=1;var e=Xt(),t=Ve();function r(n,o,i){t(n,function(s,a){if(e(n,a))return o.call(i,n[a],a,n)})}return Qe=r,Qe}var tr,lo;function ec(){if(lo)return tr;lo=1;function e(t){return t}return tr=e,tr}var er,fo;function ho(){if(fo)return er;fo=1;function e(t){return function(r){return r[t]}}return er=e,er}var rr,bo;function nr(){if(bo)return rr;bo=1;var e=/^\[object (.*)\]$/,t=Object.prototype.toString,r;function n(o){return o===null?"Null":o===r?"Undefined":e.exec(t.call(o))[1]}return rr=n,rr}var or,po;function sr(){if(po)return or;po=1;var e=nr();function t(r,n){return e(r)===n}return or=t,or}var ir,mo;function rc(){if(mo)return ir;mo=1;var e=sr(),t=Array.isArray||function(r){return e(r,"Array")};return ir=t,ir}var ar,go;function _o(){if(go)return ar;go=1;var e=V(),t=rc();function r(s,a){for(var c=-1,u=s.length;++cs&&(s=c,i=a);return i}return Or=t,Or}var Ar,Do;function Sr(){if(Do)return Ar;Do=1;var e=V();function t(r){var n=[];return e(r,function(o,i){n.push(o)}),n}return Ar=t,Ar}var $r,Vo;function bc(){if(Vo)return $r;Vo=1;var e=dc(),t=Sr();function r(n,o){return e(t(n),o)}return $r=r,$r}var Er,Yo;function Zo(){if(Yo)return Er;Yo=1;var e=V();function t(n,o){for(var i=0,s=arguments.length,a;++i2;if(!t(n)&&!a)throw new Error("reduce of empty object with no initial value");return e(n,function(c,u,f){a?i=o.call(s,i,c,u,f):(i=c,a=!0)}),i}return Dr=r,Dr}var Vr,ls;function qc(){if(ls)return Vr;ls=1;var e=Lo(),t=yt();function r(n,o,i){return o=t(o,i),e(n,function(s,a,c){return!o(s,a,c)},i)}return Vr=r,Vr}var Yr,fs;function Mc(){if(fs)return Yr;fs=1;var e=sr();function t(r){return e(r,"Function")}return Yr=t,Yr}var Zr,hs;function Oc(){if(hs)return Zr;hs=1;var e=Mc();function t(r,n){var o=r[n];if(o!==void 0)return e(o)?o.call(r):o}return Zr=t,Zr}var Jr,ds;function Ac(){if(ds)return Jr;ds=1;var e=es();function t(r,n,o){var i=/^(.+)\.(.+)$/.exec(n);i?e(r,i[1])[i[2]]=o:r[n]=o}return Jr=t,Jr}var Hr,bs;function Sc(){if(bs)return Hr;bs=1;var e=Bo();function t(r,n){if(e(r,n)){for(var o=n.split("."),i=o.pop();n=o.shift();)r=r[n];return delete r[i]}else return!0}return Hr=t,Hr}var Wr,ps;function Ur(){return ps||(ps=1,Wr={bindAll:tc(),contains:nc(),deepFillIn:oc(),deepMatches:_o(),deepMixIn:sc(),equals:ac(),every:qo(),fillIn:cc(),filter:Lo(),find:uc(),flatten:lc(),forIn:Ve(),forOwn:V(),functions:oo(),get:Po(),has:Bo(),hasOwn:Xt(),keys:fc(),map:Fo(),matches:hc(),max:bc(),merge:gc(),min:vc(),mixIn:Zo(),namespace:es(),omit:xc(),pick:Cc(),pluck:kc(),reduce:Rc(),reject:qc(),result:Oc(),set:Ac(),size:cs(),some:lr(),unset:Sc(),values:Sr()}),Wr}var ms;function gs(){return ms||(ms=1,(function(e,t){Object.defineProperty(t,"__esModule",{value:!0});var r=Ur(),n={A:{x:.44758,y:.40745},C:{x:.31006,y:.31616},D50:{x:.34567,y:.35851},D65:{x:.31272,y:.32903},D55:{x:.33243,y:.34744},D75:{x:.29903,y:.31488}},o=(0,r.map)(n,function(i){var s=100*(i.x/i.y),a=100,c=100*(1-i.x-i.y)/i.y;return[s,a,c]});t.default=o,e.exports=t.default})(ie,ie.exports)),ie.exports}var ae={exports:{}},_s;function vs(){return _s||(_s=1,(function(e,t){Object.defineProperty(t,"__esModule",{value:!0});var r=Math,n=r.pow,o=r.sign,i=r.abs,s={decode:function(l){return l<=.04045?l/12.92:n((l+.055)/1.055,2.4)},encode:function(l){return l<=.0031308?12.92*l:1.055*n(l,1/2.4)-.055}},a={encode:function(l){return l<.001953125?16*l:n(l,1/1.8)},decode:function(l){return l<16*.001953125?l/16:n(l,1.8)}};function c(f){return{decode:function(h){return o(h)*n(i(h),f)},encode:function(h){return o(h)*n(i(h),1/f)}}}var u={sRGB:{r:{x:.64,y:.33},g:{x:.3,y:.6},b:{x:.15,y:.06},gamma:s},"Adobe RGB":{r:{x:.64,y:.33},g:{x:.21,y:.71},b:{x:.15,y:.06},gamma:c(2.2)},"Wide Gamut RGB":{r:{x:.7347,y:.2653},g:{x:.1152,y:.8264},b:{x:.1566,y:.0177},gamma:c(563/256)},"ProPhoto RGB":{r:{x:.7347,y:.2653},g:{x:.1596,y:.8404},b:{x:.0366,y:1e-4},gamma:a}};t.default=u,e.exports=t.default})(ae,ae.exports)),ae.exports}var pt={},ys;function ws(){if(ys)return pt;ys=1,Object.defineProperty(pt,"__esModule",{value:!0});function e(s){return[[s[0][0],s[1][0],s[2][0]],[s[0][1],s[1][1],s[2][1]],[s[0][2],s[1][2],s[2][2]]]}function t(s){return s[0][0]*(s[2][2]*s[1][1]-s[2][1]*s[1][2])+s[1][0]*(s[2][1]*s[0][2]-s[2][2]*s[0][1])+s[2][0]*(s[1][2]*s[0][1]-s[1][1]*s[0][2])}function r(s){var a=1/t(s);return[[(s[2][2]*s[1][1]-s[2][1]*s[1][2])*a,(s[2][1]*s[0][2]-s[2][2]*s[0][1])*a,(s[1][2]*s[0][1]-s[1][1]*s[0][2])*a],[(s[2][0]*s[1][2]-s[2][2]*s[1][0])*a,(s[2][2]*s[0][0]-s[2][0]*s[0][2])*a,(s[1][0]*s[0][2]-s[1][2]*s[0][0])*a],[(s[2][1]*s[1][0]-s[2][0]*s[1][1])*a,(s[2][0]*s[0][1]-s[2][1]*s[0][0])*a,(s[1][1]*s[0][0]-s[1][0]*s[0][1])*a]]}function n(s,a){return[s[0][0]*a[0]+s[0][1]*a[1]+s[0][2]*a[2],s[1][0]*a[0]+s[1][1]*a[1]+s[1][2]*a[2],s[2][0]*a[0]+s[2][1]*a[1]+s[2][2]*a[2]]}function o(s,a){return[[s[0][0]*a[0],s[0][1]*a[1],s[0][2]*a[2]],[s[1][0]*a[0],s[1][1]*a[1],s[1][2]*a[2]],[s[2][0]*a[0],s[2][1]*a[1],s[2][2]*a[2]]]}function i(s,a){return[[s[0][0]*a[0][0]+s[0][1]*a[1][0]+s[0][2]*a[2][0],s[0][0]*a[0][1]+s[0][1]*a[1][1]+s[0][2]*a[2][1],s[0][0]*a[0][2]+s[0][1]*a[1][2]+s[0][2]*a[2][2]],[s[1][0]*a[0][0]+s[1][1]*a[1][0]+s[1][2]*a[2][0],s[1][0]*a[0][1]+s[1][1]*a[1][1]+s[1][2]*a[2][1],s[1][0]*a[0][2]+s[1][1]*a[1][2]+s[1][2]*a[2][2]],[s[2][0]*a[0][0]+s[2][1]*a[1][0]+s[2][2]*a[2][0],s[2][0]*a[0][1]+s[2][1]*a[1][1]+s[2][2]*a[2][1],s[2][0]*a[0][2]+s[2][1]*a[1][2]+s[2][2]*a[2][2]]]}return pt.transpose=e,pt.determinant=t,pt.inverse=r,pt.multiply=n,pt.scalar=o,pt.product=i,pt}var Yt={},xs;function $c(){if(xs)return Yt;xs=1,Object.defineProperty(Yt,"__esModule",{value:!0});var e=Math,t=e.PI;function r(o){for(var i=o*180/t;i<0;)i+=360;for(;i>360;)i-=360;return i}function n(o){for(var i=t*o/180;i<0;)i+=2*t;for(;i>2*t;)i-=2*t;return i}return Yt.fromRadian=r,Yt.toRadian=n,Yt}var Zt={},Cs;function Ec(){if(Cs)return Zt;Cs=1,Object.defineProperty(Zt,"__esModule",{value:!0});var e=Math,t=e.round;function r(o){return o[0]=="#"&&(o=o.slice(1)),o.length<6&&(o=o.split("").map(function(i){return i+i}).join("")),o.match(/../g).map(function(i){return parseInt(i,16)/255})}function n(o){var i=o.map(function(s){return s=t(255*s).toString(16),s.length<2&&(s="0"+s),s}).join("");return"#"+i}return Zt.fromHex=r,Zt.toHex=n,Zt}var ce={exports:{}},ks;function Lc(){return ks||(ks=1,(function(e,t){Object.defineProperty(t,"__esModule",{value:!0});var r=ws(),n=u(r),o=gs(),i=c(o),s=vs(),a=c(s);function c(l){return l&&l.__esModule?l:{default:l}}function u(l){if(l&&l.__esModule)return l;var h={};if(l!=null)for(var d in l)Object.prototype.hasOwnProperty.call(l,d)&&(h[d]=l[d]);return h.default=l,h}function f(){var l=arguments.length<=0||arguments[0]===void 0?a.default.sRGB:arguments[0],h=arguments.length<=1||arguments[1]===void 0?i.default.D65:arguments[1],d=[l.r,l.g,l.b],b=n.transpose(d.map(function(w){var x=w.x/w.y,S=1,R=(1-w.x-w.y)/w.y;return[x,S,R]})),g=l.gamma,m=n.multiply(n.inverse(b),h),y=n.scalar(b,m),L=n.inverse(y);return{fromRgb:function(x){return n.multiply(y,x.map(g.decode))},toRgb:function(x){return n.multiply(L,x).map(g.encode)}}}t.default=f,e.exports=t.default})(ce,ce.exports)),ce.exports}var Qr,Rs;function ue(){if(Rs)return Qr;Rs=1;var e=gs(),t=vs(),r=ws(),n=$c(),o=Ec(),i=Lc();return Qr={illuminant:e,workspace:t,matrix:r,degree:n,rgb:o,xyz:i},Qr}var Nc=ue();const le=to(Nc);var st={},qs;function fe(){if(qs)return st;qs=1,Object.defineProperty(st,"__esModule",{value:!0}),st.cfs=st.distance=st.lerp=st.corLerp=void 0;var e=Ur();function t(h,d,b){return d in h?Object.defineProperty(h,d,{value:b,enumerable:!0,configurable:!0,writable:!0}):h[d]=b,h}function r(h){if(Array.isArray(h)){for(var d=0,b=Array(h.length);dm/2&&(h>d?d+=m:h+=m)}return((1-b)*h+b*d)%(m||1/0)}function u(h,d,b){var g={};for(var m in h)g[m]=c(h[m],d[m],b,m);return g}function f(h,d){var b=0;for(var g in h)b+=i(h[g]-d[g],2);return s(b)}function l(h){return e.merge.apply(void 0,r(h.split("").map(function(d){return t({},d,!0)})))}return st.corLerp=c,st.lerp=u,st.distance=f,st.cfs=l,st}var he={exports:{}},Ms;function Tc(){return Ms||(Ms=1,(function(e,t){var r=(function(){function s(a,c){var u=[],f=!0,l=!1,h=void 0;try{for(var d=a[Symbol.iterator](),b;!(f=(b=d.next()).done)&&(u.push(b.value),!(c&&u.length===c));f=!0);}catch(g){l=!0,h=g}finally{try{!f&&d.return&&d.return()}finally{if(l)throw h}}return u}return function(a,c){if(Array.isArray(a))return a;if(Symbol.iterator in Object(a))return s(a,c);throw new TypeError("Invalid attempt to destructure non-iterable instance")}})();Object.defineProperty(t,"__esModule",{value:!0});var n=ue(),o=fe();function i(s,a){var c=arguments.length<=2||arguments[2]===void 0?1e-6:arguments[2],u=-c,f=1+c,l=Math,h=l.min,d=l.max,b=["000","fff"].map(function(R){return a.fromXyz(s.fromRgb(n.rgb.fromHex(R)))}),g=r(b,2),m=g[0],y=g[1];function L(R){var M=s.toRgb(a.toXyz(R)),p=M.map(function(C){return C>=u&&C<=f}).reduce(function(C,O){return C&&O},!0);return[p,M]}function w(R,M){for(var p=arguments.length<=2||arguments[2]===void 0?.001:arguments[2];(0,o.distance)(R,M)>p;){var C=(0,o.lerp)(R,M,.5),O=L(C),q=r(O,1),T=q[0];T?R=C:M=C}return R}function x(R){return(0,o.lerp)(m,y,R)}function S(R){return R.map(function(M){return d(u,h(f,M))})}return{contains:L,limit:w,spine:x,crop:S}}t.default=i,e.exports=t.default})(he,he.exports)),he.exports}var de={exports:{}},it={},Os;function As(){if(Os)return it;Os=1;var e=(function(){function l(h,d){var b=[],g=!0,m=!1,y=void 0;try{for(var L=h[Symbol.iterator](),w;!(g=(w=L.next()).done)&&(b.push(w.value),!(d&&b.length===d));g=!0);}catch(x){m=!0,y=x}finally{try{!g&&L.return&&L.return()}finally{if(m)throw y}}return b}return function(h,d){if(Array.isArray(h))return h;if(Symbol.iterator in Object(h))return l(h,d);throw new TypeError("Invalid attempt to destructure non-iterable instance")}})();Object.defineProperty(it,"__esModule",{value:!0}),it.toNotation=it.fromNotation=it.toHue=it.fromHue=void 0;var t=fe(),r=Math,n=r.floor,o=[{s:"R",h:20.14,e:.8,H:0},{s:"Y",h:90,e:.7,H:100},{s:"G",h:164.25,e:1,H:200},{s:"B",h:237.53,e:1.2,H:300},{s:"R",h:380.14,e:.8,H:400}],i=o.map(function(l){return l.s}).slice(0,-1).join("");function s(l){l50){var g=[d,h];h=g[0],d=g[1],b=100-b}return b<1?i[h]:i[h]+b.toFixed()+i[d]}return it.fromHue=s,it.toHue=a,it.fromNotation=u,it.toNotation=f,it}var Ss;function jc(){return Ss||(Ss=1,(function(e,t){var r=(function(){function P(G,Y){var U=[],ut=!0,xt=!1,Jt=void 0;try{for(var lt=G[Symbol.iterator](),Mt;!(ut=(Mt=lt.next()).done)&&(U.push(Mt.value),!(Y&&U.length===Y));ut=!0);}catch(Ct){xt=!0,Jt=Ct}finally{try{!ut&<.return&<.return()}finally{if(xt)throw Jt}}return U}return function(G,Y){if(Array.isArray(G))return G;if(Symbol.iterator in Object(G))return P(G,Y);throw new TypeError("Invalid attempt to destructure non-iterable instance")}})();Object.defineProperty(t,"__esModule",{value:!0});var n=ue(),o=As(),i=c(o),s=fe(),a=Ur();function c(P){if(P&&P.__esModule)return P;var G={};if(P!=null)for(var Y in P)Object.prototype.hasOwnProperty.call(P,Y)&&(G[Y]=P[Y]);return G.default=P,G}var u=Math,f=u.pow,l=u.sqrt,h=u.exp,d=u.abs,b=u.sign,g=Math,m=g.sin,y=g.cos,L=g.atan2,w={average:{F:1,c:.69,N_c:1},dim:{F:.9,c:.59,N_c:.9},dark:{F:.8,c:.535,N_c:.8}},x=[[.7328,.4296,-.1624],[-.7036,1.6975,.0061],[.003,.0136,.9834]],S=[[.38971,.68898,-.07868],[-.22981,1.1834,.04641],[0,0,1]],R=x,M=n.matrix.inverse(x),p=n.matrix.product(S,n.matrix.inverse(x)),C=n.matrix.product(x,n.matrix.inverse(S)),O={whitePoint:n.illuminant.D65,adaptingLuminance:40,backgroundLuminance:20,surroundType:"average",discounting:!1},q=(0,s.cfs)("QJMCshH"),T=(0,s.cfs)("JCh");function A(){var P=arguments.length<=0||arguments[0]===void 0?{}:arguments[0],G=arguments.length<=1||arguments[1]===void 0?q:arguments[1];P=(0,a.merge)(O,P);var Y=P.whitePoint,U=P.adaptingLuminance,ut=P.backgroundLuminance,xt=w[P.surroundType],Jt=xt.F,lt=xt.c,Mt=xt.N_c,Ct=Y[1],Ys=1/(5*U+1),Ot=.2*f(Ys,4)*5*U+.1*f(1-f(Ys,4),2)*f(5*U,1/3),_e=ut/Ct,an=.725*f(1/_e,.2),Zs=an,Js=1.48+l(_e),Hs=P.discounting?1:Jt*(1-1/3.6*h(-(U+42)/92)),d0=n.matrix.multiply(x,Y),b0=d0.map(function(j){return Hs*Ct/j+1-Hs}),cn=r(b0,3),Ws=cn[0],Us=cn[1],Qs=cn[2],p0=ti(Y),m0=ei(p0),ve=ri(m0);function ti(j){var z=n.matrix.multiply(R,j),B=r(z,3),Z=B[0],D=B[1],tt=B[2];return[Ws*Z,Us*D,Qs*tt]}function g0(j){var z=r(j,3),B=z[0],Z=z[1],D=z[2];return n.matrix.multiply(M,[B/Ws,Z/Us,D/Qs])}function ei(j){return n.matrix.multiply(p,j).map(function(z){var B=f(Ot*d(z)/100,.42);return b(z)*400*B/(27.13+B)+.1})}function _0(j){return n.matrix.multiply(C,j.map(function(z){var B=z-.1;return b(B)*100/Ot*f(27.13*d(B)/(400-d(B)),2.380952380952381)}))}function ri(j){var z=r(j,3),B=z[0],Z=z[1],D=z[2];return(B*2+Z+D/20-.305)*an}function un(j){return 4/lt*l(j/100)*(ve+4)*f(Ot,.25)}function v0(j){return 6.25*f(lt*j/((ve+4)*f(Ot,.25)),2)}function ni(j){return j*f(Ot,.25)}function y0(j,z){return f(j/100,2)*z/f(Ot,.25)}function w0(j){return j/f(Ot,.25)}function x0(j,z){return 100*l(j/z)}function ln(j,z){var B=z.Q,Z=z.J,D=z.M,tt=z.C,at=z.s,mt=z.h,gt=z.H,J={};return j.J&&(J.J=isNaN(Z)?v0(B):Z),j.C&&(isNaN(tt)?isNaN(D)?(B=isNaN(B)?un(Z):B,J.C=y0(at,B)):J.C=w0(D):J.C=z.C),j.h&&(J.h=isNaN(mt)?i.toHue(gt):mt),j.Q&&(J.Q=isNaN(B)?un(Z):B),j.M&&(J.M=isNaN(D)?ni(tt):D),j.s&&(isNaN(at)?(B=isNaN(B)?un(Z):B,D=isNaN(D)?ni(tt):D,J.s=x0(D,B)):J.s=at),j.H&&(J.H=isNaN(gt)?i.fromHue(mt):gt),J}function C0(j){var z=ti(j),B=ei(z),Z=r(B,3),D=Z[0],tt=Z[1],at=Z[2],mt=D-tt*12/11+at/11,gt=(D+tt-2*at)/9,J=L(gt,mt),Ft=n.degree.fromRadian(J),ye=1/4*(y(J+2)+3.8),we=ri(B),Ht=100*f(we/ve,lt*Js),kt=5e4/13*Mt*Zs*ye*l(mt*mt+gt*gt)/(D+tt+21/20*at),Rt=f(kt,.9)*l(Ht/100)*f(1.64-f(.29,_e),.73);return ln(G,{J:Ht,C:Rt,h:Ft})}function k0(j){var z=ln(T,j),B=z.J,Z=z.C,D=z.h,tt=n.degree.toRadian(D),at=f(Z/(l(B/100)*f(1.64-f(.29,_e),.73)),10/9),mt=1/4*(y(tt+2)+3.8),gt=ve*f(B/100,1/lt/Js),J=5e4/13*Mt*Zs*mt/at,Ft=gt/an+.305,ye=Ft*61/20*460/1403,we=61/20*220/1403,Ht=21/20*6300/1403-27/1403,kt=m(tt),Rt=y(tt),At,St;at===0||isNaN(at)?At=St=0:d(kt)>=d(Rt)?(St=ye/(J/kt+we*Rt/kt+Ht),At=St*Rt/kt):(At=ye/(J/Rt+we+Ht*kt/Rt),St=At*kt/Rt);var R0=[20/61*Ft+451/1403*At+288/1403*St,20/61*Ft-891/1403*At-261/1403*St,20/61*Ft-220/1403*At-6300/1403*St],q0=_0(R0),M0=g0(q0);return M0}return{fromXyz:C0,toXyz:k0,fillOut:ln}}t.default=A,e.exports=t.default})(de,de.exports)),de.exports}var be={exports:{}},$s;function Pc(){return $s||($s=1,(function(e,t){Object.defineProperty(t,"__esModule",{value:!0});var r=ue(),n=Math,o=n.sqrt,i=n.pow,s=n.exp,a=n.log,c=n.cos,u=n.sin,f=n.atan2,l={LCD:{K_L:.77,c_1:.007,c_2:.0053},SCD:{K_L:1.24,c_1:.007,c_2:.0363},UCS:{K_L:1,c_1:.007,c_2:.0228}};function h(){var d=arguments.length<=0||arguments[0]===void 0?"UCS":arguments[0],b=l[d],g=b.K_L,m=b.c_1,y=b.c_2;function L(S){var R=S.J,M=S.M,p=S.h,C=r.degree.toRadian(p),O=(1+100*m)*R/(1+m*R),q=1/y*a(1+y*M),T=q*c(C),A=q*u(C);return{J_p:O,a_p:T,b_p:A}}function w(S){var R=S.J_p,M=S.a_p,p=S.b_p,C=-R/(m*R-100*m-1),O=o(i(M,2)+i(p,2)),q=(s(y*O)-1)/y,T=f(p,M),A=r.degree.fromRadian(T);return{J:C,M:q,h:A}}function x(S,R){return o(i((S.J_p-R.J_p)/g,2)+i(S.a_p-R.a_p,2)+i(S.b_p-R.b_p,2))}return{fromCam:L,toCam:w,distance:x}}t.default=h,e.exports=t.default})(be,be.exports)),be.exports}var tn,Es;function zc(){if(Es)return tn;Es=1;var e=fe(),t=Tc(),r=jc(),n=Pc(),o=As();return tn={gamut:t,cfs:e.cfs,lerp:e.lerp,cam:r,ucs:n,hq:o},tn}var Bc=zc();const Ls=to(Bc);function Ns(e){const t=new v;return t.rgb_r=e[0],t.rgb_g=e[1],t.rgb_b=e[2],t.rgbToHsluv(),[t.hsluv_h,t.hsluv_s,t.hsluv_l]}function Ic(e){const t=new v;return t.hsluv_h=e[0],t.hsluv_s=e[1],t.hsluv_l=e[2],t.hsluvToRgb(),[t.rgb_r,t.rgb_g,t.rgb_b]}const Ts=Ls.cam({whitePoint:le.illuminant.D65,adaptingLuminance:40,backgroundLuminance:20,surroundType:"average",discounting:!1},Ls.cfs("JCh")),js=le.xyz(le.workspace.sRGB,le.illuminant.D65),Ps=e=>js.toRgb(Ts.toXyz({J:e[0],C:e[1],h:e[2]})),en=e=>{const t=Ts.fromXyz(js.fromRgb(e));return[t.J,t.C,t.h]},[Gc,Fc]=(()=>{const e={k_l:1,c1:.007,c2:.0228},t=Math.PI,r=64/t/5,n=1/(5*r+1),o=.2*n**4*(5*r)+.1*(1-n**4)**2*(5*r)**(1/3);return[i=>{const[s,a,c]=i,u=a*o**.25;let f=(1+100*e.c1)*s/(1+e.c1*s);f/=e.k_l;const l=1/e.c2*Math.log(1+e.c2*u),h=l*Math.cos(c*(t/180)),d=l*Math.sin(c*(t/180));return[f,h,d]},i=>{const[s,a,c]=i,u=Math.sqrt(a*a+c*c),f=(Math.exp(u*e.c2)-1)/e.c2,l=(180/t*Math.atan2(c,a)+360)%360,h=f/o**.25;return[s/(1+e.c1*(100-s)),h,l]}]})(),Kc=e=>Ps(Fc(e)),zs=e=>Gc(en(e)),pe=console;pe.color=(e,t="")=>{const n=k(e).luminance();pe.log(`%c${e} ${t}`,`background-color: ${e};padding: 5px; border-radius: 5px; color: ${n>.5?"#000":"#fff"}`)},pe.ramp=(e,t=1)=>{pe.log("%c ",`font-size: 1px;line-height: 16px;background: ${k.getCSSGradient(e,t)};padding: 0 0 0 200px; border-radius: 2px;`)};const Bs=(e,t,r,n,o,i,s=.1)=>{if(e===r||t===n)return!0;const a=(n-t)/(r-e),c=(i+o/a-t+a*e)/(a+1/a),u=i+o/a-c/a;return(o-c)**2+(i-u)**2{const o=(t[0]+r[0])/2,i=e(o);return Bs(...t,...r,o,i,n)?null:[o,i]},rn=(e,t,r,n=.1)=>{const o=(r-t)/10,i=[];for(let s=t;sMath.round(e*10**t)/10**t,Dc=(e,t=1,r=90,n=.005)=>{const o=rn(c=>e(c).gl()[0],0,t,n),i=rn(c=>e(c).gl()[1],0,t,n),s=rn(c=>e(c).gl()[2],0,t,n),a=Array.from(new Set([...o.map(c=>me(c[0])),...i.map(c=>me(c[0])),...s.map(c=>me(c[0]))].sort((c,u)=>c-u)));return`linear-gradient(${r}deg, ${a.map(c=>`${e(c).hex()} ${me(c*100)}%`).join()});`},Vc=e=>{e.Color.prototype.jch=function(){return en(this._rgb.slice(0,3).map(o=>o/255))},e.jch=(...o)=>new e.Color(...Ps(o).map(i=>Math.floor(i*255)),"rgb"),e.Color.prototype.jab=function(){return zs(this._rgb.slice(0,3).map(o=>o/255))},e.jab=(...o)=>new e.Color(...Kc(o).map(i=>Math.floor(i*255)),"rgb"),e.Color.prototype.hsluv=function(){return Ns(this._rgb.slice(0,3).map(o=>o/255))},e.hsluv=(...o)=>new e.Color(...Ic(o).map(i=>Math.floor(i*255)),"rgb");const t=e.interpolate,r={jch:en,jab:zs,hsluv:Ns},n=(o,i,s)=>(Math.abs(o-i)>360/2&&(o>i?i+=360:o+=360),((1-s)*o+s*i)%360);e.interpolate=(o,i,s=.5,a="lrgb")=>{if(r[a]){typeof o!="object"&&(o=new e.Color(o)),typeof i!="object"&&(i=new e.Color(i));const c=r[a](o.gl()),u=r[a](i.gl()),f=Number.isNaN(o.hsl()[0]),l=Number.isNaN(i.hsl()[0]);let h,d,b;switch(a){case"hsluv":c[1]<1e-10&&(c[0]=u[0]),c[1]===0&&(c[1]=u[1]),u[1]<1e-10&&(u[0]=c[0]),u[1]===0&&(u[1]=c[1]),h=n(c[0],u[0],s),d=c[1]+(u[1]-c[1])*s,b=c[2]+(u[2]-c[2])*s;break;case"jch":f&&(c[2]=u[2]),l&&(u[2]=c[2]),h=c[0]+(u[0]-c[0])*s,d=c[1]+(u[1]-c[1])*s,b=n(c[2],u[2],s);break;default:h=c[0]+(u[0]-c[0])*s,d=c[1]+(u[1]-c[1])*s,b=c[2]+(u[2]-c[2])*s}return e[a](h,d,b).alpha(o.alpha()+s*(i.alpha()-o.alpha()))}return t(o,i,s,a)},e.getCSSGradient=Dc};const X={mainTRC:2.4,sRco:.2126729,sGco:.7151522,sBco:.072175,normBG:.56,normTXT:.57,revTXT:.62,revBG:.65,blkThrs:.022,blkClmp:1.414,scaleBoW:1.14,scaleWoB:1.14,loBoWoffset:.027,loWoBoffset:.027,deltaYmin:5e-4,loClip:.1};function Is(e,t,r=-1){const n=[0,1.1];if(isNaN(e)||isNaN(t)||Math.min(e,t)n[1])return 0;let o=0,i=0,s="BoW";return e=e>X.blkThrs?e:e+Math.pow(X.blkThrs-e,X.blkClmp),t=t>X.blkThrs?t:t+Math.pow(X.blkThrs-t,X.blkClmp),Math.abs(t-e)e?(o=(Math.pow(t,X.normBG)-Math.pow(e,X.normTXT))*X.scaleBoW,i=o-.1?0:o+X.loWoBoffset),r<0?i*100:r==0?Math.round(Math.abs(i)*100)+""+s+"":Number.isInteger(r)?(i*100).toFixed(r):0)}function ge(e=[0,0,0]){function t(r){return Math.pow(r/255,X.mainTRC)}return X.sRco*t(e[0])+X.sGco*t(e[1])+X.sBco*t(e[2])}const Gs=(e,t,r,n,o,i,s,a,c)=>{const u=1-c,f=u*u,l=f*u,d=c*c*c,b=l*e+f*3*c*r+u*3*c*c*o+d*s,g=l*t+f*3*c*n+u*3*c*c*i+d*a;return{x:b,y:g}},Yc=(e,t)=>{const r=[];let n={x:+e[0],y:+e[1]};for(let o=0,i=e.length;i-2*!0>o;o+=2){const s=[{x:+e[o-2],y:+e[o-1]},{x:+e[o],y:+e[o+1]},{x:+e[o+2],y:+e[o+3]},{x:+e[o+4],y:+e[o+5]}];i-4===o?s[3]=s[2]:o||(s[0]={x:+e[o],y:+e[o+1]}),r.push([n.x,n.y,(-s[0].x+6*s[1].x+s[2].x)/6,(-s[0].y+6*s[1].y+s[2].y)/6,(s[1].x+6*s[2].x-s[3].x)/6,(s[1].y+6*s[2].y-s[3].y)/6,s[2].x,s[2].y]),n=s[2]}return r},Zc=(e,t,r,n,o,i,s,a)=>{let u=e,f=t,l=0;for(let h=1;h<5;h++){const{x:d,y:b}=Gs(e,t,r,n,o,i,s,a,h/5);l+=Math.hypot(d-u,b-f),u=d,f=b}return l+=Math.hypot(s-u,a-f),l},Jc=(e,t,r,n,o,i,s,a)=>{const c=Math.floor(Zc(e,t,r,n,o,i,s,a)*.75),u=[];let f=0;for(let l=0;l<=c;l++){const h=l/c,d=Gs(e,t,r,n,o,i,s,a,h),b=Math.round(d.x);if(u[b]=d.y,b-f>1){const g=u[f],m=u[b];for(let y=f+1;yu[Math.round(l)]||null},Gt={CAM02:"jab",CAM02p:"jch",HEX:"hex",HSL:"hsl",HSLuv:"hsluv",HSV:"hsv",LAB:"lab",LCH:"lch",RGB:"rgb",OKLAB:"oklab",OKLCH:"oklch"};function wt(e,t=0){const r=10**t;return Math.round(e*r)/r}function Hc(e,t){let r;return e>1?r=(e-1)*t+1:e<-1?r=(e+1)*t-1:r=1,wt(r,2)}function Wc(e){return k(String(e)).jch()}function Uc(e){return k(String(e)).hsluv()}function Qc(e,t,r){const n=[[],[],[]];if(e.forEach((i,s)=>n.forEach((a,c)=>a.push(t[s],i[c]))),r==="hcl"){const i=n[1];for(let s=1;s{const s=[];for(let a=1;a{i[c]=i[a]}),s.length=0;break}if(s.length){const a=k("#ccc").jch()[2];s.forEach(c=>{i[c]=a})}s.length=0;for(let a=i.length-1;a>0;a-=2)if(Number.isNaN(i[a]))s.push(a);else{s.forEach(c=>{i[c]=i[a]});break}for(let a=1;aYc(i).map(s=>Jc(...s)));return i=>{const s=o.map(a=>{for(let c=0;cn*i**e+o}function nn({swatches:e,colorKeys:t,colorspace:r,colorSpace:n=r??"LAB",shift:o=1,fullScale:i=!0,smooth:s=!1,distributeLightness:a="linear",sortColor:c=!0,asFun:u=!1}={}){r!==void 0&&console.warn("Leonardo: `colorspace` is deprecated. Use `colorSpace` instead.");const f=Gt[n];if(!f)throw new Error(`Colorspace “${n}” not supported`);if(!t)throw new Error(`Colorkeys missing: returned “${t}”`);let l;if(i)l=t.map(w=>e-e*(k(w).jch()[0]/100)).sort((w,x)=>w-x).concat(e),l.unshift(0);else{let w=t.map(R=>k(R).jch()[0]/100),x=Math.min(...w),S=Math.max(...w);l=w.map(R=>R===0||isNaN((R-x)/(S-x))?0:e-(R-x)/(S-x)*e).sort((R,M)=>R-M)}let h=t0(o,[1,e],[1,e]);if(h=l.map(w=>Math.max(0,h(w))),l=h,a==="polynomial"){const w=R=>Math.sqrt(Math.sqrt((Math.pow(R,2.25)+Math.pow(R,4))/2));l=h.map(R=>R/e).map(R=>w(R)*e)}const d=t.map((w,x)=>({colorKeys:Wc(w),index:x})).sort((w,x)=>x.colorKeys[0]-w.colorKeys[0]).map(w=>t[w.index]);let b=[],g;if(i){const w=f==="lch"?k.lch(...k("#fff").lch()):"#ffffff",x=f==="lch"?k.lch(...k("#000").lch()):"#000000";b=[w,...d,x]}else c?b=d:b=t;let m;if(s){const w=b;if(b=b.map(x=>k(String(x))[f]()),f==="hcl"&&b.forEach(x=>{x[1]=Number.isNaN(x[1])?0:x[1]}),f==="jch")for(let x=0;xg(S))}else g=k.scale(b.map(w=>typeof w=="object"&&w.constructor===k.Color?w:String(w))).domain(l).mode(f);return u?g:(!s||s===!1?g.colors(e):m).filter(w=>w!=null)}function e0(e,t){const r=[],n={};return Object.keys(e).forEach(s=>{n[e[s][t]]=e[s]}),Object.keys(n).forEach(s=>r.push(n[s])),r}function r0(e){return Number.isNaN(e)?0:e}function on(e,t,r=!1){if(!e)throw new Error(`Cannot convert color value of “${e}”`);if(!Gt[t])throw new Error(`Cannot convert to colorspace “${t}”`);const n=Gt[t],o=k(String(e))[n]();if(t==="HSL"&&o.pop(),t==="HEX"){if(r){const u=k(String(e)).rgb();return{r:u[0],g:u[1],b:u[2]}}return o}const i={};let s=o.map(r0);s=s.map((u,f)=>{let l=wt(u),h=f;n==="hsluv"&&(h+=2);let d=n.charAt(h);return n==="jch"&&d==="c"&&(d="C"),i[d==="j"?"J":d]=l,n in{lab:1,lch:1,jab:1,jch:1}?r||(d==="l"||d==="j")&&(l+="%"):n!=="hsluv"&&(d==="s"||d==="l"||d==="v")&&(i[d]=wt(u,2),r||(l=wt(u*100),l+="%")),l});const c=`${n}(${s.join(", ")})`;return r?i:c}function Fs(e,t,r){const n=[e,t,r].map(o=>(o/=255,o<=.03928?o/12.92:((o+.055)/1.055)**2.4));return n[0]*.2126+n[1]*.7152+n[2]*.0722}function n0(e,t,r,n="wcag2"){if(r===void 0){const o=k.rgb(...t).hsluv()[2];r=wt(o/100,2)}if(n==="wcag2"){const o=Fs(e[0],e[1],e[2]),i=Fs(t[0],t[1],t[2]),s=(o+.05)/(i+.05),a=(i+.05)/(o+.05);return r<.5?s>=1?s:-a:s<1?a:s===1?s:-s}else{if(n==="wcag3")return r<.5?Is(ge(e),ge(t))*-1:Is(ge(e),ge(t));throw new Error(`Contrast calculation method ${n} unsupported; use 'wcag2' or 'wcag3'`)}}function o0(e,t){if(!e)throw new Error("Array undefined");if(!Array.isArray(e))throw new Error("Passed object is not an array");const r=t==="wcag2"?0:1;return Math.min(...e.filter(n=>n>=r))}function s0(e,t){if(!e)throw new Error("Ratios undefined");e=e.sort((a,c)=>a-c);const r=o0(e,t),n=e.indexOf(r),o=[],i=e.slice(0,n),s=e.slice(n,e.length);for(let a=0;aa-c),o}const i0=(e,t,r,n,o)=>{const s=nn({swatches:3e3,colorKeys:e._modifiedKeys,colorspace:e._colorspace,shift:1,smooth:e._smooth,asFun:!0}),a={},c=l=>{if(a[l])return a[l];const h=k(s(l)).rgb(),d=n0(h,t,r,o);return a[l]=d,d},u=l=>{const h=c(0),d=c(3e3),b=hg&&w;)w--,m/=2,Lf.push(s(u(+l)))),f};class Q{constructor({name:t,colorKeys:r,colorspace:n,colorSpace:o=n??"RGB",ratios:i,smooth:s=!1,output:a="HEX",saturation:c=100}){if(n!==void 0&&console.warn("Leonardo: `colorspace` is deprecated. Use `colorSpace` instead."),this._name=t,this._colorKeys=r,this._modifiedKeys=r,this._colorspace=o,this._ratios=i,this._smooth=s,this._output=a,this._saturation=c,!this._name)throw new Error("Color missing name");if(!this._colorKeys)throw new Error("Color Keys are undefined");if(!Gt[this._colorspace])throw new Error(`Colorspace “${o}” not supported`);if(!Gt[this._output])throw new Error(`Output “${this._output}” not supported`);for(let u=0;u{let n=k(`${r}`).oklch(),i=n[1]*(this._saturation/100),s=k.oklch(n[0],i,n[2]),a=k.rgb(s).hex();t.push(a)}),this._modifiedKeys=t,this._generateColorScale()}_generateColorScale(){this._colorScale=nn({swatches:3e3,colorKeys:this._modifiedKeys,colorSpace:this._colorspace,shift:1,smooth:this._smooth,asFun:!0})}}class Ks extends Q{get backgroundColorScale(){return this._backgroundColorScale||this._generateColorScale(),this._backgroundColorScale}_generateColorScale(){Q.prototype._generateColorScale.call(this);const t=nn({swatches:1e3,colorKeys:this._colorKeys,colorspace:this._colorspace,shift:1,smooth:this._smooth});t.push(...this.colorKeys);const r=t.map((i,s)=>({value:Math.round(Uc(i)[2]),index:s})),o=e0(r,"value").map(i=>t[i.index]);return o.length>=101&&(o.length=100,o.push("#ffffff")),this._backgroundColorScale=o.map(i=>on(i,this._output)),this._backgroundColorScale}}class a0{constructor({colors:t,backgroundColor:r,lightness:n,contrast:o=1,saturation:i=100,output:s="HEX",formula:a="wcag2"}){if(this._output=s,this._colors=t,this._lightness=n,this._saturation=i,this._formula=a,this._setBackgroundColor(r),this._setBackgroundColorValue(),this._contrast=o,!this._colors)throw new Error("No colors are defined");if(!this._backgroundColor)throw new Error("Background color is undefined");if(t.forEach(c=>{if(!c.ratios)throw new Error(`Color ${c.name}'s ratios are undefined`)}),!Gt[this._output])throw new Error(`Output “${s}” not supported`);this._saturation<100&&this._updateColorSaturation(this._saturation),this._findContrastColors(),this._findContrastColorPairs(),this._findContrastColorValues()}set formula(t){this._formula=t,this._findContrastColors()}get formula(){return this._formula}set contrast(t){this._contrast=t,this._findContrastColors()}get contrast(){return this._contrast}set lightness(t){this._lightness=t,this._setBackgroundColor(this._backgroundColor),this._findContrastColors()}get lightness(){return this._lightness}set saturation(t){this._saturation=t,this._updateColorSaturation(t),this._findContrastColors()}get saturation(){return this._saturation}set backgroundColor(t){this._setBackgroundColor(t),this._findContrastColors()}get backgroundColorValue(){return this._backgroundColorValue}get backgroundColor(){return this._backgroundColor}set colors(t){this._colors=t,this._findContrastColors()}get colors(){return this._colors}set addColor(t){this._colors.push(t),this._findContrastColors()}set removeColor(t){const r=this._colors.filter(n=>n.name!==t.name);this._colors=r,this._findContrastColors()}set updateColor(t){if(Array.isArray(t))for(let r=0;rs.name===t[r].color);n=n[0];let o=this._colors.indexOf(n);const i=this._colors.filter(s=>s.name!==t[r].color);t[r].name&&(n.name=t[r].name),t[r].colorKeys&&(n.colorKeys=t[r].colorKeys),t[r].ratios&&(n.ratios=t[r].ratios),(t[r].colorSpace!==void 0||t[r].colorspace!==void 0)&&(t[r].colorspace!==void 0&&t[r].colorSpace===void 0&&console.warn("Leonardo: `colorspace` is deprecated. Use `colorSpace` instead."),n.colorSpace=t[r].colorSpace??t[r].colorspace),t[r].smooth&&(n.smooth=t[r].smooth),n._generateColorScale(),i.splice(o,0,n),this._colors=i}else{let r=this._colors.filter(i=>i.name===t.color);r=r[0];let n=this._colors.indexOf(r);const o=this._colors.filter(i=>i.name!==t.color);t.name&&(r.name=t.name),t.colorKeys&&(r.colorKeys=t.colorKeys),t.ratios&&(r.ratios=t.ratios),(t.colorSpace!==void 0||t.colorspace!==void 0)&&(t.colorspace!==void 0&&t.colorSpace===void 0&&console.warn("Leonardo: `colorspace` is deprecated. Use `colorSpace` instead."),r.colorSpace=t.colorSpace??t.colorspace),t.smooth&&(r.smooth=t.smooth),r._generateColorScale(),o.splice(n,0,r),this._colors=o}this._findContrastColors()}set output(t){this._output=t,this._colors.forEach(r=>{r.output=this._output}),this._backgroundColor.output=this._output,this._findContrastColors()}get output(){return this._output}get contrastColors(){return this._contrastColors}get contrastColorPairs(){return this._contrastColorPairs}get contrastColorValues(){return this._contrastColorValues}_setBackgroundColor(t){if(typeof t=="string"){const r=new Ks({name:"background",colorKeys:[t],output:"RGB"}),n=wt(k(String(t)).hsluv()[2]);this._backgroundColor=r,this._lightness=n,this._backgroundColorValue=r[this._lightness]}else{t.output="RGB";const r=t.backgroundColorScale[this._lightness];this._backgroundColor=t,this._backgroundColorValue=r}}_setBackgroundColorValue(){this._backgroundColorValue=this._backgroundColor.backgroundColorScale[this._lightness]}_updateColorSaturation(t){this._colors.map(r=>{r.saturation=t})}_findContrastColors(){const t=k(String(this._backgroundColorValue)).rgb(),r=this._lightness/100,o={background:on(this._backgroundColorValue,this._output)},i=[],s=[],a={...o};return i.push(o),this._colors.map(c=>{if(c.ratios!==void 0){let u;const f=[],l={name:c.name,values:f};let h;Array.isArray(c.ratios)?h=c.ratios:Array.isArray(c.ratios)||(u=Object.keys(c.ratios),h=Object.values(c.ratios)),h=h.map(b=>Hc(+b,this._contrast));const d=i0(c,t,r,h,this._formula).map(b=>on(b,this._output));for(let b=0;b{const t=/^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(e);return[Number.parseInt(t[1],16),Number.parseInt(t[2],16),Number.parseInt(t[3],16)]},Ds=(e,t,r)=>{const n=e/255,o=t/255,i=r/255,s=Math.min(n,o,i),a=Math.max(n,o,i),c=a-s;let u=0,f=0,l=0;return c===0?u=0:a===n?u=(o-i)/c%6:a===o?u=(i-n)/c+2:u=(n-o)/c+4,u=Math.round(u*60),u<0&&(u+=360),l=(a+s)/2,f=c===0?0:c/(1-Math.abs(2*l-1)),f=+(f*100).toFixed(1),l=+(l*100).toFixed(1),[u,f,Math.round(l)]},u0=(e,t,r,n)=>{const o=r/100,i=t*Math.min(o,1-o)/100,s=d=>{const b=(d+e/30)%12,g=o-i*Math.max(Math.min(b-3,9-b,1),-1);return Math.round(255*g).toString(16).padStart(2,"0").toUpperCase()},a=s(0),c=s(8),u=s(4),l=((d,b,g)=>Math.min(Math.max(d,b),g))(n,0,1),h=Math.round(l*255).toString(16).padStart(2,"0").toUpperCase();return`#${a}${c}${u}${h}`},l0=(e,t,r=1)=>{const n=Xs(e),o=Xs(t==="white"?"#FFFFFF":t==="black"?"#000000":t),i=n.map((u,f)=>[(u-o[f])/(255-o[f]),(u-o[f])/(0-o[f])]),s=c0(Math.max(...i.flat().filter(u=>/^-?\d+\.?\d*$/.test(u)))),a=n.map((u,f)=>Math.round((u-o[f]+o[f]*s)/s));if(a.includes(Number.NaN)){const u=Ds(n[0],n[1],n[2]);return{h:u[0],s:Math.round(u[1]*r),l:u[2],a:1}}const c=Ds(a[0],a[1],a[2]);return{h:c[0],s:Math.round(c[1]*r),l:c[2],a:s}},sn={backgroundColor:"gray",colorSpace:"OKLCH",colorSmoothing:!1,formula:"wcag2",output:"HEX",colors:{gray:[I(215,20,90),I(215,8,50),I(215,6,25)],red:[I(358,100,58),I(350,100,30)],orange:[I(32,100,48),I(12,100,30)],yellow:[I(50,100,50),I(25,100,20)],lime:[I(100,68,50),I(115,86,25)],green:[I(163,87,42),I(168,100,25)],cyan:[I(185,80,45),I(200,98,35)],blue:[I(212,98,46),I(222,95,25)],purple:[I(258,94,64),I(265,100,35)],fuchsia:[I(295,56,50),I(285,80,25)],pink:[I(334,90,50),I(330,91,25)]},themes:{light:{ratios:[1.03,1.06,1.12,1.25,1.5,1.75,2.25,3.5,5.25,6.5,8,10.5,13.75,16.75],contrast:1,lightness:100,saturation:100},dark:{ratios:[1.03,1.06,1.12,1.25,1.5,1.75,2.25,3.5,5.25,6.5,8,10.5,13.75,16],contrast:1,lightness:6,saturation:97},lightHc:{ratios:[1.06,1.12,1.25,1.37,1.75,2.25,3.25,4.75,8.87,10,11.75,13.25,16,17],contrast:1,lightness:100,saturation:100},darkHc:{ratios:[1.06,1.12,1.25,1.37,1.75,2.25,3.25,4.75,8.87,10,11.75,13.25,16,17],contrast:1,lightness:6,saturation:97}}};function I(e,t,r){return k.hsl(e,t/100,r/100).hex()}function f0(e,t){const r=e.colorSpace,n=e.colorSmoothing,o=e.themes[t].ratios,i=new Ks({name:"gray",colorKeys:e.colors.gray,colorspace:r,ratios:o,smooth:n}),s=new Q({name:"blue",colorKeys:e.colors.blue,colorspace:r,ratios:o,smooth:n}),a=new Q({name:"cyan",colorKeys:e.colors.cyan,colorspace:r,ratios:o,smooth:n}),c=new Q({name:"fuchsia",colorKeys:e.colors.fuchsia,colorspace:r,ratios:o,smooth:n}),u=new Q({name:"green",colorKeys:e.colors.green,colorspace:r,ratios:o,smooth:n}),f=new Q({name:"lime",colorKeys:e.colors.lime,colorspace:r,ratios:o,smooth:n}),l=new Q({name:"orange",colorKeys:e.colors.orange,colorspace:r,ratios:o,smooth:n}),h=new Q({name:"pink",colorKeys:e.colors.pink,colorspace:r,ratios:o,smooth:n}),d=new Q({name:"purple",colorKeys:e.colors.purple,colorspace:r,ratios:o,smooth:n}),b=new Q({name:"red",colorKeys:e.colors.red,colorspace:r,ratios:o,smooth:n}),g=new Q({name:"yellow",colorKeys:e.colors.yellow,colorspace:r,ratios:o,smooth:n}),m={gray:i,red:b,orange:l,yellow:g,lime:f,green:u,cyan:a,blue:s,purple:d,fuchsia:c,pink:h};return e.colors.custom&&(m.custom=new Q({name:"custom",colorKeys:e.colors.custom,colorspace:r,ratios:o,smooth:n})),new a0({colors:Object.values(m),backgroundColor:m[e.backgroundColor],contrast:e.themes[t].contrast,lightness:e.themes[t].lightness,saturation:e.themes[t].saturation,output:e.output,formula:e.formula}).contrastColors}function Vs(e){const t={};for(const r of Object.keys(e.themes))t[r]=f0(e,r);return t}function h0(e){sn.colors.custom=[e];const t=Vs(sn);return Object.fromEntries(Object.entries(t).map(([r,n])=>{const o=n.find(s=>s&&s.name==="custom"),i=Object.fromEntries(o.values.map(({name:s,value:a})=>[s,a]));for(const[s,a]of Object.entries(i)){const c=l0(a,n[0].background);i[`alpha${s.charAt(0).toUpperCase()+s.slice(1)}`]=u0(c.h,c.s,c.l,c.a)}return[r,i]}))}return $t.generateCustomColors=h0,$t.generateThemesJson=Vs,$t.hslToHex=I,$t.leonardoConfig=sn,Object.defineProperty($t,Symbol.toStringTag,{value:"Module"}),$t})({}); diff --git a/libraries/compound/src/main/kotlin/io/element/android/compound/tokens/generated/CompoundIcons.kt b/libraries/compound/src/main/kotlin/io/element/android/compound/tokens/generated/CompoundIcons.kt index 6c30eda7f9..456ffcf625 100644 --- a/libraries/compound/src/main/kotlin/io/element/android/compound/tokens/generated/CompoundIcons.kt +++ b/libraries/compound/src/main/kotlin/io/element/android/compound/tokens/generated/CompoundIcons.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025 Element Creations Ltd. + * Copyright (c) 2026 Element Creations Ltd. * * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial. * Please see LICENSE files in the repository root for full details. @@ -25,6 +25,9 @@ object CompoundIcons { @Composable fun Admin(): ImageVector { return ImageVector.vectorResource(R.drawable.ic_compound_admin) } + @Composable fun AdvancedSettings(): ImageVector { + return ImageVector.vectorResource(R.drawable.ic_compound_advanced_settings) + } @Composable fun ArrowDown(): ImageVector { return ImageVector.vectorResource(R.drawable.ic_compound_arrow_down) } @@ -64,6 +67,9 @@ object CompoundIcons { @Composable fun Bold(): ImageVector { return ImageVector.vectorResource(R.drawable.ic_compound_bold) } + @Composable fun Bug(): ImageVector { + return ImageVector.vectorResource(R.drawable.ic_compound_bug) + } @Composable fun Calendar(): ImageVector { return ImageVector.vectorResource(R.drawable.ic_compound_calendar) } @@ -460,6 +466,9 @@ object CompoundIcons { @Composable fun RaisedHandSolid(): ImageVector { return ImageVector.vectorResource(R.drawable.ic_compound_raised_hand_solid) } + @Composable fun ReOrder(): ImageVector { + return ImageVector.vectorResource(R.drawable.ic_compound_re_order) + } @Composable fun Reaction(): ImageVector { return ImageVector.vectorResource(R.drawable.ic_compound_reaction) } @@ -478,9 +487,18 @@ object CompoundIcons { @Composable fun Room(): ImageVector { return ImageVector.vectorResource(R.drawable.ic_compound_room) } + @Composable fun RotateLeft(): ImageVector { + return ImageVector.vectorResource(R.drawable.ic_compound_rotate_left) + } + @Composable fun RotateRight(): ImageVector { + return ImageVector.vectorResource(R.drawable.ic_compound_rotate_right) + } @Composable fun Search(): ImageVector { return ImageVector.vectorResource(R.drawable.ic_compound_search) } + @Composable fun Section(): ImageVector { + return ImageVector.vectorResource(R.drawable.ic_compound_section) + } @Composable fun Send(): ImageVector { return ImageVector.vectorResource(R.drawable.ic_compound_send) } @@ -535,6 +553,12 @@ object CompoundIcons { @Composable fun Sticker(): ImageVector { return ImageVector.vectorResource(R.drawable.ic_compound_sticker) } + @Composable fun Stop(): ImageVector { + return ImageVector.vectorResource(R.drawable.ic_compound_stop) + } + @Composable fun StopSolid(): ImageVector { + return ImageVector.vectorResource(R.drawable.ic_compound_stop_solid) + } @Composable fun Strikethrough(): ImageVector { return ImageVector.vectorResource(R.drawable.ic_compound_strikethrough) } @@ -550,6 +574,9 @@ object CompoundIcons { @Composable fun TextFormatting(): ImageVector { return ImageVector.vectorResource(R.drawable.ic_compound_text_formatting) } + @Composable fun Theme(): ImageVector { + return ImageVector.vectorResource(R.drawable.ic_compound_theme) + } @Composable fun Threads(): ImageVector { return ImageVector.vectorResource(R.drawable.ic_compound_threads) } @@ -559,6 +586,12 @@ object CompoundIcons { @Composable fun Time(): ImageVector { return ImageVector.vectorResource(R.drawable.ic_compound_time) } + @Composable fun Translate(): ImageVector { + return ImageVector.vectorResource(R.drawable.ic_compound_translate) + } + @Composable fun Tree(): ImageVector { + return ImageVector.vectorResource(R.drawable.ic_compound_tree) + } @Composable fun Underline(): ImageVector { return ImageVector.vectorResource(R.drawable.ic_compound_underline) } @@ -607,6 +640,9 @@ object CompoundIcons { @Composable fun VideoCallOffSolid(): ImageVector { return ImageVector.vectorResource(R.drawable.ic_compound_video_call_off_solid) } + @Composable fun VideoCallOutgoingSolid(): ImageVector { + return ImageVector.vectorResource(R.drawable.ic_compound_video_call_outgoing_solid) + } @Composable fun VideoCallSolid(): ImageVector { return ImageVector.vectorResource(R.drawable.ic_compound_video_call_solid) } @@ -619,6 +655,15 @@ object CompoundIcons { @Composable fun VoiceCall(): ImageVector { return ImageVector.vectorResource(R.drawable.ic_compound_voice_call) } + @Composable fun VoiceCallDeclinedSolid(): ImageVector { + return ImageVector.vectorResource(R.drawable.ic_compound_voice_call_declined_solid) + } + @Composable fun VoiceCallMissedSolid(): ImageVector { + return ImageVector.vectorResource(R.drawable.ic_compound_voice_call_missed_solid) + } + @Composable fun VoiceCallOutgoingSolid(): ImageVector { + return ImageVector.vectorResource(R.drawable.ic_compound_voice_call_outgoing_solid) + } @Composable fun VoiceCallSolid(): ImageVector { return ImageVector.vectorResource(R.drawable.ic_compound_voice_call_solid) } @@ -643,9 +688,16 @@ object CompoundIcons { @Composable fun Windows(): ImageVector { return ImageVector.vectorResource(R.drawable.ic_compound_windows) } + @Composable fun ZoomIn(): ImageVector { + return ImageVector.vectorResource(R.drawable.ic_compound_zoom_in) + } + @Composable fun ZoomOut(): ImageVector { + return ImageVector.vectorResource(R.drawable.ic_compound_zoom_out) + } val all @Composable get() = persistentListOf( Admin(), + AdvancedSettings(), ArrowDown(), ArrowLeft(), ArrowRight(), @@ -659,6 +711,7 @@ object CompoundIcons { BackspaceSolid(), Block(), Bold(), + Bug(), Calendar(), Chart(), Chat(), @@ -791,13 +844,17 @@ object CompoundIcons { QrCode(), Quote(), RaisedHandSolid(), + ReOrder(), Reaction(), ReactionAdd(), ReactionSolid(), Reply(), Restart(), Room(), + RotateLeft(), + RotateRight(), Search(), + Section(), Send(), SendSolid(), Settings(), @@ -816,14 +873,19 @@ object CompoundIcons { Spotlight(), SpotlightView(), Sticker(), + Stop(), + StopSolid(), Strikethrough(), SwitchCameraSolid(), TakePhoto(), TakePhotoSolid(), TextFormatting(), + Theme(), Threads(), ThreadsSolid(), Time(), + Translate(), + Tree(), Underline(), Unknown(), UnknownSolid(), @@ -840,10 +902,14 @@ object CompoundIcons { VideoCallMissedSolid(), VideoCallOff(), VideoCallOffSolid(), + VideoCallOutgoingSolid(), VideoCallSolid(), VisibilityOff(), VisibilityOn(), VoiceCall(), + VoiceCallDeclinedSolid(), + VoiceCallMissedSolid(), + VoiceCallOutgoingSolid(), VoiceCallSolid(), VolumeOff(), VolumeOffSolid(), @@ -852,10 +918,13 @@ object CompoundIcons { Warning(), WebBrowser(), Windows(), + ZoomIn(), + ZoomOut(), ) val allResIds get() = persistentListOf( R.drawable.ic_compound_admin, + R.drawable.ic_compound_advanced_settings, R.drawable.ic_compound_arrow_down, R.drawable.ic_compound_arrow_left, R.drawable.ic_compound_arrow_right, @@ -869,6 +938,7 @@ object CompoundIcons { R.drawable.ic_compound_backspace_solid, R.drawable.ic_compound_block, R.drawable.ic_compound_bold, + R.drawable.ic_compound_bug, R.drawable.ic_compound_calendar, R.drawable.ic_compound_chart, R.drawable.ic_compound_chat, @@ -1001,13 +1071,17 @@ object CompoundIcons { R.drawable.ic_compound_qr_code, R.drawable.ic_compound_quote, R.drawable.ic_compound_raised_hand_solid, + R.drawable.ic_compound_re_order, R.drawable.ic_compound_reaction, R.drawable.ic_compound_reaction_add, R.drawable.ic_compound_reaction_solid, R.drawable.ic_compound_reply, R.drawable.ic_compound_restart, R.drawable.ic_compound_room, + R.drawable.ic_compound_rotate_left, + R.drawable.ic_compound_rotate_right, R.drawable.ic_compound_search, + R.drawable.ic_compound_section, R.drawable.ic_compound_send, R.drawable.ic_compound_send_solid, R.drawable.ic_compound_settings, @@ -1026,14 +1100,19 @@ object CompoundIcons { R.drawable.ic_compound_spotlight, R.drawable.ic_compound_spotlight_view, R.drawable.ic_compound_sticker, + R.drawable.ic_compound_stop, + R.drawable.ic_compound_stop_solid, R.drawable.ic_compound_strikethrough, R.drawable.ic_compound_switch_camera_solid, R.drawable.ic_compound_take_photo, R.drawable.ic_compound_take_photo_solid, R.drawable.ic_compound_text_formatting, + R.drawable.ic_compound_theme, R.drawable.ic_compound_threads, R.drawable.ic_compound_threads_solid, R.drawable.ic_compound_time, + R.drawable.ic_compound_translate, + R.drawable.ic_compound_tree, R.drawable.ic_compound_underline, R.drawable.ic_compound_unknown, R.drawable.ic_compound_unknown_solid, @@ -1050,10 +1129,14 @@ object CompoundIcons { R.drawable.ic_compound_video_call_missed_solid, R.drawable.ic_compound_video_call_off, R.drawable.ic_compound_video_call_off_solid, + R.drawable.ic_compound_video_call_outgoing_solid, R.drawable.ic_compound_video_call_solid, R.drawable.ic_compound_visibility_off, R.drawable.ic_compound_visibility_on, R.drawable.ic_compound_voice_call, + R.drawable.ic_compound_voice_call_declined_solid, + R.drawable.ic_compound_voice_call_missed_solid, + R.drawable.ic_compound_voice_call_outgoing_solid, R.drawable.ic_compound_voice_call_solid, R.drawable.ic_compound_volume_off, R.drawable.ic_compound_volume_off_solid, @@ -1062,5 +1145,7 @@ object CompoundIcons { R.drawable.ic_compound_warning, R.drawable.ic_compound_web_browser, R.drawable.ic_compound_windows, + R.drawable.ic_compound_zoom_in, + R.drawable.ic_compound_zoom_out, ) } diff --git a/libraries/compound/src/main/kotlin/io/element/android/compound/tokens/generated/SemanticColors.kt b/libraries/compound/src/main/kotlin/io/element/android/compound/tokens/generated/SemanticColors.kt index 6136b04d4b..4c9b20ef9f 100644 --- a/libraries/compound/src/main/kotlin/io/element/android/compound/tokens/generated/SemanticColors.kt +++ b/libraries/compound/src/main/kotlin/io/element/android/compound/tokens/generated/SemanticColors.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025 Element Creations Ltd. + * Copyright (c) 2026 Element Creations Ltd. * * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial. * Please see LICENSE files in the repository root for full details. @@ -121,18 +121,14 @@ data class SemanticColors( val gradientActionStop3: Color, /** Background gradient stop for super and send buttons */ val gradientActionStop4: Color, + /** Subtle background gradient stop for critical */ + val gradientCriticalStop1: Color, + /** Subtle background gradient stop for critical */ + val gradientCriticalStop2: Color, /** Subtle background gradient stop for info */ val gradientInfoStop1: Color, /** Subtle background gradient stop for info */ val gradientInfoStop2: Color, - /** Subtle background gradient stop for info */ - val gradientInfoStop3: Color, - /** Subtle background gradient stop for info */ - val gradientInfoStop4: Color, - /** Subtle background gradient stop for info */ - val gradientInfoStop5: Color, - /** Subtle background gradient stop for info */ - val gradientInfoStop6: Color, /** Subtle background gradient stop for message highlight and bloom */ val gradientSubtleStop1: Color, /** Subtle background gradient stop for message highlight and bloom */ diff --git a/libraries/compound/src/main/kotlin/io/element/android/compound/tokens/generated/SemanticColorsDark.kt b/libraries/compound/src/main/kotlin/io/element/android/compound/tokens/generated/SemanticColorsDark.kt index 60afe79ae2..9ad028f507 100644 --- a/libraries/compound/src/main/kotlin/io/element/android/compound/tokens/generated/SemanticColorsDark.kt +++ b/libraries/compound/src/main/kotlin/io/element/android/compound/tokens/generated/SemanticColorsDark.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025 Element Creations Ltd. + * Copyright (c) 2026 Element Creations Ltd. * * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial. * Please see LICENSE files in the repository root for full details. @@ -73,12 +73,10 @@ val compoundColorsDark = SemanticColors( gradientActionStop2 = DarkColorTokens.colorGreen900, gradientActionStop3 = DarkColorTokens.colorGreen700, gradientActionStop4 = DarkColorTokens.colorGreen500, - gradientInfoStop1 = DarkColorTokens.colorAlphaBlue500, - gradientInfoStop2 = DarkColorTokens.colorAlphaBlue400, - gradientInfoStop3 = DarkColorTokens.colorAlphaBlue300, - gradientInfoStop4 = DarkColorTokens.colorAlphaBlue200, - gradientInfoStop5 = DarkColorTokens.colorAlphaBlue100, - gradientInfoStop6 = DarkColorTokens.colorTransparent, + gradientCriticalStop1 = DarkColorTokens.colorRed200, + gradientCriticalStop2 = DarkColorTokens.colorThemeBg, + gradientInfoStop1 = DarkColorTokens.colorBlue200, + gradientInfoStop2 = DarkColorTokens.colorThemeBg, gradientSubtleStop1 = DarkColorTokens.colorAlphaGreen500, gradientSubtleStop2 = DarkColorTokens.colorAlphaGreen400, gradientSubtleStop3 = DarkColorTokens.colorAlphaGreen300, diff --git a/libraries/compound/src/main/kotlin/io/element/android/compound/tokens/generated/SemanticColorsDarkHc.kt b/libraries/compound/src/main/kotlin/io/element/android/compound/tokens/generated/SemanticColorsDarkHc.kt index c718caeeeb..9af9edd913 100644 --- a/libraries/compound/src/main/kotlin/io/element/android/compound/tokens/generated/SemanticColorsDarkHc.kt +++ b/libraries/compound/src/main/kotlin/io/element/android/compound/tokens/generated/SemanticColorsDarkHc.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025 Element Creations Ltd. + * Copyright (c) 2026 Element Creations Ltd. * * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial. * Please see LICENSE files in the repository root for full details. @@ -73,12 +73,10 @@ val compoundColorsHcDark = SemanticColors( gradientActionStop2 = DarkHcColorTokens.colorGreen900, gradientActionStop3 = DarkHcColorTokens.colorGreen700, gradientActionStop4 = DarkHcColorTokens.colorGreen500, - gradientInfoStop1 = DarkHcColorTokens.colorAlphaBlue500, - gradientInfoStop2 = DarkHcColorTokens.colorAlphaBlue400, - gradientInfoStop3 = DarkHcColorTokens.colorAlphaBlue300, - gradientInfoStop4 = DarkHcColorTokens.colorAlphaBlue200, - gradientInfoStop5 = DarkHcColorTokens.colorAlphaBlue100, - gradientInfoStop6 = DarkHcColorTokens.colorTransparent, + gradientCriticalStop1 = DarkHcColorTokens.colorRed200, + gradientCriticalStop2 = DarkHcColorTokens.colorThemeBg, + gradientInfoStop1 = DarkHcColorTokens.colorBlue200, + gradientInfoStop2 = DarkHcColorTokens.colorThemeBg, gradientSubtleStop1 = DarkHcColorTokens.colorAlphaGreen500, gradientSubtleStop2 = DarkHcColorTokens.colorAlphaGreen400, gradientSubtleStop3 = DarkHcColorTokens.colorAlphaGreen300, diff --git a/libraries/compound/src/main/kotlin/io/element/android/compound/tokens/generated/SemanticColorsLight.kt b/libraries/compound/src/main/kotlin/io/element/android/compound/tokens/generated/SemanticColorsLight.kt index 377997ec79..6569f5a676 100644 --- a/libraries/compound/src/main/kotlin/io/element/android/compound/tokens/generated/SemanticColorsLight.kt +++ b/libraries/compound/src/main/kotlin/io/element/android/compound/tokens/generated/SemanticColorsLight.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025 Element Creations Ltd. + * Copyright (c) 2026 Element Creations Ltd. * * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial. * Please see LICENSE files in the repository root for full details. @@ -73,12 +73,10 @@ val compoundColorsLight = SemanticColors( gradientActionStop2 = LightColorTokens.colorGreen700, gradientActionStop3 = LightColorTokens.colorGreen900, gradientActionStop4 = LightColorTokens.colorGreen1100, - gradientInfoStop1 = LightColorTokens.colorAlphaBlue500, - gradientInfoStop2 = LightColorTokens.colorAlphaBlue400, - gradientInfoStop3 = LightColorTokens.colorAlphaBlue300, - gradientInfoStop4 = LightColorTokens.colorAlphaBlue200, - gradientInfoStop5 = LightColorTokens.colorAlphaBlue100, - gradientInfoStop6 = LightColorTokens.colorTransparent, + gradientCriticalStop1 = LightColorTokens.colorRed200, + gradientCriticalStop2 = LightColorTokens.colorThemeBg, + gradientInfoStop1 = LightColorTokens.colorBlue200, + gradientInfoStop2 = LightColorTokens.colorThemeBg, gradientSubtleStop1 = LightColorTokens.colorAlphaGreen500, gradientSubtleStop2 = LightColorTokens.colorAlphaGreen400, gradientSubtleStop3 = LightColorTokens.colorAlphaGreen300, diff --git a/libraries/compound/src/main/kotlin/io/element/android/compound/tokens/generated/SemanticColorsLightHc.kt b/libraries/compound/src/main/kotlin/io/element/android/compound/tokens/generated/SemanticColorsLightHc.kt index b32a0dd9f0..8a8fa44e61 100644 --- a/libraries/compound/src/main/kotlin/io/element/android/compound/tokens/generated/SemanticColorsLightHc.kt +++ b/libraries/compound/src/main/kotlin/io/element/android/compound/tokens/generated/SemanticColorsLightHc.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025 Element Creations Ltd. + * Copyright (c) 2026 Element Creations Ltd. * * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial. * Please see LICENSE files in the repository root for full details. @@ -73,12 +73,10 @@ val compoundColorsHcLight = SemanticColors( gradientActionStop2 = LightHcColorTokens.colorGreen700, gradientActionStop3 = LightHcColorTokens.colorGreen900, gradientActionStop4 = LightHcColorTokens.colorGreen1100, - gradientInfoStop1 = LightHcColorTokens.colorAlphaBlue500, - gradientInfoStop2 = LightHcColorTokens.colorAlphaBlue400, - gradientInfoStop3 = LightHcColorTokens.colorAlphaBlue300, - gradientInfoStop4 = LightHcColorTokens.colorAlphaBlue200, - gradientInfoStop5 = LightHcColorTokens.colorAlphaBlue100, - gradientInfoStop6 = LightHcColorTokens.colorTransparent, + gradientCriticalStop1 = LightHcColorTokens.colorRed200, + gradientCriticalStop2 = LightHcColorTokens.colorThemeBg, + gradientInfoStop1 = LightHcColorTokens.colorBlue200, + gradientInfoStop2 = LightHcColorTokens.colorThemeBg, gradientSubtleStop1 = LightHcColorTokens.colorAlphaGreen500, gradientSubtleStop2 = LightHcColorTokens.colorAlphaGreen400, gradientSubtleStop3 = LightHcColorTokens.colorAlphaGreen300, diff --git a/libraries/compound/src/main/kotlin/io/element/android/compound/tokens/generated/TypographyTokens.kt b/libraries/compound/src/main/kotlin/io/element/android/compound/tokens/generated/TypographyTokens.kt index 0f450776ef..ad6811b3ec 100644 --- a/libraries/compound/src/main/kotlin/io/element/android/compound/tokens/generated/TypographyTokens.kt +++ b/libraries/compound/src/main/kotlin/io/element/android/compound/tokens/generated/TypographyTokens.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025 Element Creations Ltd. + * Copyright (c) 2026 Element Creations Ltd. * * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial. * Please see LICENSE files in the repository root for full details. diff --git a/libraries/compound/src/main/kotlin/io/element/android/compound/tokens/generated/internal/DarkColorTokens.kt b/libraries/compound/src/main/kotlin/io/element/android/compound/tokens/generated/internal/DarkColorTokens.kt index 04dbf6b9f2..11502de977 100644 --- a/libraries/compound/src/main/kotlin/io/element/android/compound/tokens/generated/internal/DarkColorTokens.kt +++ b/libraries/compound/src/main/kotlin/io/element/android/compound/tokens/generated/internal/DarkColorTokens.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025 Element Creations Ltd. + * Copyright (c) 2026 Element Creations Ltd. * * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial. * Please see LICENSE files in the repository root for full details. diff --git a/libraries/compound/src/main/kotlin/io/element/android/compound/tokens/generated/internal/DarkHcColorTokens.kt b/libraries/compound/src/main/kotlin/io/element/android/compound/tokens/generated/internal/DarkHcColorTokens.kt index 8b2c04a93a..06e5e3450e 100644 --- a/libraries/compound/src/main/kotlin/io/element/android/compound/tokens/generated/internal/DarkHcColorTokens.kt +++ b/libraries/compound/src/main/kotlin/io/element/android/compound/tokens/generated/internal/DarkHcColorTokens.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025 Element Creations Ltd. + * Copyright (c) 2026 Element Creations Ltd. * * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial. * Please see LICENSE files in the repository root for full details. diff --git a/libraries/compound/src/main/kotlin/io/element/android/compound/tokens/generated/internal/LightColorTokens.kt b/libraries/compound/src/main/kotlin/io/element/android/compound/tokens/generated/internal/LightColorTokens.kt index c7561c7ce9..e7ac3ecc66 100644 --- a/libraries/compound/src/main/kotlin/io/element/android/compound/tokens/generated/internal/LightColorTokens.kt +++ b/libraries/compound/src/main/kotlin/io/element/android/compound/tokens/generated/internal/LightColorTokens.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025 Element Creations Ltd. + * Copyright (c) 2026 Element Creations Ltd. * * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial. * Please see LICENSE files in the repository root for full details. diff --git a/libraries/compound/src/main/kotlin/io/element/android/compound/tokens/generated/internal/LightHcColorTokens.kt b/libraries/compound/src/main/kotlin/io/element/android/compound/tokens/generated/internal/LightHcColorTokens.kt index 40c91c5b53..7ab935932b 100644 --- a/libraries/compound/src/main/kotlin/io/element/android/compound/tokens/generated/internal/LightHcColorTokens.kt +++ b/libraries/compound/src/main/kotlin/io/element/android/compound/tokens/generated/internal/LightHcColorTokens.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025 Element Creations Ltd. + * Copyright (c) 2026 Element Creations Ltd. * * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial. * Please see LICENSE files in the repository root for full details. diff --git a/libraries/compound/src/main/res/drawable/ic_compound_advanced_settings.xml b/libraries/compound/src/main/res/drawable/ic_compound_advanced_settings.xml new file mode 100644 index 0000000000..a1c61bf419 --- /dev/null +++ b/libraries/compound/src/main/res/drawable/ic_compound_advanced_settings.xml @@ -0,0 +1,14 @@ + + + + diff --git a/libraries/compound/src/main/res/drawable/ic_compound_backspace.xml b/libraries/compound/src/main/res/drawable/ic_compound_backspace.xml index 90464cb595..044da0d4b3 100644 --- a/libraries/compound/src/main/res/drawable/ic_compound_backspace.xml +++ b/libraries/compound/src/main/res/drawable/ic_compound_backspace.xml @@ -4,11 +4,11 @@ android:autoMirrored="true" android:viewportWidth="24" android:viewportHeight="24"> - - - - + + diff --git a/libraries/compound/src/main/res/drawable/ic_compound_backspace_solid.xml b/libraries/compound/src/main/res/drawable/ic_compound_backspace_solid.xml index 27d5805811..b7f454e330 100644 --- a/libraries/compound/src/main/res/drawable/ic_compound_backspace_solid.xml +++ b/libraries/compound/src/main/res/drawable/ic_compound_backspace_solid.xml @@ -5,6 +5,7 @@ android:viewportWidth="24" android:viewportHeight="24"> + android:pathData="M20,4a2,2 0,0 1,2 2v12a2,2 0,0 1,-2 2L7.33,20a2,2 0,0 1,-1.673 -0.902l-3.937,-6a2,2 0,0 1,0 -2.196l3.937,-6A2,2 0,0 1,7.33 4zM16.457,8.457a1,1 0,0 0,-1.414 0L13,10.5l-2.043,-2.043a1,1 0,0 0,-1.414 1.414l2.043,2.043 -2.129,2.129a1,1 0,0 0,1.414 1.414l2.13,-2.129 2.128,2.129a1,1 0,0 0,1.414 -1.414l-2.129,-2.129 2.043,-2.043a1,1 0,0 0,0 -1.414" + android:fillColor="#FF000000" + android:fillType="evenOdd"/> diff --git a/libraries/compound/src/main/res/drawable/ic_compound_bug.xml b/libraries/compound/src/main/res/drawable/ic_compound_bug.xml new file mode 100644 index 0000000000..7ee32ec13c --- /dev/null +++ b/libraries/compound/src/main/res/drawable/ic_compound_bug.xml @@ -0,0 +1,9 @@ + + + diff --git a/libraries/compound/src/main/res/drawable/ic_compound_mac.xml b/libraries/compound/src/main/res/drawable/ic_compound_mac.xml index 47a4d690ef..f802f5fa4e 100644 --- a/libraries/compound/src/main/res/drawable/ic_compound_mac.xml +++ b/libraries/compound/src/main/res/drawable/ic_compound_mac.xml @@ -4,7 +4,7 @@ android:viewportWidth="24" android:viewportHeight="24"> diff --git a/libraries/compound/src/main/res/drawable/ic_compound_re_order.xml b/libraries/compound/src/main/res/drawable/ic_compound_re_order.xml new file mode 100644 index 0000000000..b980906cc7 --- /dev/null +++ b/libraries/compound/src/main/res/drawable/ic_compound_re_order.xml @@ -0,0 +1,9 @@ + + + diff --git a/libraries/compound/src/main/res/drawable/ic_compound_rotate_left.xml b/libraries/compound/src/main/res/drawable/ic_compound_rotate_left.xml new file mode 100644 index 0000000000..5d372e143c --- /dev/null +++ b/libraries/compound/src/main/res/drawable/ic_compound_rotate_left.xml @@ -0,0 +1,9 @@ + + + diff --git a/libraries/compound/src/main/res/drawable/ic_compound_rotate_right.xml b/libraries/compound/src/main/res/drawable/ic_compound_rotate_right.xml new file mode 100644 index 0000000000..0026ea4ab8 --- /dev/null +++ b/libraries/compound/src/main/res/drawable/ic_compound_rotate_right.xml @@ -0,0 +1,13 @@ + + + + + + diff --git a/libraries/compound/src/main/res/drawable/ic_compound_section.xml b/libraries/compound/src/main/res/drawable/ic_compound_section.xml new file mode 100644 index 0000000000..14fe28cac4 --- /dev/null +++ b/libraries/compound/src/main/res/drawable/ic_compound_section.xml @@ -0,0 +1,9 @@ + + + diff --git a/libraries/compound/src/main/res/drawable/ic_compound_stop.xml b/libraries/compound/src/main/res/drawable/ic_compound_stop.xml new file mode 100644 index 0000000000..2724787b6f --- /dev/null +++ b/libraries/compound/src/main/res/drawable/ic_compound_stop.xml @@ -0,0 +1,9 @@ + + + diff --git a/libraries/compound/src/main/res/drawable/ic_compound_stop_solid.xml b/libraries/compound/src/main/res/drawable/ic_compound_stop_solid.xml new file mode 100644 index 0000000000..820ea4405b --- /dev/null +++ b/libraries/compound/src/main/res/drawable/ic_compound_stop_solid.xml @@ -0,0 +1,9 @@ + + + diff --git a/libraries/compound/src/main/res/drawable/ic_compound_theme.xml b/libraries/compound/src/main/res/drawable/ic_compound_theme.xml new file mode 100644 index 0000000000..99e2927492 --- /dev/null +++ b/libraries/compound/src/main/res/drawable/ic_compound_theme.xml @@ -0,0 +1,9 @@ + + + diff --git a/libraries/compound/src/main/res/drawable/ic_compound_translate.xml b/libraries/compound/src/main/res/drawable/ic_compound_translate.xml new file mode 100644 index 0000000000..13c7a37d28 --- /dev/null +++ b/libraries/compound/src/main/res/drawable/ic_compound_translate.xml @@ -0,0 +1,10 @@ + + + diff --git a/libraries/compound/src/main/res/drawable/ic_compound_tree.xml b/libraries/compound/src/main/res/drawable/ic_compound_tree.xml new file mode 100644 index 0000000000..bc7283dca9 --- /dev/null +++ b/libraries/compound/src/main/res/drawable/ic_compound_tree.xml @@ -0,0 +1,9 @@ + + + diff --git a/libraries/compound/src/main/res/drawable/ic_compound_video_call_outgoing_solid.xml b/libraries/compound/src/main/res/drawable/ic_compound_video_call_outgoing_solid.xml new file mode 100644 index 0000000000..aa5b4e4fd7 --- /dev/null +++ b/libraries/compound/src/main/res/drawable/ic_compound_video_call_outgoing_solid.xml @@ -0,0 +1,11 @@ + + + diff --git a/libraries/compound/src/main/res/drawable/ic_compound_voice_call.xml b/libraries/compound/src/main/res/drawable/ic_compound_voice_call.xml index 258a541751..49860d99c8 100644 --- a/libraries/compound/src/main/res/drawable/ic_compound_voice_call.xml +++ b/libraries/compound/src/main/res/drawable/ic_compound_voice_call.xml @@ -4,12 +4,8 @@ android:autoMirrored="true" android:viewportWidth="24" android:viewportHeight="24"> - - - - + diff --git a/libraries/compound/src/main/res/drawable/ic_compound_voice_call_declined_solid.xml b/libraries/compound/src/main/res/drawable/ic_compound_voice_call_declined_solid.xml new file mode 100644 index 0000000000..8a303785d0 --- /dev/null +++ b/libraries/compound/src/main/res/drawable/ic_compound_voice_call_declined_solid.xml @@ -0,0 +1,10 @@ + + + diff --git a/libraries/compound/src/main/res/drawable/ic_compound_voice_call_missed_solid.xml b/libraries/compound/src/main/res/drawable/ic_compound_voice_call_missed_solid.xml new file mode 100644 index 0000000000..a6a6e25369 --- /dev/null +++ b/libraries/compound/src/main/res/drawable/ic_compound_voice_call_missed_solid.xml @@ -0,0 +1,13 @@ + + + + diff --git a/libraries/compound/src/main/res/drawable/ic_compound_voice_call_outgoing_solid.xml b/libraries/compound/src/main/res/drawable/ic_compound_voice_call_outgoing_solid.xml new file mode 100644 index 0000000000..a5c8e0a329 --- /dev/null +++ b/libraries/compound/src/main/res/drawable/ic_compound_voice_call_outgoing_solid.xml @@ -0,0 +1,13 @@ + + + + diff --git a/libraries/compound/src/main/res/drawable/ic_compound_zoom_in.xml b/libraries/compound/src/main/res/drawable/ic_compound_zoom_in.xml new file mode 100644 index 0000000000..62f7b9cd24 --- /dev/null +++ b/libraries/compound/src/main/res/drawable/ic_compound_zoom_in.xml @@ -0,0 +1,23 @@ + + + + + + + + + diff --git a/libraries/compound/src/main/res/drawable/ic_compound_zoom_out.xml b/libraries/compound/src/main/res/drawable/ic_compound_zoom_out.xml new file mode 100644 index 0000000000..db334baf5e --- /dev/null +++ b/libraries/compound/src/main/res/drawable/ic_compound_zoom_out.xml @@ -0,0 +1,13 @@ + + + + diff --git a/tools/compound/addAutoMirrored.py b/tools/compound/addAutoMirrored.py index 4fd4a64aa0..96e4e6c170 100644 --- a/tools/compound/addAutoMirrored.py +++ b/tools/compound/addAutoMirrored.py @@ -94,9 +94,13 @@ files = [ "ic_compound_video_call_missed_solid.xml", "ic_compound_video_call_off.xml", "ic_compound_video_call_off_solid.xml", + "ic_compound_video_call_outgoing_solid.xml", "ic_compound_video_call_solid.xml", "ic_compound_visibility_off.xml", "ic_compound_voice_call.xml", + "ic_compound_voice_call_declined_solid.xml", + "ic_compound_voice_call_missed_solid.xml", + "ic_compound_voice_call_outgoing_solid.xml", "ic_compound_voice_call_solid.xml", "ic_compound_volume_off.xml", "ic_compound_volume_off_solid.xml", From ab7325a2e739ea4be0578dd004f8d14aac7c90d4 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Mon, 2 Mar 2026 12:42:45 +0100 Subject: [PATCH 36/60] Use stop icon from Compound. --- .../android/libraries/designsystem/icons/IconsList.kt | 1 - libraries/designsystem/src/main/res/drawable/ic_stop.xml | 9 --------- .../components/VoiceMessageRecorderButtonIcon.kt | 2 +- 3 files changed, 1 insertion(+), 11 deletions(-) delete mode 100644 libraries/designsystem/src/main/res/drawable/ic_stop.xml diff --git a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/icons/IconsList.kt b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/icons/IconsList.kt index f0a6fc847b..939dfaa69f 100644 --- a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/icons/IconsList.kt +++ b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/icons/IconsList.kt @@ -14,7 +14,6 @@ import io.element.android.libraries.designsystem.R // All the icons should be defined in Compound. internal val iconsOther = listOf( R.drawable.ic_notification, - R.drawable.ic_stop, R.drawable.pin, R.drawable.ic_winner, ) diff --git a/libraries/designsystem/src/main/res/drawable/ic_stop.xml b/libraries/designsystem/src/main/res/drawable/ic_stop.xml deleted file mode 100644 index e4cd1507bb..0000000000 --- a/libraries/designsystem/src/main/res/drawable/ic_stop.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - diff --git a/libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/components/VoiceMessageRecorderButtonIcon.kt b/libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/components/VoiceMessageRecorderButtonIcon.kt index aeeaf839c3..f11bb1d5b7 100644 --- a/libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/components/VoiceMessageRecorderButtonIcon.kt +++ b/libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/components/VoiceMessageRecorderButtonIcon.kt @@ -65,7 +65,7 @@ private fun StopButton( ) { Icon( modifier = Modifier.size(24.dp), - resourceId = CommonDrawables.ic_stop, + imageVector = CompoundIcons.StopSolid(), // Note: accessibility is managed in TextComposer. contentDescription = null, tint = ElementTheme.colors.iconOnSolidPrimary, From 2e5304ba7804ef783266202618977be7f896f706 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Mon, 2 Mar 2026 12:44:58 +0100 Subject: [PATCH 37/60] Fix compilation issue. --- .../compound/previews/SemanticColorsPreview.kt | 6 ++---- .../android/libraries/designsystem/colors/Gradient.kt | 11 +++++++---- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/libraries/compound/src/main/kotlin/io/element/android/compound/previews/SemanticColorsPreview.kt b/libraries/compound/src/main/kotlin/io/element/android/compound/previews/SemanticColorsPreview.kt index 3f5fb42149..c629e29866 100644 --- a/libraries/compound/src/main/kotlin/io/element/android/compound/previews/SemanticColorsPreview.kt +++ b/libraries/compound/src/main/kotlin/io/element/android/compound/previews/SemanticColorsPreview.kt @@ -155,12 +155,10 @@ private fun getSemanticColors(): ImmutableMap { "gradientActionStop2" to gradientActionStop2, "gradientActionStop3" to gradientActionStop3, "gradientActionStop4" to gradientActionStop4, + "gradientCriticalStop1" to gradientCriticalStop1, + "gradientCriticalStop2" to gradientCriticalStop2, "gradientInfoStop1" to gradientInfoStop1, "gradientInfoStop2" to gradientInfoStop2, - "gradientInfoStop3" to gradientInfoStop3, - "gradientInfoStop4" to gradientInfoStop4, - "gradientInfoStop5" to gradientInfoStop5, - "gradientInfoStop6" to gradientInfoStop6, "gradientSubtleStop1" to gradientSubtleStop1, "gradientSubtleStop2" to gradientSubtleStop2, "gradientSubtleStop3" to gradientSubtleStop3, diff --git a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/colors/Gradient.kt b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/colors/Gradient.kt index 1faed13425..0ed2253647 100644 --- a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/colors/Gradient.kt +++ b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/colors/Gradient.kt @@ -38,8 +38,11 @@ fun gradientSubtleColors(): List = listOf( fun gradientInfoColors(): List = listOf( ElementTheme.colors.gradientInfoStop1, ElementTheme.colors.gradientInfoStop2, - ElementTheme.colors.gradientInfoStop3, - ElementTheme.colors.gradientInfoStop4, - ElementTheme.colors.gradientInfoStop5, - ElementTheme.colors.gradientInfoStop6, +) + +@Composable +@ReadOnlyComposable +fun gradientCriticalColors(): List = listOf( + ElementTheme.colors.gradientCriticalStop1, + ElementTheme.colors.gradientCriticalStop2, ) From 723cfc77ff36b9aeaa78ab206b4aad825e036415 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Mon, 2 Mar 2026 12:56:55 +0100 Subject: [PATCH 38/60] Use gradient color in ComposerAlertMolecule. Fixes #6192 --- .../identity/IdentityChangeStateView.kt | 2 +- .../atomic/molecules/ComposerAlertMolecule.kt | 24 +++++++++++-------- .../VoiceMessageRecorderButtonIcon.kt | 1 - 3 files changed, 15 insertions(+), 12 deletions(-) diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/crypto/identity/IdentityChangeStateView.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/crypto/identity/IdentityChangeStateView.kt index 92352732b0..21684206b5 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/crypto/identity/IdentityChangeStateView.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/crypto/identity/IdentityChangeStateView.kt @@ -115,7 +115,7 @@ private fun ViolationAlert( }, submitText = stringResource(submitTextId), onSubmitClick = onSubmitClick, - level = if (isCritical) ComposerAlertLevel.Critical else ComposerAlertLevel.Default, + level = if (isCritical) ComposerAlertLevel.Critical else ComposerAlertLevel.Info, ) } diff --git a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/atomic/molecules/ComposerAlertMolecule.kt b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/atomic/molecules/ComposerAlertMolecule.kt index 72994fec44..d77df1e245 100644 --- a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/atomic/molecules/ComposerAlertMolecule.kt +++ b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/atomic/molecules/ComposerAlertMolecule.kt @@ -26,6 +26,8 @@ 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.colors.gradientCriticalColors +import io.element.android.libraries.designsystem.colors.gradientInfoColors import io.element.android.libraries.designsystem.components.avatar.Avatar import io.element.android.libraries.designsystem.components.avatar.AvatarData import io.element.android.libraries.designsystem.components.avatar.AvatarType @@ -38,6 +40,9 @@ import io.element.android.libraries.designsystem.theme.components.Icon import io.element.android.libraries.designsystem.theme.components.Text import io.element.android.libraries.ui.strings.CommonStrings +/** + * Ref: https://www.figma.com/design/G1xy0HDZKJf5TCRFmKb5d5/Compound-Android-Components?node-id=2392-6721 + */ @Composable fun ComposerAlertMolecule( avatar: AvatarData?, @@ -57,12 +62,6 @@ fun ComposerAlertMolecule( ComposerAlertLevel.Critical -> ElementTheme.colors.borderCriticalSubtle } - val startColor = when (level) { - ComposerAlertLevel.Default -> ElementTheme.colors.bgInfoSubtle - ComposerAlertLevel.Info -> ElementTheme.colors.bgInfoSubtle - ComposerAlertLevel.Critical -> ElementTheme.colors.bgCriticalSubtle - } - val textColor = when (level) { ComposerAlertLevel.Default -> ElementTheme.colors.textPrimary ComposerAlertLevel.Info -> ElementTheme.colors.textInfoPrimary @@ -75,12 +74,17 @@ fun ComposerAlertMolecule( .height(1.dp) .background(lineColor) ) - val brush = Brush.verticalGradient( - listOf(startColor, ElementTheme.colors.bgCanvasDefault), - ) + val gradientColors = when (level) { + ComposerAlertLevel.Default -> listOf( + ElementTheme.colors.bgInfoSubtle, + ElementTheme.colors.bgInfoSubtle, + ) + ComposerAlertLevel.Info -> gradientInfoColors() + ComposerAlertLevel.Critical -> gradientCriticalColors() + } Box( modifier = Modifier - .background(brush) + .background(Brush.verticalGradient(gradientColors)) .padding(start = 16.dp, end = 16.dp, top = 16.dp, bottom = 8.dp) ) { Column( diff --git a/libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/components/VoiceMessageRecorderButtonIcon.kt b/libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/components/VoiceMessageRecorderButtonIcon.kt index f11bb1d5b7..e5468dc1fd 100644 --- a/libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/components/VoiceMessageRecorderButtonIcon.kt +++ b/libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/components/VoiceMessageRecorderButtonIcon.kt @@ -23,7 +23,6 @@ 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.IconButton -import io.element.android.libraries.designsystem.utils.CommonDrawables @Composable internal fun VoiceMessageRecorderButtonIcon( From 08b91071d233ad367302a6cb0ee0aa71989b5ecf Mon Sep 17 00:00:00 2001 From: ElementBot Date: Mon, 2 Mar 2026 12:19:18 +0000 Subject: [PATCH 39/60] Update screenshots --- libraries/compound/screenshots/Compound Icons - Dark.png | 4 ++-- libraries/compound/screenshots/Compound Icons - Light.png | 4 ++-- libraries/compound/screenshots/Compound Icons - Rtl.png | 4 ++-- .../screenshots/Compound Semantic Colors - Dark HC.png | 4 ++-- .../compound/screenshots/Compound Semantic Colors - Dark.png | 4 ++-- .../screenshots/Compound Semantic Colors - Light HC.png | 4 ++-- .../compound/screenshots/Compound Semantic Colors - Light.png | 4 ++-- .../compound/screenshots/Compound Vector Icons - Dark.png | 4 ++-- .../compound/screenshots/Compound Vector Icons - Light.png | 4 ++-- ...tures.lockscreen.impl.unlock.keypad_PinKeypad_Day_0_en.png | 4 ++-- ...res.lockscreen.impl.unlock.keypad_PinKeypad_Night_0_en.png | 4 ++-- ...features.lockscreen.impl.unlock_PinUnlockView_Day_0_en.png | 4 ++-- ...features.lockscreen.impl.unlock_PinUnlockView_Day_1_en.png | 4 ++-- ...features.lockscreen.impl.unlock_PinUnlockView_Day_2_en.png | 4 ++-- ...features.lockscreen.impl.unlock_PinUnlockView_Day_3_en.png | 4 ++-- ...features.lockscreen.impl.unlock_PinUnlockView_Day_4_en.png | 4 ++-- ...features.lockscreen.impl.unlock_PinUnlockView_Day_5_en.png | 4 ++-- ...features.lockscreen.impl.unlock_PinUnlockView_Day_6_en.png | 4 ++-- ...features.lockscreen.impl.unlock_PinUnlockView_Day_7_en.png | 4 ++-- ...atures.lockscreen.impl.unlock_PinUnlockView_Night_0_en.png | 4 ++-- ...atures.lockscreen.impl.unlock_PinUnlockView_Night_1_en.png | 4 ++-- ...atures.lockscreen.impl.unlock_PinUnlockView_Night_2_en.png | 4 ++-- ...atures.lockscreen.impl.unlock_PinUnlockView_Night_3_en.png | 4 ++-- ...atures.lockscreen.impl.unlock_PinUnlockView_Night_4_en.png | 4 ++-- ...atures.lockscreen.impl.unlock_PinUnlockView_Night_5_en.png | 4 ++-- ...atures.lockscreen.impl.unlock_PinUnlockView_Night_6_en.png | 4 ++-- ...atures.lockscreen.impl.unlock_PinUnlockView_Night_7_en.png | 4 ++-- ....impl.crypto.identity_IdentityChangeStateView_Day_1_en.png | 4 ++-- ...mpl.crypto.identity_IdentityChangeStateView_Night_1_en.png | 4 ++-- ...rypto.identity_MessagesViewWithIdentityChange_Day_1_en.png | 4 ++-- ...pto.identity_MessagesViewWithIdentityChange_Night_1_en.png | 4 ++-- ...impl.messagecomposer_MessageComposerViewVoice_Day_0_en.png | 4 ++-- ...pl.messagecomposer_MessageComposerViewVoice_Night_0_en.png | 4 ++-- ...ponents.virtual_TimelineItemRoomBeginningView_Day_0_en.png | 4 ++-- ...nents.virtual_TimelineItemRoomBeginningView_Night_0_en.png | 4 ++-- .../images/features.messages.impl_MessagesView_Day_10_en.png | 4 ++-- .../images/features.messages.impl_MessagesView_Day_8_en.png | 4 ++-- .../features.messages.impl_MessagesView_Night_10_en.png | 4 ++-- .../images/features.messages.impl_MessagesView_Night_8_en.png | 4 ++-- ...system.atomic.molecules_ComposerAlertMolecule_Day_0_en.png | 4 ++-- ...system.atomic.molecules_ComposerAlertMolecule_Day_1_en.png | 4 ++-- ...system.atomic.molecules_ComposerAlertMolecule_Day_2_en.png | 4 ++-- ...stem.atomic.molecules_ComposerAlertMolecule_Night_0_en.png | 4 ++-- ...stem.atomic.molecules_ComposerAlertMolecule_Night_1_en.png | 4 ++-- ...stem.atomic.molecules_ComposerAlertMolecule_Night_2_en.png | 4 ++-- .../libraries.designsystem.icons_IconsOther_Day_0_en.png | 4 ++-- .../libraries.designsystem.icons_IconsOther_Night_0_en.png | 4 ++-- ...raries.designsystem.theme.components_AllIcons_Icons_en.png | 4 ++-- ...ser.components_VoiceMessageRecorderButtonIcon_Day_0_en.png | 4 ++-- ...r.components_VoiceMessageRecorderButtonIcon_Night_0_en.png | 4 ++-- ...es.textcomposer_TextComposerVoiceNotEncrypted_Day_0_en.png | 4 ++-- ....textcomposer_TextComposerVoiceNotEncrypted_Night_0_en.png | 4 ++-- .../libraries.textcomposer_TextComposerVoice_Day_0_en.png | 4 ++-- .../libraries.textcomposer_TextComposerVoice_Night_0_en.png | 4 ++-- 54 files changed, 108 insertions(+), 108 deletions(-) diff --git a/libraries/compound/screenshots/Compound Icons - Dark.png b/libraries/compound/screenshots/Compound Icons - Dark.png index c0d816a6b9..a381536ce4 100644 --- a/libraries/compound/screenshots/Compound Icons - Dark.png +++ b/libraries/compound/screenshots/Compound Icons - Dark.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:fa16f659aa3e7d05fa03a51d52faddc0c40c3ab52231687f8c6c8a4ba81ff6f0 -size 219813 +oid sha256:460ddd253f4029b29edde9d858237204acb55aca7e13e92bc691ea71ca34c53e +size 237462 diff --git a/libraries/compound/screenshots/Compound Icons - Light.png b/libraries/compound/screenshots/Compound Icons - Light.png index fd105971e0..c26dbc59cb 100644 --- a/libraries/compound/screenshots/Compound Icons - Light.png +++ b/libraries/compound/screenshots/Compound Icons - Light.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:72fb457dc50bf1a2261502fc1da15c01ab415344e9070354d38dc7b74234d790 -size 232095 +oid sha256:a0b76eee73be6a2ba58eb12883477ebce7daf039b6c60637e263a478a0bc68fe +size 250668 diff --git a/libraries/compound/screenshots/Compound Icons - Rtl.png b/libraries/compound/screenshots/Compound Icons - Rtl.png index 50c98caee5..0af5bf0631 100644 --- a/libraries/compound/screenshots/Compound Icons - Rtl.png +++ b/libraries/compound/screenshots/Compound Icons - Rtl.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:24cfe760717881ee71f36fae1fb201e74b2c32a2f9a5aef71ef21dab69ea5366 -size 233212 +oid sha256:d12abdfa2a2d7d1943e0e377279134b44de0ad5d8fb12b09e23c2083b728989f +size 251951 diff --git a/libraries/compound/screenshots/Compound Semantic Colors - Dark HC.png b/libraries/compound/screenshots/Compound Semantic Colors - Dark HC.png index b66b386ed8..2a9029e303 100644 --- a/libraries/compound/screenshots/Compound Semantic Colors - Dark HC.png +++ b/libraries/compound/screenshots/Compound Semantic Colors - Dark HC.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c846cd10b83361c368bdbb31ed6220cc22693c3cbf52791fb369841af1e9ea48 -size 327701 +oid sha256:afb0295b04f302c25f40774562e7d5b2bb668c4cf1158b521ae9b50a35a58d2b +size 322068 diff --git a/libraries/compound/screenshots/Compound Semantic Colors - Dark.png b/libraries/compound/screenshots/Compound Semantic Colors - Dark.png index 35d684d39b..60761e34e0 100644 --- a/libraries/compound/screenshots/Compound Semantic Colors - Dark.png +++ b/libraries/compound/screenshots/Compound Semantic Colors - Dark.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:05b35fedbd53dec2cc5c4c211a8db1a56055963de69425ddae2cab5aff7e3e75 -size 325750 +oid sha256:3b94a6d004999869b8650559a70a1427882408b242c9b47788e56320aaeef34c +size 320114 diff --git a/libraries/compound/screenshots/Compound Semantic Colors - Light HC.png b/libraries/compound/screenshots/Compound Semantic Colors - Light HC.png index 9061d2b894..d20e3628c7 100644 --- a/libraries/compound/screenshots/Compound Semantic Colors - Light HC.png +++ b/libraries/compound/screenshots/Compound Semantic Colors - Light HC.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:8d98e64eda5d6333067ccc599e99636f618331397207bb7534595e2756edb75e -size 309312 +oid sha256:06cebaaf9e0e4f2b69231ab2b866652419e70df50b0abb68288e08f748ed9b76 +size 301985 diff --git a/libraries/compound/screenshots/Compound Semantic Colors - Light.png b/libraries/compound/screenshots/Compound Semantic Colors - Light.png index 83c00ab51c..213f90fbc7 100644 --- a/libraries/compound/screenshots/Compound Semantic Colors - Light.png +++ b/libraries/compound/screenshots/Compound Semantic Colors - Light.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:5ccbf1234065b182939f001eb65eca0a62adae41a2d91ef0307d27b059407178 -size 309084 +oid sha256:baf841165dfd7c6315dc7bd82d1be8935976d0a9a70e83f4d70e23a2389dab95 +size 301760 diff --git a/libraries/compound/screenshots/Compound Vector Icons - Dark.png b/libraries/compound/screenshots/Compound Vector Icons - Dark.png index 638e4a5cba..b50dc7b82a 100644 --- a/libraries/compound/screenshots/Compound Vector Icons - Dark.png +++ b/libraries/compound/screenshots/Compound Vector Icons - Dark.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a699170cabca6fb912d034a588b45961485afe6ef6d2c24f0ab79f10ae00c168 -size 85629 +oid sha256:40f0940bd8a5ddee96ea2aac01d9672478fc15044621bfb10f5f0b20d61f035d +size 93402 diff --git a/libraries/compound/screenshots/Compound Vector Icons - Light.png b/libraries/compound/screenshots/Compound Vector Icons - Light.png index d60a3fdadb..5e32ca9c59 100644 --- a/libraries/compound/screenshots/Compound Vector Icons - Light.png +++ b/libraries/compound/screenshots/Compound Vector Icons - Light.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:dd4b2a40fcf02d6db29cb0bc371d93236b4a0be6d4446bab86358692cddb53f5 -size 91692 +oid sha256:48d8c1bef4a59554649fab33aa716ca2e9fe24f29a6b7e0dae9c404afedd6695 +size 99735 diff --git a/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.unlock.keypad_PinKeypad_Day_0_en.png b/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.unlock.keypad_PinKeypad_Day_0_en.png index 4be53a66fb..abef40e89b 100644 --- a/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.unlock.keypad_PinKeypad_Day_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.unlock.keypad_PinKeypad_Day_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:650cbf541a2fb9cabb99c5d94105d9e48bda8cae66cc5537ae463c33fd66b055 -size 27870 +oid sha256:7b5d9b30a6c0a1e47b98123e7adddbc349d5e7d4b7d1072322ff1893a7385c48 +size 27885 diff --git a/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.unlock.keypad_PinKeypad_Night_0_en.png b/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.unlock.keypad_PinKeypad_Night_0_en.png index 891f61d9fe..b66e75a96a 100644 --- a/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.unlock.keypad_PinKeypad_Night_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.unlock.keypad_PinKeypad_Night_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:744fe9ec84370f46992b776c550a8f28293b59c4e2c54b1350fcfbebf467a7a9 -size 26856 +oid sha256:beb8c5b4b2999ad1d21e99b8f83783298088582bbd5becfad66df257765d64a9 +size 26857 diff --git a/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.unlock_PinUnlockView_Day_0_en.png b/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.unlock_PinUnlockView_Day_0_en.png index a7270b3bba..dd05b7e17f 100644 --- a/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.unlock_PinUnlockView_Day_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.unlock_PinUnlockView_Day_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:430d5286c4a59eea7020ba082610374d0d69790734dbca3da814d86f4b740012 -size 35941 +oid sha256:011c3caceeb03e9162c5e60dd71d53212971e13b7a6b58692feb901ac13b79e1 +size 35844 diff --git a/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.unlock_PinUnlockView_Day_1_en.png b/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.unlock_PinUnlockView_Day_1_en.png index a905bc2b4a..680f363dca 100644 --- a/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.unlock_PinUnlockView_Day_1_en.png +++ b/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.unlock_PinUnlockView_Day_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:5c18873cedc9b1390af00d6ae3e6af5308cd806eb6b6ce638c924779d27588e6 -size 36346 +oid sha256:aef835a050377afd05e6a517107586160a86fce4f32344fd92d00a08b4a2c660 +size 36250 diff --git a/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.unlock_PinUnlockView_Day_2_en.png b/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.unlock_PinUnlockView_Day_2_en.png index ca50cbd72a..8e99b487cf 100644 --- a/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.unlock_PinUnlockView_Day_2_en.png +++ b/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.unlock_PinUnlockView_Day_2_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:405c000168f3369b4c942676905e02a1babac4405edb6ae0c366f9a51f3e3d79 -size 37177 +oid sha256:f36922d058b19410a38456a9e29760f9b890c1fc0549b3aba2a0e76d3dc64c54 +size 37079 diff --git a/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.unlock_PinUnlockView_Day_3_en.png b/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.unlock_PinUnlockView_Day_3_en.png index cd6ad128f2..655573b7ac 100644 --- a/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.unlock_PinUnlockView_Day_3_en.png +++ b/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.unlock_PinUnlockView_Day_3_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:90728bbeccfddabbe88aa48e645ecef44e0bbcd06ffaa33afd3a09d15ab87d9c -size 40200 +oid sha256:3a1fce6ec4b708fab1df642899f8b12a335dc50c386e2ab2b6168b501069422b +size 40137 diff --git a/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.unlock_PinUnlockView_Day_4_en.png b/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.unlock_PinUnlockView_Day_4_en.png index 0d5bb3759b..0af4ff0fcf 100644 --- a/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.unlock_PinUnlockView_Day_4_en.png +++ b/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.unlock_PinUnlockView_Day_4_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:df0885f9389247dd506b75869a20dba6330ef7e67343dfdc1478a25089ff7248 -size 33641 +oid sha256:ec435ce434370cb5ca711458b955e8843872b01675234eab15cad4ab6e08dc38 +size 33542 diff --git a/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.unlock_PinUnlockView_Day_5_en.png b/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.unlock_PinUnlockView_Day_5_en.png index 0d2164576c..5160773456 100644 --- a/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.unlock_PinUnlockView_Day_5_en.png +++ b/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.unlock_PinUnlockView_Day_5_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:78ed552b1112f9fe6f64d7e1911543302eef7e481997850c55ab677a4774ced1 -size 37500 +oid sha256:f17bdcb653ee9c811b70fa98a975b76e73ea59a896fde869875d7fc8c84f8450 +size 37438 diff --git a/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.unlock_PinUnlockView_Day_6_en.png b/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.unlock_PinUnlockView_Day_6_en.png index 42c3009458..19dd373269 100644 --- a/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.unlock_PinUnlockView_Day_6_en.png +++ b/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.unlock_PinUnlockView_Day_6_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:7d4dd70566a5d285f4ae448076eadc03973c501cefae04469bd1dac7b07261d2 -size 29789 +oid sha256:4b939d947263360619b40986550bad3715439cd9037285410c32c26cc4078251 +size 29725 diff --git a/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.unlock_PinUnlockView_Day_7_en.png b/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.unlock_PinUnlockView_Day_7_en.png index 7e7725b69d..9dd19fc627 100644 --- a/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.unlock_PinUnlockView_Day_7_en.png +++ b/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.unlock_PinUnlockView_Day_7_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:cfb45a91a984afc31376db5fe7038650527505b937f3d8dd444e22478c8770a6 -size 29870 +oid sha256:98252e4f345d6b34e37a8b065cb570f85b5678f6d81b36ef96ca3c5df9433a23 +size 29804 diff --git a/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.unlock_PinUnlockView_Night_0_en.png b/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.unlock_PinUnlockView_Night_0_en.png index 9aa7e42b10..9d1bd22ef5 100644 --- a/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.unlock_PinUnlockView_Night_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.unlock_PinUnlockView_Night_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:99b099d03e53332d971cf703817af3ad6b0e5721ceb36c6a6ba98fb368bdeb80 -size 34684 +oid sha256:e87b9820e45b16a13d2f9fb0a470b5f57abf0e45f48d16e5049c4abca04e94ea +size 34629 diff --git a/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.unlock_PinUnlockView_Night_1_en.png b/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.unlock_PinUnlockView_Night_1_en.png index 92b57a0376..bf74b3022e 100644 --- a/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.unlock_PinUnlockView_Night_1_en.png +++ b/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.unlock_PinUnlockView_Night_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:02c8fae133d02db2caae3d5ab09c8e124beaf7cec0dfa207d1c6551edfc14ef2 -size 35055 +oid sha256:74e88064bd3817c79443b6ed2df9b68e9e455d7bef2d94590854ce0d937e2107 +size 34997 diff --git a/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.unlock_PinUnlockView_Night_2_en.png b/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.unlock_PinUnlockView_Night_2_en.png index a6674d46b7..d5087096c0 100644 --- a/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.unlock_PinUnlockView_Night_2_en.png +++ b/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.unlock_PinUnlockView_Night_2_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:96fc33b031be71d79f20059351531149893063f3366d745de7a55f05dc06e435 -size 35782 +oid sha256:23d3ded6d54724df9d03d382e12b58fc23970c354de52dc90cb0b13b66c9c614 +size 35729 diff --git a/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.unlock_PinUnlockView_Night_3_en.png b/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.unlock_PinUnlockView_Night_3_en.png index d67d6639fc..9ce741484a 100644 --- a/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.unlock_PinUnlockView_Night_3_en.png +++ b/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.unlock_PinUnlockView_Night_3_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:6ef4bde885a848b4b0be1406b979dcf6c21c3b521d783461d6de698286bac605 -size 37888 +oid sha256:be40f01d7694d9d92977037f9d84d9f1a1762f9d10ac20db271227032ecc18ff +size 37834 diff --git a/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.unlock_PinUnlockView_Night_4_en.png b/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.unlock_PinUnlockView_Night_4_en.png index 5c4ec96250..22553fcf66 100644 --- a/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.unlock_PinUnlockView_Night_4_en.png +++ b/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.unlock_PinUnlockView_Night_4_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ceeddcd04359b8c794dcd3f416409c4104b003f4fe68259f55bb17c2af274a3a -size 32529 +oid sha256:94ed59c67dacb5066006189c0daf6d55704495ecffd145d69ea3ba968ffda246 +size 32467 diff --git a/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.unlock_PinUnlockView_Night_5_en.png b/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.unlock_PinUnlockView_Night_5_en.png index 8664799c10..fa1bc40c16 100644 --- a/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.unlock_PinUnlockView_Night_5_en.png +++ b/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.unlock_PinUnlockView_Night_5_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:e335823e079be1ad9e432cac403cab511fa15d854d9515b15554f392c0cdde81 -size 35435 +oid sha256:f204a4e3d113c1f835c959246c5abdaf8dcf601757f17219c83d57d356bc3fdb +size 35381 diff --git a/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.unlock_PinUnlockView_Night_6_en.png b/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.unlock_PinUnlockView_Night_6_en.png index dfd2591e23..a0886cef42 100644 --- a/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.unlock_PinUnlockView_Night_6_en.png +++ b/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.unlock_PinUnlockView_Night_6_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:1d8079dc52cde1c2116d08dd47ac5082c62bb7fe7e906575833da8fa3b10b885 -size 28402 +oid sha256:f76eed2d734821db5e84dcf93e4b83fcb64350f8d41a18827f0ec4242779c5a1 +size 28348 diff --git a/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.unlock_PinUnlockView_Night_7_en.png b/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.unlock_PinUnlockView_Night_7_en.png index 50dab35ef3..9de7f9b9b3 100644 --- a/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.unlock_PinUnlockView_Night_7_en.png +++ b/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.unlock_PinUnlockView_Night_7_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:874201b58d12f6bc76861d74018a8bbe84a14adf01adea96d72dda0c6af4ae63 -size 27920 +oid sha256:d98c1f00e81a318d5df078cb91f88b1a16fe01bf37b835d9c8b976045d4b3023 +size 27860 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.crypto.identity_IdentityChangeStateView_Day_1_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.crypto.identity_IdentityChangeStateView_Day_1_en.png index 9dc48d6c40..5d09fb79bb 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.crypto.identity_IdentityChangeStateView_Day_1_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.crypto.identity_IdentityChangeStateView_Day_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:de136cb7d23d33665936dbd5c7633a5092e12b2ee5fd796fab473f43c8dc8a64 -size 23233 +oid sha256:bdcf85f3e7fdd7b922adb37e72bbf79908b8976398b063cdf388dc63a65656f3 +size 23179 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.crypto.identity_IdentityChangeStateView_Night_1_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.crypto.identity_IdentityChangeStateView_Night_1_en.png index ae411ffa6f..c6ebac9797 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.crypto.identity_IdentityChangeStateView_Night_1_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.crypto.identity_IdentityChangeStateView_Night_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:54518d42c92f2cc88af4edc94ba34fa96ced83a35e884266bd9637a7e8de2aaa -size 26351 +oid sha256:59d4cdd92b696e6a604a00188ab2127ef9397ed6f2d3244e923e604bf4d15509 +size 26143 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.crypto.identity_MessagesViewWithIdentityChange_Day_1_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.crypto.identity_MessagesViewWithIdentityChange_Day_1_en.png index 15225ee23b..1d643d2454 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.crypto.identity_MessagesViewWithIdentityChange_Day_1_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.crypto.identity_MessagesViewWithIdentityChange_Day_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:4b73acbe8a6d63b782f19714ac19a5fab3cbd8e85c87ec0cd7b7cb9f093f891d -size 63257 +oid sha256:322669f2d24c4870b3852e6f73628d892650f56dc437b2db8654d1c0ef2baa19 +size 63295 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.crypto.identity_MessagesViewWithIdentityChange_Night_1_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.crypto.identity_MessagesViewWithIdentityChange_Night_1_en.png index 2daa3219e5..7e0f695cbd 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.crypto.identity_MessagesViewWithIdentityChange_Night_1_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.crypto.identity_MessagesViewWithIdentityChange_Night_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:7d457c27d169001c2a59992fce130ed5a25144e39b182422cf4d31baeed708e5 -size 66652 +oid sha256:8710fb1f12d2337240f47be164892b0337e07f77e0b06faea659181fb5234a69 +size 66374 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.messagecomposer_MessageComposerViewVoice_Day_0_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.messagecomposer_MessageComposerViewVoice_Day_0_en.png index 6626c5d774..24b105d49f 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.messagecomposer_MessageComposerViewVoice_Day_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.messagecomposer_MessageComposerViewVoice_Day_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:0038fefb48b24eaf8226a38b8276fc44e5a106fef6125f581acb08189740374a -size 8622 +oid sha256:35dcf4715c24a1e228cd4cc030105bd89678ce154c3c540d854ba9e4a5ea55d3 +size 8746 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.messagecomposer_MessageComposerViewVoice_Night_0_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.messagecomposer_MessageComposerViewVoice_Night_0_en.png index c9856b2693..c2ca44acea 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.messagecomposer_MessageComposerViewVoice_Night_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.messagecomposer_MessageComposerViewVoice_Night_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:6aa86db8a75ec9bd2680cb81d2089a2eda0d7d25625d95ef60a0e15f0392936d -size 8220 +oid sha256:d55f952bb21069f51dc7bbce90c18b35ca6b0d710478850dc7452f909169eb16 +size 8331 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.virtual_TimelineItemRoomBeginningView_Day_0_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.virtual_TimelineItemRoomBeginningView_Day_0_en.png index 5815548686..8c444c0d05 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.virtual_TimelineItemRoomBeginningView_Day_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.virtual_TimelineItemRoomBeginningView_Day_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:abc1526f441c218d39e44ef3f146d4fee3bbb0628c4ece25fb2ae4ef7e4100b0 -size 48820 +oid sha256:0f30735f80910428772fb5f084eac1950a7163d8211693cf65dadd6058f09dfb +size 40659 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.virtual_TimelineItemRoomBeginningView_Night_0_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.virtual_TimelineItemRoomBeginningView_Night_0_en.png index e01465633c..e6ad5d3e48 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.virtual_TimelineItemRoomBeginningView_Night_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.virtual_TimelineItemRoomBeginningView_Night_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:20c52bb8f44c186d3104d457c5de9c0597d99f0a5be37a9d8680fb4be35d422f -size 53777 +oid sha256:034910a5771e06c07f559917c81b4f94d5eaa36f90394ed21561083bacf5d777 +size 39682 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 7484268e7e..85070a6bc2 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:503983c278dcf6cb1cd427a309fb3e0a60fc3882a4cbf9491fd0617d72058d88 -size 65267 +oid sha256:601d6945ec4869b2113762279301043910c1eb9771f3dc85bb8995140d66b663 +size 65298 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 b8d8a2cf4c..b1d6c2c62e 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:1cb21bd5e7d348d1d07ca4b6a360f26a4735cc9760fdd7e3b4b1bcde32da6f08 -size 62655 +oid sha256:75db744101463a0116d6784a89be961b2d551741bc62ed892e1e896fcf0c673c +size 57593 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 e2fc20773a..e9fa9bb565 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:6ea79d33090c606b1ce22de0302380ba188bb81230ea9ee7b04a0f0e80bb19a0 -size 67921 +oid sha256:cd92f78ab9aa2288b3630cc0c7de96a53faa35c260242d6de757298675151fe0 +size 67645 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 6e371532de..5b3290ec0a 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:86273e812cbc6245527c3d1f138111ece99375aec0d68728882b656b01687bff -size 64392 +oid sha256:425212f4ee67fd8cfc7c0153b8f50f8faebec42b373e936229305260de5d0949 +size 56801 diff --git a/tests/uitests/src/test/snapshots/images/libraries.designsystem.atomic.molecules_ComposerAlertMolecule_Day_0_en.png b/tests/uitests/src/test/snapshots/images/libraries.designsystem.atomic.molecules_ComposerAlertMolecule_Day_0_en.png index f24d03b794..468e353988 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.designsystem.atomic.molecules_ComposerAlertMolecule_Day_0_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.designsystem.atomic.molecules_ComposerAlertMolecule_Day_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:345ce61fcc3e735c2a5c93b2dcb3b62e3046a322ee40a67ef45a5c1593a2d51d -size 17445 +oid sha256:99bcf32a0d1bd3734a1eb7cfa821439927b19fe5120c021f9a90470bc66817a7 +size 12941 diff --git a/tests/uitests/src/test/snapshots/images/libraries.designsystem.atomic.molecules_ComposerAlertMolecule_Day_1_en.png b/tests/uitests/src/test/snapshots/images/libraries.designsystem.atomic.molecules_ComposerAlertMolecule_Day_1_en.png index 112f74afee..66384df40e 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.designsystem.atomic.molecules_ComposerAlertMolecule_Day_1_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.designsystem.atomic.molecules_ComposerAlertMolecule_Day_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:64c2775cdfba87b15bad8692e6be8e5bd1a31b07d67361f523883b5e3537c68d -size 19626 +oid sha256:8b0627f61a38b771bcdeb270db5b819232cb9bf7718ba0c122a172bc505ad730 +size 13995 diff --git a/tests/uitests/src/test/snapshots/images/libraries.designsystem.atomic.molecules_ComposerAlertMolecule_Day_2_en.png b/tests/uitests/src/test/snapshots/images/libraries.designsystem.atomic.molecules_ComposerAlertMolecule_Day_2_en.png index fac56be590..b1130a4672 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.designsystem.atomic.molecules_ComposerAlertMolecule_Day_2_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.designsystem.atomic.molecules_ComposerAlertMolecule_Day_2_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:3bc715d121f67bfa0896aa6cd20f42d5423d1f50fc823f9d44a03ca8dbd7fa1d -size 19593 +oid sha256:4a77f9c7dd17745f213374fe31849469c0d6245aa061daf0e280595185bf26d2 +size 13926 diff --git a/tests/uitests/src/test/snapshots/images/libraries.designsystem.atomic.molecules_ComposerAlertMolecule_Night_0_en.png b/tests/uitests/src/test/snapshots/images/libraries.designsystem.atomic.molecules_ComposerAlertMolecule_Night_0_en.png index 484c8543f3..9d754849c9 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.designsystem.atomic.molecules_ComposerAlertMolecule_Night_0_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.designsystem.atomic.molecules_ComposerAlertMolecule_Night_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:664312de0cceccb5a7bad7e97909fa7177fa70d90edce5b92a55fc84645b84d6 -size 20889 +oid sha256:685812792702bde50766c32aaf769a9d6849b670e8aa196596d57e9f90a2f7b5 +size 13075 diff --git a/tests/uitests/src/test/snapshots/images/libraries.designsystem.atomic.molecules_ComposerAlertMolecule_Night_1_en.png b/tests/uitests/src/test/snapshots/images/libraries.designsystem.atomic.molecules_ComposerAlertMolecule_Night_1_en.png index 896a94bfc7..82afb8c58b 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.designsystem.atomic.molecules_ComposerAlertMolecule_Night_1_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.designsystem.atomic.molecules_ComposerAlertMolecule_Night_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:55d008331c4d83f4e1411d151f1c8e77c56537f2d7457827900930f4d4194b29 -size 23100 +oid sha256:4ceecbb92d0edab1d7cc6a14f07082fb90371245235dfcbf32cd36586644c88b +size 14546 diff --git a/tests/uitests/src/test/snapshots/images/libraries.designsystem.atomic.molecules_ComposerAlertMolecule_Night_2_en.png b/tests/uitests/src/test/snapshots/images/libraries.designsystem.atomic.molecules_ComposerAlertMolecule_Night_2_en.png index 3696e544ad..ff2009d4ce 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.designsystem.atomic.molecules_ComposerAlertMolecule_Night_2_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.designsystem.atomic.molecules_ComposerAlertMolecule_Night_2_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:8eacce2e989c03602201144a41fd97ee7a7d747a85ecdb5eea294af760914894 -size 22877 +oid sha256:cd295161407d847f0a9c61e856c09e715350d7fc8aae174ad00821b0c66b27d3 +size 14192 diff --git a/tests/uitests/src/test/snapshots/images/libraries.designsystem.icons_IconsOther_Day_0_en.png b/tests/uitests/src/test/snapshots/images/libraries.designsystem.icons_IconsOther_Day_0_en.png index 3fd2e10649..c08c04d02c 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.designsystem.icons_IconsOther_Day_0_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.designsystem.icons_IconsOther_Day_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:fe4d10dd2a8fc9e6d4047f40e0e3cb5e97a534ef9857ba557ffdac394c709c04 -size 13653 +oid sha256:e332ec62aa00bd409f33ebdb67240e4e55b1bead2df524522b6a4091343ad0a7 +size 12863 diff --git a/tests/uitests/src/test/snapshots/images/libraries.designsystem.icons_IconsOther_Night_0_en.png b/tests/uitests/src/test/snapshots/images/libraries.designsystem.icons_IconsOther_Night_0_en.png index 744ab19b3a..7592d5a045 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.designsystem.icons_IconsOther_Night_0_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.designsystem.icons_IconsOther_Night_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:9112c6b84e24c58f6f230f390b09b368497348e3a4f913409ff40409cddda6c5 -size 13002 +oid sha256:3f1baf335253cac6c58e0305b2848c1753ef05f07ce9235c9d40928f1191ac7a +size 12223 diff --git a/tests/uitests/src/test/snapshots/images/libraries.designsystem.theme.components_AllIcons_Icons_en.png b/tests/uitests/src/test/snapshots/images/libraries.designsystem.theme.components_AllIcons_Icons_en.png index 27ebcf92ac..d137fa3678 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.designsystem.theme.components_AllIcons_Icons_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.designsystem.theme.components_AllIcons_Icons_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:813b2ee132d7de92e384b185dea13b366a6760095e03c52a9f127bc21402c383 -size 105960 +oid sha256:9af7cbe72cb2e9905ed8b4eb7f9007eaf92bc8dec5b23e0af46d7b41f770b2a8 +size 113751 diff --git a/tests/uitests/src/test/snapshots/images/libraries.textcomposer.components_VoiceMessageRecorderButtonIcon_Day_0_en.png b/tests/uitests/src/test/snapshots/images/libraries.textcomposer.components_VoiceMessageRecorderButtonIcon_Day_0_en.png index 035e81f958..79a641b898 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.textcomposer.components_VoiceMessageRecorderButtonIcon_Day_0_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.textcomposer.components_VoiceMessageRecorderButtonIcon_Day_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:5a1d961ff9854bc804ae3df561ae33f562523fa2ff9ca7ce3758c31c1d8a5c4e -size 5772 +oid sha256:ebfb2a9e5cb38253191c83d232b89db3f2e1fa5eb299aa34747e46eaa1b390fc +size 5898 diff --git a/tests/uitests/src/test/snapshots/images/libraries.textcomposer.components_VoiceMessageRecorderButtonIcon_Night_0_en.png b/tests/uitests/src/test/snapshots/images/libraries.textcomposer.components_VoiceMessageRecorderButtonIcon_Night_0_en.png index d1a43082d9..93aa648ff4 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.textcomposer.components_VoiceMessageRecorderButtonIcon_Night_0_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.textcomposer.components_VoiceMessageRecorderButtonIcon_Night_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:3bc1dee4cf07940aa2bdefb8a5927a6d93ab246f94e19bb625c25581717be3bf -size 5739 +oid sha256:e36f5044c7d30751eda3d5745e14821a0e6a51f4a6ef2b6e63e05475e1110bf9 +size 5828 diff --git a/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerVoiceNotEncrypted_Day_0_en.png b/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerVoiceNotEncrypted_Day_0_en.png index df095badd0..9b8ade34d4 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerVoiceNotEncrypted_Day_0_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerVoiceNotEncrypted_Day_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:71cf49cfdeb78764419825b26e75100c6dbc07e3ae20fcd4882b4dc63c56dcb7 -size 35961 +oid sha256:c394e9a8d80c6081b9759817e06077508d02d34b972edc6a44d5ebe428679448 +size 36087 diff --git a/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerVoiceNotEncrypted_Night_0_en.png b/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerVoiceNotEncrypted_Night_0_en.png index 5d4b8e050b..6b976713b9 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerVoiceNotEncrypted_Night_0_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerVoiceNotEncrypted_Night_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:fa12f44951d01cd2fbcffe3ccf83e7205ea3cb83f681249599b40a36c5df5ad2 -size 34142 +oid sha256:e72a58d07138e2e771ff848f435cfb04956c4f96c66e07100dc1a1905c126fef +size 34267 diff --git a/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerVoice_Day_0_en.png b/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerVoice_Day_0_en.png index e28e0dfe58..19c9f9f4b7 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerVoice_Day_0_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerVoice_Day_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:d908cc7fe22e3f970aa597768d1a9acff8f89efc91b66f066ba1069dd4b22a78 -size 25108 +oid sha256:6852bf756c3f1d44e21409b884c422773c887b1623b2a80c8394394916ed87f6 +size 25210 diff --git a/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerVoice_Night_0_en.png b/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerVoice_Night_0_en.png index c12da311f5..983960cb05 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerVoice_Night_0_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerVoice_Night_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:1005f62c18a05ca7f49311412ba5986e5cc950fc7225e012eee6242c547afcdd -size 24066 +oid sha256:1376d130c9cc5ebf37786708ef3acd75ad11516db6d23a81906ff5ebbfa002d0 +size 24184 From 217c3a2b084ce5e0472254db3da463c3e1c92d6c Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Mon, 2 Mar 2026 13:56:08 +0100 Subject: [PATCH 40/60] Remove ComposerAlertLevel.Default (not in the design). --- .../atomic/molecules/ComposerAlertMolecule.kt | 13 ++----------- .../ComposerAlertMoleculeParamsProvider.kt | 1 - 2 files changed, 2 insertions(+), 12 deletions(-) diff --git a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/atomic/molecules/ComposerAlertMolecule.kt b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/atomic/molecules/ComposerAlertMolecule.kt index d77df1e245..8b0f17177b 100644 --- a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/atomic/molecules/ComposerAlertMolecule.kt +++ b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/atomic/molecules/ComposerAlertMolecule.kt @@ -49,7 +49,7 @@ fun ComposerAlertMolecule( content: AnnotatedString, onSubmitClick: () -> Unit, modifier: Modifier = Modifier, - level: ComposerAlertLevel = ComposerAlertLevel.Default, + level: ComposerAlertLevel = ComposerAlertLevel.Info, showIcon: Boolean = false, submitText: String = stringResource(CommonStrings.action_ok), ) { @@ -57,14 +57,12 @@ fun ComposerAlertMolecule( modifier.fillMaxWidth() ) { val lineColor = when (level) { - ComposerAlertLevel.Default -> ElementTheme.colors.borderInfoSubtle ComposerAlertLevel.Info -> ElementTheme.colors.borderInfoSubtle ComposerAlertLevel.Critical -> ElementTheme.colors.borderCriticalSubtle } val textColor = when (level) { - ComposerAlertLevel.Default -> ElementTheme.colors.textPrimary - ComposerAlertLevel.Info -> ElementTheme.colors.textInfoPrimary + ComposerAlertLevel.Info -> ElementTheme.colors.textPrimary ComposerAlertLevel.Critical -> ElementTheme.colors.textCriticalPrimary } @@ -75,10 +73,6 @@ fun ComposerAlertMolecule( .background(lineColor) ) val gradientColors = when (level) { - ComposerAlertLevel.Default -> listOf( - ElementTheme.colors.bgInfoSubtle, - ElementTheme.colors.bgInfoSubtle, - ) ComposerAlertLevel.Info -> gradientInfoColors() ComposerAlertLevel.Critical -> gradientCriticalColors() } @@ -100,12 +94,10 @@ fun ComposerAlertMolecule( ) } else if (showIcon) { val icon = when (level) { - ComposerAlertLevel.Default -> CompoundIcons.Info() ComposerAlertLevel.Info -> CompoundIcons.Info() ComposerAlertLevel.Critical -> CompoundIcons.Error() } val iconTint = when (level) { - ComposerAlertLevel.Default -> ElementTheme.colors.iconPrimary ComposerAlertLevel.Info -> ElementTheme.colors.iconInfoPrimary ComposerAlertLevel.Critical -> ElementTheme.colors.iconCriticalPrimary } @@ -135,7 +127,6 @@ fun ComposerAlertMolecule( } enum class ComposerAlertLevel { - Default, Info, Critical } diff --git a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/atomic/molecules/ComposerAlertMoleculeParamsProvider.kt b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/atomic/molecules/ComposerAlertMoleculeParamsProvider.kt index 09027e0c91..cd1bc8a02b 100644 --- a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/atomic/molecules/ComposerAlertMoleculeParamsProvider.kt +++ b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/atomic/molecules/ComposerAlertMoleculeParamsProvider.kt @@ -21,7 +21,6 @@ internal data class ComposerAlertMoleculeParams( internal class ComposerAlertMoleculeParamsProvider : PreviewParameterProvider { private val allLevels = sequenceOf( - ComposerAlertLevel.Default, ComposerAlertLevel.Info, ComposerAlertLevel.Critical ) From d577bfd9dc45e6156ebf56e0c7862ee5fce372b9 Mon Sep 17 00:00:00 2001 From: ElementBot Date: Mon, 2 Mar 2026 13:15:54 +0000 Subject: [PATCH 41/60] Update screenshots --- ....impl.crypto.identity_IdentityChangeStateView_Day_1_en.png | 4 ++-- ...mpl.crypto.identity_IdentityChangeStateView_Night_1_en.png | 4 ++-- ...rypto.identity_MessagesViewWithIdentityChange_Day_1_en.png | 4 ++-- ...pto.identity_MessagesViewWithIdentityChange_Night_1_en.png | 4 ++-- ...ponents.virtual_TimelineItemRoomBeginningView_Day_0_en.png | 4 ++-- ...nents.virtual_TimelineItemRoomBeginningView_Night_0_en.png | 4 ++-- .../images/features.messages.impl_MessagesView_Day_10_en.png | 4 ++-- .../images/features.messages.impl_MessagesView_Day_8_en.png | 4 ++-- .../features.messages.impl_MessagesView_Night_10_en.png | 4 ++-- .../images/features.messages.impl_MessagesView_Night_8_en.png | 4 ++-- ...system.atomic.molecules_ComposerAlertMolecule_Day_0_en.png | 4 ++-- ...system.atomic.molecules_ComposerAlertMolecule_Day_1_en.png | 4 ++-- ...system.atomic.molecules_ComposerAlertMolecule_Day_2_en.png | 4 ++-- ...system.atomic.molecules_ComposerAlertMolecule_Day_3_en.png | 4 ++-- ...system.atomic.molecules_ComposerAlertMolecule_Day_4_en.png | 4 ++-- ...system.atomic.molecules_ComposerAlertMolecule_Day_5_en.png | 4 ++-- ...system.atomic.molecules_ComposerAlertMolecule_Day_6_en.png | 3 --- ...system.atomic.molecules_ComposerAlertMolecule_Day_7_en.png | 3 --- ...system.atomic.molecules_ComposerAlertMolecule_Day_8_en.png | 3 --- ...stem.atomic.molecules_ComposerAlertMolecule_Night_0_en.png | 4 ++-- ...stem.atomic.molecules_ComposerAlertMolecule_Night_1_en.png | 4 ++-- ...stem.atomic.molecules_ComposerAlertMolecule_Night_2_en.png | 4 ++-- ...stem.atomic.molecules_ComposerAlertMolecule_Night_3_en.png | 4 ++-- ...stem.atomic.molecules_ComposerAlertMolecule_Night_4_en.png | 4 ++-- ...stem.atomic.molecules_ComposerAlertMolecule_Night_5_en.png | 4 ++-- ...stem.atomic.molecules_ComposerAlertMolecule_Night_6_en.png | 3 --- ...stem.atomic.molecules_ComposerAlertMolecule_Night_7_en.png | 3 --- ...stem.atomic.molecules_ComposerAlertMolecule_Night_8_en.png | 3 --- 28 files changed, 44 insertions(+), 62 deletions(-) delete mode 100644 tests/uitests/src/test/snapshots/images/libraries.designsystem.atomic.molecules_ComposerAlertMolecule_Day_6_en.png delete mode 100644 tests/uitests/src/test/snapshots/images/libraries.designsystem.atomic.molecules_ComposerAlertMolecule_Day_7_en.png delete mode 100644 tests/uitests/src/test/snapshots/images/libraries.designsystem.atomic.molecules_ComposerAlertMolecule_Day_8_en.png delete mode 100644 tests/uitests/src/test/snapshots/images/libraries.designsystem.atomic.molecules_ComposerAlertMolecule_Night_6_en.png delete mode 100644 tests/uitests/src/test/snapshots/images/libraries.designsystem.atomic.molecules_ComposerAlertMolecule_Night_7_en.png delete mode 100644 tests/uitests/src/test/snapshots/images/libraries.designsystem.atomic.molecules_ComposerAlertMolecule_Night_8_en.png diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.crypto.identity_IdentityChangeStateView_Day_1_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.crypto.identity_IdentityChangeStateView_Day_1_en.png index 5d09fb79bb..9dc48d6c40 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.crypto.identity_IdentityChangeStateView_Day_1_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.crypto.identity_IdentityChangeStateView_Day_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:bdcf85f3e7fdd7b922adb37e72bbf79908b8976398b063cdf388dc63a65656f3 -size 23179 +oid sha256:de136cb7d23d33665936dbd5c7633a5092e12b2ee5fd796fab473f43c8dc8a64 +size 23233 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.crypto.identity_IdentityChangeStateView_Night_1_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.crypto.identity_IdentityChangeStateView_Night_1_en.png index c6ebac9797..ae411ffa6f 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.crypto.identity_IdentityChangeStateView_Night_1_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.crypto.identity_IdentityChangeStateView_Night_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:59d4cdd92b696e6a604a00188ab2127ef9397ed6f2d3244e923e604bf4d15509 -size 26143 +oid sha256:54518d42c92f2cc88af4edc94ba34fa96ced83a35e884266bd9637a7e8de2aaa +size 26351 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.crypto.identity_MessagesViewWithIdentityChange_Day_1_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.crypto.identity_MessagesViewWithIdentityChange_Day_1_en.png index 1d643d2454..15225ee23b 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.crypto.identity_MessagesViewWithIdentityChange_Day_1_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.crypto.identity_MessagesViewWithIdentityChange_Day_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:322669f2d24c4870b3852e6f73628d892650f56dc437b2db8654d1c0ef2baa19 -size 63295 +oid sha256:4b73acbe8a6d63b782f19714ac19a5fab3cbd8e85c87ec0cd7b7cb9f093f891d +size 63257 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.crypto.identity_MessagesViewWithIdentityChange_Night_1_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.crypto.identity_MessagesViewWithIdentityChange_Night_1_en.png index 7e0f695cbd..2daa3219e5 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.crypto.identity_MessagesViewWithIdentityChange_Night_1_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.crypto.identity_MessagesViewWithIdentityChange_Night_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:8710fb1f12d2337240f47be164892b0337e07f77e0b06faea659181fb5234a69 -size 66374 +oid sha256:7d457c27d169001c2a59992fce130ed5a25144e39b182422cf4d31baeed708e5 +size 66652 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.virtual_TimelineItemRoomBeginningView_Day_0_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.virtual_TimelineItemRoomBeginningView_Day_0_en.png index 8c444c0d05..5815548686 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.virtual_TimelineItemRoomBeginningView_Day_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.virtual_TimelineItemRoomBeginningView_Day_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:0f30735f80910428772fb5f084eac1950a7163d8211693cf65dadd6058f09dfb -size 40659 +oid sha256:abc1526f441c218d39e44ef3f146d4fee3bbb0628c4ece25fb2ae4ef7e4100b0 +size 48820 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.virtual_TimelineItemRoomBeginningView_Night_0_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.virtual_TimelineItemRoomBeginningView_Night_0_en.png index e6ad5d3e48..e01465633c 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.virtual_TimelineItemRoomBeginningView_Night_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.virtual_TimelineItemRoomBeginningView_Night_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:034910a5771e06c07f559917c81b4f94d5eaa36f90394ed21561083bacf5d777 -size 39682 +oid sha256:20c52bb8f44c186d3104d457c5de9c0597d99f0a5be37a9d8680fb4be35d422f +size 53777 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 85070a6bc2..7484268e7e 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:601d6945ec4869b2113762279301043910c1eb9771f3dc85bb8995140d66b663 -size 65298 +oid sha256:503983c278dcf6cb1cd427a309fb3e0a60fc3882a4cbf9491fd0617d72058d88 +size 65267 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 b1d6c2c62e..b8d8a2cf4c 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:75db744101463a0116d6784a89be961b2d551741bc62ed892e1e896fcf0c673c -size 57593 +oid sha256:1cb21bd5e7d348d1d07ca4b6a360f26a4735cc9760fdd7e3b4b1bcde32da6f08 +size 62655 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 e9fa9bb565..e2fc20773a 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:cd92f78ab9aa2288b3630cc0c7de96a53faa35c260242d6de757298675151fe0 -size 67645 +oid sha256:6ea79d33090c606b1ce22de0302380ba188bb81230ea9ee7b04a0f0e80bb19a0 +size 67921 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 5b3290ec0a..6e371532de 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:425212f4ee67fd8cfc7c0153b8f50f8faebec42b373e936229305260de5d0949 -size 56801 +oid sha256:86273e812cbc6245527c3d1f138111ece99375aec0d68728882b656b01687bff +size 64392 diff --git a/tests/uitests/src/test/snapshots/images/libraries.designsystem.atomic.molecules_ComposerAlertMolecule_Day_0_en.png b/tests/uitests/src/test/snapshots/images/libraries.designsystem.atomic.molecules_ComposerAlertMolecule_Day_0_en.png index 468e353988..f24d03b794 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.designsystem.atomic.molecules_ComposerAlertMolecule_Day_0_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.designsystem.atomic.molecules_ComposerAlertMolecule_Day_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:99bcf32a0d1bd3734a1eb7cfa821439927b19fe5120c021f9a90470bc66817a7 -size 12941 +oid sha256:345ce61fcc3e735c2a5c93b2dcb3b62e3046a322ee40a67ef45a5c1593a2d51d +size 17445 diff --git a/tests/uitests/src/test/snapshots/images/libraries.designsystem.atomic.molecules_ComposerAlertMolecule_Day_1_en.png b/tests/uitests/src/test/snapshots/images/libraries.designsystem.atomic.molecules_ComposerAlertMolecule_Day_1_en.png index 66384df40e..112f74afee 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.designsystem.atomic.molecules_ComposerAlertMolecule_Day_1_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.designsystem.atomic.molecules_ComposerAlertMolecule_Day_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:8b0627f61a38b771bcdeb270db5b819232cb9bf7718ba0c122a172bc505ad730 -size 13995 +oid sha256:64c2775cdfba87b15bad8692e6be8e5bd1a31b07d67361f523883b5e3537c68d +size 19626 diff --git a/tests/uitests/src/test/snapshots/images/libraries.designsystem.atomic.molecules_ComposerAlertMolecule_Day_2_en.png b/tests/uitests/src/test/snapshots/images/libraries.designsystem.atomic.molecules_ComposerAlertMolecule_Day_2_en.png index b1130a4672..cfd3205f40 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.designsystem.atomic.molecules_ComposerAlertMolecule_Day_2_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.designsystem.atomic.molecules_ComposerAlertMolecule_Day_2_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:4a77f9c7dd17745f213374fe31849469c0d6245aa061daf0e280595185bf26d2 -size 13926 +oid sha256:dda7f51afe674c8c7cb0a38f4f042025b088de7518e7f40c51b114939f6448a1 +size 19871 diff --git a/tests/uitests/src/test/snapshots/images/libraries.designsystem.atomic.molecules_ComposerAlertMolecule_Day_3_en.png b/tests/uitests/src/test/snapshots/images/libraries.designsystem.atomic.molecules_ComposerAlertMolecule_Day_3_en.png index c56aa067e6..a6c2015e4f 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.designsystem.atomic.molecules_ComposerAlertMolecule_Day_3_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.designsystem.atomic.molecules_ComposerAlertMolecule_Day_3_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:7639f45d1ee6e2f83508239166a6913cfd860bc65647de640ed3a42738422960 -size 17252 +oid sha256:ce0b5e05128196d4f14fd2b4e1c5b25f1eadec5f53011f310273962e24d30cc1 +size 16920 diff --git a/tests/uitests/src/test/snapshots/images/libraries.designsystem.atomic.molecules_ComposerAlertMolecule_Day_4_en.png b/tests/uitests/src/test/snapshots/images/libraries.designsystem.atomic.molecules_ComposerAlertMolecule_Day_4_en.png index f1df8fdde2..da69c263fa 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.designsystem.atomic.molecules_ComposerAlertMolecule_Day_4_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.designsystem.atomic.molecules_ComposerAlertMolecule_Day_4_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ff8a80e502af236bda4b6553293a6ff0ec3387b2945ee23d415513c1b3e1cac4 -size 19392 +oid sha256:7f77e13209da1562e1dd23c48d15315e7c74e8ad7e72b421309ba3bbc13c9ce4 +size 19849 diff --git a/tests/uitests/src/test/snapshots/images/libraries.designsystem.atomic.molecules_ComposerAlertMolecule_Day_5_en.png b/tests/uitests/src/test/snapshots/images/libraries.designsystem.atomic.molecules_ComposerAlertMolecule_Day_5_en.png index 6c7ddc1769..0fc5a5766c 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.designsystem.atomic.molecules_ComposerAlertMolecule_Day_5_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.designsystem.atomic.molecules_ComposerAlertMolecule_Day_5_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a7745c2b9d122f2cce60503f6f2e745dcb91ae7fec37530b00d6e59cf56c5b9c -size 19289 +oid sha256:2a9f45cc63d97f5de0848cec943d3492242962b169c0ce50fb47e3b0d0cd5bea +size 19676 diff --git a/tests/uitests/src/test/snapshots/images/libraries.designsystem.atomic.molecules_ComposerAlertMolecule_Day_6_en.png b/tests/uitests/src/test/snapshots/images/libraries.designsystem.atomic.molecules_ComposerAlertMolecule_Day_6_en.png deleted file mode 100644 index a6c2015e4f..0000000000 --- a/tests/uitests/src/test/snapshots/images/libraries.designsystem.atomic.molecules_ComposerAlertMolecule_Day_6_en.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:ce0b5e05128196d4f14fd2b4e1c5b25f1eadec5f53011f310273962e24d30cc1 -size 16920 diff --git a/tests/uitests/src/test/snapshots/images/libraries.designsystem.atomic.molecules_ComposerAlertMolecule_Day_7_en.png b/tests/uitests/src/test/snapshots/images/libraries.designsystem.atomic.molecules_ComposerAlertMolecule_Day_7_en.png deleted file mode 100644 index da69c263fa..0000000000 --- a/tests/uitests/src/test/snapshots/images/libraries.designsystem.atomic.molecules_ComposerAlertMolecule_Day_7_en.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:7f77e13209da1562e1dd23c48d15315e7c74e8ad7e72b421309ba3bbc13c9ce4 -size 19849 diff --git a/tests/uitests/src/test/snapshots/images/libraries.designsystem.atomic.molecules_ComposerAlertMolecule_Day_8_en.png b/tests/uitests/src/test/snapshots/images/libraries.designsystem.atomic.molecules_ComposerAlertMolecule_Day_8_en.png deleted file mode 100644 index 0fc5a5766c..0000000000 --- a/tests/uitests/src/test/snapshots/images/libraries.designsystem.atomic.molecules_ComposerAlertMolecule_Day_8_en.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:2a9f45cc63d97f5de0848cec943d3492242962b169c0ce50fb47e3b0d0cd5bea -size 19676 diff --git a/tests/uitests/src/test/snapshots/images/libraries.designsystem.atomic.molecules_ComposerAlertMolecule_Night_0_en.png b/tests/uitests/src/test/snapshots/images/libraries.designsystem.atomic.molecules_ComposerAlertMolecule_Night_0_en.png index 9d754849c9..484c8543f3 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.designsystem.atomic.molecules_ComposerAlertMolecule_Night_0_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.designsystem.atomic.molecules_ComposerAlertMolecule_Night_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:685812792702bde50766c32aaf769a9d6849b670e8aa196596d57e9f90a2f7b5 -size 13075 +oid sha256:664312de0cceccb5a7bad7e97909fa7177fa70d90edce5b92a55fc84645b84d6 +size 20889 diff --git a/tests/uitests/src/test/snapshots/images/libraries.designsystem.atomic.molecules_ComposerAlertMolecule_Night_1_en.png b/tests/uitests/src/test/snapshots/images/libraries.designsystem.atomic.molecules_ComposerAlertMolecule_Night_1_en.png index 82afb8c58b..896a94bfc7 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.designsystem.atomic.molecules_ComposerAlertMolecule_Night_1_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.designsystem.atomic.molecules_ComposerAlertMolecule_Night_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:4ceecbb92d0edab1d7cc6a14f07082fb90371245235dfcbf32cd36586644c88b -size 14546 +oid sha256:55d008331c4d83f4e1411d151f1c8e77c56537f2d7457827900930f4d4194b29 +size 23100 diff --git a/tests/uitests/src/test/snapshots/images/libraries.designsystem.atomic.molecules_ComposerAlertMolecule_Night_2_en.png b/tests/uitests/src/test/snapshots/images/libraries.designsystem.atomic.molecules_ComposerAlertMolecule_Night_2_en.png index ff2009d4ce..f369fa9f5f 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.designsystem.atomic.molecules_ComposerAlertMolecule_Night_2_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.designsystem.atomic.molecules_ComposerAlertMolecule_Night_2_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:cd295161407d847f0a9c61e856c09e715350d7fc8aae174ad00821b0c66b27d3 -size 14192 +oid sha256:0dbe9ea5e32714993a78db1f5a0e33f4276048f29021979f931607c9da55548a +size 22988 diff --git a/tests/uitests/src/test/snapshots/images/libraries.designsystem.atomic.molecules_ComposerAlertMolecule_Night_3_en.png b/tests/uitests/src/test/snapshots/images/libraries.designsystem.atomic.molecules_ComposerAlertMolecule_Night_3_en.png index 20a7afdab8..181080e492 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.designsystem.atomic.molecules_ComposerAlertMolecule_Night_3_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.designsystem.atomic.molecules_ComposerAlertMolecule_Night_3_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:44fd329498dc7b8c3258a25b4ef819b4f05363b9329be63dd76dcf0e59962845 -size 20406 +oid sha256:3358ff34d01f2261e98bbe595b0a3baf3377a35473e4bd90efae0b0cf5612028 +size 19388 diff --git a/tests/uitests/src/test/snapshots/images/libraries.designsystem.atomic.molecules_ComposerAlertMolecule_Night_4_en.png b/tests/uitests/src/test/snapshots/images/libraries.designsystem.atomic.molecules_ComposerAlertMolecule_Night_4_en.png index e7faed0a60..ba58c597b7 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.designsystem.atomic.molecules_ComposerAlertMolecule_Night_4_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.designsystem.atomic.molecules_ComposerAlertMolecule_Night_4_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f355e2d2b80890c876e7a8f3a575c207788d875f49a3e0ccf9875190505fd387 -size 22798 +oid sha256:2788dc05b5d242670ffab703ef220990d5c48538d3f4bc3654b81f6b5e72c7ea +size 22415 diff --git a/tests/uitests/src/test/snapshots/images/libraries.designsystem.atomic.molecules_ComposerAlertMolecule_Night_5_en.png b/tests/uitests/src/test/snapshots/images/libraries.designsystem.atomic.molecules_ComposerAlertMolecule_Night_5_en.png index 3dfaba3ecf..d8a9d0e0ef 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.designsystem.atomic.molecules_ComposerAlertMolecule_Night_5_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.designsystem.atomic.molecules_ComposerAlertMolecule_Night_5_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:9942fbfa7c5fb11250683339269c0409ff67e228c4a7cbf9c74efe16e7bcef53 -size 22506 +oid sha256:1a96b3725a2b81c928f95e368c327916609fbad2aba74d07e6d7b5fbaee42ba4 +size 21954 diff --git a/tests/uitests/src/test/snapshots/images/libraries.designsystem.atomic.molecules_ComposerAlertMolecule_Night_6_en.png b/tests/uitests/src/test/snapshots/images/libraries.designsystem.atomic.molecules_ComposerAlertMolecule_Night_6_en.png deleted file mode 100644 index 181080e492..0000000000 --- a/tests/uitests/src/test/snapshots/images/libraries.designsystem.atomic.molecules_ComposerAlertMolecule_Night_6_en.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:3358ff34d01f2261e98bbe595b0a3baf3377a35473e4bd90efae0b0cf5612028 -size 19388 diff --git a/tests/uitests/src/test/snapshots/images/libraries.designsystem.atomic.molecules_ComposerAlertMolecule_Night_7_en.png b/tests/uitests/src/test/snapshots/images/libraries.designsystem.atomic.molecules_ComposerAlertMolecule_Night_7_en.png deleted file mode 100644 index ba58c597b7..0000000000 --- a/tests/uitests/src/test/snapshots/images/libraries.designsystem.atomic.molecules_ComposerAlertMolecule_Night_7_en.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:2788dc05b5d242670ffab703ef220990d5c48538d3f4bc3654b81f6b5e72c7ea -size 22415 diff --git a/tests/uitests/src/test/snapshots/images/libraries.designsystem.atomic.molecules_ComposerAlertMolecule_Night_8_en.png b/tests/uitests/src/test/snapshots/images/libraries.designsystem.atomic.molecules_ComposerAlertMolecule_Night_8_en.png deleted file mode 100644 index d8a9d0e0ef..0000000000 --- a/tests/uitests/src/test/snapshots/images/libraries.designsystem.atomic.molecules_ComposerAlertMolecule_Night_8_en.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:1a96b3725a2b81c928f95e368c327916609fbad2aba74d07e6d7b5fbaee42ba4 -size 21954 From 5bcaad1e81a1f8e1fd0220ed498e1da241e510ae Mon Sep 17 00:00:00 2001 From: ElementBot <110224175+ElementBot@users.noreply.github.com> Date: Mon, 2 Mar 2026 14:54:50 +0100 Subject: [PATCH 42/60] Sync Strings from Localazy (#6269) Co-authored-by: bmarty <3940906+bmarty@users.noreply.github.com> --- .../src/main/res/values-el/translations.xml | 11 + .../src/main/res/values-tr/translations.xml | 11 + .../src/main/res/values-uz/translations.xml | 11 + .../src/main/res/values-es/translations.xml | 1 + .../src/main/res/values-tr/translations.xml | 1 + .../src/main/res/values-bg/translations.xml | 2 +- .../src/main/res/values-da/translations.xml | 5 + .../src/main/res/values-el/translations.xml | 30 +- .../src/main/res/values-es/translations.xml | 11 +- .../src/main/res/values-fi/translations.xml | 32 +- .../src/main/res/values-hu/translations.xml | 7 +- .../src/main/res/values-nb/translations.xml | 11 + .../src/main/res/values-nl/translations.xml | 4 + .../src/main/res/values-ru/translations.xml | 7 + .../src/main/res/values-tr/translations.xml | 2 +- .../src/main/res/values-uz/translations.xml | 1 + .../src/main/res/values-zh/translations.xml | 30 +- .../src/main/res/values-be/translations.xml | 2 + .../src/main/res/values-el/translations.xml | 6 + .../src/main/res/values-es/translations.xml | 5 + .../src/main/res/values-fi/translations.xml | 1 + .../src/main/res/values-nb/translations.xml | 1 + .../src/main/res/values-ru/translations.xml | 1 + .../src/main/res/values-tr/translations.xml | 4 + .../src/main/res/values-uz/translations.xml | 4 +- .../src/main/res/values-zh/translations.xml | 1 + .../src/main/res/values-tr/translations.xml | 1 + .../src/main/res/values-el/translations.xml | 14 +- .../src/main/res/values-es/translations.xml | 12 +- .../src/main/res/values-sv/translations.xml | 8 +- .../src/main/res/values-uz/translations.xml | 1 + .../src/main/res/values-el/translations.xml | 1 + .../src/main/res/values-es/translations.xml | 1 + .../src/main/res/values-el/translations.xml | 3 + .../src/main/res/values-fr/translations.xml | 2 +- .../src/main/res/values-tr/translations.xml | 3 + .../src/main/res/values-el/translations.xml | 19 + .../src/main/res/values-fi/translations.xml | 19 + .../src/main/res/values-tr/translations.xml | 16 + .../src/main/res/values-uz/translations.xml | 16 + .../src/main/res/values-zh/translations.xml | 19 + .../src/main/res/values-tr/translations.xml | 4 +- .../src/main/res/values-el/translations.xml | 6 + .../src/main/res/values-es/translations.xml | 1 + .../src/main/res/values-fi/translations.xml | 2 + .../src/main/res/values-tr/translations.xml | 4 + .../src/main/res/values-zh/translations.xml | 2 + .../src/main/res/values-el/translations.xml | 8 + .../src/main/res/values-es/translations.xml | 6 + .../src/main/res/values-nb/translations.xml | 2 +- .../src/main/res/values-tr/translations.xml | 5 + .../src/main/res/values-uz/translations.xml | 2 + .../src/main/res/values-el/translations.xml | 1 + .../src/main/res/values-es/translations.xml | 4 + .../src/main/res/values-tr/translations.xml | 5 + .../src/main/res/values-es/translations.xml | 1 + .../src/main/res/values-el/translations.xml | 13 + .../src/main/res/values-nl/translations.xml | 1 + .../src/main/res/values-tr/translations.xml | 16 + .../src/main/res/values-uz/translations.xml | 6 + .../src/main/res/values-el/translations.xml | 3 + .../src/main/res/values-es/translations.xml | 1 + .../src/main/res/values-tr/translations.xml | 2 + .../src/main/res/values-uz/translations.xml | 2 + .../src/main/res/values-tr/translations.xml | 7 + .../src/main/res/values-bg/translations.xml | 14 +- .../src/main/res/values-el/translations.xml | 46 +- .../src/main/res/values-es/translations.xml | 22 +- .../src/main/res/values-fi/translations.xml | 17 +- .../src/main/res/values-fr/translations.xml | 2 +- .../src/main/res/values-tr/translations.xml | 14 + .../src/main/res/values-uz/translations.xml | 30 +- .../src/main/res/values-zh/translations.xml | 34 +- .../src/main/res/values-bg/translations.xml | 30 +- .../src/main/res/values-da/translations.xml | 4 + .../src/main/res/values-el/translations.xml | 86 +- .../src/main/res/values-es/translations.xml | 45 +- .../src/main/res/values-fi/translations.xml | 36 +- .../src/main/res/values-fr/translations.xml | 2 +- .../src/main/res/values-hu/translations.xml | 4 + .../src/main/res/values-nb/translations.xml | 5 + .../src/main/res/values-nl/translations.xml | 1 + .../main/res/values-pt-rBR/translations.xml | 1 + .../src/main/res/values-ru/translations.xml | 2 + .../src/main/res/values-sv/translations.xml | 4 +- .../src/main/res/values-tr/translations.xml | 22 +- .../src/main/res/values-uz/translations.xml | 38 +- .../src/main/res/values-zh/translations.xml | 76 +- .../src/main/res/values-bg/translations.xml | 2 +- .../src/main/res/values-el/translations.xml | 2 +- .../src/main/res/values-es/translations.xml | 2 +- .../src/main/res/values-zh/translations.xml | 2 +- .../src/main/res/values-el/translations.xml | 4 +- .../src/main/res/values-tr/translations.xml | 3 + .../src/main/res/values-uz/translations.xml | 2 + .../src/main/res/values-be/translations.xml | 4 + .../src/main/res/values-bg/translations.xml | 14 +- .../src/main/res/values-da/translations.xml | 1 + .../src/main/res/values-el/translations.xml | 42 +- .../src/main/res/values-es/translations.xml | 21 +- .../src/main/res/values-fi/translations.xml | 20 +- .../src/main/res/values-hu/translations.xml | 1 + .../src/main/res/values-nb/translations.xml | 2 + .../main/res/values-pt-rBR/translations.xml | 1 + .../src/main/res/values-ru/translations.xml | 2 + .../src/main/res/values-sv/translations.xml | 4 +- .../src/main/res/values-tr/translations.xml | 16 +- .../src/main/res/values-uz/translations.xml | 15 + .../src/main/res/values-zh/translations.xml | 45 +- .../src/main/res/values-da/translations.xml | 4 + .../src/main/res/values-el/translations.xml | 23 + .../src/main/res/values-fi/translations.xml | 10 + .../src/main/res/values-fr/translations.xml | 2 +- .../src/main/res/values-hu/translations.xml | 1 + .../src/main/res/values-nb/translations.xml | 7 + .../src/main/res/values-ru/translations.xml | 3 + .../src/main/res/values-tr/translations.xml | 7 + .../src/main/res/values-uz/translations.xml | 12 + .../src/main/res/values-zh/translations.xml | 9 + .../src/main/res/values-el/translations.xml | 6 +- .../src/main/res/values-es/translations.xml | 6 +- .../src/main/res/values-nl/translations.xml | 1 + .../src/main/res/values-da/translations.xml | 4 + .../src/main/res/values-el/translations.xml | 18 + .../src/main/res/values-es/translations.xml | 1 + .../src/main/res/values-fi/translations.xml | 7 + .../src/main/res/values-fr/translations.xml | 4 + .../src/main/res/values-hu/translations.xml | 4 + .../src/main/res/values-nb/translations.xml | 4 + .../src/main/res/values-nl/translations.xml | 1 + .../src/main/res/values-uz/translations.xml | 15 + .../src/main/res/values-zh/translations.xml | 6 + .../src/main/res/values-el/translations.xml | 2 +- .../src/main/res/values-es/translations.xml | 3 +- .../src/main/res/values-be/translations.xml | 6 + .../src/main/res/values-da/translations.xml | 9 + .../src/main/res/values-el/translations.xml | 108 +- .../src/main/res/values-es/translations.xml | 14 +- .../src/main/res/values-et/translations.xml | 1 + .../src/main/res/values-fi/translations.xml | 30 + .../src/main/res/values-fr/translations.xml | 4 + .../src/main/res/values-hu/translations.xml | 9 +- .../src/main/res/values-nb/translations.xml | 33 +- .../src/main/res/values-nl/translations.xml | 15 +- .../src/main/res/values-ru/translations.xml | 5 + .../src/main/res/values-tr/translations.xml | 48 +- .../src/main/res/values-uz/translations.xml | 29 +- .../main/res/values-zh-rTW/translations.xml | 1 + .../src/main/res/values-zh/translations.xml | 30 +- .../src/main/res/values/localazy.xml | 2 + ...me.impl.spaces_HomeSpacesView_Day_0_de.png | 4 +- ...me.impl.spaces_HomeSpacesView_Day_1_de.png | 4 +- ...me.impl.spaces_HomeSpacesView_Day_2_de.png | 4 +- ...me.impl.spaces_HomeSpacesView_Day_3_de.png | 4 +- .../features.home.impl_HomeView_Day_0_de.png | 4 +- .../features.home.impl_HomeView_Day_10_de.png | 4 +- .../features.home.impl_HomeView_Day_13_de.png | 4 +- .../features.home.impl_HomeView_Day_14_de.png | 4 +- .../features.home.impl_HomeView_Day_15_de.png | 4 +- .../features.home.impl_HomeView_Day_16_de.png | 3 + .../features.home.impl_HomeView_Day_1_de.png | 4 +- .../features.home.impl_HomeView_Day_2_de.png | 4 +- .../features.home.impl_HomeView_Day_3_de.png | 4 +- .../features.home.impl_HomeView_Day_4_de.png | 4 +- .../features.home.impl_HomeView_Day_5_de.png | 4 +- .../features.home.impl_HomeView_Day_9_de.png | 4 +- screenshots/html/data.js | 2029 +++++++++-------- 167 files changed, 2455 insertions(+), 1322 deletions(-) create mode 100644 features/announcement/impl/src/main/res/values-el/translations.xml create mode 100644 features/announcement/impl/src/main/res/values-tr/translations.xml create mode 100644 features/announcement/impl/src/main/res/values-uz/translations.xml create mode 100644 features/poll/api/src/main/res/values-es/translations.xml create mode 100644 features/poll/api/src/main/res/values-tr/translations.xml create mode 100644 features/reportroom/impl/src/main/res/values-tr/translations.xml create mode 100644 features/securityandprivacy/impl/src/main/res/values-be/translations.xml create mode 100644 screenshots/de/features.home.impl_HomeView_Day_16_de.png diff --git a/features/announcement/impl/src/main/res/values-el/translations.xml b/features/announcement/impl/src/main/res/values-el/translations.xml new file mode 100644 index 0000000000..bdeb821efb --- /dev/null +++ b/features/announcement/impl/src/main/res/values-el/translations.xml @@ -0,0 +1,11 @@ + + + "Δείτε τους χώρους που έχετε δημιουργήσει ή στους οποίους έχετε εγγραφεί" + "Να αποδεχθείτε ή να απορρίψετε προσκλήσεις σε χώρους" + "Να ανακαλύψτε όλες τις αίθουσες που μπορείτε να συμμετάσχετε στους χώρους σας" + "Να συμμετάσχετε σε δημόσιους χώρους" + "Να αποχωρήστε από χώρους στους οποίους έχετε συμμετάσχει" + "Το φιλτράρισμα, η δημιουργία και η διαχείριση χώρων θα είναι σύντομα διαθέσιμα." + "Καλώς ορίσατε στην δοκιμαστική έκδοση των Χώρων! Με αυτήν την πρώτη έκδοση μπορείτε:" + "Παρουσιάζοντας τους Χώρους" + diff --git a/features/announcement/impl/src/main/res/values-tr/translations.xml b/features/announcement/impl/src/main/res/values-tr/translations.xml new file mode 100644 index 0000000000..8551dbb02b --- /dev/null +++ b/features/announcement/impl/src/main/res/values-tr/translations.xml @@ -0,0 +1,11 @@ + + + "Oluşturduğunuz veya katıldığınız alanları görüntüleyin" + "Alan davetlerini kabul edin veya reddedin" + "Alanlarınızdaki katılabileceğiniz odaları keşfedin" + "Herkese açık alanlara katılın" + "Katıldığınız alanlardan ayrılın" + "Alanları filtreleme, oluşturma ve yönetme yakında geliyor." + "Alanlar’ın beta sürümüne hoş geldiniz! Bu ilk sürümle şunları yapabilirsiniz:" + "Alanlar ile tanışın" + diff --git a/features/announcement/impl/src/main/res/values-uz/translations.xml b/features/announcement/impl/src/main/res/values-uz/translations.xml new file mode 100644 index 0000000000..12356160b8 --- /dev/null +++ b/features/announcement/impl/src/main/res/values-uz/translations.xml @@ -0,0 +1,11 @@ + + + "Siz yaratgan yoki qo‘shilgan maydonlarni ko‘rish" + "Maydonlarga takliflarni qabul qilish yoki rad etish" + "Maydonlaringizga qo‘shilishingiz mumkin bo‘lgan xonalarni kashf eting" + "Jamoat maydonlariga qo‘shilish" + "Kirgan maydonlaringizni tark eting" + "Maydonlarni filtrlash, yaratish va boshqarish tez orada amalga oshiriladi." + "Maydonlar beta versiyasiga xush kelibsiz! Bu birinchi versiya bilan siz:" + "Maydonlar bilan tanishish" + diff --git a/features/call/impl/src/main/res/values-es/translations.xml b/features/call/impl/src/main/res/values-es/translations.xml index b0c3092efa..a532e72d6a 100644 --- a/features/call/impl/src/main/res/values-es/translations.xml +++ b/features/call/impl/src/main/res/values-es/translations.xml @@ -3,5 +3,6 @@ "Llamada en curso" "Pulsa para regresar a la llamada" "☎️ Llamada en curso" + "Element Call no soporta dispositivos de audio Bluetooth en esta versión de Android. Selecciona otro dispositivo de audio." "Llamada de Element Call entrante" diff --git a/features/call/impl/src/main/res/values-tr/translations.xml b/features/call/impl/src/main/res/values-tr/translations.xml index 37607db690..10213921fd 100644 --- a/features/call/impl/src/main/res/values-tr/translations.xml +++ b/features/call/impl/src/main/res/values-tr/translations.xml @@ -3,5 +3,6 @@ "Devam eden çağrı" "Aramaya geri dönmek için dokunun" "☎️ Çağrı devam ediyor" + "Element Araması, bu Android sürümünde Bluetooth ses cihazlarını desteklemiyor. Lütfen farklı bir ses cihazı seçin." "Gelen Element Call" diff --git a/features/createroom/impl/src/main/res/values-bg/translations.xml b/features/createroom/impl/src/main/res/values-bg/translations.xml index c985ea89a5..94a728c478 100644 --- a/features/createroom/impl/src/main/res/values-bg/translations.xml +++ b/features/createroom/impl/src/main/res/values-bg/translations.xml @@ -6,7 +6,7 @@ "Само поканени хора имат достъп до тази стая. Всички съобщения са шифровани от край до край." "Всеки може да намери тази стая. Можете да промените това по всяко време в настройките на стаята." - "Всеки може да се присъедини към тази стая" + "Всеки може да се присъедини." "За да бъде тази стая видима в директорията на общодостъпните стаи, ще ви е необходим адрес на стаята." "Видимост на стаята" "Тема за разговор (незадължително)" diff --git a/features/createroom/impl/src/main/res/values-da/translations.xml b/features/createroom/impl/src/main/res/values-da/translations.xml index bf4d8836cd..2a6759a135 100644 --- a/features/createroom/impl/src/main/res/values-da/translations.xml +++ b/features/createroom/impl/src/main/res/values-da/translations.xml @@ -8,21 +8,26 @@ "Nyt rum" "Ny gruppe" "Kun inviterede personer kan deltage." + "Privat" "Alle kan finde dette rum. Du kan ændre dette når som helst i rummets indstillinger." "Alle kan deltage." + "Offentlig" "Alle kan bede om at deltage i rummet, men en administrator eller en moderator skal acceptere anmodningen" "Tillad at man kan anmode om deltagelse" "Enhver i %1$s kan deltage, men alle andre skal anmode om adgang." "Anmod om at deltage" "Kun inviterede brugere kan deltage." + "Privat" "Alle kan deltage i dette rum" + "Offentlig" "Alle i %1$s kan deltage." "Standard" "Hvem har adgang" "Hvis dette rum skal være synligt i det offentlige register, skal du bruge en adresse." "Adresse" "Rummets synlighed" + "Tilføj ikke til et mellemrum" "Emne (valgfrit)" "Tilføj beskrivelse…" diff --git a/features/createroom/impl/src/main/res/values-el/translations.xml b/features/createroom/impl/src/main/res/values-el/translations.xml index 1a81e2cf44..1e6d7841ec 100644 --- a/features/createroom/impl/src/main/res/values-el/translations.xml +++ b/features/createroom/impl/src/main/res/values-el/translations.xml @@ -3,14 +3,34 @@ "Νέα αίθουσα" "Πρόσκληση ατόμων" "Προέκυψε σφάλμα κατά τη δημιουργία της αίθουσας" - "Μόνο τα άτομα που έχουν προσκληθεί μπορούν να έχουν πρόσβαση σε αυτή την αίθουσα. Όλα τα μηνύματα είναι κρυπτογραφημένα από άκρο σε άκρο." + "Δεν ήταν δυνατή η δημιουργία του χώρου λόγω άγνωστου σφάλματος. Δοκιμάστε ξανά αργότερα." + "Προσθήκη ονόματος…" + "Νέα αίθουσα" + "Νέος χώρος" + "Μόνο άτομα που έχουν προσκληθεί μπορούν να συμμετάσχουν." + "Ιδιωτικό" "Ο καθένας μπορεί να βρει αυτή την αίθουσα. Αυτό μπορείτε να το αλλάξετε ανά πάσα στιγμή στις ρυθμίσεις της αίθουσας." - "Οποιοσδήποτε μπορεί να ζητήσει να συμμετάσχει στην αίθουσα, αλλά ένας διαχειριστής ή ένας συντονιστής θα πρέπει να αποδεχτεί το αίτημα" - "Αίτημα συμμετοχής" - "Οποιοσδήποτε μπορεί να συμμετάσχει σε αυτή την αίθουσα" - "Για να είναι ορατή αυτή η αίθουσα στον δημόσιο κατάλογο αιθουσών, θα χρειαστείτε μια διεύθυνση αίθουσας." + "Οποιοσδήποτε μπορεί να συμμετάσχει." + "Δημόσιο" + "Οποιοσδήποτε μπορεί να ζητήσει να συμμετάσχει στην αίθουσα, αλλά ένας διαχειριστής ή ένας συντονιστής θα πρέπει να αποδεχτεί το αίτημα." + "Επιτρέψτε την αίτηση συμμετοχής" + "Οποιοιδήποτε στο %1$s μπορούν να συμμετάσχουν, αλλά όλοι οι υπόλοιποι πρέπει να ζητήσουν πρόσβαση." + "Αίτημα συμμετοχής" + "Μόνο άτομα που έχουν προσκληθεί μπορούν να συμμετάσχουν." + "Ιδιωτικό" + "Οποιοσδήποτε μπορεί να συμμετάσχει." + "Δημόσιο" + "Οποιοσδήποτε στο %1$s μπορεί να συμμετάσχει." + "Πρότυπο" + "Ποιος έχει πρόσβαση" + "Θα χρειαστείτε μια διεύθυνση για να την κάνετε ορατή στον δημόσιο κατάλογο." "Διεύθυνση δωματίου" "Ορατότητα αίθουσας" + "(κανένας χώρος)" + "Μην προσθέτετε σε χώρο" + "Δεν έχει επιλεγεί χώρος" + "Προσθήκη στον χώρο" "Θέμα (προαιρετικό)" + "Προσθήκη περιγραφής…" diff --git a/features/createroom/impl/src/main/res/values-es/translations.xml b/features/createroom/impl/src/main/res/values-es/translations.xml index 4008835685..740e0b70cc 100644 --- a/features/createroom/impl/src/main/res/values-es/translations.xml +++ b/features/createroom/impl/src/main/res/values-es/translations.xml @@ -3,13 +3,14 @@ "Nueva sala" "Invitar personas" "Se ha producido un error al crear la sala" - "Solo las personas invitadas pueden acceder a esta sala. Todos los mensajes están cifrados de extremo a extremo." + "Solo las personas invitadas pueden acceder." "Cualquiera puede encontrar esta sala. Puedes cambiar esto en cualquier momento en los ajustes de la sala." - "Cualquiera puede solicitar unirse a la sala, pero un administrador o un moderador tendrá que aceptar la solicitud" - "Solicitud para unirse" - "Cualquiera puede unirse a esta sala" - "Para que esta sala sea visible en el directorio de salas públicas, necesitarás una dirección de sala." + "Cualquiera puede solicitar unirse, pero un administrador o un moderador tendrá que aceptar la solicitud" + "Permitir solicitar unirse" + "Cualquiera puede unirse." + "Necesitarás una dirección de sala para que sea visible en el directorio de salas públicas." + "Dirección" "Visibilidad de la sala" "Tema (opcional)" diff --git a/features/createroom/impl/src/main/res/values-fi/translations.xml b/features/createroom/impl/src/main/res/values-fi/translations.xml index ea808ce047..c912a7ffe9 100644 --- a/features/createroom/impl/src/main/res/values-fi/translations.xml +++ b/features/createroom/impl/src/main/res/values-fi/translations.xml @@ -3,14 +3,34 @@ "Uusi huone" "Kutsu henkilöitä" "Huoneen luomisessa tapahtui virhe" - "Vain kutsutut henkilöt pääsevät tähän huoneeseen. Kaikki viestit ovat päästä päähän salattuja." + "Tilaa ei voitu luoda tuntemattoman virheen vuoksi. Yritä myöhemmin uudelleen." + "Lisää nimi…" + "Uusi huone" + "Uusi tila" + "Vain kutsutut henkilöt voivat liittyä." + "Yksityinen" "Kuka tahansa voi löytää tämän huoneen. Voit muuttaa tämän milloin tahansa huoneen asetuksista." - "Kuka tahansa voi pyytää saada liittyä huoneeseen, mutta ylläpitäjän tai valvojan on hyväksyttävä pyyntö" - "Pyydä liittymistä" - "Kuka tahansa voi liittyä tähän huoneeseen" - "Jotta tämä huone näkyisi julkisessa huonehakemistossa, tarvitset huoneen osoitteen." - "Huoneen osoite" + "Kuka tahansa voi liittyä." + "Julkinen" + "Kuka tahansa voi pyytää saada liittyä huoneeseen, mutta ylläpitäjän tai valvojan on hyväksyttävä pyyntö." + "Salli liittymispyynnöt" + "Kuka tahansa tilassa %1$s voi liittyä, mutta kaikkien muiden on pyydettävä pääsyä." + "Pyydä liittymistä" + "Vain kutsutut henkilöt voivat liittyä." + "Yksityinen" + "Kuka tahansa voi liittyä." + "Julkinen" + "Kuka tahansa tilassa %1$s voi liittyä." + "Vakio" + "Kenellä on pääsy" + "Jotta tämä näkyisi julkisessa hakemistossa, tarvitset osoitteen." + "Osoite" "Huoneen näkyvyys" + "(ei tilaa)" + "Älä lisää tilaan" + "Ei valittua tilaa" + "Lisää tilaan" "Aihe (valinnainen)" + "Lisää kuvaus…" diff --git a/features/createroom/impl/src/main/res/values-hu/translations.xml b/features/createroom/impl/src/main/res/values-hu/translations.xml index 56809b5a5a..c6d654c8de 100644 --- a/features/createroom/impl/src/main/res/values-hu/translations.xml +++ b/features/createroom/impl/src/main/res/values-hu/translations.xml @@ -8,15 +8,19 @@ "Új szoba" "Új tér" "Csak a meghívottak léphetnek be." + "Privát" "Bárki megtalálhatja ezt a szobát. Ezt bármikor módosíthatja a szobabeállításokban." "Bárki csatlakozhat." + "Nyilvános" "Bárki kérheti, hogy csatlakozhasson a szobához, de egy adminisztrátornak vagy moderátornak el kell fogadnia a kérést." "Csatlakozás kérése" "Bárki csatlakozhat innen: %1$s, de mindenki másnak hozzáférést kell kérnie." "Csatlakozás kérése" "Csak a meghívottak léphetnek be." + "Privát" "Bárki csatlakozhat." + "Nyilvános" "Bárki csatlakozhat innen: %1$s." "Szokásos" "Hozzáférésre jogosultak" @@ -24,7 +28,8 @@ Ezt bármikor módosíthatja a szobabeállításokban." "Cím" "Szoba láthatósága" "(nincs tér)" - "Kezdőlap" + "Ne adja hozzá térhez" + "Nincs kiválasztott tér" "Hozzáadás a térhez" "Téma (nem kötelező)" "Leírás hozzáadása…" diff --git a/features/createroom/impl/src/main/res/values-nb/translations.xml b/features/createroom/impl/src/main/res/values-nb/translations.xml index b6076fb561..6a31334437 100644 --- a/features/createroom/impl/src/main/res/values-nb/translations.xml +++ b/features/createroom/impl/src/main/res/values-nb/translations.xml @@ -3,21 +3,32 @@ "Nytt rom" "Inviter folk" "Det oppsto en feil under opprettelsen av rommet" + "Området kunne ikke opprettes på grunn av en ukjent feil. Prøv på nytt senere." "Legg til navn…" "Nytt rom" "Nytt område" "Bare inviterte personer kan bli med." + "Privat" "Alle kan finne dette rommet. Du kan endre dette når som helst i rominnstillingene." "Alle kan bli med." + "Offentlig" "Alle kan be om å få bli med, men en administrator eller moderator må godta forespørselen." "Be om å bli med" + "Be om å få bli med" "Bare inviterte personer kan bli med." + "Privat" "Alle kan bli med." + "Offentlig" + "Alle i %1$s kan bli med." + "Standard" "Hvem har tilgang" "Du trenger en adresse for å gjøre den synlig i den offentlige katalogen." "Adresse" "Romsynlighet" + "(ingen område)" + "Ingen områder valgt" + "Legg til området" "Emne (valgfritt)" "Legg til beskrivelse…" diff --git a/features/createroom/impl/src/main/res/values-nl/translations.xml b/features/createroom/impl/src/main/res/values-nl/translations.xml index 411e9ea673..681885bbc0 100644 --- a/features/createroom/impl/src/main/res/values-nl/translations.xml +++ b/features/createroom/impl/src/main/res/values-nl/translations.xml @@ -4,10 +4,14 @@ "Mensen uitnodigen" "Er is een fout opgetreden bij het aanmaken van de kamer" "Alleen uitgenodigde personen hebben toegang tot deze kamer. Alle berichten zijn end-to-end versleuteld." + "Privé" "Iedereen kan deze kamer vinden. Je kunt dit op elk gewenst moment wijzigen in de kamerinstellingen." + "Openbaar" "Iedereen kan vragen om toe te treden tot de kamer, maar een beheerder of moderator moet het verzoek accepteren" "Vraag om toe te treden" + "Privé" "Iedereen kan toetreden tot deze kamer" + "Openbaar" "Onderwerp (optioneel)" diff --git a/features/createroom/impl/src/main/res/values-ru/translations.xml b/features/createroom/impl/src/main/res/values-ru/translations.xml index aed5dc3ae3..07ccc80871 100644 --- a/features/createroom/impl/src/main/res/values-ru/translations.xml +++ b/features/createroom/impl/src/main/res/values-ru/translations.xml @@ -13,12 +13,19 @@ "Присоединиться может любой." "Любой желающий может подать заявку на присоединение к комнате, но администратор или модератор должен будет принять запрос." "Разрешить запрос на присоединение" + "Любой из %1$s может присоединиться, а всем остальным нужно запросить доступ." + "Подать заявку на вступление" "Присоединиться могут только приглашенные." "Присоединиться может любой желающий." + "Любой в %1$s может присоединиться." + "Стандарт" "Кто имеет доступ" "Вам понадобится адрес комнаты, чтобы сделать ее видимой в каталоге." "Адрес" "Видимость комнаты" + "(нет пространства)" + "Главная" + "Добавить в пространство" "Тема (необязательно)" "Добавить описание…" diff --git a/features/createroom/impl/src/main/res/values-tr/translations.xml b/features/createroom/impl/src/main/res/values-tr/translations.xml index bc13556576..7ae62ca872 100644 --- a/features/createroom/impl/src/main/res/values-tr/translations.xml +++ b/features/createroom/impl/src/main/res/values-tr/translations.xml @@ -1,7 +1,7 @@ "Yeni oda" - "İnsanları davet et" + "Kişileri davet et" "Oda oluşturulurken bir hata oluştu" "Bu odaya yalnızca davet edilen kişiler erişebilir. Tüm mesajlar uçtan uca şifrelenir." "Bu odayı herkes bulabilir. diff --git a/features/createroom/impl/src/main/res/values-uz/translations.xml b/features/createroom/impl/src/main/res/values-uz/translations.xml index f5d9c96f8e..98e246716d 100644 --- a/features/createroom/impl/src/main/res/values-uz/translations.xml +++ b/features/createroom/impl/src/main/res/values-uz/translations.xml @@ -10,6 +10,7 @@ Buni xona sozlamalaridan istalgan vaqtda oʻzgartirishingiz mumkin." "Qo‘shilishni so‘rang" "Bu xonaga istalgan kishi qo‘shilishi mumkin" "Ushbu xona ommaviy xonalar ro‘yxatida ko‘rinishi uchun sizga xona manzili kerak bo‘ladi." + "Xona manzili" "Xonaning ko‘rinishi" "Mavzu (ixtiyoriy)" diff --git a/features/createroom/impl/src/main/res/values-zh/translations.xml b/features/createroom/impl/src/main/res/values-zh/translations.xml index fe896c8f98..46d9654fbf 100644 --- a/features/createroom/impl/src/main/res/values-zh/translations.xml +++ b/features/createroom/impl/src/main/res/values-zh/translations.xml @@ -3,14 +3,34 @@ "新聊天室" "邀请朋友" "创建聊天室时出错" - "只有受邀用户才能访问此聊天室。所有消息均经过端到端加密。" + "由于未知错误,空间创建失败。请稍后再试。" + "添加名称…" + "新聊天室" + "新空间" + "仅限受邀者加入。" + "私密" "任何人都能找到此聊天室。 你可以随时在聊天室设置中更改。" - "任何人都可以请求加入房间,但必须由管理员或审核人接受" + "任何人都可以找到并加入" + "公共" + "任何人都可申请加入,但需由管理员或版主批准请求。" "请求加入" - "任何人都可以加入此房间" - "要使该房间在公开房间目录中可见,您需要一个房间地址。" - "房间地址" + "%1$s 中的任何人都可加入,但其他人必须申请访问权限。" + "申请加入" + "仅限受邀者加入。" + "私密" + "任何人都可以加入。" + "公共" + "%1$s 中的任何人可加入。" + "标准" + "谁有权访问此房间" + "要使该聊天室在公共目录中可见,您需要一个聊天室地址。" + "地址" "房间可见性" + "(无空间)" + "请勿添加至空间" + "未选择空间" + "添加至空间" "主题(可选)" + "添加描述…" diff --git a/features/home/impl/src/main/res/values-be/translations.xml b/features/home/impl/src/main/res/values-be/translations.xml index d6cd4a1e71..1fed1f21c8 100644 --- a/features/home/impl/src/main/res/values-be/translations.xml +++ b/features/home/impl/src/main/res/values-be/translations.xml @@ -8,6 +8,7 @@ "Каб не прапусціць важны званок, зменіце налады, каб дазволіць поўнаэкранныя апавяшчэнні, калі тэлефон заблакіраваны." "Палепшыце якасць званкоў" "Усе чаты" + "Прасторы" "Вы ўпэўненыя, што хочаце адхіліць запрашэнне ў %1$s?" "Адхіліць запрашэнне" "Вы ўпэўненыя, што хочаце адмовіцца ад прыватных зносін з %1$s?" @@ -38,6 +39,7 @@ "Усе чаты" "Пазначыць як прачытанае" "Пазначыць як непрачытанае" + "Вашы прасторы" "Здаецца, вы карыстаецеся новай прыладай. Праверце з дапамогай іншай прылады, каб атрымаць доступ да зашыфраваных паведамленняў." "Пацвердзіце, што гэта вы" diff --git a/features/home/impl/src/main/res/values-el/translations.xml b/features/home/impl/src/main/res/values-el/translations.xml index df492840b0..5b345f1a9f 100644 --- a/features/home/impl/src/main/res/values-el/translations.xml +++ b/features/home/impl/src/main/res/values-el/translations.xml @@ -3,6 +3,8 @@ "Απενεργοποίησε τη βελτιστοποίηση μπαταρίας για αυτήν την εφαρμογή, για να βεβαιωθείς ότι λαμβάνονται όλες οι ειδοποιήσεις." "Απενεργοποίηση βελτιστοποίησης" "Δεν φτάνουν οι ειδοποιήσεις;" + "Το ping ειδοποιήσεών σας έχει ενημερωθεί—είναι πιο σαφές, πιο γρήγορο και λιγότερο ενοχλητικό." + "Ανανεώσαμε τους ήχους σας" "Δημιούργησε ένα νέο κλειδί ανάκτησης που μπορεί να χρησιμοποιηθεί για την επαναφορά του ιστορικού των κρυπτογραφημένων μηνυμάτων σου σε περίπτωση που χάσεις την πρόσβαση στις συσκευές σου." "Ρύθμιση ανάκτησης" "Ρύθμιση ανάκτησης" @@ -13,6 +15,7 @@ "Για να διασφαλίσετε ότι δεν θα χάσετε ποτέ μια σημαντική κλήση, αλλάξτε τις ρυθμίσεις σας ώστε να επιτρέπονται οι ειδοποιήσεις πλήρους οθόνης όταν το τηλέφωνό σας είναι κλειδωμένο." "Βελτίωσε την εμπειρία κλήσεων" "Συνομιλίες" + "Χώροι" "Σίγουρα θες να απορρίψεις την πρόσκληση συμμετοχής στο %1$s;" "Απόρριψη πρόσκλησης" "Σίγουρα θες να απορρίψεις την ιδιωτική συνομιλία με τον χρήστη %1$s;" @@ -22,6 +25,7 @@ "Αυτή είναι μια εφάπαξ διαδικασία, ευχαριστώ που περίμενες." "Ρύθμιση του λογαριασμού σου." "Δημιουργία νέας συνομιλίας ή αίθουσας" + "Καθαρισμός φίλτρων" "Ξεκίνησε στέλνοντας μηνύματα σε κάποιον." "Δεν υπάρχουν συνομιλίες ακόμα." "Αγαπημένα" @@ -31,6 +35,7 @@ "Προσκλήσεις" "Δεν έχεις εκκρεμείς προσκλήσεις." "Χαμηλής Προτεραιότητας" + "Δεν έχετε ακόμη συνομιλίες χαμηλής προτεραιότητας" "Μπορείς να καταργήσεις την επιλογή φίλτρων για να δεις τις άλλες συνομιλίες σου" "Δεν έχεις συνομιλίες για αυτήν την επιλογή" "Άτομα" @@ -45,6 +50,7 @@ "Επισήμανση ως αναγνωσμένου" "Επισήμανση ως μη αναγνωσμένου" "Αυτή η αίθουσα έχει αναβαθμιστεί" + "Οι χώροι σας" "Φαίνεται ότι χρησιμοποιείς μια νέα συσκευή. Επαλήθευσε με άλλη συσκευή για πρόσβαση στα κρυπτογραφημένα σου μηνύματα." "Επαλήθευσε ότι είσαι εσύ" diff --git a/features/home/impl/src/main/res/values-es/translations.xml b/features/home/impl/src/main/res/values-es/translations.xml index 77e52fc6b6..ed6cfdc990 100644 --- a/features/home/impl/src/main/res/values-es/translations.xml +++ b/features/home/impl/src/main/res/values-es/translations.xml @@ -1,5 +1,8 @@ + "Deshabilita la optimización de la batería en esta aplicación para asegurarte de que recibes notificaciones." + "Deshabilitar la optimización" + "¿No llegan las notificaciones?" "Recupera tu identidad criptográfica y tu historial de mensajes con una clave de recuperación si has perdido todos tus dispositivos actuales." "Configurar la recuperación" "Configura la recuperación para proteger tu cuenta" @@ -19,6 +22,7 @@ "Este proceso solo se hace una vez, gracias por esperar." "Configura tu cuenta" "Crear una nueva conversación o sala" + "Borrar filtros" "Empieza enviando un mensaje a alguien." "Aún no hay chats." "Favoritos" @@ -41,6 +45,7 @@ Por ahora, puedes deseleccionar los filtros para ver tus otros chats" "Chats" "Marcar como leído" "Marcar como no leído" + "Esta sala ha sido renovada" "Parece que estás usando un nuevo dispositivo. Verifica que eres tú para acceder a tus mensajes cifrados." "Verifica que eres tú" diff --git a/features/home/impl/src/main/res/values-fi/translations.xml b/features/home/impl/src/main/res/values-fi/translations.xml index fa7150b546..99f0321f89 100644 --- a/features/home/impl/src/main/res/values-fi/translations.xml +++ b/features/home/impl/src/main/res/values-fi/translations.xml @@ -50,6 +50,7 @@ Sinulla ei ole lukemattomia viestejä!" "Merkitse luetuksi" "Merkitse lukemattomaksi" "Tämä huone on päivitetty" + "Tilasi" "Vaikuttaisi siltä, että käytät uutta laitetta. Vahvista toisella laitteella nähdäksesi salatut viestit." "Vahvista, että se olet sinä" diff --git a/features/home/impl/src/main/res/values-nb/translations.xml b/features/home/impl/src/main/res/values-nb/translations.xml index 42216442cb..574658d10a 100644 --- a/features/home/impl/src/main/res/values-nb/translations.xml +++ b/features/home/impl/src/main/res/values-nb/translations.xml @@ -50,6 +50,7 @@ Du har ingen uleste meldinger!" "Marker som lest" "Merk som ulest" "Dette rommet har blitt oppgradert" + "Dine områder" "Det ser ut til at du bruker en ny enhet. Bekreft med en annen enhet for å få tilgang til de krypterte meldingene dine." "Bekreft at det er deg" diff --git a/features/home/impl/src/main/res/values-ru/translations.xml b/features/home/impl/src/main/res/values-ru/translations.xml index a5007784ee..be892b5e6c 100644 --- a/features/home/impl/src/main/res/values-ru/translations.xml +++ b/features/home/impl/src/main/res/values-ru/translations.xml @@ -50,6 +50,7 @@ "Пометить как прочитанное" "Отметить как непрочитанное" "Эта комната была обновлена" + "Ваши пространства" "Похоже, вы используете новое устройство. Чтобы получить доступ к зашифрованным сообщениям пройдите подтверждение с другим устройством." "Подтвердите, что это вы" diff --git a/features/home/impl/src/main/res/values-tr/translations.xml b/features/home/impl/src/main/res/values-tr/translations.xml index 1dda320ff0..cecd31b06c 100644 --- a/features/home/impl/src/main/res/values-tr/translations.xml +++ b/features/home/impl/src/main/res/values-tr/translations.xml @@ -1,5 +1,6 @@ + "Bildirim sesi güncellendi — daha net, daha hızlı ve daha az dikkat dağıtıcı." "Mevcut tüm cihazlarınızı kaybettiyseniz şifreleme kimliğinizi ve mesaj geçmişinizi bir kurtarma anahtarıyla kurtarın." "Kurtarmayı ayarlayın" "Hesabınızı korumak için kurtarmayı ayarlayın" @@ -10,6 +11,7 @@ "Önemli bir aramayı asla kaçırmamak için, telefonunuz kilitliyken tam ekran bildirimlere izin vermek üzere ayarlarınızı değiştirin." "Arama deneyiminizi geliştirin" "Sohbetler" + "Alanlar" "%1$s katılma davetini reddetmek istediğinizden emin misiniz?" "Daveti reddet" "%1$s ile bu özel sohbeti reddetmek istediğinizden emin misiniz?" @@ -19,6 +21,7 @@ "Bu tek seferlik bir işlemdir, beklediğiniz için teşekkürler." "Hesabınızı ayarlanıyor." "Yeni bir sohbet veya oda oluşturun" + "Filtreleri temizle" "Birine mesaj göndererek başla." "Henüz sohbet yok." "Favoriler" @@ -41,6 +44,7 @@ Okunmamış mesajınız yok!" "Sohbetler" "Okundu olarak işaretle" "Okunmamış olarak işaretle" + "Bu oda yükseltildi" "Görünüşe göre yeni bir cihaz kullanıyorsunuz. Şifrelenmiş mesajlarınıza erişmek için başka bir cihazla doğrulayın." "Siz olduğunuzu doğrulayın" diff --git a/features/home/impl/src/main/res/values-uz/translations.xml b/features/home/impl/src/main/res/values-uz/translations.xml index 2de9b1b266..e5ef24e80a 100644 --- a/features/home/impl/src/main/res/values-uz/translations.xml +++ b/features/home/impl/src/main/res/values-uz/translations.xml @@ -3,6 +3,8 @@ "Ushbu ilova uchun quvvatni optimallashtirishni oʻchirib qoʻying, barcha xabarnomalar qabul qilinganligiga ishonch hosil qilish uchun." "Optimallashtirishni o\'chiring" "Bildirishnoma kelmayaptimi?" + "Xabarnoma signali yangilandi — endi u aniqroq, tezroq va kamroq halal beradigan bo‘ldi." + "Tovushlaringiz yangilandi" "Mavjud barcha qurilmalarni yoʻqotgan boʻlsangiz, kriptografik kimligingizni va xabarlar tarixini qayta tiklovchi kalit bilan saqlab qoʻying." "Qayta tiklashni sozlang" "Hisobingizni himoya qilish uchun tiklashni sozlang" @@ -13,7 +15,7 @@ "Muhim qoʻngʻiroqlarni oʻtkazib yubormasligingiz uchun telefoningiz qulflangan holatida toʻliq ekranli bildirishnomalarni ko‘rsatishga ruxsat beradigan qilib sozlamalaringizni oʻzgartiring." "Qoʻngʻiroq tajribangizni yaxshilang" "Suhbatlar" - "Bo‘shliqlar" + "Maydonlar" "Haqiqatan ham qo\'shilish taklifini rad qilmoqchimisiz%1$s ?" "Taklifni rad etish" "Haqiqatan ham bu shaxsiy chatni rad qilmoqchimisiz%1$s ?" diff --git a/features/home/impl/src/main/res/values-zh/translations.xml b/features/home/impl/src/main/res/values-zh/translations.xml index 748159d80f..1705569a49 100644 --- a/features/home/impl/src/main/res/values-zh/translations.xml +++ b/features/home/impl/src/main/res/values-zh/translations.xml @@ -50,6 +50,7 @@ "标记为已读" "标记为未读" "此房间已升级" + "您的空间" "您似乎正在使用新设备。使用另一台设备进行验证以访问您的加密消息。" "验证是你本人" diff --git a/features/invite/impl/src/main/res/values-tr/translations.xml b/features/invite/impl/src/main/res/values-tr/translations.xml index 26ed1cb6d8..4628296fc2 100644 --- a/features/invite/impl/src/main/res/values-tr/translations.xml +++ b/features/invite/impl/src/main/res/values-tr/translations.xml @@ -1,6 +1,7 @@ "Kullanıcıyı engelle" + "Bildirme nedenini açıklayın…" "%1$s katılma davetini reddetmek istediğinizden emin misiniz?" "Daveti reddet" "%1$s ile bu özel sohbeti reddetmek istediğinizden emin misiniz?" diff --git a/features/joinroom/impl/src/main/res/values-el/translations.xml b/features/joinroom/impl/src/main/res/values-el/translations.xml index b12bbb9374..144e035bbe 100644 --- a/features/joinroom/impl/src/main/res/values-el/translations.xml +++ b/features/joinroom/impl/src/main/res/values-el/translations.xml @@ -1,7 +1,7 @@ - "Αποκλειστήκατε από αυτή την αίθουσα από το χρήστη %1$s." - "Σας απαγορεύτηκε η είσοδος σε αυτή την αίθουσα" + "Αποκλειστήκατε από το χρήστη %1$s." + "Σας επιβλήθηκε ένα ban" "Αιτία: %1$s." "Ακύρωση αιτήματος" "Ναι, ακύρωση" @@ -11,13 +11,15 @@ "Είστε βέβαιοι ότι θέλετε να απορρίψετε την πρόσκληση συμμετοχής σε αυτήν την αίθουσα; Αυτό θα εμποδίσει επίσης τον χρήστη %1$s να επικοινωνήσει μαζί σας ή να σας προσκαλέσει σε αίθουσες." "Απόρριψη πρόσκλησης και αποκλεισμός" "Απόρριψη και αποκλεισμός" - "Η συμμετοχή στην αίθουσα απέτυχε." - "Αυτή η αίθουσα είναι είτε μόνο για προσκεκλημένους είτε ενδέχεται να υπάρχουν περιορισμοί πρόσβασης σε επίπεδο χώρου." - "Ξεχάστε αυτή την αίθουσα" - "Χρειάζεστε πρόσκληση για να συμμετάσχετε σε αυτή την αίθουσα" + "Η συμμετοχή απέτυχε" + "Πρέπει να λάβετε πρόσκληση για να συμμετάσχετε ή ενδέχεται να υπάρχουν περιορισμοί πρόσβασης." + "Κατάργηση" + "Χρειάζεστε πρόσκληση για να συμμετάσχετε" + "Προσκεκλημένο από" "Συμμετοχή" "Ενδέχεται να χρειαστεί να προσκληθείτε ή να είστε μέλος ενός χώρου για να συμμετάσχετε." "Χτύπα για συμμετοχή" + "Επιτρεπόμενοι χαρακτήρες %1$d από %2$d" "Μήνυμα (προαιρετικό)" "Θα λάβετε πρόσκληση για να συμμετάσχετε στην αίθουσα, εάν το αίτημά σας γίνει αποδεκτό." "Το αίτημα συμμετοχής στάλθηκε" diff --git a/features/joinroom/impl/src/main/res/values-es/translations.xml b/features/joinroom/impl/src/main/res/values-es/translations.xml index 1f905bbbf7..698a6eb1c9 100644 --- a/features/joinroom/impl/src/main/res/values-es/translations.xml +++ b/features/joinroom/impl/src/main/res/values-es/translations.xml @@ -1,7 +1,7 @@ - "Has sido vetado de esta sala por %1$s." - "Has sido vetado de esta sala" + "Has sido baneado por %1$s." + "Has sido baneado." "Motivo: %1$s." "Cancelar solicitud" "Sí, cancelar" @@ -11,10 +11,10 @@ "¿Estás seguro de que deseas rechazar la invitación para unirte a esta sala? Esto también impedirá que %1$s pueda contactar contigo o invitarte a salas." "Rechazar invitación y bloquear" "Rechazar y bloquear" - "No se pudo unir a la sala." - "O bien solo se puede acceder a esta sala con invitación, o puede que haya restricciones de acceso a nivel de espacio." - "Olvidar esta sala" - "Necesitas una invitación para unirte a esta sala" + "Error al unirse" + "O es necesario estar invitado para unirse o puede haber restricciones de acceso." + "Olvidar" + "Necesitas una invitación para unirte" "Unirse" "Es posible que necesites ser invitado o ser miembro de un espacio para poder unirte." "Enviar solicitud de unión" diff --git a/features/joinroom/impl/src/main/res/values-sv/translations.xml b/features/joinroom/impl/src/main/res/values-sv/translations.xml index 11af0da734..99e267f6e0 100644 --- a/features/joinroom/impl/src/main/res/values-sv/translations.xml +++ b/features/joinroom/impl/src/main/res/values-sv/translations.xml @@ -1,6 +1,6 @@ - "Du bannades från det här rummet av %1$s." + "Du bannades av %1$s." "Du bannades från det här rummet" "Anledning: %1$s." "Avbryt begäran" @@ -11,10 +11,10 @@ "Är du säker på att du vill avvisa inbjudan att gå med i det här rummet? Detta kommer också att hindra %1$s från att kontakta dig eller bjuda in dig till rum." "Avvisa inbjudan och blockera" "Avvisa och blockera" - "Misslyckades att gå med i rummet." + "Misslyckades att gå med." "Detta rum är antingen endast för inbjudna eller så kan det finnas begränsningar för åtkomst på utrymmesnivå." - "Glöm det här rummet" - "Du behöver en inbjudan för att gå med i detta rum" + "Glöm" + "Du behöver en inbjudan för att gå med" "Gå med" "Du kan behöva bli inbjuden eller vara medlem i ett utrymme för att gå med." "Knacka för att gå med" diff --git a/features/joinroom/impl/src/main/res/values-uz/translations.xml b/features/joinroom/impl/src/main/res/values-uz/translations.xml index de8b10f2b1..4562a169f1 100644 --- a/features/joinroom/impl/src/main/res/values-uz/translations.xml +++ b/features/joinroom/impl/src/main/res/values-uz/translations.xml @@ -15,6 +15,7 @@ "Bu xona faqat taklif etilganlar uchun yoki bu maydonga kirish huquqi cheklangan bo‘lishi mumkin." "Bu xonani esdan chiqarish" "Bu xonaga kirish uchun taklifnoma kerak" + "Tomonidan taklif qilingan" "Qo\'shilish" "Qo‘shilish uchun sizga taklif kerak yoki siz maydonga a’zo bo‘lishingiz kerak." "Qoʻshilish soʻrovini yuborish" diff --git a/features/knockrequests/impl/src/main/res/values-el/translations.xml b/features/knockrequests/impl/src/main/res/values-el/translations.xml index 5c8bec16f8..2066b2e293 100644 --- a/features/knockrequests/impl/src/main/res/values-el/translations.xml +++ b/features/knockrequests/impl/src/main/res/values-el/translations.xml @@ -32,4 +32,5 @@ "Προβολή όλων" "Αποδοχή" "%1$s θέλει να συμμετάσχει σε αυτή την αίθουσα" + "Προβολή" diff --git a/features/knockrequests/impl/src/main/res/values-es/translations.xml b/features/knockrequests/impl/src/main/res/values-es/translations.xml index 8f9ab72b70..ea9f74544d 100644 --- a/features/knockrequests/impl/src/main/res/values-es/translations.xml +++ b/features/knockrequests/impl/src/main/res/values-es/translations.xml @@ -32,4 +32,5 @@ "Ver todo" "Aceptar" "%1$s quiere unirse a esta sala" + "Ver" diff --git a/features/leaveroom/api/src/main/res/values-el/translations.xml b/features/leaveroom/api/src/main/res/values-el/translations.xml index b6ea1a6caf..330fe188bd 100644 --- a/features/leaveroom/api/src/main/res/values-el/translations.xml +++ b/features/leaveroom/api/src/main/res/values-el/translations.xml @@ -3,5 +3,8 @@ "Είσαι σίγουρος ότι θέλεις να αποχωρήσεις από αυτή τη συζήτηση; Αυτή η συνομιλία δεν είναι δημόσια και δεν θα μπορείς να συμμετάσχεις ξανά χωρίς πρόσκληση." "Είστε σίγουροι ότι θέλετε να αποχωρήσετε από αυτή την αίθουσα; Είστε το μόνο άτομο εδώ. Αν αποχωρήσετε, κανείς δεν θα μπορεί να ενταχθεί στο μέλλον, ούτε εσείς." "Είστε σίγουροι ότι θέλετε να αποχωρήσετε από αυτήν την αίθουσα; Αυτή η αίθουσα δεν είναι δημόσια και δεν θα μπορέσετε να επανενταχτείτε χωρίς πρόσκληση." + "Επιλέξτε ιδιοκτήτες" + "Είστε ο μόνος ιδιοκτήτης αυτής της αίθουσας. Πρέπει να μεταβιβάσετε την ιδιοκτησία σε κάποιον άλλο πριν φύγετε από την αίθουσα." + "Μεταβίβαση ιδιοκτησίας" "Είστε σίγουροι ότι θέλετε να αποχωρήσετε από την αίθουσα;" diff --git a/features/leaveroom/api/src/main/res/values-fr/translations.xml b/features/leaveroom/api/src/main/res/values-fr/translations.xml index 5f75b7ae55..fe0a5d4d0b 100644 --- a/features/leaveroom/api/src/main/res/values-fr/translations.xml +++ b/features/leaveroom/api/src/main/res/values-fr/translations.xml @@ -3,7 +3,7 @@ "Êtes-vous sûr de vouloir quitter cette discussion ? Vous ne pourrez pas la rejoindre à nouveau sans y être invité." "Êtes-vous sûr de vouloir quitter ce salon ? Vous êtes la seule personne ici. Si vous partez, personne ne pourra rejoindre le salon à l’avenir, y compris vous." "Êtes-vous sûr de vouloir quitter ce salon ? Ce salon n’est pas public et vous ne pourrez pas le rejoindre sans invitation." - "Choisissez les propriétaires" + "Choisir les propriétaires" "Vous êtes le seul propriétaire de ce salon. Vous devez en transférer la propriété à quelqu’un d’autre avant de le quitter." "Transférer la propriété" "Êtes-vous sûr de vouloir quitter le salon ?" diff --git a/features/leaveroom/api/src/main/res/values-tr/translations.xml b/features/leaveroom/api/src/main/res/values-tr/translations.xml index 39ba596628..d97a1bf75d 100644 --- a/features/leaveroom/api/src/main/res/values-tr/translations.xml +++ b/features/leaveroom/api/src/main/res/values-tr/translations.xml @@ -3,5 +3,8 @@ "Bu sohbetten ayrılmak istediğinizden emin misiniz? Bu sohbet herkese açık değil ve davet olmadan tekrar katılamayacaksınız." "Bu odadan ayrılmak istediğinizden emin misiniz? Burada tek kişi sizsiniz. Ayrılırsanız, siz de dahil olmak üzere gelecekte kimse katılamayacak." "Bu odadan ayrılmak istediğinizden emin misiniz? Bu oda herkese açık değildir ve davet olmadan tekrar katılamazsınız." + "Sahipleri seçin" + "Bu odanın tek sahibisiniz. Odadan çıkmadan önce sahipliği başka birine devretmelisiniz." + "Sahipliği aktar" "Odadan çıkmak istediğinden emin misin?" diff --git a/features/linknewdevice/impl/src/main/res/values-el/translations.xml b/features/linknewdevice/impl/src/main/res/values-el/translations.xml index 2133bb352c..26c917075b 100644 --- a/features/linknewdevice/impl/src/main/res/values-el/translations.xml +++ b/features/linknewdevice/impl/src/main/res/values-el/translations.xml @@ -1,16 +1,33 @@ "Σάρωση κωδικού QR" + "Ανοίξτε το %1$s σε φορητό ή επιτραπέζιο υπολογιστή" "Σάρωσε τον κωδικό QR με αυτήν τη συσκευή" "Έτοιμο για σάρωση" + "Ανοίξτε το %1$s σε έναν επιτραπέζιο υπολογιστή για να λάβετε τον κωδικό QR" + "Οι αριθμοί δεν ταιριάζουν" + "Εισαγάγετε έναν 2ψήφιο κωδικό" + "Αυτό θα επαληθεύσει ότι η σύνδεση με την άλλη συσκευή σας είναι ασφαλής." + "Εισαγάγετε τον αριθμό που εμφανίζεται στην άλλη συσκευή σας" "Ο πάροχος λογαριασμού σου δεν υποστηρίζει το %1$s." "Το %1$s δεν υποστηρίζεται" + "Ο πάροχος του λογαριασμού σας δεν υποστηρίζει τη σύνδεση σε νέα συσκευή με κωδικό QR." "Ο κωδικός QR δεν υποστηρίζεται" "Η σύνδεση ακυρώθηκε στην άλλη συσκευή." "Το αίτημα σύνδεσης ακυρώθηκε" "Η είσοδος έληξε. Παρακαλώ προσπάθησε ξανά." "Η σύνδεση δεν ολοκληρώθηκε εγκαίρως" + "Ανοίξτε το %1$s στην άλλη συσκευή" "Επιλογή %1$s" + "«Συνδεθείτε με κωδικό QR»" + "Σαρώστε τον QR κωδικό που εμφανίζεται εδώ με την άλλη συσκευή." + "Ανοίξτε το %1$s στην άλλη συσκευή" + "Υπολογιστής" + "Φόρτωση QR κωδικού…" + "Κινητή συσκευή" + "Τι είδους συσκευή θέλετε να συνδέσετε;" + "Δοκιμάστε ξανά και βεβαιωθείτε ότι έχετε εισαγάγει σωστά τον 2ψήφιο κωδικό. Εάν οι αριθμοί εξακολουθούν να μην ταιριάζουν, επικοινωνήστε με τον πάροχο του λογαριασμού σας." + "Οι αριθμοί δεν ταιριάζουν" "Δεν ήταν δυνατή η πραγματοποίηση ασφαλούς σύνδεσης στη νέα συσκευή. Οι υπάρχουσες συσκευές σας εξακολουθούν να είναι ασφαλείς και δεν χρειάζεται να ανησυχείς για αυτές." "Τί είναι πάλι;" "Δοκίμασε να συνδεθείς ξανά με έναν κωδικό QR σε περίπτωση που ήταν πρόβλημα του δικτύου" @@ -21,6 +38,8 @@ "Το αίτημα σύνδεσης ακυρώθηκε" "Η σύνδεση απορρίφθηκε στην άλλη συσκευή." "Η σύνδεση απορρίφθηκε" + "Δεν χρειάζεται να κάνετε τίποτα άλλο." + "Η άλλη συσκευή σας είναι ήδη συνδεδεμένη" "Η είσοδος έληξε. Παρακαλώ προσπάθησε ξανά." "Η σύνδεση δεν ολοκληρώθηκε εγκαίρως" "Η άλλη σου συσκευή δεν υποστηρίζει σύνδεση στο %s με κωδικό QR. diff --git a/features/linknewdevice/impl/src/main/res/values-fi/translations.xml b/features/linknewdevice/impl/src/main/res/values-fi/translations.xml index 3ed954a842..d7fb07623e 100644 --- a/features/linknewdevice/impl/src/main/res/values-fi/translations.xml +++ b/features/linknewdevice/impl/src/main/res/values-fi/translations.xml @@ -1,16 +1,33 @@ "Skannaa QR-koodi" + "Avaa %1$s läppärillä tai pöytätietokoneella" "Skannaa QR-koodi tällä laitteella" "Valmis skannaamaan" + "Avaa %1$s pöytätietokoneella saadaksesi QR-koodin" + "Numerot eivät täsmää" + "Syötä 2-numeroinen koodi" + "Tämä varmistaa, että yhteys toiseen laitteeseesi on turvallinen." + "Kirjoita toisessa laitteessa näkyvä numero" "Palveluntarjoajasi ei tue %1$s -sovellusta" "%1$s -sovellusta ei tueta" + "Palveluntarjoajasi ei tue kirjautumista uuteen laitteeseen QR-koodilla." "QR-koodia ei tueta" "Kirjautuminen peruutettiin toisella laitteella." "Kirjautumispyyntö peruutettu" "Kirjautuminen vanhentui. Yritä uudelleen." "Kirjautumista ei suoritettu ajoissa" + "Avaa %1$s toisella laitteella" "Valitse %1$s" + "\"Kirjaudu sisään QR-koodilla\"" + "Skannaa tässä näkyvä QR-koodi toisella laitteella" + "Avaa %1$s toisella laitteella" + "Pöytätietokone" + "Ladataan QR-koodia…" + "Mobiililaite" + "Minkä tyyppisen laitteen haluat yhdistää?" + "Yritä uudelleen ja varmista, että olet syöttänyt 2-numeroisen koodin oikein. Jos numerot eivät vieläkään täsmää, ota yhteyttä palveluntarjoajaasi." + "Numerot eivät täsmää" "Turvallista yhteyttä uuteen laitteeseen ei voitu muodostaa. Olemassa olevat laitteesi ovat edelleen turvassa, eikä sinun tarvitse huolehtia niistä." "Mitä nyt?" "Yritä kirjautua sisään uudelleen QR-koodilla, jos kyseessä oli verkko-ongelma" @@ -21,6 +38,8 @@ "Kirjautumispyyntö peruutettu" "Kirjautuminen hylättiin toisella laitteella." "Kirjautuminen hylätty" + "Sinun ei tarvitse tehdä mitään muuta." + "Toinen laitteesi on jo kirjautunut sisään" "Kirjautuminen vanhentui. Yritä uudelleen." "Kirjautumista ei suoritettu ajoissa" "Toinen laitteesi ei tue kirjautumista %s -sovellukseen QR-koodilla. diff --git a/features/linknewdevice/impl/src/main/res/values-tr/translations.xml b/features/linknewdevice/impl/src/main/res/values-tr/translations.xml index 2d3bebcad8..d5677fbcdd 100644 --- a/features/linknewdevice/impl/src/main/res/values-tr/translations.xml +++ b/features/linknewdevice/impl/src/main/res/values-tr/translations.xml @@ -1,16 +1,32 @@ "QR kodunu tara" + "%1$s uygulamasını bir dizüstü veya masaüstü bilgisayarda açın" "QR kodunu bu cihazla tarayın" "Taramaya hazır" + "QR kodu almak için %1$s uygulamasını masaüstü bilgisayarda açın%1$s%1$s" + "Sayılar uyuşmuyor" + "2 haneli kodu girin" + "Bu işlem, diğer cihazla olan bağlantının güvenli olduğunu doğrular." + "Diğer cihazda gösterilen numarayı girin" "Hesap sağlayıcınız %1$s desteklemiyor." "%1$s desteklenmiyor" + "Hesap sağlayıcınız QR kod ile yeni bir cihaza giriş yapılmasını desteklemiyor." "QR kodu desteklenmiyor" "Oturum açma işlemi diğer cihazda iptal edildi." "Oturum açma isteği iptal edildi" "Oturum açma süresi doldu. Lütfen tekrar deneyin." "Oturum açma işlemi zamanında tamamlanmadı" + "Diğer cihazda %1$s uygulamasını açın" "Seç %1$s" + "QR kod ile giriş yap" + "Burada gösterilen QR kodu diğer cihazla tarayın" + "Diğer cihazda %1$s uygulamasını açın" + "Masaüstü bilgisayar" + "QR kod yükleniyor…" + "Hangi tür cihazı bağlamak istiyorsunuz?" + "Lütfen tekrar deneyin ve 2 haneli kodu doğru girdiğinizden emin olun. Numaralar hâlâ eşleşmiyorsa hesap sağlayıcınızla iletişime geçin." + "Sayılar uyuşmuyor" "Yeni cihaza güvenli bir bağlantı kurulamadı. Mevcut cihazlarınız hala güvende ve onlar için endişelenmenize gerek yok." "Şimdi ne olacak?" "Bunun bir ağ sorunu olması ihtimaline karşı bir QR koduyla tekrar oturum açmayı deneyin" diff --git a/features/linknewdevice/impl/src/main/res/values-uz/translations.xml b/features/linknewdevice/impl/src/main/res/values-uz/translations.xml index d2f3b7a865..b1f3deebf4 100644 --- a/features/linknewdevice/impl/src/main/res/values-uz/translations.xml +++ b/features/linknewdevice/impl/src/main/res/values-uz/translations.xml @@ -1,16 +1,32 @@ "QR kodni skanerlash" + "%1$s ilovasini noutbuk yoki desktopda ochish" "Bu qurilma bilan QR kodni skanerlang" "Skanerlashga tayyor" + "QR kodni olish uchun desktop kompyuterda %1$s ilovasini oching" + "Raqamlar mos kelmaydi" + "2 xonali kodni kiriting" + "Bu boshqa qurilmangizga ulanish xavfsiz ekanligini tasdiqlaydi." + "Boshqa qurilmangizda ko‘rsatilgan raqamni kiriting" "Hisob provayderingiz %1$s bilan ishlamaydi." "%1$s qoʻllab-quvvatlanmaydi" + "Hisob provayderingiz QR kodi bilan yangi qurilmaga kirishni qo‘llab-quvvatlamaydi." "QR kod qoʻllab-quvvatlanmaydi" "Boshqa qurilmadan hisobga kirish bekor qilindi." "Tizimga kirish soʻrovi bekor qilindi" "Kirish muddati tugagan. Iltimos, qayta urinib koʻring." "Kirish oʻz vaqtida tugallanmagan" + "Boshqa qurilmada %1$s ni ochish" "%1$sʼni tanlang" + "\"QR kod bilan kirish\"" + "Bu yerda ko‘rsatilgan QR kodni boshqa qurilma bilan skanerlang" + "Boshqa qurilmada %1$s ni ochish" + "Ish stoli kompyuter" + "QR kod yuklanmoqda…" + "Mobil qurilma" + "Qaysi turdagi qurilmani bog‘lashni xohlaysiz?" + "Raqamlar mos kelmaydi" "Yangi qurilmaga xavfsiz ulanish amalga oshirilmadi. Mavjud qurilmalaringiz hali ham xavfsiz va ular haqida qaygʻurishingiz shart emas." "Endi nima?" "Agar bu tarmoq muammosi boʻlsa, QR kod bilan qayta kiring" diff --git a/features/linknewdevice/impl/src/main/res/values-zh/translations.xml b/features/linknewdevice/impl/src/main/res/values-zh/translations.xml index 99359cc695..843395fab7 100644 --- a/features/linknewdevice/impl/src/main/res/values-zh/translations.xml +++ b/features/linknewdevice/impl/src/main/res/values-zh/translations.xml @@ -1,16 +1,33 @@ "扫描二维码" + "在笔记本电脑或台式机上打开%1$s " "使用此设备扫描二维码" "准备进行扫描" + "在电脑上打开%1$s 获取二维码" + "数字不匹配" + "输入两位数的验证码" + "这将验证您与其他设备的连接是否安全。" + "请输入另一台设备上显示的数字" "账户提供方不支持 %1$s." "不支持 %1$s." + "您的账户提供商不支持使用二维码登录新设备。" "不支持二维码" "登录被另一台设备取消" "登录请求已取消" "登录已过期. 请重试." "登录未及时完成" + "在另一台设备上打开 %1$s" "选择 %1$s" + "“使用二维码登录”" + "请用另一台设备扫描此处显示的二维码" + "在另一台设备上打开 %1$s" + "台式计算机" + "正在加载 QR 码…" + "移动设备" + "您想连接哪种类型的设备?" + "请重试,并确保您已正确输入两位验证码。如果验证码仍然不匹配,请联系您的账户提供商。" + "数字不匹配" "无法与新设备建立安全连接。您现有的设备仍然安全,无需担心。" "现在怎么办?" "如果这是网络问题,请尝试使用二维码再次登录" @@ -21,6 +38,8 @@ "登录请求已取消" "其它设备未接受请求" "登录被拒绝" + "您无需额外操作。" + "您已在另一台设备登录。" "登录已过期. 请重试." "登录未及时完成" "另一个设备不支持使用二维码登录 %s. diff --git a/features/lockscreen/impl/src/main/res/values-tr/translations.xml b/features/lockscreen/impl/src/main/res/values-tr/translations.xml index 5a9b94af11..862fa05608 100644 --- a/features/lockscreen/impl/src/main/res/values-tr/translations.xml +++ b/features/lockscreen/impl/src/main/res/values-tr/translations.xml @@ -15,9 +15,9 @@ "%1$s kullanarak oturum açarken kendinize zaman kazandırın" "PIN Seç" "PIN\'i onayla" - "Sohbetlerinize ekstra güvenlik eklemek için %1$s kilitleyin. + "Sohbetlerinizi daha güvenli hale getirmek için %1$s uygulamasına bir kilit ekleyin. -Hatırlanabilir bir şey seçin. Bu PIN\'i unutursanız, uygulamadan çıkış yaparsınız." +Uygulamayı her açtığınızda bu PIN’i girmeniz gerekecek. Bu PIN’i unutursanız, uygulamadan çıkış yapmanız gerekir." "Güvenlik nedeniyle bunu PIN kodunuz olarak seçemezsiniz" "Farklı bir PIN seçin" "Lütfen aynı PIN\'i iki kez girin" diff --git a/features/login/impl/src/main/res/values-el/translations.xml b/features/login/impl/src/main/res/values-el/translations.xml index 047cd3baa0..5f21a53c37 100644 --- a/features/login/impl/src/main/res/values-el/translations.xml +++ b/features/login/impl/src/main/res/values-el/translations.xml @@ -13,6 +13,9 @@ "Άλλο" "Χρησιμοποίησε διαφορετικό πάροχο λογαριασμού, όπως τον δικό σου ιδιωτικό διακομιστή ή έναν εργασιακό λογαριασμό." "Αλλαγή παρόχου λογαριασμού" + "Google Play" + "Η εφαρμογή Element Pro απαιτείται στο %1$s. Παρακαλώ κατεβάστε την από το κατάστημα." + "Απαιτείται το Element Pro" "Δεν μπορούσαμε να επικοινωνήσουμε με αυτόν τον οικιακό διακομιστή. Βεβαιώσου ότι έχεις εισαγάγει σωστά τη διεύθυνση URL του αρχικού διακομιστή. Εάν η διεύθυνση URL είναι σωστή, επικοινώνησε με τον διαχειριστή του κεντρικού διακομιστή για περαιτέρω βοήθεια." "Ο διακομιστής δεν είναι διαθέσιμος λόγω προβλήματος στο αρχείο .well-known: %1$s" @@ -34,6 +37,7 @@ "Το Matrix είναι ένα ανοιχτό δίκτυο για ασφαλή, αποκεντρωμένη επικοινωνία." "Καλωσόρισες ξανά!" "Συνδέσου στο %1$s" + "Έκδοση %1$s" "Σύνδεση χειροκίνητα" "Συνδέσου στο %1$s" "Συνδέσου με κωδικό QR" @@ -56,6 +60,8 @@ "Το αίτημα σύνδεσης ακυρώθηκε" "Η σύνδεση απορρίφθηκε στην άλλη συσκευή." "Η σύνδεση απορρίφθηκε" + "Δεν χρειάζεται να κάνετε τίποτα άλλο." + "Η άλλη συσκευή σας είναι ήδη συνδεδεμένη" "Η είσοδος έληξε. Παρακαλώ προσπάθησε ξανά." "Η σύνδεση δεν ολοκληρώθηκε εγκαίρως" "Η άλλη σου συσκευή δεν υποστηρίζει σύνδεση στο %s με κωδικό QR. diff --git a/features/login/impl/src/main/res/values-es/translations.xml b/features/login/impl/src/main/res/values-es/translations.xml index d4841e2171..df6a06ab29 100644 --- a/features/login/impl/src/main/res/values-es/translations.xml +++ b/features/login/impl/src/main/res/values-es/translations.xml @@ -34,6 +34,7 @@ "Matrix es una red abierta para una comunicación segura y descentralizada." "¡Hola de nuevo!" "Iniciar sesión en %1$s" + "Versión %1$s" "Iniciar sesión manualmente" "Iniciar sesión en %1$s" "Iniciar sesión con un código QR" diff --git a/features/login/impl/src/main/res/values-fi/translations.xml b/features/login/impl/src/main/res/values-fi/translations.xml index e16f66b87e..993be573dc 100644 --- a/features/login/impl/src/main/res/values-fi/translations.xml +++ b/features/login/impl/src/main/res/values-fi/translations.xml @@ -60,6 +60,8 @@ "Kirjautumispyyntö peruutettu" "Kirjautuminen hylättiin toisella laitteella." "Kirjautuminen hylätty" + "Sinun ei tarvitse tehdä mitään muuta." + "Toinen laitteesi on jo kirjautunut sisään" "Kirjautuminen vanhentui. Yritä uudelleen." "Kirjautumista ei suoritettu ajoissa" "Toinen laitteesi ei tue kirjautumista %s -sovellukseen QR-koodilla. diff --git a/features/login/impl/src/main/res/values-tr/translations.xml b/features/login/impl/src/main/res/values-tr/translations.xml index 6d2bbeef13..1574fca3a8 100644 --- a/features/login/impl/src/main/res/values-tr/translations.xml +++ b/features/login/impl/src/main/res/values-tr/translations.xml @@ -16,6 +16,10 @@ "Bu ana sunucuya ulaşamadık. Lütfen ana sunucu URL\'sini doğru girip girmediğinizi kontrol edin. URL doğruysa, daha fazla yardım için ana sunucu yöneticinize başvurun." "Well-known dosyasında bir sorun nedeniyle sunucu kullanılamıyor: %1$s" + "Seçilen hesap sağlayıcısı sliding sync özelliğini desteklemiyor. %1$s kullanmak için sunucunun yükseltilmesi gerekiyor." + "%1$s, %2$s ile bağlantı kurma yetkisine sahip değil." + "Bu uygulama şu sağlayıcılara izin verecek şekilde yapılandırıldı: %1$s." + "Hesap sağlayıcısı %1$s İzin verilmiyor." "Ana sunucu URL\'si" "Sunucunuzun adresi nedir?" "Sunucunuzu seçin" diff --git a/features/login/impl/src/main/res/values-zh/translations.xml b/features/login/impl/src/main/res/values-zh/translations.xml index de7ea8bc0a..fd8105b71e 100644 --- a/features/login/impl/src/main/res/values-zh/translations.xml +++ b/features/login/impl/src/main/res/values-zh/translations.xml @@ -60,6 +60,8 @@ "登录请求已取消" "其它设备未接受请求" "登录被拒绝" + "您无需额外操作。" + "您已在另一台设备登录。" "登录已过期. 请重试." "登录未及时完成" "另一个设备不支持使用二维码登录 %s. diff --git a/features/messages/impl/src/main/res/values-el/translations.xml b/features/messages/impl/src/main/res/values-el/translations.xml index 7402055f15..f21f34ab63 100644 --- a/features/messages/impl/src/main/res/values-el/translations.xml +++ b/features/messages/impl/src/main/res/values-el/translations.xml @@ -14,10 +14,18 @@ "Αντικείμενα" "Φατσούλες & Άνθρωποι" "Ταξίδια & Μέρη" + "Πρόσφατα emoji" "Σύμβολα" "Οι λεζάντες ενδέχεται να μην είναι ορατές σε άτομα που χρησιμοποιούν παλαιότερες εφαρμογές." + "Πατήστε για να αλλάξετε την ποιότητα μεταφόρτωσης βίντεο" + "Δεν ήταν δυνατή η μεταφόρτωση του αρχείου." "Αποτυχία μεταφόρτωσης μέσου, δοκίμασε ξανά." "Αποτυχία μεταφόρτωσης πολυμέσων, δοκίμασε ξανά." + "Το μέγιστο επιτρεπόμενο μέγεθος αρχείου είναι %1$s." + "Το αρχείο είναι πολύ μεγάλο για μεταφόρτωση" + "Στοιχείο %1$d από %2$d" + "Βελτιστοποίηση ποιότητας εικόνας" + "Επεξεργασία…" "Αποκλεισμός χρήστη" "Επέλεξε εάν θες να αποκρύψεις όλα τα τρέχοντα και μελλοντικά μηνύματα από αυτόν τον χρήστη" "Αυτό το μήνυμα θα αναφερθεί στον διαχειριστή του οικιακού διακομιστή σας. Δεν θα μπορεί να διαβάσει κρυπτογραφημένα μηνύματα." diff --git a/features/messages/impl/src/main/res/values-es/translations.xml b/features/messages/impl/src/main/res/values-es/translations.xml index d39cdcd5da..81ca655676 100644 --- a/features/messages/impl/src/main/res/values-es/translations.xml +++ b/features/messages/impl/src/main/res/values-es/translations.xml @@ -1,5 +1,6 @@ + "El remitente del evento no coincide con el propietario del dispositivo que lo envió." "La autenticidad de este mensaje cifrado no puede ser garantizada en este dispositivo." "Cifrado por un usuario verificado anteriormente." "No cifrado." @@ -46,11 +47,16 @@ "No tienes permiso para publicar en esta sala" "Mostrar menos" "Mostrar más" + "Mostrar todas las reacciones" "Nuevos" "%1$d cambio en la sala" "%1$d cambios en la sala" + "Ir a la nueva sala" + "Esta sala ha sido reemplazada y ya no está activa." + "Ver mensajes antiguos" + "Esta sala es la sucesora de otra sala." "%1$s, %2$s y %3$d otro" "%1$s, %2$s y %3$d otros" diff --git a/features/messages/impl/src/main/res/values-nb/translations.xml b/features/messages/impl/src/main/res/values-nb/translations.xml index a21c2875c5..f68333264a 100644 --- a/features/messages/impl/src/main/res/values-nb/translations.xml +++ b/features/messages/impl/src/main/res/values-nb/translations.xml @@ -35,7 +35,7 @@ "Ta opp video" "Vedlegg" "Foto- og videobibliotek" - "Lokasjon" + "Posisjon" "Avstemning" "Tekstformatering" "Meldingshistorikken er for øyeblikket ikke tilgjengelig." diff --git a/features/messages/impl/src/main/res/values-tr/translations.xml b/features/messages/impl/src/main/res/values-tr/translations.xml index f630a5fdec..a40687444b 100644 --- a/features/messages/impl/src/main/res/values-tr/translations.xml +++ b/features/messages/impl/src/main/res/values-tr/translations.xml @@ -1,5 +1,6 @@ + "Etkinliği gönderen kişi, onu gönderen cihazın sahibiyle eşleşmiyor." "Bu şifrelenmiş mesajın doğruluğu bu cihazda garanti edilemez." "Daha önce doğrulanmış bir kullanıcı tarafından şifrelenmiştir." "Şifrelenmemiş." @@ -46,11 +47,15 @@ "Bu odada gönderi yapma izniniz yok" "Daha az göster" "Daha fazla göster" + "Tepki özetini göster" "Yeni" "%1$d oda değişikliği" "%1$d oda değişikliği" + "Yeni odaya git" + "Bu odanın yerini başka bir oda aldı ve artık aktif değil" + "Bu oda, başka bir odanın devamıdır" "%1$s, %2$s ve %3$d diğer" "%1$s, %2$s ve %3$d diğer" diff --git a/features/messages/impl/src/main/res/values-uz/translations.xml b/features/messages/impl/src/main/res/values-uz/translations.xml index 4e5d83a649..9c0246ee60 100644 --- a/features/messages/impl/src/main/res/values-uz/translations.xml +++ b/features/messages/impl/src/main/res/values-uz/translations.xml @@ -14,6 +14,7 @@ "Ob\'ektlar" "Smayllar va odamlar" "Sayohat va Joylar" + "Oxirgi kulgichlar" "Belgilar" "Taglavhalar eski ilovalardan foydalanuvchilarga ko‘rinmasligi mumkin." "Video yuklash sifatini oʻzgartirish uchun bosing" @@ -22,6 +23,7 @@ "Media yuklanmadi, qayta urinib ko‘ring." "Ruxsat etilgan maksimal fayl hajmi %1$s ." "Fayl yuklash uchun juda katta" + "Element%1$d ning %2$d" "Tasvir sifatini optimallashtirish" "Qayta ishlanmoqda…" "Foydalanuvchini bloklash" diff --git a/features/poll/api/src/main/res/values-el/translations.xml b/features/poll/api/src/main/res/values-el/translations.xml index fcd34977d3..ebf3a0a8f7 100644 --- a/features/poll/api/src/main/res/values-el/translations.xml +++ b/features/poll/api/src/main/res/values-el/translations.xml @@ -4,5 +4,6 @@ "%1$d τοις εκατό των συνολικών ψήφων" "%1$d τοις εκατό του συνόλου των ψήφων" + "Θα καταργήσει την προηγούμενη επιλογή" "Αυτή είναι η νικητήρια απάντηση" diff --git a/features/poll/api/src/main/res/values-es/translations.xml b/features/poll/api/src/main/res/values-es/translations.xml new file mode 100644 index 0000000000..10e1193163 --- /dev/null +++ b/features/poll/api/src/main/res/values-es/translations.xml @@ -0,0 +1,4 @@ + + + "Esta es la respuesta ganadora" + diff --git a/features/poll/api/src/main/res/values-tr/translations.xml b/features/poll/api/src/main/res/values-tr/translations.xml new file mode 100644 index 0000000000..8007526f52 --- /dev/null +++ b/features/poll/api/src/main/res/values-tr/translations.xml @@ -0,0 +1,5 @@ + + + "Önceki seçim kaldırılacak" + "Kazanan cevap" + diff --git a/features/poll/impl/src/main/res/values-es/translations.xml b/features/poll/impl/src/main/res/values-es/translations.xml index adc90e59bf..d111c27611 100644 --- a/features/poll/impl/src/main/res/values-es/translations.xml +++ b/features/poll/impl/src/main/res/values-es/translations.xml @@ -5,6 +5,7 @@ "Ocultar votos" "Opción %1$d" "Tus cambios no se han guardado. ¿Estás seguro de que quieres volver atrás?" + "Eliminar opción %1$s" "Pregunta o tema" "¿De qué trata la encuesta?" "Crear una Encuesta" diff --git a/features/preferences/impl/src/main/res/values-el/translations.xml b/features/preferences/impl/src/main/res/values-el/translations.xml index 49d2f6df47..64b651114d 100644 --- a/features/preferences/impl/src/main/res/values-el/translations.xml +++ b/features/preferences/impl/src/main/res/values-el/translations.xml @@ -10,9 +10,17 @@ "Μη έγκυρη διεύθυνση URL, βεβαιώσου ότι έχεις συμπεριλάβει το πρωτόκολλο (http/https) και τη σωστή διεύθυνση." "Απόκρυψη εικόνων προφίλ σε αιτήματα πρόσκλησης αίθουσας" "Απόκρυψη προεπισκοπήσεων πολυμέσων στο timeline" + "Εργαστήρια" "Ανέβασε φωτογραφίες και βίντεο γρηγορότερα και μείωσε τη χρήση δεδομένων" "Βελτιστοποίηση ποιότητας των μέσων" "Συντονισμός και Ασφάλεια" + "Αυτόματη βελτιστοποίηση εικόνων για ταχύτερες μεταφορτώσεις και μικρότερα μεγέθη αρχείων." + "Βελτιστοποιήστε την ποιότητα μεταφόρτωσης εικόνων" + "%1$s. Πατήστε εδώ για αλλαγή." + "Υψηλή (1080p)" + "Χαμηλή (480p)" + "Τυπικό (720p)" + "Ποιότητα μεταφόρτωσης βίντεο" "Πάροχος ειδοποιήσεων push" "Απενεργοποίησε τον επεξεργαστή εμπλουτισμένου κειμένου για να πληκτρολογήσεις Markdown χειροκίνητα." "Αποδεικτικά ανάγνωσης" @@ -36,6 +44,11 @@ "Δεν είναι δυνατή η ενημέρωση του προφίλ" "Επεξεργασία προφίλ" "Ενημέρωση προφίλ…" + "Ενεργοποίηση απαντήσεων σε νήμα" + "Η εφαρμογή θα επανεκκινηθεί για να εφαρμοστεί αυτήν την αλλαγή." + "Δοκιμάστε τις τελευταίες μας ιδέες που βρίσκονται σε φάση ανάπτυξης. Αυτές οι λειτουργίες δεν είναι τελικές, ενδέχεται να είναι ασταθείς ή να αλλάξουν." + "Έχετε διάθεση για πειραματισμούς;" + "Εργαστήρια" "Πρόσθετες ρυθμίσεις" "Κλήσεις ήχου και βίντεο" "Αναντιστοιχία διαμόρφωσης" diff --git a/features/preferences/impl/src/main/res/values-nl/translations.xml b/features/preferences/impl/src/main/res/values-nl/translations.xml index 0b6419a2f0..28614965c5 100644 --- a/features/preferences/impl/src/main/res/values-nl/translations.xml +++ b/features/preferences/impl/src/main/res/values-nl/translations.xml @@ -26,6 +26,7 @@ "Kan profiel niet bijwerken" "Profiel bewerken" "Profiel bijwerken…" + "Gesprek antwoorden inschakelen" "Aanvullende instellingen" "Audio- en videogesprekken" "Configuratie komt niet overeen" diff --git a/features/preferences/impl/src/main/res/values-tr/translations.xml b/features/preferences/impl/src/main/res/values-tr/translations.xml index fd0a94955c..0df8500fda 100644 --- a/features/preferences/impl/src/main/res/values-tr/translations.xml +++ b/features/preferences/impl/src/main/res/values-tr/translations.xml @@ -13,12 +13,24 @@ "Fotoğraf ve videoları daha hızlı yükleyin ve veri kullanımını azaltın" "Medya kalitesini optimize edin" "Yönetim ve Güvenlik" + "Daha hızlı yükleme ve daha küçük dosya boyutları için görselleri otomatik olarak optimize eder." + "Görsel yükleme kalitesini optimize et" + "%1$s. Değiştirmek için buraya dokunun." + "Yüksek (1080p)" + "Düşük (480p)" + "Standart (720p)" + "Video yükleme kalitesi" "Anlık bildirim sağlayıcısı" "Markdown\'ı manuel olarak yazmak için zengin metin düzenleyicisini devre dışı bırakın." "Okundu bilgisi" "Kapatılırsa, okundu bilgileriniz kimseye gönderilmez. Diğer kullanıcılardan okundu bilgisi almaya devam edersiniz." "Varlığı paylaşın" "Kapatılırsa, okundu bilgisi veya yazma bildirimleri gönderemez veya alamazsınız." + "Her zaman gizle" + "Her zaman göster" + "Özel odalarda" + "Gizli bir medya, üzerine dokunularak her zaman görüntülenebilir" + "Medya dosyalarını zaman çizelgesinde göster" "Zaman çizelgesinde mesaj kaynağını görüntüleme seçeneğini etkinleştirin." "Engellenen kullanıcı yok." "Engellemeyi kaldır" @@ -31,6 +43,10 @@ "Profil güncellenemiyor" "Profili düzenle" "Profil güncelleniyor…" + "Konu yanıtlarını etkinleştir" + "Bu değişikliği uygulamak için uygulama yeniden başlatılacak." + "Geliştirme aşamasındaki en yeni fikirlerimizi deneyin. Bu özellikler henüz tamamlanmamıştır ve kararsız olabilir." + "Labs Ortamı" "Ek ayarlar" "Sesli ve Görüntülü aramalar" "Yapılandırma uyuşmazlığı" diff --git a/features/preferences/impl/src/main/res/values-uz/translations.xml b/features/preferences/impl/src/main/res/values-uz/translations.xml index 82e9b24e98..9c81fc3daa 100644 --- a/features/preferences/impl/src/main/res/values-uz/translations.xml +++ b/features/preferences/impl/src/main/res/values-uz/translations.xml @@ -10,6 +10,7 @@ "URL noto‘g‘ri, iltimos, protokol (http/https) va to‘g‘ri manzilni kiritganingizga ishonch hosil qiling." "Xonaga taklif so‘rovlarida avatarlarni berkitish" "Vaqt jadvalida mediaga razm solishlarni berkitish" + "Laboratoriyalar" "Rasm va videolarni tezroq yuklang va trafik sarfini kamaytiring" "Media sifatini yaxshilash" "Moderatsiya va xavfsizlik" @@ -43,6 +44,11 @@ "Profilni yangilab bo‘lmadi" "Profilni tahrirlash" "Profil yangilanmoqda…" + "Mavzu javoblarini yoqish" + "Ushbu oʻzgartirishni qoʻllash uchun ilova qayta ishga tushadi." + "Ishlab chiqarishdagi eng so‘nggi g‘oyalarimizni sinab ko‘ring. Bu xususiyatlar hali yakuniy emas; ular beqaror bo‘lishi va o‘zgarishi mumkin." + "Tajribani his qilyapsizmi?" + "Laboratoriyalar" "Qo\'shimcha sozlamalar" "Audio va video qo\'ng\'iroqlar" "Konfiguratsiya mos kelmasligi" diff --git a/features/rageshake/impl/src/main/res/values-el/translations.xml b/features/rageshake/impl/src/main/res/values-el/translations.xml index 86400b4806..62c794afed 100644 --- a/features/rageshake/impl/src/main/res/values-el/translations.xml +++ b/features/rageshake/impl/src/main/res/values-el/translations.xml @@ -10,8 +10,11 @@ "Η περιγραφή είναι πολύ σύντομη, δώσε περισσότερες λεπτομέρειες σχετικά με το τί συνέβη. Ευχαριστώ!" "Αποστολή αρχείων καταγραφής σφαλμάτων" "Να επιτρέπονται τα αρχεία καταγραφής" + "Τα αρχεία καταγραφής σας είναι υπερβολικά μεγάλα και δεν μπορούν να συμπεριληφθούν σε αυτήν την αναφορά. Παρακαλούμε να μας τα στείλετε με άλλο τρόπο." "Αποστολή στιγμιοτύπου οθόνης" "Τα αρχεία καταγραφής θα συμπεριληφθούν στο μήνυμά σου για να βεβαιωθούμε ότι όλα λειτουργούν σωστά. Για να στείλεις το μήνυμά σου χωρίς αρχεία καταγραφής, απενεργοποίησε αυτήν τη ρύθμιση." "Το %1$s διακόπηκε την τελευταία φορά που χρησιμοποιήθηκε. Θα \'θελες να μοιραστείς μια αναφορά σφάλματος μαζί μας;" + "Εάν αντιμετωπίζετε προβλήματα με τις ειδοποιήσεις, η μεταφόρτωση των κανόνων προώθησης ειδοποιήσεων μπορεί να μας βοηθήσει να εντοπίσουμε την αιτία. Λάβετε υπόψη ότι αυτοί οι κανόνες μπορεί να περιέχουν ιδιωτικές πληροφορίες, όπως το εμφανιζόμενο όνομά σας ή λέξεις-κλειδιά για τις οποίες θα λαμβάνετε ειδοποιήσεις." + "Ρυθμίσεις αποστολής ειδοποιήσεων" "Προβολή αρχείων καταγραφής" diff --git a/features/rageshake/impl/src/main/res/values-es/translations.xml b/features/rageshake/impl/src/main/res/values-es/translations.xml index cdeb467cfa..5c21e4a9bd 100644 --- a/features/rageshake/impl/src/main/res/values-es/translations.xml +++ b/features/rageshake/impl/src/main/res/values-es/translations.xml @@ -10,6 +10,7 @@ "La descripción es demasiado corta. Proporciona más detalles sobre lo sucedido. ¡Gracias!" "Enviar registros de fallos" "Permitir registros" + "Tus registros de errores son demasiado grandes y no pueden añadirse a este informe, por favor envíanoslos de otra manera." "Enviar captura de pantalla" "Los registros se incluirán con tu mensaje para asegurarse de que todo funciona correctamente. Para enviar tu mensaje sin registros, desactiva esta opción." "%1$s se cerró inesperadamente la última vez que se lo usaste. ¿Quieres compartir un informe de error con nosotros?" diff --git a/features/rageshake/impl/src/main/res/values-tr/translations.xml b/features/rageshake/impl/src/main/res/values-tr/translations.xml index d558126f21..ad1e164874 100644 --- a/features/rageshake/impl/src/main/res/values-tr/translations.xml +++ b/features/rageshake/impl/src/main/res/values-tr/translations.xml @@ -13,5 +13,7 @@ "Ekran görüntüsü gönder" "Her şeyin düzgün çalıştığından emin olmak için günlükler mesajınıza dahil edilecektir. Mesajınızı kayıt tutmadan göndermek için bu ayarı kapatın." "%1$s son kullanıldığında çöktü. Bizimle bir çökme raporu paylaşmak ister misiniz?" + "Bildirimlerle ilgili sorun yaşıyorsanız, bildirim ayarlarını göndermek sorunun kaynağını bulmamıza yardımcı olabilir. Bu ayarların, görünen adınız veya bildirim almak istediğiniz anahtar kelimeler gibi özel bilgiler içerebileceğini unutmayın." + "Bildirim ayarlarını gönder" "Günlükleri görüntüle" diff --git a/features/rageshake/impl/src/main/res/values-uz/translations.xml b/features/rageshake/impl/src/main/res/values-uz/translations.xml index e3aceaa7d6..30e9e1787b 100644 --- a/features/rageshake/impl/src/main/res/values-uz/translations.xml +++ b/features/rageshake/impl/src/main/res/values-uz/translations.xml @@ -14,5 +14,7 @@ "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?" + "Agar bildirishnomalar bilan bog‘liq muammolarga duch kelayotgan bo‘lsangiz, bildirishnomalarni yetkazish qoidalarini yuklash bizga asosiy sababni aniqlashda yordam beradi. Shuni yodda tutingki, bu qoidalarda shaxsiy ma’lumotlar, masalan, ko‘rsatiladigan ismingiz yoki bildirishnoma olishingiz kerak bo‘lgan kalit so‘zlar kabi ma’lumotlar bo‘lishi mumkin." + "Bildirishnoma sozlamalarini yuborish" "Jurnallarni ko'rish" diff --git a/features/reportroom/impl/src/main/res/values-tr/translations.xml b/features/reportroom/impl/src/main/res/values-tr/translations.xml new file mode 100644 index 0000000000..e104994456 --- /dev/null +++ b/features/reportroom/impl/src/main/res/values-tr/translations.xml @@ -0,0 +1,7 @@ + + + "Bildiriminiz başarıyla gönderildi ancak odadan çıkarken bir sorun oluştu. Lütfen tekrar deneyin." + "Odadan çıkılamadı" + "Bu odayı yöneticinize bildirin. Mesajlar şifreliyse yöneticiniz onları okuyamaz." + "Bildirme nedenini açıklayın…" + diff --git a/features/rolesandpermissions/impl/src/main/res/values-bg/translations.xml b/features/rolesandpermissions/impl/src/main/res/values-bg/translations.xml index b1ca5f9718..fee2a2f58a 100644 --- a/features/rolesandpermissions/impl/src/main/res/values-bg/translations.xml +++ b/features/rolesandpermissions/impl/src/main/res/values-bg/translations.xml @@ -1,12 +1,12 @@ - "Само администратори" + "Администратор" "Премахване на съобщения" - "Поканване на хора и приемане на заявки за присъединяване" + "Поканване на хора" "Съобщения и съдържание" - "Администратори и модератори" - "Премахване на хора и отхвърляне на заявки за присъединяване" - "Редактиране на стаята" + "Модератор" + "Премахване на хора" + "Редактиране на подробностите" "Промяна на името на стаята" "Промяна на темата на стаята" "Изпращане на съобщения" @@ -22,8 +22,8 @@ "%1$d души" "Членове" - "Само администратори" - "Администратори и модератори" + "Администратор" + "Модератор" "Членове на стаята" "Администратори" "Промяна на моята роля" diff --git a/features/rolesandpermissions/impl/src/main/res/values-el/translations.xml b/features/rolesandpermissions/impl/src/main/res/values-el/translations.xml index 8cd14feb47..fcc1abe283 100644 --- a/features/rolesandpermissions/impl/src/main/res/values-el/translations.xml +++ b/features/rolesandpermissions/impl/src/main/res/values-el/translations.xml @@ -1,36 +1,52 @@ - "Μόνο διαχειριστές" + "Διαχειριστής" "Αποκλεισμός ατόμων" + "Αλλαγή ρυθμίσεων" "Αφαίρεση μηνυμάτων" - "Προσκάλεσε άτομα και αποδέξου αιτήματα συμμετοχής" + "Μέλος" + "Πρόσκληση ατόμων" + "Διαχείριση χώρου" + "Διαχείριση αίθουσών" + "Διαχείριση μελών" "Μηνύματα και περιεχόμενο" - "Διαχειριστές και συντονιστές" - "Αφαίρεση ατόμων και απόρριψη αιτημάτων συμμετοχής" + "Συντονιστής" + "Αφαίρεση ατόμων" "Αλλαγή εικόνας προφίλ αίθουσας" - "Επεξεργασία Αίθουσας" + "Επεξεργασία λεπτομερειών" "Αλλαγή ονόματος αίθουσας" "Αλλαγή θέματος αίθουσας" "Αποστολή μηνυμάτων" + "Άδειες" "Επεξεργασία Διαχειριστών" "Δεν θα μπορείς να αναιρέσεις αυτήν την ενέργεια. Προβιβάζεις τον χρήστη να έχει το ίδιο επίπεδο ισχύος με σένα." "Προσθήκη Διαχειριστή;" + "Δεν θα μπορείτε να αναιρέσετε αυτήν την ενέργεια. Μεταβιβάζετε την κυριότητα στους επιλεγμένους χρήστες. Μόλις αποχωρήσετε, αυτό θα είναι μόνιμο." + "Μεταβίβαση ιδιοκτησίας;" "Υποβιβασμός" "Δεν θα μπορέσετε να αναιρέσετε αυτή την αλλαγή καθώς υποβιβάζετε τον εαυτό σας, αν είστε ο τελευταίος χρήστης με δικαιώματα στην αίθουσα θα είναι αδύνατο να ανακτήσετε δικαιώματα." "Υποβιβασμός του εαυτού σου;" "%1$s (Σε αναμονή)" "(Σε αναμονή)" "Οι διαχειριστές έχουν αυτόματα δικαιώματα συντονιστή" + "Οι κάτοχοι έχουν αυτομάτως δικαιώματα διαχειριστή." "Επεξεργασία Συντονιστών" + "Επιλογή Ιδιοκτητών" "Διαχειριστές" "Συντονιστές" "Μέλη" "Έχεις μη αποθηκευμένες αλλαγές." "Αποθήκευση αλλαγών;" - "Δεν υπάρχουν αποκλεισμένοι χρήστες σε αυτή την αίθουσα." + "Δεν υπάρχουν αποκλεισμένοι χρήστες." + + "%1$d Αποκλείστηκε" + "%1$d Αποκλείστηκαν" + + "Ελέγξτε την ορθογραφία ή δοκιμάστε μια νέα αναζήτηση" + "Δεν υπάρχουν αποτελέσματα για «%1$s»" - "%1$d άτομο" - "%1$d άτομα" + "%1$d Άτομο" + "%1$d Άτομα" "Αφαίρεση και αποκλεισμός μέλους" "Μόνο αφαίρεση μέλους" @@ -39,21 +55,31 @@ "Άρση αποκλεισμού από την αίθουσα" "Αποκλεισμένοι" "Μέλη" - "Μόνο διαχειριστές" - "Διαχειριστές και συντονιστές" + + "%1$d Προσκλήθηκε" + "%1$d Προσκλήθηκαν" + + "Εκκρεμής" + "Διαχειριστής" + "Συντονιστής" + "Ιδιοκτήτης" "Μέλη της αίθουσας" "Άρση αποκλεισμού %1$s" "Διαχειριστές" + "Διαχειριστές και κάτοχοι" "Άλλαξε τον ρόλο μου" "Υποβιβασμός σε μέλος" "Υποβιβασμός σε συντονιστή" "Συντονισμός μελών" "Μηνύματα και περιεχόμενο" "Συντονιστές" + "Ιδιοκτήτες" + "Άδειες" "Επαναφορά δικαιωμάτων" "Μόλις επαναφέρεις τα δικαιώματα, θα χάσεις τις τρέχουσες ρυθμίσεις." "Επαναφορά δικαιωμάτων;" "Ρόλοι" "Λεπτομέρειες αίθουσας" + "Λεπτομέρειες χώρου" "Ρόλοι και δικαιώματα" diff --git a/features/rolesandpermissions/impl/src/main/res/values-es/translations.xml b/features/rolesandpermissions/impl/src/main/res/values-es/translations.xml index 383ffba1eb..a41489ea1b 100644 --- a/features/rolesandpermissions/impl/src/main/res/values-es/translations.xml +++ b/features/rolesandpermissions/impl/src/main/res/values-es/translations.xml @@ -1,14 +1,16 @@ - "Solo administradores" + "Administrador" "Vetar personas" "Eliminar mensajes" - "Invitar personas y aceptar solicitudes de unión" + "Miembro" + "Invitar a otras personas" + "Administrar miembros" "Mensajes y contenido" - "Administradores y moderadores" - "Eliminar personas y rechazar solicitudes de unión" + "Moderador" + "Eliminar personas" "Cambiar el avatar de la sala" - "Editar sala" + "Editar detalles" "Cambiar el nombre de la sala" "Cambiar el tema de la sala" "Enviar mensajes" @@ -27,10 +29,10 @@ "Miembros" "Tienes cambios sin guardar." "¿Guardar cambios?" - "No hay usuarios vetados en esta sala." + "No hay usuarios baneados." - "Una persona" - "%1$d personas" + "%1$d Persona" + "%1$d Personas" "Sacar y vetar a un miembro" "Solo eliminar miembro" @@ -39,8 +41,8 @@ "Eliminar veto en la sala" "Vetados" "Miembros" - "Solo administradores" - "Administradores y moderadores" + "Administrador" + "Moderador" "Miembros de la sala" "Levantando veto a %1$s" "Administradores" diff --git a/features/rolesandpermissions/impl/src/main/res/values-fi/translations.xml b/features/rolesandpermissions/impl/src/main/res/values-fi/translations.xml index 29331bcd13..7c5d635b14 100644 --- a/features/rolesandpermissions/impl/src/main/res/values-fi/translations.xml +++ b/features/rolesandpermissions/impl/src/main/res/values-fi/translations.xml @@ -5,13 +5,13 @@ "Asetusten muuttaminen" "Viestien poistaminen" "Jäsen" - "Ihmisten kutsuminen ja liittymispyyntöjen hyväksyminen" + "Kutsujen antaminen" "Tilan hallitseminen" "Huoneiden hallitseminen" - "Jäsenien hallinta" + "Jäsenien hallitseminen" "Viestit ja sisältö" "Valvoja" - "Henkilöiden poistaminen ja liittymispyyntöjen hylkääminen" + "Henkilöiden poistaminen" "Huoneen avatarin vaihtaminen" "Muokkaa tietoja" "Huoneen nimen vaihtaminen" @@ -38,6 +38,12 @@ "Sinulla on tallentamattomia muutoksia" "Tallennetaanko muutokset?" "Porttikiellettyjä käyttäjiä ei ole." + + "%1$d porttikielletty" + "%1$d porttikiellettyä" + + "Tarkista oikeinkirjoitus tai kokeile uutta hakua" + "Ei tuloksia haulle \"%1$s\"" "%1$d henkilö" "%1$d henkilöä" @@ -49,6 +55,11 @@ "Poista porttikielto huoneesta" "Porttikiellot" "Jäsenet" + + "%1$d kutsuttu" + "%1$d kutsuttua" + + "Kutsuttu" "Ylläpitäjä" "Valvoja" "Omistaja" diff --git a/features/rolesandpermissions/impl/src/main/res/values-fr/translations.xml b/features/rolesandpermissions/impl/src/main/res/values-fr/translations.xml index 874b6710cd..7e5736bbed 100644 --- a/features/rolesandpermissions/impl/src/main/res/values-fr/translations.xml +++ b/features/rolesandpermissions/impl/src/main/res/values-fr/translations.xml @@ -31,7 +31,7 @@ "Les administrateurs ont automatiquement les privilèges des modérateurs" "Les propriétaires disposent automatiquement des privilèges des administrateurs." "Modifier les modérateurs" - "Choisissez les propriétaires" + "Choisir les propriétaires" "Administrateurs" "Modérateurs" "Membres" diff --git a/features/rolesandpermissions/impl/src/main/res/values-tr/translations.xml b/features/rolesandpermissions/impl/src/main/res/values-tr/translations.xml index 6e53f48610..8a953d0c21 100644 --- a/features/rolesandpermissions/impl/src/main/res/values-tr/translations.xml +++ b/features/rolesandpermissions/impl/src/main/res/values-tr/translations.xml @@ -2,8 +2,11 @@ "Yalnızca yöneticiler" "İnsanları yasakla" + "Ayarları değiştir" "Mesajları kaldır" "Kişileri davet etme ve katılma isteklerini kabul etme" + "Alanı yönet" + "Odaları yönet" "Mesajlar ve içerik" "Yöneticiler ve moderatörler" "Kişileri kaldırma ve katılma isteklerini reddetme" @@ -12,9 +15,11 @@ "Oda adını değiştir" "Oda konusunu değiştir" "Mesaj gönder" + "İzinler" "Yöneticileri Düzenle" "Bu eylemi geri alamazsınız. Kullanıcıyı sizinle aynı güç seviyesine sahip olacak şekilde terfi ettiriyorsunuz." "Yönetici Ekle?" + "Bu işlemi geri alamazsınız. Sahipliği seçilen kullanıcılara devrediyorsunuz. Ayrıldıktan sonra bu işlem kalıcı olacaktır." "Rütbe Düşür" "Rütbenizi düşürdüğünüz için bu değişikliği geri alamazsınız, eğer odadaki son ayrıcalıklı kullanıcı sizseniz ayrıcalıkları yeniden kazanmanız mümkün olmayacaktır." "Rütbeni düşür?" @@ -28,6 +33,8 @@ "Kaydedilmemiş değişiklikleriniz var." "Değişiklikleri Kaydet?" "Bu odada yasaklı kullanıcı yok." + "Metni kontrol edin ya da yeni bir arama yapmayı deneyin." + "“%1$s” için sonuç bulunamadı" "%1$d kişi" "%1$d kişi" @@ -38,6 +45,11 @@ "Davet edildikleri takdirde bu odaya tekrar katılabileceklerdir." "Yasaklandı" "Üyeler" + + "%1$d Davetli" + "%1$d Davetli" + + "Beklemede" "Yalnızca yöneticiler" "Yöneticiler ve moderatörler" "Oda üyeleri" @@ -49,10 +61,12 @@ "Üye moderasyonu" "Mesajlar ve içerik" "Moderatörler" + "İzinler" "İzinleri sıfırla" "İzinleri sıfırladığınızda, mevcut ayarları kaybedersiniz." "İzinleri sıfırla?" "Roller" "Oda bilgileri" + "Alan ayrıntıları" "Roller ve izinler" diff --git a/features/rolesandpermissions/impl/src/main/res/values-uz/translations.xml b/features/rolesandpermissions/impl/src/main/res/values-uz/translations.xml index 03f94969b5..e020a9ffcc 100644 --- a/features/rolesandpermissions/impl/src/main/res/values-uz/translations.xml +++ b/features/rolesandpermissions/impl/src/main/res/values-uz/translations.xml @@ -1,18 +1,23 @@ - "Faqat adminlar" + "Admin" "Odamlarni taqiqlash" + "Sozlamalarni o‘zgartirish" "Xabarlarni olib tashlash" + "A\'zo" "Odamlarni taklif qiling va qo‘shilish so‘rovlarini qabul qiling" + "Maydonni boshqarish" + "Xonalarni boshqarish" "A’zolarni boshqarish" "Xabarlar va kontent" - "Adminlar va moderatorlar" - "Odamlarni olib tashlash va qoʻshilish soʻrovlarini rad etish" + "Moderator" + "Odamlarni olib tashlash" "Xona avatarini oʻzgartirish" "Tafsilotlarni tahrirlash" "Xona nomini oʻzgartirish" "Xona mavzusini almashtirish" "Xabarlar yuborish" + "Ruxsatlar" "Administratorlarni tahrirlash" "Bu amalni bekor qila olmaysiz. Siz foydalanuvchini o‘zingiz bilan bir xil quvvat darajasiga ega bo‘lishga undayapsiz." "Admin qo‘shilsinmi?" @@ -32,7 +37,13 @@ "Azolar" "Sizda saqlanmagan oʻzgarishlar bor" "O‘zgartirishlarni saqlaysizmi?" - "Bu xonada taqiqlangan foydalanuvchilar yoʻq." + "Taqiqlangan foydalanuvchilar yoʻq." + + "%1$dTaqiqlangan" + "%1$dTaqiqlangan" + + "Imloni tekshiring yoki yangi qidiruvni sinang" + "%1$s – hech narsa topilmadi" "%1$dodam" "%1$dodamlar" @@ -44,8 +55,13 @@ "Xonadan taqiqni olib tashlash" "Taqiqlangan" "Azolar" - "Faqat adminlar" - "Adminlar va moderatorlar" + + "%1$d Taklif qilingan" + "%1$d Taklif qilingan" + + "Jarayonda" + "Admin" + "Moderator" "Egasi" "Xona a\'zolari" "Taqiqni bekor qilish %1$s" @@ -58,10 +74,12 @@ "Xabarlar va kontent" "Moderatorlar" "Egalari" + "Ruxsatlar" "Ruxsatlarni tiklash" "Ruxsatlarni asliga qaytargach, joriy sozlamalarni yoʻqotasiz." "Ruxsatlar asliga qaytarilsinmi?" "Rollar" "Xona tafsilotlari" + "Maydon tafsilotlari" "Rollar va ruxsatlar" diff --git a/features/rolesandpermissions/impl/src/main/res/values-zh/translations.xml b/features/rolesandpermissions/impl/src/main/res/values-zh/translations.xml index d2882d8ab4..768bed1a86 100644 --- a/features/rolesandpermissions/impl/src/main/res/values-zh/translations.xml +++ b/features/rolesandpermissions/impl/src/main/res/values-zh/translations.xml @@ -1,17 +1,23 @@ - "仅限管理员" + "管理员" "封禁成员" + "更改设置" "移除消息" - "邀请他人及接受加入请求" + "成员" + "邀请人员" + "管理空间" + "管理聊天室" + "管理成员" "消息和内容" - "管理员和协管员" - "移除成员及拒绝加入请求" + "协管员" + "移除人员" "更改聊天室头像" - "编辑聊天室" + "编辑详情" "更改聊天室名称" "更改聊天室主题" "发送消息" + "权限" "编辑管理员" "您将无法撤消此操作。您正在提升用户的权限,使其拥有与您平权。" "添加管理员?" @@ -21,7 +27,7 @@ "您正在降级,此更改将无法撤消。如果您是聊天室中的最后一个特权用户,则无法重新获得权限。" "降级自己?" "%1$s(待处理)" - "(已邀请)" + "(待处理)" "管理员自动拥有协管员权限" "所有者自动拥有管理员权限。" "编辑协管员" @@ -32,8 +38,13 @@ "您有未保存的更改。" "保存更改?" "没有被封禁的用户。" + + "%1$d 被禁用" + + "检查拼写或尝试新搜索" + "未找到 “%1$s” 相关结果" - "%1$d 人" + "%1$d 个人" "移除并封禁成员" "仅移除成员" @@ -42,8 +53,12 @@ "从房间取消解封" "已封禁用户" "成员" - "仅限管理员" - "管理员和协管员" + + "%1$d 受邀" + + "待处理" + "管理员" + "协管员" "所有者" "聊天室成员" "解除封禁 %1$s" @@ -56,6 +71,7 @@ "消息和内容" "协管员" "所有者" + "权限" "重置权限" "重置权限后,您将丢失当前设置。" "重置权限?" diff --git a/features/roomdetails/impl/src/main/res/values-bg/translations.xml b/features/roomdetails/impl/src/main/res/values-bg/translations.xml index 57852f92d5..55bce6cd12 100644 --- a/features/roomdetails/impl/src/main/res/values-bg/translations.xml +++ b/features/roomdetails/impl/src/main/res/values-bg/translations.xml @@ -3,13 +3,13 @@ "Възникна грешка при обновяването на настройките за известия." "Вашият сървър не поддържа тази опция в шифровани стаи, може да не получавате известия в някои стаи." "Анкети" - "Само администратори" + "Администратор" "Премахване на съобщения" - "Поканване на хора и приемане на заявки за присъединяване" + "Поканване на хора" "Съобщения и съдържание" - "Администратори и модератори" - "Премахване на хора и отхвърляне на заявки за присъединяване" - "Редактиране на стаята" + "Модератор" + "Премахване на хора" + "Редактиране на подробностите" "Промяна на името на стаята" "Промяна на темата на стаята" "Изпращане на съобщения" @@ -24,7 +24,7 @@ "С шифроване" "Без шифроване" "Общодостъпна стая" - "Редактиране на стаята" + "Редактиране на подробностите" "Възникна неизвестна грешка и информацията не можа да бъде променена." "Не може да се обнови стаята" "Съобщенията са защитени с ключове. Само вие и получателите имате уникалните ключове, за да ги отключите." @@ -53,8 +53,8 @@ "%1$d души" "Членове" - "Само администратори" - "Администратори и модератори" + "Администратор" + "Модератор" "Членове на стаята" "Разрешаване на персонализирана настройка" "Включването на това ще замени вашата настройка по подразбиране" @@ -78,20 +78,20 @@ "Роли" "Подробности за стаята" "Роли и разрешения" - "Добавяне на адрес на стаята" + "Добавяне на адрес" "Да, включване на шифроването" "Да се включи ли шифроването?" "Веднъж включено, шифроването не може да бъде изключено." "Шифроване" "Включване на шифроване от край до край" - "Всеки може да намери и да се присъедини" - "Хората могат да се присъединят само ако са поканени" + "Всеки може да се присъедини." + "Само поканени хора могат да се присъединят." "Само с покана" - "Достъп до стаята" + "Достъп" "Пространствата в момента не се поддържат" - "Видима в директорията на обществените стаи" + "Видима в обществената директория" "Кой може да чете историята" - "Само за членове откакто са поканени" - "Само за членове от избирането на тази опция" + "Членове откакто са поканени" + "Членове (пълната история)" "Защита и поверителност" diff --git a/features/roomdetails/impl/src/main/res/values-da/translations.xml b/features/roomdetails/impl/src/main/res/values-da/translations.xml index 997066cdd1..d5efb73b82 100644 --- a/features/roomdetails/impl/src/main/res/values-da/translations.xml +++ b/features/roomdetails/impl/src/main/res/values-da/translations.xml @@ -1,5 +1,8 @@ + "Nye medlemmer kan ikke se historikken" + "Nye medlemmer ser historik" + "Alle kan se historikken" "Du skal bruge en adresse for at gøre det synligt i det offentlige register." "Redigér adresse" "Der opstod en fejl under opdatering af notifikationsindstillingen." @@ -150,6 +153,7 @@ Vi anbefaler ikke at aktivere kryptering for rum, som alle kan finde og deltage "Adgang" "Alle i autoriserede grupper kan deltage." "Alle i %1$s kan deltage." + "Medlemmer af rummet" "Grupper understøttes ikke i øjeblikket" "Du skal bruge en adresse for at gøre det synligt i det offentlige register." "Adresse" 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 80a5505f53..c1b108a524 100644 --- a/features/roomdetails/impl/src/main/res/values-el/translations.xml +++ b/features/roomdetails/impl/src/main/res/values-el/translations.xml @@ -1,32 +1,41 @@ - "Θα χρειαστείτε μια διεύθυνση αίθουσας για να την κάνετε ορατή στον κατάλογο." - "Διεύθυνση αίθουσας" + "Τα νέα μέλη δεν βλέπουν το ιστορικό" + "Τα νέα μέλη βλέπουν το ιστορικό" + "Οποιοσδήποτε μπορεί να δει το ιστορικό" + "Θα χρειαστείτε μια διεύθυνση για να την κάνετε ορατή στον δημόσιο κατάλογο." + "Επεξεργασία διεύθυνσης" "Παρουσιάστηκε σφάλμα κατά την ενημέρωση της ρύθμισης ειδοποίησης." "Ο αρχικός διακομιστής σας δεν υποστηρίζει αυτή την επιλογή σε κρυπτογραφημένες αίθουσες, ενδέχεται να μην λαμβάνετε ειδοποιήσεις σε ορισμένες αίθουσες." "Δημοσκοπήσεις" - "Μόνο διαχειριστές" + "Διαχειριστής" "Αποκλεισμός ατόμων" "Αφαίρεση μηνυμάτων" - "Προσκάλεσε άτομα και αποδέξου αιτήματα συμμετοχής" + "Μέλος" + "Πρόσκληση ατόμων" + "Διαχείριση μελών" "Μηνύματα και περιεχόμενο" - "Διαχειριστές και συντονιστές" - "Αφαίρεση ατόμων και απόρριψη αιτημάτων συμμετοχής" + "Συντονιστής" + "Αφαίρεση ατόμων" "Αλλαγή εικόνας προφίλ αίθουσας" - "Επεξεργασία Αίθουσας" + "Επεξεργασία λεπτομερειών" "Αλλαγή ονόματος αίθουσας" "Αλλαγή θέματος αίθουσας" "Αποστολή μηνυμάτων" "Επεξεργασία Διαχειριστών" "Δεν θα μπορείς να αναιρέσεις αυτήν την ενέργεια. Προβιβάζεις τον χρήστη να έχει το ίδιο επίπεδο ισχύος με σένα." "Προσθήκη Διαχειριστή;" + "Δεν θα μπορείτε να αναιρέσετε αυτήν την ενέργεια. Μεταβιβάζετε την κυριότητα στους επιλεγμένους χρήστες. Μόλις αποχωρήσετε, αυτό θα είναι μόνιμο." + "Μεταβίβαση ιδιοκτησίας;" "Υποβιβασμός" "Δεν θα μπορέσετε να αναιρέσετε αυτή την αλλαγή καθώς υποβιβάζετε τον εαυτό σας, αν είστε ο τελευταίος χρήστης με δικαιώματα στην αίθουσα θα είναι αδύνατο να ανακτήσετε δικαιώματα." "Υποβιβασμός του εαυτού σου;" "%1$s (Σε αναμονή)" "(Σε αναμονή)" "Οι διαχειριστές έχουν αυτόματα δικαιώματα συντονιστή" + "Οι κάτοχοι έχουν αυτομάτως δικαιώματα διαχειριστή." "Επεξεργασία Συντονιστών" + "Επιλογή Ιδιοκτητών" "Διαχειριστές" "Συντονιστές" "Μέλη" @@ -36,7 +45,7 @@ "Κρυπτογραφημένο" "Μη κρυπτογραφημένο" "Δημόσια αίθουσα" - "Επεξεργασία Αίθουσας" + "Επεξεργασία λεπτομερειών" "Υπήρξε ένα άγνωστο σφάλμα και οι πληροφορίες δεν μπορούσαν να αλλάξουν." "Αδυναμία ενημέρωσης αίθουσας" "Τα μηνύματα ασφαλίζονται με κλειδαριές. Μόνο εσύ και οι παραλήπτες έχετε τα μοναδικά κλειδιά για να τα ξεκλειδώσετε." @@ -44,6 +53,8 @@ "Παρουσιάστηκε σφάλμα κατά τη φόρτωση των ρυθμίσεων ειδοποίησης." "Η σίγαση αυτής της αίθουσας απέτυχε, δοκιμάστε ξανά." "Η κατάργηση σίγασης αυτής της αίθουσας απέτυχε, δοκιμάστε ξανά." + "Μην κλείσετε την εφαρμογή μέχρι να τελειώσει." + "Προετοιμασία προσκλήσεων…" "Πρόσκληση ατόμων" "Αποχώρηση από τη συζήτηση" "Αποχώρηση από την αίθουσα" @@ -55,16 +66,23 @@ "Προφίλ" "Αιτήματα συμμετοχής" "Ρόλοι και δικαιώματα" + "Όνομα" "Ασφάλεια & απόρρητο" "Ασφάλεια" "Κοινή χρήση αίθουσας" "Πληροφορίες αίθουσας" "Θέμα" "Ενημέρωση αίθουσας…" - "Δεν υπάρχουν αποκλεισμένοι χρήστες σε αυτή την αίθουσα." + "Δεν υπάρχουν αποκλεισμένοι χρήστες." + + "%1$d Αποκλείστηκε" + "%1$d Αποκλείστηκαν" + + "Ελέγξτε την ορθογραφία ή δοκιμάστε μια νέα αναζήτηση" + "Δεν υπάρχουν αποτελέσματα για «%1$s»" - "%1$d άτομο" - "%1$d άτομα" + "%1$d Άτομο" + "%1$d Άτομα" "Αφαίρεση και αποκλεισμός μέλους" "Μόνο αφαίρεση μέλους" @@ -73,8 +91,14 @@ "Άρση αποκλεισμού από την αίθουσα" "Αποκλεισμένοι" "Μέλη" - "Μόνο διαχειριστές" - "Διαχειριστές και συντονιστές" + + "%1$d Προσκλήθηκε" + "%1$d Προσκλήθηκαν" + + "Εκκρεμής" + "Διαχειριστής" + "Συντονιστής" + "Ιδιοκτήτης" "Μέλη της αίθουσας" "Άρση αποκλεισμού %1$s" "Να επιτρέπεται η προσαρμοσμένη ρύθμιση" @@ -92,21 +116,26 @@ "Μόνο αναφορές και λέξεις-κλειδιά" "Σε αυτήν την αίθουσα, ειδοποιήστε με για" "Διαχειριστές" + "Διαχειριστές και κάτοχοι" "Άλλαξε τον ρόλο μου" "Υποβιβασμός σε μέλος" "Υποβιβασμός σε συντονιστή" "Συντονισμός μελών" "Μηνύματα και περιεχόμενο" "Συντονιστές" + "Ιδιοκτήτες" + "Άδειες" "Επαναφορά δικαιωμάτων" "Μόλις επαναφέρεις τα δικαιώματα, θα χάσεις τις τρέχουσες ρυθμίσεις." "Επαναφορά δικαιωμάτων;" "Ρόλοι" "Λεπτομέρειες αίθουσας" "Ρόλοι και δικαιώματα" - "Προσθήκη διεύθυνσης αίθουσας" - "Οποιοσδήποτε μπορεί να ζητήσει να συμμετάσχει στην αίθουσα, αλλά ένας διαχειριστής ή συντονιστής θα πρέπει να αποδεχτεί το αίτημα." + "Προσθήκη διεύθυνσης" + "Οποιοσδήποτε σε εξουσιοδοτημένους χώρους μπορεί να συμμετάσχει, αλλά όλοι οι άλλοι πρέπει να ζητήσουν πρόσβαση." + "Όλοι πρέπει να αιτούνται πρόσβαση." "Αίτημα συμμετοχής" + "Οποιοσδήποτε στο %1$s μπορεί να συμμετάσχει, αλλά όλοι οι άλλοι πρέπει να ζητήσουν πρόσβαση." "Ναι, ενεργοποιήστε την κρυπτογράφηση" "Μόλις ενεργοποιηθεί, η κρυπτογράφηση για μια αίθουσα δεν μπορεί να απενεργοποιηθεί, το ιστορικό μηνυμάτων θα είναι ορατό μόνο για τα μέλη της αίθουσας από τότε που προσκλήθηκαν ή από τότε που συμμετείχαν στην αίθουσα. Κανείς άλλος εκτός από τα μέλη της αίθουσας δεν θα μπορεί να διαβάσει τα μηνύματα. Αυτό μπορεί να εμποδίσει τη σωστή λειτουργία των bots και των γεφυρών. @@ -115,20 +144,31 @@ "Μόλις ενεργοποιηθεί, η κρυπτογράφηση δεν μπορεί να απενεργοποιηθεί." "Κρυπτογράφηση" "Ενεργοποίηση κρυπτογράφησης από άκρο σε άκρο" - "Οποιοσδήποτε μπορεί να βρει και να συμμετάσχει" + "Οποιοσδήποτε μπορεί να συμμετάσχει." "Οποιοσδήποτε" - "Τα άτομα μπορούν να συμμετάσχουν μόνο εάν έχουν προσκληθεί" - "Μόνο πρόσκληση" - "Πρόσβαση στην αίθουσα" + "Επιλέξτε ποια μέλη των χώρων μπορούν να συμμετάσχουν σε αυτήν την αίθουσα χωρίς πρόσκληση. %1$s" + "Διαχείριση χώρων" + "Μόνο άτομα που έχουν προσκληθεί μπορούν να συμμετάσχουν." + "Μόνο με πρόσκληση" + "Πρόσβαση" + "Οποιοσδήποτε σε εξουσιοδοτημένους χώρους μπορεί να συμμετάσχει." + "Οποιοσδήποτε στο %1$s μπορεί να συμμετάσχει." + "Μέλη χώρου" "Οι χώροι δεν υποστηρίζονται προς το παρόν" - "Θα χρειαστείτε μια διεύθυνση αίθουσας για να την κάνετε ορατή στον κατάλογο." + "Θα χρειαστείτε μια διεύθυνση για να την κάνετε ορατή στον δημόσιο κατάλογο." + "Διεύθυνση" "Επιστρέψτε την εύρεση αυτής της αίθουσας με αναζήτηση στον κατάλογο %1$s δημοσίων αιθουσών" - "Ορατή στον κατάλογο δημόσιων αιθουσών" + "Επιτρέψτε την εύρεσή σας μέσω αναζήτησης στον δημόσιο κατάλογο." + "Ορατό στον δημόσιο κατάλογο" + "Οποιοσδήποτε (το ιστορικό είναι δημόσιο)" + "Οι αλλαγές δεν θα επηρεάσουν τα παλιά μηνύματα, μόνο τα νέα. %1$s" "Ποιος μπορεί να διαβάσει το ιστορικό" - "Μόνο μέλη από τη στιγμή που προσκλήθηκαν" - "Μόνο για μέλη μετά από αυτήν την επιλογή" + "Μέλη από τότε που προσκλήθηκατε" + "Μέλη (πλήρες ιστορικό)" "Οι διευθύνσεις αιθουσών είναι τρόποι εύρεσης και πρόσβασης σε αίθουσες. Αυτό διασφαλίζει επίσης ότι μπορείτε εύκολα να μοιραστείτε την αίθουσα με άλλους. Μπορείτε να επιλέξετε να δημοσιεύσετε την αίθουσά σας στον δημόσιο κατάλογο αιθουσών του αρχικού διακομιστή σας." "Δημοσίευση αίθουσας" + "Οι διευθύνσεις είναι ένας τρόπος για να βρίσκετε και να έχετε πρόσβαση σε αίθουσες και χώρους. Αυτό διασφαλίζει επίσης ότι μπορείτε εύκολα να τις μοιραστείτε με άλλους." + "Ορατότητα" "Ασφάλεια & απόρρητο" diff --git a/features/roomdetails/impl/src/main/res/values-es/translations.xml b/features/roomdetails/impl/src/main/res/values-es/translations.xml index 6d2ca8df2d..716e3ed32a 100644 --- a/features/roomdetails/impl/src/main/res/values-es/translations.xml +++ b/features/roomdetails/impl/src/main/res/values-es/translations.xml @@ -1,19 +1,21 @@ "Necesitarás una dirección de sala para que sea visible en el directorio." - "Dirección de la sala" + "Editar dirección" "Se ha producido un error al actualizar la configuración de notificaciones." "Tu servidor base no admite esta opción en salas cifradas, puede que no recibas notificaciones de algunas salas." "Encuestas" - "Solo administradores" + "Administrador" "Vetar personas" "Eliminar mensajes" - "Invitar personas y aceptar solicitudes de unión" + "Miembro" + "Invitar a otras personas" + "Administrar miembros" "Mensajes y contenido" - "Administradores y moderadores" - "Eliminar personas y rechazar solicitudes de unión" + "Moderador" + "Eliminar personas" "Cambiar el avatar de la sala" - "Editar sala" + "Editar detalles" "Cambiar el nombre de la sala" "Cambiar el tema de la sala" "Enviar mensajes" @@ -36,7 +38,7 @@ "Cifrada" "No cifrada" "Sala pública" - "Editar sala" + "Editar detalles" "Se ha producido un error desconocido y no se ha podido cambiar la información." "No se puede actualizar la sala" "Los mensajes están protegidos con \"candados\". Sólo tú y los destinatarios tenéis las llaves únicas para abrirlos." @@ -61,10 +63,10 @@ "Información de la sala" "Tema" "Actualizando la sala…" - "No hay usuarios vetados en esta sala." + "No hay usuarios baneados." - "Una persona" - "%1$d personas" + "%1$d Persona" + "%1$d Personas" "Sacar y vetar a un miembro" "Solo eliminar miembro" @@ -73,8 +75,8 @@ "Eliminar veto en la sala" "Vetados" "Miembros" - "Solo administradores" - "Administradores y moderadores" + "Administrador" + "Moderador" "Miembros de la sala" "Levantando veto a %1$s" "Permitir configuración personalizada" @@ -104,8 +106,9 @@ "Roles" "Detalles de la sala" "Roles y permisos" - "Agregar dirección de sala" - "Cualquiera puede solicitar unirse a la sala, pero un administrador o moderador tendrá que aceptar la solicitud." + "Agregar dirección" + "Todos deben solicitar acceso." + "Solicitar unirse" "Sí, activar cifrado" "Una vez activado, el cifrado de una sala no se puede desactivar. El historial de mensajes solo será visible para los miembros de la sala desde que fueron invitados o desde que se unieron a la sala. Nadie más que los miembros de la sala podrán leer los mensajes. Esto puede impedir que los bots y los puentes funcionen correctamente. @@ -114,19 +117,23 @@ No recomendamos habilitar el cifrado para las salas que cualquiera pueda encontr "Una vez activado, el cifrado no se puede desactivar." "Cifrado" "Activar el cifrado de extremo a extremo" - "Cualquiera puede encontrarla y unirse" - "Las personas solo pueden unirse si están invitadas" + "Cualquiera puede unirse" + "Cualquiera" + "Solo las personas invitadas pueden unirse." "Solo por invitación" - "Acceso a la sala" + "Acceso" "No se admiten los espacios por el momento." "Necesitarás una dirección de sala para que sea visible en el directorio." + "Dirección" "Permite encontrar esta sala buscando en el directorio de salas públicas de %1$s" - "Visible en el directorio de salas públicas" + "Visible en el directorio público" + "Cualquiera (el historial es público)" "Quién puede leer el historial" "Solo participantes desde que fueron invitados" - "Solo participantes desde que se selecciona esta opción" + "Miembros (historia completa)" "Las direcciones de sala son formas de buscar salas y acceder a ellas. Esto también garantiza que puedas compartir fácilmente tu sala con otras personas. Puedes optar por publicar tu sala en el directorio de salas públicas de tu servidor base." "Publicación de la sala" + "Visibilidad" "Seguridad y privacidad" diff --git a/features/roomdetails/impl/src/main/res/values-fi/translations.xml b/features/roomdetails/impl/src/main/res/values-fi/translations.xml index 8afb161bd5..110790fac1 100644 --- a/features/roomdetails/impl/src/main/res/values-fi/translations.xml +++ b/features/roomdetails/impl/src/main/res/values-fi/translations.xml @@ -1,5 +1,8 @@ + "Uudet jäsenet eivät näe historiaa" + "Uudet jäsenet näkevät historian" + "Kuka tahansa voi nähdä historian" "Tarvitset osoitteen, jotta se näkyy julkisessa hakemistossa." "Muokkaa osoitetta" "Ilmoitusasetusten muokkaamisessa tapahtui virhe." @@ -9,11 +12,11 @@ "Porttikieltojen antaminen" "Viestien poistaminen" "Jäsen" - "Ihmisten kutsuminen ja liittymispyyntöjen hyväksyminen" - "Jäsenien hallinta" + "Kutsujen antaminen" + "Jäsenien hallitseminen" "Viestit ja sisältö" "Valvoja" - "Henkilöiden poistaminen ja liittymispyyntöjen hylkääminen" + "Henkilöiden poistaminen" "Huoneen avatarin vaihtaminen" "Muokkaa tietoja" "Huoneen nimen vaihtaminen" @@ -63,6 +66,7 @@ "Profiili" "Liittymispyynnöt" "Roolit ja oikeudet" + "Nimi" "Turvallisuus ja yksityisyys" "Turvallisuus" "Jaa huone" @@ -70,6 +74,12 @@ "Aihe" "Muokataan huonetta…" "Porttikiellettyjä käyttäjiä ei ole." + + "%1$d porttikielletty" + "%1$d porttikiellettyä" + + "Tarkista oikeinkirjoitus tai kokeile uutta hakua" + "Ei tuloksia haulle \"%1$s\"" "%1$d henkilö" "%1$d henkilöä" @@ -81,6 +91,11 @@ "Poista porttikielto huoneesta" "Porttikiellot" "Jäsenet" + + "%1$d kutsuttu" + "%1$d kutsuttua" + + "Kutsuttu" "Ylläpitäjä" "Valvoja" "Omistaja" @@ -117,8 +132,10 @@ "Huoneen tiedot" "Roolit ja oikeudet" "Lisää osoite" + "Kuka tahansa valtuutetuissa tiloissa voi liittyä, mutta kaikkien muiden on pyydettävä pääsyä." "Kaikkien on pyydettävä pääsyä." "Pyydä liittymistä" + "Kuka tahansa tilassa %1$s voi liittyä, mutta kaikkien muiden on pyydettävä pääsyä." "Kyllä, ota salaus käyttöön" "Kun salaus on kerran otettu käyttöön, sitä ei voi poistaa käytöstä. Viestihistoria näkyy vain huoneen jäsenille kutsusta tai liittymisestä lähtien. Kukaan muu kuin huoneen jäsenet eivät pysty lukemaan viestejä. Tämä voi estää botteja tai siltoja toimimasta oikein. @@ -129,22 +146,29 @@ Emme suosittele salauksen ottamista käyttöön huoneissa, jotka kuka tahansa vo "Ota päästä päähän -salaus käyttöön" "Kuka tahansa voi liittyä." "Kuka tahansa" + "Valitse, minkä tilojen jäsenet voivat liittyä tähän huoneeseen ilman kutsua. %1$s" + "Hallitse tiloja" "Vain kutsutut henkilöt voivat liittyä." "Vain kutsutut" "Pääsy" + "Kuka tahansa valtuutetuissa tiloissa voi liittyä." + "Kuka tahansa tilassa %1$s voi liittyä." + "Tilan jäsenet" "Tiloja ei tällä hetkellä tueta" "Tarvitset osoitteen, jotta se näkyy julkisessa hakemistossa." "Osoite" "Salli tämän huoneen löytäminen hakemalla %1$s -palvelimen julkisesta huonehakemistosta." "Anna muiden löytää tämä julkisen hakemiston kautta." - "Näkyy julkisessa hakemistossa" - "Kuka tahansa" + "Näytä julkisessa hakemistossa" + "Kuka tahansa (historia on julkinen)" + "Muutokset eivät vaikuta aiempiin viesteihin, vain uusiin. %1$s" "Kuka voi lukea viestihistoriaa" - "Jäsenet vasta kutsusta lähtien" + "Jäsenet kutsusta lähtien" "Jäsenet (koko historia)" "Huoneosoitteet ovat tapoja löytää ja käyttää huoneita. Näin voit myös helposti jakaa huoneesi muiden kanssa. Voit halutessasi julkaista huoneesi kotipalvelimesi julkisessa huonehakemistossa." "Huoneen julkaiseminen" + "Osoitteiden avulla voit löytää ja liittyä huoneisiin ja tiloihin. Tämä varmistaa myös, että voit helposti jakaa ne muiden kanssa." "Näkyvyys" "Turvallisuus ja yksityisyys" diff --git a/features/roomdetails/impl/src/main/res/values-fr/translations.xml b/features/roomdetails/impl/src/main/res/values-fr/translations.xml index b3568aff21..0fad68c934 100644 --- a/features/roomdetails/impl/src/main/res/values-fr/translations.xml +++ b/features/roomdetails/impl/src/main/res/values-fr/translations.xml @@ -35,7 +35,7 @@ "Les administrateurs ont automatiquement les privilèges des modérateurs" "Les propriétaires disposent automatiquement des privilèges des administrateurs." "Modifier les modérateurs" - "Choisissez les propriétaires" + "Choisir les propriétaires" "Administrateurs" "Modérateurs" "Membres" diff --git a/features/roomdetails/impl/src/main/res/values-hu/translations.xml b/features/roomdetails/impl/src/main/res/values-hu/translations.xml index 285ddcb13f..1dc523f319 100644 --- a/features/roomdetails/impl/src/main/res/values-hu/translations.xml +++ b/features/roomdetails/impl/src/main/res/values-hu/translations.xml @@ -1,5 +1,8 @@ + "Az új tagok nem látják az előzményeket" + "Az új tagok látják az előzményeket" + "Bárki láthatja az előzményeket" "Szüksége lesz egy szobacímre, hogy láthatóvá tegye a szobakatalógusban." "Cím szerkesztése" "Hiba történt az értesítési beállítás frissítésekor." @@ -150,6 +153,7 @@ Nem javasoljuk a titkosítás engedélyezését az olyan szobákban, amelyeket b "Hozzáférés" "Bárki csatlakozhat, az engedélyezett terekből." "Bárki csatlakozhatnak innen: %1$s." + "A tér tagjai" "A terek jelenleg nem támogatottak" "Szüksége lesz egy szobacímre, hogy láthatóvá tegye a szobakatalógusban." "Cím" diff --git a/features/roomdetails/impl/src/main/res/values-nb/translations.xml b/features/roomdetails/impl/src/main/res/values-nb/translations.xml index cc9b22517d..e522f5cd79 100644 --- a/features/roomdetails/impl/src/main/res/values-nb/translations.xml +++ b/features/roomdetails/impl/src/main/res/values-nb/translations.xml @@ -1,5 +1,8 @@ + "Nye medlemmer ser ikke historikken" + "Nye medlemmer ser historikk" + "Alle kan se historikk" "Du trenger en adresse for å gjøre den synlig i den offentlige katalogen." "Rediger adresse" "Det oppstod en feil under oppdatering av varslingsinnstillingen." @@ -143,12 +146,14 @@ Vi anbefaler ikke å aktivere kryptering for rom som hvem som helst kan finne og "Aktiver ende-til-ende-kryptering" "Alle kan bli med." "Hvem som helst" + "Velg hvilke av områdets medlemmer som kan bli med i dette rommet uten invitasjon. %1$s" "Administrer områder" "Bare inviterte personer kan bli med." "Kun for inviterte" "Tilgang" "Alle i autoriserte områder kan bli med." "Alle i %1$s kan bli med." + "Medlemmer av område" "Områder støttes ikke for øyeblikket" "Du trenger en adresse for å gjøre den synlig i den offentlige katalogen." "Adresse" diff --git a/features/roomdetails/impl/src/main/res/values-nl/translations.xml b/features/roomdetails/impl/src/main/res/values-nl/translations.xml index f6655f690d..9234921c35 100644 --- a/features/roomdetails/impl/src/main/res/values-nl/translations.xml +++ b/features/roomdetails/impl/src/main/res/values-nl/translations.xml @@ -45,6 +45,7 @@ "Mensen uitnodigen" "Gesprek verlaten" "Kamer verlaten" + "Media en bestanden" "Aangepast" "Standaard" "Meldingen" 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 0646f55709..ddbbe0f601 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 @@ -142,6 +142,7 @@ Não recomendamos que você ative a criptografia para salas que qualquer pessoa "Criptografia" "Ativar a criptografia de ponta a ponta" "Qualquer um pode entrar" + "Público" "Escolha os espaços dos quais os membros podem entrar nesta sala sem um convite. %1$s" "Gerenciar espaços" "Apenas pessoas convidadas podem entrar." diff --git a/features/roomdetails/impl/src/main/res/values-ru/translations.xml b/features/roomdetails/impl/src/main/res/values-ru/translations.xml index ca00b07e0a..52b5c7969f 100644 --- a/features/roomdetails/impl/src/main/res/values-ru/translations.xml +++ b/features/roomdetails/impl/src/main/res/values-ru/translations.xml @@ -152,6 +152,8 @@ "Только по приглашению" "Доступ" "Любой человек в авторизованных пространствах может присоединиться." + "Любой в %1$s может присоединиться." + "Участники пространства" "Пространства в настоящее время не поддерживаются." "Вам понадобится адрес комнаты, чтобы сделать ее видимой в каталоге." "Адрес" 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 1495809432..1a0e2a8735 100644 --- a/features/roomdetails/impl/src/main/res/values-sv/translations.xml +++ b/features/roomdetails/impl/src/main/res/values-sv/translations.xml @@ -1,6 +1,6 @@ - "Du behöver en rumsadress för att göra den synlig i katalogen." + "Du behöver en adress för att göra den synlig i den offentliga katalogen." "Redigera adress" "Ett fel uppstod vid uppdatering av aviseringsinställningen." "Din hemserver stöder inte det här alternativet i krypterade rum, du kanske inte aviseras i vissa rum." @@ -130,7 +130,7 @@ Vi rekommenderar inte att aktivera kryptering för rum som vem som helst kan hit "Endast inbjudan" "Åtkomst" "Utrymmen stöds för närvarande inte" - "Du behöver en rumsadress för att göra den synlig i katalogen." + "Du behöver en adress för att göra den synlig i den offentliga katalogen." "Adress" "Tillåt att detta rum hittas genom att söka i den offentliga rumskatalogen på %1$s" "Synlig i offentliga katalogen" diff --git a/features/roomdetails/impl/src/main/res/values-tr/translations.xml b/features/roomdetails/impl/src/main/res/values-tr/translations.xml index 2211455333..16137ce753 100644 --- a/features/roomdetails/impl/src/main/res/values-tr/translations.xml +++ b/features/roomdetails/impl/src/main/res/values-tr/translations.xml @@ -20,6 +20,7 @@ "Yöneticileri Düzenle" "Bu eylemi geri alamazsınız. Kullanıcıyı sizinle aynı güç seviyesine sahip olacak şekilde terfi ettiriyorsunuz." "Yönetici Ekle?" + "Bu işlemi geri alamazsınız. Sahipliği seçilen kullanıcılara devrediyorsunuz. Ayrıldıktan sonra bu işlem kalıcı olacaktır." "Rütbe Düşür" "Rütbenizi düşürdüğünüz için bu değişikliği geri alamazsınız, eğer odadaki son ayrıcalıklı kullanıcı sizseniz ayrıcalıkları yeniden kazanmanız mümkün olmayacaktır." "Rütbeni düşür?" @@ -44,7 +45,7 @@ "Bildirim ayarları yüklenirken bir hata oluştu." "Bu odayı sessize alma başarısız oldu, lütfen tekrar deneyin." "Bu odanın sesi açılamadı, lütfen tekrar deneyin." - "İnsanları davet et" + "Kişileri davet et" "Sohbeti bırak" "Odadan ayrıl" "Medya ve dosyalar" @@ -62,6 +63,8 @@ "Konu" "Oda güncelleniyor…" "Bu odada yasaklı kullanıcı yok." + "Metni kontrol edin ya da yeni bir arama yapmayı deneyin." + "“%1$s” için sonuç bulunamadı" "%1$d kişi" "%1$d kişi" @@ -72,6 +75,11 @@ "Davet edildikleri takdirde bu odaya tekrar katılabileceklerdir." "Yasaklandı" "Üyeler" + + "%1$d Davetli" + "%1$d Davetli" + + "Beklemede" "Yalnızca yöneticiler" "Yöneticiler ve moderatörler" "Oda üyeleri" @@ -97,6 +105,7 @@ "Üye moderasyonu" "Mesajlar ve içerik" "Moderatörler" + "İzinler" "İzinleri sıfırla" "İzinleri sıfırladığınızda, mevcut ayarları kaybedersiniz." "İzinleri sıfırla?" @@ -104,8 +113,10 @@ "Oda bilgileri" "Roller ve izinler" "Oda adresi ekle" + "Yetkilendirilmiş alanlardaki herkes katılabilir, diğer herkes erişim talep etmelidir." "Herkes odaya katılma isteğinde bulunabilir ancak bir yönetici veya moderatörün isteği kabul etmesi gerekir." "Katılma isteği gönder" + "%1$s alanındaki herkes katılabilir, diğer herkes erişim talep etmelidir." "Evet, şifrelemeyi etkinleştir" "Etkinleştirildikten sonra, bir oda için şifreleme devre dışı bırakılamaz, Mesaj geçmişi yalnızca davet edildiklerinden veya odaya katıldıklarından beri oda üyeleri için görünür olacaktır. Oda üyeleri dışında hiç kimse mesajları okuyamayacaktır. Bu, botların ve köprülerin düzgün çalışmasını engelleyebilir. @@ -116,21 +127,28 @@ Herkesin bulabileceği ve katılabileceği odalar için şifrelemenin etkinleşt "Uçtan uca şifrelemeyi etkinleştir" "Herkes bulabilir ve katılabilir" "Herkes" + "Davetsiz olarak bu odaya katılabilecek alan üyelerini seçin. %1$s" + "Alanları yönet" "İnsanlar yalnızca davet edildiklerinde katılabilirler" "Yalnızca davet" "Oda Erişimi" + "Yetkilendirilmiş alanlardaki herkes katılabilir." + "%1$s alanındaki herkes katılabilir." "Alanlar şu anda desteklenmiyor" "Dizinde görünür hale getirmek için bir oda adresine ihtiyacınız olacak." "Oda adresi" "Bu odanın %1$s genel oda dizininde arama yapılarak bulunmasına izin verin" + "Genel dizinde arama yapılarak bulunmasına izin ver." "Genel oda dizininde görünür" "Herkes" + "Değişiklikler geçmiş mesajları etkilemez, yalnızca yeni mesajlar için geçerlidir. %1$s" "Geçmişi kimler okuyabilir ?" - "Sadece üyeler (davet edildiklerinden beri)" + "Sadece üyeler (davet edildiklerinden itibaren)" "Bu seçeneği seçtiğinden beri yalnızca üyeler" "Oda adresleri, odaları bulmanın ve odalara erişmenin yoludur. Bu aynı zamanda odanızı başkalarıyla kolayca paylaşabilmenizi sağlar. Odanızı ana sunucunuzun genel oda dizininde yayınlamayı seçebilirsiniz." "Oda yayınlama" + "Adresler, oda ve alanları bulmak ve erişmek için kullanılır. Ayrıca bunları başkalarıyla kolayca paylaşabilmenizi sağlar." "Oda görünürlüğü" "Güvenlik ve gizlilik" diff --git a/features/roomdetails/impl/src/main/res/values-uz/translations.xml b/features/roomdetails/impl/src/main/res/values-uz/translations.xml index 2a3f694969..645c6725ac 100644 --- a/features/roomdetails/impl/src/main/res/values-uz/translations.xml +++ b/features/roomdetails/impl/src/main/res/values-uz/translations.xml @@ -5,14 +5,15 @@ "Bildirishnoma sozlamalarini yangilashda xatolik yuz berdi." "Uy serveringiz shifrlangan xonalarda ushbu imkoniyatni qoʻllab-quvvatlamaydi, shuning uchun baʼzi xonalardagi xabarlarni olmasligingiz mumkin." "Soʻrovnomalar" - "Faqat adminlar" + "Admin" "Odamlarni taqiqlash" "Xabarlarni olib tashlash" + "A\'zo" "Odamlarni taklif qiling va qo‘shilish so‘rovlarini qabul qiling" "A’zolarni boshqarish" "Xabarlar va kontent" - "Adminlar va moderatorlar" - "Odamlarni olib tashlash va qoʻshilish soʻrovlarini rad etish" + "Moderator" + "Odamlarni olib tashlash" "Xona avatarini oʻzgartirish" "Tafsilotlarni tahrirlash" "Xona nomini oʻzgartirish" @@ -49,6 +50,8 @@ "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." + "Tugallanmaguncha ilovani yopmang." + "Taklifnomalar tayyorlanmoqda…" "Odamlarni taklif qiling" "Suhbatni tark etish" "Xonani tark etish" @@ -60,13 +63,20 @@ "Profil" "Qo‘shilish uchun so‘rovlar" "Rollar va ruxsatlar" + "Ism" "Xavfsizlik va maxfiylik" "Xavfsizlik" "Xonani baham ko\'ring" "Xona haqida maʼlumot" "Mavzu" "Xona yangilanmoqda…" - "Bu xonada taqiqlangan foydalanuvchilar yoʻq." + "Taqiqlangan foydalanuvchilar yoʻq." + + "%1$dTaqiqlangan" + "%1$dTaqiqlangan" + + "Imloni tekshiring yoki yangi qidiruvni sinang" + "%1$s – hech narsa topilmadi" "%1$dodam" "%1$dodamlar" @@ -78,8 +88,13 @@ "Xonadan taqiqni olib tashlash" "Taqiqlangan" "Azolar" - "Faqat adminlar" - "Adminlar va moderatorlar" + + "%1$d Taklif qilingan" + "%1$d Taklif qilingan" + + "Jarayonda" + "Admin" + "Moderator" "Egasi" "Xona a\'zolari" "Taqiqni bekor qilish %1$s" @@ -106,6 +121,7 @@ "Xabarlar va kontent" "Moderatorlar" "Egalari" + "Ruxsatlar" "Ruxsatlarni tiklash" "Ruxsatlarni asliga qaytargach, joriy sozlamalarni yoʻqotasiz." "Ruxsatlar asliga qaytarilsinmi?" @@ -113,7 +129,9 @@ "Xona tafsilotlari" "Rollar va ruxsatlar" "Xona manzilini kiritish" + "Vakolatli guruhlardagi har kim qo‘shilishi mumkin, lekin qolganlar ruxsat so‘rashi kerak. Tarjima eslatmasi yo‘q" "Xonaga qo‘shilishni istalgan kishi so‘rashi mumkin, lekin administrator yoki moderator so‘rovni qabul qilishi kerak" + "%1$s ichidagi istalgan kishi qo‘shilishi mumkin, lekin qolganlar ruxsat so‘rashi kerak." "Ha, shifrlashni yoqish" "Yoqilgandan so‘ng, xona uchun shifrlashni o‘chirib bo‘lmaydi. Xabarlar tarixi faqat xona a’zolari taklif qilinganidan yoki xonaga qo‘shilganidan keyingi davrdan boshlab ko‘rinadi. Xona a’zolaridan tashqari hech kim xabarlarni o‘qiy olmaydi. Bu botlar va ko‘priklarning to‘g‘ri ishlashiga to‘sqinlik qilishi mumkin. Shu sababli, har kim topishi va qo‘shilishi mumkin bo‘lgan xonalar uchun shifrlashni yoqishni tavsiya etmaymiz." @@ -122,12 +140,18 @@ Shu sababli, har kim topishi va qo‘shilishi mumkin bo‘lgan xonalar uchun shi "Shifrlash" "End-to-end shifrlashni yoqish" "Istalgan kishi topishi va qo‘shilishi mumkin" + "Qaysi maydonlar a’zolari bu xonaga taklifnomalarsiz kirishi mumkinligini tanlang. %1$s" + "Maydonlarni boshqarish" "Odamlar faqat taklif qilingan taqdirdagina qo‘shilishi mumkin" "Faqat taklif qilish" "Xonaga kirish huquqi" + "Ruxsat berilgan maydonlardagi istalgan kishi qo‘shilishi mumkin." + "%1$s ichidagi istalgan kishi qo‘shilishi mumkin." "Hozirda maydonlar qo‘llab-quvvatlanmaydi" "Katalogda ko‘rinadigan qilish uchun xona manzili kerak bo‘ladi." + "Manzil" "Bu xonani %1$s umumiy xonalar ro‘yxatidan qidirib topish imkoniyatini berish" + "Umumiy katalogni qidirish orqali topishga ruxsat bering." "Umumiy xona ro‘yxatida ko‘rinadi" "Tarixni kim o‘qiy oladi" "Taklif qilinganidan buyon faqat a’zolar" @@ -135,5 +159,7 @@ Shu sababli, har kim topishi va qo‘shilishi mumkin bo‘lgan xonalar uchun shi "Xona manzillari xonalarni topish va ularga kirish usullaridir. Bu shuningdek xonangizni boshqalar bilan oson ulashish imkonini beradi. Xonangizni o‘z homeserveringizning ommaviy xonalar ro‘yxatida e’lon qilishni tanlashingiz mumkin." "xona nashriyoti" + "Manzillar xona va maydonlarni topish va ularga kirish usulidir. Bu, shuningdek, ularni boshqalar bilan osongina bo‘lishishingizni ta’minlaydi." + "Ko‘rinish" "Xavfsizlik va maxfiylik" diff --git a/features/roomdetails/impl/src/main/res/values-zh/translations.xml b/features/roomdetails/impl/src/main/res/values-zh/translations.xml index e36efcdcb2..4101f67260 100644 --- a/features/roomdetails/impl/src/main/res/values-zh/translations.xml +++ b/features/roomdetails/impl/src/main/res/values-zh/translations.xml @@ -1,19 +1,24 @@ - "你需要房间地址才能使其在目录中可见。" - "房间地址" + "新成员无法查看历史记录" + "新成员可见历史记录" + "任何人都能查看历史记录" + "您需要一个地址才能在公共目录中显示。" + "编辑地址" "更新通知设置时出错。" "服务器在加密聊天室中不支持此选项,因此在某些聊天室可能无法收到通知。" "投票" - "仅限管理员" + "管理员" "封禁成员" "移除消息" - "邀请他人及接受加入请求" + "成员" + "邀请人员" + "管理成员" "消息和内容" - "管理员和协管员" - "移除成员及拒绝加入请求" + "协管员" + "移除人员" "更改聊天室头像" - "编辑聊天室" + "编辑详情" "更改聊天室名称" "更改聊天室主题" "发送消息" @@ -26,7 +31,7 @@ "您正在降级,此更改将无法撤消。如果您是聊天室中的最后一个特权用户,则无法重新获得权限。" "降级自己?" "%1$s(待处理)" - "(已邀请)" + "(待处理)" "管理员自动拥有协管员权限" "所有者自动拥有管理员权限。" "编辑协管员" @@ -40,7 +45,7 @@ "加密的" "未加密的" "公共聊天室" - "编辑聊天室" + "编辑详情" "出现未知错误,无法更改信息。" "无法更新聊天室" "消息已加密,只有你和消息接收者拥有唯一解密密钥。" @@ -61,6 +66,7 @@ "个人资料" "申请加入" "角色与权限" + "名称" "安全与隐私" "安全" "分享聊天室" @@ -68,8 +74,13 @@ "主题" "正在更新聊天室……" "没有被封禁的用户。" + + "%1$d 被禁用" + + "检查拼写或尝试新搜索" + "未找到 “%1$s” 相关结果" - "%1$d 人" + "%1$d 个人" "移除并封禁成员" "仅移除成员" @@ -78,8 +89,12 @@ "从房间取消解封" "已封禁用户" "成员" - "仅限管理员" - "管理员和协管员" + + "%1$d 受邀" + + "待处理" + "管理员" + "协管员" "所有者" "聊天室成员" "解除封禁 %1$s" @@ -106,15 +121,18 @@ "消息和内容" "协管员" "所有者" + "权限" "重置权限" "重置权限后,您将丢失当前设置。" "重置权限?" "角色" "聊天室详情" "角色与权限" - "添加房间地址" - "任何人都可以请求加入房间,但必须由管理员或版主接受请求。" + "添加地址" + "授权空间内任何成员均可加入,其他人员需申请访问权限。" + "所有用户均需申请访问权限。" "请求加入" + "%1$s 成员可自由加入,其他人员需申请访问权限。" "是的,启用加密" "一旦启用,就不能再禁用房间的加密功能。消息历史记录只能在房间成员被邀请或加入房间后才可见。 除房间成员外,任何人都无法阅读信息。这可能会妨碍机器人和网桥正常工作。 @@ -123,23 +141,31 @@ "加密一旦启用,就无法禁用。" "加密" "启用端到端加密" - "任何人都可以找到并加入" + "任何人都可以加入。" "任何人" - "只有受邀者才能加入" - "仅限邀请" - "房间访问权限" + "选择哪些空间的成员无需邀请即可加入本聊天室。%1$s" + "管理空间" + "仅限受邀者加入。" + "仅限受邀者" + "访问权限" + "任何位于已授权空间的成员均可加入。" + "%1$s 中的任何人都可加入。" + "空间成员" "目前不支持空间" - "你需要房间地址才能使其在目录中可见。" - "房间地址" + "您需要一个地址才能在公共目录中显示。" + "地址" "允许通过搜索 %1$s 的公共房间目录来发现此房间" - "在公共房间目录中可见" - "任何人" + "通过公共目录搜索功能实现可被发现性。" + "在公共目录中可见" + "任何人(历史记录公开)" + "更改不会影响之前的消息,只会影响新消息。%1$s" "谁可以读取历史记录" - "仅限被邀请的成员" - "仅自选择此选项以来的成员" + "自受邀以来的成员" + "成员(完整历史记录)" "房间地址是查找和访问房间的方式。这也确保你可以轻松地向他人分享房间。 你可以选择在你服务器的公共房间目录中发布你的房间。" "房间发布" - "房间可见性" + "地址是查找和访问聊天室及空间的途径,同时确保您能轻松与他人共享。" + "可见性" "安全与隐私" diff --git a/features/roomdetailsedit/impl/src/main/res/values-bg/translations.xml b/features/roomdetailsedit/impl/src/main/res/values-bg/translations.xml index 787110dc79..4a2cff5b41 100644 --- a/features/roomdetailsedit/impl/src/main/res/values-bg/translations.xml +++ b/features/roomdetailsedit/impl/src/main/res/values-bg/translations.xml @@ -1,6 +1,6 @@ - "Редактиране на стаята" + "Редактиране на подробностите" "Възникна неизвестна грешка и информацията не можа да бъде променена." "Не може да се обнови стаята" "Обновяване на стаята…" diff --git a/features/roomdetailsedit/impl/src/main/res/values-el/translations.xml b/features/roomdetailsedit/impl/src/main/res/values-el/translations.xml index c783ab1d86..cbb50dd8c5 100644 --- a/features/roomdetailsedit/impl/src/main/res/values-el/translations.xml +++ b/features/roomdetailsedit/impl/src/main/res/values-el/translations.xml @@ -1,6 +1,6 @@ - "Επεξεργασία Αίθουσας" + "Επεξεργασία λεπτομερειών" "Υπήρξε ένα άγνωστο σφάλμα και οι πληροφορίες δεν μπορούσαν να αλλάξουν." "Αδυναμία ενημέρωσης αίθουσας" "Ενημέρωση αίθουσας…" diff --git a/features/roomdetailsedit/impl/src/main/res/values-es/translations.xml b/features/roomdetailsedit/impl/src/main/res/values-es/translations.xml index 45e1d81df9..d45082c36c 100644 --- a/features/roomdetailsedit/impl/src/main/res/values-es/translations.xml +++ b/features/roomdetailsedit/impl/src/main/res/values-es/translations.xml @@ -1,6 +1,6 @@ - "Editar sala" + "Editar detalles" "Se ha producido un error desconocido y no se ha podido cambiar la información." "No se puede actualizar la sala" "Actualizando la sala…" diff --git a/features/roomdetailsedit/impl/src/main/res/values-zh/translations.xml b/features/roomdetailsedit/impl/src/main/res/values-zh/translations.xml index 6b174fcb2c..cf7abd7cc8 100644 --- a/features/roomdetailsedit/impl/src/main/res/values-zh/translations.xml +++ b/features/roomdetailsedit/impl/src/main/res/values-zh/translations.xml @@ -1,6 +1,6 @@ - "编辑聊天室" + "编辑详情" "出现未知错误,无法更改信息。" "无法更新聊天室" "正在更新聊天室……" diff --git a/features/roommembermoderation/impl/src/main/res/values-el/translations.xml b/features/roommembermoderation/impl/src/main/res/values-el/translations.xml index 89bf97f4d2..e2047232ed 100644 --- a/features/roommembermoderation/impl/src/main/res/values-el/translations.xml +++ b/features/roommembermoderation/impl/src/main/res/values-el/translations.xml @@ -4,12 +4,14 @@ "Αποκλεισμός" "Δεν θα μπορούν να ενταχθούν ξανά σε αυτή την αίθουσα, αν προσκληθούν." "Θες σίγουρα να αποκλείσεις αυτό το μέλος;" + "Δεν θα μπορούν να ενταχθούν ξανά σε αυτόν τον χώρο αν προσκληθούν, αλλά θα διατηρήσουν τη συμμετοχή τους σε οποιαδήποτε αίθουσα ή υποχώρο." "Αποκλεισμός %1$s" "Αφαίρεση" "Θα μπορούν να συμμετάσχουν ξανά σε αυτή την αίθουσα, εάν προσκληθούν." "Είστε βέβαιοι ότι θέλετε να αφαιρέσετε αυτό το μέλος;" + "Θα μπορούν να ενταχθούν ξανά σε αυτόν τον χώρο εάν προσκληθούν και θα διατηρήσουν τη συμμετοχή τους σε οποιαδήποτε αίθουσα ή υποχώρο." "Προβολή προφίλ" - "Αφαίρεση από την αίθουσα" + "Αφαίρεση χρήστη" "Αφαίρεση μέλους και απαγόρευση συμμετοχής στο μέλλον;" "Αφαίρεση %1$s…" "Άρση αποκλεισμού από την αίθουσα" diff --git a/features/roommembermoderation/impl/src/main/res/values-tr/translations.xml b/features/roommembermoderation/impl/src/main/res/values-tr/translations.xml index a63e4eb55d..8da5f9cb43 100644 --- a/features/roommembermoderation/impl/src/main/res/values-tr/translations.xml +++ b/features/roommembermoderation/impl/src/main/res/values-tr/translations.xml @@ -4,8 +4,11 @@ "Yasakla" "Davet edilseler bile bu odaya tekrar katılamazlar." "Bu üyeyi yasaklamak istediğinize emin misiniz?" + "Davet edilseler bile bu alana tekrar katılamazlar, ancak diğer oda veya alt alan üyelikleri korunur." "Yasaklanıyor %1$s" "Davet edildikleri takdirde bu odaya tekrar katılabileceklerdir." + "Bu üyeyi kaldırmak istediğinizden emin misiniz?" + "Davet edilirse bu alana tekrar katılabilir ve diğer oda veya alt alan üyelikleri korunur." "Profili görüntüle" "Odadan çıkar" "Üyeyi çıkarın ve gelecekte katılmasını yasaklayın?" diff --git a/features/roommembermoderation/impl/src/main/res/values-uz/translations.xml b/features/roommembermoderation/impl/src/main/res/values-uz/translations.xml index 9b8c57ede3..339c26810a 100644 --- a/features/roommembermoderation/impl/src/main/res/values-uz/translations.xml +++ b/features/roommembermoderation/impl/src/main/res/values-uz/translations.xml @@ -4,10 +4,12 @@ "Taqiqlash" "Taklif qilingan taqdirda ham, ular bu xonaga boshqa qo‘shila olmaydilar." "Haqiqatan ham bu aʼzoni taqiqlamoqchimisiz?" + "Agar taklif qilinsa, ular bu maydonga qayta qo‘shila olmaydi, lekin ular har qanday xona yoki kichik maydonlarga a’zoligini saqlab qoladi." "Taqiqlash %1$s" "Oʻchirish" "Agar taklif qilinsa, ular bu xonaga qayta qo‘shilishlari mumkin." "Haqiqatan ham bu a’zoni olib tashlaysizmi?" + "Agar taklif qilinsa, ular bu maydonga qayta qo‘shilishlari mumkin va ular har qanday xona yoki kichik maydonlarga a’zoligini saqlab qoladi." "Profilni koʻrish" "Foydalanuvchini olib tashlash" "Aʻzo oʻchirilsinmi va kelgusida qoʻshilish taqiqlansinmi?" diff --git a/features/securityandprivacy/impl/src/main/res/values-be/translations.xml b/features/securityandprivacy/impl/src/main/res/values-be/translations.xml new file mode 100644 index 0000000000..45ca9760ac --- /dev/null +++ b/features/securityandprivacy/impl/src/main/res/values-be/translations.xml @@ -0,0 +1,4 @@ + + + "Вашы прасторы" + diff --git a/features/securityandprivacy/impl/src/main/res/values-bg/translations.xml b/features/securityandprivacy/impl/src/main/res/values-bg/translations.xml index 510e1cbf22..34e8ea10c1 100644 --- a/features/securityandprivacy/impl/src/main/res/values-bg/translations.xml +++ b/features/securityandprivacy/impl/src/main/res/values-bg/translations.xml @@ -1,19 +1,19 @@ - "Добавяне на адрес на стаята" + "Добавяне на адрес" "Да, включване на шифроването" "Да се включи ли шифроването?" "Веднъж включено, шифроването не може да бъде изключено." "Шифроване" "Включване на шифроване от край до край" - "Всеки може да намери и да се присъедини" - "Хората могат да се присъединят само ако са поканени" + "Всеки може да се присъедини." + "Само поканени хора могат да се присъединят." "Само с покана" - "Достъп до стаята" + "Достъп" "Пространствата в момента не се поддържат" - "Видима в директорията на обществените стаи" + "Видима в обществената директория" "Кой може да чете историята" - "Само за членове откакто са поканени" - "Само за членове от избирането на тази опция" + "Членове откакто са поканени" + "Членове (пълната история)" "Защита и поверителност" diff --git a/features/securityandprivacy/impl/src/main/res/values-da/translations.xml b/features/securityandprivacy/impl/src/main/res/values-da/translations.xml index 4c8b155584..2eff2662d1 100644 --- a/features/securityandprivacy/impl/src/main/res/values-da/translations.xml +++ b/features/securityandprivacy/impl/src/main/res/values-da/translations.xml @@ -29,6 +29,7 @@ Vi anbefaler ikke at aktivere kryptering for rum, som alle kan finde og deltage "Adgang" "Alle i autoriserede grupper kan deltage." "Alle i %1$s kan deltage." + "Medlemmer af rummet" "Grupper understøttes ikke i øjeblikket" "Du skal bruge en adresse for at gøre det synligt i det offentlige register." "Adresse" diff --git a/features/securityandprivacy/impl/src/main/res/values-el/translations.xml b/features/securityandprivacy/impl/src/main/res/values-el/translations.xml index 7ef6f168c6..dfbf4e075c 100644 --- a/features/securityandprivacy/impl/src/main/res/values-el/translations.xml +++ b/features/securityandprivacy/impl/src/main/res/values-el/translations.xml @@ -1,10 +1,17 @@ - "Θα χρειαστείτε μια διεύθυνση αίθουσας για να την κάνετε ορατή στον κατάλογο." - "Διεύθυνση αίθουσας" - "Προσθήκη διεύθυνσης αίθουσας" - "Οποιοσδήποτε μπορεί να ζητήσει να συμμετάσχει στην αίθουσα, αλλά ένας διαχειριστής ή συντονιστής θα πρέπει να αποδεχτεί το αίτημα." + "Θα χρειαστείτε μια διεύθυνση για να την κάνετε ορατή στον δημόσιο κατάλογο." + "Επεξεργασία διεύθυνσης" + "Χώροι όπου τα μέλη μπορούν να συμμετάσχουν στην αίθουσα χωρίς πρόσκληση." + "Διαχείριση χώρων" + "(Άγνωστος χώρος)" + "Άλλοι χώροι στους οποίους δεν είστε μέλος" + "Οι χώροι σας" + "Προσθήκη διεύθυνσης" + "Οποιοσδήποτε σε εξουσιοδοτημένους χώρους μπορεί να συμμετάσχει, αλλά όλοι οι άλλοι πρέπει να ζητήσουν πρόσβαση." + "Όλοι πρέπει να αιτούνται πρόσβαση." "Αίτημα συμμετοχής" + "Οποιοσδήποτε στο %1$s μπορεί να συμμετάσχει, αλλά όλοι οι άλλοι πρέπει να ζητήσουν πρόσβαση." "Ναι, ενεργοποιήστε την κρυπτογράφηση" "Μόλις ενεργοποιηθεί, η κρυπτογράφηση για μια αίθουσα δεν μπορεί να απενεργοποιηθεί, το ιστορικό μηνυμάτων θα είναι ορατό μόνο για τα μέλη της αίθουσας από τότε που προσκλήθηκαν ή από τότε που συμμετείχαν στην αίθουσα. Κανείς άλλος εκτός από τα μέλη της αίθουσας δεν θα μπορεί να διαβάσει τα μηνύματα. Αυτό μπορεί να εμποδίσει τη σωστή λειτουργία των bots και των γεφυρών. @@ -13,20 +20,31 @@ "Μόλις ενεργοποιηθεί, η κρυπτογράφηση δεν μπορεί να απενεργοποιηθεί." "Κρυπτογράφηση" "Ενεργοποίηση κρυπτογράφησης από άκρο σε άκρο" - "Οποιοσδήποτε μπορεί να βρει και να συμμετάσχει" + "Οποιοσδήποτε μπορεί να συμμετάσχει." "Οποιοσδήποτε" - "Τα άτομα μπορούν να συμμετάσχουν μόνο εάν έχουν προσκληθεί" - "Μόνο πρόσκληση" - "Πρόσβαση στην αίθουσα" + "Επιλέξτε ποια μέλη των χώρων μπορούν να συμμετάσχουν σε αυτήν την αίθουσα χωρίς πρόσκληση. %1$s" + "Διαχείριση χώρων" + "Μόνο άτομα που έχουν προσκληθεί μπορούν να συμμετάσχουν." + "Μόνο με πρόσκληση" + "Πρόσβαση" + "Οποιοσδήποτε σε εξουσιοδοτημένους χώρους μπορεί να συμμετάσχει." + "Οποιοσδήποτε στο %1$s μπορεί να συμμετάσχει." + "Μέλη χώρου" "Οι χώροι δεν υποστηρίζονται προς το παρόν" - "Θα χρειαστείτε μια διεύθυνση αίθουσας για να την κάνετε ορατή στον κατάλογο." + "Θα χρειαστείτε μια διεύθυνση για να την κάνετε ορατή στον δημόσιο κατάλογο." + "Διεύθυνση" "Επιστρέψτε την εύρεση αυτής της αίθουσας με αναζήτηση στον κατάλογο %1$s δημοσίων αιθουσών" - "Ορατή στον κατάλογο δημόσιων αιθουσών" + "Επιτρέψτε την εύρεσή σας μέσω αναζήτησης στον δημόσιο κατάλογο." + "Ορατό στον δημόσιο κατάλογο" + "Οποιοσδήποτε (το ιστορικό είναι δημόσιο)" + "Οι αλλαγές δεν θα επηρεάσουν τα παλιά μηνύματα, μόνο τα νέα. %1$s" "Ποιος μπορεί να διαβάσει το ιστορικό" - "Μόνο μέλη από τη στιγμή που προσκλήθηκαν" - "Μόνο για μέλη μετά από αυτήν την επιλογή" + "Μέλη από τότε που προσκλήθηκατε" + "Μέλη (πλήρες ιστορικό)" "Οι διευθύνσεις αιθουσών είναι τρόποι εύρεσης και πρόσβασης σε αίθουσες. Αυτό διασφαλίζει επίσης ότι μπορείτε εύκολα να μοιραστείτε την αίθουσα με άλλους. Μπορείτε να επιλέξετε να δημοσιεύσετε την αίθουσά σας στον δημόσιο κατάλογο αιθουσών του αρχικού διακομιστή σας." "Δημοσίευση αίθουσας" + "Οι διευθύνσεις είναι ένας τρόπος για να βρίσκετε και να έχετε πρόσβαση σε αίθουσες και χώρους. Αυτό διασφαλίζει επίσης ότι μπορείτε εύκολα να τις μοιραστείτε με άλλους." + "Ορατότητα" "Ασφάλεια & απόρρητο" diff --git a/features/securityandprivacy/impl/src/main/res/values-es/translations.xml b/features/securityandprivacy/impl/src/main/res/values-es/translations.xml index ebf49d2f07..f7e7812914 100644 --- a/features/securityandprivacy/impl/src/main/res/values-es/translations.xml +++ b/features/securityandprivacy/impl/src/main/res/values-es/translations.xml @@ -1,9 +1,10 @@ "Necesitarás una dirección de sala para que sea visible en el directorio." - "Dirección de la sala" - "Agregar dirección de sala" - "Cualquiera puede solicitar unirse a la sala, pero un administrador o moderador tendrá que aceptar la solicitud." + "Editar dirección" + "Agregar dirección" + "Todos deben solicitar acceso." + "Solicitar unirse" "Sí, activar cifrado" "Una vez activado, el cifrado de una sala no se puede desactivar. El historial de mensajes solo será visible para los miembros de la sala desde que fueron invitados o desde que se unieron a la sala. Nadie más que los miembros de la sala podrán leer los mensajes. Esto puede impedir que los bots y los puentes funcionen correctamente. @@ -12,19 +13,23 @@ No recomendamos habilitar el cifrado para las salas que cualquiera pueda encontr "Una vez activado, el cifrado no se puede desactivar." "Cifrado" "Activar el cifrado de extremo a extremo" - "Cualquiera puede encontrarla y unirse" - "Las personas solo pueden unirse si están invitadas" + "Cualquiera puede unirse" + "Cualquiera" + "Solo las personas invitadas pueden unirse." "Solo por invitación" - "Acceso a la sala" + "Acceso" "No se admiten los espacios por el momento." "Necesitarás una dirección de sala para que sea visible en el directorio." + "Dirección" "Permite encontrar esta sala buscando en el directorio de salas públicas de %1$s" - "Visible en el directorio de salas públicas" + "Visible en el directorio público" + "Cualquiera (el historial es público)" "Quién puede leer el historial" "Solo participantes desde que fueron invitados" - "Solo participantes desde que se selecciona esta opción" + "Miembros (historia completa)" "Las direcciones de sala son formas de buscar salas y acceder a ellas. Esto también garantiza que puedas compartir fácilmente tu sala con otras personas. Puedes optar por publicar tu sala en el directorio de salas públicas de tu servidor base." "Publicación de la sala" + "Visibilidad" "Seguridad y privacidad" diff --git a/features/securityandprivacy/impl/src/main/res/values-fi/translations.xml b/features/securityandprivacy/impl/src/main/res/values-fi/translations.xml index 5e928374e2..fcf8a90ee3 100644 --- a/features/securityandprivacy/impl/src/main/res/values-fi/translations.xml +++ b/features/securityandprivacy/impl/src/main/res/values-fi/translations.xml @@ -2,9 +2,16 @@ "Tarvitset osoitteen, jotta se näkyy julkisessa hakemistossa." "Muokkaa osoitetta" + "Tilat, joihin jäsenet voivat liittyä ilman kutsua." + "Hallitse tiloja" + "(Tuntematon tila)" + "Muut tilat, joiden jäsen et ole" + "Sinun tilasi" "Lisää osoite" + "Kuka tahansa valtuutetuissa tiloissa voi liittyä, mutta kaikkien muiden on pyydettävä pääsyä." "Kaikkien on pyydettävä pääsyä." "Pyydä liittymistä" + "Kuka tahansa tilassa %1$s voi liittyä, mutta kaikkien muiden on pyydettävä pääsyä." "Kyllä, ota salaus käyttöön" "Kun salaus on kerran otettu käyttöön, sitä ei voi poistaa käytöstä. Viestihistoria näkyy vain huoneen jäsenille kutsusta tai liittymisestä lähtien. Kukaan muu kuin huoneen jäsenet eivät pysty lukemaan viestejä. Tämä voi estää botteja tai siltoja toimimasta oikein. @@ -15,22 +22,29 @@ Emme suosittele salauksen ottamista käyttöön huoneissa, jotka kuka tahansa vo "Ota päästä päähän -salaus käyttöön" "Kuka tahansa voi liittyä." "Kuka tahansa" + "Valitse, minkä tilojen jäsenet voivat liittyä tähän huoneeseen ilman kutsua. %1$s" + "Hallitse tiloja" "Vain kutsutut henkilöt voivat liittyä." "Vain kutsutut" "Pääsy" + "Kuka tahansa valtuutetuissa tiloissa voi liittyä." + "Kuka tahansa tilassa %1$s voi liittyä." + "Tilan jäsenet" "Tiloja ei tällä hetkellä tueta" "Tarvitset osoitteen, jotta se näkyy julkisessa hakemistossa." "Osoite" "Salli tämän huoneen löytäminen hakemalla %1$s -palvelimen julkisesta huonehakemistosta." "Anna muiden löytää tämä julkisen hakemiston kautta." - "Näkyy julkisessa hakemistossa" - "Kuka tahansa" + "Näytä julkisessa hakemistossa" + "Kuka tahansa (historia on julkinen)" + "Muutokset eivät vaikuta aiempiin viesteihin, vain uusiin. %1$s" "Kuka voi lukea viestihistoriaa" - "Jäsenet vasta kutsusta lähtien" + "Jäsenet kutsusta lähtien" "Jäsenet (koko historia)" "Huoneosoitteet ovat tapoja löytää ja käyttää huoneita. Näin voit myös helposti jakaa huoneesi muiden kanssa. Voit halutessasi julkaista huoneesi kotipalvelimesi julkisessa huonehakemistossa." "Huoneen julkaiseminen" + "Osoitteiden avulla voit löytää ja liittyä huoneisiin ja tiloihin. Tämä varmistaa myös, että voit helposti jakaa ne muiden kanssa." "Näkyvyys" "Turvallisuus ja yksityisyys" diff --git a/features/securityandprivacy/impl/src/main/res/values-hu/translations.xml b/features/securityandprivacy/impl/src/main/res/values-hu/translations.xml index f0c15b514e..60e2190e84 100644 --- a/features/securityandprivacy/impl/src/main/res/values-hu/translations.xml +++ b/features/securityandprivacy/impl/src/main/res/values-hu/translations.xml @@ -29,6 +29,7 @@ Nem javasoljuk a titkosítás engedélyezését az olyan szobákban, amelyeket b "Hozzáférés" "Bárki csatlakozhat, az engedélyezett terekből." "Bárki csatlakozhatnak innen: %1$s." + "A tér tagjai" "A terek jelenleg nem támogatottak" "Szüksége lesz egy szobacímre, hogy láthatóvá tegye a szobakatalógusban." "Cím" diff --git a/features/securityandprivacy/impl/src/main/res/values-nb/translations.xml b/features/securityandprivacy/impl/src/main/res/values-nb/translations.xml index 75fe9c5f46..0f3f643fd6 100644 --- a/features/securityandprivacy/impl/src/main/res/values-nb/translations.xml +++ b/features/securityandprivacy/impl/src/main/res/values-nb/translations.xml @@ -22,12 +22,14 @@ Vi anbefaler ikke å aktivere kryptering for rom som hvem som helst kan finne og "Aktiver ende-til-ende-kryptering" "Alle kan bli med." "Hvem som helst" + "Velg hvilke av områdets medlemmer som kan bli med i dette rommet uten invitasjon. %1$s" "Administrer områder" "Bare inviterte personer kan bli med." "Kun for inviterte" "Tilgang" "Alle i autoriserte områder kan bli med." "Alle i %1$s kan bli med." + "Medlemmer av område" "Områder støttes ikke for øyeblikket" "Du trenger en adresse for å gjøre den synlig i den offentlige katalogen." "Adresse" diff --git a/features/securityandprivacy/impl/src/main/res/values-pt-rBR/translations.xml b/features/securityandprivacy/impl/src/main/res/values-pt-rBR/translations.xml index 3cb05d3e0d..fac8c9790a 100644 --- a/features/securityandprivacy/impl/src/main/res/values-pt-rBR/translations.xml +++ b/features/securityandprivacy/impl/src/main/res/values-pt-rBR/translations.xml @@ -21,6 +21,7 @@ Não recomendamos que você ative a criptografia para salas que qualquer pessoa "Criptografia" "Ativar a criptografia de ponta a ponta" "Qualquer um pode entrar" + "Público" "Escolha os espaços dos quais os membros podem entrar nesta sala sem um convite. %1$s" "Gerenciar espaços" "Apenas pessoas convidadas podem entrar." diff --git a/features/securityandprivacy/impl/src/main/res/values-ru/translations.xml b/features/securityandprivacy/impl/src/main/res/values-ru/translations.xml index 148b06d343..98166699c6 100644 --- a/features/securityandprivacy/impl/src/main/res/values-ru/translations.xml +++ b/features/securityandprivacy/impl/src/main/res/values-ru/translations.xml @@ -28,6 +28,8 @@ "Только по приглашению" "Доступ" "Любой человек в авторизованных пространствах может присоединиться." + "Любой в %1$s может присоединиться." + "Участники пространства" "Пространства в настоящее время не поддерживаются." "Вам понадобится адрес комнаты, чтобы сделать ее видимой в каталоге." "Адрес" diff --git a/features/securityandprivacy/impl/src/main/res/values-sv/translations.xml b/features/securityandprivacy/impl/src/main/res/values-sv/translations.xml index 3ddda1a596..b28c0b09de 100644 --- a/features/securityandprivacy/impl/src/main/res/values-sv/translations.xml +++ b/features/securityandprivacy/impl/src/main/res/values-sv/translations.xml @@ -1,6 +1,6 @@ - "Du behöver en rumsadress för att göra den synlig i katalogen." + "Du behöver en adress för att göra den synlig i den offentliga katalogen." "Redigera adress" "Lägg till adress" "Alla måste begära åtkomst." @@ -19,7 +19,7 @@ Vi rekommenderar inte att aktivera kryptering för rum som vem som helst kan hit "Endast inbjudan" "Åtkomst" "Utrymmen stöds för närvarande inte" - "Du behöver en rumsadress för att göra den synlig i katalogen." + "Du behöver en adress för att göra den synlig i den offentliga katalogen." "Adress" "Tillåt att detta rum hittas genom att söka i den offentliga rumskatalogen på %1$s" "Synlig i offentliga katalogen" diff --git a/features/securityandprivacy/impl/src/main/res/values-tr/translations.xml b/features/securityandprivacy/impl/src/main/res/values-tr/translations.xml index 7f0532698d..1a8cfbe91b 100644 --- a/features/securityandprivacy/impl/src/main/res/values-tr/translations.xml +++ b/features/securityandprivacy/impl/src/main/res/values-tr/translations.xml @@ -2,9 +2,16 @@ "Dizinde görünür hale getirmek için bir oda adresine ihtiyacınız olacak." "Oda adresi" + "Üyelerin davet olmadan odaya katılabildiği alanlar." + "Alanları yönet" + "(Bilinmeyen alan)" + "Üyesi olmadığınız diğer alanlar" + "Alanlarınız" "Oda adresi ekle" + "Yetkilendirilmiş alanlardaki herkes katılabilir, diğer herkes erişim talep etmelidir." "Herkes odaya katılma isteğinde bulunabilir ancak bir yönetici veya moderatörün isteği kabul etmesi gerekir." "Katılma isteği gönder" + "%1$s alanındaki herkes katılabilir, diğer herkes erişim talep etmelidir." "Evet, şifrelemeyi etkinleştir" "Etkinleştirildikten sonra, bir oda için şifreleme devre dışı bırakılamaz, Mesaj geçmişi yalnızca davet edildiklerinden veya odaya katıldıklarından beri oda üyeleri için görünür olacaktır. Oda üyeleri dışında hiç kimse mesajları okuyamayacaktır. Bu, botların ve köprülerin düzgün çalışmasını engelleyebilir. @@ -15,21 +22,28 @@ Herkesin bulabileceği ve katılabileceği odalar için şifrelemenin etkinleşt "Uçtan uca şifrelemeyi etkinleştir" "Herkes bulabilir ve katılabilir" "Herkes" + "Davetsiz olarak bu odaya katılabilecek alan üyelerini seçin. %1$s" + "Alanları yönet" "İnsanlar yalnızca davet edildiklerinde katılabilirler" "Yalnızca davet" "Oda Erişimi" + "Yetkilendirilmiş alanlardaki herkes katılabilir." + "%1$s alanındaki herkes katılabilir." "Alanlar şu anda desteklenmiyor" "Dizinde görünür hale getirmek için bir oda adresine ihtiyacınız olacak." "Oda adresi" "Bu odanın %1$s genel oda dizininde arama yapılarak bulunmasına izin verin" + "Genel dizinde arama yapılarak bulunmasına izin ver." "Genel oda dizininde görünür" "Herkes" + "Değişiklikler geçmiş mesajları etkilemez, yalnızca yeni mesajlar için geçerlidir. %1$s" "Geçmişi kimler okuyabilir ?" - "Sadece üyeler (davet edildiklerinden beri)" + "Sadece üyeler (davet edildiklerinden itibaren)" "Bu seçeneği seçtiğinden beri yalnızca üyeler" "Oda adresleri, odaları bulmanın ve odalara erişmenin yoludur. Bu aynı zamanda odanızı başkalarıyla kolayca paylaşabilmenizi sağlar. Odanızı ana sunucunuzun genel oda dizininde yayınlamayı seçebilirsiniz." "Oda yayınlama" + "Adresler, oda ve alanları bulmak ve erişmek için kullanılır. Ayrıca bunları başkalarıyla kolayca paylaşabilmenizi sağlar." "Oda görünürlüğü" "Güvenlik ve gizlilik" diff --git a/features/securityandprivacy/impl/src/main/res/values-uz/translations.xml b/features/securityandprivacy/impl/src/main/res/values-uz/translations.xml index d5306bfa5c..2197e52905 100644 --- a/features/securityandprivacy/impl/src/main/res/values-uz/translations.xml +++ b/features/securityandprivacy/impl/src/main/res/values-uz/translations.xml @@ -2,8 +2,15 @@ "Katalogda ko‘rinadigan qilish uchun xona manzili kerak bo‘ladi." "Xona manzili" + "Maydon aʻzolari xonaga taklif olmay turib qoʻshilishi mumkin boʻlgan joy." + "Maydonlarni boshqarish" + "(Noma’lum maydon)" + "Siz a’zo bo‘lmagan boshqa maydonlar" + "Maydonlaringiz" "Xona manzilini kiritish" + "Vakolatli guruhlardagi har kim qo‘shilishi mumkin, lekin qolganlar ruxsat so‘rashi kerak. Tarjima eslatmasi yo‘q" "Xonaga qo‘shilishni istalgan kishi so‘rashi mumkin, lekin administrator yoki moderator so‘rovni qabul qilishi kerak" + "%1$s ichidagi istalgan kishi qo‘shilishi mumkin, lekin qolganlar ruxsat so‘rashi kerak." "Ha, shifrlashni yoqish" "Yoqilgandan so‘ng, xona uchun shifrlashni o‘chirib bo‘lmaydi. Xabarlar tarixi faqat xona a’zolari taklif qilinganidan yoki xonaga qo‘shilganidan keyingi davrdan boshlab ko‘rinadi. Xona a’zolaridan tashqari hech kim xabarlarni o‘qiy olmaydi. Bu botlar va ko‘priklarning to‘g‘ri ishlashiga to‘sqinlik qilishi mumkin. Shu sababli, har kim topishi va qo‘shilishi mumkin bo‘lgan xonalar uchun shifrlashni yoqishni tavsiya etmaymiz." @@ -12,12 +19,18 @@ Shu sababli, har kim topishi va qo‘shilishi mumkin bo‘lgan xonalar uchun shi "Shifrlash" "End-to-end shifrlashni yoqish" "Istalgan kishi topishi va qo‘shilishi mumkin" + "Qaysi maydonlar a’zolari bu xonaga taklifnomalarsiz kirishi mumkinligini tanlang. %1$s" + "Maydonlarni boshqarish" "Odamlar faqat taklif qilingan taqdirdagina qo‘shilishi mumkin" "Faqat taklif qilish" "Xonaga kirish huquqi" + "Ruxsat berilgan maydonlardagi istalgan kishi qo‘shilishi mumkin." + "%1$s ichidagi istalgan kishi qo‘shilishi mumkin." "Hozirda maydonlar qo‘llab-quvvatlanmaydi" "Katalogda ko‘rinadigan qilish uchun xona manzili kerak bo‘ladi." + "Manzil" "Bu xonani %1$s umumiy xonalar ro‘yxatidan qidirib topish imkoniyatini berish" + "Umumiy katalogni qidirish orqali topishga ruxsat bering." "Umumiy xona ro‘yxatida ko‘rinadi" "Tarixni kim o‘qiy oladi" "Taklif qilinganidan buyon faqat a’zolar" @@ -25,5 +38,7 @@ Shu sababli, har kim topishi va qo‘shilishi mumkin bo‘lgan xonalar uchun shi "Xona manzillari xonalarni topish va ularga kirish usullaridir. Bu shuningdek xonangizni boshqalar bilan oson ulashish imkonini beradi. Xonangizni o‘z homeserveringizning ommaviy xonalar ro‘yxatida e’lon qilishni tanlashingiz mumkin." "xona nashriyoti" + "Manzillar xona va maydonlarni topish va ularga kirish usulidir. Bu, shuningdek, ularni boshqalar bilan osongina bo‘lishishingizni ta’minlaydi." + "Ko‘rinish" "Xavfsizlik va maxfiylik" diff --git a/features/securityandprivacy/impl/src/main/res/values-zh/translations.xml b/features/securityandprivacy/impl/src/main/res/values-zh/translations.xml index f37c7868f1..8b10638e25 100644 --- a/features/securityandprivacy/impl/src/main/res/values-zh/translations.xml +++ b/features/securityandprivacy/impl/src/main/res/values-zh/translations.xml @@ -1,10 +1,17 @@ - "你需要房间地址才能使其在目录中可见。" - "房间地址" - "添加房间地址" - "任何人都可以请求加入房间,但必须由管理员或版主接受请求。" + "您需要一个地址才能在公共目录中显示。" + "编辑地址" + "无需邀请即可加入的公共空间。" + "管理空间" + "(未知空间)" + "您尚未加入的其他空间" + "您的空间" + "添加地址" + "授权空间内任何成员均可加入,其他人员需申请访问权限。" + "所有用户均需申请访问权限。" "请求加入" + "%1$s 成员可自由加入,其他人员需申请访问权限。" "是的,启用加密" "一旦启用,就不能再禁用房间的加密功能。消息历史记录只能在房间成员被邀请或加入房间后才可见。 除房间成员外,任何人都无法阅读信息。这可能会妨碍机器人和网桥正常工作。 @@ -13,23 +20,31 @@ "加密一旦启用,就无法禁用。" "加密" "启用端到端加密" - "任何人都可以找到并加入" + "任何人都可以加入。" "任何人" - "只有受邀者才能加入" - "仅限邀请" - "房间访问权限" + "选择哪些空间的成员无需邀请即可加入本聊天室。%1$s" + "管理空间" + "仅限受邀者加入。" + "仅限受邀者" + "访问权限" + "任何位于已授权空间的成员均可加入。" + "%1$s 中的任何人都可加入。" + "空间成员" "目前不支持空间" - "你需要房间地址才能使其在目录中可见。" - "房间地址" + "您需要一个地址才能在公共目录中显示。" + "地址" "允许通过搜索 %1$s 的公共房间目录来发现此房间" - "在公共房间目录中可见" - "任何人" + "通过公共目录搜索功能实现可被发现性。" + "在公共目录中可见" + "任何人(历史记录公开)" + "更改不会影响之前的消息,只会影响新消息。%1$s" "谁可以读取历史记录" - "仅限被邀请的成员" - "仅自选择此选项以来的成员" + "自受邀以来的成员" + "成员(完整历史记录)" "房间地址是查找和访问房间的方式。这也确保你可以轻松地向他人分享房间。 你可以选择在你服务器的公共房间目录中发布你的房间。" "房间发布" - "房间可见性" + "地址是查找和访问聊天室及空间的途径,同时确保您能轻松与他人共享。" + "可见性" "安全与隐私" diff --git a/features/space/impl/src/main/res/values-da/translations.xml b/features/space/impl/src/main/res/values-da/translations.xml index c6340ed557..063109d9a5 100644 --- a/features/space/impl/src/main/res/values-da/translations.xml +++ b/features/space/impl/src/main/res/values-da/translations.xml @@ -8,10 +8,14 @@ "Vælg de rum, du vil forlade, som du ikke er den eneste administrator for:" "Du skal tildele en anden administrator til denne gruppe, før du kan forlade den." + "Du er den eneste ejer af %1$s Du skal overføre ejerskabet til en anden, før du forlader rummet." "Du vil ikke blive fjernet fra følgende rum, fordi du er den eneste administrator:" "Forlad %1$s?" "Du er den eneste administrator for %1$s" + "Overfør ejerskab" + "Rum" "Tilføjelse af et rum påvirker ikke adgangen til rummet. For at ændre adgangen, gå til Rumindstillinger > Sikkerhed og privatliv." + "Tilføj dit første rum" "Vis medlemmer" "Fjernelse af et rum påvirker ikke adgangen til rummet. For at ændre adgangen, gå til Rum-info > Privatliv og sikkerhed." diff --git a/features/space/impl/src/main/res/values-el/translations.xml b/features/space/impl/src/main/res/values-el/translations.xml index 144aae7278..3c1a2aa34b 100644 --- a/features/space/impl/src/main/res/values-el/translations.xml +++ b/features/space/impl/src/main/res/values-el/translations.xml @@ -1,5 +1,28 @@ + "Επιλέξτε ιδιοκτήτες" + "%1$s (Διαχειριστής)" + + "Αφήστε αίθουσα και χώρο του %1$d" + "Αφήστε τις αίθουσες και τους χώρους του %1$d" + + "Επιλέξτε τις αίθουσες από τις οποίες θέλετε να αποχωρήσετε και στα οποία δεν είστε ο μόνος διαχειριστής:" + "Πρέπει να ορίσετε έναν άλλο διαχειριστή για αυτόν τον χώρο προτού μπορέσετε να αποχωρήσετε." + "Είστε ο μοναδικός ιδιοκτήτης του %1$s. Πρέπει να μεταβιβάσετε την ιδιοκτησία σε κάποιον άλλο πριν φύγετε." + "Δεν θα αφαιρεθείτε από την ακόλουθη αίθουσα(ες) επειδή είστε ο μόνος διαχειριστής:" + "Αποχώρηση από %1$s ;" + "Είστε ο μόνος διαχειριστής για %1$s" + "Μεταβίβαση ιδιοκτησίας" + "Αίθουσα" + "Η προσθήκη μιας αίθουσας δεν θα επηρεάσει την πρόσβαση στην αίθουσα. Για να αλλάξετε την πρόσβαση, μεταβείτε στις Ρυθμίσεις αίθουσας > Ασφάλεια και απόρρητο." + "Προσθέστε την πρώτη σας αίθουσα" + "Προβολή μελών" + "Η κατάργηση μιας αίθουσας δεν θα επηρεάσει την πρόσβαση σε αυτή. Για να αλλάξετε την πρόσβαση, μεταβείτε στις Πληροφορίες αίθουσας > Απόρρητο και ασφάλεια." + + "Αφαιρείται η %1$d αίθουσα από %2$s" + "Αφαιρούνται οι %1$d αίθουσες από %2$s" + + "Αποχώρηση από τον χώρο" "Ρόλοι και δικαιώματα" "Ασφάλεια & απόρρητο" diff --git a/features/space/impl/src/main/res/values-fi/translations.xml b/features/space/impl/src/main/res/values-fi/translations.xml index b95a5afd2a..01b9962129 100644 --- a/features/space/impl/src/main/res/values-fi/translations.xml +++ b/features/space/impl/src/main/res/values-fi/translations.xml @@ -8,10 +8,20 @@ "Tämä poistaa sinut myös kaikista tämän tilan huoneista." "Sinun on valittava tälle tilalle toinen ylläpitäjä ennen kuin voit poistua." + "Olet tilan %1$s ainoa omistaja. Sinun on siirrettävä omistajuus jollekin toiselle ennen lähtöäsi." "Sinua ei poisteta seuraavista huoneista, koska olet ainoa ylläpitäjä:" "Haluatko poistua tilasta %1$s?" "Olet ainoa ylläpitäjä tilassa %1$s" + "Siirrä omistajuus" + "Huone" + "Huoneen lisääminen ei vaikuta huoneen käyttöoikeuksiin. Voit muuttaa käyttöoikeuksia kohdassa Huoneen asetukset > Turvallisuus ja yksityisyys." + "Lisää ensimmäinen huoneesi" "Näytä jäsenet" + "Huoneen poistaminen ei vaikuta huoneen käyttöoikeuksiin. Voit muuttaa käyttöoikeuksia kohdassa Huoneen asetukset > Turvallisuus ja yksityisyys." + + "Poista %1$d huone tilasta %2$s" + "Poista %1$d huonetta tilasta %2$s" + "Poistu tilasta" "Roolit ja oikeudet" "Turvallisuus ja yksityisyys" diff --git a/features/space/impl/src/main/res/values-fr/translations.xml b/features/space/impl/src/main/res/values-fr/translations.xml index 2520fa26ba..dc3f298115 100644 --- a/features/space/impl/src/main/res/values-fr/translations.xml +++ b/features/space/impl/src/main/res/values-fr/translations.xml @@ -1,6 +1,6 @@ - "Choisissez les propriétaires" + "Choisir les propriétaires" "%1$s (Admin)" "Quitter %1$d salon et l’espace" diff --git a/features/space/impl/src/main/res/values-hu/translations.xml b/features/space/impl/src/main/res/values-hu/translations.xml index 631e2062e0..a02bd9a18d 100644 --- a/features/space/impl/src/main/res/values-hu/translations.xml +++ b/features/space/impl/src/main/res/values-hu/translations.xml @@ -12,6 +12,7 @@ "Nem lesz eltávolítva a következő szobá(k)ból, mert ön az egyetlen adminisztrátor:" "Kilép innen: %1$s?" "Ön az egyetlen adminisztrátor itt: %1$s" + "Tulajdonjog átruházása" "Szoba" "A szoba hozzáadása nem befolyásolja a szobához való hozzáférést. A hozzáférés módosításához lépjen a szoba beállításainak Biztonság és adatvédelem menüpontjához." "Első szoba hozzáadása" diff --git a/features/space/impl/src/main/res/values-nb/translations.xml b/features/space/impl/src/main/res/values-nb/translations.xml index eb20c2a100..62545db328 100644 --- a/features/space/impl/src/main/res/values-nb/translations.xml +++ b/features/space/impl/src/main/res/values-nb/translations.xml @@ -11,7 +11,14 @@ "Du vil ikke bli fjernet fra følgende rom fordi du er den eneste administratoren:" "Forlat %1$s?" "Du er den eneste administratoren for %1$s" + "Overfør eierskap" + "Rom" + "Legg til ditt første rom" "Vis medlemmer" + + "Fjern %1$d rom fra %2$s" + "Fjern %1$d rommene fra %2$s" + "Forlat område" "Roller og tillatelser" "Sikkerhet og personvern" diff --git a/features/space/impl/src/main/res/values-ru/translations.xml b/features/space/impl/src/main/res/values-ru/translations.xml index 776d62be2a..2492106807 100644 --- a/features/space/impl/src/main/res/values-ru/translations.xml +++ b/features/space/impl/src/main/res/values-ru/translations.xml @@ -9,10 +9,13 @@ "Выберите комнаты, которые вы хотите покинуть и в которых вы не являетесь единственным администратором:" "Прежде чем покинуть это пространство, вам необходимо назначить другого администратора." + "Вы — единственный владелец %1$s. Перед тем как покинуть, вам нужно передать право владения кому-то другому." "Вы не будете удалены из следующих комнат, поскольку вы являетесь единственным администратором:" "Выйти из %1$s?" "Вы единственный администратор для %1$s" + "Комната" "Добавление комнаты не повлияет на доступ к ней. Чтобы изменить доступ к комнате, перейдите в Настройки > Безопасность и конфиденциальность." + "Добавить свою первую комнату" "Просмотреть участников" "Удаление комнаты не повлияет на доступ к ней. Чтобы изменить доступ, перейдите в раздел «Информация о комнате > Конфиденциальность и безопасность." diff --git a/features/space/impl/src/main/res/values-tr/translations.xml b/features/space/impl/src/main/res/values-tr/translations.xml index 99e4a986fa..96a3b3c762 100644 --- a/features/space/impl/src/main/res/values-tr/translations.xml +++ b/features/space/impl/src/main/res/values-tr/translations.xml @@ -1,5 +1,12 @@ + "Sahipleri seçin" + "Ayrılmak istediğiniz odaları seçin (yalnızca yöneticisi olmadığınız alanlardaki odalar):" + "Bu alandan ayrılmadan önce başka bir yönetici atamalısınız." + "Tek yönetici olduğunuz için aşağıdaki oda(lar)dan çıkarılmayacaksınız:" + "%1$s alanından ayrılmak istiyor musunuz?" + "%1$s alanının tek yöneticisisiniz" + "Üyeleri görüntüle" "Roller ve izinler" "Güvenlik ve gizlilik" diff --git a/features/space/impl/src/main/res/values-uz/translations.xml b/features/space/impl/src/main/res/values-uz/translations.xml index 85b8271c21..ae0bee0a51 100644 --- a/features/space/impl/src/main/res/values-uz/translations.xml +++ b/features/space/impl/src/main/res/values-uz/translations.xml @@ -1,6 +1,18 @@ "Egalarni tanlang" + "%1$s(Admin)" + + "%1$d xona va maydonni tar etish" + "%1$d ta xona va maydonni tar etish" + + "Siz yagona administrator bo‘lmagan xonalardan chiqishni xohlasangiz, ularni tanlang:" + " Ketishingizdan oldin bu maydon uchun boshqa administrator tayinlashingiz kerak." + "Siz quyidagi xona(lar)dan olib tashlanmaysiz, chunki siz yagona administratorsiz:" + "%1$s dan chiqasizmi?" + "Siz %1$s uchun yagona administratorsiz" + "A’zolarni ko‘rish" + "Maydondan chiqish" "Rollar va ruxsatlar" "Xavfsizlik va maxfiylik" diff --git a/features/space/impl/src/main/res/values-zh/translations.xml b/features/space/impl/src/main/res/values-zh/translations.xml index cc204f14b6..cdac25a8ae 100644 --- a/features/space/impl/src/main/res/values-zh/translations.xml +++ b/features/space/impl/src/main/res/values-zh/translations.xml @@ -7,10 +7,19 @@ "选择您想要离开且您不是其唯一管理员的房间:" "您需要为该空间指定另一位管理员才能离开。" + "您是%1$s 的唯一所有者。在您离开前,需要将所有权转移给他人。" "您不会从以下房间中被移除,因为您是唯一的管理员:" "离开%1$s?" "您是 %1$s 的唯一管理员" + "转让所有权" + "聊天室" + "添加聊天室不会影响其访问权限。如需更改访问权限,请前往“聊天室设置” > “安全与隐私”。" + "添加您的第一个聊天室" "查看成员" + "移除聊天室不会影响其访问权限。要更改访问权限,请转到“聊天室信息”>“隐私和安全”。" + + "移除 %1$d 个 %2$s 中的聊天室" + "离开空间" "角色与权限" "安全与隐私" 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 1cbb7d3c04..d8ea86e780 100644 --- a/features/verifysession/impl/src/main/res/values-el/translations.xml +++ b/features/verifysession/impl/src/main/res/values-el/translations.xml @@ -11,12 +11,12 @@ "Χρήση άλλης συσκευής" "Αναμονή σε άλλη συσκευή…" "Κάτι δεν πάει καλά. Είτε το αίτημα έληξε είτε απορρίφθηκε." - "Επιβεβαίωσε ότι τα παρακάτω emoji ταιριάζουν με αυτά που εμφανίζονται στην άλλη συνεδρία σου." + "Επιβεβαιώστε ότι τα παρακάτω emoji ταιριάζουν με αυτά που εμφανίζονται στην άλλη συσκευή σας." "Σύγκριση emoji" "Επιβεβαιώστε ότι τα παρακάτω emoji ταιριάζουν με αυτά που εμφανίζονται στη συσκευή του άλλου χρήστη." "Επιβεβαίωσε ότι οι παρακάτω αριθμοί ταιριάζουν με αυτούς που εμφανίζονται στην άλλη συνεδρία σου." "Σύγκριση αριθμών" - "Η νέα σου συνεδρία έχει πλέον επαληθευτεί. Έχει πρόσβαση στα κρυπτογραφημένα μηνύματά σας και άλλοι χρήστες θα το βλέπουν ως αξιόπιστο." + "Τώρα μπορείτε να διαβάζετε ή να στέλνετε μηνύματα με ασφάλεια στην άλλη συσκευή σας." "Τώρα μπορείτε να εμπιστευτείτε την ταυτότητα αυτού του χρήστη κατά την αποστολή ή τη λήψη μηνυμάτων." "Επαληθευμένη συσκευή" "Εισαγωγή κλειδιού ανάκτησης" @@ -33,7 +33,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 19d471cb2b..52422393bf 100644 --- a/features/verifysession/impl/src/main/res/values-es/translations.xml +++ b/features/verifysession/impl/src/main/res/values-es/translations.xml @@ -11,12 +11,12 @@ "Usar otro dispositivo" "Esperando en 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." + "Confirma que los emojis coinciden con los que se muestran en tu otro dispositivo." "Comparar emojis" "Confirma que los emojis que aparecen a continuación coinciden con los mostrados en el dispositivo del otro usuario." "Confirma que los números que aparecen a continuación coinciden con los mostrados en tu otra sesión." "Comparar números" - "Tu nueva sesión ya está verificada. Tienes acceso a tus mensajes cifrados y otros usuarios lo considerarán de confianza." + "Ahora puedes leer o enviar mensajes de forma segura en tu otro dispositivo." "Ahora puedes confiar en la identidad de este usuario al enviar o recibir mensajes." "Dispositivo verificado" "Introduce la clave de recuperación" @@ -33,7 +33,7 @@ "Verificación fallida" "Continúa solo si has iniciado esta verificación." "Verifica el otro dispositivo para mantener seguro tu historial de mensajes." - "Tu nueva sesión ya está verificada. Tienes acceso a tus mensajes cifrados y otros usuarios lo considerarán de confianza." + "Ahora puedes leer o enviar mensajes de forma segura en tu otro dispositivo." "Dispositivo verificado" "Verificación solicitada" "No coinciden" diff --git a/libraries/mediaviewer/impl/src/main/res/values-nl/translations.xml b/libraries/mediaviewer/impl/src/main/res/values-nl/translations.xml index ab7f922d95..efa4571909 100644 --- a/libraries/mediaviewer/impl/src/main/res/values-nl/translations.xml +++ b/libraries/mediaviewer/impl/src/main/res/values-nl/translations.xml @@ -1,4 +1,5 @@ "Bestand verwijderen?" + "Media en bestanden" diff --git a/libraries/push/impl/src/main/res/values-da/translations.xml b/libraries/push/impl/src/main/res/values-da/translations.xml index b48875c20e..51ff99f919 100644 --- a/libraries/push/impl/src/main/res/values-da/translations.xml +++ b/libraries/push/impl/src/main/res/values-da/translations.xml @@ -15,6 +15,10 @@ "UnifiedPush-push notification-distributøren kunne ikke registreres, så du vil ikke længere modtage notifikationer. Kontrollér appens notifikationsindstillinger og push-distributørens status." "Du har nye beskeder." + + "Du har %d ny besked." + "Du har %d nye beskeder." + "📹 Indgående opkald" "** Kunne ikke sende - åbn venligst rummet" "Deltag" diff --git a/libraries/push/impl/src/main/res/values-el/translations.xml b/libraries/push/impl/src/main/res/values-el/translations.xml index 1229218f09..72e87f0980 100644 --- a/libraries/push/impl/src/main/res/values-el/translations.xml +++ b/libraries/push/impl/src/main/res/values-el/translations.xml @@ -13,7 +13,12 @@ "%d ειδοποίηση" "%d ειδοποιήσεις" + "Δεν ήταν δυνατή η εγγραφή του διανομέα ειδοποιήσεων UnifiedPush, επομένως δεν θα λαμβάνετε πλέον ειδοποιήσεις. Ελέγξτε τις ρυθμίσεις ειδοποιήσεων της εφαρμογής και την κατάσταση του διανομέα push." "Έχεις νέο(α) μήνυμα(τα)." + + "Έχετε %d νέο μήνυμα." + "Έχετε %d νέα μηνύματα." + "📹 Εισερχόμενη κλήση" "** Αποτυχία αποστολής - παρακαλώ ανοίξτε την αίθουσα" "Συμμετοχή" @@ -37,7 +42,10 @@ "%1$s σας προσκάλεσε να συμμετάσχετε στην αίθουσα" "Εγώ" "Ο χρήστης %1$s αναφέρθηκε ή απάντησε" + "Σας προσκάλεσε να συμμετάσχετε στον χώρο" + "%1$s σας προσκάλεσε να συμμετάσχετε στον χώρο" "Βλέπεις την ειδοποίηση! Κάνε μου κλικ!" + "Νήμα στο %1$s" "%1$s: %2$s" "%1$s: %2$s %3$s" @@ -54,10 +62,20 @@ "Συγχρονισμός στο παρασκήνιο" "Υπηρεσίες Google" "Δεν βρέθηκαν έγκυρες υπηρεσίες Google Play. Οι ειδοποιήσεις ενδέχεται να μην λειτουργούν σωστά." + "Έλεγχος αποκλεισμένων χρηστών" + "Προβολή αποκλεισμένων χρηστών" + "Δεν υπάρχουν αποκλεισμένοι χρήστες." + + "Αποκλείσατε τον χρήστη %1$d. Δεν θα λαμβάνετε ειδοποιήσεις για αυτόν τον χρήστη." + "Αποκλείσατε τους χρήστες %1$d. Δεν θα λαμβάνετε ειδοποιήσεις για αυτούς τους χρήστες." + "Αποκλεισμένοι χρήστες" "Λάβε το όνομα του τρέχοντος παρόχου." "Δεν έχουν επιλεγεί πάροχοι push." + "Τρέχων πάροχος push: %1$s και τρέχων διανομέας: %2$s. Αλλά ο διανομέας %3$s δεν βρέθηκε. Ίσως η εφαρμογή έχει απεγκατασταθεί;" + "Τρέχων πάροχος push: %1$s, αλλά δεν έχουν ρυθμιστεί διανομείς." "Τρέχων πάροχος push: %1$s." + "Τρέχων πάροχος push: %1$s (%2$s)" "Τρέχων πάροχος push" "Βεβαιώσου ότι η εφαρμογή διαθέτει τουλάχιστον έναν πάροχο push." "Δεν βρέθηκαν πάροχοι push." diff --git a/libraries/push/impl/src/main/res/values-es/translations.xml b/libraries/push/impl/src/main/res/values-es/translations.xml index cee68d6072..412d32bfb6 100644 --- a/libraries/push/impl/src/main/res/values-es/translations.xml +++ b/libraries/push/impl/src/main/res/values-es/translations.xml @@ -13,6 +13,7 @@ "%d notificación" "%d notificaciones" + "Tienes nuevos mensajes." "📹 Llamada entrante" "** No se ha podido enviar - por favor, abre la sala" "Unirse" diff --git a/libraries/push/impl/src/main/res/values-fi/translations.xml b/libraries/push/impl/src/main/res/values-fi/translations.xml index 1af69c2da9..6b41750b9f 100644 --- a/libraries/push/impl/src/main/res/values-fi/translations.xml +++ b/libraries/push/impl/src/main/res/values-fi/translations.xml @@ -15,6 +15,10 @@ "UnifiedPush ilmoitusten jakelijaa ei voitu rekisteröidä, joten et enää vastaanota ilmoituksia. Tarkista sovelluksen ilmoitusasetukset ja push-jakelijan tila." "Sinulle on uusia viestejä." + + "Sinulla on %d uusi viesti." + "Sinulla on %d uutta viestiä." + "📹 Saapuva puhelu" "** Lähetys epäonnistui - avaa huone" "Liity" @@ -38,7 +42,10 @@ "%1$s kutsui sinut liittymään huoneeseen" "Minä" "%1$s mainitsi tai vastasi" + "Kutsui sinut liittymään tilaan" + "%1$s kutsui sinut liittymään tilaan" "Katselet ilmoitusta! Klikkaa minua!" + "Viestiketju huoneessa %1$s" "%1$s: %2$s" "%1$s: %2$s %3$s" diff --git a/libraries/push/impl/src/main/res/values-fr/translations.xml b/libraries/push/impl/src/main/res/values-fr/translations.xml index 746f797cd0..13e1b519ab 100644 --- a/libraries/push/impl/src/main/res/values-fr/translations.xml +++ b/libraries/push/impl/src/main/res/values-fr/translations.xml @@ -15,6 +15,10 @@ "Le distributeur de notifications UnifiedPush n’a pas pu être enregistré, vous ne recevrez donc plus de notifications. Veuillez vérifier les paramètres de notification de l’application et l’état du distributeur." "Vous avez de nouveau(x) message(s)." + + "Vous avez %d nouveau message." + "Vous avez %d nouveaux messages." + "📹 Appel entrant" "** Échec de l’envoi - veuillez ouvrir le salon" "Rejoindre" diff --git a/libraries/push/impl/src/main/res/values-hu/translations.xml b/libraries/push/impl/src/main/res/values-hu/translations.xml index d65c3bb4c8..38726a6463 100644 --- a/libraries/push/impl/src/main/res/values-hu/translations.xml +++ b/libraries/push/impl/src/main/res/values-hu/translations.xml @@ -15,6 +15,10 @@ "A UnifiedPush leküldéses értesítési terjesztő nem regisztrálható, ezért többé nem fog értesítéseket kapni. Ellenőrizze az alkalmazás értesítési beállításait és a leküldés értesítési terjesztő állapotát." "Értesítés" + + "Van %d új üzenete." + "Van %d új üzenete." + "📹 Bejövő hívás" "** Nem sikerült elküldeni – nyissa meg a szobát" "Csatlakozás" diff --git a/libraries/push/impl/src/main/res/values-nb/translations.xml b/libraries/push/impl/src/main/res/values-nb/translations.xml index 20e8f3f86d..d7f0016442 100644 --- a/libraries/push/impl/src/main/res/values-nb/translations.xml +++ b/libraries/push/impl/src/main/res/values-nb/translations.xml @@ -15,6 +15,10 @@ "UnifiedPush-varslingsdistributøren kunne ikke registreres, så du vil ikke motta varsler lenger. Sjekk varslingsinnstillingene til appen og statusen til push-distributøren." "Du har nye meldinger." + + "Du har %d ny melding." + "Du har %d nye meldinger." + "📹 Innkommende anrop" "** Kunne ikke sende - vennligst åpne rommet" "Bli med" diff --git a/libraries/push/impl/src/main/res/values-nl/translations.xml b/libraries/push/impl/src/main/res/values-nl/translations.xml index 79244669e6..7a75f4914b 100644 --- a/libraries/push/impl/src/main/res/values-nl/translations.xml +++ b/libraries/push/impl/src/main/res/values-nl/translations.xml @@ -37,6 +37,7 @@ "Mij" "%1$s heeft vermeld of beantwoord" "Je bekijkt de melding! Klik hier!" + "Gesprek in %1$s" "%1$s: %2$s" "%1$s: %2$s %3$s" diff --git a/libraries/push/impl/src/main/res/values-uz/translations.xml b/libraries/push/impl/src/main/res/values-uz/translations.xml index e967b47d34..1058fdd1d2 100644 --- a/libraries/push/impl/src/main/res/values-uz/translations.xml +++ b/libraries/push/impl/src/main/res/values-uz/translations.xml @@ -13,6 +13,7 @@ "%dbildirishnoma" "%dbildirishnomalar" + "UnifiedPush bildirishnoma tarqatuvchisini roʻyxatdan oʻtkazib boʻlmadi, shuning uchun siz endi bildirishnomalarni olmaysiz. Iltimos, ilovaning bildirishnoma sozlamalarini va push distribyutor holatini tekshiring." "Sizda yangi xabarlar bor." "📹 Kiruvchi qoʻngʻiroq" "** Yuborilmadi - iltimos, xonani oching" @@ -37,7 +38,10 @@ "%1$s sizni xonaga kirishga taklif qildi" "Men" "%1$s eslatib o‘tdi yoki javob qaytardi" + "Sizga maydonga qo‘shilishni taklif qildi" + "%1$s sizni guruhga kirishga taklif qildi" "Siz bildirishnomani ko\'ryapsiz! Meni bosing!" + "%1$s ichidagi thread" "%1$s:%2$s" "%1$s:%2$s%3$s" @@ -54,10 +58,20 @@ "Orqa Fon sinxronizatsiyasi" "Google xizmatlari" "Yaroqli Google Play xizmatlari topilmadi. Bildirishnomalar to\'g\'ri ishlamasligi mumkin." + "Bloklangan foydalanuvchilar tekshirilmoqda" + "Bloklangan foydalanuvchilarni ko‘rish" + "Hech qanday foydalanuvchi bloklanmagan." + + "Siz %1$d ta foydalanuvchini blokladingiz. Bu foydalanuvchi uchun bildirishnomalar olmaysiz." + "Siz %1$d ta foydalanuvchini blokladingiz. Bu foydalanuvchilar uchun bildirishnomalar olmaysiz." + "Bloklangan foydalanuvchilar" "Joriy provayder nomini oling." "Hech qanday push-provayder tanlanmagan." + "Joriy push-provayder: %1$sva joriy distributor: %2$s. Lekin %3$s distribyutori topilmadi. Balki ilova o‘chirib tashlangandir?" + "Joriy push-provayder:%1$s, lekin hech qanday distribyutor sozlanmagan." "Joriy push provider: %1$s." + "Joriy push-provayder:%1$s (%2$s )" "Joriy push provider" "Ilova kamida bitta push-provayderni qo‘llab-quvvatlashini tekshiring." "Hech qanday push-provayder xizmati topilmadi." @@ -78,5 +92,6 @@ "Xato: %1$s." "Xatolik, push qilishni sinab bo‘lmadi." "Xatolik, taym aut pushni kutmoqda." + "Tsiklni orqaga surish %1$d millisekund davom etdi." "Test Push loop back" diff --git a/libraries/push/impl/src/main/res/values-zh/translations.xml b/libraries/push/impl/src/main/res/values-zh/translations.xml index 3f2bd7e836..9a9057b07b 100644 --- a/libraries/push/impl/src/main/res/values-zh/translations.xml +++ b/libraries/push/impl/src/main/res/values-zh/translations.xml @@ -11,7 +11,11 @@ "%d 条通知" + "统一推送通知分发器注册失败,您将无法再接收通知。请检查应用的通知设置及推送分发器的状态。" "您有新消息。" + + "您有 %d 条新消息。" + "📹 来电" "** 无法发送——请打开聊天室" "加入" @@ -33,6 +37,8 @@ "%1$s 邀请您加入房间" "我" "%1$s提及或回复" + "已邀请您加入该空间" + "%1$s 邀请您加入该空间" "您正在查看通知!点击我!" "线程 %1$s" "%1$s:%2$s" diff --git a/libraries/textcomposer/impl/src/main/res/values-el/translations.xml b/libraries/textcomposer/impl/src/main/res/values-el/translations.xml index a054182993..b76549882a 100644 --- a/libraries/textcomposer/impl/src/main/res/values-el/translations.xml +++ b/libraries/textcomposer/impl/src/main/res/values-el/translations.xml @@ -2,7 +2,7 @@ "Προσθήκη συνημμένου" "Διακόπτης λίστας κουκκίδων" - "Κλείσε τις επιλογές μορφοποίησης" + "Ακύρωση και κλείσιμο μορφοποίησης κειμένου" "Διακόπτης μπλοκ κώδικα" "Προαιρετική λεζάντα…" "Κρυπτογραφημένο μήνυμα…" diff --git a/libraries/textcomposer/impl/src/main/res/values-es/translations.xml b/libraries/textcomposer/impl/src/main/res/values-es/translations.xml index 2c7031a6d5..68b8b7b02c 100644 --- a/libraries/textcomposer/impl/src/main/res/values-es/translations.xml +++ b/libraries/textcomposer/impl/src/main/res/values-es/translations.xml @@ -2,7 +2,7 @@ "Adjuntar archivo" "Lista de puntos" - "Cerrar opciones de formato" + "Cancelar y cerrar opciones de formato" "Bloque de código" "Agregar una leyenda" "Mensaje cifrado…" @@ -12,6 +12,7 @@ "Editar enlace" "Aplicar formato negrita" "Aplicar formato cursiva" + "deshabilitado" "Aplicar formato tachado" "Aplicar formato de subrayado" "Pantalla completa" 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 467fb05e25..6e2374a5aa 100644 --- a/libraries/ui-strings/src/main/res/values-be/translations.xml +++ b/libraries/ui-strings/src/main/res/values-be/translations.xml @@ -1,5 +1,6 @@ + "Адрас" "Аватар" "Выдаліць" @@ -18,6 +19,7 @@ "Прайграць" "Апытанне" "Апытанне скончана" + "QR-код" "Рэагаваць з %1$s" "Рэагаваць з іншымі эмодзі" "Прачытана %1$s і %2$s" @@ -98,6 +100,7 @@ "Выдаліць" "Адказаць" "Адказаць у гутаркі" + "Паскардзіцца" "Паведаміць пра памылку" "Паскардзіцца на змест" "Скінуць" @@ -106,6 +109,7 @@ "Паўтарыць расшыфроўку" "Захаваць" "Пошук" + "Выбраць усё" "Адправіць" "Адправіць паведамленне" "Падзяліцца" @@ -122,6 +126,7 @@ "Націсніце, каб загрузіць карту" "Зрабіць фота" "Дакраніцеся, каб убачыць параметры" + "Перакласці" "Паўтарыць спробу" "Адмацаваць" "Прагляд у хроніцы" @@ -319,6 +324,7 @@ "Адкрыць у Google Maps" "Адкрыць у OpenStreetMap" "Падзяліцеся гэтым месцазнаходжаннем" + "Прасторы" "Паведамленне не адпраўлена таму што%1$s не праверыў усе прылады." "Месцазнаходжанне" "Версія: %1$s (%2$s)" diff --git a/libraries/ui-strings/src/main/res/values-da/translations.xml b/libraries/ui-strings/src/main/res/values-da/translations.xml index fe555905ff..cfb495e3ab 100644 --- a/libraries/ui-strings/src/main/res/values-da/translations.xml +++ b/libraries/ui-strings/src/main/res/values-da/translations.xml @@ -1,6 +1,7 @@ "Tilføj reaktion: %1$s" + "Adresse" "Avatar" "Minimér tekstfeltet for beskeder" "Slet" @@ -27,8 +28,10 @@ "Talebesked, varighed: %1$s, aktuel position: %2$s" "PIN-felt" "Afspil" + "Afspilningshastighed" "Afstemning" "Afsluttet afstemning" + "QR-kode" "Reager med%1$s" "Reager med andre emojis" "Læs af %1$s og %2$s" @@ -285,8 +288,10 @@ "Forbereder…" "Privatlivspolitik" + "Privat" "Privat rum" "Privat gruppe" + "Offentlig" "Offentligt rum" "Offentlig gruppe" "Reaktion" @@ -303,6 +308,7 @@ "Anmeld et problem" "Anmeldelsen er indsendt" "Rich text editor" + "Rolle" "Rum" "Navn på rum" "f.eks. navnet på dit projekt" @@ -332,12 +338,14 @@ "Server URL" "Indstillinger" "Del gruppe" + "Nye medlemmer ser historik" "Delt placering" "Delt gruppe" "Logger ud" "Noget gik galt" "Vi stødte på et problem. Prøv venligst igen." "Gruppe" + "Medlemmer af rummet" "Hvad handler denne gruppe om?" "%1$d Gruppe" @@ -383,6 +391,7 @@ "Talebesked" "Venter…" "Venter på denne besked" + "Alle kan se historikken" "Dig" "%1$s(%2$s ) har delt denne besked siden du ikke var i rummet da den blev sendt." "%1$s delte denne besked, siden du ikke var i rummet da den blev sendt." 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 20f52b7208..52c0ea4442 100644 --- a/libraries/ui-strings/src/main/res/values-el/translations.xml +++ b/libraries/ui-strings/src/main/res/values-el/translations.xml @@ -1,24 +1,37 @@ "Προσθήκη αντίδρασης: %1$s" + "Διεύθυνση" "Εικόνα Προφίλ" + "Ελαχιστοποίηση πεδίου κειμένου μηνύματος" "Διαγραφή" "%1$d ψηφίο εισήχθη" "%1$d ψηφία εισήχθησαν" + "Επεξεργασία Άβαταρ" + "Η πλήρης διεύθυνση θα είναι %1$s" + "Λεπτομέρειες κρυπτογράφησης" + "Επεκτείνετε το πεδίο κειμένου του μηνύματος" "Απόκρυψη κωδικού πρόσβασης" "Συμμετοχή στην κλήση" "Άλμα προς τα κάτω" + "Μετακινήστε τον χάρτη στην τοποθεσία μου" "Αναφορές μόνο" "Σε σίγαση" + "Νέες αναφορές" + "Νέα μηνύματα" + "Κλήση σε εξέλιξη" + "Άβαταρ άλλου χρήστη" "Σελίδα %1$d" "Παύση" "Φωνητικό μήνυμα, διάρκεια:%1$s, τρέχουσα θέση: %2$s" "Πεδίο PIN" "Αναπαραγωγή" + "Ταχύτητα αναπαραγωγής" "Δημοσκόπηση" "Ολοκληρωμένη δημοσκόπηση" + "Κωδικός QR" "Αντέδρασε με %1$s" "Αντέδρασε με άλλα emoji" "Διαβάστηκε από%1$s και %2$s" @@ -30,16 +43,23 @@ "Πάτα για εμφάνιση όλων" "Αφαίρεση αντίδρασης με %1$s" "Αφαιρέστε την αντίδραση με %1$s" + "Άβαταρ αίθουσας" "Αποστολή αρχείων" + "Απαιτείται ενέργεια περιορισμένης χρονικής διάρκειας, έχετε ένα λεπτό για επαλήθευση." "Εμφάνιση κωδικού πρόσβασης" "Ξεκίνησε μια κλήση" + "Θαμένη αίθουσα" + "Άβαταρ χρήστη" "Μενού χρήστη" + "Προβολή avatar" "Προβολή λεπτομερειών" "Φωνητικό μήνυμα, διάρκεια: %1$s" "Εγγραφή φωνητικού μηνύματος." "Διακοπή καταγραφής" + "Το άβατάρ σας" "Αποδοχή" "Προσθήκη λεζάντας" + "Προσθέστε υπάρχουσες αίθουσες" "Προσθήκη στο χρονοδιάγραμμα" "Πίσω" "Κάλεσε" @@ -59,11 +79,13 @@ "Αντιγραφή κειμένου" "Δημιουργία" "Δημιουργία αίθουσας" + "Δημιουργήστε χώρο" "Απενεργοποίηση" "Απενεργοποίηση λογαριασμού" "Απόρριψη" "Απόρριψη και αποκλεισμός" "Διαγραφή Δημοσκόπησης" + "Αποεπιλογή όλων" "Απενεργοποίηση" "Απόρριψη" "Παράβλεψη" @@ -74,9 +96,13 @@ "Ενεργοποίηση" "Λήξη δημοσκόπησης" "Εισαγωγή PIN" + "Εξερευνήστε δημόσιους χώρους" + "Τέλος" "Ξέχασες τον κωδικό πρόσβασης;" "Προώθηση" "Πήγαινε πίσω" + "Μετάβαση στους ρόλους και τα δικαιώματα" + "Μεταβείτε στις ρυθμίσεις" "Παράβλεψη" "Πρόσκληση" "Πρόσκληση ατόμων" @@ -88,14 +114,18 @@ "Αποχώρηση" "Αποχώρηση από τη συζήτηση" "Αποχώρηση από την αίθουσα" + "Αποχώρηση από τον χώρο" "Φόρτωσε περισσότερα" "Διαχείριση λογαριασμού" "Διαχείριση συσκευών" + "Διαχείριση αίθουσών" "Στείλε" + "Ελαχιστοποίηση" "Επόμενο" "Όχι" "Όχι τώρα" "OK" + "Άνοιγμα μενού περιβάλλοντος" "Ρυθμίσεις" "Άνοιγμα με" "Καρφίτσωμα" @@ -119,8 +149,11 @@ "Επανάληψη αποκρυπτογράφησης" "Αποθήκευση" "Αναζήτηση" + "Επιλογή όλων" "Αποστολή" + "Αποστολή επεξεργασμένου μηνύματος" "Αποστολή μηνύματος" + "Αποστολή φωνητικού μηνύματος" "Κοινή χρήση" "Κοινή χρήση συνδέσμου" "Εμφάνιση" @@ -135,8 +168,10 @@ "Πάτα για φόρτωση χάρτη" "Τράβηξε φωτογραφία" "Πάτα για επιλογές" + "Μετάφραση" "Προσπάθησε ξανά" "Ξεκαρφίτσωμα" + "Προβολή" "Προβολή στο χρονοδιάγραμμα" "Προβολή πηγής" "Ναι" @@ -145,13 +180,17 @@ "Διαθέσιμη αναβάθμιση" "Σχετικά" "Πολιτική αποδεκτής χρήσης" + "Προσθέστε έναν λογαριασμό" + "Προσθήκη άλλου λογαριασμού" "Η λεζάντα προστίθεται" "Ρυθμίσεις για προχωρημένους" "μια εικόνα" "Στατιστικά στοιχεία" "Αποχωρήσατε από την αίθουσα" + "Αποσυνδεθήκατε από την περίοδο λειτουργίας" "Εμφάνιση" "Ήχος" + "Δοκιμαστική" "Αποκλεισμένοι χρήστες" "Φυσαλίδες" "Η κλήση ξεκίνησε" @@ -159,11 +198,14 @@ "Αντιγράφηκε στο πρόχειρο" "Πνευματικά δικαιώματα" "Δημιουργία αίθουσας…" + "Δημιουργία χώρου…" "Το αίτημα ακυρώθηκε" "Αποχώρησε από την αίθουσα" + "Αποχωρήσατε από τον χώρο" "Η πρόσκληση απορρίφθηκε" "Σκοτεινό" "Σφάλμα αποκρυπτογράφησης" + "Περιγραφή" "Επιλογές προγραμματιστή" "ID συσκευής" "Άμεση συνομιλία" @@ -198,9 +240,11 @@ "Εγκατάσταση APK" "Αυτό το Matrix ID δεν μπορεί να βρεθεί, επομένως η πρόσκληση ενδέχεται να μην ληφθεί." "Αποχώρηση από την αίθουσα" + "Αποχωρείτε από τον χώρο" "Φωτεινό" "Η γραμμή αντιγράφηκε στο πρόχειρο" "Ο σύνδεσμος αντιγράφηκε στο πρόχειρο" + "Σύνδεση νέας συσκευής" "Φόρτωση…" "Φόρτωση περισσότερων…" @@ -208,18 +252,21 @@ "%d ακόμη" - "%1$d μέλος" - "%1$d μέλη" + "%1$d Μέλος" + "%1$d Μέλη" "Μήνυμα" "Ενέργειες μηνυμάτων" + "Αποτυχία αποστολής μηνύματος" "Διάταξη μηνύματος" "Το μήνυμα αφαιρέθηκε" "Σύγχρονη" "Σίγαση" + "Όνομα" "%1$s (%2$s)" "Κανένα αποτέλεσμα" "Δεν υπάρχει όνομα αίθουσας" + "Δεν υπάρχει όνομα χώρου" "Χωρίς κρυπτογράφηση" "Εκτός σύνδεσης" "Άδειες ανοιχτού κώδικα" @@ -239,14 +286,20 @@ "%d ψήφος" "%d ψήφοι" + "Προετοιμασία…" "Πολιτική απορρήτου" + "Ιδιωτικό" "Ιδιωτική αίθουσα" + "Ιδιωτικός χώρος" + "Δημόσιο" "Δημόσια αίθουσα" + "Δημόσιος χώρος" "Αντίδραση" "Αντιδράσεις" "Αιτιολογία" "Κλειδί ανάκτησης" "Ανανέωση…" + "Αφαίρεση…" "%1$d απάντηση" "%1$d απαντήσεις" @@ -256,9 +309,14 @@ "Αναφορά προβλήματος" "Η αναφορά υποβλήθηκε" "Επεξεργαστής εμπλουτισμένου κειμένου" + "Ρόλος" "Αίθουσα" "Όνομα αίθουσας" - "πχ. το όνομα του έργου σου" + "π.χ. το όνομα του έργου σας" + + "%1$d Αίθουσα" + "%1$d Αίθουσες" + "Αποθηκευμένες αλλαγές" "Αποθηκεύεται" "Κλείδωμα οθόνης" @@ -266,21 +324,38 @@ "Αποτελέσματα αναζήτησης" "Ασφάλεια" "Προβλήθηκε από" + "Επιλέξτε έναν λογαριασμό" + + "%1$d επιλέχθηκε" + "%1$d επιλέχθηκαν" + "Αποστολή σε" "Αποστολή…" "Αποτυχία αποστολής" "Εστάλη" ". " "Ο διακομιστής δεν υποστηρίζεται" + "Ο διακομιστής δεν είναι προσβάσιμος" "URL διακομιστή" "Ρυθμίσεις" + "Κοινή χρήση χώρου" + "Τα νέα μέλη βλέπουν το ιστορικό" "Κοινόχρηστη τοποθεσία" + "Κοινόχρηστος χώρος" "Αποσύνδεση" "Κάτι πήγε στραβά" "Αντιμετωπίσαμε ένα πρόβλημα. Παρακαλώ προσπαθήστε ξανά." + "Χώρος" + "Μέλη χώρου" + "Τι αφορά αυτός ο χώρος;" + + "%1$d Χώρος" + "%1$d Χώροι" + "Έναρξη συνομιλίας…" "Αυτοκόλλητο" "Επιτυχία" + "Προτεινόμενο" "Προτάσεις" "Συγχρονισμός" "Σύστημα" @@ -308,20 +383,35 @@ "Επαλήθευση ταυτότητας" "Επαλήθευση χρήστη" "Βίντεο" + "Υψηλή ποιότητα" + "Καλύτερη ποιότητα αλλά μεγαλύτερο μέγεθος αρχείου" + "Χαμηλή ποιότητα" + "Ταχύτερη ταχύτητα μεταφόρτωσης και μικρότερο μέγεθος αρχείου" + "Τυπική ποιότητα" + "Ισορροπία μεταξύ ποιότητας και ταχύτητας μεταφόρτωσης" "Φωνητικό μήνυμα" "Αναμονή…" "Αναμονή για αυτό το μήνυμα" + "Οποιοσδήποτε μπορεί να δει το ιστορικό" "Εσύ" + "%1$s (%2$s) μοιράστηκε αυτό το μήνυμα, καθώς δεν ήσασταν στην αίθουσα όταν στάλθηκε." + "%1$s μοιράστηκε αυτό το μήνυμα, ενόσω δεν ήσασταν στην αίθουσα όταν στάλθηκε." + "Αυτή η αίθουσα έχει διαμορφωθεί έτσι ώστε τα νέα μέλη να μπορούν να διαβάσουν το ιστορικό. %1$s" "Η ταυτότητα του χρήστη %1$s επαναφέρθηκε. %2$s" "Η ταυτότητα του %1$s %2$s επαναφέρθηκε. %3$s" "(%1$s)" "Η ταυτότητα του χρήστη %1$s επαναφέρθηκε." "Η ταυτότητα του χρήστη %1$s %2$s επαναφέρθηκε. %3$s" "Ανάκληση επαλήθευσης" + "Επιτρέψτε την πρόσβαση" "Ο σύνδεσμος %1$s σας μεταφέρει σε άλλο ιστότοπο %2$s Είστε βέβαιοι ότι θέλετε να συνεχίσετε;" "Ελέγξτε ξανά αυτόν τον σύνδεσμο" + "Επιλέξτε την προεπιλεγμένη ποιότητα των βίντεο που ανεβάζετε." + "Ποιότητα μεταφόρτωσης βίντεο" + "Το μέγιστο επιτρεπόμενο μέγεθος αρχείου είναι: %1$s" + "Το μέγεθος του αρχείου είναι πολύ μεγάλο για μεταφόρτωση" "Η αίθουσα αναφέρθηκε" "Αναφέρθηκε και αποχωρήσατε από την αίθουσα" "Επιβεβαίωση" @@ -331,6 +421,11 @@ "Έχεις μη αποθηκευμένες αλλαγές." "Οι αλλαγές σου δεν έχουν αποθηκευτεί. Σίγουρα θες να πας πίσω;" "Αποθήκευση αλλαγών;" + "Το μέγιστο επιτρεπόμενο μέγεθος αρχείου είναι: %1$s" + "Επιλέξτε την ποιότητα του βίντεο που θέλετε να ανεβάσετε." + "Επιλέξτε την ποιότητα μεταφόρτωσης βίντεο" + "Αναζήτηση emoji" + "Έχετε ήδη συνδεθεί σε αυτή τη συσκευή ως %1$s." "Ο οικιακός διακομιστής σου πρέπει να αναβαθμιστεί για να υποστηρίζει το Matrix Authentication Service και τη δημιουργία λογαριασμού." "Αποτυχία δημιουργίας του μόνιμου συνδέσμου" "%1$s δεν ήταν δυνατή η φόρτωση του χάρτη. Παρακαλώ δοκίμασε ξανά αργότερα." @@ -351,6 +446,7 @@ "Γεια, μίλα μου στην εφαρμογή %1$s :%2$s" "%1$s Android" "Κούνησε δυνατά τη συσκευή σου για να αναφέρεις κάποιο σφάλμα" + "Στιγμιότυπο οθόνης" "%1$s: %2$s" "Επιλογές" "Αφαίρεση %1$s" @@ -373,6 +469,7 @@ "Το μήνυμά σου δεν στάλθηκε επειδή ο χρήστης %1$s δεν έχει επαληθεύσει όλες τις συσκευές" "Μία ή περισσότερες από τις συσκευές σου δεν έχουν επαληθευτεί. Μπορείς να στείλεις το μήνυμα ούτως ή άλλως, ή μπορείς να το ακυρώσεις προς το παρόν και να προσπαθήσεις ξανά αργότερα αφού επαληθεύσεις όλες τις συσκευές σου." "Το μήνυμά σου δεν στάλθηκε επειδή δεν έχεις επαληθεύσει τουλάχιστον μία από τις συσκευές σου" + "Επεξεργασία διαχειριστών ή κατόχων" "Αποτυχία μεταφόρτωσης μέσου, δοκίμασε ξανά." "Δεν ήταν δυνατή η ανάκτηση στοιχείων χρήστη" "Μήνυμα στο %1$s" @@ -390,6 +487,11 @@ "Άνοιγμα στο Google Maps" "Άνοιγμα στο OpenStreetMap" "Κοινή χρήση αυτής της τοποθεσίας" + "Χώροι που έχετε δημιουργήσει ή στους οποίους έχετε συμμετάσχει." + "%1$s • %2$s" + "Δημιουργήστε χώρους για να οργανώσετε αίθουσες" + "%1$s χώρος" + "Χώροι" "Το μήνυμα δεν στάλθηκε γιατί έγινε επαναφορά της επαληθευμένης ταυτότητας του χρήστη %1$s." "Το μήνυμα δεν στάλθηκε επειδή ο χρήστης %1$s δεν έχει επαληθεύσει όλες τις συσκευές." "Το μήνυμα δεν στάλθηκε επειδή δεν έχεις επαληθεύσει τουλάχιστον μία από τις συσκευές σου." diff --git a/libraries/ui-strings/src/main/res/values-es/translations.xml b/libraries/ui-strings/src/main/res/values-es/translations.xml index 4d47792f1a..fa0bc700cb 100644 --- a/libraries/ui-strings/src/main/res/values-es/translations.xml +++ b/libraries/ui-strings/src/main/res/values-es/translations.xml @@ -1,5 +1,6 @@ + "Añadir reacción: %1$s" "Avatar" "Borrar" @@ -28,10 +29,13 @@ "Leído por %1$s" "Pulsa para mostrar todo" "Elimina la reacción con %1$s" + "Retirar la reacción con %1$s" + "Avatar de la sala" "Enviar archivos" "Mostrar contraseña" "Iniciar llamada" "Menú de usuario" + "Ver avatar" "Mostrar detalles" "Mensaje de voz, duración: %1$s" "Grabar mensaje de voz" @@ -102,7 +106,7 @@ "Reaccionar" "Rechazar" "Eliminar" - "Eliminar leyenda" + "Quitar leyenda" "Eliminar mensaje" "Responder" "Responder en el hilo" @@ -135,6 +139,7 @@ "Toca para ver opciones" "Intentar de nuevo" "Desprender" + "Ver" "Ver en la cronología" "Ver fuente" "Sí" @@ -145,6 +150,7 @@ "Política de uso aceptable" "Añadiendo leyenda" "Ajustes avanzados" + "una imagen" "Estadísticas" "Saliste de la sala" "Apariencia" @@ -329,6 +335,7 @@ Motivo: %1$s." "Error al cargar mensajes" "%1$s no ha podido acceder a tu ubicación. Por favor vuelve a intentarlo más tarde." "No se pudo cargar tu mensaje de voz." + "La sala ya no existe o la invitación ya no es válida." "Mensaje no encontrado" "%1$s no tiene permiso para acceder a tu ubicación. Puedes habilitar el acceso en Ajustes." "%1$s no tiene permiso para acceder a tu ubicación. Habilita el acceso a continuación." @@ -342,6 +349,8 @@ Motivo: %1$s." "Hola, puedes hablar conmigo en %1$s: %2$s" "%1$s Android" "Agitar con fuerza para informar de un error" + "Opciones" + "Ajustes" "Error al seleccionar archivos multimedia, por favor inténtalo de nuevo." "Presiona sobre un mensaje y selecciona «%1$s» para incluirlo aquí." "Fija los mensajes importantes para que se puedan descubrir fácilmente" @@ -363,6 +372,9 @@ Motivo: %1$s." "Error al procesar el contenido multimedia, por favor inténtalo de nuevo." "No se pudieron recuperar los detalles del usuario" "Mensaje en %1$s" + "Expandir" + "Reducir" + "¡Ya estás viendo esta sala!" "%1$s de %2$s" "%1$s mensajes fijados" "Cargando mensaje…" 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 2b0adb66e6..53f2178a1a 100644 --- a/libraries/ui-strings/src/main/res/values-et/translations.xml +++ b/libraries/ui-strings/src/main/res/values-et/translations.xml @@ -28,6 +28,7 @@ "Häälsõnum, kestus:%1$s, praegune asukoht: %2$s" "PIN-koodi väli" "Esita" + "Taasesituse kiirus" "Küsitlus" "Lõppenud küsitlus" "QR-kood" diff --git a/libraries/ui-strings/src/main/res/values-fi/translations.xml b/libraries/ui-strings/src/main/res/values-fi/translations.xml index bc1e0ab604..bdbc8e5946 100644 --- a/libraries/ui-strings/src/main/res/values-fi/translations.xml +++ b/libraries/ui-strings/src/main/res/values-fi/translations.xml @@ -1,6 +1,7 @@ "Lisää reaktio: %1$s" + "Osoite" "Avatar" "Pienennä viestin tekstikenttä" "Poista" @@ -27,8 +28,10 @@ "Ääniviesti, kesto: %1$s, nykyinen sijainti: %2$s" "PIN-kenttä" "Toista" + "Toistonopeus" "Kysely" "Päättynyt kysely" + "QR-koodi" "Lisää reaktio: %1$s" "Reagoi muilla emojeilla" "%1$s ja %2$s on lukenut viestin" @@ -56,6 +59,7 @@ "Avatarisi" "Hyväksy" "Lisää kuvateksti" + "Lisää olemassa olevia huoneita" "Lisää aikajanalle" "Takaisin" "Soita" @@ -75,6 +79,7 @@ "Kopioi teksti" "Luo" "Luo huone" + "Luo tila" "Deaktivoi" "Deaktivoi tili" "Hylkää" @@ -91,6 +96,7 @@ "Ota käyttöön" "Lopeta kysely" "Syötä PIN-koodi" + "Selaa julkisia tiloja" "Valmis" "Unohditko salasanan?" "Välitä" @@ -150,6 +156,7 @@ "Lähetä ääniviesti" "Jaa" "Jaa linkki" + "Jaa reaaliaikainen sijainti" "Näytä" "Kirjaudu uudelleen" "Kirjaudu ulos" @@ -162,6 +169,7 @@ "Lataa kartta napauttamalla" "Ota kuva" "Näytä vaihtoehdot napauttamalla" + "Käännä" "Yritä uudelleen" "Poista kiinnitys" "Näytä" @@ -191,6 +199,7 @@ "Kopioitu leikepöydälle" "Tekijänoikeudet" "Luodaan huonetta…" + "Luodaan tilaa…" "Pyyntö peruutettu" "Poistuit huoneesta" "Poistuit tilasta" @@ -236,6 +245,7 @@ Syy: %1$s." "Vaalea" "Rivi kopioitu leikepöydälle" "Linkki kopioitu leikepöydälle" + "Yhdistä uusi laite" "Ladataan…" "Ladataan lisää…" @@ -248,10 +258,12 @@ Syy: %1$s." "Viesti" "Viestitoiminnot" + "Viestin lähettäminen epäonnistui" "Viestien asettelu" "Viesti poistettu" "Moderni" "Mykistä" + "Nimi" "%1$s (%2$s)" "Ei tuloksia" "Nimetön huone" @@ -277,8 +289,10 @@ Syy: %1$s." "Valmistellaan…" "Tietosuojakäytäntö" + "Yksityinen" "Yksityinen huone" "Yksityinen tila" + "Julkinen" "Julkinen huone" "Julkinen tila" "Reaktio" @@ -286,6 +300,7 @@ Syy: %1$s." "Syy" "Palautusavain" "Päivitetään…" + "Poistetaan…" "%1$d vastaus" "%1$d vastausta" @@ -295,6 +310,7 @@ Syy: %1$s." "Ilmoita ongelmasta" "Ilmoitus lähetetty" "Rikastettu tekstieditori" + "Rooli" "Huone" "Huoneen nimi" "esim. projektisi nimi" @@ -310,6 +326,10 @@ Syy: %1$s." "Turvallisuus" "Nähneet henkilöt" "Valitse tili" + + "%1$d valittu" + "%1$d valittu" + "Jaa" "Lähetetään…" "Lähetys epäonnistui" @@ -320,12 +340,15 @@ Syy: %1$s." "Palvelimen osoite" "Asetukset" "Jaa tila" + "Uudet jäsenet näkevät historian" "Jaettu sijainti" "Jaettu tila" "Kirjaudutaan ulos" "Jokin meni pieleen" "Kohtasimme ongelman. Yritä uudelleen." "Tila" + "Tilan jäsenet" + "Mistä tässä tilassa on kyse?" "%1$d Tila" "%1$d Tilaa" @@ -333,6 +356,7 @@ Syy: %1$s." "Aloitetaan keskustelua…" "Tarra" "Onnistui" + "Ehdotettu" "Ehdotukset" "Synkronoidaan" "Järjestelmän oletus" @@ -369,13 +393,18 @@ Syy: %1$s." "Ääniviesti" "Odotetaan…" "Odotetaan viestiä" + "Kuka tahansa voi nähdä historian" "Sinä" + "%1$s (%2$s) jakoi tämän viestin, koska et ollut huoneessa, kun se lähetettiin." + "%1$s jakoi tämän viestin, koska et ollut huoneessa, kun se lähetettiin." + "Tämä huone on määritetty niin, että uudet jäsenet voivat lukea historiaa. %1$s" "Käyttäjän %1$s identiteetti nollattiin. %2$s" "Käyttäjän %1$s %2$s identiteetti nollattiin. %3$s" "(%1$s)" "Käyttäjän %1$s identiteetti nollattiin." "Käyttäjän %1$s %2$s identiteetti nollattiin. %3$s" "Peruuta vahvistus" + "Anna käyttölupa" "Linkki %1$s on viemässä sinua toiselle sivustolle %2$s Haluatko varmasti jatkaa?" @@ -461,6 +490,7 @@ Haluatko varmasti jatkaa?" "Jaa tämä sijainti" "Luomasi tai liittymäsi tilat." "%1$s • %2$s" + "Luo tiloja huoneiden järjestämiseksi" "%1$s tila" "Tilat" "Viestiä ei lähetetty, koska käyttäjän %1$s vahvistettu identiteetti nollattiin." diff --git a/libraries/ui-strings/src/main/res/values-fr/translations.xml b/libraries/ui-strings/src/main/res/values-fr/translations.xml index 18ffa891a4..9f28eabf9a 100644 --- a/libraries/ui-strings/src/main/res/values-fr/translations.xml +++ b/libraries/ui-strings/src/main/res/values-fr/translations.xml @@ -1,6 +1,7 @@ "Ajouter une réaction: %1$s" + "Adresse" "Avatar" "Réduire la taille du composeur" "Supprimer" @@ -27,8 +28,10 @@ "Message vocal, durée: %1$s, position actuelle: %2$s" "Code PIN" "Lecture" + "Vitesse de lecture" "Sondage" "Sondage terminé" + "Code QR" "Réagir avec %1$s" "Réagir avec d’autres émojis" "Lu par %1$s et %2$s" @@ -400,6 +403,7 @@ Raison : %1$s." "L’identité de %1$s a été réinitialisée." "L’identité de %1$s %2$s a été réinitialisée. %3$s" "Révoquer la vérification" + "Autoriser l’accès" "Le lien \"%1$s\" vous redirige vers un autre site \"%2$s\". Êtes-vous sûr de vouloir continuer ?" 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 ffcec0bf05..2e7975518d 100644 --- a/libraries/ui-strings/src/main/res/values-hu/translations.xml +++ b/libraries/ui-strings/src/main/res/values-hu/translations.xml @@ -1,6 +1,7 @@ "Reakció hozzáadása: %1$s" + "Cím" "Profilkép" "Üzenet szövegmezőjének minimalizálása" "Törlés" @@ -27,8 +28,10 @@ "Hangüzenet, időtartam:%1$s, jelenlegi pozíció:%2$s" "PIN-mező" "Lejátszás" + "Lejátszási sebesség" "Szavazás" "Befejezett szavazás" + "QR-kód" "Reagálás a következővel: %1$s" "Reagálás más emodzsikkal" "Olvasta: %1$s és %2$s" @@ -285,8 +288,10 @@ Ok: %1$s." "Előkészítés…" "Adatvédelmi nyilatkozat" + "Privát" "Privát szoba" "Privát tér" + "Nyilvános" "Nyilvános szoba" "Nyilvános tér" "Reakció" @@ -340,6 +345,7 @@ Ok: %1$s." "Valamilyen hiba történt" "Problémába ütköztünk. Próbálja újra." "Tér" + "A tér tagjai" "Miről szól ez a tér?" "%1$d tér" @@ -384,7 +390,8 @@ Ok: %1$s." "A minőség és a feltöltési sebesség egyensúlya." "Hangüzenet" "Várakozás…" - "Várakozás a visszafejtési kulcsra" + "Várakozás erre az üzenetre" + "Bárki láthatja az előzményeket" "Ön" "%1$s (%2$s) megosztotta ezt az üzenetet, mivel Ön nem volt a szobában, amikor elküldték." "%1$s megosztotta ezt az üzenetet, mivel Ön nem volt a szobában, amikor elküldték." diff --git a/libraries/ui-strings/src/main/res/values-nb/translations.xml b/libraries/ui-strings/src/main/res/values-nb/translations.xml index 1abe6fd0a3..a81b206c19 100644 --- a/libraries/ui-strings/src/main/res/values-nb/translations.xml +++ b/libraries/ui-strings/src/main/res/values-nb/translations.xml @@ -1,6 +1,7 @@ "Legg til reaksjon: %1$s" + "Adresse" "Profilbilde" "Minimer meldingstekstfeltet" "Slett" @@ -15,7 +16,7 @@ "Skjul passord" "Bli med i samtale" "Hopp til bunnen" - "Flytt kartet til min lokasjon" + "Flytt kartet til min posisjon" "Bare omtaler" "Dempet" "Nye omtaler" @@ -27,8 +28,10 @@ "Talemelding, lengde: %1$s, nåværende posisjon: %2$s" "PIN-felt" "Spill av" + "Avspillingshastighet" "Avstemning" "Avsluttet avstemning" + "QR-kode" "Reager med %1$s" "Reager med andre emojier" "Lest av %1$s og %2$s" @@ -93,6 +96,7 @@ "Aktiver" "Avslutt avstemning" "Skriv inn PIN-koden" + "Utforsk offentlige områder" "Fullfør" "Glemt passordet?" "Videresend" @@ -152,6 +156,7 @@ "Send talemelding" "Dele" "Dele lenke" + "Del posisjon i sanntid" "Vis" "Logg på igjen" "Logg ut" @@ -284,8 +289,10 @@ "Forbereder…" "Retningslinjer for personvern" + "Privat" "Privat rom" "Privat område" + "Offentlig" "Offentlig rom" "Offentlig område" "Reaksjon" @@ -293,6 +300,7 @@ "Årsak" "Gjenopprettingsnøkkel" "Oppdaterer…" + "Fjerner…" "%1$d svar" @@ -301,6 +309,7 @@ "Rapporter et problem" "Rapport sendt inn" "Redigeringsprogram for rik tekst" + "Rolle" "Rom" "Romnavn" "f.eks. prosjektnavnet ditt" @@ -316,6 +325,10 @@ "Sikkerhet" "Sett av" "Velg en konto" + + "%1$d valgt" + "%1$d valgt" + "Sendt til" "Sender…" "Kunne ikke sende" @@ -325,12 +338,14 @@ "URL-adresse til server" "Innstillinger" "Del område" + "Nye medlemmer ser historikk" "Delt posisjon" "Delt område" "Logger av" "Noe gikk galt" "Vi har støtt på et problem. Vennligst prøv igjen." "Område" + "Medlemmer av område" "Hva handler dette området om?" "%1$d Område" @@ -376,6 +391,7 @@ "Talemelding" "Venter…" "Venter på denne meldingen" + "Alle kan se historikk" "Du" "Dette rommet er konfigurert slik at nye medlemmer kan lese historikken.%1$s" "%1$s\'s identitet ble tilbakestilt. %2$s" @@ -384,6 +400,7 @@ "%1$ss identitet ble tilbakestilt." "%1$ss %2$s identitet ble tilbakestilt. %3$s" "Trekk tilbake verifisering" + "Tillat tilgang" "Lenken %1$s tar deg til et annet nettsted %2$s Er du sikker på at du vil fortsette?" @@ -410,12 +427,12 @@ Er du sikker på at du vil fortsette?" "Opprettelse av permalenken mislyktes" "%1$s kunne ikke laste inn kartet. Prøv igjen senere." "Kunne ikke laste inn meldinger" - "%1$s fikk ikke tilgang til lokasjonen din. Vennligst prøv igjen senere." + "%1$s fikk ikke tilgang til posisjonen din. Vennligst prøv igjen senere." "Kunne ikke laste opp talemeldingen din." "Rommet eksisterer ikke lenger, eller invitasjonen er ikke lenger gyldig." "Melding ikke funnet" - "%1$s har ikke tilgang til lokasjonen din. Du kan aktivere tilgang i Innstillinger." - "%1$s har ikke tilgang til lokasjonen din. Aktiver tilgang nedenfor." + "%1$s har ikke tilgang til posisjonen din. Du kan aktivere tilgang i Innstillinger." + "%1$s har ikke tilgang til posisjonen din. Aktiver tilgang nedenfor." "%1$s har ikke tilgang til mikrofonen din. Aktiver tilgang til å ta opp en talemelding." "Dette kan skyldes nettverks- eller serverproblemer." "Denne romadressen finnes allerede. Prøv å redigere romadressefeltet eller endre romnavnet" @@ -461,12 +478,12 @@ Er du sikker på at du vil fortsette?" "Laster inn melding…" "Vis alle" "Chat" - "Del lokasjon" - "Del min lokasjon" + "Del posisjon" + "Del min posisjon" "Åpne i Apple Maps" "Åpne i Google Maps" "Åpne i OpenStreetMap" - "Del denne lokasjonen" + "Del denne posisjonen" "Områder du har opprettet eller blitt med i." "%1$s • %2$s" "Opprett område for å organisere rom" @@ -475,7 +492,7 @@ Er du sikker på at du vil fortsette?" "Meldingen ble ikke sendt fordi %1$ss verifiserte identitet er tilbakestilt." "Meldingen ble ikke sendt fordi %1$s ikke har verifisert alle enheter." "Meldingen ble ikke sendt fordi du ikke har verifisert en eller flere av enhetene dine." - "Lokasjon" + "Posisjon" "Versjon: %1$s (%2$s)" "en" "Historiske meldinger er ikke tilgjengelige på denne enheten" diff --git a/libraries/ui-strings/src/main/res/values-nl/translations.xml b/libraries/ui-strings/src/main/res/values-nl/translations.xml index b9675f8f76..6e136e7d77 100644 --- a/libraries/ui-strings/src/main/res/values-nl/translations.xml +++ b/libraries/ui-strings/src/main/res/values-nl/translations.xml @@ -1,13 +1,13 @@ "Reactie toevoegen: %1$s" - "Afbeelding" + "Avatar" "Verwijderen" "%1$d cijfer ingevoerd" "%1$d cijfers ingevoerd" - "Afbeelding bewerken" + "Avatar bewerken" "Het volledige adres wordt %1$s" "Wachtwoord verbergen" "Deelnemen aan gesprek" @@ -85,6 +85,7 @@ "Activeren" "Peiling beëindigen" "Voer pincode in" + "Ontdek openbare spaces" "Wachtwoord vergeten?" "Doorsturen" "Terug" @@ -118,7 +119,7 @@ "Bijschrift verwijderen" "Bericht verwijderen" "Antwoorden" - "Antwoord in subchat" + "Antwoord in gesprek" "Melden" "Probleem melden" "Inhoud melden" @@ -236,12 +237,18 @@ Reden: %1$s." "%d stemmen" "Privacybeleid" + "Privé" "Privé kamer" + "Openbaar" "Openbare kamer" "Reactie" "Reacties" "Herstelsleutel" "Verversen…" + + "%1$d antwoord" + "%1$d antwoorden" + "Reageren op %1$s" "Een fout melden" "Meld een probleem" @@ -275,7 +282,7 @@ Reden: %1$s." "Systeem" "Tekst" "Kennisgevingen van derden" - "Subchat" + "Gesprek" "Onderwerp" "Waar gaat deze kamer over?" "Kan niet ontsleutelen" 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 1d4379d9a2..ddc3fdeaca 100644 --- a/libraries/ui-strings/src/main/res/values-ru/translations.xml +++ b/libraries/ui-strings/src/main/res/values-ru/translations.xml @@ -95,6 +95,7 @@ "Включить" "Завершить опрос" "Введите PIN-код" + "Просмотреть публичные пространства" "Завершить" "Забыли пароль?" "Переслать" @@ -309,6 +310,7 @@ "Сообщить о проблеме" "Отчет отправлен" "Редактор форматированного текста" + "Роль" "Комната" "Название комнаты" "например, название вашего проекта" @@ -340,12 +342,14 @@ "Адрес сервера" "Настройки" "Поделиться пространством" + "Новые участники видят историю" "Поделился местоположением" "Общее пространство" "Выход…" "Что-то пошло не так" "Мы столкнулись с проблемой. Пожалуйста, попробуйте еще раз." "Пространство" + "Участники пространства" "О чём это пространство?" "%1$d Пространство" @@ -393,6 +397,7 @@ "Ожидание…" "Ожидание ключа расшифровки" "Вы" + "%1$s (%2$s) поделился этим сообщением, поскольку вас не было в комнате, когда оно было отправлено." "%1$s поделился этим сообщением, поскольку вас не было в комнате, когда оно было отправлено." "Эта комната оборудована таким образом, чтобы новые участники могли ознакомиться с историей. %1$s" "Идентификатор %1$s изменился. %2$s" diff --git a/libraries/ui-strings/src/main/res/values-tr/translations.xml b/libraries/ui-strings/src/main/res/values-tr/translations.xml index 26de6080dd..d92daa6527 100644 --- a/libraries/ui-strings/src/main/res/values-tr/translations.xml +++ b/libraries/ui-strings/src/main/res/values-tr/translations.xml @@ -1,18 +1,30 @@ + "Tepki ekle:%1$s" "Profil resmi" + "Mesaj metin alanını küçült" "Sil" "%1$d basamak girildi" "%1$d basamak girildi" + "Fotoğrafı düzenle" + "Tam adres %1$s olacaktır" + "Şifreleme ayrıntıları" + "Mesaj metin alanını genişlet" "Şifreyi gizle" "Aramaya katıl" "Aşağıya atla" + "Haritayı konumuma taşı" "Yalnızca bahsetmeler" "Sessiz" + "Yeni bahsetmeler" + "Yeni mesajlar" + "Devam eden arama" + "Diğer kullanıcının avatarı" "Sayfa %1$d" "Duraklat" + "Sesli mesaj, süre: %1$s, geçerli konum: %2$s" "PIN alanı" "Oynat" "Anket" @@ -27,13 +39,18 @@ "Okuyan %1$s" "Tümünü göstermek için dokunun" "Tepkimeyi kaldır %1$s" + "%1$s ile verilen tepkiyi kaldır" + "Oda avatarı" "Dosyaları gönder" + "Zaman sınırlı işlem gerekli, doğrulamak için bir dakikanız var" "Şifreyi göster" "Bir arama başlatın" + "Kullanıcı avatarı" "Kullanıcı menüsü" "Ayrıntıları görüntüle" "Sesli mesajı kaydedin." "Kaydı durdur" + "Fotoğrafın" "Kabul et" "Açıklama ekle" "Zaman çizelgesine ekle" @@ -51,7 +68,7 @@ "Kopyala" "Açıklamayı kopyala" "Bağlantıyı kopyala" - "Bağlantıyı mesaja kopyala" + "Mesaj bağlantısını kopyala" "Metni kopyala" "Oluştur" "Bir oda oluştur" @@ -59,6 +76,7 @@ "Hesabı devre dışı bırak" "Reddet" "Anketi Sil" + "Seçimi kaldır" "Devre dışı" "Vazgeç" "Kapat" @@ -70,12 +88,12 @@ "Anketi sonlandır" "PIN girin" "Parolanızı mı unuttunuz?" - "İleri" + "İlet" "Geri dön" "Yoksay" "Davet et" - "İnsanları davet et" - "İnsanları davet et %1$s" + "Kişileri davet et" + "Kişileri %1$s\'ye davet et" "İnsanları davet et %1$s" "Davetiyeler" "Katıl" @@ -86,6 +104,7 @@ "Daha fazla yükle" "Hesabı yönet" "Cihazları yönet" + "Odaları yönet" "Mesaj" "Sonraki" "Hayır" @@ -127,6 +146,7 @@ "Haritayı yüklemek için dokunun" "Fotoğraf çek" "Seçenekler için dokunun" + "Çeviri" "Tekrar deneyin" "Sabitlemeyi kaldır" "Zaman çizelgesinde görüntüle" @@ -137,6 +157,8 @@ "Yükseltme mevcut" "Hakkında" "Kabul edilebilir kullanım politikası" + "Hesap ekle" + "Başka bir hesap ekle" "Açıklama ekleme" "Gelişmiş Ayarlar" "Analizler" @@ -211,6 +233,7 @@ Neden: %1$s." "%1$s (%2$s)" "Sonuç yok" "Oda adı yok" + "Alan adı yok" "Şifrelenmemiş" "Çevrimdışı" "Açık kaynak lisansları" @@ -229,11 +252,15 @@ Neden: %1$s." "%d oy" "%d oy" + "Hazırlanıyor…" "Gizlilik Politikası" "Özel oda" + "Özel alan" "Herkese açık oda" + "Herkese açık alan" "Tepki" "Tepkiler" + "Neden" "Kurtarma anahtarı" "Yenileniyor…" "Cevaplamak için %1$s" @@ -251,6 +278,7 @@ Neden: %1$s." "Arama sonuçları" "Güvenlik" "Tarafından görüldü" + "Hesap seç" "Şuraya gönder" "Gönderiliyor…" "Gönderme başarısız oldu" @@ -261,6 +289,8 @@ Neden: %1$s." "Paylaşılan konum" "Oturumu kapatma" "Bir şeyler ters gitti" + "Bir sorunla karşılaştık. Lütfen tekrar deneyin." + "Bu alan ne hakkında?" "Sohbet başlatılıyor…" "Çıkartma" "Başarılı" @@ -291,6 +321,8 @@ Neden: %1$s." "Kimliği doğrula" "Kullanıcıyı Doğrula" "Video" + "Yüksek kalite" + "En iyi kalite ancak daha büyük dosya boyutu" "Sesli Mesaj" "Bekleniyor…" "Bu mesajı bekliyorum" @@ -305,6 +337,8 @@ Neden: %1$s." Devam etmek istediğinizden emin misiniz?" "Bu bağlantıyı tekrardan kontrol edin" + "Yüklediğiniz videoların varsayılan kaliteyi seçin." + "Video yükleme kalitesi" "Onaylama" "Hata" "Başarılı" @@ -318,6 +352,7 @@ Devam etmek istediğinizden emin misiniz?" "Mesajlar yüklenemedi" "%1$s konumunuza erişemedi. Lütfen daha sonra tekrar deneyin." "Sesli mesajınız yüklenemedi." + "Oda artık mevcut değil veya davet artık geçerli değil." "Mesaj bulunamadı" "%1$s konumunuza erişim iznine sahip değil. Erişimi Ayarlar\'dan etkinleştirebilirsiniz." "%1$s konumunuza erişim iznine sahip değil. Aşağıdan erişimi etkinleştirin." @@ -349,8 +384,11 @@ Devam etmek istediğinizden emin misiniz?" "%1$s tüm cihazları doğrulamadığı için mesajınız gönderilmedi" "Bir veya daha fazla cihazınız doğrulanmamış. Mesajı yine de gönderebilir veya şimdilik iptal edip tüm cihazlarınızı doğruladıktan sonra tekrar deneyebilirsiniz." "Bir veya daha fazla cihazınızı doğrulamadığınız için mesajınız gönderilmedi" + "Yöneticileri veya Sahipleri Düzenle" "Medya yüklenemedi, lütfen tekrar deneyin." "Kullanıcı ayrıntıları alınamadı" + "Daha fazla" + "Daha az" "%1$s / %2$s" "%1$s Sabitlenmiş mesajlar" "Mesaj yükleniyor…" @@ -362,6 +400,8 @@ Devam etmek istediğinizden emin misiniz?" "Google Maps\'te aç" "OpenStreetMap\'te aç" "Bu konumu paylaş" + "Oluşturduğunuz veya katıldığınız alanlar." + "Alanlar" "%1$s kullanıcısının doğrulanmış kimliği değiştiği için ileti gönderilmedi." "%1$s tüm cihazları doğrulamadığı için mesaj gönderilmedi." "Bir veya daha fazla cihazınızı doğrulamadığınız için mesaj gönderilmedi." diff --git a/libraries/ui-strings/src/main/res/values-uz/translations.xml b/libraries/ui-strings/src/main/res/values-uz/translations.xml index 22fa0a173a..aada6634d2 100644 --- a/libraries/ui-strings/src/main/res/values-uz/translations.xml +++ b/libraries/ui-strings/src/main/res/values-uz/translations.xml @@ -80,6 +80,7 @@ "Rad etish" "Rad etish va bloklash" "So‘rovnomani o‘chirish" + "Hammasini bekor qilish" "Oʻchirish" "Bekor qilish" "Bekor qilish" @@ -94,6 +95,8 @@ "Parolni unutdingizmi?" "Oldinga" "Ortga qaytish" + "Rollar va ruxsatlarga kirish" + "Sozlamalarga o‘tish" "E’tiborsiz qoldirish" "Taklif qilish" "Odamlarni taklif qiling" @@ -105,10 +108,13 @@ "Tark etish" "Suhbatni tark etish" "Xonani tark etish" + "Maydondan chiqish" "Ko\'proq yuklash" "Hisobni boshqarish" "Qurilmalarni boshqarish" + "Xonalarni boshqarish" "Xabar" + "Kichraytirmoq" "Keyingisi" "Yo\'q" "Hozir emas" @@ -137,6 +143,7 @@ "Shifrni ochishni qayta urinish" "Saqlash" "Qidirmoq" + "Barchasini tanlash" "Yuborish" "Tahrirlangan xabarni yuboring" "Xabar yuborish" @@ -176,6 +183,7 @@ "Siz sessiyadan chiqdingiz" "Ko\'rinish" "Audio" + "Beta" "Bloklangan foydalanuvchilar" "Pufakchalar" "Qoʻngʻiroq boshlandi" @@ -185,6 +193,7 @@ "Xona yaratilmoqda…" "So\'rov bekor qilindi" "Xonani tark etdi" + "Tar etilgan maydon" "Taklif rad etildi" "Tungi" "Shifrni ochish xatosi" @@ -223,9 +232,11 @@ Sababi:%1$s." "APK-ni o\'rnating" "Ushbu Matrix identifikatori topilmadi, shuning uchun taklif qabul qilinmasligi mumkin." "Xonadan chiqish" + "Maydonni tark etish" "Nur" "Satr vaqtinchalik xotiraga nusxalandi" "Havola vaqtinchalik xotiraga nusxalandi" + "Yangi qurilmani ulang" "Yuklanmoqda…" "Batafsil yuklanmoqda…" @@ -238,13 +249,16 @@ Sababi:%1$s." "Xabar" "Xabar harakatlari" + "Xabar yuborilmadi" "Xabar tartibi" "Xabar ochirib tashlandi" "Zamonaviy" "Ovozsiz qilish" + "Ism" "%1$s(%2$s )" "Natijalar yoʻq" "Xona nomi yoʻq" + "Maydon nomi yo\'q" "Shifrlanmagan" "Oflayn" "Ochiq kodli litsenziyalar" @@ -308,14 +322,17 @@ Sababi:%1$s." "Serverga kirish imkonsiz" "Server URL manzili" "Sozlamalar" + "Maydonni ulashish" "Joylashuvi ulashildi" + "Umumiy maydon" "Chiqish" "Nimadir xato ketdi" "Muammoga duch keldik. Iltimos, qayta urinib koʻring." - "Bo‘shliq" + "Maydon" + "Bu maydon nima haqida?" - "%1$d Guruh" - "%1$d Guruhlar" + "%1$d Maydon" + "%1$d ta maydon" "Chat boshlanmoqda…" "Stiker" @@ -357,6 +374,7 @@ Sababi:%1$s." "Kutilmoqda…" "Ushbu xabarni kutilmoqda" "Siz" + "Siz yuborgan xabarlar bu xonaga taklif qilingan yangi a’zolarga ulashiladi. %1$s" "%1$sning shaxsi qayta tiklandi.%2$s" "%1$sʼning %2$s shaxsiy ma’lumotlari qayta tiklandi.%3$s" "(%1$s )" @@ -446,9 +464,10 @@ Davom etasizmi?" "Google Mapsda oching" "OpenStreetMapda oching" "Bu joylashuvni ulashing" - "Siz yaratgan yoki qo‘shilgan guruhlar." + "Siz yaratgan yoki qo‘shilgan maydonlar." "%1$s•%2$s" - "Bo‘shliqlar" + "%1$s ta maydon" + "Maydonlar" "Xabar yuborilmadi, chunki %1$sʼning tasdiqlangan identifikatori asliga qaytarildi." "Xabar yuborilmadi, chunki %1$s barcha qurilmalarni tasdiqlamagan." "Xabaringiz yuborilmadi, chunki siz bir yoki bir nechta qurilmangizni tasdiqlamagan ekansiz." diff --git a/libraries/ui-strings/src/main/res/values-zh-rTW/translations.xml b/libraries/ui-strings/src/main/res/values-zh-rTW/translations.xml index b0989f7d59..2b12c212a7 100644 --- a/libraries/ui-strings/src/main/res/values-zh-rTW/translations.xml +++ b/libraries/ui-strings/src/main/res/values-zh-rTW/translations.xml @@ -160,6 +160,7 @@ "點擊以載入地圖" "拍照" "點擊以查看選項" + "翻譯" "再試一次" "取消釘選" "檢視" diff --git a/libraries/ui-strings/src/main/res/values-zh/translations.xml b/libraries/ui-strings/src/main/res/values-zh/translations.xml index 37a39449ac..44f7c1c1e6 100644 --- a/libraries/ui-strings/src/main/res/values-zh/translations.xml +++ b/libraries/ui-strings/src/main/res/values-zh/translations.xml @@ -1,6 +1,7 @@ "添加表情符号:%1$s" + "地址" "头像" "最小化消息文本框" "删除" @@ -26,8 +27,10 @@ "语音消息,时长:%1$s,当前位置:%2$s" "PIN 字段" "播放" + "播放速度" "投票" "投票已结束" + "QR 码" "使用 %1$s 回应" "使用其他表情符号回应" "%1$s 和 %2$s 已读" @@ -54,6 +57,7 @@ "您的头像" "接受" "添加标题" + "添加现有聊天室" "添加到时间线" "返回" "呼叫" @@ -73,6 +77,7 @@ "复制文本" "创建" "创建聊天室" + "创建空间" "停用" "停用账户" "拒绝" @@ -89,6 +94,7 @@ "启用" "结束投票" "输入 PIN" + "探索公共空间" "完成" "忘记密码?" "转发" @@ -110,6 +116,7 @@ "载入更多" "管理账户" "管理设备" + "管理聊天室" "发送消息给" "最小化" "下一步" @@ -159,6 +166,7 @@ "点击以加载地图" "拍摄照片" "点按查看选项" + "翻译" "再试一次" "取消置顶" "查看" @@ -188,6 +196,7 @@ "已复制到剪贴板" "版权" "正在创建聊天室…" + "正在创建空间……" "请求已取消" "离开聊天室" "离开空间" @@ -233,6 +242,7 @@ "浅色" "链接已复制到剪贴板" "链接已复制到剪贴板" + "关联新设备" "正在加载…" "正在加载更多……" @@ -243,10 +253,12 @@ "消息" "消息操作" + "消息发送失败" "消息布局" "消息已移除" "现代" "静音" + "名称" "%1$s (%2$s)" "没有结果" "无聊天室名" @@ -271,8 +283,10 @@ "正在准备…" "隐私政策" + "私密" "私有聊天室" "私有空间" + "公共" "公共聊天室" "公开空间" "回应" @@ -280,6 +294,7 @@ "理由" "恢复密钥" "正在刷新…" + "正在移除…" "%1$d 个回复" @@ -288,6 +303,7 @@ "报告问题" "报告已提交" "富文本编辑器" + "角色" "聊天室" "聊天室名称" "例如:您的项目名称" @@ -302,6 +318,9 @@ "安全" "已读" "选择账户" + + "%1$d 已选中" + "发送至" "正在发送…" "发送失败" @@ -312,18 +331,22 @@ "服务器 URL" "设置" "共享空间" + "新成员可见历史记录" "共享位置" "共享空间" "正在登出" "发生了一些错误" "我们遇到了一个问题。请重试。" "空间" + "空间成员" + "该空间的主题是什么?" "%1$d 空间" "开始聊天…" "贴纸" "成功" + "推荐" "建议" "正在同步" "系统" @@ -331,7 +354,7 @@ "第三方通知" "消息列" "主题" - "这个聊天室是关于什么的?" + "该聊天室的主题是什么?" "无法解密" "从不安全的设备发送" "无权访问此消息" @@ -360,7 +383,11 @@ "语音消息" "等待…" "正在等待解密密钥" + "任何人都可查看历史记录" "您" + "%1$s (%2$s) 由于您当时不在聊天室内,系统已将消息共享给您。" + "%1$s 由于您当时不在聊天室内,系统已将此消息共享给您。" + "本聊天室已配置为允许新成员阅读历史记录。%1$s" "%1$s的身份已重置。%2$s" "%1$s %2$s 的身份已重置。%3$s" "(%1$s)" @@ -451,6 +478,7 @@ "分享这个位置" "您创建或加入的空间。" "%1$s • %2$s" + "创建空间以组织聊天室" "%1$s空间" "空间" "消息未发送,因为%1$s的已验证身份已被重置。" diff --git a/libraries/ui-strings/src/main/res/values/localazy.xml b/libraries/ui-strings/src/main/res/values/localazy.xml index f243686226..90eb61253d 100644 --- a/libraries/ui-strings/src/main/res/values/localazy.xml +++ b/libraries/ui-strings/src/main/res/values/localazy.xml @@ -156,6 +156,7 @@ "Send voice message" "Share" "Share link" + "Share live location" "Show" "Sign in again" "Sign out" @@ -403,6 +404,7 @@ Reason: %1$s." "%1$s’s identity was reset." "%1$s’s %2$s identity was reset. %3$s" "Withdraw verification" + "Allow access" "The link %1$s is taking you to another site %2$s Are you sure you want to continue?" diff --git a/screenshots/de/features.home.impl.spaces_HomeSpacesView_Day_0_de.png b/screenshots/de/features.home.impl.spaces_HomeSpacesView_Day_0_de.png index a5d56a5fb8..57b0b95a3b 100644 --- a/screenshots/de/features.home.impl.spaces_HomeSpacesView_Day_0_de.png +++ b/screenshots/de/features.home.impl.spaces_HomeSpacesView_Day_0_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:78a539b7a6acef8655d71e42f63162ec7d1e2a3d3b15b6b9d1d32fc07b3ec2e3 -size 86944 +oid sha256:77959d24fd7c52c4d63090e51d189bd6c41c9c350c1a4c97a2260c05b226c119 +size 86868 diff --git a/screenshots/de/features.home.impl.spaces_HomeSpacesView_Day_1_de.png b/screenshots/de/features.home.impl.spaces_HomeSpacesView_Day_1_de.png index 005008c906..5b2f0bbb1f 100644 --- a/screenshots/de/features.home.impl.spaces_HomeSpacesView_Day_1_de.png +++ b/screenshots/de/features.home.impl.spaces_HomeSpacesView_Day_1_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:24246853c2e1edbbb128a85b16c7746ff9f79ed378a3b3a5d83477173a076d82 -size 39374 +oid sha256:53a21b0c20ed1fb442fdb8d860805ee8f476cb2f527d571b07084751b58c762b +size 39239 diff --git a/screenshots/de/features.home.impl.spaces_HomeSpacesView_Day_2_de.png b/screenshots/de/features.home.impl.spaces_HomeSpacesView_Day_2_de.png index 005008c906..5b2f0bbb1f 100644 --- a/screenshots/de/features.home.impl.spaces_HomeSpacesView_Day_2_de.png +++ b/screenshots/de/features.home.impl.spaces_HomeSpacesView_Day_2_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:24246853c2e1edbbb128a85b16c7746ff9f79ed378a3b3a5d83477173a076d82 -size 39374 +oid sha256:53a21b0c20ed1fb442fdb8d860805ee8f476cb2f527d571b07084751b58c762b +size 39239 diff --git a/screenshots/de/features.home.impl.spaces_HomeSpacesView_Day_3_de.png b/screenshots/de/features.home.impl.spaces_HomeSpacesView_Day_3_de.png index bd7f8fb3b5..f0e44135ec 100644 --- a/screenshots/de/features.home.impl.spaces_HomeSpacesView_Day_3_de.png +++ b/screenshots/de/features.home.impl.spaces_HomeSpacesView_Day_3_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:6534192c29e4025442c64dcb5e46fc5914d78556f52e2a317c88865f0007b769 -size 28459 +oid sha256:c7f97df762e010742fb2627a83e0939f4e190195200c53004412e01c6361cb43 +size 28480 diff --git a/screenshots/de/features.home.impl_HomeView_Day_0_de.png b/screenshots/de/features.home.impl_HomeView_Day_0_de.png index bd04adf310..3f4ea30f5c 100644 --- a/screenshots/de/features.home.impl_HomeView_Day_0_de.png +++ b/screenshots/de/features.home.impl_HomeView_Day_0_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a4a44180d4089ac95697beabb5284fdaa0a3d18a3163cac3968a6fe8afafd75c -size 66799 +oid sha256:1ffc6ec59463b5047e28186f2e0628dcd10391ce51515f2ffbbca150fe590cf4 +size 69561 diff --git a/screenshots/de/features.home.impl_HomeView_Day_10_de.png b/screenshots/de/features.home.impl_HomeView_Day_10_de.png index a9cfe216ac..4a1b203d2a 100644 --- a/screenshots/de/features.home.impl_HomeView_Day_10_de.png +++ b/screenshots/de/features.home.impl_HomeView_Day_10_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:e4b44a5f23a9e3b64407cef8411bfb1a6e80026d455a2ea6dccf2c3aa900aa5e -size 36861 +oid sha256:b1f61b44eadaaccb0ad9f1bb244b7c0a7c4ee1e24b88b78a4bff0d4b41d66401 +size 39625 diff --git a/screenshots/de/features.home.impl_HomeView_Day_13_de.png b/screenshots/de/features.home.impl_HomeView_Day_13_de.png index 90a85a16a0..1f5c8972bc 100644 --- a/screenshots/de/features.home.impl_HomeView_Day_13_de.png +++ b/screenshots/de/features.home.impl_HomeView_Day_13_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:0fb6ded9f4b44e7c0de88bd19f565793bf53f2120bf018eb05c13a27d6b99ae0 -size 88662 +oid sha256:e3f9c61cbe5f80b7574765bfcc6a1bef06b434d35666ee4fa2b0ba6f09078352 +size 97503 diff --git a/screenshots/de/features.home.impl_HomeView_Day_14_de.png b/screenshots/de/features.home.impl_HomeView_Day_14_de.png index 94f54b4478..7476615fc3 100644 --- a/screenshots/de/features.home.impl_HomeView_Day_14_de.png +++ b/screenshots/de/features.home.impl_HomeView_Day_14_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:71aabe78f2a043d65906ae1711e9a2d541e93b54f8dcfbecc988fc209223b613 -size 85766 +oid sha256:36a222231a7399ffa88190117f82db0f96b3a3aef4c939988e8f862c75d1fa52 +size 91989 diff --git a/screenshots/de/features.home.impl_HomeView_Day_15_de.png b/screenshots/de/features.home.impl_HomeView_Day_15_de.png index 19c366b434..510b419a08 100644 --- a/screenshots/de/features.home.impl_HomeView_Day_15_de.png +++ b/screenshots/de/features.home.impl_HomeView_Day_15_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:342d97e25104cfe127d14d4fc0bc18fc0bc37c3f73fc84575893055e57043c18 -size 54559 +oid sha256:21cdc577a1177a8919afaf4d7d0cba5ca9ca9ee2538645145f022aaa3778d958 +size 59512 diff --git a/screenshots/de/features.home.impl_HomeView_Day_16_de.png b/screenshots/de/features.home.impl_HomeView_Day_16_de.png new file mode 100644 index 0000000000..316e974912 --- /dev/null +++ b/screenshots/de/features.home.impl_HomeView_Day_16_de.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:b8f03c1ef30c115873d0757602f689362bb0a442658d44e8108b1b87e5134f4f +size 46217 diff --git a/screenshots/de/features.home.impl_HomeView_Day_1_de.png b/screenshots/de/features.home.impl_HomeView_Day_1_de.png index bd04adf310..3f4ea30f5c 100644 --- a/screenshots/de/features.home.impl_HomeView_Day_1_de.png +++ b/screenshots/de/features.home.impl_HomeView_Day_1_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a4a44180d4089ac95697beabb5284fdaa0a3d18a3163cac3968a6fe8afafd75c -size 66799 +oid sha256:1ffc6ec59463b5047e28186f2e0628dcd10391ce51515f2ffbbca150fe590cf4 +size 69561 diff --git a/screenshots/de/features.home.impl_HomeView_Day_2_de.png b/screenshots/de/features.home.impl_HomeView_Day_2_de.png index bd04adf310..3f4ea30f5c 100644 --- a/screenshots/de/features.home.impl_HomeView_Day_2_de.png +++ b/screenshots/de/features.home.impl_HomeView_Day_2_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a4a44180d4089ac95697beabb5284fdaa0a3d18a3163cac3968a6fe8afafd75c -size 66799 +oid sha256:1ffc6ec59463b5047e28186f2e0628dcd10391ce51515f2ffbbca150fe590cf4 +size 69561 diff --git a/screenshots/de/features.home.impl_HomeView_Day_3_de.png b/screenshots/de/features.home.impl_HomeView_Day_3_de.png index 7ff2419b98..f4adeb4894 100644 --- a/screenshots/de/features.home.impl_HomeView_Day_3_de.png +++ b/screenshots/de/features.home.impl_HomeView_Day_3_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:68914b7ddc57512662892bbc9c8ceb5d230b667c07b8a2a8f0b955b42ffadea7 -size 61617 +oid sha256:e7a3316558a8b352adc4bfc18030e8cf30e06fd5f3e78524c46e3cdbdd2c5907 +size 65168 diff --git a/screenshots/de/features.home.impl_HomeView_Day_4_de.png b/screenshots/de/features.home.impl_HomeView_Day_4_de.png index 6a8e08430f..f200461dc7 100644 --- a/screenshots/de/features.home.impl_HomeView_Day_4_de.png +++ b/screenshots/de/features.home.impl_HomeView_Day_4_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:65d163c105ed07f8edcd3e86ef070ad89b46410bc5753410c1cf98977acaeead -size 53648 +oid sha256:19266c73ca346e8a290c9eb4091cd5088b5569710a31d06353782be071c03fcb +size 58359 diff --git a/screenshots/de/features.home.impl_HomeView_Day_5_de.png b/screenshots/de/features.home.impl_HomeView_Day_5_de.png index bd04adf310..3f4ea30f5c 100644 --- a/screenshots/de/features.home.impl_HomeView_Day_5_de.png +++ b/screenshots/de/features.home.impl_HomeView_Day_5_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a4a44180d4089ac95697beabb5284fdaa0a3d18a3163cac3968a6fe8afafd75c -size 66799 +oid sha256:1ffc6ec59463b5047e28186f2e0628dcd10391ce51515f2ffbbca150fe590cf4 +size 69561 diff --git a/screenshots/de/features.home.impl_HomeView_Day_9_de.png b/screenshots/de/features.home.impl_HomeView_Day_9_de.png index 3a25fbe31f..3a5002ae42 100644 --- a/screenshots/de/features.home.impl_HomeView_Day_9_de.png +++ b/screenshots/de/features.home.impl_HomeView_Day_9_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:1e1f892734f017d12bedbbfb0a67f34942cb70b642b0df0ea58114f222813d27 -size 84173 +oid sha256:fef5908ddd4fba551a21710e5558089d8b22af459b8024ec0e49489e44a9409c +size 93092 diff --git a/screenshots/html/data.js b/screenshots/html/data.js index ecdb91e7e7..669e47b76d 100644 --- a/screenshots/html/data.js +++ b/screenshots/html/data.js @@ -1,87 +1,87 @@ // 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",20504,], +["features.preferences.impl.about_AboutView_Day_0_en","features.preferences.impl.about_AboutView_Night_0_en",20511,], ["features.invite.impl.acceptdecline_AcceptDeclineInviteView_Day_0_en","features.invite.impl.acceptdecline_AcceptDeclineInviteView_Night_0_en",0,], -["features.invite.impl.acceptdecline_AcceptDeclineInviteView_Day_1_en","features.invite.impl.acceptdecline_AcceptDeclineInviteView_Night_1_en",20504,], -["features.invite.impl.acceptdecline_AcceptDeclineInviteView_Day_2_en","features.invite.impl.acceptdecline_AcceptDeclineInviteView_Night_2_en",20504,], -["features.invite.impl.acceptdecline_AcceptDeclineInviteView_Day_3_en","features.invite.impl.acceptdecline_AcceptDeclineInviteView_Night_3_en",20504,], -["features.invite.impl.acceptdecline_AcceptDeclineInviteView_Day_4_en","features.invite.impl.acceptdecline_AcceptDeclineInviteView_Night_4_en",20504,], -["features.invite.impl.acceptdecline_AcceptDeclineInviteView_Day_5_en","features.invite.impl.acceptdecline_AcceptDeclineInviteView_Night_5_en",20504,], -["features.logout.impl_AccountDeactivationView_Day_0_en","features.logout.impl_AccountDeactivationView_Night_0_en",20504,], -["features.logout.impl_AccountDeactivationView_Day_1_en","features.logout.impl_AccountDeactivationView_Night_1_en",20504,], -["features.logout.impl_AccountDeactivationView_Day_2_en","features.logout.impl_AccountDeactivationView_Night_2_en",20504,], -["features.logout.impl_AccountDeactivationView_Day_3_en","features.logout.impl_AccountDeactivationView_Night_3_en",20504,], -["features.logout.impl_AccountDeactivationView_Day_4_en","features.logout.impl_AccountDeactivationView_Night_4_en",20504,], -["features.login.impl.accountprovider_AccountProviderOtherView_Day_0_en","features.login.impl.accountprovider_AccountProviderOtherView_Night_0_en",20504,], +["features.invite.impl.acceptdecline_AcceptDeclineInviteView_Day_1_en","features.invite.impl.acceptdecline_AcceptDeclineInviteView_Night_1_en",20511,], +["features.invite.impl.acceptdecline_AcceptDeclineInviteView_Day_2_en","features.invite.impl.acceptdecline_AcceptDeclineInviteView_Night_2_en",20511,], +["features.invite.impl.acceptdecline_AcceptDeclineInviteView_Day_3_en","features.invite.impl.acceptdecline_AcceptDeclineInviteView_Night_3_en",20511,], +["features.invite.impl.acceptdecline_AcceptDeclineInviteView_Day_4_en","features.invite.impl.acceptdecline_AcceptDeclineInviteView_Night_4_en",20511,], +["features.invite.impl.acceptdecline_AcceptDeclineInviteView_Day_5_en","features.invite.impl.acceptdecline_AcceptDeclineInviteView_Night_5_en",20511,], +["features.logout.impl_AccountDeactivationView_Day_0_en","features.logout.impl_AccountDeactivationView_Night_0_en",20511,], +["features.logout.impl_AccountDeactivationView_Day_1_en","features.logout.impl_AccountDeactivationView_Night_1_en",20511,], +["features.logout.impl_AccountDeactivationView_Day_2_en","features.logout.impl_AccountDeactivationView_Night_2_en",20511,], +["features.logout.impl_AccountDeactivationView_Day_3_en","features.logout.impl_AccountDeactivationView_Night_3_en",20511,], +["features.logout.impl_AccountDeactivationView_Day_4_en","features.logout.impl_AccountDeactivationView_Night_4_en",20511,], +["features.login.impl.accountprovider_AccountProviderOtherView_Day_0_en","features.login.impl.accountprovider_AccountProviderOtherView_Night_0_en",20511,], ["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,], -["libraries.accountselect.impl_AccountSelectView_Day_0_en","libraries.accountselect.impl_AccountSelectView_Night_0_en",20504,], -["libraries.accountselect.impl_AccountSelectView_Day_1_en","libraries.accountselect.impl_AccountSelectView_Night_1_en",20504,], +["libraries.accountselect.impl_AccountSelectView_Day_0_en","libraries.accountselect.impl_AccountSelectView_Night_0_en",20511,], +["libraries.accountselect.impl_AccountSelectView_Day_1_en","libraries.accountselect.impl_AccountSelectView_Night_1_en",20511,], ["features.messages.impl.actionlist_ActionListViewContent_Day_0_en","features.messages.impl.actionlist_ActionListViewContent_Night_0_en",0,], -["features.messages.impl.actionlist_ActionListViewContent_Day_10_en","features.messages.impl.actionlist_ActionListViewContent_Night_10_en",20504,], -["features.messages.impl.actionlist_ActionListViewContent_Day_11_en","features.messages.impl.actionlist_ActionListViewContent_Night_11_en",20504,], -["features.messages.impl.actionlist_ActionListViewContent_Day_12_en","features.messages.impl.actionlist_ActionListViewContent_Night_12_en",20504,], +["features.messages.impl.actionlist_ActionListViewContent_Day_10_en","features.messages.impl.actionlist_ActionListViewContent_Night_10_en",20511,], +["features.messages.impl.actionlist_ActionListViewContent_Day_11_en","features.messages.impl.actionlist_ActionListViewContent_Night_11_en",20511,], +["features.messages.impl.actionlist_ActionListViewContent_Day_12_en","features.messages.impl.actionlist_ActionListViewContent_Night_12_en",20511,], ["features.messages.impl.actionlist_ActionListViewContent_Day_1_en","features.messages.impl.actionlist_ActionListViewContent_Night_1_en",0,], -["features.messages.impl.actionlist_ActionListViewContent_Day_2_en","features.messages.impl.actionlist_ActionListViewContent_Night_2_en",20504,], -["features.messages.impl.actionlist_ActionListViewContent_Day_3_en","features.messages.impl.actionlist_ActionListViewContent_Night_3_en",20504,], -["features.messages.impl.actionlist_ActionListViewContent_Day_4_en","features.messages.impl.actionlist_ActionListViewContent_Night_4_en",20504,], -["features.messages.impl.actionlist_ActionListViewContent_Day_5_en","features.messages.impl.actionlist_ActionListViewContent_Night_5_en",20504,], -["features.messages.impl.actionlist_ActionListViewContent_Day_6_en","features.messages.impl.actionlist_ActionListViewContent_Night_6_en",20504,], -["features.messages.impl.actionlist_ActionListViewContent_Day_7_en","features.messages.impl.actionlist_ActionListViewContent_Night_7_en",20504,], -["features.messages.impl.actionlist_ActionListViewContent_Day_8_en","features.messages.impl.actionlist_ActionListViewContent_Night_8_en",20504,], -["features.messages.impl.actionlist_ActionListViewContent_Day_9_en","features.messages.impl.actionlist_ActionListViewContent_Night_9_en",20504,], -["features.createroom.impl.addpeople_AddPeopleView_Day_0_en","features.createroom.impl.addpeople_AddPeopleView_Night_0_en",20504,], -["features.createroom.impl.addpeople_AddPeopleView_Day_1_en","features.createroom.impl.addpeople_AddPeopleView_Night_1_en",20504,], -["features.createroom.impl.addpeople_AddPeopleView_Day_2_en","features.createroom.impl.addpeople_AddPeopleView_Night_2_en",20504,], -["features.createroom.impl.addpeople_AddPeopleView_Day_3_en","features.createroom.impl.addpeople_AddPeopleView_Night_3_en",20504,], -["features.space.impl.addroom_AddRoomToSpaceView_Day_0_en","features.space.impl.addroom_AddRoomToSpaceView_Night_0_en",20504,], -["features.space.impl.addroom_AddRoomToSpaceView_Day_1_en","features.space.impl.addroom_AddRoomToSpaceView_Night_1_en",20504,], -["features.space.impl.addroom_AddRoomToSpaceView_Day_2_en","features.space.impl.addroom_AddRoomToSpaceView_Night_2_en",20504,], -["features.space.impl.addroom_AddRoomToSpaceView_Day_3_en","features.space.impl.addroom_AddRoomToSpaceView_Night_3_en",20504,], -["features.space.impl.addroom_AddRoomToSpaceView_Day_4_en","features.space.impl.addroom_AddRoomToSpaceView_Night_4_en",20504,], -["features.space.impl.addroom_AddRoomToSpaceView_Day_5_en","features.space.impl.addroom_AddRoomToSpaceView_Night_5_en",20504,], -["features.space.impl.addroom_AddRoomToSpaceView_Day_6_en","features.space.impl.addroom_AddRoomToSpaceView_Night_6_en",20504,], -["features.preferences.impl.advanced_AdvancedSettingsViewDark_0_en","",20504,], -["features.preferences.impl.advanced_AdvancedSettingsViewDark_1_en","",20504,], -["features.preferences.impl.advanced_AdvancedSettingsViewDark_2_en","",20504,], -["features.preferences.impl.advanced_AdvancedSettingsViewDark_3_en","",20504,], -["features.preferences.impl.advanced_AdvancedSettingsViewDark_4_en","",20504,], -["features.preferences.impl.advanced_AdvancedSettingsViewDark_5_en","",20504,], -["features.preferences.impl.advanced_AdvancedSettingsViewDark_6_en","",20504,], -["features.preferences.impl.advanced_AdvancedSettingsViewDark_7_en","",20504,], -["features.preferences.impl.advanced_AdvancedSettingsViewDark_8_en","",20504,], -["features.preferences.impl.advanced_AdvancedSettingsViewLight_0_en","",20504,], -["features.preferences.impl.advanced_AdvancedSettingsViewLight_1_en","",20504,], -["features.preferences.impl.advanced_AdvancedSettingsViewLight_2_en","",20504,], -["features.preferences.impl.advanced_AdvancedSettingsViewLight_3_en","",20504,], -["features.preferences.impl.advanced_AdvancedSettingsViewLight_4_en","",20504,], -["features.preferences.impl.advanced_AdvancedSettingsViewLight_5_en","",20504,], -["features.preferences.impl.advanced_AdvancedSettingsViewLight_6_en","",20504,], -["features.preferences.impl.advanced_AdvancedSettingsViewLight_7_en","",20504,], -["features.preferences.impl.advanced_AdvancedSettingsViewLight_8_en","",20504,], -["libraries.designsystem.components.dialogs_AlertDialogContent_Dialogs_en","",20504,], -["libraries.designsystem.components.dialogs_AlertDialog_Day_0_en","libraries.designsystem.components.dialogs_AlertDialog_Night_0_en",20504,], +["features.messages.impl.actionlist_ActionListViewContent_Day_2_en","features.messages.impl.actionlist_ActionListViewContent_Night_2_en",20511,], +["features.messages.impl.actionlist_ActionListViewContent_Day_3_en","features.messages.impl.actionlist_ActionListViewContent_Night_3_en",20511,], +["features.messages.impl.actionlist_ActionListViewContent_Day_4_en","features.messages.impl.actionlist_ActionListViewContent_Night_4_en",20511,], +["features.messages.impl.actionlist_ActionListViewContent_Day_5_en","features.messages.impl.actionlist_ActionListViewContent_Night_5_en",20511,], +["features.messages.impl.actionlist_ActionListViewContent_Day_6_en","features.messages.impl.actionlist_ActionListViewContent_Night_6_en",20511,], +["features.messages.impl.actionlist_ActionListViewContent_Day_7_en","features.messages.impl.actionlist_ActionListViewContent_Night_7_en",20511,], +["features.messages.impl.actionlist_ActionListViewContent_Day_8_en","features.messages.impl.actionlist_ActionListViewContent_Night_8_en",20511,], +["features.messages.impl.actionlist_ActionListViewContent_Day_9_en","features.messages.impl.actionlist_ActionListViewContent_Night_9_en",20511,], +["features.createroom.impl.addpeople_AddPeopleView_Day_0_en","features.createroom.impl.addpeople_AddPeopleView_Night_0_en",20511,], +["features.createroom.impl.addpeople_AddPeopleView_Day_1_en","features.createroom.impl.addpeople_AddPeopleView_Night_1_en",20511,], +["features.createroom.impl.addpeople_AddPeopleView_Day_2_en","features.createroom.impl.addpeople_AddPeopleView_Night_2_en",20511,], +["features.createroom.impl.addpeople_AddPeopleView_Day_3_en","features.createroom.impl.addpeople_AddPeopleView_Night_3_en",20511,], +["features.space.impl.addroom_AddRoomToSpaceView_Day_0_en","features.space.impl.addroom_AddRoomToSpaceView_Night_0_en",20511,], +["features.space.impl.addroom_AddRoomToSpaceView_Day_1_en","features.space.impl.addroom_AddRoomToSpaceView_Night_1_en",20511,], +["features.space.impl.addroom_AddRoomToSpaceView_Day_2_en","features.space.impl.addroom_AddRoomToSpaceView_Night_2_en",20511,], +["features.space.impl.addroom_AddRoomToSpaceView_Day_3_en","features.space.impl.addroom_AddRoomToSpaceView_Night_3_en",20511,], +["features.space.impl.addroom_AddRoomToSpaceView_Day_4_en","features.space.impl.addroom_AddRoomToSpaceView_Night_4_en",20511,], +["features.space.impl.addroom_AddRoomToSpaceView_Day_5_en","features.space.impl.addroom_AddRoomToSpaceView_Night_5_en",20511,], +["features.space.impl.addroom_AddRoomToSpaceView_Day_6_en","features.space.impl.addroom_AddRoomToSpaceView_Night_6_en",20511,], +["features.preferences.impl.advanced_AdvancedSettingsViewDark_0_en","",20511,], +["features.preferences.impl.advanced_AdvancedSettingsViewDark_1_en","",20511,], +["features.preferences.impl.advanced_AdvancedSettingsViewDark_2_en","",20511,], +["features.preferences.impl.advanced_AdvancedSettingsViewDark_3_en","",20511,], +["features.preferences.impl.advanced_AdvancedSettingsViewDark_4_en","",20511,], +["features.preferences.impl.advanced_AdvancedSettingsViewDark_5_en","",20511,], +["features.preferences.impl.advanced_AdvancedSettingsViewDark_6_en","",20511,], +["features.preferences.impl.advanced_AdvancedSettingsViewDark_7_en","",20511,], +["features.preferences.impl.advanced_AdvancedSettingsViewDark_8_en","",20511,], +["features.preferences.impl.advanced_AdvancedSettingsViewLight_0_en","",20511,], +["features.preferences.impl.advanced_AdvancedSettingsViewLight_1_en","",20511,], +["features.preferences.impl.advanced_AdvancedSettingsViewLight_2_en","",20511,], +["features.preferences.impl.advanced_AdvancedSettingsViewLight_3_en","",20511,], +["features.preferences.impl.advanced_AdvancedSettingsViewLight_4_en","",20511,], +["features.preferences.impl.advanced_AdvancedSettingsViewLight_5_en","",20511,], +["features.preferences.impl.advanced_AdvancedSettingsViewLight_6_en","",20511,], +["features.preferences.impl.advanced_AdvancedSettingsViewLight_7_en","",20511,], +["features.preferences.impl.advanced_AdvancedSettingsViewLight_8_en","",20511,], +["libraries.designsystem.components.dialogs_AlertDialogContent_Dialogs_en","",20511,], +["libraries.designsystem.components.dialogs_AlertDialog_Day_0_en","libraries.designsystem.components.dialogs_AlertDialog_Night_0_en",20511,], ["libraries.designsystem.theme.components_AllIcons_Icons_en","",0,], -["features.analytics.impl_AnalyticsOptInView_Day_0_en","features.analytics.impl_AnalyticsOptInView_Night_0_en",20504,], -["features.analytics.impl_AnalyticsOptInView_Day_1_en","features.analytics.impl_AnalyticsOptInView_Night_1_en",20504,], -["features.analytics.api.preferences_AnalyticsPreferencesView_Day_0_en","features.analytics.api.preferences_AnalyticsPreferencesView_Night_0_en",20504,], -["features.analytics.api.preferences_AnalyticsPreferencesView_Day_1_en","features.analytics.api.preferences_AnalyticsPreferencesView_Night_1_en",20504,], -["features.preferences.impl.analytics_AnalyticsSettingsView_Day_0_en","features.preferences.impl.analytics_AnalyticsSettingsView_Night_0_en",20504,], +["features.analytics.impl_AnalyticsOptInView_Day_0_en","features.analytics.impl_AnalyticsOptInView_Night_0_en",20511,], +["features.analytics.impl_AnalyticsOptInView_Day_1_en","features.analytics.impl_AnalyticsOptInView_Night_1_en",20511,], +["features.analytics.api.preferences_AnalyticsPreferencesView_Day_0_en","features.analytics.api.preferences_AnalyticsPreferencesView_Night_0_en",20511,], +["features.analytics.api.preferences_AnalyticsPreferencesView_Day_1_en","features.analytics.api.preferences_AnalyticsPreferencesView_Night_1_en",20511,], +["features.preferences.impl.analytics_AnalyticsSettingsView_Day_0_en","features.preferences.impl.analytics_AnalyticsSettingsView_Night_0_en",20511,], ["libraries.designsystem.components_Announcement_Day_0_en","libraries.designsystem.components_Announcement_Night_0_en",0,], -["services.apperror.impl_AppErrorView_Day_0_en","services.apperror.impl_AppErrorView_Night_0_en",20504,], +["services.apperror.impl_AppErrorView_Day_0_en","services.apperror.impl_AppErrorView_Night_0_en",20511,], ["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",20504,], +["libraries.designsystem.components.async_AsyncActionView_Day_1_en","libraries.designsystem.components.async_AsyncActionView_Night_1_en",20511,], ["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",20504,], +["libraries.designsystem.components.async_AsyncActionView_Day_3_en","libraries.designsystem.components.async_AsyncActionView_Night_3_en",20511,], ["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",20504,], +["libraries.designsystem.components.async_AsyncFailure_Day_0_en","libraries.designsystem.components.async_AsyncFailure_Night_0_en",20511,], ["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",20504,], +["features.messages.impl.messagecomposer_AttachmentSourcePickerMenu_Day_0_en","features.messages.impl.messagecomposer_AttachmentSourcePickerMenu_Night_0_en",20511,], ["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,], @@ -91,19 +91,19 @@ export const screenshots = [ ["libraries.matrix.ui.components_AttachmentThumbnail_Day_6_en","libraries.matrix.ui.components_AttachmentThumbnail_Night_6_en",0,], ["libraries.matrix.ui.components_AttachmentThumbnail_Day_7_en","libraries.matrix.ui.components_AttachmentThumbnail_Night_7_en",0,], ["libraries.matrix.ui.components_AttachmentThumbnail_Day_8_en","libraries.matrix.ui.components_AttachmentThumbnail_Night_8_en",0,], -["features.messages.impl.attachments.preview_AttachmentsPreviewView_0_en","",20504,], -["features.messages.impl.attachments.preview_AttachmentsPreviewView_1_en","",20504,], -["features.messages.impl.attachments.preview_AttachmentsPreviewView_2_en","",20504,], -["features.messages.impl.attachments.preview_AttachmentsPreviewView_3_en","",20504,], -["features.messages.impl.attachments.preview_AttachmentsPreviewView_4_en","",20504,], -["features.messages.impl.attachments.preview_AttachmentsPreviewView_5_en","",20504,], -["features.messages.impl.attachments.preview_AttachmentsPreviewView_6_en","",20504,], -["features.messages.impl.attachments.preview_AttachmentsPreviewView_7_en","",20504,], -["features.messages.impl.attachments.preview_AttachmentsPreviewView_8_en","",20504,], +["features.messages.impl.attachments.preview_AttachmentsPreviewView_0_en","",20511,], +["features.messages.impl.attachments.preview_AttachmentsPreviewView_1_en","",20511,], +["features.messages.impl.attachments.preview_AttachmentsPreviewView_2_en","",20511,], +["features.messages.impl.attachments.preview_AttachmentsPreviewView_3_en","",20511,], +["features.messages.impl.attachments.preview_AttachmentsPreviewView_4_en","",20511,], +["features.messages.impl.attachments.preview_AttachmentsPreviewView_5_en","",20511,], +["features.messages.impl.attachments.preview_AttachmentsPreviewView_6_en","",20511,], +["features.messages.impl.attachments.preview_AttachmentsPreviewView_7_en","",20511,], +["features.messages.impl.attachments.preview_AttachmentsPreviewView_8_en","",20511,], ["libraries.mediaviewer.impl.gallery.ui_AudioItemView_Day_0_en","libraries.mediaviewer.impl.gallery.ui_AudioItemView_Night_0_en",0,], ["libraries.mediaviewer.impl.gallery.ui_AudioItemView_Day_1_en","libraries.mediaviewer.impl.gallery.ui_AudioItemView_Night_1_en",0,], ["libraries.mediaviewer.impl.gallery.ui_AudioItemView_Day_2_en","libraries.mediaviewer.impl.gallery.ui_AudioItemView_Night_2_en",0,], -["libraries.matrix.ui.components_AvatarActionBottomSheet_Day_0_en","libraries.matrix.ui.components_AvatarActionBottomSheet_Night_0_en",20504,], +["libraries.matrix.ui.components_AvatarActionBottomSheet_Day_0_en","libraries.matrix.ui.components_AvatarActionBottomSheet_Night_0_en",20511,], ["libraries.designsystem.components.avatar.internal_AvatarCluster_Avatars_en","",0,], ["libraries.matrix.ui.components_AvatarPickerSizes_Day_0_en","libraries.matrix.ui.components_AvatarPickerSizes_Night_0_en",0,], ["libraries.matrix.ui.components_AvatarPickerViewRtl_Day_0_en","libraries.matrix.ui.components_AvatarPickerViewRtl_Night_0_en",0,], @@ -133,22 +133,22 @@ export const screenshots = [ ["libraries.designsystem.modifiers_BackgroundVerticalGradientDisabled_Day_0_en","libraries.designsystem.modifiers_BackgroundVerticalGradientDisabled_Night_0_en",0,], ["libraries.designsystem.modifiers_BackgroundVerticalGradient_Day_0_en","libraries.designsystem.modifiers_BackgroundVerticalGradient_Night_0_en",0,], ["libraries.designsystem.components_Badge_Day_0_en","libraries.designsystem.components_Badge_Night_0_en",0,], -["features.home.impl.components_BatteryOptimizationBanner_Day_0_en","features.home.impl.components_BatteryOptimizationBanner_Night_0_en",20504,], +["features.home.impl.components_BatteryOptimizationBanner_Day_0_en","features.home.impl.components_BatteryOptimizationBanner_Night_0_en",20511,], ["libraries.designsystem.atomic.atoms_BetaLabel_Day_0_en","libraries.designsystem.atomic.atoms_BetaLabel_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",20504,], -["features.preferences.impl.blockedusers_BlockedUsersView_Day_1_en","features.preferences.impl.blockedusers_BlockedUsersView_Night_1_en",20504,], -["features.preferences.impl.blockedusers_BlockedUsersView_Day_2_en","features.preferences.impl.blockedusers_BlockedUsersView_Night_2_en",20504,], -["features.preferences.impl.blockedusers_BlockedUsersView_Day_3_en","features.preferences.impl.blockedusers_BlockedUsersView_Night_3_en",20504,], -["features.preferences.impl.blockedusers_BlockedUsersView_Day_4_en","features.preferences.impl.blockedusers_BlockedUsersView_Night_4_en",20504,], -["features.preferences.impl.blockedusers_BlockedUsersView_Day_5_en","features.preferences.impl.blockedusers_BlockedUsersView_Night_5_en",20504,], -["features.preferences.impl.blockedusers_BlockedUsersView_Day_6_en","features.preferences.impl.blockedusers_BlockedUsersView_Night_6_en",20504,], +["features.preferences.impl.blockedusers_BlockedUsersView_Day_0_en","features.preferences.impl.blockedusers_BlockedUsersView_Night_0_en",20511,], +["features.preferences.impl.blockedusers_BlockedUsersView_Day_1_en","features.preferences.impl.blockedusers_BlockedUsersView_Night_1_en",20511,], +["features.preferences.impl.blockedusers_BlockedUsersView_Day_2_en","features.preferences.impl.blockedusers_BlockedUsersView_Night_2_en",20511,], +["features.preferences.impl.blockedusers_BlockedUsersView_Day_3_en","features.preferences.impl.blockedusers_BlockedUsersView_Night_3_en",20511,], +["features.preferences.impl.blockedusers_BlockedUsersView_Day_4_en","features.preferences.impl.blockedusers_BlockedUsersView_Night_4_en",20511,], +["features.preferences.impl.blockedusers_BlockedUsersView_Day_5_en","features.preferences.impl.blockedusers_BlockedUsersView_Night_5_en",20511,], +["features.preferences.impl.blockedusers_BlockedUsersView_Day_6_en","features.preferences.impl.blockedusers_BlockedUsersView_Night_6_en",20511,], ["libraries.designsystem.theme.components_BottomSheetDragHandle_Day_0_en","libraries.designsystem.theme.components_BottomSheetDragHandle_Night_0_en",0,], -["features.rageshake.impl.bugreport_BugReportViewDay_0_en","",20504,], -["features.rageshake.impl.bugreport_BugReportViewDay_1_en","",20504,], -["features.rageshake.impl.bugreport_BugReportViewDay_2_en","",20504,], -["features.rageshake.impl.bugreport_BugReportViewDay_3_en","",20504,], -["features.rageshake.impl.bugreport_BugReportViewDay_4_en","",20504,], +["features.rageshake.impl.bugreport_BugReportViewDay_0_en","",20511,], +["features.rageshake.impl.bugreport_BugReportViewDay_1_en","",20511,], +["features.rageshake.impl.bugreport_BugReportViewDay_2_en","",20511,], +["features.rageshake.impl.bugreport_BugReportViewDay_3_en","",20511,], +["features.rageshake.impl.bugreport_BugReportViewDay_4_en","",20511,], ["features.rageshake.impl.bugreport_BugReportViewNight_0_en","",0,], ["features.rageshake.impl.bugreport_BugReportViewNight_1_en","",0,], ["features.rageshake.impl.bugreport_BugReportViewNight_2_en","",0,], @@ -158,143 +158,143 @@ export const screenshots = [ ["libraries.designsystem.atomic.molecules_ButtonRowMolecule_Day_0_en","libraries.designsystem.atomic.molecules_ButtonRowMolecule_Night_0_en",0,], ["features.messages.impl.timeline.components_CallMenuItem_Day_0_en","features.messages.impl.timeline.components_CallMenuItem_Night_0_en",0,], ["features.messages.impl.timeline.components_CallMenuItem_Day_1_en","features.messages.impl.timeline.components_CallMenuItem_Night_1_en",0,], -["features.messages.impl.timeline.components_CallMenuItem_Day_2_en","features.messages.impl.timeline.components_CallMenuItem_Night_2_en",20504,], -["features.messages.impl.timeline.components_CallMenuItem_Day_3_en","features.messages.impl.timeline.components_CallMenuItem_Night_3_en",20504,], +["features.messages.impl.timeline.components_CallMenuItem_Day_2_en","features.messages.impl.timeline.components_CallMenuItem_Night_2_en",20511,], +["features.messages.impl.timeline.components_CallMenuItem_Day_3_en","features.messages.impl.timeline.components_CallMenuItem_Night_3_en",20511,], ["features.messages.impl.timeline.components_CallMenuItem_Day_4_en","features.messages.impl.timeline.components_CallMenuItem_Night_4_en",0,], ["features.messages.impl.timeline.components_CallMenuItem_Day_5_en","features.messages.impl.timeline.components_CallMenuItem_Night_5_en",0,], ["features.call.impl.ui_CallScreenView_Day_0_en","features.call.impl.ui_CallScreenView_Night_0_en",0,], -["features.call.impl.ui_CallScreenView_Day_1_en","features.call.impl.ui_CallScreenView_Night_1_en",20504,], -["features.call.impl.ui_CallScreenView_Day_2_en","features.call.impl.ui_CallScreenView_Night_2_en",20504,], -["features.call.impl.ui_CallScreenView_Day_3_en","features.call.impl.ui_CallScreenView_Night_3_en",20504,], -["libraries.textcomposer_CaptionWarningBottomSheet_Day_0_en","libraries.textcomposer_CaptionWarningBottomSheet_Night_0_en",20504,], -["features.login.impl.screens.changeaccountprovider_ChangeAccountProviderView_Day_0_en","features.login.impl.screens.changeaccountprovider_ChangeAccountProviderView_Night_0_en",20504,], -["features.login.impl.screens.changeaccountprovider_ChangeAccountProviderView_Day_1_en","features.login.impl.screens.changeaccountprovider_ChangeAccountProviderView_Night_1_en",20504,], -["features.rolesandpermissions.impl.roles_ChangeRolesView_Day_0_en","features.rolesandpermissions.impl.roles_ChangeRolesView_Night_0_en",20504,], -["features.rolesandpermissions.impl.roles_ChangeRolesView_Day_10_en","features.rolesandpermissions.impl.roles_ChangeRolesView_Night_10_en",20504,], -["features.rolesandpermissions.impl.roles_ChangeRolesView_Day_11_en","features.rolesandpermissions.impl.roles_ChangeRolesView_Night_11_en",20504,], -["features.rolesandpermissions.impl.roles_ChangeRolesView_Day_12_en","features.rolesandpermissions.impl.roles_ChangeRolesView_Night_12_en",20504,], -["features.rolesandpermissions.impl.roles_ChangeRolesView_Day_13_en","features.rolesandpermissions.impl.roles_ChangeRolesView_Night_13_en",20504,], -["features.rolesandpermissions.impl.roles_ChangeRolesView_Day_1_en","features.rolesandpermissions.impl.roles_ChangeRolesView_Night_1_en",20504,], -["features.rolesandpermissions.impl.roles_ChangeRolesView_Day_2_en","features.rolesandpermissions.impl.roles_ChangeRolesView_Night_2_en",20504,], -["features.rolesandpermissions.impl.roles_ChangeRolesView_Day_3_en","features.rolesandpermissions.impl.roles_ChangeRolesView_Night_3_en",20504,], -["features.rolesandpermissions.impl.roles_ChangeRolesView_Day_4_en","features.rolesandpermissions.impl.roles_ChangeRolesView_Night_4_en",20504,], +["features.call.impl.ui_CallScreenView_Day_1_en","features.call.impl.ui_CallScreenView_Night_1_en",20511,], +["features.call.impl.ui_CallScreenView_Day_2_en","features.call.impl.ui_CallScreenView_Night_2_en",20511,], +["features.call.impl.ui_CallScreenView_Day_3_en","features.call.impl.ui_CallScreenView_Night_3_en",20511,], +["libraries.textcomposer_CaptionWarningBottomSheet_Day_0_en","libraries.textcomposer_CaptionWarningBottomSheet_Night_0_en",20511,], +["features.login.impl.screens.changeaccountprovider_ChangeAccountProviderView_Day_0_en","features.login.impl.screens.changeaccountprovider_ChangeAccountProviderView_Night_0_en",20511,], +["features.login.impl.screens.changeaccountprovider_ChangeAccountProviderView_Day_1_en","features.login.impl.screens.changeaccountprovider_ChangeAccountProviderView_Night_1_en",20511,], +["features.rolesandpermissions.impl.roles_ChangeRolesView_Day_0_en","features.rolesandpermissions.impl.roles_ChangeRolesView_Night_0_en",20511,], +["features.rolesandpermissions.impl.roles_ChangeRolesView_Day_10_en","features.rolesandpermissions.impl.roles_ChangeRolesView_Night_10_en",20511,], +["features.rolesandpermissions.impl.roles_ChangeRolesView_Day_11_en","features.rolesandpermissions.impl.roles_ChangeRolesView_Night_11_en",20511,], +["features.rolesandpermissions.impl.roles_ChangeRolesView_Day_12_en","features.rolesandpermissions.impl.roles_ChangeRolesView_Night_12_en",20511,], +["features.rolesandpermissions.impl.roles_ChangeRolesView_Day_13_en","features.rolesandpermissions.impl.roles_ChangeRolesView_Night_13_en",20511,], +["features.rolesandpermissions.impl.roles_ChangeRolesView_Day_1_en","features.rolesandpermissions.impl.roles_ChangeRolesView_Night_1_en",20511,], +["features.rolesandpermissions.impl.roles_ChangeRolesView_Day_2_en","features.rolesandpermissions.impl.roles_ChangeRolesView_Night_2_en",20511,], +["features.rolesandpermissions.impl.roles_ChangeRolesView_Day_3_en","features.rolesandpermissions.impl.roles_ChangeRolesView_Night_3_en",20511,], +["features.rolesandpermissions.impl.roles_ChangeRolesView_Day_4_en","features.rolesandpermissions.impl.roles_ChangeRolesView_Night_4_en",20511,], ["features.rolesandpermissions.impl.roles_ChangeRolesView_Day_5_en","features.rolesandpermissions.impl.roles_ChangeRolesView_Night_5_en",0,], -["features.rolesandpermissions.impl.roles_ChangeRolesView_Day_6_en","features.rolesandpermissions.impl.roles_ChangeRolesView_Night_6_en",20504,], -["features.rolesandpermissions.impl.roles_ChangeRolesView_Day_7_en","features.rolesandpermissions.impl.roles_ChangeRolesView_Night_7_en",20504,], -["features.rolesandpermissions.impl.roles_ChangeRolesView_Day_8_en","features.rolesandpermissions.impl.roles_ChangeRolesView_Night_8_en",20504,], -["features.rolesandpermissions.impl.roles_ChangeRolesView_Day_9_en","features.rolesandpermissions.impl.roles_ChangeRolesView_Night_9_en",20504,], -["features.rolesandpermissions.impl.permissions_ChangeRoomPermissionsView_Day_0_en","features.rolesandpermissions.impl.permissions_ChangeRoomPermissionsView_Night_0_en",20504,], -["features.rolesandpermissions.impl.permissions_ChangeRoomPermissionsView_Day_1_en","features.rolesandpermissions.impl.permissions_ChangeRoomPermissionsView_Night_1_en",20504,], -["features.rolesandpermissions.impl.permissions_ChangeRoomPermissionsView_Day_2_en","features.rolesandpermissions.impl.permissions_ChangeRoomPermissionsView_Night_2_en",20504,], -["features.rolesandpermissions.impl.permissions_ChangeRoomPermissionsView_Day_3_en","features.rolesandpermissions.impl.permissions_ChangeRoomPermissionsView_Night_3_en",20504,], -["features.rolesandpermissions.impl.permissions_ChangeRoomPermissionsView_Day_4_en","features.rolesandpermissions.impl.permissions_ChangeRoomPermissionsView_Night_4_en",20504,], -["features.rolesandpermissions.impl.permissions_ChangeRoomPermissionsView_Day_5_en","features.rolesandpermissions.impl.permissions_ChangeRoomPermissionsView_Night_5_en",20504,], -["features.rolesandpermissions.impl.permissions_ChangeRoomPermissionsView_Day_6_en","features.rolesandpermissions.impl.permissions_ChangeRoomPermissionsView_Night_6_en",20504,], +["features.rolesandpermissions.impl.roles_ChangeRolesView_Day_6_en","features.rolesandpermissions.impl.roles_ChangeRolesView_Night_6_en",20511,], +["features.rolesandpermissions.impl.roles_ChangeRolesView_Day_7_en","features.rolesandpermissions.impl.roles_ChangeRolesView_Night_7_en",20511,], +["features.rolesandpermissions.impl.roles_ChangeRolesView_Day_8_en","features.rolesandpermissions.impl.roles_ChangeRolesView_Night_8_en",20511,], +["features.rolesandpermissions.impl.roles_ChangeRolesView_Day_9_en","features.rolesandpermissions.impl.roles_ChangeRolesView_Night_9_en",20511,], +["features.rolesandpermissions.impl.permissions_ChangeRoomPermissionsView_Day_0_en","features.rolesandpermissions.impl.permissions_ChangeRoomPermissionsView_Night_0_en",20511,], +["features.rolesandpermissions.impl.permissions_ChangeRoomPermissionsView_Day_1_en","features.rolesandpermissions.impl.permissions_ChangeRoomPermissionsView_Night_1_en",20511,], +["features.rolesandpermissions.impl.permissions_ChangeRoomPermissionsView_Day_2_en","features.rolesandpermissions.impl.permissions_ChangeRoomPermissionsView_Night_2_en",20511,], +["features.rolesandpermissions.impl.permissions_ChangeRoomPermissionsView_Day_3_en","features.rolesandpermissions.impl.permissions_ChangeRoomPermissionsView_Night_3_en",20511,], +["features.rolesandpermissions.impl.permissions_ChangeRoomPermissionsView_Day_4_en","features.rolesandpermissions.impl.permissions_ChangeRoomPermissionsView_Night_4_en",20511,], +["features.rolesandpermissions.impl.permissions_ChangeRoomPermissionsView_Day_5_en","features.rolesandpermissions.impl.permissions_ChangeRoomPermissionsView_Night_5_en",20511,], +["features.rolesandpermissions.impl.permissions_ChangeRoomPermissionsView_Day_6_en","features.rolesandpermissions.impl.permissions_ChangeRoomPermissionsView_Night_6_en",20511,], ["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",20504,], -["features.login.impl.changeserver_ChangeServerView_Day_2_en","features.login.impl.changeserver_ChangeServerView_Night_2_en",20504,], -["features.login.impl.changeserver_ChangeServerView_Day_3_en","features.login.impl.changeserver_ChangeServerView_Night_3_en",20504,], -["features.login.impl.changeserver_ChangeServerView_Day_4_en","features.login.impl.changeserver_ChangeServerView_Night_4_en",20504,], -["features.login.impl.changeserver_ChangeServerView_Day_5_en","features.login.impl.changeserver_ChangeServerView_Night_5_en",20504,], +["features.login.impl.changeserver_ChangeServerView_Day_1_en","features.login.impl.changeserver_ChangeServerView_Night_1_en",20511,], +["features.login.impl.changeserver_ChangeServerView_Day_2_en","features.login.impl.changeserver_ChangeServerView_Night_2_en",20511,], +["features.login.impl.changeserver_ChangeServerView_Day_3_en","features.login.impl.changeserver_ChangeServerView_Night_3_en",20511,], +["features.login.impl.changeserver_ChangeServerView_Day_4_en","features.login.impl.changeserver_ChangeServerView_Night_4_en",20511,], +["features.login.impl.changeserver_ChangeServerView_Day_5_en","features.login.impl.changeserver_ChangeServerView_Night_5_en",20511,], ["libraries.matrix.ui.components_CheckableResolvedUserRow_en","",0,], -["libraries.matrix.ui.components_CheckableUnresolvedUserRow_en","",20504,], +["libraries.matrix.ui.components_CheckableUnresolvedUserRow_en","",20511,], ["libraries.designsystem.theme.components_Checkboxes_Toggles_en","",0,], -["features.login.impl.screens.chooseaccountprovider_ChooseAccountProviderView_Day_0_en","features.login.impl.screens.chooseaccountprovider_ChooseAccountProviderView_Night_0_en",20504,], -["features.login.impl.screens.chooseaccountprovider_ChooseAccountProviderView_Day_1_en","features.login.impl.screens.chooseaccountprovider_ChooseAccountProviderView_Night_1_en",20504,], -["features.login.impl.screens.chooseaccountprovider_ChooseAccountProviderView_Day_2_en","features.login.impl.screens.chooseaccountprovider_ChooseAccountProviderView_Night_2_en",20504,], -["features.ftue.impl.sessionverification.choosemode_ChooseSelfVerificationModeView_Day_0_en","features.ftue.impl.sessionverification.choosemode_ChooseSelfVerificationModeView_Night_0_en",20504,], -["features.ftue.impl.sessionverification.choosemode_ChooseSelfVerificationModeView_Day_1_en","features.ftue.impl.sessionverification.choosemode_ChooseSelfVerificationModeView_Night_1_en",20504,], -["features.ftue.impl.sessionverification.choosemode_ChooseSelfVerificationModeView_Day_2_en","features.ftue.impl.sessionverification.choosemode_ChooseSelfVerificationModeView_Night_2_en",20504,], -["features.ftue.impl.sessionverification.choosemode_ChooseSelfVerificationModeView_Day_3_en","features.ftue.impl.sessionverification.choosemode_ChooseSelfVerificationModeView_Night_3_en",20504,], -["features.ftue.impl.sessionverification.choosemode_ChooseSelfVerificationModeView_Day_4_en","features.ftue.impl.sessionverification.choosemode_ChooseSelfVerificationModeView_Night_4_en",20504,], +["features.login.impl.screens.chooseaccountprovider_ChooseAccountProviderView_Day_0_en","features.login.impl.screens.chooseaccountprovider_ChooseAccountProviderView_Night_0_en",20511,], +["features.login.impl.screens.chooseaccountprovider_ChooseAccountProviderView_Day_1_en","features.login.impl.screens.chooseaccountprovider_ChooseAccountProviderView_Night_1_en",20511,], +["features.login.impl.screens.chooseaccountprovider_ChooseAccountProviderView_Day_2_en","features.login.impl.screens.chooseaccountprovider_ChooseAccountProviderView_Night_2_en",20511,], +["features.ftue.impl.sessionverification.choosemode_ChooseSelfVerificationModeView_Day_0_en","features.ftue.impl.sessionverification.choosemode_ChooseSelfVerificationModeView_Night_0_en",20511,], +["features.ftue.impl.sessionverification.choosemode_ChooseSelfVerificationModeView_Day_1_en","features.ftue.impl.sessionverification.choosemode_ChooseSelfVerificationModeView_Night_1_en",20511,], +["features.ftue.impl.sessionverification.choosemode_ChooseSelfVerificationModeView_Day_2_en","features.ftue.impl.sessionverification.choosemode_ChooseSelfVerificationModeView_Night_2_en",20511,], +["features.ftue.impl.sessionverification.choosemode_ChooseSelfVerificationModeView_Day_3_en","features.ftue.impl.sessionverification.choosemode_ChooseSelfVerificationModeView_Night_3_en",20511,], +["features.ftue.impl.sessionverification.choosemode_ChooseSelfVerificationModeView_Day_4_en","features.ftue.impl.sessionverification.choosemode_ChooseSelfVerificationModeView_Night_4_en",20511,], ["libraries.designsystem.theme.components_CircularProgressIndicator_Progress_Indicators_en","",0,], ["libraries.designsystem.components_ClickableLinkText_Text_en","",0,], ["libraries.designsystem.theme_ColorAliases_Day_0_en","libraries.designsystem.theme_ColorAliases_Night_0_en",0,], -["libraries.designsystem.atomic.molecules_ComposerAlertMolecule_Day_0_en","libraries.designsystem.atomic.molecules_ComposerAlertMolecule_Night_0_en",20504,], -["libraries.designsystem.atomic.molecules_ComposerAlertMolecule_Day_1_en","libraries.designsystem.atomic.molecules_ComposerAlertMolecule_Night_1_en",20504,], -["libraries.designsystem.atomic.molecules_ComposerAlertMolecule_Day_2_en","libraries.designsystem.atomic.molecules_ComposerAlertMolecule_Night_2_en",20504,], -["libraries.designsystem.atomic.molecules_ComposerAlertMolecule_Day_3_en","libraries.designsystem.atomic.molecules_ComposerAlertMolecule_Night_3_en",20504,], -["libraries.designsystem.atomic.molecules_ComposerAlertMolecule_Day_4_en","libraries.designsystem.atomic.molecules_ComposerAlertMolecule_Night_4_en",20504,], -["libraries.designsystem.atomic.molecules_ComposerAlertMolecule_Day_5_en","libraries.designsystem.atomic.molecules_ComposerAlertMolecule_Night_5_en",20504,], -["libraries.designsystem.atomic.molecules_ComposerAlertMolecule_Day_6_en","libraries.designsystem.atomic.molecules_ComposerAlertMolecule_Night_6_en",20504,], -["libraries.designsystem.atomic.molecules_ComposerAlertMolecule_Day_7_en","libraries.designsystem.atomic.molecules_ComposerAlertMolecule_Night_7_en",20504,], -["libraries.designsystem.atomic.molecules_ComposerAlertMolecule_Day_8_en","libraries.designsystem.atomic.molecules_ComposerAlertMolecule_Night_8_en",20504,], -["libraries.textcomposer_ComposerModeView_Day_0_en","libraries.textcomposer_ComposerModeView_Night_0_en",20504,], +["libraries.designsystem.atomic.molecules_ComposerAlertMolecule_Day_0_en","libraries.designsystem.atomic.molecules_ComposerAlertMolecule_Night_0_en",20511,], +["libraries.designsystem.atomic.molecules_ComposerAlertMolecule_Day_1_en","libraries.designsystem.atomic.molecules_ComposerAlertMolecule_Night_1_en",20511,], +["libraries.designsystem.atomic.molecules_ComposerAlertMolecule_Day_2_en","libraries.designsystem.atomic.molecules_ComposerAlertMolecule_Night_2_en",20511,], +["libraries.designsystem.atomic.molecules_ComposerAlertMolecule_Day_3_en","libraries.designsystem.atomic.molecules_ComposerAlertMolecule_Night_3_en",20511,], +["libraries.designsystem.atomic.molecules_ComposerAlertMolecule_Day_4_en","libraries.designsystem.atomic.molecules_ComposerAlertMolecule_Night_4_en",20511,], +["libraries.designsystem.atomic.molecules_ComposerAlertMolecule_Day_5_en","libraries.designsystem.atomic.molecules_ComposerAlertMolecule_Night_5_en",20511,], +["libraries.designsystem.atomic.molecules_ComposerAlertMolecule_Day_6_en","libraries.designsystem.atomic.molecules_ComposerAlertMolecule_Night_6_en",20511,], +["libraries.designsystem.atomic.molecules_ComposerAlertMolecule_Day_7_en","libraries.designsystem.atomic.molecules_ComposerAlertMolecule_Night_7_en",20511,], +["libraries.designsystem.atomic.molecules_ComposerAlertMolecule_Day_8_en","libraries.designsystem.atomic.molecules_ComposerAlertMolecule_Night_8_en",20511,], +["libraries.textcomposer_ComposerModeView_Day_0_en","libraries.textcomposer_ComposerModeView_Night_0_en",20511,], ["libraries.textcomposer_ComposerModeView_Day_1_en","libraries.textcomposer_ComposerModeView_Night_1_en",0,], ["libraries.textcomposer_ComposerModeView_Day_2_en","libraries.textcomposer_ComposerModeView_Night_2_en",0,], ["libraries.textcomposer_ComposerModeView_Day_3_en","libraries.textcomposer_ComposerModeView_Night_3_en",0,], -["features.createroom.impl.configureroom_ConfigureRoomViewDark_0_en","",20504,], -["features.createroom.impl.configureroom_ConfigureRoomViewDark_1_en","",20504,], -["features.createroom.impl.configureroom_ConfigureRoomViewDark_2_en","",20504,], -["features.createroom.impl.configureroom_ConfigureRoomViewDark_3_en","",20504,], -["features.createroom.impl.configureroom_ConfigureRoomViewDark_4_en","",20504,], -["features.createroom.impl.configureroom_ConfigureRoomViewDark_5_en","",20504,], -["features.createroom.impl.configureroom_ConfigureRoomViewDark_6_en","",20504,], -["features.createroom.impl.configureroom_ConfigureRoomViewDark_7_en","",20504,], -["features.createroom.impl.configureroom_ConfigureRoomViewDark_8_en","",20504,], -["features.createroom.impl.configureroom_ConfigureRoomViewLight_0_en","",20504,], -["features.createroom.impl.configureroom_ConfigureRoomViewLight_1_en","",20504,], -["features.createroom.impl.configureroom_ConfigureRoomViewLight_2_en","",20504,], -["features.createroom.impl.configureroom_ConfigureRoomViewLight_3_en","",20504,], -["features.createroom.impl.configureroom_ConfigureRoomViewLight_4_en","",20504,], -["features.createroom.impl.configureroom_ConfigureRoomViewLight_5_en","",20504,], -["features.createroom.impl.configureroom_ConfigureRoomViewLight_6_en","",20504,], -["features.createroom.impl.configureroom_ConfigureRoomViewLight_7_en","",20504,], -["features.createroom.impl.configureroom_ConfigureRoomViewLight_8_en","",20504,], -["features.login.impl.screens.confirmaccountprovider_ConfirmAccountProviderView_Day_0_en","features.login.impl.screens.confirmaccountprovider_ConfirmAccountProviderView_Night_0_en",20504,], -["features.login.impl.screens.confirmaccountprovider_ConfirmAccountProviderView_Day_1_en","features.login.impl.screens.confirmaccountprovider_ConfirmAccountProviderView_Night_1_en",20504,], -["features.login.impl.screens.confirmaccountprovider_ConfirmAccountProviderView_Day_2_en","features.login.impl.screens.confirmaccountprovider_ConfirmAccountProviderView_Night_2_en",20504,], -["features.home.impl.components_ConfirmRecoveryKeyBanner_Day_0_en","features.home.impl.components_ConfirmRecoveryKeyBanner_Night_0_en",20504,], +["features.createroom.impl.configureroom_ConfigureRoomViewDark_0_en","",20511,], +["features.createroom.impl.configureroom_ConfigureRoomViewDark_1_en","",20511,], +["features.createroom.impl.configureroom_ConfigureRoomViewDark_2_en","",20511,], +["features.createroom.impl.configureroom_ConfigureRoomViewDark_3_en","",20511,], +["features.createroom.impl.configureroom_ConfigureRoomViewDark_4_en","",20511,], +["features.createroom.impl.configureroom_ConfigureRoomViewDark_5_en","",20511,], +["features.createroom.impl.configureroom_ConfigureRoomViewDark_6_en","",20511,], +["features.createroom.impl.configureroom_ConfigureRoomViewDark_7_en","",20511,], +["features.createroom.impl.configureroom_ConfigureRoomViewDark_8_en","",20511,], +["features.createroom.impl.configureroom_ConfigureRoomViewLight_0_en","",20511,], +["features.createroom.impl.configureroom_ConfigureRoomViewLight_1_en","",20511,], +["features.createroom.impl.configureroom_ConfigureRoomViewLight_2_en","",20511,], +["features.createroom.impl.configureroom_ConfigureRoomViewLight_3_en","",20511,], +["features.createroom.impl.configureroom_ConfigureRoomViewLight_4_en","",20511,], +["features.createroom.impl.configureroom_ConfigureRoomViewLight_5_en","",20511,], +["features.createroom.impl.configureroom_ConfigureRoomViewLight_6_en","",20511,], +["features.createroom.impl.configureroom_ConfigureRoomViewLight_7_en","",20511,], +["features.createroom.impl.configureroom_ConfigureRoomViewLight_8_en","",20511,], +["features.login.impl.screens.confirmaccountprovider_ConfirmAccountProviderView_Day_0_en","features.login.impl.screens.confirmaccountprovider_ConfirmAccountProviderView_Night_0_en",20511,], +["features.login.impl.screens.confirmaccountprovider_ConfirmAccountProviderView_Day_1_en","features.login.impl.screens.confirmaccountprovider_ConfirmAccountProviderView_Night_1_en",20511,], +["features.login.impl.screens.confirmaccountprovider_ConfirmAccountProviderView_Day_2_en","features.login.impl.screens.confirmaccountprovider_ConfirmAccountProviderView_Night_2_en",20511,], +["features.home.impl.components_ConfirmRecoveryKeyBanner_Day_0_en","features.home.impl.components_ConfirmRecoveryKeyBanner_Night_0_en",20511,], ["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_ConnectivityIndicator_Day_0_en","features.networkmonitor.api.ui_ConnectivityIndicator_Night_0_en",0,], ["libraries.designsystem.atomic.atoms_CounterAtom_Day_0_en","libraries.designsystem.atomic.atoms_CounterAtom_Night_0_en",0,], -["features.rageshake.api.crash_CrashDetectionView_Day_0_en","features.rageshake.api.crash_CrashDetectionView_Night_0_en",20504,], -["features.login.impl.screens.createaccount_CreateAccountView_Day_0_en","features.login.impl.screens.createaccount_CreateAccountView_Night_0_en",20504,], -["features.login.impl.screens.createaccount_CreateAccountView_Day_1_en","features.login.impl.screens.createaccount_CreateAccountView_Night_1_en",20504,], -["features.login.impl.screens.createaccount_CreateAccountView_Day_2_en","features.login.impl.screens.createaccount_CreateAccountView_Night_2_en",20504,], -["features.login.impl.screens.createaccount_CreateAccountView_Day_3_en","features.login.impl.screens.createaccount_CreateAccountView_Night_3_en",20504,], -["libraries.matrix.ui.components_CreateDmConfirmationBottomSheet_Day_0_en","libraries.matrix.ui.components_CreateDmConfirmationBottomSheet_Night_0_en",20504,], -["libraries.matrix.ui.components_CreateDmConfirmationBottomSheet_Day_1_en","libraries.matrix.ui.components_CreateDmConfirmationBottomSheet_Night_1_en",20504,], -["features.poll.impl.create_CreatePollView_Day_0_en","features.poll.impl.create_CreatePollView_Night_0_en",20504,], -["features.poll.impl.create_CreatePollView_Day_1_en","features.poll.impl.create_CreatePollView_Night_1_en",20504,], -["features.poll.impl.create_CreatePollView_Day_2_en","features.poll.impl.create_CreatePollView_Night_2_en",20504,], -["features.poll.impl.create_CreatePollView_Day_3_en","features.poll.impl.create_CreatePollView_Night_3_en",20504,], -["features.poll.impl.create_CreatePollView_Day_4_en","features.poll.impl.create_CreatePollView_Night_4_en",20504,], -["features.poll.impl.create_CreatePollView_Day_5_en","features.poll.impl.create_CreatePollView_Night_5_en",20504,], -["features.poll.impl.create_CreatePollView_Day_6_en","features.poll.impl.create_CreatePollView_Night_6_en",20504,], -["features.poll.impl.create_CreatePollView_Day_7_en","features.poll.impl.create_CreatePollView_Night_7_en",20504,], -["libraries.dateformatter.impl.previews_DateFormatterModeView_0_en","",20504,], -["libraries.dateformatter.impl.previews_DateFormatterModeView_1_en","",20504,], -["libraries.dateformatter.impl.previews_DateFormatterModeView_2_en","",20504,], -["libraries.dateformatter.impl.previews_DateFormatterModeView_3_en","",20504,], -["libraries.dateformatter.impl.previews_DateFormatterModeView_4_en","",20504,], +["features.rageshake.api.crash_CrashDetectionView_Day_0_en","features.rageshake.api.crash_CrashDetectionView_Night_0_en",20511,], +["features.login.impl.screens.createaccount_CreateAccountView_Day_0_en","features.login.impl.screens.createaccount_CreateAccountView_Night_0_en",20511,], +["features.login.impl.screens.createaccount_CreateAccountView_Day_1_en","features.login.impl.screens.createaccount_CreateAccountView_Night_1_en",20511,], +["features.login.impl.screens.createaccount_CreateAccountView_Day_2_en","features.login.impl.screens.createaccount_CreateAccountView_Night_2_en",20511,], +["features.login.impl.screens.createaccount_CreateAccountView_Day_3_en","features.login.impl.screens.createaccount_CreateAccountView_Night_3_en",20511,], +["libraries.matrix.ui.components_CreateDmConfirmationBottomSheet_Day_0_en","libraries.matrix.ui.components_CreateDmConfirmationBottomSheet_Night_0_en",20511,], +["libraries.matrix.ui.components_CreateDmConfirmationBottomSheet_Day_1_en","libraries.matrix.ui.components_CreateDmConfirmationBottomSheet_Night_1_en",20511,], +["features.poll.impl.create_CreatePollView_Day_0_en","features.poll.impl.create_CreatePollView_Night_0_en",20511,], +["features.poll.impl.create_CreatePollView_Day_1_en","features.poll.impl.create_CreatePollView_Night_1_en",20511,], +["features.poll.impl.create_CreatePollView_Day_2_en","features.poll.impl.create_CreatePollView_Night_2_en",20511,], +["features.poll.impl.create_CreatePollView_Day_3_en","features.poll.impl.create_CreatePollView_Night_3_en",20511,], +["features.poll.impl.create_CreatePollView_Day_4_en","features.poll.impl.create_CreatePollView_Night_4_en",20511,], +["features.poll.impl.create_CreatePollView_Day_5_en","features.poll.impl.create_CreatePollView_Night_5_en",20511,], +["features.poll.impl.create_CreatePollView_Day_6_en","features.poll.impl.create_CreatePollView_Night_6_en",20511,], +["features.poll.impl.create_CreatePollView_Day_7_en","features.poll.impl.create_CreatePollView_Night_7_en",20511,], +["libraries.dateformatter.impl.previews_DateFormatterModeView_0_en","",20511,], +["libraries.dateformatter.impl.previews_DateFormatterModeView_1_en","",20511,], +["libraries.dateformatter.impl.previews_DateFormatterModeView_2_en","",20511,], +["libraries.dateformatter.impl.previews_DateFormatterModeView_3_en","",20511,], +["libraries.dateformatter.impl.previews_DateFormatterModeView_4_en","",20511,], ["libraries.mediaviewer.impl.gallery.ui_DateItemView_Day_0_en","libraries.mediaviewer.impl.gallery.ui_DateItemView_Night_0_en",0,], ["libraries.mediaviewer.impl.gallery.ui_DateItemView_Day_1_en","libraries.mediaviewer.impl.gallery.ui_DateItemView_Night_1_en",0,], -["libraries.designsystem.theme.components.previews_DatePickerDark_DateTime_pickers_en","",20504,], -["libraries.designsystem.theme.components.previews_DatePickerLight_DateTime_pickers_en","",20504,], -["features.invite.impl.declineandblock_DeclineAndBlockView_Day_0_en","features.invite.impl.declineandblock_DeclineAndBlockView_Night_0_en",20504,], -["features.invite.impl.declineandblock_DeclineAndBlockView_Day_1_en","features.invite.impl.declineandblock_DeclineAndBlockView_Night_1_en",20504,], -["features.invite.impl.declineandblock_DeclineAndBlockView_Day_2_en","features.invite.impl.declineandblock_DeclineAndBlockView_Night_2_en",20504,], -["features.invite.impl.declineandblock_DeclineAndBlockView_Day_3_en","features.invite.impl.declineandblock_DeclineAndBlockView_Night_3_en",20504,], -["features.invite.impl.declineandblock_DeclineAndBlockView_Day_4_en","features.invite.impl.declineandblock_DeclineAndBlockView_Night_4_en",20504,], +["libraries.designsystem.theme.components.previews_DatePickerDark_DateTime_pickers_en","",20511,], +["libraries.designsystem.theme.components.previews_DatePickerLight_DateTime_pickers_en","",20511,], +["features.invite.impl.declineandblock_DeclineAndBlockView_Day_0_en","features.invite.impl.declineandblock_DeclineAndBlockView_Night_0_en",20511,], +["features.invite.impl.declineandblock_DeclineAndBlockView_Day_1_en","features.invite.impl.declineandblock_DeclineAndBlockView_Night_1_en",20511,], +["features.invite.impl.declineandblock_DeclineAndBlockView_Day_2_en","features.invite.impl.declineandblock_DeclineAndBlockView_Night_2_en",20511,], +["features.invite.impl.declineandblock_DeclineAndBlockView_Day_3_en","features.invite.impl.declineandblock_DeclineAndBlockView_Night_3_en",20511,], +["features.invite.impl.declineandblock_DeclineAndBlockView_Day_4_en","features.invite.impl.declineandblock_DeclineAndBlockView_Night_4_en",20511,], ["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",20504,], -["features.logout.impl.direct_DefaultDirectLogoutView_Day_2_en","features.logout.impl.direct_DefaultDirectLogoutView_Night_2_en",20504,], -["features.logout.impl.direct_DefaultDirectLogoutView_Day_3_en","features.logout.impl.direct_DefaultDirectLogoutView_Night_3_en",20504,], +["features.logout.impl.direct_DefaultDirectLogoutView_Day_1_en","features.logout.impl.direct_DefaultDirectLogoutView_Night_1_en",20511,], +["features.logout.impl.direct_DefaultDirectLogoutView_Day_2_en","features.logout.impl.direct_DefaultDirectLogoutView_Night_2_en",20511,], +["features.logout.impl.direct_DefaultDirectLogoutView_Day_3_en","features.logout.impl.direct_DefaultDirectLogoutView_Night_3_en",20511,], ["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",20504,], +["features.preferences.impl.notifications.edit_DefaultNotificationSettingOption_Day_0_en","features.preferences.impl.notifications.edit_DefaultNotificationSettingOption_Night_0_en",20511,], ["features.licenses.impl.details_DependenciesDetailsView_Day_0_en","features.licenses.impl.details_DependenciesDetailsView_Night_0_en",0,], -["features.licenses.impl.list_DependencyLicensesListView_Day_0_en","features.licenses.impl.list_DependencyLicensesListView_Night_0_en",20504,], -["features.licenses.impl.list_DependencyLicensesListView_Day_1_en","features.licenses.impl.list_DependencyLicensesListView_Night_1_en",20504,], -["features.licenses.impl.list_DependencyLicensesListView_Day_2_en","features.licenses.impl.list_DependencyLicensesListView_Night_2_en",20504,], -["features.licenses.impl.list_DependencyLicensesListView_Day_3_en","features.licenses.impl.list_DependencyLicensesListView_Night_3_en",20504,], -["features.linknewdevice.impl.screens.desktop_DesktopNoticeView_Day_0_en","features.linknewdevice.impl.screens.desktop_DesktopNoticeView_Night_0_en",20504,], -["features.linknewdevice.impl.screens.desktop_DesktopNoticeView_Day_1_en","features.linknewdevice.impl.screens.desktop_DesktopNoticeView_Night_1_en",20504,], -["features.preferences.impl.developer_DeveloperSettingsView_Day_0_en","features.preferences.impl.developer_DeveloperSettingsView_Night_0_en",20504,], -["features.preferences.impl.developer_DeveloperSettingsView_Day_1_en","features.preferences.impl.developer_DeveloperSettingsView_Night_1_en",20504,], -["features.preferences.impl.developer_DeveloperSettingsView_Day_2_en","features.preferences.impl.developer_DeveloperSettingsView_Night_2_en",20504,], -["features.preferences.impl.developer_DeveloperSettingsView_Day_3_en","features.preferences.impl.developer_DeveloperSettingsView_Night_3_en",20504,], +["features.licenses.impl.list_DependencyLicensesListView_Day_0_en","features.licenses.impl.list_DependencyLicensesListView_Night_0_en",20511,], +["features.licenses.impl.list_DependencyLicensesListView_Day_1_en","features.licenses.impl.list_DependencyLicensesListView_Night_1_en",20511,], +["features.licenses.impl.list_DependencyLicensesListView_Day_2_en","features.licenses.impl.list_DependencyLicensesListView_Night_2_en",20511,], +["features.licenses.impl.list_DependencyLicensesListView_Day_3_en","features.licenses.impl.list_DependencyLicensesListView_Night_3_en",20511,], +["features.linknewdevice.impl.screens.desktop_DesktopNoticeView_Day_0_en","features.linknewdevice.impl.screens.desktop_DesktopNoticeView_Night_0_en",20511,], +["features.linknewdevice.impl.screens.desktop_DesktopNoticeView_Day_1_en","features.linknewdevice.impl.screens.desktop_DesktopNoticeView_Night_1_en",20511,], +["features.preferences.impl.developer_DeveloperSettingsView_Day_0_en","features.preferences.impl.developer_DeveloperSettingsView_Night_0_en",20511,], +["features.preferences.impl.developer_DeveloperSettingsView_Day_1_en","features.preferences.impl.developer_DeveloperSettingsView_Night_1_en",20511,], +["features.preferences.impl.developer_DeveloperSettingsView_Day_2_en","features.preferences.impl.developer_DeveloperSettingsView_Night_2_en",20511,], +["features.preferences.impl.developer_DeveloperSettingsView_Day_3_en","features.preferences.impl.developer_DeveloperSettingsView_Night_3_en",20511,], ["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,], @@ -309,19 +309,19 @@ 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",20504,], -["features.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_Day_1_en","features.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_Night_1_en",20504,], -["features.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_Day_2_en","features.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_Night_2_en",20504,], -["features.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_Day_3_en","features.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_Night_3_en",20504,], -["features.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_Day_4_en","features.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_Night_4_en",20504,], -["features.securityandprivacy.impl.editroomaddress_EditRoomAddressView_Day_0_en","features.securityandprivacy.impl.editroomaddress_EditRoomAddressView_Night_0_en",20504,], -["features.securityandprivacy.impl.editroomaddress_EditRoomAddressView_Day_1_en","features.securityandprivacy.impl.editroomaddress_EditRoomAddressView_Night_1_en",20504,], -["features.securityandprivacy.impl.editroomaddress_EditRoomAddressView_Day_2_en","features.securityandprivacy.impl.editroomaddress_EditRoomAddressView_Night_2_en",20504,], -["features.securityandprivacy.impl.editroomaddress_EditRoomAddressView_Day_3_en","features.securityandprivacy.impl.editroomaddress_EditRoomAddressView_Night_3_en",20504,], -["features.securityandprivacy.impl.editroomaddress_EditRoomAddressView_Day_4_en","features.securityandprivacy.impl.editroomaddress_EditRoomAddressView_Night_4_en",20504,], -["features.preferences.impl.user.editprofile_EditUserProfileView_Day_0_en","features.preferences.impl.user.editprofile_EditUserProfileView_Night_0_en",20504,], -["features.preferences.impl.user.editprofile_EditUserProfileView_Day_1_en","features.preferences.impl.user.editprofile_EditUserProfileView_Night_1_en",20504,], -["features.preferences.impl.user.editprofile_EditUserProfileView_Day_2_en","features.preferences.impl.user.editprofile_EditUserProfileView_Night_2_en",20504,], +["features.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_Day_0_en","features.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_Night_0_en",20511,], +["features.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_Day_1_en","features.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_Night_1_en",20511,], +["features.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_Day_2_en","features.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_Night_2_en",20511,], +["features.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_Day_3_en","features.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_Night_3_en",20511,], +["features.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_Day_4_en","features.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_Night_4_en",20511,], +["features.securityandprivacy.impl.editroomaddress_EditRoomAddressView_Day_0_en","features.securityandprivacy.impl.editroomaddress_EditRoomAddressView_Night_0_en",20511,], +["features.securityandprivacy.impl.editroomaddress_EditRoomAddressView_Day_1_en","features.securityandprivacy.impl.editroomaddress_EditRoomAddressView_Night_1_en",20511,], +["features.securityandprivacy.impl.editroomaddress_EditRoomAddressView_Day_2_en","features.securityandprivacy.impl.editroomaddress_EditRoomAddressView_Night_2_en",20511,], +["features.securityandprivacy.impl.editroomaddress_EditRoomAddressView_Day_3_en","features.securityandprivacy.impl.editroomaddress_EditRoomAddressView_Night_3_en",20511,], +["features.securityandprivacy.impl.editroomaddress_EditRoomAddressView_Day_4_en","features.securityandprivacy.impl.editroomaddress_EditRoomAddressView_Night_4_en",20511,], +["features.preferences.impl.user.editprofile_EditUserProfileView_Day_0_en","features.preferences.impl.user.editprofile_EditUserProfileView_Night_0_en",20511,], +["features.preferences.impl.user.editprofile_EditUserProfileView_Day_1_en","features.preferences.impl.user.editprofile_EditUserProfileView_Night_1_en",20511,], +["features.preferences.impl.user.editprofile_EditUserProfileView_Day_2_en","features.preferences.impl.user.editprofile_EditUserProfileView_Night_2_en",20511,], ["libraries.matrix.ui.components_EditableOrgAvatarRtl_Day_0_en","libraries.matrix.ui.components_EditableOrgAvatarRtl_Night_0_en",0,], ["libraries.matrix.ui.components_EditableOrgAvatar_Day_0_en","libraries.matrix.ui.components_EditableOrgAvatar_Night_0_en",0,], ["libraries.designsystem.atomic.atoms_ElementLogoAtomLargeNoBlurShadow_Day_0_en","libraries.designsystem.atomic.atoms_ElementLogoAtomLargeNoBlurShadow_Night_0_en",0,], @@ -329,28 +329,28 @@ export const screenshots = [ ["libraries.designsystem.atomic.atoms_ElementLogoAtomMediumNoBlurShadow_Day_0_en","libraries.designsystem.atomic.atoms_ElementLogoAtomMediumNoBlurShadow_Night_0_en",0,], ["libraries.designsystem.atomic.atoms_ElementLogoAtomMedium_Day_0_en","libraries.designsystem.atomic.atoms_ElementLogoAtomMedium_Night_0_en",0,], ["features.messages.impl.timeline.components.customreaction_EmojiItem_Day_0_en","features.messages.impl.timeline.components.customreaction_EmojiItem_Night_0_en",0,], -["features.messages.impl.timeline.components.customreaction.picker_EmojiPicker_Day_0_en","features.messages.impl.timeline.components.customreaction.picker_EmojiPicker_Night_0_en",20504,], -["features.messages.impl.timeline.components.customreaction.picker_EmojiPicker_Day_1_en","features.messages.impl.timeline.components.customreaction.picker_EmojiPicker_Night_1_en",20504,], +["features.messages.impl.timeline.components.customreaction.picker_EmojiPicker_Day_0_en","features.messages.impl.timeline.components.customreaction.picker_EmojiPicker_Night_0_en",20511,], +["features.messages.impl.timeline.components.customreaction.picker_EmojiPicker_Day_1_en","features.messages.impl.timeline.components.customreaction.picker_EmojiPicker_Night_1_en",20511,], ["features.messages.impl.timeline.components.customreaction.picker_EmojiPicker_Day_2_en","features.messages.impl.timeline.components.customreaction.picker_EmojiPicker_Night_2_en",0,], ["features.messages.impl.timeline.components.customreaction.picker_EmojiPicker_Day_3_en","features.messages.impl.timeline.components.customreaction.picker_EmojiPicker_Night_3_en",0,], ["libraries.ui.common.nodes_EmptyView_Day_0_en","libraries.ui.common.nodes_EmptyView_Night_0_en",0,], -["features.linknewdevice.impl.screens.number_EnterNumberView_Day_0_en","features.linknewdevice.impl.screens.number_EnterNumberView_Night_0_en",20504,], -["features.linknewdevice.impl.screens.number_EnterNumberView_Day_1_en","features.linknewdevice.impl.screens.number_EnterNumberView_Night_1_en",20504,], -["features.linknewdevice.impl.screens.number_EnterNumberView_Day_2_en","features.linknewdevice.impl.screens.number_EnterNumberView_Night_2_en",20504,], -["features.linknewdevice.impl.screens.number_EnterNumberView_Day_3_en","features.linknewdevice.impl.screens.number_EnterNumberView_Night_3_en",20504,], -["features.linknewdevice.impl.screens.number_EnterNumberView_Day_4_en","features.linknewdevice.impl.screens.number_EnterNumberView_Night_4_en",20504,], -["features.linknewdevice.impl.screens.number_EnterNumberView_Day_5_en","features.linknewdevice.impl.screens.number_EnterNumberView_Night_5_en",20504,], -["libraries.designsystem.components.dialogs_ErrorDialogContent_Dialogs_en","",20504,], -["libraries.designsystem.components.dialogs_ErrorDialogWithDoNotShowAgain_Day_0_en","libraries.designsystem.components.dialogs_ErrorDialogWithDoNotShowAgain_Night_0_en",20504,], -["libraries.designsystem.components.dialogs_ErrorDialog_Day_0_en","libraries.designsystem.components.dialogs_ErrorDialog_Night_0_en",20504,], -["features.linknewdevice.impl.screens.error_ErrorView_Day_0_en","features.linknewdevice.impl.screens.error_ErrorView_Night_0_en",20504,], -["features.linknewdevice.impl.screens.error_ErrorView_Day_1_en","features.linknewdevice.impl.screens.error_ErrorView_Night_1_en",20504,], -["features.linknewdevice.impl.screens.error_ErrorView_Day_2_en","features.linknewdevice.impl.screens.error_ErrorView_Night_2_en",20504,], -["features.linknewdevice.impl.screens.error_ErrorView_Day_3_en","features.linknewdevice.impl.screens.error_ErrorView_Night_3_en",20504,], -["features.linknewdevice.impl.screens.error_ErrorView_Day_4_en","features.linknewdevice.impl.screens.error_ErrorView_Night_4_en",20504,], -["features.linknewdevice.impl.screens.error_ErrorView_Day_5_en","features.linknewdevice.impl.screens.error_ErrorView_Night_5_en",20504,], -["features.linknewdevice.impl.screens.error_ErrorView_Day_6_en","features.linknewdevice.impl.screens.error_ErrorView_Night_6_en",20504,], -["features.linknewdevice.impl.screens.error_ErrorView_Day_7_en","features.linknewdevice.impl.screens.error_ErrorView_Night_7_en",20504,], +["features.linknewdevice.impl.screens.number_EnterNumberView_Day_0_en","features.linknewdevice.impl.screens.number_EnterNumberView_Night_0_en",20511,], +["features.linknewdevice.impl.screens.number_EnterNumberView_Day_1_en","features.linknewdevice.impl.screens.number_EnterNumberView_Night_1_en",20511,], +["features.linknewdevice.impl.screens.number_EnterNumberView_Day_2_en","features.linknewdevice.impl.screens.number_EnterNumberView_Night_2_en",20511,], +["features.linknewdevice.impl.screens.number_EnterNumberView_Day_3_en","features.linknewdevice.impl.screens.number_EnterNumberView_Night_3_en",20511,], +["features.linknewdevice.impl.screens.number_EnterNumberView_Day_4_en","features.linknewdevice.impl.screens.number_EnterNumberView_Night_4_en",20511,], +["features.linknewdevice.impl.screens.number_EnterNumberView_Day_5_en","features.linknewdevice.impl.screens.number_EnterNumberView_Night_5_en",20511,], +["libraries.designsystem.components.dialogs_ErrorDialogContent_Dialogs_en","",20511,], +["libraries.designsystem.components.dialogs_ErrorDialogWithDoNotShowAgain_Day_0_en","libraries.designsystem.components.dialogs_ErrorDialogWithDoNotShowAgain_Night_0_en",20511,], +["libraries.designsystem.components.dialogs_ErrorDialog_Day_0_en","libraries.designsystem.components.dialogs_ErrorDialog_Night_0_en",20511,], +["features.linknewdevice.impl.screens.error_ErrorView_Day_0_en","features.linknewdevice.impl.screens.error_ErrorView_Night_0_en",20511,], +["features.linknewdevice.impl.screens.error_ErrorView_Day_1_en","features.linknewdevice.impl.screens.error_ErrorView_Night_1_en",20511,], +["features.linknewdevice.impl.screens.error_ErrorView_Day_2_en","features.linknewdevice.impl.screens.error_ErrorView_Night_2_en",20511,], +["features.linknewdevice.impl.screens.error_ErrorView_Day_3_en","features.linknewdevice.impl.screens.error_ErrorView_Night_3_en",20511,], +["features.linknewdevice.impl.screens.error_ErrorView_Day_4_en","features.linknewdevice.impl.screens.error_ErrorView_Night_4_en",20511,], +["features.linknewdevice.impl.screens.error_ErrorView_Day_5_en","features.linknewdevice.impl.screens.error_ErrorView_Night_5_en",20511,], +["features.linknewdevice.impl.screens.error_ErrorView_Day_6_en","features.linknewdevice.impl.screens.error_ErrorView_Night_6_en",20511,], +["features.linknewdevice.impl.screens.error_ErrorView_Day_7_en","features.linknewdevice.impl.screens.error_ErrorView_Night_7_en",20511,], ["features.messages.impl.timeline.debug_EventDebugInfoView_Day_0_en","features.messages.impl.timeline.debug_EventDebugInfoView_Night_0_en",0,], ["libraries.designsystem.components_ExpandableBottomSheetLayout_en","",0,], ["libraries.featureflag.ui_FeatureListView_Day_0_en","libraries.featureflag.ui_FeatureListView_Night_0_en",0,], @@ -369,48 +369,51 @@ 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",20504,], -["features.messages.impl.timeline.focus_FocusRequestStateView_Day_2_en","features.messages.impl.timeline.focus_FocusRequestStateView_Night_2_en",20504,], -["features.messages.impl.timeline.focus_FocusRequestStateView_Day_3_en","features.messages.impl.timeline.focus_FocusRequestStateView_Night_3_en",20504,], +["features.messages.impl.timeline.focus_FocusRequestStateView_Day_1_en","features.messages.impl.timeline.focus_FocusRequestStateView_Night_1_en",20511,], +["features.messages.impl.timeline.focus_FocusRequestStateView_Day_2_en","features.messages.impl.timeline.focus_FocusRequestStateView_Night_2_en",20511,], +["features.messages.impl.timeline.focus_FocusRequestStateView_Day_3_en","features.messages.impl.timeline.focus_FocusRequestStateView_Night_3_en",20511,], ["features.messages.impl.timeline.components_FocusedEvent_Day_0_en","features.messages.impl.timeline.components_FocusedEvent_Night_0_en",0,], ["libraries.textcomposer.components_FormattingOption_Day_0_en","libraries.textcomposer.components_FormattingOption_Night_0_en",0,], ["features.forward.impl_ForwardMessagesView_Day_0_en","features.forward.impl_ForwardMessagesView_Night_0_en",0,], ["features.forward.impl_ForwardMessagesView_Day_1_en","features.forward.impl_ForwardMessagesView_Night_1_en",0,], ["features.forward.impl_ForwardMessagesView_Day_2_en","features.forward.impl_ForwardMessagesView_Night_2_en",0,], -["features.forward.impl_ForwardMessagesView_Day_3_en","features.forward.impl_ForwardMessagesView_Night_3_en",20504,], -["features.home.impl.components_FullScreenIntentPermissionBanner_Day_0_en","features.home.impl.components_FullScreenIntentPermissionBanner_Night_0_en",20504,], +["features.forward.impl_ForwardMessagesView_Day_3_en","features.forward.impl_ForwardMessagesView_Night_3_en",20511,], +["features.home.impl.components_FullScreenIntentPermissionBanner_Day_0_en","features.home.impl.components_FullScreenIntentPermissionBanner_Night_0_en",20511,], ["libraries.designsystem.components.button_GradientFloatingActionButtonCircleShape_Day_0_en","libraries.designsystem.components.button_GradientFloatingActionButtonCircleShape_Night_0_en",0,], ["libraries.designsystem.components.button_GradientFloatingActionButton_Day_0_en","libraries.designsystem.components.button_GradientFloatingActionButton_Night_0_en",0,], ["features.messages.impl.timeline.components.group_GroupHeaderView_Day_0_en","features.messages.impl.timeline.components.group_GroupHeaderView_Night_0_en",0,], ["libraries.designsystem.atomic.pages_HeaderFooterPageScrollable_Day_0_en","libraries.designsystem.atomic.pages_HeaderFooterPageScrollable_Night_0_en",0,], ["libraries.designsystem.atomic.pages_HeaderFooterPage_Day_0_en","libraries.designsystem.atomic.pages_HeaderFooterPage_Night_0_en",0,], -["features.home.impl.spaces_HomeSpacesView_Day_0_en","features.home.impl.spaces_HomeSpacesView_Night_0_en",20504,], -["features.home.impl.spaces_HomeSpacesView_Day_1_en","features.home.impl.spaces_HomeSpacesView_Night_1_en",20504,], -["features.home.impl.spaces_HomeSpacesView_Day_2_en","features.home.impl.spaces_HomeSpacesView_Night_2_en",20504,], -["features.home.impl.spaces_HomeSpacesView_Day_3_en","features.home.impl.spaces_HomeSpacesView_Night_3_en",20504,], -["features.home.impl.components_HomeTopBarMultiAccount_Day_0_en","features.home.impl.components_HomeTopBarMultiAccount_Night_0_en",20504,], -["features.home.impl.components_HomeTopBarSpaceFiltersSelected_Day_0_en","features.home.impl.components_HomeTopBarSpaceFiltersSelected_Night_0_en",20504,], +["features.home.impl.spaces_HomeSpacesView_Day_0_en","features.home.impl.spaces_HomeSpacesView_Night_0_en",20511,], +["features.home.impl.spaces_HomeSpacesView_Day_1_en","features.home.impl.spaces_HomeSpacesView_Night_1_en",20511,], +["features.home.impl.spaces_HomeSpacesView_Day_2_en","features.home.impl.spaces_HomeSpacesView_Night_2_en",20511,], +["features.home.impl.spaces_HomeSpacesView_Day_3_en","features.home.impl.spaces_HomeSpacesView_Night_3_en",20511,], +["features.home.impl.components_HomeTopBarMultiAccount_Day_0_en","features.home.impl.components_HomeTopBarMultiAccount_Night_0_en",20511,], +["features.home.impl.components_HomeTopBarSpaceFiltersSelected_Day_0_en","features.home.impl.components_HomeTopBarSpaceFiltersSelected_Night_0_en",20511,], ["features.home.impl.components_HomeTopBarSpaces_Day_0_en","features.home.impl.components_HomeTopBarSpaces_Night_0_en",0,], -["features.home.impl.components_HomeTopBarWithIndicator_Day_0_en","features.home.impl.components_HomeTopBarWithIndicator_Night_0_en",20504,], -["features.home.impl.components_HomeTopBar_Day_0_en","features.home.impl.components_HomeTopBar_Night_0_en",20504,], +["features.home.impl.components_HomeTopBarWithIndicator_Day_0_en","features.home.impl.components_HomeTopBarWithIndicator_Night_0_en",20511,], +["features.home.impl.components_HomeTopBar_Day_0_en","features.home.impl.components_HomeTopBar_Night_0_en",20511,], ["features.home.impl_HomeViewA11y_en","",0,], -["features.home.impl_HomeView_Day_0_en","features.home.impl_HomeView_Night_0_en",20504,], -["features.home.impl_HomeView_Day_10_en","features.home.impl_HomeView_Night_10_en",20504,], +["features.home.impl_HomeView_Day_0_en","features.home.impl_HomeView_Night_0_en",20511,], +["features.home.impl_HomeView_Day_10_en","features.home.impl_HomeView_Night_10_en",20511,], ["features.home.impl_HomeView_Day_11_en","features.home.impl_HomeView_Night_11_en",0,], ["features.home.impl_HomeView_Day_12_en","features.home.impl_HomeView_Night_12_en",0,], -["features.home.impl_HomeView_Day_13_en","features.home.impl_HomeView_Night_13_en",20504,], -["features.home.impl_HomeView_Day_14_en","features.home.impl_HomeView_Night_14_en",20504,], -["features.home.impl_HomeView_Day_15_en","features.home.impl_HomeView_Night_15_en",20504,], -["features.home.impl_HomeView_Day_1_en","features.home.impl_HomeView_Night_1_en",20504,], -["features.home.impl_HomeView_Day_2_en","features.home.impl_HomeView_Night_2_en",20504,], -["features.home.impl_HomeView_Day_3_en","features.home.impl_HomeView_Night_3_en",20504,], -["features.home.impl_HomeView_Day_4_en","features.home.impl_HomeView_Night_4_en",20504,], -["features.home.impl_HomeView_Day_5_en","features.home.impl_HomeView_Night_5_en",20504,], -["features.home.impl_HomeView_Day_6_en","features.home.impl_HomeView_Night_6_en",20504,], -["features.home.impl_HomeView_Day_7_en","features.home.impl_HomeView_Night_7_en",20504,], -["features.home.impl_HomeView_Day_8_en","features.home.impl_HomeView_Night_8_en",20504,], -["features.home.impl_HomeView_Day_9_en","features.home.impl_HomeView_Night_9_en",20504,], +["features.home.impl_HomeView_Day_13_en","features.home.impl_HomeView_Night_13_en",20511,], +["features.home.impl_HomeView_Day_14_en","features.home.impl_HomeView_Night_14_en",20511,], +["features.home.impl_HomeView_Day_15_en","features.home.impl_HomeView_Night_15_en",20511,], +["features.home.impl_HomeView_Day_16_en","features.home.impl_HomeView_Night_16_en",20514,], +["features.home.impl_HomeView_Day_1_en","features.home.impl_HomeView_Night_1_en",20511,], +["features.home.impl_HomeView_Day_2_en","features.home.impl_HomeView_Night_2_en",20511,], +["features.home.impl_HomeView_Day_3_en","features.home.impl_HomeView_Night_3_en",20511,], +["features.home.impl_HomeView_Day_4_en","features.home.impl_HomeView_Night_4_en",20511,], +["features.home.impl_HomeView_Day_5_en","features.home.impl_HomeView_Night_5_en",20511,], +["features.home.impl_HomeView_Day_6_en","features.home.impl_HomeView_Night_6_en",20511,], +["features.home.impl_HomeView_Day_7_en","features.home.impl_HomeView_Night_7_en",20511,], +["features.home.impl_HomeView_Day_8_en","features.home.impl_HomeView_Night_8_en",20511,], +["features.home.impl_HomeView_Day_9_en","features.home.impl_HomeView_Night_9_en",20511,], ["libraries.designsystem.theme.components_HorizontalDivider_Dividers_en","",0,], +["libraries.designsystem.theme.components_HorizontalFloatingToolbarNoFab_Day_0_en","libraries.designsystem.theme.components_HorizontalFloatingToolbarNoFab_Night_0_en",0,], +["libraries.designsystem.theme.components_HorizontalFloatingToolbar_Day_0_en","libraries.designsystem.theme.components_HorizontalFloatingToolbar_Night_0_en",0,], ["libraries.designsystem.ruler_HorizontalRuler_Day_0_en","libraries.designsystem.ruler_HorizontalRuler_Night_0_en",0,], ["libraries.designsystem.theme.components_IconButton_Buttons_en","",0,], ["libraries.designsystem.theme.components_IconColorButton_Day_0_en","libraries.designsystem.theme.components_IconColorButton_Night_0_en",0,], @@ -422,8 +425,8 @@ export const screenshots = [ ["appicon.enterprise_Icon_en","",0,], ["libraries.designsystem.icons_IconsOther_Day_0_en","libraries.designsystem.icons_IconsOther_Night_0_en",0,], ["features.messages.impl.crypto.identity_IdentityChangeStateView_Day_0_en","features.messages.impl.crypto.identity_IdentityChangeStateView_Night_0_en",0,], -["features.messages.impl.crypto.identity_IdentityChangeStateView_Day_1_en","features.messages.impl.crypto.identity_IdentityChangeStateView_Night_1_en",20504,], -["features.messages.impl.crypto.identity_IdentityChangeStateView_Day_2_en","features.messages.impl.crypto.identity_IdentityChangeStateView_Night_2_en",20504,], +["features.messages.impl.crypto.identity_IdentityChangeStateView_Day_1_en","features.messages.impl.crypto.identity_IdentityChangeStateView_Night_1_en",20511,], +["features.messages.impl.crypto.identity_IdentityChangeStateView_Day_2_en","features.messages.impl.crypto.identity_IdentityChangeStateView_Night_2_en",20511,], ["libraries.mediaviewer.impl.gallery.ui_ImageItemView_Day_0_en","libraries.mediaviewer.impl.gallery.ui_ImageItemView_Night_0_en",0,], ["libraries.matrix.ui.messages.reply_InReplyToView_Day_0_en","libraries.matrix.ui.messages.reply_InReplyToView_Night_0_en",0,], ["libraries.matrix.ui.messages.reply_InReplyToView_Day_10_en","libraries.matrix.ui.messages.reply_InReplyToView_Night_10_en",0,], @@ -431,116 +434,116 @@ 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",20504,], +["libraries.matrix.ui.messages.reply_InReplyToView_Day_4_en","libraries.matrix.ui.messages.reply_InReplyToView_Night_4_en",20511,], ["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",20504,], +["libraries.matrix.ui.messages.reply_InReplyToView_Day_8_en","libraries.matrix.ui.messages.reply_InReplyToView_Night_8_en",20511,], ["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",20504,], +["features.call.impl.ui_IncomingCallScreen_Day_0_en","features.call.impl.ui_IncomingCallScreen_Night_0_en",20511,], ["features.verifysession.impl.incoming_IncomingVerificationViewA11y_en","",0,], -["features.verifysession.impl.incoming_IncomingVerificationView_Day_0_en","features.verifysession.impl.incoming_IncomingVerificationView_Night_0_en",20504,], -["features.verifysession.impl.incoming_IncomingVerificationView_Day_10_en","features.verifysession.impl.incoming_IncomingVerificationView_Night_10_en",20504,], -["features.verifysession.impl.incoming_IncomingVerificationView_Day_11_en","features.verifysession.impl.incoming_IncomingVerificationView_Night_11_en",20504,], -["features.verifysession.impl.incoming_IncomingVerificationView_Day_12_en","features.verifysession.impl.incoming_IncomingVerificationView_Night_12_en",20504,], -["features.verifysession.impl.incoming_IncomingVerificationView_Day_13_en","features.verifysession.impl.incoming_IncomingVerificationView_Night_13_en",20504,], -["features.verifysession.impl.incoming_IncomingVerificationView_Day_1_en","features.verifysession.impl.incoming_IncomingVerificationView_Night_1_en",20504,], -["features.verifysession.impl.incoming_IncomingVerificationView_Day_2_en","features.verifysession.impl.incoming_IncomingVerificationView_Night_2_en",20504,], -["features.verifysession.impl.incoming_IncomingVerificationView_Day_3_en","features.verifysession.impl.incoming_IncomingVerificationView_Night_3_en",20504,], -["features.verifysession.impl.incoming_IncomingVerificationView_Day_4_en","features.verifysession.impl.incoming_IncomingVerificationView_Night_4_en",20504,], -["features.verifysession.impl.incoming_IncomingVerificationView_Day_5_en","features.verifysession.impl.incoming_IncomingVerificationView_Night_5_en",20504,], -["features.verifysession.impl.incoming_IncomingVerificationView_Day_6_en","features.verifysession.impl.incoming_IncomingVerificationView_Night_6_en",20504,], -["features.verifysession.impl.incoming_IncomingVerificationView_Day_7_en","features.verifysession.impl.incoming_IncomingVerificationView_Night_7_en",20504,], -["features.verifysession.impl.incoming_IncomingVerificationView_Day_8_en","features.verifysession.impl.incoming_IncomingVerificationView_Night_8_en",20504,], -["features.verifysession.impl.incoming_IncomingVerificationView_Day_9_en","features.verifysession.impl.incoming_IncomingVerificationView_Night_9_en",20504,], +["features.verifysession.impl.incoming_IncomingVerificationView_Day_0_en","features.verifysession.impl.incoming_IncomingVerificationView_Night_0_en",20511,], +["features.verifysession.impl.incoming_IncomingVerificationView_Day_10_en","features.verifysession.impl.incoming_IncomingVerificationView_Night_10_en",20511,], +["features.verifysession.impl.incoming_IncomingVerificationView_Day_11_en","features.verifysession.impl.incoming_IncomingVerificationView_Night_11_en",20511,], +["features.verifysession.impl.incoming_IncomingVerificationView_Day_12_en","features.verifysession.impl.incoming_IncomingVerificationView_Night_12_en",20511,], +["features.verifysession.impl.incoming_IncomingVerificationView_Day_13_en","features.verifysession.impl.incoming_IncomingVerificationView_Night_13_en",20511,], +["features.verifysession.impl.incoming_IncomingVerificationView_Day_1_en","features.verifysession.impl.incoming_IncomingVerificationView_Night_1_en",20511,], +["features.verifysession.impl.incoming_IncomingVerificationView_Day_2_en","features.verifysession.impl.incoming_IncomingVerificationView_Night_2_en",20511,], +["features.verifysession.impl.incoming_IncomingVerificationView_Day_3_en","features.verifysession.impl.incoming_IncomingVerificationView_Night_3_en",20511,], +["features.verifysession.impl.incoming_IncomingVerificationView_Day_4_en","features.verifysession.impl.incoming_IncomingVerificationView_Night_4_en",20511,], +["features.verifysession.impl.incoming_IncomingVerificationView_Day_5_en","features.verifysession.impl.incoming_IncomingVerificationView_Night_5_en",20511,], +["features.verifysession.impl.incoming_IncomingVerificationView_Day_6_en","features.verifysession.impl.incoming_IncomingVerificationView_Night_6_en",20511,], +["features.verifysession.impl.incoming_IncomingVerificationView_Day_7_en","features.verifysession.impl.incoming_IncomingVerificationView_Night_7_en",20511,], +["features.verifysession.impl.incoming_IncomingVerificationView_Day_8_en","features.verifysession.impl.incoming_IncomingVerificationView_Night_8_en",20511,], +["features.verifysession.impl.incoming_IncomingVerificationView_Day_9_en","features.verifysession.impl.incoming_IncomingVerificationView_Night_9_en",20511,], ["libraries.designsystem.atomic.molecules_InfoListItemMolecule_Day_0_en","libraries.designsystem.atomic.molecules_InfoListItemMolecule_Night_0_en",0,], ["libraries.designsystem.atomic.organisms_InfoListOrganism_Day_0_en","libraries.designsystem.atomic.organisms_InfoListOrganism_Night_0_en",0,], ["libraries.matrix.ui.media_InitialsAvatarBitmapGenerator_Day_0_en","libraries.matrix.ui.media_InitialsAvatarBitmapGenerator_Night_0_en",0,], -["features.call.impl.ui_InvalidAudioDeviceDialog_Day_0_en","features.call.impl.ui_InvalidAudioDeviceDialog_Night_0_en",20504,], -["features.invitepeople.impl_InvitePeopleView_Day_0_en","features.invitepeople.impl_InvitePeopleView_Night_0_en",20504,], -["features.invitepeople.impl_InvitePeopleView_Day_1_en","features.invitepeople.impl_InvitePeopleView_Night_1_en",20504,], +["features.call.impl.ui_InvalidAudioDeviceDialog_Day_0_en","features.call.impl.ui_InvalidAudioDeviceDialog_Night_0_en",20511,], +["features.invitepeople.impl_InvitePeopleView_Day_0_en","features.invitepeople.impl_InvitePeopleView_Night_0_en",20511,], +["features.invitepeople.impl_InvitePeopleView_Day_1_en","features.invitepeople.impl_InvitePeopleView_Night_1_en",20511,], ["features.invitepeople.impl_InvitePeopleView_Day_2_en","features.invitepeople.impl_InvitePeopleView_Night_2_en",0,], ["features.invitepeople.impl_InvitePeopleView_Day_3_en","features.invitepeople.impl_InvitePeopleView_Night_3_en",0,], -["features.invitepeople.impl_InvitePeopleView_Day_4_en","features.invitepeople.impl_InvitePeopleView_Night_4_en",20504,], -["features.invitepeople.impl_InvitePeopleView_Day_5_en","features.invitepeople.impl_InvitePeopleView_Night_5_en",20504,], -["features.invitepeople.impl_InvitePeopleView_Day_6_en","features.invitepeople.impl_InvitePeopleView_Night_6_en",20504,], -["features.invitepeople.impl_InvitePeopleView_Day_7_en","features.invitepeople.impl_InvitePeopleView_Night_7_en",20504,], +["features.invitepeople.impl_InvitePeopleView_Day_4_en","features.invitepeople.impl_InvitePeopleView_Night_4_en",20511,], +["features.invitepeople.impl_InvitePeopleView_Day_5_en","features.invitepeople.impl_InvitePeopleView_Night_5_en",20511,], +["features.invitepeople.impl_InvitePeopleView_Day_6_en","features.invitepeople.impl_InvitePeopleView_Night_6_en",20511,], +["features.invitepeople.impl_InvitePeopleView_Day_7_en","features.invitepeople.impl_InvitePeopleView_Night_7_en",20511,], ["features.invitepeople.impl_InvitePeopleView_Day_8_en","features.invitepeople.impl_InvitePeopleView_Night_8_en",0,], -["features.invitepeople.impl_InvitePeopleView_Day_9_en","features.invitepeople.impl_InvitePeopleView_Night_9_en",20504,], -["libraries.matrix.ui.components_InviteSenderView_Day_0_en","libraries.matrix.ui.components_InviteSenderView_Night_0_en",20504,], -["features.startchat.impl.joinbyaddress_JoinRoomByAddressView_Day_0_en","features.startchat.impl.joinbyaddress_JoinRoomByAddressView_Night_0_en",20504,], -["features.startchat.impl.joinbyaddress_JoinRoomByAddressView_Day_1_en","features.startchat.impl.joinbyaddress_JoinRoomByAddressView_Night_1_en",20504,], -["features.startchat.impl.joinbyaddress_JoinRoomByAddressView_Day_2_en","features.startchat.impl.joinbyaddress_JoinRoomByAddressView_Night_2_en",20504,], -["features.startchat.impl.joinbyaddress_JoinRoomByAddressView_Day_3_en","features.startchat.impl.joinbyaddress_JoinRoomByAddressView_Night_3_en",20504,], -["features.startchat.impl.joinbyaddress_JoinRoomByAddressView_Day_4_en","features.startchat.impl.joinbyaddress_JoinRoomByAddressView_Night_4_en",20504,], -["features.startchat.impl.joinbyaddress_JoinRoomByAddressView_Day_5_en","features.startchat.impl.joinbyaddress_JoinRoomByAddressView_Night_5_en",20504,], +["features.invitepeople.impl_InvitePeopleView_Day_9_en","features.invitepeople.impl_InvitePeopleView_Night_9_en",20511,], +["libraries.matrix.ui.components_InviteSenderView_Day_0_en","libraries.matrix.ui.components_InviteSenderView_Night_0_en",20511,], +["features.startchat.impl.joinbyaddress_JoinRoomByAddressView_Day_0_en","features.startchat.impl.joinbyaddress_JoinRoomByAddressView_Night_0_en",20511,], +["features.startchat.impl.joinbyaddress_JoinRoomByAddressView_Day_1_en","features.startchat.impl.joinbyaddress_JoinRoomByAddressView_Night_1_en",20511,], +["features.startchat.impl.joinbyaddress_JoinRoomByAddressView_Day_2_en","features.startchat.impl.joinbyaddress_JoinRoomByAddressView_Night_2_en",20511,], +["features.startchat.impl.joinbyaddress_JoinRoomByAddressView_Day_3_en","features.startchat.impl.joinbyaddress_JoinRoomByAddressView_Night_3_en",20511,], +["features.startchat.impl.joinbyaddress_JoinRoomByAddressView_Day_4_en","features.startchat.impl.joinbyaddress_JoinRoomByAddressView_Night_4_en",20511,], +["features.startchat.impl.joinbyaddress_JoinRoomByAddressView_Day_5_en","features.startchat.impl.joinbyaddress_JoinRoomByAddressView_Night_5_en",20511,], ["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",20504,], -["features.joinroom.impl_JoinRoomView_Day_11_en","features.joinroom.impl_JoinRoomView_Night_11_en",20504,], -["features.joinroom.impl_JoinRoomView_Day_12_en","features.joinroom.impl_JoinRoomView_Night_12_en",20504,], -["features.joinroom.impl_JoinRoomView_Day_13_en","features.joinroom.impl_JoinRoomView_Night_13_en",20504,], -["features.joinroom.impl_JoinRoomView_Day_14_en","features.joinroom.impl_JoinRoomView_Night_14_en",20504,], -["features.joinroom.impl_JoinRoomView_Day_15_en","features.joinroom.impl_JoinRoomView_Night_15_en",20504,], -["features.joinroom.impl_JoinRoomView_Day_16_en","features.joinroom.impl_JoinRoomView_Night_16_en",20504,], -["features.joinroom.impl_JoinRoomView_Day_1_en","features.joinroom.impl_JoinRoomView_Night_1_en",20504,], -["features.joinroom.impl_JoinRoomView_Day_2_en","features.joinroom.impl_JoinRoomView_Night_2_en",20504,], -["features.joinroom.impl_JoinRoomView_Day_3_en","features.joinroom.impl_JoinRoomView_Night_3_en",20504,], -["features.joinroom.impl_JoinRoomView_Day_4_en","features.joinroom.impl_JoinRoomView_Night_4_en",20504,], -["features.joinroom.impl_JoinRoomView_Day_5_en","features.joinroom.impl_JoinRoomView_Night_5_en",20504,], -["features.joinroom.impl_JoinRoomView_Day_6_en","features.joinroom.impl_JoinRoomView_Night_6_en",20504,], -["features.joinroom.impl_JoinRoomView_Day_7_en","features.joinroom.impl_JoinRoomView_Night_7_en",20504,], -["features.joinroom.impl_JoinRoomView_Day_8_en","features.joinroom.impl_JoinRoomView_Night_8_en",20504,], -["features.joinroom.impl_JoinRoomView_Day_9_en","features.joinroom.impl_JoinRoomView_Night_9_en",20504,], -["features.knockrequests.impl.banner_KnockRequestsBannerView_Day_0_en","features.knockrequests.impl.banner_KnockRequestsBannerView_Night_0_en",20504,], -["features.knockrequests.impl.banner_KnockRequestsBannerView_Day_1_en","features.knockrequests.impl.banner_KnockRequestsBannerView_Night_1_en",20504,], -["features.knockrequests.impl.banner_KnockRequestsBannerView_Day_2_en","features.knockrequests.impl.banner_KnockRequestsBannerView_Night_2_en",20504,], -["features.knockrequests.impl.banner_KnockRequestsBannerView_Day_3_en","features.knockrequests.impl.banner_KnockRequestsBannerView_Night_3_en",20504,], -["features.knockrequests.impl.banner_KnockRequestsBannerView_Day_4_en","features.knockrequests.impl.banner_KnockRequestsBannerView_Night_4_en",20504,], -["features.knockrequests.impl.banner_KnockRequestsBannerView_Day_5_en","features.knockrequests.impl.banner_KnockRequestsBannerView_Night_5_en",20504,], -["features.knockrequests.impl.banner_KnockRequestsBannerView_Day_6_en","features.knockrequests.impl.banner_KnockRequestsBannerView_Night_6_en",20504,], -["features.knockrequests.impl.list_KnockRequestsListView_Day_0_en","features.knockrequests.impl.list_KnockRequestsListView_Night_0_en",20504,], -["features.knockrequests.impl.list_KnockRequestsListView_Day_10_en","features.knockrequests.impl.list_KnockRequestsListView_Night_10_en",20504,], -["features.knockrequests.impl.list_KnockRequestsListView_Day_1_en","features.knockrequests.impl.list_KnockRequestsListView_Night_1_en",20504,], -["features.knockrequests.impl.list_KnockRequestsListView_Day_2_en","features.knockrequests.impl.list_KnockRequestsListView_Night_2_en",20504,], -["features.knockrequests.impl.list_KnockRequestsListView_Day_3_en","features.knockrequests.impl.list_KnockRequestsListView_Night_3_en",20504,], -["features.knockrequests.impl.list_KnockRequestsListView_Day_4_en","features.knockrequests.impl.list_KnockRequestsListView_Night_4_en",20504,], -["features.knockrequests.impl.list_KnockRequestsListView_Day_5_en","features.knockrequests.impl.list_KnockRequestsListView_Night_5_en",20504,], -["features.knockrequests.impl.list_KnockRequestsListView_Day_6_en","features.knockrequests.impl.list_KnockRequestsListView_Night_6_en",20504,], -["features.knockrequests.impl.list_KnockRequestsListView_Day_7_en","features.knockrequests.impl.list_KnockRequestsListView_Night_7_en",20504,], -["features.knockrequests.impl.list_KnockRequestsListView_Day_8_en","features.knockrequests.impl.list_KnockRequestsListView_Night_8_en",20504,], -["features.knockrequests.impl.list_KnockRequestsListView_Day_9_en","features.knockrequests.impl.list_KnockRequestsListView_Night_9_en",20504,], +["features.joinroom.impl_JoinRoomView_Day_10_en","features.joinroom.impl_JoinRoomView_Night_10_en",20511,], +["features.joinroom.impl_JoinRoomView_Day_11_en","features.joinroom.impl_JoinRoomView_Night_11_en",20511,], +["features.joinroom.impl_JoinRoomView_Day_12_en","features.joinroom.impl_JoinRoomView_Night_12_en",20511,], +["features.joinroom.impl_JoinRoomView_Day_13_en","features.joinroom.impl_JoinRoomView_Night_13_en",20511,], +["features.joinroom.impl_JoinRoomView_Day_14_en","features.joinroom.impl_JoinRoomView_Night_14_en",20511,], +["features.joinroom.impl_JoinRoomView_Day_15_en","features.joinroom.impl_JoinRoomView_Night_15_en",20511,], +["features.joinroom.impl_JoinRoomView_Day_16_en","features.joinroom.impl_JoinRoomView_Night_16_en",20511,], +["features.joinroom.impl_JoinRoomView_Day_1_en","features.joinroom.impl_JoinRoomView_Night_1_en",20511,], +["features.joinroom.impl_JoinRoomView_Day_2_en","features.joinroom.impl_JoinRoomView_Night_2_en",20511,], +["features.joinroom.impl_JoinRoomView_Day_3_en","features.joinroom.impl_JoinRoomView_Night_3_en",20511,], +["features.joinroom.impl_JoinRoomView_Day_4_en","features.joinroom.impl_JoinRoomView_Night_4_en",20511,], +["features.joinroom.impl_JoinRoomView_Day_5_en","features.joinroom.impl_JoinRoomView_Night_5_en",20511,], +["features.joinroom.impl_JoinRoomView_Day_6_en","features.joinroom.impl_JoinRoomView_Night_6_en",20511,], +["features.joinroom.impl_JoinRoomView_Day_7_en","features.joinroom.impl_JoinRoomView_Night_7_en",20511,], +["features.joinroom.impl_JoinRoomView_Day_8_en","features.joinroom.impl_JoinRoomView_Night_8_en",20511,], +["features.joinroom.impl_JoinRoomView_Day_9_en","features.joinroom.impl_JoinRoomView_Night_9_en",20511,], +["features.knockrequests.impl.banner_KnockRequestsBannerView_Day_0_en","features.knockrequests.impl.banner_KnockRequestsBannerView_Night_0_en",20511,], +["features.knockrequests.impl.banner_KnockRequestsBannerView_Day_1_en","features.knockrequests.impl.banner_KnockRequestsBannerView_Night_1_en",20511,], +["features.knockrequests.impl.banner_KnockRequestsBannerView_Day_2_en","features.knockrequests.impl.banner_KnockRequestsBannerView_Night_2_en",20511,], +["features.knockrequests.impl.banner_KnockRequestsBannerView_Day_3_en","features.knockrequests.impl.banner_KnockRequestsBannerView_Night_3_en",20511,], +["features.knockrequests.impl.banner_KnockRequestsBannerView_Day_4_en","features.knockrequests.impl.banner_KnockRequestsBannerView_Night_4_en",20511,], +["features.knockrequests.impl.banner_KnockRequestsBannerView_Day_5_en","features.knockrequests.impl.banner_KnockRequestsBannerView_Night_5_en",20511,], +["features.knockrequests.impl.banner_KnockRequestsBannerView_Day_6_en","features.knockrequests.impl.banner_KnockRequestsBannerView_Night_6_en",20511,], +["features.knockrequests.impl.list_KnockRequestsListView_Day_0_en","features.knockrequests.impl.list_KnockRequestsListView_Night_0_en",20511,], +["features.knockrequests.impl.list_KnockRequestsListView_Day_10_en","features.knockrequests.impl.list_KnockRequestsListView_Night_10_en",20511,], +["features.knockrequests.impl.list_KnockRequestsListView_Day_1_en","features.knockrequests.impl.list_KnockRequestsListView_Night_1_en",20511,], +["features.knockrequests.impl.list_KnockRequestsListView_Day_2_en","features.knockrequests.impl.list_KnockRequestsListView_Night_2_en",20511,], +["features.knockrequests.impl.list_KnockRequestsListView_Day_3_en","features.knockrequests.impl.list_KnockRequestsListView_Night_3_en",20511,], +["features.knockrequests.impl.list_KnockRequestsListView_Day_4_en","features.knockrequests.impl.list_KnockRequestsListView_Night_4_en",20511,], +["features.knockrequests.impl.list_KnockRequestsListView_Day_5_en","features.knockrequests.impl.list_KnockRequestsListView_Night_5_en",20511,], +["features.knockrequests.impl.list_KnockRequestsListView_Day_6_en","features.knockrequests.impl.list_KnockRequestsListView_Night_6_en",20511,], +["features.knockrequests.impl.list_KnockRequestsListView_Day_7_en","features.knockrequests.impl.list_KnockRequestsListView_Night_7_en",20511,], +["features.knockrequests.impl.list_KnockRequestsListView_Day_8_en","features.knockrequests.impl.list_KnockRequestsListView_Night_8_en",20511,], +["features.knockrequests.impl.list_KnockRequestsListView_Day_9_en","features.knockrequests.impl.list_KnockRequestsListView_Night_9_en",20511,], ["libraries.designsystem.components_LabelledCheckbox_Toggles_en","",0,], -["features.preferences.impl.labs_LabsView_Day_0_en","features.preferences.impl.labs_LabsView_Night_0_en",20504,], -["features.preferences.impl.labs_LabsView_Day_1_en","features.preferences.impl.labs_LabsView_Night_1_en",20504,], +["features.preferences.impl.labs_LabsView_Day_0_en","features.preferences.impl.labs_LabsView_Night_0_en",20511,], +["features.preferences.impl.labs_LabsView_Day_1_en","features.preferences.impl.labs_LabsView_Night_1_en",20511,], ["features.leaveroom.impl_LeaveRoomView_Day_0_en","features.leaveroom.impl_LeaveRoomView_Night_0_en",0,], -["features.leaveroom.impl_LeaveRoomView_Day_1_en","features.leaveroom.impl_LeaveRoomView_Night_1_en",20504,], -["features.leaveroom.impl_LeaveRoomView_Day_2_en","features.leaveroom.impl_LeaveRoomView_Night_2_en",20504,], -["features.leaveroom.impl_LeaveRoomView_Day_3_en","features.leaveroom.impl_LeaveRoomView_Night_3_en",20504,], -["features.leaveroom.impl_LeaveRoomView_Day_4_en","features.leaveroom.impl_LeaveRoomView_Night_4_en",20504,], -["features.leaveroom.impl_LeaveRoomView_Day_5_en","features.leaveroom.impl_LeaveRoomView_Night_5_en",20504,], -["features.leaveroom.impl_LeaveRoomView_Day_6_en","features.leaveroom.impl_LeaveRoomView_Night_6_en",20504,], -["features.leaveroom.impl_LeaveRoomView_Day_7_en","features.leaveroom.impl_LeaveRoomView_Night_7_en",20504,], -["features.space.impl.leave_LeaveSpaceView_Day_0_en","features.space.impl.leave_LeaveSpaceView_Night_0_en",20504,], -["features.space.impl.leave_LeaveSpaceView_Day_10_en","features.space.impl.leave_LeaveSpaceView_Night_10_en",20504,], -["features.space.impl.leave_LeaveSpaceView_Day_1_en","features.space.impl.leave_LeaveSpaceView_Night_1_en",20504,], -["features.space.impl.leave_LeaveSpaceView_Day_2_en","features.space.impl.leave_LeaveSpaceView_Night_2_en",20504,], -["features.space.impl.leave_LeaveSpaceView_Day_3_en","features.space.impl.leave_LeaveSpaceView_Night_3_en",20504,], -["features.space.impl.leave_LeaveSpaceView_Day_4_en","features.space.impl.leave_LeaveSpaceView_Night_4_en",20504,], -["features.space.impl.leave_LeaveSpaceView_Day_5_en","features.space.impl.leave_LeaveSpaceView_Night_5_en",20504,], -["features.space.impl.leave_LeaveSpaceView_Day_6_en","features.space.impl.leave_LeaveSpaceView_Night_6_en",20504,], -["features.space.impl.leave_LeaveSpaceView_Day_7_en","features.space.impl.leave_LeaveSpaceView_Night_7_en",20504,], -["features.space.impl.leave_LeaveSpaceView_Day_8_en","features.space.impl.leave_LeaveSpaceView_Night_8_en",20504,], -["features.space.impl.leave_LeaveSpaceView_Day_9_en","features.space.impl.leave_LeaveSpaceView_Night_9_en",20504,], +["features.leaveroom.impl_LeaveRoomView_Day_1_en","features.leaveroom.impl_LeaveRoomView_Night_1_en",20511,], +["features.leaveroom.impl_LeaveRoomView_Day_2_en","features.leaveroom.impl_LeaveRoomView_Night_2_en",20511,], +["features.leaveroom.impl_LeaveRoomView_Day_3_en","features.leaveroom.impl_LeaveRoomView_Night_3_en",20511,], +["features.leaveroom.impl_LeaveRoomView_Day_4_en","features.leaveroom.impl_LeaveRoomView_Night_4_en",20511,], +["features.leaveroom.impl_LeaveRoomView_Day_5_en","features.leaveroom.impl_LeaveRoomView_Night_5_en",20511,], +["features.leaveroom.impl_LeaveRoomView_Day_6_en","features.leaveroom.impl_LeaveRoomView_Night_6_en",20511,], +["features.leaveroom.impl_LeaveRoomView_Day_7_en","features.leaveroom.impl_LeaveRoomView_Night_7_en",20511,], +["features.space.impl.leave_LeaveSpaceView_Day_0_en","features.space.impl.leave_LeaveSpaceView_Night_0_en",20511,], +["features.space.impl.leave_LeaveSpaceView_Day_10_en","features.space.impl.leave_LeaveSpaceView_Night_10_en",20511,], +["features.space.impl.leave_LeaveSpaceView_Day_1_en","features.space.impl.leave_LeaveSpaceView_Night_1_en",20511,], +["features.space.impl.leave_LeaveSpaceView_Day_2_en","features.space.impl.leave_LeaveSpaceView_Night_2_en",20511,], +["features.space.impl.leave_LeaveSpaceView_Day_3_en","features.space.impl.leave_LeaveSpaceView_Night_3_en",20511,], +["features.space.impl.leave_LeaveSpaceView_Day_4_en","features.space.impl.leave_LeaveSpaceView_Night_4_en",20511,], +["features.space.impl.leave_LeaveSpaceView_Day_5_en","features.space.impl.leave_LeaveSpaceView_Night_5_en",20511,], +["features.space.impl.leave_LeaveSpaceView_Day_6_en","features.space.impl.leave_LeaveSpaceView_Night_6_en",20511,], +["features.space.impl.leave_LeaveSpaceView_Day_7_en","features.space.impl.leave_LeaveSpaceView_Night_7_en",20511,], +["features.space.impl.leave_LeaveSpaceView_Day_8_en","features.space.impl.leave_LeaveSpaceView_Night_8_en",20511,], +["features.space.impl.leave_LeaveSpaceView_Day_9_en","features.space.impl.leave_LeaveSpaceView_Night_9_en",20511,], ["libraries.designsystem.background_LightGradientBackground_Day_0_en","libraries.designsystem.background_LightGradientBackground_Night_0_en",0,], ["libraries.designsystem.theme.components_LinearProgressIndicator_Progress_Indicators_en","",0,], -["features.linknewdevice.impl.screens.root_LinkNewDeviceRootView_Day_0_en","features.linknewdevice.impl.screens.root_LinkNewDeviceRootView_Night_0_en",20504,], -["features.linknewdevice.impl.screens.root_LinkNewDeviceRootView_Day_1_en","features.linknewdevice.impl.screens.root_LinkNewDeviceRootView_Night_1_en",20504,], -["features.linknewdevice.impl.screens.root_LinkNewDeviceRootView_Day_2_en","features.linknewdevice.impl.screens.root_LinkNewDeviceRootView_Night_2_en",20504,], -["features.linknewdevice.impl.screens.root_LinkNewDeviceRootView_Day_3_en","features.linknewdevice.impl.screens.root_LinkNewDeviceRootView_Night_3_en",20504,], -["features.linknewdevice.impl.screens.root_LinkNewDeviceRootView_Day_4_en","features.linknewdevice.impl.screens.root_LinkNewDeviceRootView_Night_4_en",20504,], -["features.linknewdevice.impl.screens.root_LinkNewDeviceRootView_Day_5_en","features.linknewdevice.impl.screens.root_LinkNewDeviceRootView_Night_5_en",20504,], +["features.linknewdevice.impl.screens.root_LinkNewDeviceRootView_Day_0_en","features.linknewdevice.impl.screens.root_LinkNewDeviceRootView_Night_0_en",20511,], +["features.linknewdevice.impl.screens.root_LinkNewDeviceRootView_Day_1_en","features.linknewdevice.impl.screens.root_LinkNewDeviceRootView_Night_1_en",20511,], +["features.linknewdevice.impl.screens.root_LinkNewDeviceRootView_Day_2_en","features.linknewdevice.impl.screens.root_LinkNewDeviceRootView_Night_2_en",20511,], +["features.linknewdevice.impl.screens.root_LinkNewDeviceRootView_Day_3_en","features.linknewdevice.impl.screens.root_LinkNewDeviceRootView_Night_3_en",20511,], +["features.linknewdevice.impl.screens.root_LinkNewDeviceRootView_Day_4_en","features.linknewdevice.impl.screens.root_LinkNewDeviceRootView_Night_4_en",20511,], +["features.linknewdevice.impl.screens.root_LinkNewDeviceRootView_Day_5_en","features.linknewdevice.impl.screens.root_LinkNewDeviceRootView_Night_5_en",20511,], ["features.messages.impl.link_LinkView_Day_0_en","features.messages.impl.link_LinkView_Night_0_en",0,], -["features.messages.impl.link_LinkView_Day_1_en","features.messages.impl.link_LinkView_Night_1_en",20504,], +["features.messages.impl.link_LinkView_Day_1_en","features.messages.impl.link_LinkView_Night_1_en",20511,], ["libraries.designsystem.components.dialogs_ListDialogContent_Dialogs_en","",0,], ["libraries.designsystem.components.dialogs_ListDialog_Day_0_en","libraries.designsystem.components.dialogs_ListDialog_Night_0_en",0,], ["libraries.designsystem.theme.components_ListItemPrimaryActionWithIcon_List_item_-_Primary_action_&_Icon_List_items_en","",0,], @@ -595,41 +598,41 @@ 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",20504,], -["features.lockscreen.impl.settings_LockScreenSettingsView_Day_0_en","features.lockscreen.impl.settings_LockScreenSettingsView_Night_0_en",20504,], -["features.lockscreen.impl.settings_LockScreenSettingsView_Day_1_en","features.lockscreen.impl.settings_LockScreenSettingsView_Night_1_en",20504,], -["features.lockscreen.impl.settings_LockScreenSettingsView_Day_2_en","features.lockscreen.impl.settings_LockScreenSettingsView_Night_2_en",20504,], +["appnav.room.joined_LoadingRoomNodeView_Day_1_en","appnav.room.joined_LoadingRoomNodeView_Night_1_en",20511,], +["features.lockscreen.impl.settings_LockScreenSettingsView_Day_0_en","features.lockscreen.impl.settings_LockScreenSettingsView_Night_0_en",20511,], +["features.lockscreen.impl.settings_LockScreenSettingsView_Day_1_en","features.lockscreen.impl.settings_LockScreenSettingsView_Night_1_en",20511,], +["features.lockscreen.impl.settings_LockScreenSettingsView_Day_2_en","features.lockscreen.impl.settings_LockScreenSettingsView_Night_2_en",20511,], ["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",20504,], -["appnav.loggedin_LoggedInView_Day_2_en","appnav.loggedin_LoggedInView_Night_2_en",20504,], -["appnav.loggedin_LoggedInView_Day_3_en","appnav.loggedin_LoggedInView_Night_3_en",20504,], -["features.login.impl.login_LoginModeView_Day_0_en","features.login.impl.login_LoginModeView_Night_0_en",20504,], -["features.login.impl.login_LoginModeView_Day_1_en","features.login.impl.login_LoginModeView_Night_1_en",20504,], -["features.login.impl.login_LoginModeView_Day_2_en","features.login.impl.login_LoginModeView_Night_2_en",20504,], -["features.login.impl.login_LoginModeView_Day_3_en","features.login.impl.login_LoginModeView_Night_3_en",20504,], -["features.login.impl.login_LoginModeView_Day_4_en","features.login.impl.login_LoginModeView_Night_4_en",20504,], -["features.login.impl.login_LoginModeView_Day_5_en","features.login.impl.login_LoginModeView_Night_5_en",20504,], -["features.login.impl.login_LoginModeView_Day_6_en","features.login.impl.login_LoginModeView_Night_6_en",20504,], -["features.login.impl.screens.loginpassword_LoginPasswordView_Day_0_en","features.login.impl.screens.loginpassword_LoginPasswordView_Night_0_en",20504,], -["features.login.impl.screens.loginpassword_LoginPasswordView_Day_1_en","features.login.impl.screens.loginpassword_LoginPasswordView_Night_1_en",20504,], -["features.login.impl.screens.loginpassword_LoginPasswordView_Day_2_en","features.login.impl.screens.loginpassword_LoginPasswordView_Night_2_en",20504,], -["features.logout.impl_LogoutView_Day_0_en","features.logout.impl_LogoutView_Night_0_en",20504,], -["features.logout.impl_LogoutView_Day_10_en","features.logout.impl_LogoutView_Night_10_en",20504,], -["features.logout.impl_LogoutView_Day_11_en","features.logout.impl_LogoutView_Night_11_en",20504,], -["features.logout.impl_LogoutView_Day_1_en","features.logout.impl_LogoutView_Night_1_en",20504,], -["features.logout.impl_LogoutView_Day_2_en","features.logout.impl_LogoutView_Night_2_en",20504,], -["features.logout.impl_LogoutView_Day_3_en","features.logout.impl_LogoutView_Night_3_en",20504,], -["features.logout.impl_LogoutView_Day_4_en","features.logout.impl_LogoutView_Night_4_en",20504,], -["features.logout.impl_LogoutView_Day_5_en","features.logout.impl_LogoutView_Night_5_en",20504,], -["features.logout.impl_LogoutView_Day_6_en","features.logout.impl_LogoutView_Night_6_en",20504,], -["features.logout.impl_LogoutView_Day_7_en","features.logout.impl_LogoutView_Night_7_en",20504,], -["features.logout.impl_LogoutView_Day_8_en","features.logout.impl_LogoutView_Night_8_en",20504,], -["features.logout.impl_LogoutView_Day_9_en","features.logout.impl_LogoutView_Night_9_en",20504,], +["appnav.loggedin_LoggedInView_Day_1_en","appnav.loggedin_LoggedInView_Night_1_en",20511,], +["appnav.loggedin_LoggedInView_Day_2_en","appnav.loggedin_LoggedInView_Night_2_en",20511,], +["appnav.loggedin_LoggedInView_Day_3_en","appnav.loggedin_LoggedInView_Night_3_en",20511,], +["features.login.impl.login_LoginModeView_Day_0_en","features.login.impl.login_LoginModeView_Night_0_en",20511,], +["features.login.impl.login_LoginModeView_Day_1_en","features.login.impl.login_LoginModeView_Night_1_en",20511,], +["features.login.impl.login_LoginModeView_Day_2_en","features.login.impl.login_LoginModeView_Night_2_en",20511,], +["features.login.impl.login_LoginModeView_Day_3_en","features.login.impl.login_LoginModeView_Night_3_en",20511,], +["features.login.impl.login_LoginModeView_Day_4_en","features.login.impl.login_LoginModeView_Night_4_en",20511,], +["features.login.impl.login_LoginModeView_Day_5_en","features.login.impl.login_LoginModeView_Night_5_en",20511,], +["features.login.impl.login_LoginModeView_Day_6_en","features.login.impl.login_LoginModeView_Night_6_en",20511,], +["features.login.impl.screens.loginpassword_LoginPasswordView_Day_0_en","features.login.impl.screens.loginpassword_LoginPasswordView_Night_0_en",20511,], +["features.login.impl.screens.loginpassword_LoginPasswordView_Day_1_en","features.login.impl.screens.loginpassword_LoginPasswordView_Night_1_en",20511,], +["features.login.impl.screens.loginpassword_LoginPasswordView_Day_2_en","features.login.impl.screens.loginpassword_LoginPasswordView_Night_2_en",20511,], +["features.logout.impl_LogoutView_Day_0_en","features.logout.impl_LogoutView_Night_0_en",20511,], +["features.logout.impl_LogoutView_Day_10_en","features.logout.impl_LogoutView_Night_10_en",20511,], +["features.logout.impl_LogoutView_Day_11_en","features.logout.impl_LogoutView_Night_11_en",20511,], +["features.logout.impl_LogoutView_Day_1_en","features.logout.impl_LogoutView_Night_1_en",20511,], +["features.logout.impl_LogoutView_Day_2_en","features.logout.impl_LogoutView_Night_2_en",20511,], +["features.logout.impl_LogoutView_Day_3_en","features.logout.impl_LogoutView_Night_3_en",20511,], +["features.logout.impl_LogoutView_Day_4_en","features.logout.impl_LogoutView_Night_4_en",20511,], +["features.logout.impl_LogoutView_Day_5_en","features.logout.impl_LogoutView_Night_5_en",20511,], +["features.logout.impl_LogoutView_Day_6_en","features.logout.impl_LogoutView_Night_6_en",20511,], +["features.logout.impl_LogoutView_Day_7_en","features.logout.impl_LogoutView_Night_7_en",20511,], +["features.logout.impl_LogoutView_Day_8_en","features.logout.impl_LogoutView_Night_8_en",20511,], +["features.logout.impl_LogoutView_Day_9_en","features.logout.impl_LogoutView_Night_9_en",20511,], ["libraries.designsystem.components.button_MainActionButton_Buttons_en","",0,], -["features.securityandprivacy.impl.manageauthorizedspaces_ManageAuthorizedSpacesView_Day_0_en","features.securityandprivacy.impl.manageauthorizedspaces_ManageAuthorizedSpacesView_Night_0_en",20504,], -["features.securityandprivacy.impl.manageauthorizedspaces_ManageAuthorizedSpacesView_Day_1_en","features.securityandprivacy.impl.manageauthorizedspaces_ManageAuthorizedSpacesView_Night_1_en",20504,], -["features.securityandprivacy.impl.manageauthorizedspaces_ManageAuthorizedSpacesView_Day_2_en","features.securityandprivacy.impl.manageauthorizedspaces_ManageAuthorizedSpacesView_Night_2_en",20504,], -["libraries.textcomposer_MarkdownTextComposerEdit_Day_0_en","libraries.textcomposer_MarkdownTextComposerEdit_Night_0_en",20504,], +["features.securityandprivacy.impl.manageauthorizedspaces_ManageAuthorizedSpacesView_Day_0_en","features.securityandprivacy.impl.manageauthorizedspaces_ManageAuthorizedSpacesView_Night_0_en",20511,], +["features.securityandprivacy.impl.manageauthorizedspaces_ManageAuthorizedSpacesView_Day_1_en","features.securityandprivacy.impl.manageauthorizedspaces_ManageAuthorizedSpacesView_Night_1_en",20511,], +["features.securityandprivacy.impl.manageauthorizedspaces_ManageAuthorizedSpacesView_Day_2_en","features.securityandprivacy.impl.manageauthorizedspaces_ManageAuthorizedSpacesView_Night_2_en",20511,], +["libraries.textcomposer_MarkdownTextComposerEdit_Day_0_en","libraries.textcomposer_MarkdownTextComposerEdit_Night_0_en",20511,], ["libraries.textcomposer.components.markdown_MarkdownTextInput_Day_0_en","libraries.textcomposer.components.markdown_MarkdownTextInput_Night_0_en",0,], ["libraries.designsystem.atomic.atoms_MatrixBadgeAtomInfo_Day_0_en","libraries.designsystem.atomic.atoms_MatrixBadgeAtomInfo_Night_0_en",0,], ["libraries.designsystem.atomic.atoms_MatrixBadgeAtomNegative_Day_0_en","libraries.designsystem.atomic.atoms_MatrixBadgeAtomNegative_Night_0_en",0,], @@ -643,22 +646,22 @@ export const screenshots = [ ["libraries.matrix.ui.components_MatrixUserRow_Day_1_en","libraries.matrix.ui.components_MatrixUserRow_Night_1_en",0,], ["libraries.mediaviewer.impl.local.audio_MediaAudioView_Day_0_en","libraries.mediaviewer.impl.local.audio_MediaAudioView_Night_0_en",0,], ["libraries.mediaviewer.impl.local.audio_MediaAudioView_Day_1_en","libraries.mediaviewer.impl.local.audio_MediaAudioView_Night_1_en",0,], -["libraries.mediaviewer.impl.details_MediaDeleteConfirmationBottomSheet_Day_0_en","libraries.mediaviewer.impl.details_MediaDeleteConfirmationBottomSheet_Night_0_en",20504,], -["libraries.mediaviewer.impl.details_MediaDetailsBottomSheet_Day_0_en","libraries.mediaviewer.impl.details_MediaDetailsBottomSheet_Night_0_en",20504,], +["libraries.mediaviewer.impl.details_MediaDeleteConfirmationBottomSheet_Day_0_en","libraries.mediaviewer.impl.details_MediaDeleteConfirmationBottomSheet_Night_0_en",20511,], +["libraries.mediaviewer.impl.details_MediaDetailsBottomSheet_Day_0_en","libraries.mediaviewer.impl.details_MediaDetailsBottomSheet_Night_0_en",20511,], ["libraries.mediaviewer.impl.local.file_MediaFileView_Day_0_en","libraries.mediaviewer.impl.local.file_MediaFileView_Night_0_en",0,], -["libraries.mediaviewer.impl.gallery_MediaGalleryView_Day_0_en","libraries.mediaviewer.impl.gallery_MediaGalleryView_Night_0_en",20504,], -["libraries.mediaviewer.impl.gallery_MediaGalleryView_Day_10_en","libraries.mediaviewer.impl.gallery_MediaGalleryView_Night_10_en",20504,], -["libraries.mediaviewer.impl.gallery_MediaGalleryView_Day_11_en","libraries.mediaviewer.impl.gallery_MediaGalleryView_Night_11_en",20504,], -["libraries.mediaviewer.impl.gallery_MediaGalleryView_Day_12_en","libraries.mediaviewer.impl.gallery_MediaGalleryView_Night_12_en",20504,], -["libraries.mediaviewer.impl.gallery_MediaGalleryView_Day_1_en","libraries.mediaviewer.impl.gallery_MediaGalleryView_Night_1_en",20504,], -["libraries.mediaviewer.impl.gallery_MediaGalleryView_Day_2_en","libraries.mediaviewer.impl.gallery_MediaGalleryView_Night_2_en",20504,], -["libraries.mediaviewer.impl.gallery_MediaGalleryView_Day_3_en","libraries.mediaviewer.impl.gallery_MediaGalleryView_Night_3_en",20504,], -["libraries.mediaviewer.impl.gallery_MediaGalleryView_Day_4_en","libraries.mediaviewer.impl.gallery_MediaGalleryView_Night_4_en",20504,], -["libraries.mediaviewer.impl.gallery_MediaGalleryView_Day_5_en","libraries.mediaviewer.impl.gallery_MediaGalleryView_Night_5_en",20504,], -["libraries.mediaviewer.impl.gallery_MediaGalleryView_Day_6_en","libraries.mediaviewer.impl.gallery_MediaGalleryView_Night_6_en",20504,], -["libraries.mediaviewer.impl.gallery_MediaGalleryView_Day_7_en","libraries.mediaviewer.impl.gallery_MediaGalleryView_Night_7_en",20504,], -["libraries.mediaviewer.impl.gallery_MediaGalleryView_Day_8_en","libraries.mediaviewer.impl.gallery_MediaGalleryView_Night_8_en",20504,], -["libraries.mediaviewer.impl.gallery_MediaGalleryView_Day_9_en","libraries.mediaviewer.impl.gallery_MediaGalleryView_Night_9_en",20504,], +["libraries.mediaviewer.impl.gallery_MediaGalleryView_Day_0_en","libraries.mediaviewer.impl.gallery_MediaGalleryView_Night_0_en",20511,], +["libraries.mediaviewer.impl.gallery_MediaGalleryView_Day_10_en","libraries.mediaviewer.impl.gallery_MediaGalleryView_Night_10_en",20511,], +["libraries.mediaviewer.impl.gallery_MediaGalleryView_Day_11_en","libraries.mediaviewer.impl.gallery_MediaGalleryView_Night_11_en",20511,], +["libraries.mediaviewer.impl.gallery_MediaGalleryView_Day_12_en","libraries.mediaviewer.impl.gallery_MediaGalleryView_Night_12_en",20511,], +["libraries.mediaviewer.impl.gallery_MediaGalleryView_Day_1_en","libraries.mediaviewer.impl.gallery_MediaGalleryView_Night_1_en",20511,], +["libraries.mediaviewer.impl.gallery_MediaGalleryView_Day_2_en","libraries.mediaviewer.impl.gallery_MediaGalleryView_Night_2_en",20511,], +["libraries.mediaviewer.impl.gallery_MediaGalleryView_Day_3_en","libraries.mediaviewer.impl.gallery_MediaGalleryView_Night_3_en",20511,], +["libraries.mediaviewer.impl.gallery_MediaGalleryView_Day_4_en","libraries.mediaviewer.impl.gallery_MediaGalleryView_Night_4_en",20511,], +["libraries.mediaviewer.impl.gallery_MediaGalleryView_Day_5_en","libraries.mediaviewer.impl.gallery_MediaGalleryView_Night_5_en",20511,], +["libraries.mediaviewer.impl.gallery_MediaGalleryView_Day_6_en","libraries.mediaviewer.impl.gallery_MediaGalleryView_Night_6_en",20511,], +["libraries.mediaviewer.impl.gallery_MediaGalleryView_Day_7_en","libraries.mediaviewer.impl.gallery_MediaGalleryView_Night_7_en",20511,], +["libraries.mediaviewer.impl.gallery_MediaGalleryView_Day_8_en","libraries.mediaviewer.impl.gallery_MediaGalleryView_Night_8_en",20511,], +["libraries.mediaviewer.impl.gallery_MediaGalleryView_Day_9_en","libraries.mediaviewer.impl.gallery_MediaGalleryView_Night_9_en",20511,], ["libraries.mediaviewer.impl.local.image_MediaImageView_Day_0_en","libraries.mediaviewer.impl.local.image_MediaImageView_Night_0_en",0,], ["libraries.mediaviewer.impl.local.player_MediaPlayerControllerView_Day_0_en","libraries.mediaviewer.impl.local.player_MediaPlayerControllerView_Night_0_en",0,], ["libraries.mediaviewer.impl.local.player_MediaPlayerControllerView_Day_1_en","libraries.mediaviewer.impl.local.player_MediaPlayerControllerView_Night_1_en",0,], @@ -666,14 +669,14 @@ export const screenshots = [ ["libraries.mediaviewer.impl.local.video_MediaVideoView_Day_0_en","libraries.mediaviewer.impl.local.video_MediaVideoView_Night_0_en",0,], ["libraries.mediaviewer.impl.viewer_MediaViewerView_0_en","",0,], ["libraries.mediaviewer.impl.viewer_MediaViewerView_10_en","",0,], -["libraries.mediaviewer.impl.viewer_MediaViewerView_11_en","",20504,], -["libraries.mediaviewer.impl.viewer_MediaViewerView_12_en","",20504,], +["libraries.mediaviewer.impl.viewer_MediaViewerView_11_en","",20511,], +["libraries.mediaviewer.impl.viewer_MediaViewerView_12_en","",20511,], ["libraries.mediaviewer.impl.viewer_MediaViewerView_13_en","",0,], -["libraries.mediaviewer.impl.viewer_MediaViewerView_14_en","",20504,], +["libraries.mediaviewer.impl.viewer_MediaViewerView_14_en","",20511,], ["libraries.mediaviewer.impl.viewer_MediaViewerView_15_en","",0,], ["libraries.mediaviewer.impl.viewer_MediaViewerView_16_en","",0,], ["libraries.mediaviewer.impl.viewer_MediaViewerView_1_en","",0,], -["libraries.mediaviewer.impl.viewer_MediaViewerView_2_en","",20504,], +["libraries.mediaviewer.impl.viewer_MediaViewerView_2_en","",20511,], ["libraries.mediaviewer.impl.viewer_MediaViewerView_3_en","",0,], ["libraries.mediaviewer.impl.viewer_MediaViewerView_4_en","",0,], ["libraries.mediaviewer.impl.viewer_MediaViewerView_5_en","",0,], @@ -687,7 +690,7 @@ export const screenshots = [ ["libraries.textcomposer.mentions_MentionSpanTheme_Day_0_en","libraries.textcomposer.mentions_MentionSpanTheme_Night_0_en",0,], ["libraries.designsystem.theme.components.previews_Menu_Menus_en","",0,], ["features.messages.impl.messagecomposer_MessageComposerViewVoice_Day_0_en","features.messages.impl.messagecomposer_MessageComposerViewVoice_Night_0_en",0,], -["features.messages.impl.messagecomposer_MessageComposerView_Day_0_en","features.messages.impl.messagecomposer_MessageComposerView_Night_0_en",20504,], +["features.messages.impl.messagecomposer_MessageComposerView_Day_0_en","features.messages.impl.messagecomposer_MessageComposerView_Night_0_en",20511,], ["features.messages.impl.timeline.components_MessageEventBubble_Day_0_en","features.messages.impl.timeline.components_MessageEventBubble_Night_0_en",0,], ["features.messages.impl.timeline.components_MessageEventBubble_Day_1_en","features.messages.impl.timeline.components_MessageEventBubble_Night_1_en",0,], ["features.messages.impl.timeline.components_MessageEventBubble_Day_2_en","features.messages.impl.timeline.components_MessageEventBubble_Night_2_en",0,], @@ -696,7 +699,7 @@ export const screenshots = [ ["features.messages.impl.timeline.components_MessageEventBubble_Day_5_en","features.messages.impl.timeline.components_MessageEventBubble_Night_5_en",0,], ["features.messages.impl.timeline.components_MessageEventBubble_Day_6_en","features.messages.impl.timeline.components_MessageEventBubble_Night_6_en",0,], ["features.messages.impl.timeline.components_MessageEventBubble_Day_7_en","features.messages.impl.timeline.components_MessageEventBubble_Night_7_en",0,], -["features.messages.impl.timeline.components_MessageShieldView_Day_0_en","features.messages.impl.timeline.components_MessageShieldView_Night_0_en",20504,], +["features.messages.impl.timeline.components_MessageShieldView_Day_0_en","features.messages.impl.timeline.components_MessageShieldView_Night_0_en",20511,], ["features.messages.impl.timeline.components_MessageStateEventContainer_Day_0_en","features.messages.impl.timeline.components_MessageStateEventContainer_Night_0_en",0,], ["features.messages.impl.timeline.components_MessagesReactionButtonAdd_Day_0_en","features.messages.impl.timeline.components_MessagesReactionButtonAdd_Night_0_en",0,], ["features.messages.impl.timeline.components_MessagesReactionButtonExtra_Day_0_en","features.messages.impl.timeline.components_MessagesReactionButtonExtra_Night_0_en",0,], @@ -705,23 +708,23 @@ export const screenshots = [ ["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_MessagesViewA11y_en","",0,], -["features.messages.impl.topbars_MessagesViewTopBar_Day_0_en","features.messages.impl.topbars_MessagesViewTopBar_Night_0_en",20504,], -["features.messages.impl.crypto.identity_MessagesViewWithIdentityChange_Day_0_en","features.messages.impl.crypto.identity_MessagesViewWithIdentityChange_Night_0_en",20504,], -["features.messages.impl.crypto.identity_MessagesViewWithIdentityChange_Day_1_en","features.messages.impl.crypto.identity_MessagesViewWithIdentityChange_Night_1_en",20504,], -["features.messages.impl.crypto.identity_MessagesViewWithIdentityChange_Day_2_en","features.messages.impl.crypto.identity_MessagesViewWithIdentityChange_Night_2_en",20504,], -["features.messages.impl_MessagesView_Day_0_en","features.messages.impl_MessagesView_Night_0_en",20504,], -["features.messages.impl_MessagesView_Day_10_en","features.messages.impl_MessagesView_Night_10_en",20504,], -["features.messages.impl_MessagesView_Day_1_en","features.messages.impl_MessagesView_Night_1_en",20504,], -["features.messages.impl_MessagesView_Day_2_en","features.messages.impl_MessagesView_Night_2_en",20504,], -["features.messages.impl_MessagesView_Day_3_en","features.messages.impl_MessagesView_Night_3_en",20504,], -["features.messages.impl_MessagesView_Day_4_en","features.messages.impl_MessagesView_Night_4_en",20504,], -["features.messages.impl_MessagesView_Day_5_en","features.messages.impl_MessagesView_Night_5_en",20504,], -["features.messages.impl_MessagesView_Day_6_en","features.messages.impl_MessagesView_Night_6_en",20504,], -["features.messages.impl_MessagesView_Day_7_en","features.messages.impl_MessagesView_Night_7_en",20504,], -["features.messages.impl_MessagesView_Day_8_en","features.messages.impl_MessagesView_Night_8_en",20504,], -["features.messages.impl_MessagesView_Day_9_en","features.messages.impl_MessagesView_Night_9_en",20504,], +["features.messages.impl.topbars_MessagesViewTopBar_Day_0_en","features.messages.impl.topbars_MessagesViewTopBar_Night_0_en",20511,], +["features.messages.impl.crypto.identity_MessagesViewWithIdentityChange_Day_0_en","features.messages.impl.crypto.identity_MessagesViewWithIdentityChange_Night_0_en",20511,], +["features.messages.impl.crypto.identity_MessagesViewWithIdentityChange_Day_1_en","features.messages.impl.crypto.identity_MessagesViewWithIdentityChange_Night_1_en",20511,], +["features.messages.impl.crypto.identity_MessagesViewWithIdentityChange_Day_2_en","features.messages.impl.crypto.identity_MessagesViewWithIdentityChange_Night_2_en",20511,], +["features.messages.impl_MessagesView_Day_0_en","features.messages.impl_MessagesView_Night_0_en",20511,], +["features.messages.impl_MessagesView_Day_10_en","features.messages.impl_MessagesView_Night_10_en",20511,], +["features.messages.impl_MessagesView_Day_1_en","features.messages.impl_MessagesView_Night_1_en",20511,], +["features.messages.impl_MessagesView_Day_2_en","features.messages.impl_MessagesView_Night_2_en",20511,], +["features.messages.impl_MessagesView_Day_3_en","features.messages.impl_MessagesView_Night_3_en",20511,], +["features.messages.impl_MessagesView_Day_4_en","features.messages.impl_MessagesView_Night_4_en",20511,], +["features.messages.impl_MessagesView_Day_5_en","features.messages.impl_MessagesView_Night_5_en",20511,], +["features.messages.impl_MessagesView_Day_6_en","features.messages.impl_MessagesView_Night_6_en",20511,], +["features.messages.impl_MessagesView_Day_7_en","features.messages.impl_MessagesView_Night_7_en",20511,], +["features.messages.impl_MessagesView_Day_8_en","features.messages.impl_MessagesView_Night_8_en",20511,], +["features.messages.impl_MessagesView_Day_9_en","features.messages.impl_MessagesView_Night_9_en",20511,], ["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",20504,], +["features.migration.impl_MigrationView_Day_1_en","features.migration.impl_MigrationView_Night_1_en",20511,], ["libraries.designsystem.theme.components_ModalBottomSheetDark_Bottom_Sheets_en","",0,], ["libraries.designsystem.theme.components_ModalBottomSheetLight_Bottom_Sheets_en","",0,], ["appicon.element_MonochromeIcon_en","",0,], @@ -732,113 +735,113 @@ export const screenshots = [ ["libraries.designsystem.components.list_MutipleSelectionListItemSelected_Multiple_selection_List_item_-_selection_in_supporting_text_List_items_en","",0,], ["libraries.designsystem.components.list_MutipleSelectionListItem_Multiple_selection_List_item_-_no_selection_List_items_en","",0,], ["libraries.designsystem.theme.components_NavigationBar_App_Bars_en","",0,], -["features.home.impl.components_NewNotificationSoundBanner_Day_0_en","features.home.impl.components_NewNotificationSoundBanner_Night_0_en",20504,], -["features.preferences.impl.notifications_NotificationSettingsView_Day_0_en","features.preferences.impl.notifications_NotificationSettingsView_Night_0_en",20504,], -["features.preferences.impl.notifications_NotificationSettingsView_Day_10_en","features.preferences.impl.notifications_NotificationSettingsView_Night_10_en",20504,], -["features.preferences.impl.notifications_NotificationSettingsView_Day_11_en","features.preferences.impl.notifications_NotificationSettingsView_Night_11_en",20504,], -["features.preferences.impl.notifications_NotificationSettingsView_Day_12_en","features.preferences.impl.notifications_NotificationSettingsView_Night_12_en",20504,], -["features.preferences.impl.notifications_NotificationSettingsView_Day_13_en","features.preferences.impl.notifications_NotificationSettingsView_Night_13_en",20504,], -["features.preferences.impl.notifications_NotificationSettingsView_Day_1_en","features.preferences.impl.notifications_NotificationSettingsView_Night_1_en",20504,], -["features.preferences.impl.notifications_NotificationSettingsView_Day_2_en","features.preferences.impl.notifications_NotificationSettingsView_Night_2_en",20504,], -["features.preferences.impl.notifications_NotificationSettingsView_Day_3_en","features.preferences.impl.notifications_NotificationSettingsView_Night_3_en",20504,], -["features.preferences.impl.notifications_NotificationSettingsView_Day_4_en","features.preferences.impl.notifications_NotificationSettingsView_Night_4_en",20504,], -["features.preferences.impl.notifications_NotificationSettingsView_Day_5_en","features.preferences.impl.notifications_NotificationSettingsView_Night_5_en",20504,], -["features.preferences.impl.notifications_NotificationSettingsView_Day_6_en","features.preferences.impl.notifications_NotificationSettingsView_Night_6_en",20504,], -["features.preferences.impl.notifications_NotificationSettingsView_Day_7_en","features.preferences.impl.notifications_NotificationSettingsView_Night_7_en",20504,], -["features.preferences.impl.notifications_NotificationSettingsView_Day_8_en","features.preferences.impl.notifications_NotificationSettingsView_Night_8_en",20504,], -["features.preferences.impl.notifications_NotificationSettingsView_Day_9_en","features.preferences.impl.notifications_NotificationSettingsView_Night_9_en",20504,], -["features.ftue.impl.notifications_NotificationsOptInView_Day_0_en","features.ftue.impl.notifications_NotificationsOptInView_Night_0_en",20504,], +["features.home.impl.components_NewNotificationSoundBanner_Day_0_en","features.home.impl.components_NewNotificationSoundBanner_Night_0_en",20511,], +["features.preferences.impl.notifications_NotificationSettingsView_Day_0_en","features.preferences.impl.notifications_NotificationSettingsView_Night_0_en",20511,], +["features.preferences.impl.notifications_NotificationSettingsView_Day_10_en","features.preferences.impl.notifications_NotificationSettingsView_Night_10_en",20511,], +["features.preferences.impl.notifications_NotificationSettingsView_Day_11_en","features.preferences.impl.notifications_NotificationSettingsView_Night_11_en",20511,], +["features.preferences.impl.notifications_NotificationSettingsView_Day_12_en","features.preferences.impl.notifications_NotificationSettingsView_Night_12_en",20511,], +["features.preferences.impl.notifications_NotificationSettingsView_Day_13_en","features.preferences.impl.notifications_NotificationSettingsView_Night_13_en",20511,], +["features.preferences.impl.notifications_NotificationSettingsView_Day_1_en","features.preferences.impl.notifications_NotificationSettingsView_Night_1_en",20511,], +["features.preferences.impl.notifications_NotificationSettingsView_Day_2_en","features.preferences.impl.notifications_NotificationSettingsView_Night_2_en",20511,], +["features.preferences.impl.notifications_NotificationSettingsView_Day_3_en","features.preferences.impl.notifications_NotificationSettingsView_Night_3_en",20511,], +["features.preferences.impl.notifications_NotificationSettingsView_Day_4_en","features.preferences.impl.notifications_NotificationSettingsView_Night_4_en",20511,], +["features.preferences.impl.notifications_NotificationSettingsView_Day_5_en","features.preferences.impl.notifications_NotificationSettingsView_Night_5_en",20511,], +["features.preferences.impl.notifications_NotificationSettingsView_Day_6_en","features.preferences.impl.notifications_NotificationSettingsView_Night_6_en",20511,], +["features.preferences.impl.notifications_NotificationSettingsView_Day_7_en","features.preferences.impl.notifications_NotificationSettingsView_Night_7_en",20511,], +["features.preferences.impl.notifications_NotificationSettingsView_Day_8_en","features.preferences.impl.notifications_NotificationSettingsView_Night_8_en",20511,], +["features.preferences.impl.notifications_NotificationSettingsView_Day_9_en","features.preferences.impl.notifications_NotificationSettingsView_Night_9_en",20511,], +["features.ftue.impl.notifications_NotificationsOptInView_Day_0_en","features.ftue.impl.notifications_NotificationsOptInView_Night_0_en",20511,], ["features.linknewdevice.impl.screens.number.component_NumberTextField_Day_0_en","features.linknewdevice.impl.screens.number.component_NumberTextField_Night_0_en",0,], ["libraries.designsystem.atomic.pages_OnBoardingPage_Day_0_en","libraries.designsystem.atomic.pages_OnBoardingPage_Night_0_en",0,], -["features.login.impl.screens.onboarding_OnBoardingView_Day_0_en","features.login.impl.screens.onboarding_OnBoardingView_Night_0_en",20504,], -["features.login.impl.screens.onboarding_OnBoardingView_Day_1_en","features.login.impl.screens.onboarding_OnBoardingView_Night_1_en",20504,], -["features.login.impl.screens.onboarding_OnBoardingView_Day_2_en","features.login.impl.screens.onboarding_OnBoardingView_Night_2_en",20504,], -["features.login.impl.screens.onboarding_OnBoardingView_Day_3_en","features.login.impl.screens.onboarding_OnBoardingView_Night_3_en",20504,], -["features.login.impl.screens.onboarding_OnBoardingView_Day_4_en","features.login.impl.screens.onboarding_OnBoardingView_Night_4_en",20504,], -["features.login.impl.screens.onboarding_OnBoardingView_Day_5_en","features.login.impl.screens.onboarding_OnBoardingView_Night_5_en",20504,], -["features.login.impl.screens.onboarding_OnBoardingView_Day_6_en","features.login.impl.screens.onboarding_OnBoardingView_Night_6_en",20504,], -["features.login.impl.screens.onboarding_OnBoardingView_Day_7_en","features.login.impl.screens.onboarding_OnBoardingView_Night_7_en",20504,], +["features.login.impl.screens.onboarding_OnBoardingView_Day_0_en","features.login.impl.screens.onboarding_OnBoardingView_Night_0_en",20511,], +["features.login.impl.screens.onboarding_OnBoardingView_Day_1_en","features.login.impl.screens.onboarding_OnBoardingView_Night_1_en",20511,], +["features.login.impl.screens.onboarding_OnBoardingView_Day_2_en","features.login.impl.screens.onboarding_OnBoardingView_Night_2_en",20511,], +["features.login.impl.screens.onboarding_OnBoardingView_Day_3_en","features.login.impl.screens.onboarding_OnBoardingView_Night_3_en",20511,], +["features.login.impl.screens.onboarding_OnBoardingView_Day_4_en","features.login.impl.screens.onboarding_OnBoardingView_Night_4_en",20511,], +["features.login.impl.screens.onboarding_OnBoardingView_Day_5_en","features.login.impl.screens.onboarding_OnBoardingView_Night_5_en",20511,], +["features.login.impl.screens.onboarding_OnBoardingView_Day_6_en","features.login.impl.screens.onboarding_OnBoardingView_Night_6_en",20511,], +["features.login.impl.screens.onboarding_OnBoardingView_Day_7_en","features.login.impl.screens.onboarding_OnBoardingView_Night_7_en",20511,], ["libraries.designsystem.background_OnboardingBackground_Day_0_en","libraries.designsystem.background_OnboardingBackground_Night_0_en",0,], -["libraries.matrix.ui.components_OrganizationHeader_Day_0_en","libraries.matrix.ui.components_OrganizationHeader_Night_0_en",20504,], -["features.verifysession.impl.outgoing_OutgoingVerificationView_Day_0_en","features.verifysession.impl.outgoing_OutgoingVerificationView_Night_0_en",20504,], -["features.verifysession.impl.outgoing_OutgoingVerificationView_Day_10_en","features.verifysession.impl.outgoing_OutgoingVerificationView_Night_10_en",20504,], -["features.verifysession.impl.outgoing_OutgoingVerificationView_Day_11_en","features.verifysession.impl.outgoing_OutgoingVerificationView_Night_11_en",20504,], +["libraries.matrix.ui.components_OrganizationHeader_Day_0_en","libraries.matrix.ui.components_OrganizationHeader_Night_0_en",20511,], +["features.verifysession.impl.outgoing_OutgoingVerificationView_Day_0_en","features.verifysession.impl.outgoing_OutgoingVerificationView_Night_0_en",20511,], +["features.verifysession.impl.outgoing_OutgoingVerificationView_Day_10_en","features.verifysession.impl.outgoing_OutgoingVerificationView_Night_10_en",20511,], +["features.verifysession.impl.outgoing_OutgoingVerificationView_Day_11_en","features.verifysession.impl.outgoing_OutgoingVerificationView_Night_11_en",20511,], ["features.verifysession.impl.outgoing_OutgoingVerificationView_Day_12_en","features.verifysession.impl.outgoing_OutgoingVerificationView_Night_12_en",0,], ["features.verifysession.impl.outgoing_OutgoingVerificationView_Day_13_en","features.verifysession.impl.outgoing_OutgoingVerificationView_Night_13_en",0,], -["features.verifysession.impl.outgoing_OutgoingVerificationView_Day_1_en","features.verifysession.impl.outgoing_OutgoingVerificationView_Night_1_en",20504,], -["features.verifysession.impl.outgoing_OutgoingVerificationView_Day_2_en","features.verifysession.impl.outgoing_OutgoingVerificationView_Night_2_en",20504,], -["features.verifysession.impl.outgoing_OutgoingVerificationView_Day_3_en","features.verifysession.impl.outgoing_OutgoingVerificationView_Night_3_en",20504,], -["features.verifysession.impl.outgoing_OutgoingVerificationView_Day_4_en","features.verifysession.impl.outgoing_OutgoingVerificationView_Night_4_en",20504,], -["features.verifysession.impl.outgoing_OutgoingVerificationView_Day_5_en","features.verifysession.impl.outgoing_OutgoingVerificationView_Night_5_en",20504,], -["features.verifysession.impl.outgoing_OutgoingVerificationView_Day_6_en","features.verifysession.impl.outgoing_OutgoingVerificationView_Night_6_en",20504,], -["features.verifysession.impl.outgoing_OutgoingVerificationView_Day_7_en","features.verifysession.impl.outgoing_OutgoingVerificationView_Night_7_en",20504,], -["features.verifysession.impl.outgoing_OutgoingVerificationView_Day_8_en","features.verifysession.impl.outgoing_OutgoingVerificationView_Night_8_en",20504,], -["features.verifysession.impl.outgoing_OutgoingVerificationView_Day_9_en","features.verifysession.impl.outgoing_OutgoingVerificationView_Night_9_en",20504,], +["features.verifysession.impl.outgoing_OutgoingVerificationView_Day_1_en","features.verifysession.impl.outgoing_OutgoingVerificationView_Night_1_en",20511,], +["features.verifysession.impl.outgoing_OutgoingVerificationView_Day_2_en","features.verifysession.impl.outgoing_OutgoingVerificationView_Night_2_en",20511,], +["features.verifysession.impl.outgoing_OutgoingVerificationView_Day_3_en","features.verifysession.impl.outgoing_OutgoingVerificationView_Night_3_en",20511,], +["features.verifysession.impl.outgoing_OutgoingVerificationView_Day_4_en","features.verifysession.impl.outgoing_OutgoingVerificationView_Night_4_en",20511,], +["features.verifysession.impl.outgoing_OutgoingVerificationView_Day_5_en","features.verifysession.impl.outgoing_OutgoingVerificationView_Night_5_en",20511,], +["features.verifysession.impl.outgoing_OutgoingVerificationView_Day_6_en","features.verifysession.impl.outgoing_OutgoingVerificationView_Night_6_en",20511,], +["features.verifysession.impl.outgoing_OutgoingVerificationView_Day_7_en","features.verifysession.impl.outgoing_OutgoingVerificationView_Night_7_en",20511,], +["features.verifysession.impl.outgoing_OutgoingVerificationView_Day_8_en","features.verifysession.impl.outgoing_OutgoingVerificationView_Night_8_en",20511,], +["features.verifysession.impl.outgoing_OutgoingVerificationView_Day_9_en","features.verifysession.impl.outgoing_OutgoingVerificationView_Night_9_en",20511,], ["libraries.designsystem.theme.components_OutlinedButtonLargeLowPadding_Buttons_en","",0,], ["libraries.designsystem.theme.components_OutlinedButtonLarge_Buttons_en","",0,], ["libraries.designsystem.theme.components_OutlinedButtonMediumLowPadding_Buttons_en","",0,], ["libraries.designsystem.theme.components_OutlinedButtonMedium_Buttons_en","",0,], ["libraries.designsystem.theme.components_OutlinedButtonSmall_Buttons_en","",0,], -["libraries.mediaviewer.impl.local.pdf_PdfPagesErrorView_Day_0_en","libraries.mediaviewer.impl.local.pdf_PdfPagesErrorView_Night_0_en",20504,], -["features.rolesandpermissions.impl.roles_PendingMemberRowWithLongName_Day_0_en","features.rolesandpermissions.impl.roles_PendingMemberRowWithLongName_Night_0_en",20504,], -["libraries.permissions.api_PermissionsView_Day_0_en","libraries.permissions.api_PermissionsView_Night_0_en",20504,], -["libraries.permissions.api_PermissionsView_Day_1_en","libraries.permissions.api_PermissionsView_Night_1_en",20504,], -["libraries.permissions.api_PermissionsView_Day_2_en","libraries.permissions.api_PermissionsView_Night_2_en",20504,], -["libraries.permissions.api_PermissionsView_Day_3_en","libraries.permissions.api_PermissionsView_Night_3_en",20504,], +["libraries.mediaviewer.impl.local.pdf_PdfPagesErrorView_Day_0_en","libraries.mediaviewer.impl.local.pdf_PdfPagesErrorView_Night_0_en",20511,], +["features.rolesandpermissions.impl.roles_PendingMemberRowWithLongName_Day_0_en","features.rolesandpermissions.impl.roles_PendingMemberRowWithLongName_Night_0_en",20511,], +["libraries.permissions.api_PermissionsView_Day_0_en","libraries.permissions.api_PermissionsView_Night_0_en",20511,], +["libraries.permissions.api_PermissionsView_Day_1_en","libraries.permissions.api_PermissionsView_Night_1_en",20511,], +["libraries.permissions.api_PermissionsView_Day_2_en","libraries.permissions.api_PermissionsView_Night_2_en",20511,], +["libraries.permissions.api_PermissionsView_Day_3_en","libraries.permissions.api_PermissionsView_Night_3_en",20511,], ["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",20504,], -["features.lockscreen.impl.unlock_PinUnlockViewInApp_Day_1_en","features.lockscreen.impl.unlock_PinUnlockViewInApp_Night_1_en",20504,], -["features.lockscreen.impl.unlock_PinUnlockViewInApp_Day_2_en","features.lockscreen.impl.unlock_PinUnlockViewInApp_Night_2_en",20504,], -["features.lockscreen.impl.unlock_PinUnlockViewInApp_Day_3_en","features.lockscreen.impl.unlock_PinUnlockViewInApp_Night_3_en",20504,], -["features.lockscreen.impl.unlock_PinUnlockViewInApp_Day_4_en","features.lockscreen.impl.unlock_PinUnlockViewInApp_Night_4_en",20504,], -["features.lockscreen.impl.unlock_PinUnlockViewInApp_Day_5_en","features.lockscreen.impl.unlock_PinUnlockViewInApp_Night_5_en",20504,], -["features.lockscreen.impl.unlock_PinUnlockViewInApp_Day_6_en","features.lockscreen.impl.unlock_PinUnlockViewInApp_Night_6_en",20504,], -["features.lockscreen.impl.unlock_PinUnlockViewInApp_Day_7_en","features.lockscreen.impl.unlock_PinUnlockViewInApp_Night_7_en",20504,], -["features.lockscreen.impl.unlock_PinUnlockView_Day_0_en","features.lockscreen.impl.unlock_PinUnlockView_Night_0_en",20504,], -["features.lockscreen.impl.unlock_PinUnlockView_Day_1_en","features.lockscreen.impl.unlock_PinUnlockView_Night_1_en",20504,], -["features.lockscreen.impl.unlock_PinUnlockView_Day_2_en","features.lockscreen.impl.unlock_PinUnlockView_Night_2_en",20504,], -["features.lockscreen.impl.unlock_PinUnlockView_Day_3_en","features.lockscreen.impl.unlock_PinUnlockView_Night_3_en",20504,], -["features.lockscreen.impl.unlock_PinUnlockView_Day_4_en","features.lockscreen.impl.unlock_PinUnlockView_Night_4_en",20504,], -["features.lockscreen.impl.unlock_PinUnlockView_Day_5_en","features.lockscreen.impl.unlock_PinUnlockView_Night_5_en",20504,], -["features.lockscreen.impl.unlock_PinUnlockView_Day_6_en","features.lockscreen.impl.unlock_PinUnlockView_Night_6_en",20504,], -["features.lockscreen.impl.unlock_PinUnlockView_Day_7_en","features.lockscreen.impl.unlock_PinUnlockView_Night_7_en",20504,], +["features.lockscreen.impl.unlock_PinUnlockViewInApp_Day_0_en","features.lockscreen.impl.unlock_PinUnlockViewInApp_Night_0_en",20511,], +["features.lockscreen.impl.unlock_PinUnlockViewInApp_Day_1_en","features.lockscreen.impl.unlock_PinUnlockViewInApp_Night_1_en",20511,], +["features.lockscreen.impl.unlock_PinUnlockViewInApp_Day_2_en","features.lockscreen.impl.unlock_PinUnlockViewInApp_Night_2_en",20511,], +["features.lockscreen.impl.unlock_PinUnlockViewInApp_Day_3_en","features.lockscreen.impl.unlock_PinUnlockViewInApp_Night_3_en",20511,], +["features.lockscreen.impl.unlock_PinUnlockViewInApp_Day_4_en","features.lockscreen.impl.unlock_PinUnlockViewInApp_Night_4_en",20511,], +["features.lockscreen.impl.unlock_PinUnlockViewInApp_Day_5_en","features.lockscreen.impl.unlock_PinUnlockViewInApp_Night_5_en",20511,], +["features.lockscreen.impl.unlock_PinUnlockViewInApp_Day_6_en","features.lockscreen.impl.unlock_PinUnlockViewInApp_Night_6_en",20511,], +["features.lockscreen.impl.unlock_PinUnlockViewInApp_Day_7_en","features.lockscreen.impl.unlock_PinUnlockViewInApp_Night_7_en",20511,], +["features.lockscreen.impl.unlock_PinUnlockView_Day_0_en","features.lockscreen.impl.unlock_PinUnlockView_Night_0_en",20511,], +["features.lockscreen.impl.unlock_PinUnlockView_Day_1_en","features.lockscreen.impl.unlock_PinUnlockView_Night_1_en",20511,], +["features.lockscreen.impl.unlock_PinUnlockView_Day_2_en","features.lockscreen.impl.unlock_PinUnlockView_Night_2_en",20511,], +["features.lockscreen.impl.unlock_PinUnlockView_Day_3_en","features.lockscreen.impl.unlock_PinUnlockView_Night_3_en",20511,], +["features.lockscreen.impl.unlock_PinUnlockView_Day_4_en","features.lockscreen.impl.unlock_PinUnlockView_Night_4_en",20511,], +["features.lockscreen.impl.unlock_PinUnlockView_Day_5_en","features.lockscreen.impl.unlock_PinUnlockView_Night_5_en",20511,], +["features.lockscreen.impl.unlock_PinUnlockView_Day_6_en","features.lockscreen.impl.unlock_PinUnlockView_Night_6_en",20511,], +["features.lockscreen.impl.unlock_PinUnlockView_Day_7_en","features.lockscreen.impl.unlock_PinUnlockView_Night_7_en",20511,], ["features.messages.impl.pinned.banner_PinnedMessagesBannerView_Day_0_en","features.messages.impl.pinned.banner_PinnedMessagesBannerView_Night_0_en",0,], -["features.messages.impl.pinned.banner_PinnedMessagesBannerView_Day_10_en","features.messages.impl.pinned.banner_PinnedMessagesBannerView_Night_10_en",20504,], -["features.messages.impl.pinned.banner_PinnedMessagesBannerView_Day_1_en","features.messages.impl.pinned.banner_PinnedMessagesBannerView_Night_1_en",20504,], -["features.messages.impl.pinned.banner_PinnedMessagesBannerView_Day_2_en","features.messages.impl.pinned.banner_PinnedMessagesBannerView_Night_2_en",20504,], -["features.messages.impl.pinned.banner_PinnedMessagesBannerView_Day_3_en","features.messages.impl.pinned.banner_PinnedMessagesBannerView_Night_3_en",20504,], -["features.messages.impl.pinned.banner_PinnedMessagesBannerView_Day_4_en","features.messages.impl.pinned.banner_PinnedMessagesBannerView_Night_4_en",20504,], -["features.messages.impl.pinned.banner_PinnedMessagesBannerView_Day_5_en","features.messages.impl.pinned.banner_PinnedMessagesBannerView_Night_5_en",20504,], -["features.messages.impl.pinned.banner_PinnedMessagesBannerView_Day_6_en","features.messages.impl.pinned.banner_PinnedMessagesBannerView_Night_6_en",20504,], -["features.messages.impl.pinned.banner_PinnedMessagesBannerView_Day_7_en","features.messages.impl.pinned.banner_PinnedMessagesBannerView_Night_7_en",20504,], -["features.messages.impl.pinned.banner_PinnedMessagesBannerView_Day_8_en","features.messages.impl.pinned.banner_PinnedMessagesBannerView_Night_8_en",20504,], -["features.messages.impl.pinned.banner_PinnedMessagesBannerView_Day_9_en","features.messages.impl.pinned.banner_PinnedMessagesBannerView_Night_9_en",20504,], -["features.messages.impl.pinned.list_PinnedMessagesListView_Day_0_en","features.messages.impl.pinned.list_PinnedMessagesListView_Night_0_en",20504,], -["features.messages.impl.pinned.list_PinnedMessagesListView_Day_1_en","features.messages.impl.pinned.list_PinnedMessagesListView_Night_1_en",20504,], -["features.messages.impl.pinned.list_PinnedMessagesListView_Day_2_en","features.messages.impl.pinned.list_PinnedMessagesListView_Night_2_en",20504,], -["features.messages.impl.pinned.list_PinnedMessagesListView_Day_3_en","features.messages.impl.pinned.list_PinnedMessagesListView_Night_3_en",20504,], +["features.messages.impl.pinned.banner_PinnedMessagesBannerView_Day_10_en","features.messages.impl.pinned.banner_PinnedMessagesBannerView_Night_10_en",20511,], +["features.messages.impl.pinned.banner_PinnedMessagesBannerView_Day_1_en","features.messages.impl.pinned.banner_PinnedMessagesBannerView_Night_1_en",20511,], +["features.messages.impl.pinned.banner_PinnedMessagesBannerView_Day_2_en","features.messages.impl.pinned.banner_PinnedMessagesBannerView_Night_2_en",20511,], +["features.messages.impl.pinned.banner_PinnedMessagesBannerView_Day_3_en","features.messages.impl.pinned.banner_PinnedMessagesBannerView_Night_3_en",20511,], +["features.messages.impl.pinned.banner_PinnedMessagesBannerView_Day_4_en","features.messages.impl.pinned.banner_PinnedMessagesBannerView_Night_4_en",20511,], +["features.messages.impl.pinned.banner_PinnedMessagesBannerView_Day_5_en","features.messages.impl.pinned.banner_PinnedMessagesBannerView_Night_5_en",20511,], +["features.messages.impl.pinned.banner_PinnedMessagesBannerView_Day_6_en","features.messages.impl.pinned.banner_PinnedMessagesBannerView_Night_6_en",20511,], +["features.messages.impl.pinned.banner_PinnedMessagesBannerView_Day_7_en","features.messages.impl.pinned.banner_PinnedMessagesBannerView_Night_7_en",20511,], +["features.messages.impl.pinned.banner_PinnedMessagesBannerView_Day_8_en","features.messages.impl.pinned.banner_PinnedMessagesBannerView_Night_8_en",20511,], +["features.messages.impl.pinned.banner_PinnedMessagesBannerView_Day_9_en","features.messages.impl.pinned.banner_PinnedMessagesBannerView_Night_9_en",20511,], +["features.messages.impl.pinned.list_PinnedMessagesListView_Day_0_en","features.messages.impl.pinned.list_PinnedMessagesListView_Night_0_en",20511,], +["features.messages.impl.pinned.list_PinnedMessagesListView_Day_1_en","features.messages.impl.pinned.list_PinnedMessagesListView_Night_1_en",20511,], +["features.messages.impl.pinned.list_PinnedMessagesListView_Day_2_en","features.messages.impl.pinned.list_PinnedMessagesListView_Night_2_en",20511,], +["features.messages.impl.pinned.list_PinnedMessagesListView_Day_3_en","features.messages.impl.pinned.list_PinnedMessagesListView_Night_3_en",20511,], ["libraries.designsystem.atomic.atoms_PlaceholderAtom_Day_0_en","libraries.designsystem.atomic.atoms_PlaceholderAtom_Night_0_en",0,], ["libraries.designsystem.atomic.atoms_PlaybackSpeedButton_Day_0_en","libraries.designsystem.atomic.atoms_PlaybackSpeedButton_Night_0_en",0,], -["features.poll.api.pollcontent_PollAnswerViewDisclosedNotSelected_Day_0_en","features.poll.api.pollcontent_PollAnswerViewDisclosedNotSelected_Night_0_en",20504,], -["features.poll.api.pollcontent_PollAnswerViewDisclosedSelected_Day_0_en","features.poll.api.pollcontent_PollAnswerViewDisclosedSelected_Night_0_en",20504,], -["features.poll.api.pollcontent_PollAnswerViewEndedSelected_Day_0_en","features.poll.api.pollcontent_PollAnswerViewEndedSelected_Night_0_en",20504,], -["features.poll.api.pollcontent_PollAnswerViewEndedWinnerNotSelected_Day_0_en","features.poll.api.pollcontent_PollAnswerViewEndedWinnerNotSelected_Night_0_en",20504,], -["features.poll.api.pollcontent_PollAnswerViewEndedWinnerSelected_Day_0_en","features.poll.api.pollcontent_PollAnswerViewEndedWinnerSelected_Night_0_en",20504,], +["features.poll.api.pollcontent_PollAnswerViewDisclosedNotSelected_Day_0_en","features.poll.api.pollcontent_PollAnswerViewDisclosedNotSelected_Night_0_en",20511,], +["features.poll.api.pollcontent_PollAnswerViewDisclosedSelected_Day_0_en","features.poll.api.pollcontent_PollAnswerViewDisclosedSelected_Night_0_en",20511,], +["features.poll.api.pollcontent_PollAnswerViewEndedSelected_Day_0_en","features.poll.api.pollcontent_PollAnswerViewEndedSelected_Night_0_en",20511,], +["features.poll.api.pollcontent_PollAnswerViewEndedWinnerNotSelected_Day_0_en","features.poll.api.pollcontent_PollAnswerViewEndedWinnerNotSelected_Night_0_en",20511,], +["features.poll.api.pollcontent_PollAnswerViewEndedWinnerSelected_Day_0_en","features.poll.api.pollcontent_PollAnswerViewEndedWinnerSelected_Night_0_en",20511,], ["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",20504,], -["features.poll.api.pollcontent_PollContentViewCreatorEnded_Day_0_en","features.poll.api.pollcontent_PollContentViewCreatorEnded_Night_0_en",20504,], -["features.poll.api.pollcontent_PollContentViewCreator_Day_0_en","features.poll.api.pollcontent_PollContentViewCreator_Night_0_en",20504,], -["features.poll.api.pollcontent_PollContentViewDisclosed_Day_0_en","features.poll.api.pollcontent_PollContentViewDisclosed_Night_0_en",20504,], -["features.poll.api.pollcontent_PollContentViewEnded_Day_0_en","features.poll.api.pollcontent_PollContentViewEnded_Night_0_en",20504,], -["features.poll.api.pollcontent_PollContentViewUndisclosed_Day_0_en","features.poll.api.pollcontent_PollContentViewUndisclosed_Night_0_en",20504,], -["features.poll.impl.history_PollHistoryView_Day_0_en","features.poll.impl.history_PollHistoryView_Night_0_en",20504,], -["features.poll.impl.history_PollHistoryView_Day_1_en","features.poll.impl.history_PollHistoryView_Night_1_en",20504,], -["features.poll.impl.history_PollHistoryView_Day_2_en","features.poll.impl.history_PollHistoryView_Night_2_en",20504,], -["features.poll.impl.history_PollHistoryView_Day_3_en","features.poll.impl.history_PollHistoryView_Night_3_en",20504,], -["features.poll.impl.history_PollHistoryView_Day_4_en","features.poll.impl.history_PollHistoryView_Night_4_en",20504,], +["features.poll.api.pollcontent_PollContentViewCreatorEditable_Day_0_en","features.poll.api.pollcontent_PollContentViewCreatorEditable_Night_0_en",20511,], +["features.poll.api.pollcontent_PollContentViewCreatorEnded_Day_0_en","features.poll.api.pollcontent_PollContentViewCreatorEnded_Night_0_en",20511,], +["features.poll.api.pollcontent_PollContentViewCreator_Day_0_en","features.poll.api.pollcontent_PollContentViewCreator_Night_0_en",20511,], +["features.poll.api.pollcontent_PollContentViewDisclosed_Day_0_en","features.poll.api.pollcontent_PollContentViewDisclosed_Night_0_en",20511,], +["features.poll.api.pollcontent_PollContentViewEnded_Day_0_en","features.poll.api.pollcontent_PollContentViewEnded_Night_0_en",20511,], +["features.poll.api.pollcontent_PollContentViewUndisclosed_Day_0_en","features.poll.api.pollcontent_PollContentViewUndisclosed_Night_0_en",20511,], +["features.poll.impl.history_PollHistoryView_Day_0_en","features.poll.impl.history_PollHistoryView_Night_0_en",20511,], +["features.poll.impl.history_PollHistoryView_Day_1_en","features.poll.impl.history_PollHistoryView_Night_1_en",20511,], +["features.poll.impl.history_PollHistoryView_Day_2_en","features.poll.impl.history_PollHistoryView_Night_2_en",20511,], +["features.poll.impl.history_PollHistoryView_Day_3_en","features.poll.impl.history_PollHistoryView_Night_3_en",20511,], +["features.poll.impl.history_PollHistoryView_Day_4_en","features.poll.impl.history_PollHistoryView_Night_4_en",20511,], ["features.poll.api.pollcontent_PollTitleView_Day_0_en","features.poll.api.pollcontent_PollTitleView_Night_0_en",0,], ["libraries.designsystem.components.preferences_PreferenceCategory_Preferences_en","",0,], ["libraries.designsystem.components.preferences_PreferenceCheckbox_Preferences_en","",0,], @@ -852,215 +855,215 @@ export const screenshots = [ ["libraries.designsystem.components.preferences_PreferenceRow_Preferences_en","",0,], ["libraries.designsystem.components.preferences_PreferenceSlide_Preferences_en","",0,], ["libraries.designsystem.components.preferences_PreferenceSwitch_Preferences_en","",0,], -["features.preferences.impl.root_PreferencesRootViewDark_0_en","",20504,], -["features.preferences.impl.root_PreferencesRootViewDark_1_en","",20504,], -["features.preferences.impl.root_PreferencesRootViewLight_0_en","",20504,], -["features.preferences.impl.root_PreferencesRootViewLight_1_en","",20504,], +["features.preferences.impl.root_PreferencesRootViewDark_0_en","",20511,], +["features.preferences.impl.root_PreferencesRootViewDark_1_en","",20511,], +["features.preferences.impl.root_PreferencesRootViewLight_0_en","",20511,], +["features.preferences.impl.root_PreferencesRootViewLight_1_en","",20511,], ["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","",20504,], -["libraries.designsystem.components_ProgressDialogWithContent_Day_0_en","libraries.designsystem.components_ProgressDialogWithContent_Night_0_en",20504,], +["libraries.designsystem.components_ProgressDialogContent_Dialogs_en","",20511,], +["libraries.designsystem.components_ProgressDialogWithContent_Day_0_en","libraries.designsystem.components_ProgressDialogWithContent_Night_0_en",20511,], ["libraries.designsystem.components_ProgressDialogWithTextAndContent_Day_0_en","libraries.designsystem.components_ProgressDialogWithTextAndContent_Night_0_en",0,], -["libraries.designsystem.components_ProgressDialog_Day_0_en","libraries.designsystem.components_ProgressDialog_Night_0_en",20504,], -["features.messages.impl.timeline.protection_ProtectedView_Day_0_en","features.messages.impl.timeline.protection_ProtectedView_Night_0_en",20504,], -["features.messages.impl.timeline.protection_ProtectedView_Day_1_en","features.messages.impl.timeline.protection_ProtectedView_Night_1_en",20504,], -["features.messages.impl.timeline.protection_ProtectedView_Day_2_en","features.messages.impl.timeline.protection_ProtectedView_Night_2_en",20504,], -["features.messages.impl.timeline.protection_ProtectedView_Day_3_en","features.messages.impl.timeline.protection_ProtectedView_Night_3_en",20504,], -["libraries.troubleshoot.impl.history_PushHistoryView_Day_0_en","libraries.troubleshoot.impl.history_PushHistoryView_Night_0_en",20504,], -["libraries.troubleshoot.impl.history_PushHistoryView_Day_1_en","libraries.troubleshoot.impl.history_PushHistoryView_Night_1_en",20504,], -["libraries.troubleshoot.impl.history_PushHistoryView_Day_2_en","libraries.troubleshoot.impl.history_PushHistoryView_Night_2_en",20504,], -["libraries.troubleshoot.impl.history_PushHistoryView_Day_3_en","libraries.troubleshoot.impl.history_PushHistoryView_Night_3_en",20504,], -["features.login.impl.screens.qrcode.confirmation_QrCodeConfirmationView_Day_0_en","features.login.impl.screens.qrcode.confirmation_QrCodeConfirmationView_Night_0_en",20504,], -["features.login.impl.screens.qrcode.confirmation_QrCodeConfirmationView_Day_1_en","features.login.impl.screens.qrcode.confirmation_QrCodeConfirmationView_Night_1_en",20504,], -["features.login.impl.screens.qrcode.confirmation_QrCodeConfirmationView_Day_2_en","features.login.impl.screens.qrcode.confirmation_QrCodeConfirmationView_Night_2_en",20504,], -["features.login.impl.screens.qrcode.error_QrCodeErrorView_Day_0_en","features.login.impl.screens.qrcode.error_QrCodeErrorView_Night_0_en",20504,], -["features.login.impl.screens.qrcode.error_QrCodeErrorView_Day_1_en","features.login.impl.screens.qrcode.error_QrCodeErrorView_Night_1_en",20504,], -["features.login.impl.screens.qrcode.error_QrCodeErrorView_Day_2_en","features.login.impl.screens.qrcode.error_QrCodeErrorView_Night_2_en",20504,], -["features.login.impl.screens.qrcode.error_QrCodeErrorView_Day_3_en","features.login.impl.screens.qrcode.error_QrCodeErrorView_Night_3_en",20504,], -["features.login.impl.screens.qrcode.error_QrCodeErrorView_Day_4_en","features.login.impl.screens.qrcode.error_QrCodeErrorView_Night_4_en",20504,], -["features.login.impl.screens.qrcode.error_QrCodeErrorView_Day_5_en","features.login.impl.screens.qrcode.error_QrCodeErrorView_Night_5_en",20504,], -["features.login.impl.screens.qrcode.error_QrCodeErrorView_Day_6_en","features.login.impl.screens.qrcode.error_QrCodeErrorView_Night_6_en",20504,], -["features.login.impl.screens.qrcode.intro_QrCodeIntroView_Day_0_en","features.login.impl.screens.qrcode.intro_QrCodeIntroView_Night_0_en",20504,], -["features.login.impl.screens.qrcode.intro_QrCodeIntroView_Day_1_en","features.login.impl.screens.qrcode.intro_QrCodeIntroView_Night_1_en",20504,], -["features.login.impl.screens.qrcode.scan_QrCodeScanView_Day_0_en","features.login.impl.screens.qrcode.scan_QrCodeScanView_Night_0_en",20504,], -["features.login.impl.screens.qrcode.scan_QrCodeScanView_Day_1_en","features.login.impl.screens.qrcode.scan_QrCodeScanView_Night_1_en",20504,], -["features.login.impl.screens.qrcode.scan_QrCodeScanView_Day_2_en","features.login.impl.screens.qrcode.scan_QrCodeScanView_Night_2_en",20504,], -["features.login.impl.screens.qrcode.scan_QrCodeScanView_Day_3_en","features.login.impl.screens.qrcode.scan_QrCodeScanView_Night_3_en",20504,], -["features.login.impl.screens.qrcode.scan_QrCodeScanView_Day_4_en","features.login.impl.screens.qrcode.scan_QrCodeScanView_Night_4_en",20504,], -["features.login.impl.screens.qrcode.scan_QrCodeScanView_Day_5_en","features.login.impl.screens.qrcode.scan_QrCodeScanView_Night_5_en",20504,], +["libraries.designsystem.components_ProgressDialog_Day_0_en","libraries.designsystem.components_ProgressDialog_Night_0_en",20511,], +["features.messages.impl.timeline.protection_ProtectedView_Day_0_en","features.messages.impl.timeline.protection_ProtectedView_Night_0_en",20511,], +["features.messages.impl.timeline.protection_ProtectedView_Day_1_en","features.messages.impl.timeline.protection_ProtectedView_Night_1_en",20511,], +["features.messages.impl.timeline.protection_ProtectedView_Day_2_en","features.messages.impl.timeline.protection_ProtectedView_Night_2_en",20511,], +["features.messages.impl.timeline.protection_ProtectedView_Day_3_en","features.messages.impl.timeline.protection_ProtectedView_Night_3_en",20511,], +["libraries.troubleshoot.impl.history_PushHistoryView_Day_0_en","libraries.troubleshoot.impl.history_PushHistoryView_Night_0_en",20511,], +["libraries.troubleshoot.impl.history_PushHistoryView_Day_1_en","libraries.troubleshoot.impl.history_PushHistoryView_Night_1_en",20511,], +["libraries.troubleshoot.impl.history_PushHistoryView_Day_2_en","libraries.troubleshoot.impl.history_PushHistoryView_Night_2_en",20511,], +["libraries.troubleshoot.impl.history_PushHistoryView_Day_3_en","libraries.troubleshoot.impl.history_PushHistoryView_Night_3_en",20511,], +["features.login.impl.screens.qrcode.confirmation_QrCodeConfirmationView_Day_0_en","features.login.impl.screens.qrcode.confirmation_QrCodeConfirmationView_Night_0_en",20511,], +["features.login.impl.screens.qrcode.confirmation_QrCodeConfirmationView_Day_1_en","features.login.impl.screens.qrcode.confirmation_QrCodeConfirmationView_Night_1_en",20511,], +["features.login.impl.screens.qrcode.confirmation_QrCodeConfirmationView_Day_2_en","features.login.impl.screens.qrcode.confirmation_QrCodeConfirmationView_Night_2_en",20511,], +["features.login.impl.screens.qrcode.error_QrCodeErrorView_Day_0_en","features.login.impl.screens.qrcode.error_QrCodeErrorView_Night_0_en",20511,], +["features.login.impl.screens.qrcode.error_QrCodeErrorView_Day_1_en","features.login.impl.screens.qrcode.error_QrCodeErrorView_Night_1_en",20511,], +["features.login.impl.screens.qrcode.error_QrCodeErrorView_Day_2_en","features.login.impl.screens.qrcode.error_QrCodeErrorView_Night_2_en",20511,], +["features.login.impl.screens.qrcode.error_QrCodeErrorView_Day_3_en","features.login.impl.screens.qrcode.error_QrCodeErrorView_Night_3_en",20511,], +["features.login.impl.screens.qrcode.error_QrCodeErrorView_Day_4_en","features.login.impl.screens.qrcode.error_QrCodeErrorView_Night_4_en",20511,], +["features.login.impl.screens.qrcode.error_QrCodeErrorView_Day_5_en","features.login.impl.screens.qrcode.error_QrCodeErrorView_Night_5_en",20511,], +["features.login.impl.screens.qrcode.error_QrCodeErrorView_Day_6_en","features.login.impl.screens.qrcode.error_QrCodeErrorView_Night_6_en",20511,], +["features.login.impl.screens.qrcode.intro_QrCodeIntroView_Day_0_en","features.login.impl.screens.qrcode.intro_QrCodeIntroView_Night_0_en",20511,], +["features.login.impl.screens.qrcode.intro_QrCodeIntroView_Day_1_en","features.login.impl.screens.qrcode.intro_QrCodeIntroView_Night_1_en",20511,], +["features.login.impl.screens.qrcode.scan_QrCodeScanView_Day_0_en","features.login.impl.screens.qrcode.scan_QrCodeScanView_Night_0_en",20511,], +["features.login.impl.screens.qrcode.scan_QrCodeScanView_Day_1_en","features.login.impl.screens.qrcode.scan_QrCodeScanView_Night_1_en",20511,], +["features.login.impl.screens.qrcode.scan_QrCodeScanView_Day_2_en","features.login.impl.screens.qrcode.scan_QrCodeScanView_Night_2_en",20511,], +["features.login.impl.screens.qrcode.scan_QrCodeScanView_Day_3_en","features.login.impl.screens.qrcode.scan_QrCodeScanView_Night_3_en",20511,], +["features.login.impl.screens.qrcode.scan_QrCodeScanView_Day_4_en","features.login.impl.screens.qrcode.scan_QrCodeScanView_Night_4_en",20511,], +["features.login.impl.screens.qrcode.scan_QrCodeScanView_Day_5_en","features.login.impl.screens.qrcode.scan_QrCodeScanView_Night_5_en",20511,], ["libraries.qrcode_QrCodeView_en","",0,], ["libraries.designsystem.theme.components_RadioButton_Toggles_en","",0,], -["features.rageshake.api.detection_RageshakeDialogContent_Day_0_en","features.rageshake.api.detection_RageshakeDialogContent_Night_0_en",20504,], -["features.rageshake.api.preferences_RageshakePreferencesView_Day_0_en","features.rageshake.api.preferences_RageshakePreferencesView_Night_0_en",20504,], +["features.rageshake.api.detection_RageshakeDialogContent_Day_0_en","features.rageshake.api.detection_RageshakeDialogContent_Night_0_en",20511,], +["features.rageshake.api.preferences_RageshakePreferencesView_Day_0_en","features.rageshake.api.preferences_RageshakePreferencesView_Night_0_en",20511,], ["features.rageshake.api.preferences_RageshakePreferencesView_Day_1_en","features.rageshake.api.preferences_RageshakePreferencesView_Night_1_en",0,], ["features.messages.impl.timeline.components.reactionsummary_ReactionSummaryViewContent_Day_0_en","features.messages.impl.timeline.components.reactionsummary_ReactionSummaryViewContent_Night_0_en",0,], -["features.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_Day_0_en","features.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_Night_0_en",20504,], -["features.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_Day_1_en","features.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_Night_1_en",20504,], -["features.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_Day_2_en","features.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_Night_2_en",20504,], -["features.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_Day_3_en","features.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_Night_3_en",20504,], -["features.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_Day_4_en","features.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_Night_4_en",20504,], -["features.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_Day_5_en","features.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_Night_5_en",20504,], -["features.securebackup.impl.setup.views_RecoveryKeyView_Day_0_en","features.securebackup.impl.setup.views_RecoveryKeyView_Night_0_en",20504,], -["features.securebackup.impl.setup.views_RecoveryKeyView_Day_10_en","features.securebackup.impl.setup.views_RecoveryKeyView_Night_10_en",20504,], -["features.securebackup.impl.setup.views_RecoveryKeyView_Day_11_en","features.securebackup.impl.setup.views_RecoveryKeyView_Night_11_en",20504,], -["features.securebackup.impl.setup.views_RecoveryKeyView_Day_12_en","features.securebackup.impl.setup.views_RecoveryKeyView_Night_12_en",20504,], -["features.securebackup.impl.setup.views_RecoveryKeyView_Day_13_en","features.securebackup.impl.setup.views_RecoveryKeyView_Night_13_en",20504,], -["features.securebackup.impl.setup.views_RecoveryKeyView_Day_14_en","features.securebackup.impl.setup.views_RecoveryKeyView_Night_14_en",20504,], -["features.securebackup.impl.setup.views_RecoveryKeyView_Day_1_en","features.securebackup.impl.setup.views_RecoveryKeyView_Night_1_en",20504,], -["features.securebackup.impl.setup.views_RecoveryKeyView_Day_2_en","features.securebackup.impl.setup.views_RecoveryKeyView_Night_2_en",20504,], -["features.securebackup.impl.setup.views_RecoveryKeyView_Day_3_en","features.securebackup.impl.setup.views_RecoveryKeyView_Night_3_en",20504,], -["features.securebackup.impl.setup.views_RecoveryKeyView_Day_4_en","features.securebackup.impl.setup.views_RecoveryKeyView_Night_4_en",20504,], -["features.securebackup.impl.setup.views_RecoveryKeyView_Day_5_en","features.securebackup.impl.setup.views_RecoveryKeyView_Night_5_en",20504,], -["features.securebackup.impl.setup.views_RecoveryKeyView_Day_6_en","features.securebackup.impl.setup.views_RecoveryKeyView_Night_6_en",20504,], -["features.securebackup.impl.setup.views_RecoveryKeyView_Day_7_en","features.securebackup.impl.setup.views_RecoveryKeyView_Night_7_en",20504,], -["features.securebackup.impl.setup.views_RecoveryKeyView_Day_8_en","features.securebackup.impl.setup.views_RecoveryKeyView_Night_8_en",20504,], -["features.securebackup.impl.setup.views_RecoveryKeyView_Day_9_en","features.securebackup.impl.setup.views_RecoveryKeyView_Night_9_en",20504,], +["features.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_Day_0_en","features.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_Night_0_en",20511,], +["features.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_Day_1_en","features.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_Night_1_en",20511,], +["features.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_Day_2_en","features.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_Night_2_en",20511,], +["features.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_Day_3_en","features.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_Night_3_en",20511,], +["features.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_Day_4_en","features.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_Night_4_en",20511,], +["features.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_Day_5_en","features.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_Night_5_en",20511,], +["features.securebackup.impl.setup.views_RecoveryKeyView_Day_0_en","features.securebackup.impl.setup.views_RecoveryKeyView_Night_0_en",20511,], +["features.securebackup.impl.setup.views_RecoveryKeyView_Day_10_en","features.securebackup.impl.setup.views_RecoveryKeyView_Night_10_en",20511,], +["features.securebackup.impl.setup.views_RecoveryKeyView_Day_11_en","features.securebackup.impl.setup.views_RecoveryKeyView_Night_11_en",20511,], +["features.securebackup.impl.setup.views_RecoveryKeyView_Day_12_en","features.securebackup.impl.setup.views_RecoveryKeyView_Night_12_en",20511,], +["features.securebackup.impl.setup.views_RecoveryKeyView_Day_13_en","features.securebackup.impl.setup.views_RecoveryKeyView_Night_13_en",20511,], +["features.securebackup.impl.setup.views_RecoveryKeyView_Day_14_en","features.securebackup.impl.setup.views_RecoveryKeyView_Night_14_en",20511,], +["features.securebackup.impl.setup.views_RecoveryKeyView_Day_1_en","features.securebackup.impl.setup.views_RecoveryKeyView_Night_1_en",20511,], +["features.securebackup.impl.setup.views_RecoveryKeyView_Day_2_en","features.securebackup.impl.setup.views_RecoveryKeyView_Night_2_en",20511,], +["features.securebackup.impl.setup.views_RecoveryKeyView_Day_3_en","features.securebackup.impl.setup.views_RecoveryKeyView_Night_3_en",20511,], +["features.securebackup.impl.setup.views_RecoveryKeyView_Day_4_en","features.securebackup.impl.setup.views_RecoveryKeyView_Night_4_en",20511,], +["features.securebackup.impl.setup.views_RecoveryKeyView_Day_5_en","features.securebackup.impl.setup.views_RecoveryKeyView_Night_5_en",20511,], +["features.securebackup.impl.setup.views_RecoveryKeyView_Day_6_en","features.securebackup.impl.setup.views_RecoveryKeyView_Night_6_en",20511,], +["features.securebackup.impl.setup.views_RecoveryKeyView_Day_7_en","features.securebackup.impl.setup.views_RecoveryKeyView_Night_7_en",20511,], +["features.securebackup.impl.setup.views_RecoveryKeyView_Day_8_en","features.securebackup.impl.setup.views_RecoveryKeyView_Night_8_en",20511,], +["features.securebackup.impl.setup.views_RecoveryKeyView_Day_9_en","features.securebackup.impl.setup.views_RecoveryKeyView_Night_9_en",20511,], ["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",20504,], -["features.messages.impl.report_ReportMessageView_Day_1_en","features.messages.impl.report_ReportMessageView_Night_1_en",20504,], -["features.messages.impl.report_ReportMessageView_Day_2_en","features.messages.impl.report_ReportMessageView_Night_2_en",20504,], -["features.messages.impl.report_ReportMessageView_Day_3_en","features.messages.impl.report_ReportMessageView_Night_3_en",20504,], -["features.messages.impl.report_ReportMessageView_Day_4_en","features.messages.impl.report_ReportMessageView_Night_4_en",20504,], -["features.messages.impl.report_ReportMessageView_Day_5_en","features.messages.impl.report_ReportMessageView_Night_5_en",20504,], -["features.reportroom.impl_ReportRoomView_Day_0_en","features.reportroom.impl_ReportRoomView_Night_0_en",20504,], -["features.reportroom.impl_ReportRoomView_Day_1_en","features.reportroom.impl_ReportRoomView_Night_1_en",20504,], -["features.reportroom.impl_ReportRoomView_Day_2_en","features.reportroom.impl_ReportRoomView_Night_2_en",20504,], -["features.reportroom.impl_ReportRoomView_Day_3_en","features.reportroom.impl_ReportRoomView_Night_3_en",20504,], -["features.reportroom.impl_ReportRoomView_Day_4_en","features.reportroom.impl_ReportRoomView_Night_4_en",20504,], -["features.securebackup.impl.reset.password_ResetIdentityPasswordView_Day_0_en","features.securebackup.impl.reset.password_ResetIdentityPasswordView_Night_0_en",20504,], -["features.securebackup.impl.reset.password_ResetIdentityPasswordView_Day_1_en","features.securebackup.impl.reset.password_ResetIdentityPasswordView_Night_1_en",20504,], -["features.securebackup.impl.reset.password_ResetIdentityPasswordView_Day_2_en","features.securebackup.impl.reset.password_ResetIdentityPasswordView_Night_2_en",20504,], -["features.securebackup.impl.reset.password_ResetIdentityPasswordView_Day_3_en","features.securebackup.impl.reset.password_ResetIdentityPasswordView_Night_3_en",20504,], -["features.securebackup.impl.reset.root_ResetIdentityRootView_Day_0_en","features.securebackup.impl.reset.root_ResetIdentityRootView_Night_0_en",20504,], -["features.securebackup.impl.reset.root_ResetIdentityRootView_Day_1_en","features.securebackup.impl.reset.root_ResetIdentityRootView_Night_1_en",20504,], +["features.messages.impl.report_ReportMessageView_Day_0_en","features.messages.impl.report_ReportMessageView_Night_0_en",20511,], +["features.messages.impl.report_ReportMessageView_Day_1_en","features.messages.impl.report_ReportMessageView_Night_1_en",20511,], +["features.messages.impl.report_ReportMessageView_Day_2_en","features.messages.impl.report_ReportMessageView_Night_2_en",20511,], +["features.messages.impl.report_ReportMessageView_Day_3_en","features.messages.impl.report_ReportMessageView_Night_3_en",20511,], +["features.messages.impl.report_ReportMessageView_Day_4_en","features.messages.impl.report_ReportMessageView_Night_4_en",20511,], +["features.messages.impl.report_ReportMessageView_Day_5_en","features.messages.impl.report_ReportMessageView_Night_5_en",20511,], +["features.reportroom.impl_ReportRoomView_Day_0_en","features.reportroom.impl_ReportRoomView_Night_0_en",20511,], +["features.reportroom.impl_ReportRoomView_Day_1_en","features.reportroom.impl_ReportRoomView_Night_1_en",20511,], +["features.reportroom.impl_ReportRoomView_Day_2_en","features.reportroom.impl_ReportRoomView_Night_2_en",20511,], +["features.reportroom.impl_ReportRoomView_Day_3_en","features.reportroom.impl_ReportRoomView_Night_3_en",20511,], +["features.reportroom.impl_ReportRoomView_Day_4_en","features.reportroom.impl_ReportRoomView_Night_4_en",20511,], +["features.securebackup.impl.reset.password_ResetIdentityPasswordView_Day_0_en","features.securebackup.impl.reset.password_ResetIdentityPasswordView_Night_0_en",20511,], +["features.securebackup.impl.reset.password_ResetIdentityPasswordView_Day_1_en","features.securebackup.impl.reset.password_ResetIdentityPasswordView_Night_1_en",20511,], +["features.securebackup.impl.reset.password_ResetIdentityPasswordView_Day_2_en","features.securebackup.impl.reset.password_ResetIdentityPasswordView_Night_2_en",20511,], +["features.securebackup.impl.reset.password_ResetIdentityPasswordView_Day_3_en","features.securebackup.impl.reset.password_ResetIdentityPasswordView_Night_3_en",20511,], +["features.securebackup.impl.reset.root_ResetIdentityRootView_Day_0_en","features.securebackup.impl.reset.root_ResetIdentityRootView_Night_0_en",20511,], +["features.securebackup.impl.reset.root_ResetIdentityRootView_Day_1_en","features.securebackup.impl.reset.root_ResetIdentityRootView_Night_1_en",20511,], ["features.messages.impl.crypto.sendfailure.resolve_ResolveVerifiedUserSendFailureView_Day_0_en","features.messages.impl.crypto.sendfailure.resolve_ResolveVerifiedUserSendFailureView_Night_0_en",0,], -["features.messages.impl.crypto.sendfailure.resolve_ResolveVerifiedUserSendFailureView_Day_1_en","features.messages.impl.crypto.sendfailure.resolve_ResolveVerifiedUserSendFailureView_Night_1_en",20504,], -["features.messages.impl.crypto.sendfailure.resolve_ResolveVerifiedUserSendFailureView_Day_2_en","features.messages.impl.crypto.sendfailure.resolve_ResolveVerifiedUserSendFailureView_Night_2_en",20504,], -["libraries.designsystem.components.dialogs_RetryDialogContent_Dialogs_en","",20504,], -["libraries.designsystem.components.dialogs_RetryDialog_Day_0_en","libraries.designsystem.components.dialogs_RetryDialog_Night_0_en",20504,], -["features.rolesandpermissions.impl.root_RolesAndPermissionsView_Day_0_en","features.rolesandpermissions.impl.root_RolesAndPermissionsView_Night_0_en",20504,], -["features.rolesandpermissions.impl.root_RolesAndPermissionsView_Day_1_en","features.rolesandpermissions.impl.root_RolesAndPermissionsView_Night_1_en",20504,], -["features.rolesandpermissions.impl.root_RolesAndPermissionsView_Day_2_en","features.rolesandpermissions.impl.root_RolesAndPermissionsView_Night_2_en",20504,], -["features.rolesandpermissions.impl.root_RolesAndPermissionsView_Day_3_en","features.rolesandpermissions.impl.root_RolesAndPermissionsView_Night_3_en",20504,], -["features.rolesandpermissions.impl.root_RolesAndPermissionsView_Day_4_en","features.rolesandpermissions.impl.root_RolesAndPermissionsView_Night_4_en",20504,], -["features.rolesandpermissions.impl.root_RolesAndPermissionsView_Day_5_en","features.rolesandpermissions.impl.root_RolesAndPermissionsView_Night_5_en",20504,], -["features.rolesandpermissions.impl.root_RolesAndPermissionsView_Day_6_en","features.rolesandpermissions.impl.root_RolesAndPermissionsView_Night_6_en",20504,], -["features.rolesandpermissions.impl.root_RolesAndPermissionsView_Day_7_en","features.rolesandpermissions.impl.root_RolesAndPermissionsView_Night_7_en",20504,], -["features.rolesandpermissions.impl.root_RolesAndPermissionsView_Day_8_en","features.rolesandpermissions.impl.root_RolesAndPermissionsView_Night_8_en",20504,], +["features.messages.impl.crypto.sendfailure.resolve_ResolveVerifiedUserSendFailureView_Day_1_en","features.messages.impl.crypto.sendfailure.resolve_ResolveVerifiedUserSendFailureView_Night_1_en",20511,], +["features.messages.impl.crypto.sendfailure.resolve_ResolveVerifiedUserSendFailureView_Day_2_en","features.messages.impl.crypto.sendfailure.resolve_ResolveVerifiedUserSendFailureView_Night_2_en",20511,], +["libraries.designsystem.components.dialogs_RetryDialogContent_Dialogs_en","",20511,], +["libraries.designsystem.components.dialogs_RetryDialog_Day_0_en","libraries.designsystem.components.dialogs_RetryDialog_Night_0_en",20511,], +["features.rolesandpermissions.impl.root_RolesAndPermissionsView_Day_0_en","features.rolesandpermissions.impl.root_RolesAndPermissionsView_Night_0_en",20511,], +["features.rolesandpermissions.impl.root_RolesAndPermissionsView_Day_1_en","features.rolesandpermissions.impl.root_RolesAndPermissionsView_Night_1_en",20511,], +["features.rolesandpermissions.impl.root_RolesAndPermissionsView_Day_2_en","features.rolesandpermissions.impl.root_RolesAndPermissionsView_Night_2_en",20511,], +["features.rolesandpermissions.impl.root_RolesAndPermissionsView_Day_3_en","features.rolesandpermissions.impl.root_RolesAndPermissionsView_Night_3_en",20511,], +["features.rolesandpermissions.impl.root_RolesAndPermissionsView_Day_4_en","features.rolesandpermissions.impl.root_RolesAndPermissionsView_Night_4_en",20511,], +["features.rolesandpermissions.impl.root_RolesAndPermissionsView_Day_5_en","features.rolesandpermissions.impl.root_RolesAndPermissionsView_Night_5_en",20511,], +["features.rolesandpermissions.impl.root_RolesAndPermissionsView_Day_6_en","features.rolesandpermissions.impl.root_RolesAndPermissionsView_Night_6_en",20511,], +["features.rolesandpermissions.impl.root_RolesAndPermissionsView_Day_7_en","features.rolesandpermissions.impl.root_RolesAndPermissionsView_Night_7_en",20511,], +["features.rolesandpermissions.impl.root_RolesAndPermissionsView_Day_8_en","features.rolesandpermissions.impl.root_RolesAndPermissionsView_Night_8_en",20511,], ["libraries.matrix.ui.room.address_RoomAddressField_Day_0_en","libraries.matrix.ui.room.address_RoomAddressField_Night_0_en",0,], ["features.roomaliasresolver.impl_RoomAliasResolverView_Day_0_en","features.roomaliasresolver.impl_RoomAliasResolverView_Night_0_en",0,], -["features.roomaliasresolver.impl_RoomAliasResolverView_Day_1_en","features.roomaliasresolver.impl_RoomAliasResolverView_Night_1_en",20504,], -["features.roomaliasresolver.impl_RoomAliasResolverView_Day_2_en","features.roomaliasresolver.impl_RoomAliasResolverView_Night_2_en",20504,], +["features.roomaliasresolver.impl_RoomAliasResolverView_Day_1_en","features.roomaliasresolver.impl_RoomAliasResolverView_Night_1_en",20511,], +["features.roomaliasresolver.impl_RoomAliasResolverView_Day_2_en","features.roomaliasresolver.impl_RoomAliasResolverView_Night_2_en",20511,], ["features.roomdetails.impl_RoomDetailsA11y_en","",0,], -["features.roomdetails.impl_RoomDetailsDark_0_en","",20504,], -["features.roomdetails.impl_RoomDetailsDark_10_en","",20504,], -["features.roomdetails.impl_RoomDetailsDark_11_en","",20504,], -["features.roomdetails.impl_RoomDetailsDark_12_en","",20504,], -["features.roomdetails.impl_RoomDetailsDark_13_en","",20504,], -["features.roomdetails.impl_RoomDetailsDark_14_en","",20504,], -["features.roomdetails.impl_RoomDetailsDark_15_en","",20504,], -["features.roomdetails.impl_RoomDetailsDark_16_en","",20504,], -["features.roomdetails.impl_RoomDetailsDark_17_en","",20504,], -["features.roomdetails.impl_RoomDetailsDark_18_en","",20504,], -["features.roomdetails.impl_RoomDetailsDark_19_en","",20504,], -["features.roomdetails.impl_RoomDetailsDark_1_en","",20504,], -["features.roomdetails.impl_RoomDetailsDark_20_en","",20504,], -["features.roomdetails.impl_RoomDetailsDark_21_en","",20504,], -["features.roomdetails.impl_RoomDetailsDark_22_en","",20504,], -["features.roomdetails.impl_RoomDetailsDark_2_en","",20504,], -["features.roomdetails.impl_RoomDetailsDark_3_en","",20504,], -["features.roomdetails.impl_RoomDetailsDark_4_en","",20504,], -["features.roomdetails.impl_RoomDetailsDark_5_en","",20504,], -["features.roomdetails.impl_RoomDetailsDark_6_en","",20504,], -["features.roomdetails.impl_RoomDetailsDark_7_en","",20504,], -["features.roomdetails.impl_RoomDetailsDark_8_en","",20504,], -["features.roomdetails.impl_RoomDetailsDark_9_en","",20504,], -["features.roomdetailsedit.impl_RoomDetailsEditView_Day_0_en","features.roomdetailsedit.impl_RoomDetailsEditView_Night_0_en",20504,], -["features.roomdetailsedit.impl_RoomDetailsEditView_Day_1_en","features.roomdetailsedit.impl_RoomDetailsEditView_Night_1_en",20504,], -["features.roomdetailsedit.impl_RoomDetailsEditView_Day_2_en","features.roomdetailsedit.impl_RoomDetailsEditView_Night_2_en",20504,], -["features.roomdetailsedit.impl_RoomDetailsEditView_Day_3_en","features.roomdetailsedit.impl_RoomDetailsEditView_Night_3_en",20504,], -["features.roomdetailsedit.impl_RoomDetailsEditView_Day_4_en","features.roomdetailsedit.impl_RoomDetailsEditView_Night_4_en",20504,], -["features.roomdetailsedit.impl_RoomDetailsEditView_Day_5_en","features.roomdetailsedit.impl_RoomDetailsEditView_Night_5_en",20504,], -["features.roomdetailsedit.impl_RoomDetailsEditView_Day_6_en","features.roomdetailsedit.impl_RoomDetailsEditView_Night_6_en",20504,], -["features.roomdetailsedit.impl_RoomDetailsEditView_Day_7_en","features.roomdetailsedit.impl_RoomDetailsEditView_Night_7_en",20504,], -["features.roomdetailsedit.impl_RoomDetailsEditView_Day_8_en","features.roomdetailsedit.impl_RoomDetailsEditView_Night_8_en",20504,], -["features.roomdetailsedit.impl_RoomDetailsEditView_Day_9_en","features.roomdetailsedit.impl_RoomDetailsEditView_Night_9_en",20504,], -["features.roomdetails.impl_RoomDetails_0_en","",20504,], -["features.roomdetails.impl_RoomDetails_10_en","",20504,], -["features.roomdetails.impl_RoomDetails_11_en","",20504,], -["features.roomdetails.impl_RoomDetails_12_en","",20504,], -["features.roomdetails.impl_RoomDetails_13_en","",20504,], -["features.roomdetails.impl_RoomDetails_14_en","",20504,], -["features.roomdetails.impl_RoomDetails_15_en","",20504,], -["features.roomdetails.impl_RoomDetails_16_en","",20504,], -["features.roomdetails.impl_RoomDetails_17_en","",20504,], -["features.roomdetails.impl_RoomDetails_18_en","",20504,], -["features.roomdetails.impl_RoomDetails_19_en","",20504,], -["features.roomdetails.impl_RoomDetails_1_en","",20504,], -["features.roomdetails.impl_RoomDetails_20_en","",20504,], -["features.roomdetails.impl_RoomDetails_21_en","",20504,], -["features.roomdetails.impl_RoomDetails_22_en","",20504,], -["features.roomdetails.impl_RoomDetails_2_en","",20504,], -["features.roomdetails.impl_RoomDetails_3_en","",20504,], -["features.roomdetails.impl_RoomDetails_4_en","",20504,], -["features.roomdetails.impl_RoomDetails_5_en","",20504,], -["features.roomdetails.impl_RoomDetails_6_en","",20504,], -["features.roomdetails.impl_RoomDetails_7_en","",20504,], -["features.roomdetails.impl_RoomDetails_8_en","",20504,], -["features.roomdetails.impl_RoomDetails_9_en","",20504,], -["features.roomdirectory.impl.root_RoomDirectoryView_Day_0_en","features.roomdirectory.impl.root_RoomDirectoryView_Night_0_en",20504,], -["features.roomdirectory.impl.root_RoomDirectoryView_Day_1_en","features.roomdirectory.impl.root_RoomDirectoryView_Night_1_en",20504,], -["features.roomdirectory.impl.root_RoomDirectoryView_Day_2_en","features.roomdirectory.impl.root_RoomDirectoryView_Night_2_en",20504,], -["features.roomdetails.impl.invite_RoomInviteMembersView_Day_0_en","features.roomdetails.impl.invite_RoomInviteMembersView_Night_0_en",20504,], -["features.roomdetails.impl.invite_RoomInviteMembersView_Day_1_en","features.roomdetails.impl.invite_RoomInviteMembersView_Night_1_en",20504,], -["features.roomdetails.impl.invite_RoomInviteMembersView_Day_2_en","features.roomdetails.impl.invite_RoomInviteMembersView_Night_2_en",20504,], -["features.roomdetails.impl.invite_RoomInviteMembersView_Day_3_en","features.roomdetails.impl.invite_RoomInviteMembersView_Night_3_en",20504,], -["features.home.impl.components_RoomListContentView_Day_0_en","features.home.impl.components_RoomListContentView_Night_0_en",20504,], -["features.home.impl.components_RoomListContentView_Day_1_en","features.home.impl.components_RoomListContentView_Night_1_en",20504,], +["features.roomdetails.impl_RoomDetailsDark_0_en","",20511,], +["features.roomdetails.impl_RoomDetailsDark_10_en","",20511,], +["features.roomdetails.impl_RoomDetailsDark_11_en","",20511,], +["features.roomdetails.impl_RoomDetailsDark_12_en","",20511,], +["features.roomdetails.impl_RoomDetailsDark_13_en","",20511,], +["features.roomdetails.impl_RoomDetailsDark_14_en","",20511,], +["features.roomdetails.impl_RoomDetailsDark_15_en","",20511,], +["features.roomdetails.impl_RoomDetailsDark_16_en","",20511,], +["features.roomdetails.impl_RoomDetailsDark_17_en","",20511,], +["features.roomdetails.impl_RoomDetailsDark_18_en","",20511,], +["features.roomdetails.impl_RoomDetailsDark_19_en","",20511,], +["features.roomdetails.impl_RoomDetailsDark_1_en","",20511,], +["features.roomdetails.impl_RoomDetailsDark_20_en","",20511,], +["features.roomdetails.impl_RoomDetailsDark_21_en","",20511,], +["features.roomdetails.impl_RoomDetailsDark_22_en","",20511,], +["features.roomdetails.impl_RoomDetailsDark_2_en","",20511,], +["features.roomdetails.impl_RoomDetailsDark_3_en","",20511,], +["features.roomdetails.impl_RoomDetailsDark_4_en","",20511,], +["features.roomdetails.impl_RoomDetailsDark_5_en","",20511,], +["features.roomdetails.impl_RoomDetailsDark_6_en","",20511,], +["features.roomdetails.impl_RoomDetailsDark_7_en","",20511,], +["features.roomdetails.impl_RoomDetailsDark_8_en","",20511,], +["features.roomdetails.impl_RoomDetailsDark_9_en","",20511,], +["features.roomdetailsedit.impl_RoomDetailsEditView_Day_0_en","features.roomdetailsedit.impl_RoomDetailsEditView_Night_0_en",20511,], +["features.roomdetailsedit.impl_RoomDetailsEditView_Day_1_en","features.roomdetailsedit.impl_RoomDetailsEditView_Night_1_en",20511,], +["features.roomdetailsedit.impl_RoomDetailsEditView_Day_2_en","features.roomdetailsedit.impl_RoomDetailsEditView_Night_2_en",20511,], +["features.roomdetailsedit.impl_RoomDetailsEditView_Day_3_en","features.roomdetailsedit.impl_RoomDetailsEditView_Night_3_en",20511,], +["features.roomdetailsedit.impl_RoomDetailsEditView_Day_4_en","features.roomdetailsedit.impl_RoomDetailsEditView_Night_4_en",20511,], +["features.roomdetailsedit.impl_RoomDetailsEditView_Day_5_en","features.roomdetailsedit.impl_RoomDetailsEditView_Night_5_en",20511,], +["features.roomdetailsedit.impl_RoomDetailsEditView_Day_6_en","features.roomdetailsedit.impl_RoomDetailsEditView_Night_6_en",20511,], +["features.roomdetailsedit.impl_RoomDetailsEditView_Day_7_en","features.roomdetailsedit.impl_RoomDetailsEditView_Night_7_en",20511,], +["features.roomdetailsedit.impl_RoomDetailsEditView_Day_8_en","features.roomdetailsedit.impl_RoomDetailsEditView_Night_8_en",20511,], +["features.roomdetailsedit.impl_RoomDetailsEditView_Day_9_en","features.roomdetailsedit.impl_RoomDetailsEditView_Night_9_en",20511,], +["features.roomdetails.impl_RoomDetails_0_en","",20511,], +["features.roomdetails.impl_RoomDetails_10_en","",20511,], +["features.roomdetails.impl_RoomDetails_11_en","",20511,], +["features.roomdetails.impl_RoomDetails_12_en","",20511,], +["features.roomdetails.impl_RoomDetails_13_en","",20511,], +["features.roomdetails.impl_RoomDetails_14_en","",20511,], +["features.roomdetails.impl_RoomDetails_15_en","",20511,], +["features.roomdetails.impl_RoomDetails_16_en","",20511,], +["features.roomdetails.impl_RoomDetails_17_en","",20511,], +["features.roomdetails.impl_RoomDetails_18_en","",20511,], +["features.roomdetails.impl_RoomDetails_19_en","",20511,], +["features.roomdetails.impl_RoomDetails_1_en","",20511,], +["features.roomdetails.impl_RoomDetails_20_en","",20511,], +["features.roomdetails.impl_RoomDetails_21_en","",20511,], +["features.roomdetails.impl_RoomDetails_22_en","",20511,], +["features.roomdetails.impl_RoomDetails_2_en","",20511,], +["features.roomdetails.impl_RoomDetails_3_en","",20511,], +["features.roomdetails.impl_RoomDetails_4_en","",20511,], +["features.roomdetails.impl_RoomDetails_5_en","",20511,], +["features.roomdetails.impl_RoomDetails_6_en","",20511,], +["features.roomdetails.impl_RoomDetails_7_en","",20511,], +["features.roomdetails.impl_RoomDetails_8_en","",20511,], +["features.roomdetails.impl_RoomDetails_9_en","",20511,], +["features.roomdirectory.impl.root_RoomDirectoryView_Day_0_en","features.roomdirectory.impl.root_RoomDirectoryView_Night_0_en",20511,], +["features.roomdirectory.impl.root_RoomDirectoryView_Day_1_en","features.roomdirectory.impl.root_RoomDirectoryView_Night_1_en",20511,], +["features.roomdirectory.impl.root_RoomDirectoryView_Day_2_en","features.roomdirectory.impl.root_RoomDirectoryView_Night_2_en",20511,], +["features.roomdetails.impl.invite_RoomInviteMembersView_Day_0_en","features.roomdetails.impl.invite_RoomInviteMembersView_Night_0_en",20511,], +["features.roomdetails.impl.invite_RoomInviteMembersView_Day_1_en","features.roomdetails.impl.invite_RoomInviteMembersView_Night_1_en",20511,], +["features.roomdetails.impl.invite_RoomInviteMembersView_Day_2_en","features.roomdetails.impl.invite_RoomInviteMembersView_Night_2_en",20511,], +["features.roomdetails.impl.invite_RoomInviteMembersView_Day_3_en","features.roomdetails.impl.invite_RoomInviteMembersView_Night_3_en",20511,], +["features.home.impl.components_RoomListContentView_Day_0_en","features.home.impl.components_RoomListContentView_Night_0_en",20511,], +["features.home.impl.components_RoomListContentView_Day_1_en","features.home.impl.components_RoomListContentView_Night_1_en",20511,], ["features.home.impl.components_RoomListContentView_Day_2_en","features.home.impl.components_RoomListContentView_Night_2_en",0,], -["features.home.impl.components_RoomListContentView_Day_3_en","features.home.impl.components_RoomListContentView_Night_3_en",20504,], -["features.home.impl.components_RoomListContentView_Day_4_en","features.home.impl.components_RoomListContentView_Night_4_en",20504,], -["features.home.impl.components_RoomListContentView_Day_5_en","features.home.impl.components_RoomListContentView_Night_5_en",20504,], -["features.home.impl.roomlist_RoomListDeclineInviteMenuContent_Day_0_en","features.home.impl.roomlist_RoomListDeclineInviteMenuContent_Night_0_en",20504,], -["features.home.impl.filters_RoomListFiltersView_Day_0_en","features.home.impl.filters_RoomListFiltersView_Night_0_en",20504,], -["features.home.impl.filters_RoomListFiltersView_Day_1_en","features.home.impl.filters_RoomListFiltersView_Night_1_en",20504,], -["features.home.impl.roomlist_RoomListModalBottomSheetContent_Day_0_en","features.home.impl.roomlist_RoomListModalBottomSheetContent_Night_0_en",20504,], -["features.home.impl.roomlist_RoomListModalBottomSheetContent_Day_1_en","features.home.impl.roomlist_RoomListModalBottomSheetContent_Night_1_en",20504,], -["features.home.impl.roomlist_RoomListModalBottomSheetContent_Day_2_en","features.home.impl.roomlist_RoomListModalBottomSheetContent_Night_2_en",20504,], +["features.home.impl.components_RoomListContentView_Day_3_en","features.home.impl.components_RoomListContentView_Night_3_en",20511,], +["features.home.impl.components_RoomListContentView_Day_4_en","features.home.impl.components_RoomListContentView_Night_4_en",20511,], +["features.home.impl.components_RoomListContentView_Day_5_en","features.home.impl.components_RoomListContentView_Night_5_en",20511,], +["features.home.impl.roomlist_RoomListDeclineInviteMenuContent_Day_0_en","features.home.impl.roomlist_RoomListDeclineInviteMenuContent_Night_0_en",20511,], +["features.home.impl.filters_RoomListFiltersView_Day_0_en","features.home.impl.filters_RoomListFiltersView_Night_0_en",20511,], +["features.home.impl.filters_RoomListFiltersView_Day_1_en","features.home.impl.filters_RoomListFiltersView_Night_1_en",20511,], +["features.home.impl.roomlist_RoomListModalBottomSheetContent_Day_0_en","features.home.impl.roomlist_RoomListModalBottomSheetContent_Night_0_en",20511,], +["features.home.impl.roomlist_RoomListModalBottomSheetContent_Day_1_en","features.home.impl.roomlist_RoomListModalBottomSheetContent_Night_1_en",20511,], +["features.home.impl.roomlist_RoomListModalBottomSheetContent_Day_2_en","features.home.impl.roomlist_RoomListModalBottomSheetContent_Night_2_en",20511,], ["features.home.impl.search_RoomListSearchContent_Day_0_en","features.home.impl.search_RoomListSearchContent_Night_0_en",0,], -["features.home.impl.search_RoomListSearchContent_Day_1_en","features.home.impl.search_RoomListSearchContent_Night_1_en",20504,], -["features.roomdetails.impl.members_RoomMemberListView_Day_0_en","features.roomdetails.impl.members_RoomMemberListView_Night_0_en",20504,], -["features.roomdetails.impl.members_RoomMemberListView_Day_1_en","features.roomdetails.impl.members_RoomMemberListView_Night_1_en",20504,], -["features.roomdetails.impl.members_RoomMemberListView_Day_2_en","features.roomdetails.impl.members_RoomMemberListView_Night_2_en",20504,], -["features.roomdetails.impl.members_RoomMemberListView_Day_3_en","features.roomdetails.impl.members_RoomMemberListView_Night_3_en",20504,], -["features.roomdetails.impl.members_RoomMemberListView_Day_4_en","features.roomdetails.impl.members_RoomMemberListView_Night_4_en",20504,], -["features.roomdetails.impl.members_RoomMemberListView_Day_5_en","features.roomdetails.impl.members_RoomMemberListView_Night_5_en",20504,], -["features.roomdetails.impl.members_RoomMemberListView_Day_6_en","features.roomdetails.impl.members_RoomMemberListView_Night_6_en",20504,], -["features.roommembermoderation.impl_RoomMemberModerationView_Day_0_en","features.roommembermoderation.impl_RoomMemberModerationView_Night_0_en",20504,], -["features.roommembermoderation.impl_RoomMemberModerationView_Day_1_en","features.roommembermoderation.impl_RoomMemberModerationView_Night_1_en",20504,], -["features.roommembermoderation.impl_RoomMemberModerationView_Day_2_en","features.roommembermoderation.impl_RoomMemberModerationView_Night_2_en",20504,], -["features.roommembermoderation.impl_RoomMemberModerationView_Day_3_en","features.roommembermoderation.impl_RoomMemberModerationView_Night_3_en",20504,], -["features.roommembermoderation.impl_RoomMemberModerationView_Day_4_en","features.roommembermoderation.impl_RoomMemberModerationView_Night_4_en",20504,], -["features.roommembermoderation.impl_RoomMemberModerationView_Day_5_en","features.roommembermoderation.impl_RoomMemberModerationView_Night_5_en",20504,], -["features.roommembermoderation.impl_RoomMemberModerationView_Day_6_en","features.roommembermoderation.impl_RoomMemberModerationView_Night_6_en",20504,], -["features.roommembermoderation.impl_RoomMemberModerationView_Day_7_en","features.roommembermoderation.impl_RoomMemberModerationView_Night_7_en",20504,], -["features.roommembermoderation.impl_RoomMemberModerationView_Day_8_en","features.roommembermoderation.impl_RoomMemberModerationView_Night_8_en",20504,], +["features.home.impl.search_RoomListSearchContent_Day_1_en","features.home.impl.search_RoomListSearchContent_Night_1_en",20511,], +["features.roomdetails.impl.members_RoomMemberListView_Day_0_en","features.roomdetails.impl.members_RoomMemberListView_Night_0_en",20511,], +["features.roomdetails.impl.members_RoomMemberListView_Day_1_en","features.roomdetails.impl.members_RoomMemberListView_Night_1_en",20511,], +["features.roomdetails.impl.members_RoomMemberListView_Day_2_en","features.roomdetails.impl.members_RoomMemberListView_Night_2_en",20511,], +["features.roomdetails.impl.members_RoomMemberListView_Day_3_en","features.roomdetails.impl.members_RoomMemberListView_Night_3_en",20511,], +["features.roomdetails.impl.members_RoomMemberListView_Day_4_en","features.roomdetails.impl.members_RoomMemberListView_Night_4_en",20511,], +["features.roomdetails.impl.members_RoomMemberListView_Day_5_en","features.roomdetails.impl.members_RoomMemberListView_Night_5_en",20511,], +["features.roomdetails.impl.members_RoomMemberListView_Day_6_en","features.roomdetails.impl.members_RoomMemberListView_Night_6_en",20511,], +["features.roommembermoderation.impl_RoomMemberModerationView_Day_0_en","features.roommembermoderation.impl_RoomMemberModerationView_Night_0_en",20511,], +["features.roommembermoderation.impl_RoomMemberModerationView_Day_1_en","features.roommembermoderation.impl_RoomMemberModerationView_Night_1_en",20511,], +["features.roommembermoderation.impl_RoomMemberModerationView_Day_2_en","features.roommembermoderation.impl_RoomMemberModerationView_Night_2_en",20511,], +["features.roommembermoderation.impl_RoomMemberModerationView_Day_3_en","features.roommembermoderation.impl_RoomMemberModerationView_Night_3_en",20511,], +["features.roommembermoderation.impl_RoomMemberModerationView_Day_4_en","features.roommembermoderation.impl_RoomMemberModerationView_Night_4_en",20511,], +["features.roommembermoderation.impl_RoomMemberModerationView_Day_5_en","features.roommembermoderation.impl_RoomMemberModerationView_Night_5_en",20511,], +["features.roommembermoderation.impl_RoomMemberModerationView_Day_6_en","features.roommembermoderation.impl_RoomMemberModerationView_Night_6_en",20511,], +["features.roommembermoderation.impl_RoomMemberModerationView_Day_7_en","features.roommembermoderation.impl_RoomMemberModerationView_Night_7_en",20511,], +["features.roommembermoderation.impl_RoomMemberModerationView_Day_8_en","features.roommembermoderation.impl_RoomMemberModerationView_Night_8_en",20511,], ["features.roommembermoderation.impl_RoomMemberModerationView_Day_9_en","features.roommembermoderation.impl_RoomMemberModerationView_Night_9_en",0,], -["features.roomdetails.impl.notificationsettings_RoomNotificationSettingsOption_Day_0_en","features.roomdetails.impl.notificationsettings_RoomNotificationSettingsOption_Night_0_en",20504,], -["features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Day_0_en","features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Night_0_en",20504,], -["features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Day_1_en","features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Night_1_en",20504,], -["features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Day_2_en","features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Night_2_en",20504,], -["features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Day_3_en","features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Night_3_en",20504,], -["features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Day_4_en","features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Night_4_en",20504,], -["features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Day_5_en","features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Night_5_en",20504,], -["features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Day_6_en","features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Night_6_en",20504,], +["features.roomdetails.impl.notificationsettings_RoomNotificationSettingsOption_Day_0_en","features.roomdetails.impl.notificationsettings_RoomNotificationSettingsOption_Night_0_en",20511,], +["features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Day_0_en","features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Night_0_en",20511,], +["features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Day_1_en","features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Night_1_en",20511,], +["features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Day_2_en","features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Night_2_en",20511,], +["features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Day_3_en","features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Night_3_en",20511,], +["features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Day_4_en","features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Night_4_en",20511,], +["features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Day_5_en","features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Night_5_en",20511,], +["features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Day_6_en","features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Night_6_en",20511,], ["libraries.designsystem.atomic.atoms_RoomPreviewAliasAtom_Day_0_en","libraries.designsystem.atomic.atoms_RoomPreviewAliasAtom_Night_0_en",0,], -["libraries.roomselect.impl_RoomSelectView_Day_0_en","libraries.roomselect.impl_RoomSelectView_Night_0_en",20504,], -["libraries.roomselect.impl_RoomSelectView_Day_1_en","libraries.roomselect.impl_RoomSelectView_Night_1_en",20504,], -["libraries.roomselect.impl_RoomSelectView_Day_2_en","libraries.roomselect.impl_RoomSelectView_Night_2_en",20504,], -["libraries.roomselect.impl_RoomSelectView_Day_3_en","libraries.roomselect.impl_RoomSelectView_Night_3_en",20504,], -["libraries.roomselect.impl_RoomSelectView_Day_4_en","libraries.roomselect.impl_RoomSelectView_Night_4_en",20504,], -["libraries.roomselect.impl_RoomSelectView_Day_5_en","libraries.roomselect.impl_RoomSelectView_Night_5_en",20504,], +["libraries.roomselect.impl_RoomSelectView_Day_0_en","libraries.roomselect.impl_RoomSelectView_Night_0_en",20511,], +["libraries.roomselect.impl_RoomSelectView_Day_1_en","libraries.roomselect.impl_RoomSelectView_Night_1_en",20511,], +["libraries.roomselect.impl_RoomSelectView_Day_2_en","libraries.roomselect.impl_RoomSelectView_Night_2_en",20511,], +["libraries.roomselect.impl_RoomSelectView_Day_3_en","libraries.roomselect.impl_RoomSelectView_Night_3_en",20511,], +["libraries.roomselect.impl_RoomSelectView_Day_4_en","libraries.roomselect.impl_RoomSelectView_Night_4_en",20511,], +["libraries.roomselect.impl_RoomSelectView_Day_5_en","libraries.roomselect.impl_RoomSelectView_Night_5_en",20511,], ["features.home.impl.components_RoomSummaryPlaceholderRow_Day_0_en","features.home.impl.components_RoomSummaryPlaceholderRow_Night_0_en",0,], ["features.home.impl.components_RoomSummaryRow_Day_0_en","features.home.impl.components_RoomSummaryRow_Night_0_en",0,], ["features.home.impl.components_RoomSummaryRow_Day_10_en","features.home.impl.components_RoomSummaryRow_Night_10_en",0,], @@ -1083,16 +1086,16 @@ export const screenshots = [ ["features.home.impl.components_RoomSummaryRow_Day_26_en","features.home.impl.components_RoomSummaryRow_Night_26_en",0,], ["features.home.impl.components_RoomSummaryRow_Day_27_en","features.home.impl.components_RoomSummaryRow_Night_27_en",0,], ["features.home.impl.components_RoomSummaryRow_Day_28_en","features.home.impl.components_RoomSummaryRow_Night_28_en",0,], -["features.home.impl.components_RoomSummaryRow_Day_29_en","features.home.impl.components_RoomSummaryRow_Night_29_en",20504,], -["features.home.impl.components_RoomSummaryRow_Day_2_en","features.home.impl.components_RoomSummaryRow_Night_2_en",20504,], -["features.home.impl.components_RoomSummaryRow_Day_30_en","features.home.impl.components_RoomSummaryRow_Night_30_en",20504,], -["features.home.impl.components_RoomSummaryRow_Day_31_en","features.home.impl.components_RoomSummaryRow_Night_31_en",20504,], -["features.home.impl.components_RoomSummaryRow_Day_32_en","features.home.impl.components_RoomSummaryRow_Night_32_en",20504,], -["features.home.impl.components_RoomSummaryRow_Day_33_en","features.home.impl.components_RoomSummaryRow_Night_33_en",20504,], -["features.home.impl.components_RoomSummaryRow_Day_34_en","features.home.impl.components_RoomSummaryRow_Night_34_en",20504,], -["features.home.impl.components_RoomSummaryRow_Day_35_en","features.home.impl.components_RoomSummaryRow_Night_35_en",20504,], +["features.home.impl.components_RoomSummaryRow_Day_29_en","features.home.impl.components_RoomSummaryRow_Night_29_en",20511,], +["features.home.impl.components_RoomSummaryRow_Day_2_en","features.home.impl.components_RoomSummaryRow_Night_2_en",20511,], +["features.home.impl.components_RoomSummaryRow_Day_30_en","features.home.impl.components_RoomSummaryRow_Night_30_en",20511,], +["features.home.impl.components_RoomSummaryRow_Day_31_en","features.home.impl.components_RoomSummaryRow_Night_31_en",20511,], +["features.home.impl.components_RoomSummaryRow_Day_32_en","features.home.impl.components_RoomSummaryRow_Night_32_en",20511,], +["features.home.impl.components_RoomSummaryRow_Day_33_en","features.home.impl.components_RoomSummaryRow_Night_33_en",20511,], +["features.home.impl.components_RoomSummaryRow_Day_34_en","features.home.impl.components_RoomSummaryRow_Night_34_en",20511,], +["features.home.impl.components_RoomSummaryRow_Day_35_en","features.home.impl.components_RoomSummaryRow_Night_35_en",20511,], ["features.home.impl.components_RoomSummaryRow_Day_36_en","features.home.impl.components_RoomSummaryRow_Night_36_en",0,], -["features.home.impl.components_RoomSummaryRow_Day_37_en","features.home.impl.components_RoomSummaryRow_Night_37_en",20504,], +["features.home.impl.components_RoomSummaryRow_Day_37_en","features.home.impl.components_RoomSummaryRow_Night_37_en",20511,], ["features.home.impl.components_RoomSummaryRow_Day_3_en","features.home.impl.components_RoomSummaryRow_Night_3_en",0,], ["features.home.impl.components_RoomSummaryRow_Day_4_en","features.home.impl.components_RoomSummaryRow_Night_4_en",0,], ["features.home.impl.components_RoomSummaryRow_Day_5_en","features.home.impl.components_RoomSummaryRow_Night_5_en",0,], @@ -1100,118 +1103,118 @@ export const screenshots = [ ["features.home.impl.components_RoomSummaryRow_Day_7_en","features.home.impl.components_RoomSummaryRow_Night_7_en",0,], ["features.home.impl.components_RoomSummaryRow_Day_8_en","features.home.impl.components_RoomSummaryRow_Night_8_en",0,], ["features.home.impl.components_RoomSummaryRow_Day_9_en","features.home.impl.components_RoomSummaryRow_Night_9_en",0,], -["appnav.root_RootView_Day_0_en","appnav.root_RootView_Night_0_en",20504,], -["appnav.root_RootView_Day_1_en","appnav.root_RootView_Night_1_en",20504,], -["appnav.root_RootView_Day_2_en","appnav.root_RootView_Night_2_en",20504,], +["appnav.root_RootView_Day_0_en","appnav.root_RootView_Night_0_en",20511,], +["appnav.root_RootView_Day_1_en","appnav.root_RootView_Night_1_en",20511,], +["appnav.root_RootView_Day_2_en","appnav.root_RootView_Night_2_en",20511,], ["appicon.enterprise_RoundIcon_en","",0,], ["appicon.element_RoundIcon_en","",0,], ["libraries.designsystem.atomic.atoms_RoundedIconAtom_Day_0_en","libraries.designsystem.atomic.atoms_RoundedIconAtom_Night_0_en",0,], -["features.verifysession.impl.emoji_SasEmojis_Day_0_en","features.verifysession.impl.emoji_SasEmojis_Night_0_en",20504,], -["libraries.designsystem.components.dialogs_SaveChangesDialog_Day_0_en","libraries.designsystem.components.dialogs_SaveChangesDialog_Night_0_en",20504,], -["features.linknewdevice.impl.screens.scan_ScanQrCodeView_Day_0_en","features.linknewdevice.impl.screens.scan_ScanQrCodeView_Night_0_en",20504,], -["features.linknewdevice.impl.screens.scan_ScanQrCodeView_Day_1_en","features.linknewdevice.impl.screens.scan_ScanQrCodeView_Night_1_en",20504,], -["features.linknewdevice.impl.screens.scan_ScanQrCodeView_Day_2_en","features.linknewdevice.impl.screens.scan_ScanQrCodeView_Night_2_en",20504,], -["features.linknewdevice.impl.screens.scan_ScanQrCodeView_Day_3_en","features.linknewdevice.impl.screens.scan_ScanQrCodeView_Night_3_en",20504,], -["features.login.impl.screens.searchaccountprovider_SearchAccountProviderView_Day_0_en","features.login.impl.screens.searchaccountprovider_SearchAccountProviderView_Night_0_en",20504,], -["features.login.impl.screens.searchaccountprovider_SearchAccountProviderView_Day_1_en","features.login.impl.screens.searchaccountprovider_SearchAccountProviderView_Night_1_en",20504,], +["features.verifysession.impl.emoji_SasEmojis_Day_0_en","features.verifysession.impl.emoji_SasEmojis_Night_0_en",20511,], +["libraries.designsystem.components.dialogs_SaveChangesDialog_Day_0_en","libraries.designsystem.components.dialogs_SaveChangesDialog_Night_0_en",20511,], +["features.linknewdevice.impl.screens.scan_ScanQrCodeView_Day_0_en","features.linknewdevice.impl.screens.scan_ScanQrCodeView_Night_0_en",20511,], +["features.linknewdevice.impl.screens.scan_ScanQrCodeView_Day_1_en","features.linknewdevice.impl.screens.scan_ScanQrCodeView_Night_1_en",20511,], +["features.linknewdevice.impl.screens.scan_ScanQrCodeView_Day_2_en","features.linknewdevice.impl.screens.scan_ScanQrCodeView_Night_2_en",20511,], +["features.linknewdevice.impl.screens.scan_ScanQrCodeView_Day_3_en","features.linknewdevice.impl.screens.scan_ScanQrCodeView_Night_3_en",20511,], +["features.login.impl.screens.searchaccountprovider_SearchAccountProviderView_Day_0_en","features.login.impl.screens.searchaccountprovider_SearchAccountProviderView_Night_0_en",20511,], +["features.login.impl.screens.searchaccountprovider_SearchAccountProviderView_Day_1_en","features.login.impl.screens.searchaccountprovider_SearchAccountProviderView_Night_1_en",20511,], ["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","",20504,], +["libraries.designsystem.theme.components_SearchBarActiveWithNoResults_Search_views_en","",20511,], ["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,], ["libraries.designsystem.theme.components_SearchFieldsDark_Search_views_en","",0,], ["libraries.designsystem.theme.components_SearchFieldsLight_Search_views_en","",0,], -["features.startchat.impl.components_SearchMultipleUsersResultItem_en","",20504,], -["features.startchat.impl.components_SearchSingleUserResultItem_en","",20504,], -["features.securebackup.impl.disable_SecureBackupDisableView_Day_0_en","features.securebackup.impl.disable_SecureBackupDisableView_Night_0_en",20504,], -["features.securebackup.impl.disable_SecureBackupDisableView_Day_1_en","features.securebackup.impl.disable_SecureBackupDisableView_Night_1_en",20504,], -["features.securebackup.impl.disable_SecureBackupDisableView_Day_2_en","features.securebackup.impl.disable_SecureBackupDisableView_Night_2_en",20504,], -["features.securebackup.impl.disable_SecureBackupDisableView_Day_3_en","features.securebackup.impl.disable_SecureBackupDisableView_Night_3_en",20504,], -["features.securebackup.impl.enter_SecureBackupEnterRecoveryKeyView_Day_0_en","features.securebackup.impl.enter_SecureBackupEnterRecoveryKeyView_Night_0_en",20504,], -["features.securebackup.impl.enter_SecureBackupEnterRecoveryKeyView_Day_1_en","features.securebackup.impl.enter_SecureBackupEnterRecoveryKeyView_Night_1_en",20504,], -["features.securebackup.impl.enter_SecureBackupEnterRecoveryKeyView_Day_2_en","features.securebackup.impl.enter_SecureBackupEnterRecoveryKeyView_Night_2_en",20504,], -["features.securebackup.impl.enter_SecureBackupEnterRecoveryKeyView_Day_3_en","features.securebackup.impl.enter_SecureBackupEnterRecoveryKeyView_Night_3_en",20504,], -["features.securebackup.impl.enter_SecureBackupEnterRecoveryKeyView_Day_4_en","features.securebackup.impl.enter_SecureBackupEnterRecoveryKeyView_Night_4_en",20504,], -["features.securebackup.impl.root_SecureBackupRootView_Day_0_en","features.securebackup.impl.root_SecureBackupRootView_Night_0_en",20504,], -["features.securebackup.impl.root_SecureBackupRootView_Day_10_en","features.securebackup.impl.root_SecureBackupRootView_Night_10_en",20504,], -["features.securebackup.impl.root_SecureBackupRootView_Day_11_en","features.securebackup.impl.root_SecureBackupRootView_Night_11_en",20504,], -["features.securebackup.impl.root_SecureBackupRootView_Day_12_en","features.securebackup.impl.root_SecureBackupRootView_Night_12_en",20504,], -["features.securebackup.impl.root_SecureBackupRootView_Day_13_en","features.securebackup.impl.root_SecureBackupRootView_Night_13_en",20504,], -["features.securebackup.impl.root_SecureBackupRootView_Day_14_en","features.securebackup.impl.root_SecureBackupRootView_Night_14_en",20504,], -["features.securebackup.impl.root_SecureBackupRootView_Day_15_en","features.securebackup.impl.root_SecureBackupRootView_Night_15_en",20504,], -["features.securebackup.impl.root_SecureBackupRootView_Day_16_en","features.securebackup.impl.root_SecureBackupRootView_Night_16_en",20504,], -["features.securebackup.impl.root_SecureBackupRootView_Day_17_en","features.securebackup.impl.root_SecureBackupRootView_Night_17_en",20504,], -["features.securebackup.impl.root_SecureBackupRootView_Day_1_en","features.securebackup.impl.root_SecureBackupRootView_Night_1_en",20504,], -["features.securebackup.impl.root_SecureBackupRootView_Day_2_en","features.securebackup.impl.root_SecureBackupRootView_Night_2_en",20504,], -["features.securebackup.impl.root_SecureBackupRootView_Day_3_en","features.securebackup.impl.root_SecureBackupRootView_Night_3_en",20504,], -["features.securebackup.impl.root_SecureBackupRootView_Day_4_en","features.securebackup.impl.root_SecureBackupRootView_Night_4_en",20504,], -["features.securebackup.impl.root_SecureBackupRootView_Day_5_en","features.securebackup.impl.root_SecureBackupRootView_Night_5_en",20504,], -["features.securebackup.impl.root_SecureBackupRootView_Day_6_en","features.securebackup.impl.root_SecureBackupRootView_Night_6_en",20504,], -["features.securebackup.impl.root_SecureBackupRootView_Day_7_en","features.securebackup.impl.root_SecureBackupRootView_Night_7_en",20504,], -["features.securebackup.impl.root_SecureBackupRootView_Day_8_en","features.securebackup.impl.root_SecureBackupRootView_Night_8_en",20504,], -["features.securebackup.impl.root_SecureBackupRootView_Day_9_en","features.securebackup.impl.root_SecureBackupRootView_Night_9_en",20504,], -["features.securebackup.impl.setup_SecureBackupSetupViewChange_Day_0_en","features.securebackup.impl.setup_SecureBackupSetupViewChange_Night_0_en",20504,], -["features.securebackup.impl.setup_SecureBackupSetupViewChange_Day_1_en","features.securebackup.impl.setup_SecureBackupSetupViewChange_Night_1_en",20504,], -["features.securebackup.impl.setup_SecureBackupSetupViewChange_Day_2_en","features.securebackup.impl.setup_SecureBackupSetupViewChange_Night_2_en",20504,], -["features.securebackup.impl.setup_SecureBackupSetupViewChange_Day_3_en","features.securebackup.impl.setup_SecureBackupSetupViewChange_Night_3_en",20504,], -["features.securebackup.impl.setup_SecureBackupSetupViewChange_Day_4_en","features.securebackup.impl.setup_SecureBackupSetupViewChange_Night_4_en",20504,], -["features.securebackup.impl.setup_SecureBackupSetupViewChange_Day_5_en","features.securebackup.impl.setup_SecureBackupSetupViewChange_Night_5_en",20504,], -["features.securebackup.impl.setup_SecureBackupSetupView_Day_0_en","features.securebackup.impl.setup_SecureBackupSetupView_Night_0_en",20504,], -["features.securebackup.impl.setup_SecureBackupSetupView_Day_1_en","features.securebackup.impl.setup_SecureBackupSetupView_Night_1_en",20504,], -["features.securebackup.impl.setup_SecureBackupSetupView_Day_2_en","features.securebackup.impl.setup_SecureBackupSetupView_Night_2_en",20504,], -["features.securebackup.impl.setup_SecureBackupSetupView_Day_3_en","features.securebackup.impl.setup_SecureBackupSetupView_Night_3_en",20504,], -["features.securebackup.impl.setup_SecureBackupSetupView_Day_4_en","features.securebackup.impl.setup_SecureBackupSetupView_Night_4_en",20504,], -["features.securebackup.impl.setup_SecureBackupSetupView_Day_5_en","features.securebackup.impl.setup_SecureBackupSetupView_Night_5_en",20504,], -["features.securityandprivacy.impl.root_SecurityAndPrivacyViewDark_0_en","",20504,], -["features.securityandprivacy.impl.root_SecurityAndPrivacyViewDark_10_en","",20504,], -["features.securityandprivacy.impl.root_SecurityAndPrivacyViewDark_11_en","",20504,], -["features.securityandprivacy.impl.root_SecurityAndPrivacyViewDark_12_en","",20504,], -["features.securityandprivacy.impl.root_SecurityAndPrivacyViewDark_13_en","",20504,], -["features.securityandprivacy.impl.root_SecurityAndPrivacyViewDark_14_en","",20504,], -["features.securityandprivacy.impl.root_SecurityAndPrivacyViewDark_15_en","",20504,], -["features.securityandprivacy.impl.root_SecurityAndPrivacyViewDark_16_en","",20504,], -["features.securityandprivacy.impl.root_SecurityAndPrivacyViewDark_17_en","",20504,], -["features.securityandprivacy.impl.root_SecurityAndPrivacyViewDark_18_en","",20504,], -["features.securityandprivacy.impl.root_SecurityAndPrivacyViewDark_19_en","",20504,], -["features.securityandprivacy.impl.root_SecurityAndPrivacyViewDark_1_en","",20504,], -["features.securityandprivacy.impl.root_SecurityAndPrivacyViewDark_20_en","",20504,], -["features.securityandprivacy.impl.root_SecurityAndPrivacyViewDark_21_en","",20504,], -["features.securityandprivacy.impl.root_SecurityAndPrivacyViewDark_22_en","",20504,], -["features.securityandprivacy.impl.root_SecurityAndPrivacyViewDark_23_en","",20504,], -["features.securityandprivacy.impl.root_SecurityAndPrivacyViewDark_2_en","",20504,], -["features.securityandprivacy.impl.root_SecurityAndPrivacyViewDark_3_en","",20504,], -["features.securityandprivacy.impl.root_SecurityAndPrivacyViewDark_4_en","",20504,], -["features.securityandprivacy.impl.root_SecurityAndPrivacyViewDark_5_en","",20504,], -["features.securityandprivacy.impl.root_SecurityAndPrivacyViewDark_6_en","",20504,], -["features.securityandprivacy.impl.root_SecurityAndPrivacyViewDark_7_en","",20504,], -["features.securityandprivacy.impl.root_SecurityAndPrivacyViewDark_8_en","",20504,], -["features.securityandprivacy.impl.root_SecurityAndPrivacyViewDark_9_en","",20504,], -["features.securityandprivacy.impl.root_SecurityAndPrivacyViewLight_0_en","",20504,], -["features.securityandprivacy.impl.root_SecurityAndPrivacyViewLight_10_en","",20504,], -["features.securityandprivacy.impl.root_SecurityAndPrivacyViewLight_11_en","",20504,], -["features.securityandprivacy.impl.root_SecurityAndPrivacyViewLight_12_en","",20504,], -["features.securityandprivacy.impl.root_SecurityAndPrivacyViewLight_13_en","",20504,], -["features.securityandprivacy.impl.root_SecurityAndPrivacyViewLight_14_en","",20504,], -["features.securityandprivacy.impl.root_SecurityAndPrivacyViewLight_15_en","",20504,], -["features.securityandprivacy.impl.root_SecurityAndPrivacyViewLight_16_en","",20504,], -["features.securityandprivacy.impl.root_SecurityAndPrivacyViewLight_17_en","",20504,], -["features.securityandprivacy.impl.root_SecurityAndPrivacyViewLight_18_en","",20504,], -["features.securityandprivacy.impl.root_SecurityAndPrivacyViewLight_19_en","",20504,], -["features.securityandprivacy.impl.root_SecurityAndPrivacyViewLight_1_en","",20504,], -["features.securityandprivacy.impl.root_SecurityAndPrivacyViewLight_20_en","",20504,], -["features.securityandprivacy.impl.root_SecurityAndPrivacyViewLight_21_en","",20504,], -["features.securityandprivacy.impl.root_SecurityAndPrivacyViewLight_22_en","",20504,], -["features.securityandprivacy.impl.root_SecurityAndPrivacyViewLight_23_en","",20504,], -["features.securityandprivacy.impl.root_SecurityAndPrivacyViewLight_2_en","",20504,], -["features.securityandprivacy.impl.root_SecurityAndPrivacyViewLight_3_en","",20504,], -["features.securityandprivacy.impl.root_SecurityAndPrivacyViewLight_4_en","",20504,], -["features.securityandprivacy.impl.root_SecurityAndPrivacyViewLight_5_en","",20504,], -["features.securityandprivacy.impl.root_SecurityAndPrivacyViewLight_6_en","",20504,], -["features.securityandprivacy.impl.root_SecurityAndPrivacyViewLight_7_en","",20504,], -["features.securityandprivacy.impl.root_SecurityAndPrivacyViewLight_8_en","",20504,], -["features.securityandprivacy.impl.root_SecurityAndPrivacyViewLight_9_en","",20504,], -["features.createroom.impl.configureroom_SelectParentSpaceBottomSheet_Day_0_en","features.createroom.impl.configureroom_SelectParentSpaceBottomSheet_Night_0_en",20504,], +["features.startchat.impl.components_SearchMultipleUsersResultItem_en","",20511,], +["features.startchat.impl.components_SearchSingleUserResultItem_en","",20511,], +["features.securebackup.impl.disable_SecureBackupDisableView_Day_0_en","features.securebackup.impl.disable_SecureBackupDisableView_Night_0_en",20511,], +["features.securebackup.impl.disable_SecureBackupDisableView_Day_1_en","features.securebackup.impl.disable_SecureBackupDisableView_Night_1_en",20511,], +["features.securebackup.impl.disable_SecureBackupDisableView_Day_2_en","features.securebackup.impl.disable_SecureBackupDisableView_Night_2_en",20511,], +["features.securebackup.impl.disable_SecureBackupDisableView_Day_3_en","features.securebackup.impl.disable_SecureBackupDisableView_Night_3_en",20511,], +["features.securebackup.impl.enter_SecureBackupEnterRecoveryKeyView_Day_0_en","features.securebackup.impl.enter_SecureBackupEnterRecoveryKeyView_Night_0_en",20511,], +["features.securebackup.impl.enter_SecureBackupEnterRecoveryKeyView_Day_1_en","features.securebackup.impl.enter_SecureBackupEnterRecoveryKeyView_Night_1_en",20511,], +["features.securebackup.impl.enter_SecureBackupEnterRecoveryKeyView_Day_2_en","features.securebackup.impl.enter_SecureBackupEnterRecoveryKeyView_Night_2_en",20511,], +["features.securebackup.impl.enter_SecureBackupEnterRecoveryKeyView_Day_3_en","features.securebackup.impl.enter_SecureBackupEnterRecoveryKeyView_Night_3_en",20511,], +["features.securebackup.impl.enter_SecureBackupEnterRecoveryKeyView_Day_4_en","features.securebackup.impl.enter_SecureBackupEnterRecoveryKeyView_Night_4_en",20511,], +["features.securebackup.impl.root_SecureBackupRootView_Day_0_en","features.securebackup.impl.root_SecureBackupRootView_Night_0_en",20511,], +["features.securebackup.impl.root_SecureBackupRootView_Day_10_en","features.securebackup.impl.root_SecureBackupRootView_Night_10_en",20511,], +["features.securebackup.impl.root_SecureBackupRootView_Day_11_en","features.securebackup.impl.root_SecureBackupRootView_Night_11_en",20511,], +["features.securebackup.impl.root_SecureBackupRootView_Day_12_en","features.securebackup.impl.root_SecureBackupRootView_Night_12_en",20511,], +["features.securebackup.impl.root_SecureBackupRootView_Day_13_en","features.securebackup.impl.root_SecureBackupRootView_Night_13_en",20511,], +["features.securebackup.impl.root_SecureBackupRootView_Day_14_en","features.securebackup.impl.root_SecureBackupRootView_Night_14_en",20511,], +["features.securebackup.impl.root_SecureBackupRootView_Day_15_en","features.securebackup.impl.root_SecureBackupRootView_Night_15_en",20511,], +["features.securebackup.impl.root_SecureBackupRootView_Day_16_en","features.securebackup.impl.root_SecureBackupRootView_Night_16_en",20511,], +["features.securebackup.impl.root_SecureBackupRootView_Day_17_en","features.securebackup.impl.root_SecureBackupRootView_Night_17_en",20511,], +["features.securebackup.impl.root_SecureBackupRootView_Day_1_en","features.securebackup.impl.root_SecureBackupRootView_Night_1_en",20511,], +["features.securebackup.impl.root_SecureBackupRootView_Day_2_en","features.securebackup.impl.root_SecureBackupRootView_Night_2_en",20511,], +["features.securebackup.impl.root_SecureBackupRootView_Day_3_en","features.securebackup.impl.root_SecureBackupRootView_Night_3_en",20511,], +["features.securebackup.impl.root_SecureBackupRootView_Day_4_en","features.securebackup.impl.root_SecureBackupRootView_Night_4_en",20511,], +["features.securebackup.impl.root_SecureBackupRootView_Day_5_en","features.securebackup.impl.root_SecureBackupRootView_Night_5_en",20511,], +["features.securebackup.impl.root_SecureBackupRootView_Day_6_en","features.securebackup.impl.root_SecureBackupRootView_Night_6_en",20511,], +["features.securebackup.impl.root_SecureBackupRootView_Day_7_en","features.securebackup.impl.root_SecureBackupRootView_Night_7_en",20511,], +["features.securebackup.impl.root_SecureBackupRootView_Day_8_en","features.securebackup.impl.root_SecureBackupRootView_Night_8_en",20511,], +["features.securebackup.impl.root_SecureBackupRootView_Day_9_en","features.securebackup.impl.root_SecureBackupRootView_Night_9_en",20511,], +["features.securebackup.impl.setup_SecureBackupSetupViewChange_Day_0_en","features.securebackup.impl.setup_SecureBackupSetupViewChange_Night_0_en",20511,], +["features.securebackup.impl.setup_SecureBackupSetupViewChange_Day_1_en","features.securebackup.impl.setup_SecureBackupSetupViewChange_Night_1_en",20511,], +["features.securebackup.impl.setup_SecureBackupSetupViewChange_Day_2_en","features.securebackup.impl.setup_SecureBackupSetupViewChange_Night_2_en",20511,], +["features.securebackup.impl.setup_SecureBackupSetupViewChange_Day_3_en","features.securebackup.impl.setup_SecureBackupSetupViewChange_Night_3_en",20511,], +["features.securebackup.impl.setup_SecureBackupSetupViewChange_Day_4_en","features.securebackup.impl.setup_SecureBackupSetupViewChange_Night_4_en",20511,], +["features.securebackup.impl.setup_SecureBackupSetupViewChange_Day_5_en","features.securebackup.impl.setup_SecureBackupSetupViewChange_Night_5_en",20511,], +["features.securebackup.impl.setup_SecureBackupSetupView_Day_0_en","features.securebackup.impl.setup_SecureBackupSetupView_Night_0_en",20511,], +["features.securebackup.impl.setup_SecureBackupSetupView_Day_1_en","features.securebackup.impl.setup_SecureBackupSetupView_Night_1_en",20511,], +["features.securebackup.impl.setup_SecureBackupSetupView_Day_2_en","features.securebackup.impl.setup_SecureBackupSetupView_Night_2_en",20511,], +["features.securebackup.impl.setup_SecureBackupSetupView_Day_3_en","features.securebackup.impl.setup_SecureBackupSetupView_Night_3_en",20511,], +["features.securebackup.impl.setup_SecureBackupSetupView_Day_4_en","features.securebackup.impl.setup_SecureBackupSetupView_Night_4_en",20511,], +["features.securebackup.impl.setup_SecureBackupSetupView_Day_5_en","features.securebackup.impl.setup_SecureBackupSetupView_Night_5_en",20511,], +["features.securityandprivacy.impl.root_SecurityAndPrivacyViewDark_0_en","",20511,], +["features.securityandprivacy.impl.root_SecurityAndPrivacyViewDark_10_en","",20511,], +["features.securityandprivacy.impl.root_SecurityAndPrivacyViewDark_11_en","",20511,], +["features.securityandprivacy.impl.root_SecurityAndPrivacyViewDark_12_en","",20511,], +["features.securityandprivacy.impl.root_SecurityAndPrivacyViewDark_13_en","",20511,], +["features.securityandprivacy.impl.root_SecurityAndPrivacyViewDark_14_en","",20511,], +["features.securityandprivacy.impl.root_SecurityAndPrivacyViewDark_15_en","",20511,], +["features.securityandprivacy.impl.root_SecurityAndPrivacyViewDark_16_en","",20511,], +["features.securityandprivacy.impl.root_SecurityAndPrivacyViewDark_17_en","",20511,], +["features.securityandprivacy.impl.root_SecurityAndPrivacyViewDark_18_en","",20511,], +["features.securityandprivacy.impl.root_SecurityAndPrivacyViewDark_19_en","",20511,], +["features.securityandprivacy.impl.root_SecurityAndPrivacyViewDark_1_en","",20511,], +["features.securityandprivacy.impl.root_SecurityAndPrivacyViewDark_20_en","",20511,], +["features.securityandprivacy.impl.root_SecurityAndPrivacyViewDark_21_en","",20511,], +["features.securityandprivacy.impl.root_SecurityAndPrivacyViewDark_22_en","",20511,], +["features.securityandprivacy.impl.root_SecurityAndPrivacyViewDark_23_en","",20511,], +["features.securityandprivacy.impl.root_SecurityAndPrivacyViewDark_2_en","",20511,], +["features.securityandprivacy.impl.root_SecurityAndPrivacyViewDark_3_en","",20511,], +["features.securityandprivacy.impl.root_SecurityAndPrivacyViewDark_4_en","",20511,], +["features.securityandprivacy.impl.root_SecurityAndPrivacyViewDark_5_en","",20511,], +["features.securityandprivacy.impl.root_SecurityAndPrivacyViewDark_6_en","",20511,], +["features.securityandprivacy.impl.root_SecurityAndPrivacyViewDark_7_en","",20511,], +["features.securityandprivacy.impl.root_SecurityAndPrivacyViewDark_8_en","",20511,], +["features.securityandprivacy.impl.root_SecurityAndPrivacyViewDark_9_en","",20511,], +["features.securityandprivacy.impl.root_SecurityAndPrivacyViewLight_0_en","",20511,], +["features.securityandprivacy.impl.root_SecurityAndPrivacyViewLight_10_en","",20511,], +["features.securityandprivacy.impl.root_SecurityAndPrivacyViewLight_11_en","",20511,], +["features.securityandprivacy.impl.root_SecurityAndPrivacyViewLight_12_en","",20511,], +["features.securityandprivacy.impl.root_SecurityAndPrivacyViewLight_13_en","",20511,], +["features.securityandprivacy.impl.root_SecurityAndPrivacyViewLight_14_en","",20511,], +["features.securityandprivacy.impl.root_SecurityAndPrivacyViewLight_15_en","",20511,], +["features.securityandprivacy.impl.root_SecurityAndPrivacyViewLight_16_en","",20511,], +["features.securityandprivacy.impl.root_SecurityAndPrivacyViewLight_17_en","",20511,], +["features.securityandprivacy.impl.root_SecurityAndPrivacyViewLight_18_en","",20511,], +["features.securityandprivacy.impl.root_SecurityAndPrivacyViewLight_19_en","",20511,], +["features.securityandprivacy.impl.root_SecurityAndPrivacyViewLight_1_en","",20511,], +["features.securityandprivacy.impl.root_SecurityAndPrivacyViewLight_20_en","",20511,], +["features.securityandprivacy.impl.root_SecurityAndPrivacyViewLight_21_en","",20511,], +["features.securityandprivacy.impl.root_SecurityAndPrivacyViewLight_22_en","",20511,], +["features.securityandprivacy.impl.root_SecurityAndPrivacyViewLight_23_en","",20511,], +["features.securityandprivacy.impl.root_SecurityAndPrivacyViewLight_2_en","",20511,], +["features.securityandprivacy.impl.root_SecurityAndPrivacyViewLight_3_en","",20511,], +["features.securityandprivacy.impl.root_SecurityAndPrivacyViewLight_4_en","",20511,], +["features.securityandprivacy.impl.root_SecurityAndPrivacyViewLight_5_en","",20511,], +["features.securityandprivacy.impl.root_SecurityAndPrivacyViewLight_6_en","",20511,], +["features.securityandprivacy.impl.root_SecurityAndPrivacyViewLight_7_en","",20511,], +["features.securityandprivacy.impl.root_SecurityAndPrivacyViewLight_8_en","",20511,], +["features.securityandprivacy.impl.root_SecurityAndPrivacyViewLight_9_en","",20511,], +["features.createroom.impl.configureroom_SelectParentSpaceBottomSheet_Day_0_en","features.createroom.impl.configureroom_SelectParentSpaceBottomSheet_Night_0_en",20511,], ["libraries.designsystem.atomic.atoms_SelectedIndicatorAtom_Day_0_en","libraries.designsystem.atomic.atoms_SelectedIndicatorAtom_Night_0_en",0,], ["libraries.matrix.ui.components_SelectedRoomRtl_Day_0_en","libraries.matrix.ui.components_SelectedRoomRtl_Night_0_en",0,], ["libraries.matrix.ui.components_SelectedRoomRtl_Day_1_en","libraries.matrix.ui.components_SelectedRoomRtl_Night_1_en",0,], @@ -1225,11 +1228,11 @@ export const screenshots = [ ["libraries.matrix.ui.components_SelectedUser_Day_1_en","libraries.matrix.ui.components_SelectedUser_Night_1_en",0,], ["libraries.matrix.ui.components_SelectedUsersRowList_Day_0_en","libraries.matrix.ui.components_SelectedUsersRowList_Night_0_en",0,], ["libraries.textcomposer.components_SendButtonIcon_Day_0_en","libraries.textcomposer.components_SendButtonIcon_Night_0_en",0,], -["features.location.impl.send_SendLocationView_Day_0_en","features.location.impl.send_SendLocationView_Night_0_en",20504,], -["features.location.impl.send_SendLocationView_Day_1_en","features.location.impl.send_SendLocationView_Night_1_en",20504,], -["features.location.impl.send_SendLocationView_Day_2_en","features.location.impl.send_SendLocationView_Night_2_en",20504,], -["features.location.impl.send_SendLocationView_Day_3_en","features.location.impl.send_SendLocationView_Night_3_en",20504,], -["features.location.impl.send_SendLocationView_Day_4_en","features.location.impl.send_SendLocationView_Night_4_en",20504,], +["features.location.impl.send_SendLocationView_Day_0_en","features.location.impl.send_SendLocationView_Night_0_en",20511,], +["features.location.impl.send_SendLocationView_Day_1_en","features.location.impl.send_SendLocationView_Night_1_en",20511,], +["features.location.impl.send_SendLocationView_Day_2_en","features.location.impl.send_SendLocationView_Night_2_en",20511,], +["features.location.impl.send_SendLocationView_Day_3_en","features.location.impl.send_SendLocationView_Night_3_en",20511,], +["features.location.impl.send_SendLocationView_Day_4_en","features.location.impl.send_SendLocationView_Night_4_en",20511,], ["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,], @@ -1239,28 +1242,28 @@ export const screenshots = [ ["libraries.matrix.ui.messages.sender_SenderName_Day_6_en","libraries.matrix.ui.messages.sender_SenderName_Night_6_en",0,], ["libraries.matrix.ui.messages.sender_SenderName_Day_7_en","libraries.matrix.ui.messages.sender_SenderName_Night_7_en",0,], ["libraries.matrix.ui.messages.sender_SenderName_Day_8_en","libraries.matrix.ui.messages.sender_SenderName_Night_8_en",0,], -["features.verifysession.impl.incoming.ui_SessionDetailsView_Day_0_en","features.verifysession.impl.incoming.ui_SessionDetailsView_Night_0_en",20504,], -["features.home.impl.components_SetUpRecoveryKeyBanner_Day_0_en","features.home.impl.components_SetUpRecoveryKeyBanner_Night_0_en",20504,], -["features.lockscreen.impl.setup.biometric_SetupBiometricView_Day_0_en","features.lockscreen.impl.setup.biometric_SetupBiometricView_Night_0_en",20504,], -["features.lockscreen.impl.setup.pin_SetupPinView_Day_0_en","features.lockscreen.impl.setup.pin_SetupPinView_Night_0_en",20504,], -["features.lockscreen.impl.setup.pin_SetupPinView_Day_1_en","features.lockscreen.impl.setup.pin_SetupPinView_Night_1_en",20504,], -["features.lockscreen.impl.setup.pin_SetupPinView_Day_2_en","features.lockscreen.impl.setup.pin_SetupPinView_Night_2_en",20504,], -["features.lockscreen.impl.setup.pin_SetupPinView_Day_3_en","features.lockscreen.impl.setup.pin_SetupPinView_Night_3_en",20504,], -["features.lockscreen.impl.setup.pin_SetupPinView_Day_4_en","features.lockscreen.impl.setup.pin_SetupPinView_Night_4_en",20504,], +["features.verifysession.impl.incoming.ui_SessionDetailsView_Day_0_en","features.verifysession.impl.incoming.ui_SessionDetailsView_Night_0_en",20511,], +["features.home.impl.components_SetUpRecoveryKeyBanner_Day_0_en","features.home.impl.components_SetUpRecoveryKeyBanner_Night_0_en",20511,], +["features.lockscreen.impl.setup.biometric_SetupBiometricView_Day_0_en","features.lockscreen.impl.setup.biometric_SetupBiometricView_Night_0_en",20511,], +["features.lockscreen.impl.setup.pin_SetupPinView_Day_0_en","features.lockscreen.impl.setup.pin_SetupPinView_Night_0_en",20511,], +["features.lockscreen.impl.setup.pin_SetupPinView_Day_1_en","features.lockscreen.impl.setup.pin_SetupPinView_Night_1_en",20511,], +["features.lockscreen.impl.setup.pin_SetupPinView_Day_2_en","features.lockscreen.impl.setup.pin_SetupPinView_Night_2_en",20511,], +["features.lockscreen.impl.setup.pin_SetupPinView_Day_3_en","features.lockscreen.impl.setup.pin_SetupPinView_Night_3_en",20511,], +["features.lockscreen.impl.setup.pin_SetupPinView_Day_4_en","features.lockscreen.impl.setup.pin_SetupPinView_Night_4_en",20511,], ["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",20504,], -["features.location.impl.show_ShowLocationView_Day_0_en","features.location.impl.show_ShowLocationView_Night_0_en",20504,], -["features.location.impl.show_ShowLocationView_Day_1_en","features.location.impl.show_ShowLocationView_Night_1_en",20504,], -["features.location.impl.show_ShowLocationView_Day_2_en","features.location.impl.show_ShowLocationView_Night_2_en",20504,], -["features.location.impl.show_ShowLocationView_Day_3_en","features.location.impl.show_ShowLocationView_Night_3_en",20504,], -["features.location.impl.show_ShowLocationView_Day_4_en","features.location.impl.show_ShowLocationView_Night_4_en",20504,], -["features.location.impl.show_ShowLocationView_Day_5_en","features.location.impl.show_ShowLocationView_Night_5_en",20504,], -["features.location.impl.show_ShowLocationView_Day_6_en","features.location.impl.show_ShowLocationView_Night_6_en",20504,], -["features.location.impl.show_ShowLocationView_Day_7_en","features.location.impl.show_ShowLocationView_Night_7_en",20504,], -["features.linknewdevice.impl.screens.qrcode_ShowQrCodeView_Day_0_en","features.linknewdevice.impl.screens.qrcode_ShowQrCodeView_Night_0_en",20504,], -["features.signedout.impl_SignedOutView_Day_0_en","features.signedout.impl_SignedOutView_Night_0_en",20504,], +["features.share.impl_ShareView_Day_3_en","features.share.impl_ShareView_Night_3_en",20511,], +["features.location.impl.show_ShowLocationView_Day_0_en","features.location.impl.show_ShowLocationView_Night_0_en",20511,], +["features.location.impl.show_ShowLocationView_Day_1_en","features.location.impl.show_ShowLocationView_Night_1_en",20511,], +["features.location.impl.show_ShowLocationView_Day_2_en","features.location.impl.show_ShowLocationView_Night_2_en",20511,], +["features.location.impl.show_ShowLocationView_Day_3_en","features.location.impl.show_ShowLocationView_Night_3_en",20511,], +["features.location.impl.show_ShowLocationView_Day_4_en","features.location.impl.show_ShowLocationView_Night_4_en",20511,], +["features.location.impl.show_ShowLocationView_Day_5_en","features.location.impl.show_ShowLocationView_Night_5_en",20511,], +["features.location.impl.show_ShowLocationView_Day_6_en","features.location.impl.show_ShowLocationView_Night_6_en",20511,], +["features.location.impl.show_ShowLocationView_Day_7_en","features.location.impl.show_ShowLocationView_Night_7_en",20511,], +["features.linknewdevice.impl.screens.qrcode_ShowQrCodeView_Day_0_en","features.linknewdevice.impl.screens.qrcode_ShowQrCodeView_Night_0_en",20511,], +["features.signedout.impl_SignedOutView_Day_0_en","features.signedout.impl_SignedOutView_Night_0_en",20511,], ["libraries.designsystem.components_SimpleModalBottomSheet_Day_0_en","libraries.designsystem.components_SimpleModalBottomSheet_Night_0_en",0,], ["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,], @@ -1270,107 +1273,107 @@ 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",20504,], +["features.login.impl.dialogs_SlidingSyncNotSupportedDialog_Day_0_en","features.login.impl.dialogs_SlidingSyncNotSupportedDialog_Night_0_en",20511,], ["libraries.designsystem.theme.components_SnackbarWithActionAndCloseButton_Snackbar_with_action_and_close_button_Snackbars_en","",0,], ["libraries.designsystem.theme.components_SnackbarWithActionOnNewLineAndCloseButton_Snackbar_with_action_and_close_button_on_new_line_Snackbars_en","",0,], ["libraries.designsystem.theme.components_SnackbarWithActionOnNewLine_Snackbar_with_action_on_new_line_Snackbars_en","",0,], ["libraries.designsystem.theme.components_SnackbarWithAction_Snackbar_with_action_Snackbars_en","",0,], ["libraries.designsystem.theme.components_Snackbar_Snackbar_Snackbars_en","",0,], -["features.announcement.impl.spaces_SpaceAnnouncementView_Day_0_en","features.announcement.impl.spaces_SpaceAnnouncementView_Night_0_en",20504,], +["features.announcement.impl.spaces_SpaceAnnouncementView_Day_0_en","features.announcement.impl.spaces_SpaceAnnouncementView_Night_0_en",20511,], ["libraries.designsystem.components.avatar.internal_SpaceAvatar_Avatars_en","",0,], -["features.home.impl.spacefilters_SpaceFiltersView_Day_0_en","features.home.impl.spacefilters_SpaceFiltersView_Night_0_en",20504,], -["features.home.impl.spacefilters_SpaceFiltersView_Day_1_en","features.home.impl.spacefilters_SpaceFiltersView_Night_1_en",20504,], -["libraries.matrix.ui.components_SpaceHeaderRootView_Day_0_en","libraries.matrix.ui.components_SpaceHeaderRootView_Night_0_en",20504,], +["features.home.impl.spacefilters_SpaceFiltersView_Day_0_en","features.home.impl.spacefilters_SpaceFiltersView_Night_0_en",20511,], +["features.home.impl.spacefilters_SpaceFiltersView_Day_1_en","features.home.impl.spacefilters_SpaceFiltersView_Night_1_en",20511,], +["libraries.matrix.ui.components_SpaceHeaderRootView_Day_0_en","libraries.matrix.ui.components_SpaceHeaderRootView_Night_0_en",20511,], ["libraries.matrix.ui.components_SpaceHeaderView_Day_0_en","libraries.matrix.ui.components_SpaceHeaderView_Night_0_en",0,], -["libraries.matrix.ui.components_SpaceInfoRow_Day_0_en","libraries.matrix.ui.components_SpaceInfoRow_Night_0_en",20504,], +["libraries.matrix.ui.components_SpaceInfoRow_Day_0_en","libraries.matrix.ui.components_SpaceInfoRow_Night_0_en",20511,], ["libraries.matrix.ui.components_SpaceMembersViewNoHeroes_Day_0_en","libraries.matrix.ui.components_SpaceMembersViewNoHeroes_Night_0_en",0,], ["libraries.matrix.ui.components_SpaceMembersView_Day_0_en","libraries.matrix.ui.components_SpaceMembersView_Night_0_en",0,], -["libraries.matrix.ui.components_SpaceRoomItemView_Day_0_en","libraries.matrix.ui.components_SpaceRoomItemView_Night_0_en",20504,], -["libraries.matrix.ui.components_SpaceRoomItemView_Day_1_en","libraries.matrix.ui.components_SpaceRoomItemView_Night_1_en",20504,], -["libraries.matrix.ui.components_SpaceRoomItemView_Day_2_en","libraries.matrix.ui.components_SpaceRoomItemView_Night_2_en",20504,], -["libraries.matrix.ui.components_SpaceRoomItemView_Day_3_en","libraries.matrix.ui.components_SpaceRoomItemView_Night_3_en",20504,], -["libraries.matrix.ui.components_SpaceRoomItemView_Day_4_en","libraries.matrix.ui.components_SpaceRoomItemView_Night_4_en",20504,], -["libraries.matrix.ui.components_SpaceRoomItemView_Day_5_en","libraries.matrix.ui.components_SpaceRoomItemView_Night_5_en",20504,], -["libraries.matrix.ui.components_SpaceRoomItemView_Day_6_en","libraries.matrix.ui.components_SpaceRoomItemView_Night_6_en",20504,], -["libraries.matrix.ui.components_SpaceRoomItemView_Day_7_en","libraries.matrix.ui.components_SpaceRoomItemView_Night_7_en",20504,], -["libraries.matrix.ui.components_SpaceRoomItemView_Day_8_en","libraries.matrix.ui.components_SpaceRoomItemView_Night_8_en",20504,], -["features.space.impl.settings_SpaceSettingsView_Day_0_en","features.space.impl.settings_SpaceSettingsView_Night_0_en",20504,], -["features.space.impl.settings_SpaceSettingsView_Day_1_en","features.space.impl.settings_SpaceSettingsView_Night_1_en",20504,], -["features.space.impl.settings_SpaceSettingsView_Day_2_en","features.space.impl.settings_SpaceSettingsView_Night_2_en",20504,], -["features.space.impl.settings_SpaceSettingsView_Day_3_en","features.space.impl.settings_SpaceSettingsView_Night_3_en",20504,], -["features.space.impl.root_SpaceView_Day_0_en","features.space.impl.root_SpaceView_Night_0_en",20504,], -["features.space.impl.root_SpaceView_Day_1_en","features.space.impl.root_SpaceView_Night_1_en",20504,], -["features.space.impl.root_SpaceView_Day_2_en","features.space.impl.root_SpaceView_Night_2_en",20504,], -["features.space.impl.root_SpaceView_Day_3_en","features.space.impl.root_SpaceView_Night_3_en",20504,], -["features.space.impl.root_SpaceView_Day_4_en","features.space.impl.root_SpaceView_Night_4_en",20504,], -["features.space.impl.root_SpaceView_Day_5_en","features.space.impl.root_SpaceView_Night_5_en",20504,], -["features.space.impl.root_SpaceView_Day_6_en","features.space.impl.root_SpaceView_Night_6_en",20504,], -["features.space.impl.root_SpaceView_Day_7_en","features.space.impl.root_SpaceView_Night_7_en",20504,], -["features.space.impl.root_SpaceView_Day_8_en","features.space.impl.root_SpaceView_Night_8_en",20504,], +["libraries.matrix.ui.components_SpaceRoomItemView_Day_0_en","libraries.matrix.ui.components_SpaceRoomItemView_Night_0_en",20511,], +["libraries.matrix.ui.components_SpaceRoomItemView_Day_1_en","libraries.matrix.ui.components_SpaceRoomItemView_Night_1_en",20511,], +["libraries.matrix.ui.components_SpaceRoomItemView_Day_2_en","libraries.matrix.ui.components_SpaceRoomItemView_Night_2_en",20511,], +["libraries.matrix.ui.components_SpaceRoomItemView_Day_3_en","libraries.matrix.ui.components_SpaceRoomItemView_Night_3_en",20511,], +["libraries.matrix.ui.components_SpaceRoomItemView_Day_4_en","libraries.matrix.ui.components_SpaceRoomItemView_Night_4_en",20511,], +["libraries.matrix.ui.components_SpaceRoomItemView_Day_5_en","libraries.matrix.ui.components_SpaceRoomItemView_Night_5_en",20511,], +["libraries.matrix.ui.components_SpaceRoomItemView_Day_6_en","libraries.matrix.ui.components_SpaceRoomItemView_Night_6_en",20511,], +["libraries.matrix.ui.components_SpaceRoomItemView_Day_7_en","libraries.matrix.ui.components_SpaceRoomItemView_Night_7_en",20511,], +["libraries.matrix.ui.components_SpaceRoomItemView_Day_8_en","libraries.matrix.ui.components_SpaceRoomItemView_Night_8_en",20511,], +["features.space.impl.settings_SpaceSettingsView_Day_0_en","features.space.impl.settings_SpaceSettingsView_Night_0_en",20511,], +["features.space.impl.settings_SpaceSettingsView_Day_1_en","features.space.impl.settings_SpaceSettingsView_Night_1_en",20511,], +["features.space.impl.settings_SpaceSettingsView_Day_2_en","features.space.impl.settings_SpaceSettingsView_Night_2_en",20511,], +["features.space.impl.settings_SpaceSettingsView_Day_3_en","features.space.impl.settings_SpaceSettingsView_Night_3_en",20511,], +["features.space.impl.root_SpaceView_Day_0_en","features.space.impl.root_SpaceView_Night_0_en",20511,], +["features.space.impl.root_SpaceView_Day_1_en","features.space.impl.root_SpaceView_Night_1_en",20511,], +["features.space.impl.root_SpaceView_Day_2_en","features.space.impl.root_SpaceView_Night_2_en",20511,], +["features.space.impl.root_SpaceView_Day_3_en","features.space.impl.root_SpaceView_Night_3_en",20511,], +["features.space.impl.root_SpaceView_Day_4_en","features.space.impl.root_SpaceView_Night_4_en",20511,], +["features.space.impl.root_SpaceView_Day_5_en","features.space.impl.root_SpaceView_Night_5_en",20511,], +["features.space.impl.root_SpaceView_Day_6_en","features.space.impl.root_SpaceView_Night_6_en",20511,], +["features.space.impl.root_SpaceView_Day_7_en","features.space.impl.root_SpaceView_Night_7_en",20511,], +["features.space.impl.root_SpaceView_Day_8_en","features.space.impl.root_SpaceView_Night_8_en",20511,], ["libraries.designsystem.modifiers_SquareSizeModifierInsideSquare_en","",0,], ["libraries.designsystem.modifiers_SquareSizeModifierLargeHeight_en","",0,], ["libraries.designsystem.modifiers_SquareSizeModifierLargeWidth_en","",0,], -["features.startchat.impl.root_StartChatView_Day_0_en","features.startchat.impl.root_StartChatView_Night_0_en",20504,], -["features.startchat.impl.root_StartChatView_Day_1_en","features.startchat.impl.root_StartChatView_Night_1_en",20504,], -["features.startchat.impl.root_StartChatView_Day_2_en","features.startchat.impl.root_StartChatView_Night_2_en",20504,], -["features.startchat.impl.root_StartChatView_Day_3_en","features.startchat.impl.root_StartChatView_Night_3_en",20504,], -["features.startchat.impl.root_StartChatView_Day_4_en","features.startchat.impl.root_StartChatView_Night_4_en",20504,], -["features.startchat.impl.root_StartChatView_Day_5_en","features.startchat.impl.root_StartChatView_Night_5_en",20504,], -["features.location.api.internal_StaticMapPlaceholder_Day_0_en","features.location.api.internal_StaticMapPlaceholder_Night_0_en",20504,], +["features.startchat.impl.root_StartChatView_Day_0_en","features.startchat.impl.root_StartChatView_Night_0_en",20511,], +["features.startchat.impl.root_StartChatView_Day_1_en","features.startchat.impl.root_StartChatView_Night_1_en",20511,], +["features.startchat.impl.root_StartChatView_Day_2_en","features.startchat.impl.root_StartChatView_Night_2_en",20511,], +["features.startchat.impl.root_StartChatView_Day_3_en","features.startchat.impl.root_StartChatView_Night_3_en",20511,], +["features.startchat.impl.root_StartChatView_Day_4_en","features.startchat.impl.root_StartChatView_Night_4_en",20511,], +["features.startchat.impl.root_StartChatView_Day_5_en","features.startchat.impl.root_StartChatView_Night_5_en",20511,], +["features.location.api.internal_StaticMapPlaceholder_Day_0_en","features.location.api.internal_StaticMapPlaceholder_Night_0_en",20511,], ["features.location.api_StaticMapView_Day_0_en","features.location.api_StaticMapView_Night_0_en",0,], -["features.messages.impl.messagecomposer.suggestions_SuggestionsPickerView_Day_0_en","features.messages.impl.messagecomposer.suggestions_SuggestionsPickerView_Night_0_en",20504,], +["features.messages.impl.messagecomposer.suggestions_SuggestionsPickerView_Day_0_en","features.messages.impl.messagecomposer.suggestions_SuggestionsPickerView_Night_0_en",20511,], ["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",20504,], +["appnav.loggedin_SyncStateView_Day_0_en","appnav.loggedin_SyncStateView_Night_0_en",20511,], ["libraries.designsystem.components.avatar.internal_TextAvatar_Avatars_en","",0,], ["libraries.designsystem.theme.components_TextButtonLargeLowPadding_Buttons_en","",0,], ["libraries.designsystem.theme.components_TextButtonLarge_Buttons_en","",0,], ["libraries.designsystem.theme.components_TextButtonMediumLowPadding_Buttons_en","",0,], ["libraries.designsystem.theme.components_TextButtonMedium_Buttons_en","",0,], ["libraries.designsystem.theme.components_TextButtonSmall_Buttons_en","",0,], -["libraries.textcomposer_TextComposerAddCaption_Day_0_en","libraries.textcomposer_TextComposerAddCaption_Night_0_en",20504,], -["libraries.textcomposer_TextComposerCaption_Day_0_en","libraries.textcomposer_TextComposerCaption_Night_0_en",20504,], -["libraries.textcomposer_TextComposerEditCaption_Day_0_en","libraries.textcomposer_TextComposerEditCaption_Night_0_en",20504,], -["libraries.textcomposer_TextComposerEditNotEncrypted_Day_0_en","libraries.textcomposer_TextComposerEditNotEncrypted_Night_0_en",20504,], -["libraries.textcomposer_TextComposerEdit_Day_0_en","libraries.textcomposer_TextComposerEdit_Night_0_en",20504,], -["libraries.textcomposer_TextComposerFormattingNotEncrypted_Day_0_en","libraries.textcomposer_TextComposerFormattingNotEncrypted_Night_0_en",20504,], -["libraries.textcomposer_TextComposerFormatting_Day_0_en","libraries.textcomposer_TextComposerFormatting_Night_0_en",20504,], -["libraries.textcomposer_TextComposerLinkDialogCreateLinkWithoutText_Day_0_en","libraries.textcomposer_TextComposerLinkDialogCreateLinkWithoutText_Night_0_en",20504,], -["libraries.textcomposer_TextComposerLinkDialogCreateLink_Day_0_en","libraries.textcomposer_TextComposerLinkDialogCreateLink_Night_0_en",20504,], -["libraries.textcomposer_TextComposerLinkDialogEditLink_Day_0_en","libraries.textcomposer_TextComposerLinkDialogEditLink_Night_0_en",20504,], -["libraries.textcomposer_TextComposerReplyNotEncrypted_Day_0_en","libraries.textcomposer_TextComposerReplyNotEncrypted_Night_0_en",20504,], -["libraries.textcomposer_TextComposerReplyNotEncrypted_Day_10_en","libraries.textcomposer_TextComposerReplyNotEncrypted_Night_10_en",20504,], -["libraries.textcomposer_TextComposerReplyNotEncrypted_Day_11_en","libraries.textcomposer_TextComposerReplyNotEncrypted_Night_11_en",20504,], -["libraries.textcomposer_TextComposerReplyNotEncrypted_Day_1_en","libraries.textcomposer_TextComposerReplyNotEncrypted_Night_1_en",20504,], -["libraries.textcomposer_TextComposerReplyNotEncrypted_Day_2_en","libraries.textcomposer_TextComposerReplyNotEncrypted_Night_2_en",20504,], -["libraries.textcomposer_TextComposerReplyNotEncrypted_Day_3_en","libraries.textcomposer_TextComposerReplyNotEncrypted_Night_3_en",20504,], -["libraries.textcomposer_TextComposerReplyNotEncrypted_Day_4_en","libraries.textcomposer_TextComposerReplyNotEncrypted_Night_4_en",20504,], -["libraries.textcomposer_TextComposerReplyNotEncrypted_Day_5_en","libraries.textcomposer_TextComposerReplyNotEncrypted_Night_5_en",20504,], -["libraries.textcomposer_TextComposerReplyNotEncrypted_Day_6_en","libraries.textcomposer_TextComposerReplyNotEncrypted_Night_6_en",20504,], -["libraries.textcomposer_TextComposerReplyNotEncrypted_Day_7_en","libraries.textcomposer_TextComposerReplyNotEncrypted_Night_7_en",20504,], -["libraries.textcomposer_TextComposerReplyNotEncrypted_Day_8_en","libraries.textcomposer_TextComposerReplyNotEncrypted_Night_8_en",20504,], -["libraries.textcomposer_TextComposerReplyNotEncrypted_Day_9_en","libraries.textcomposer_TextComposerReplyNotEncrypted_Night_9_en",20504,], -["libraries.textcomposer_TextComposerReply_Day_0_en","libraries.textcomposer_TextComposerReply_Night_0_en",20504,], -["libraries.textcomposer_TextComposerReply_Day_10_en","libraries.textcomposer_TextComposerReply_Night_10_en",20504,], -["libraries.textcomposer_TextComposerReply_Day_11_en","libraries.textcomposer_TextComposerReply_Night_11_en",20504,], -["libraries.textcomposer_TextComposerReply_Day_1_en","libraries.textcomposer_TextComposerReply_Night_1_en",20504,], -["libraries.textcomposer_TextComposerReply_Day_2_en","libraries.textcomposer_TextComposerReply_Night_2_en",20504,], -["libraries.textcomposer_TextComposerReply_Day_3_en","libraries.textcomposer_TextComposerReply_Night_3_en",20504,], -["libraries.textcomposer_TextComposerReply_Day_4_en","libraries.textcomposer_TextComposerReply_Night_4_en",20504,], -["libraries.textcomposer_TextComposerReply_Day_5_en","libraries.textcomposer_TextComposerReply_Night_5_en",20504,], -["libraries.textcomposer_TextComposerReply_Day_6_en","libraries.textcomposer_TextComposerReply_Night_6_en",20504,], -["libraries.textcomposer_TextComposerReply_Day_7_en","libraries.textcomposer_TextComposerReply_Night_7_en",20504,], -["libraries.textcomposer_TextComposerReply_Day_8_en","libraries.textcomposer_TextComposerReply_Night_8_en",20504,], -["libraries.textcomposer_TextComposerReply_Day_9_en","libraries.textcomposer_TextComposerReply_Night_9_en",20504,], -["libraries.textcomposer_TextComposerSimpleNotEncrypted_Day_0_en","libraries.textcomposer_TextComposerSimpleNotEncrypted_Night_0_en",20504,], -["libraries.textcomposer_TextComposerSimple_Day_0_en","libraries.textcomposer_TextComposerSimple_Night_0_en",20504,], -["libraries.textcomposer_TextComposerVoiceNotEncrypted_Day_0_en","libraries.textcomposer_TextComposerVoiceNotEncrypted_Night_0_en",20504,], +["libraries.textcomposer_TextComposerAddCaption_Day_0_en","libraries.textcomposer_TextComposerAddCaption_Night_0_en",20511,], +["libraries.textcomposer_TextComposerCaption_Day_0_en","libraries.textcomposer_TextComposerCaption_Night_0_en",20511,], +["libraries.textcomposer_TextComposerEditCaption_Day_0_en","libraries.textcomposer_TextComposerEditCaption_Night_0_en",20511,], +["libraries.textcomposer_TextComposerEditNotEncrypted_Day_0_en","libraries.textcomposer_TextComposerEditNotEncrypted_Night_0_en",20511,], +["libraries.textcomposer_TextComposerEdit_Day_0_en","libraries.textcomposer_TextComposerEdit_Night_0_en",20511,], +["libraries.textcomposer_TextComposerFormattingNotEncrypted_Day_0_en","libraries.textcomposer_TextComposerFormattingNotEncrypted_Night_0_en",20511,], +["libraries.textcomposer_TextComposerFormatting_Day_0_en","libraries.textcomposer_TextComposerFormatting_Night_0_en",20511,], +["libraries.textcomposer_TextComposerLinkDialogCreateLinkWithoutText_Day_0_en","libraries.textcomposer_TextComposerLinkDialogCreateLinkWithoutText_Night_0_en",20511,], +["libraries.textcomposer_TextComposerLinkDialogCreateLink_Day_0_en","libraries.textcomposer_TextComposerLinkDialogCreateLink_Night_0_en",20511,], +["libraries.textcomposer_TextComposerLinkDialogEditLink_Day_0_en","libraries.textcomposer_TextComposerLinkDialogEditLink_Night_0_en",20511,], +["libraries.textcomposer_TextComposerReplyNotEncrypted_Day_0_en","libraries.textcomposer_TextComposerReplyNotEncrypted_Night_0_en",20511,], +["libraries.textcomposer_TextComposerReplyNotEncrypted_Day_10_en","libraries.textcomposer_TextComposerReplyNotEncrypted_Night_10_en",20511,], +["libraries.textcomposer_TextComposerReplyNotEncrypted_Day_11_en","libraries.textcomposer_TextComposerReplyNotEncrypted_Night_11_en",20511,], +["libraries.textcomposer_TextComposerReplyNotEncrypted_Day_1_en","libraries.textcomposer_TextComposerReplyNotEncrypted_Night_1_en",20511,], +["libraries.textcomposer_TextComposerReplyNotEncrypted_Day_2_en","libraries.textcomposer_TextComposerReplyNotEncrypted_Night_2_en",20511,], +["libraries.textcomposer_TextComposerReplyNotEncrypted_Day_3_en","libraries.textcomposer_TextComposerReplyNotEncrypted_Night_3_en",20511,], +["libraries.textcomposer_TextComposerReplyNotEncrypted_Day_4_en","libraries.textcomposer_TextComposerReplyNotEncrypted_Night_4_en",20511,], +["libraries.textcomposer_TextComposerReplyNotEncrypted_Day_5_en","libraries.textcomposer_TextComposerReplyNotEncrypted_Night_5_en",20511,], +["libraries.textcomposer_TextComposerReplyNotEncrypted_Day_6_en","libraries.textcomposer_TextComposerReplyNotEncrypted_Night_6_en",20511,], +["libraries.textcomposer_TextComposerReplyNotEncrypted_Day_7_en","libraries.textcomposer_TextComposerReplyNotEncrypted_Night_7_en",20511,], +["libraries.textcomposer_TextComposerReplyNotEncrypted_Day_8_en","libraries.textcomposer_TextComposerReplyNotEncrypted_Night_8_en",20511,], +["libraries.textcomposer_TextComposerReplyNotEncrypted_Day_9_en","libraries.textcomposer_TextComposerReplyNotEncrypted_Night_9_en",20511,], +["libraries.textcomposer_TextComposerReply_Day_0_en","libraries.textcomposer_TextComposerReply_Night_0_en",20511,], +["libraries.textcomposer_TextComposerReply_Day_10_en","libraries.textcomposer_TextComposerReply_Night_10_en",20511,], +["libraries.textcomposer_TextComposerReply_Day_11_en","libraries.textcomposer_TextComposerReply_Night_11_en",20511,], +["libraries.textcomposer_TextComposerReply_Day_1_en","libraries.textcomposer_TextComposerReply_Night_1_en",20511,], +["libraries.textcomposer_TextComposerReply_Day_2_en","libraries.textcomposer_TextComposerReply_Night_2_en",20511,], +["libraries.textcomposer_TextComposerReply_Day_3_en","libraries.textcomposer_TextComposerReply_Night_3_en",20511,], +["libraries.textcomposer_TextComposerReply_Day_4_en","libraries.textcomposer_TextComposerReply_Night_4_en",20511,], +["libraries.textcomposer_TextComposerReply_Day_5_en","libraries.textcomposer_TextComposerReply_Night_5_en",20511,], +["libraries.textcomposer_TextComposerReply_Day_6_en","libraries.textcomposer_TextComposerReply_Night_6_en",20511,], +["libraries.textcomposer_TextComposerReply_Day_7_en","libraries.textcomposer_TextComposerReply_Night_7_en",20511,], +["libraries.textcomposer_TextComposerReply_Day_8_en","libraries.textcomposer_TextComposerReply_Night_8_en",20511,], +["libraries.textcomposer_TextComposerReply_Day_9_en","libraries.textcomposer_TextComposerReply_Night_9_en",20511,], +["libraries.textcomposer_TextComposerSimpleNotEncrypted_Day_0_en","libraries.textcomposer_TextComposerSimpleNotEncrypted_Night_0_en",20511,], +["libraries.textcomposer_TextComposerSimple_Day_0_en","libraries.textcomposer_TextComposerSimple_Night_0_en",20511,], +["libraries.textcomposer_TextComposerVoiceNotEncrypted_Day_0_en","libraries.textcomposer_TextComposerVoiceNotEncrypted_Night_0_en",20511,], ["libraries.textcomposer_TextComposerVoice_Day_0_en","libraries.textcomposer_TextComposerVoice_Night_0_en",0,], ["libraries.designsystem.theme.components_TextDark_Text_en","",0,], -["libraries.designsystem.components.dialogs_TextFieldDialogWithError_Day_0_en","libraries.designsystem.components.dialogs_TextFieldDialogWithError_Night_0_en",20504,], -["libraries.designsystem.components.dialogs_TextFieldDialog_Day_0_en","libraries.designsystem.components.dialogs_TextFieldDialog_Night_0_en",20504,], +["libraries.designsystem.components.dialogs_TextFieldDialogWithError_Day_0_en","libraries.designsystem.components.dialogs_TextFieldDialogWithError_Night_0_en",20511,], +["libraries.designsystem.components.dialogs_TextFieldDialog_Day_0_en","libraries.designsystem.components.dialogs_TextFieldDialog_Night_0_en",20511,], ["libraries.designsystem.components.list_TextFieldListItemEmpty_Text_field_List_item_-_empty_List_items_en","",0,], ["libraries.designsystem.components.list_TextFieldListItemTextFieldValue_Text_field_List_item_-_textfieldvalue_List_items_en","",0,], ["libraries.designsystem.components.list_TextFieldListItem_Text_field_List_item_-_text_List_items_en","",0,], @@ -1382,16 +1385,16 @@ export const screenshots = [ ["libraries.mediaviewer.impl.local.txt_TextFileContentView_Day_3_en","libraries.mediaviewer.impl.local.txt_TextFileContentView_Night_3_en",0,], ["libraries.textcomposer.components_TextFormatting_Day_0_en","libraries.textcomposer.components_TextFormatting_Night_0_en",0,], ["libraries.designsystem.theme.components_TextLight_Text_en","",0,], -["features.messages.impl.timeline.components_ThreadSummaryView_Day_0_en","features.messages.impl.timeline.components_ThreadSummaryView_Night_0_en",20504,], -["features.messages.impl.topbars_ThreadTopBar_Day_0_en","features.messages.impl.topbars_ThreadTopBar_Night_0_en",20504,], -["libraries.designsystem.theme.components.previews_TimePickerHorizontal_DateTime_pickers_en","",20504,], -["libraries.designsystem.theme.components.previews_TimePickerVerticalDark_DateTime_pickers_en","",20504,], -["libraries.designsystem.theme.components.previews_TimePickerVerticalLight_DateTime_pickers_en","",20504,], +["features.messages.impl.timeline.components_ThreadSummaryView_Day_0_en","features.messages.impl.timeline.components_ThreadSummaryView_Night_0_en",20511,], +["features.messages.impl.topbars_ThreadTopBar_Day_0_en","features.messages.impl.topbars_ThreadTopBar_Night_0_en",20511,], +["libraries.designsystem.theme.components.previews_TimePickerHorizontal_DateTime_pickers_en","",20511,], +["libraries.designsystem.theme.components.previews_TimePickerVerticalDark_DateTime_pickers_en","",20511,], +["libraries.designsystem.theme.components.previews_TimePickerVerticalLight_DateTime_pickers_en","",20511,], ["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",20504,], -["features.messages.impl.timeline.components_TimelineEventTimestampView_Day_4_en","features.messages.impl.timeline.components_TimelineEventTimestampView_Night_4_en",20504,], +["features.messages.impl.timeline.components_TimelineEventTimestampView_Day_3_en","features.messages.impl.timeline.components_TimelineEventTimestampView_Night_3_en",20511,], +["features.messages.impl.timeline.components_TimelineEventTimestampView_Day_4_en","features.messages.impl.timeline.components_TimelineEventTimestampView_Night_4_en",20511,], ["features.messages.impl.timeline.components_TimelineEventTimestampView_Day_5_en","features.messages.impl.timeline.components_TimelineEventTimestampView_Night_5_en",0,], ["features.messages.impl.timeline.components_TimelineEventTimestampView_Day_6_en","features.messages.impl.timeline.components_TimelineEventTimestampView_Night_6_en",0,], ["features.messages.impl.timeline.components_TimelineEventTimestampView_Day_7_en","features.messages.impl.timeline.components_TimelineEventTimestampView_Night_7_en",0,], @@ -1401,18 +1404,18 @@ export const screenshots = [ ["features.messages.impl.timeline.components.event_TimelineItemAudioView_Day_2_en","features.messages.impl.timeline.components.event_TimelineItemAudioView_Night_2_en",0,], ["features.messages.impl.timeline.components.event_TimelineItemAudioView_Day_3_en","features.messages.impl.timeline.components.event_TimelineItemAudioView_Night_3_en",0,], ["features.messages.impl.timeline.components.event_TimelineItemAudioView_Day_4_en","features.messages.impl.timeline.components.event_TimelineItemAudioView_Night_4_en",0,], -["features.messages.impl.timeline.components_TimelineItemCallNotifyView_Day_0_en","features.messages.impl.timeline.components_TimelineItemCallNotifyView_Night_0_en",20504,], +["features.messages.impl.timeline.components_TimelineItemCallNotifyView_Day_0_en","features.messages.impl.timeline.components_TimelineItemCallNotifyView_Night_0_en",20511,], ["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",20504,], -["features.messages.impl.timeline.components.event_TimelineItemEncryptedView_Day_1_en","features.messages.impl.timeline.components.event_TimelineItemEncryptedView_Night_1_en",20504,], -["features.messages.impl.timeline.components.event_TimelineItemEncryptedView_Day_2_en","features.messages.impl.timeline.components.event_TimelineItemEncryptedView_Night_2_en",20504,], -["features.messages.impl.timeline.components.event_TimelineItemEncryptedView_Day_3_en","features.messages.impl.timeline.components.event_TimelineItemEncryptedView_Night_3_en",20504,], -["features.messages.impl.timeline.components.event_TimelineItemEncryptedView_Day_4_en","features.messages.impl.timeline.components.event_TimelineItemEncryptedView_Night_4_en",20504,], -["features.messages.impl.timeline.components.event_TimelineItemEncryptedView_Day_5_en","features.messages.impl.timeline.components.event_TimelineItemEncryptedView_Night_5_en",20504,], -["features.messages.impl.timeline.components.event_TimelineItemEncryptedView_Day_6_en","features.messages.impl.timeline.components.event_TimelineItemEncryptedView_Night_6_en",20504,], -["features.messages.impl.timeline.components.event_TimelineItemEncryptedView_Day_7_en","features.messages.impl.timeline.components.event_TimelineItemEncryptedView_Night_7_en",20504,], -["features.messages.impl.timeline.components.event_TimelineItemEncryptedView_Day_8_en","features.messages.impl.timeline.components.event_TimelineItemEncryptedView_Night_8_en",20504,], +["features.messages.impl.timeline.components.event_TimelineItemEncryptedView_Day_0_en","features.messages.impl.timeline.components.event_TimelineItemEncryptedView_Night_0_en",20511,], +["features.messages.impl.timeline.components.event_TimelineItemEncryptedView_Day_1_en","features.messages.impl.timeline.components.event_TimelineItemEncryptedView_Night_1_en",20511,], +["features.messages.impl.timeline.components.event_TimelineItemEncryptedView_Day_2_en","features.messages.impl.timeline.components.event_TimelineItemEncryptedView_Night_2_en",20511,], +["features.messages.impl.timeline.components.event_TimelineItemEncryptedView_Day_3_en","features.messages.impl.timeline.components.event_TimelineItemEncryptedView_Night_3_en",20511,], +["features.messages.impl.timeline.components.event_TimelineItemEncryptedView_Day_4_en","features.messages.impl.timeline.components.event_TimelineItemEncryptedView_Night_4_en",20511,], +["features.messages.impl.timeline.components.event_TimelineItemEncryptedView_Day_5_en","features.messages.impl.timeline.components.event_TimelineItemEncryptedView_Night_5_en",20511,], +["features.messages.impl.timeline.components.event_TimelineItemEncryptedView_Day_6_en","features.messages.impl.timeline.components.event_TimelineItemEncryptedView_Night_6_en",20511,], +["features.messages.impl.timeline.components.event_TimelineItemEncryptedView_Day_7_en","features.messages.impl.timeline.components.event_TimelineItemEncryptedView_Night_7_en",20511,], +["features.messages.impl.timeline.components.event_TimelineItemEncryptedView_Day_8_en","features.messages.impl.timeline.components.event_TimelineItemEncryptedView_Night_8_en",20511,], ["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,], @@ -1420,18 +1423,18 @@ export const screenshots = [ ["features.messages.impl.timeline.components_TimelineItemEventRowTimestamp_Day_0_en","features.messages.impl.timeline.components_TimelineItemEventRowTimestamp_Night_0_en",0,], ["features.messages.impl.timeline.components_TimelineItemEventRowTimestamp_Day_1_en","features.messages.impl.timeline.components_TimelineItemEventRowTimestamp_Night_1_en",0,], ["features.messages.impl.timeline.components_TimelineItemEventRowTimestamp_Day_2_en","features.messages.impl.timeline.components_TimelineItemEventRowTimestamp_Night_2_en",0,], -["features.messages.impl.timeline.components_TimelineItemEventRowTimestamp_Day_3_en","features.messages.impl.timeline.components_TimelineItemEventRowTimestamp_Night_3_en",20504,], -["features.messages.impl.timeline.components_TimelineItemEventRowTimestamp_Day_4_en","features.messages.impl.timeline.components_TimelineItemEventRowTimestamp_Night_4_en",20504,], +["features.messages.impl.timeline.components_TimelineItemEventRowTimestamp_Day_3_en","features.messages.impl.timeline.components_TimelineItemEventRowTimestamp_Night_3_en",20511,], +["features.messages.impl.timeline.components_TimelineItemEventRowTimestamp_Day_4_en","features.messages.impl.timeline.components_TimelineItemEventRowTimestamp_Night_4_en",20511,], ["features.messages.impl.timeline.components_TimelineItemEventRowTimestamp_Day_5_en","features.messages.impl.timeline.components_TimelineItemEventRowTimestamp_Night_5_en",0,], ["features.messages.impl.timeline.components_TimelineItemEventRowTimestamp_Day_6_en","features.messages.impl.timeline.components_TimelineItemEventRowTimestamp_Night_6_en",0,], -["features.messages.impl.timeline.components_TimelineItemEventRowTimestamp_Day_7_en","features.messages.impl.timeline.components_TimelineItemEventRowTimestamp_Night_7_en",20504,], -["features.messages.impl.timeline.components_TimelineItemEventRowUtd_Day_0_en","features.messages.impl.timeline.components_TimelineItemEventRowUtd_Night_0_en",20504,], -["features.messages.impl.timeline.components_TimelineItemEventRowWithManyReactions_Day_0_en","features.messages.impl.timeline.components_TimelineItemEventRowWithManyReactions_Night_0_en",20504,], +["features.messages.impl.timeline.components_TimelineItemEventRowTimestamp_Day_7_en","features.messages.impl.timeline.components_TimelineItemEventRowTimestamp_Night_7_en",20511,], +["features.messages.impl.timeline.components_TimelineItemEventRowUtd_Day_0_en","features.messages.impl.timeline.components_TimelineItemEventRowUtd_Night_0_en",20511,], +["features.messages.impl.timeline.components_TimelineItemEventRowWithManyReactions_Day_0_en","features.messages.impl.timeline.components_TimelineItemEventRowWithManyReactions_Night_0_en",20511,], ["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",20504,], -["features.messages.impl.timeline.components_TimelineItemEventRowWithReplyInformative_Day_1_en","features.messages.impl.timeline.components_TimelineItemEventRowWithReplyInformative_Night_1_en",20504,], +["features.messages.impl.timeline.components_TimelineItemEventRowWithReplyInformative_Day_0_en","features.messages.impl.timeline.components_TimelineItemEventRowWithReplyInformative_Night_0_en",20511,], +["features.messages.impl.timeline.components_TimelineItemEventRowWithReplyInformative_Day_1_en","features.messages.impl.timeline.components_TimelineItemEventRowWithReplyInformative_Night_1_en",20511,], ["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,], @@ -1440,41 +1443,41 @@ export const screenshots = [ ["features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Day_1_en","features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Night_1_en",0,], ["features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Day_2_en","features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Night_2_en",0,], ["features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Day_3_en","features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Night_3_en",0,], -["features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Day_4_en","features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Night_4_en",20504,], +["features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Day_4_en","features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Night_4_en",20511,], ["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",20504,], +["features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Day_8_en","features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Night_8_en",20511,], ["features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Day_9_en","features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Night_9_en",0,], -["features.messages.impl.timeline.components_TimelineItemEventRowWithThreadSummary_Day_0_en","features.messages.impl.timeline.components_TimelineItemEventRowWithThreadSummary_Night_0_en",20504,], +["features.messages.impl.timeline.components_TimelineItemEventRowWithThreadSummary_Day_0_en","features.messages.impl.timeline.components_TimelineItemEventRowWithThreadSummary_Night_0_en",20511,], ["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","",20504,], +["features.messages.impl.timeline.components_TimelineItemEventTimestampBelow_en","",20511,], ["features.messages.impl.timeline.components.event_TimelineItemFileView_Day_0_en","features.messages.impl.timeline.components.event_TimelineItemFileView_Night_0_en",0,], ["features.messages.impl.timeline.components.event_TimelineItemFileView_Day_1_en","features.messages.impl.timeline.components.event_TimelineItemFileView_Night_1_en",0,], ["features.messages.impl.timeline.components.event_TimelineItemFileView_Day_2_en","features.messages.impl.timeline.components.event_TimelineItemFileView_Night_2_en",0,], ["features.messages.impl.timeline.components.event_TimelineItemFileView_Day_3_en","features.messages.impl.timeline.components.event_TimelineItemFileView_Night_3_en",0,], ["features.messages.impl.timeline.components.event_TimelineItemFileView_Day_4_en","features.messages.impl.timeline.components.event_TimelineItemFileView_Night_4_en",0,], -["features.messages.impl.timeline.components_TimelineItemGroupedEventsRowContentCollapse_Day_0_en","features.messages.impl.timeline.components_TimelineItemGroupedEventsRowContentCollapse_Night_0_en",20504,], -["features.messages.impl.timeline.components_TimelineItemGroupedEventsRowContentExpanded_Day_0_en","features.messages.impl.timeline.components_TimelineItemGroupedEventsRowContentExpanded_Night_0_en",20504,], -["features.messages.impl.timeline.components.event_TimelineItemImageViewHideMediaContent_Day_0_en","features.messages.impl.timeline.components.event_TimelineItemImageViewHideMediaContent_Night_0_en",20504,], +["features.messages.impl.timeline.components_TimelineItemGroupedEventsRowContentCollapse_Day_0_en","features.messages.impl.timeline.components_TimelineItemGroupedEventsRowContentCollapse_Night_0_en",20511,], +["features.messages.impl.timeline.components_TimelineItemGroupedEventsRowContentExpanded_Day_0_en","features.messages.impl.timeline.components_TimelineItemGroupedEventsRowContentExpanded_Night_0_en",20511,], +["features.messages.impl.timeline.components.event_TimelineItemImageViewHideMediaContent_Day_0_en","features.messages.impl.timeline.components.event_TimelineItemImageViewHideMediaContent_Night_0_en",20511,], ["features.messages.impl.timeline.components.event_TimelineItemImageView_Day_0_en","features.messages.impl.timeline.components.event_TimelineItemImageView_Night_0_en",0,], ["features.messages.impl.timeline.components.event_TimelineItemImageView_Day_1_en","features.messages.impl.timeline.components.event_TimelineItemImageView_Night_1_en",0,], ["features.messages.impl.timeline.components.event_TimelineItemImageView_Day_2_en","features.messages.impl.timeline.components.event_TimelineItemImageView_Night_2_en",0,], ["features.messages.impl.timeline.components.event_TimelineItemImageView_Day_3_en","features.messages.impl.timeline.components.event_TimelineItemImageView_Night_3_en",0,], ["features.messages.impl.timeline.components.event_TimelineItemInformativeView_Day_0_en","features.messages.impl.timeline.components.event_TimelineItemInformativeView_Night_0_en",0,], -["features.messages.impl.timeline.components.event_TimelineItemLegacyCallInviteView_Day_0_en","features.messages.impl.timeline.components.event_TimelineItemLegacyCallInviteView_Night_0_en",20504,], +["features.messages.impl.timeline.components.event_TimelineItemLegacyCallInviteView_Day_0_en","features.messages.impl.timeline.components.event_TimelineItemLegacyCallInviteView_Night_0_en",20511,], ["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",20504,], -["features.messages.impl.timeline.components.event_TimelineItemPollView_Day_1_en","features.messages.impl.timeline.components.event_TimelineItemPollView_Night_1_en",20504,], -["features.messages.impl.timeline.components.event_TimelineItemPollView_Day_2_en","features.messages.impl.timeline.components.event_TimelineItemPollView_Night_2_en",20504,], -["features.messages.impl.timeline.components.event_TimelineItemPollView_Day_3_en","features.messages.impl.timeline.components.event_TimelineItemPollView_Night_3_en",20504,], -["features.messages.impl.timeline.components_TimelineItemReactionsLayout_Day_0_en","features.messages.impl.timeline.components_TimelineItemReactionsLayout_Night_0_en",20504,], +["features.messages.impl.timeline.components.event_TimelineItemPollView_Day_0_en","features.messages.impl.timeline.components.event_TimelineItemPollView_Night_0_en",20511,], +["features.messages.impl.timeline.components.event_TimelineItemPollView_Day_1_en","features.messages.impl.timeline.components.event_TimelineItemPollView_Night_1_en",20511,], +["features.messages.impl.timeline.components.event_TimelineItemPollView_Day_2_en","features.messages.impl.timeline.components.event_TimelineItemPollView_Night_2_en",20511,], +["features.messages.impl.timeline.components.event_TimelineItemPollView_Day_3_en","features.messages.impl.timeline.components.event_TimelineItemPollView_Night_3_en",20511,], +["features.messages.impl.timeline.components_TimelineItemReactionsLayout_Day_0_en","features.messages.impl.timeline.components_TimelineItemReactionsLayout_Night_0_en",20511,], ["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",20504,], -["features.messages.impl.timeline.components_TimelineItemReactionsViewOutgoing_Day_0_en","features.messages.impl.timeline.components_TimelineItemReactionsViewOutgoing_Night_0_en",20504,], +["features.messages.impl.timeline.components_TimelineItemReactionsViewIncoming_Day_0_en","features.messages.impl.timeline.components_TimelineItemReactionsViewIncoming_Night_0_en",20511,], +["features.messages.impl.timeline.components_TimelineItemReactionsViewOutgoing_Day_0_en","features.messages.impl.timeline.components_TimelineItemReactionsViewOutgoing_Night_0_en",20511,], ["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",20504,], +["features.messages.impl.timeline.components.virtual_TimelineItemReadMarkerView_Day_0_en","features.messages.impl.timeline.components.virtual_TimelineItemReadMarkerView_Night_0_en",20511,], ["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,], @@ -1483,8 +1486,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",20504,], -["features.messages.impl.timeline.components.virtual_TimelineItemRoomBeginningView_Day_0_en","features.messages.impl.timeline.components.virtual_TimelineItemRoomBeginningView_Night_0_en",20504,], +["features.messages.impl.timeline.components.event_TimelineItemRedactedView_Day_0_en","features.messages.impl.timeline.components.event_TimelineItemRedactedView_Night_0_en",20511,], +["features.messages.impl.timeline.components.virtual_TimelineItemRoomBeginningView_Day_0_en","features.messages.impl.timeline.components.virtual_TimelineItemRoomBeginningView_Night_0_en",20511,], ["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,], @@ -1499,8 +1502,8 @@ export const screenshots = [ ["features.messages.impl.timeline.components.event_TimelineItemTextView_Day_3_en","features.messages.impl.timeline.components.event_TimelineItemTextView_Night_3_en",0,], ["features.messages.impl.timeline.components.event_TimelineItemTextView_Day_4_en","features.messages.impl.timeline.components.event_TimelineItemTextView_Night_4_en",0,], ["features.messages.impl.timeline.components.event_TimelineItemTextView_Day_5_en","features.messages.impl.timeline.components.event_TimelineItemTextView_Night_5_en",0,], -["features.messages.impl.timeline.components.event_TimelineItemUnknownView_Day_0_en","features.messages.impl.timeline.components.event_TimelineItemUnknownView_Night_0_en",20504,], -["features.messages.impl.timeline.components.event_TimelineItemVideoViewHideMediaContent_Day_0_en","features.messages.impl.timeline.components.event_TimelineItemVideoViewHideMediaContent_Night_0_en",20504,], +["features.messages.impl.timeline.components.event_TimelineItemUnknownView_Day_0_en","features.messages.impl.timeline.components.event_TimelineItemUnknownView_Night_0_en",20511,], +["features.messages.impl.timeline.components.event_TimelineItemVideoViewHideMediaContent_Day_0_en","features.messages.impl.timeline.components.event_TimelineItemVideoViewHideMediaContent_Night_0_en",20511,], ["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,], @@ -1523,84 +1526,84 @@ export const screenshots = [ ["features.messages.impl.timeline.components.event_TimelineItemVoiceView_Day_9_en","features.messages.impl.timeline.components.event_TimelineItemVoiceView_Night_9_en",0,], ["features.messages.impl.timeline.components.virtual_TimelineLoadingMoreIndicator_Day_0_en","features.messages.impl.timeline.components.virtual_TimelineLoadingMoreIndicator_Night_0_en",0,], ["features.messages.impl.timeline.components.event_TimelineVideoWithCaptionRow_Day_0_en","features.messages.impl.timeline.components.event_TimelineVideoWithCaptionRow_Night_0_en",0,], -["features.messages.impl.timeline_TimelineViewMessageShield_Day_0_en","features.messages.impl.timeline_TimelineViewMessageShield_Night_0_en",20504,], -["features.messages.impl.timeline_TimelineView_Day_0_en","features.messages.impl.timeline_TimelineView_Night_0_en",20504,], +["features.messages.impl.timeline_TimelineViewMessageShield_Day_0_en","features.messages.impl.timeline_TimelineViewMessageShield_Night_0_en",20511,], +["features.messages.impl.timeline_TimelineView_Day_0_en","features.messages.impl.timeline_TimelineView_Night_0_en",20511,], ["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",20504,], -["features.messages.impl.timeline_TimelineView_Day_12_en","features.messages.impl.timeline_TimelineView_Night_12_en",20504,], -["features.messages.impl.timeline_TimelineView_Day_13_en","features.messages.impl.timeline_TimelineView_Night_13_en",20504,], -["features.messages.impl.timeline_TimelineView_Day_14_en","features.messages.impl.timeline_TimelineView_Night_14_en",20504,], -["features.messages.impl.timeline_TimelineView_Day_15_en","features.messages.impl.timeline_TimelineView_Night_15_en",20504,], -["features.messages.impl.timeline_TimelineView_Day_16_en","features.messages.impl.timeline_TimelineView_Night_16_en",20504,], -["features.messages.impl.timeline_TimelineView_Day_17_en","features.messages.impl.timeline_TimelineView_Night_17_en",20504,], -["features.messages.impl.timeline_TimelineView_Day_1_en","features.messages.impl.timeline_TimelineView_Night_1_en",20504,], +["features.messages.impl.timeline_TimelineView_Day_11_en","features.messages.impl.timeline_TimelineView_Night_11_en",20511,], +["features.messages.impl.timeline_TimelineView_Day_12_en","features.messages.impl.timeline_TimelineView_Night_12_en",20511,], +["features.messages.impl.timeline_TimelineView_Day_13_en","features.messages.impl.timeline_TimelineView_Night_13_en",20511,], +["features.messages.impl.timeline_TimelineView_Day_14_en","features.messages.impl.timeline_TimelineView_Night_14_en",20511,], +["features.messages.impl.timeline_TimelineView_Day_15_en","features.messages.impl.timeline_TimelineView_Night_15_en",20511,], +["features.messages.impl.timeline_TimelineView_Day_16_en","features.messages.impl.timeline_TimelineView_Night_16_en",20511,], +["features.messages.impl.timeline_TimelineView_Day_17_en","features.messages.impl.timeline_TimelineView_Night_17_en",20511,], +["features.messages.impl.timeline_TimelineView_Day_1_en","features.messages.impl.timeline_TimelineView_Night_1_en",20511,], ["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",20504,], +["features.messages.impl.timeline_TimelineView_Day_4_en","features.messages.impl.timeline_TimelineView_Night_4_en",20511,], ["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",20504,], +["features.messages.impl.timeline_TimelineView_Day_6_en","features.messages.impl.timeline_TimelineView_Night_6_en",20511,], ["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",0,], ["features.messages.impl.timeline_TimelineView_Day_9_en","features.messages.impl.timeline_TimelineView_Night_9_en",0,], ["libraries.designsystem.components.avatar.internal_TombstonedRoomAvatar_Avatars_en","",0,], ["libraries.designsystem.theme.components_TopAppBarStr_App_Bars_en","",0,], ["libraries.designsystem.theme.components_TopAppBar_App_Bars_en","",0,], -["libraries.troubleshoot.impl_TroubleshootNotificationsView_Day_0_en","libraries.troubleshoot.impl_TroubleshootNotificationsView_Night_0_en",20504,], -["libraries.troubleshoot.impl_TroubleshootNotificationsView_Day_1_en","libraries.troubleshoot.impl_TroubleshootNotificationsView_Night_1_en",20504,], -["libraries.troubleshoot.impl_TroubleshootNotificationsView_Day_2_en","libraries.troubleshoot.impl_TroubleshootNotificationsView_Night_2_en",20504,], -["libraries.troubleshoot.impl_TroubleshootNotificationsView_Day_3_en","libraries.troubleshoot.impl_TroubleshootNotificationsView_Night_3_en",20504,], -["libraries.troubleshoot.impl_TroubleshootNotificationsView_Day_4_en","libraries.troubleshoot.impl_TroubleshootNotificationsView_Night_4_en",20504,], -["libraries.troubleshoot.impl_TroubleshootNotificationsView_Day_5_en","libraries.troubleshoot.impl_TroubleshootNotificationsView_Night_5_en",20504,], -["libraries.troubleshoot.impl_TroubleshootNotificationsView_Day_6_en","libraries.troubleshoot.impl_TroubleshootNotificationsView_Night_6_en",20504,], -["libraries.troubleshoot.impl_TroubleshootNotificationsView_Day_7_en","libraries.troubleshoot.impl_TroubleshootNotificationsView_Night_7_en",20504,], +["libraries.troubleshoot.impl_TroubleshootNotificationsView_Day_0_en","libraries.troubleshoot.impl_TroubleshootNotificationsView_Night_0_en",20511,], +["libraries.troubleshoot.impl_TroubleshootNotificationsView_Day_1_en","libraries.troubleshoot.impl_TroubleshootNotificationsView_Night_1_en",20511,], +["libraries.troubleshoot.impl_TroubleshootNotificationsView_Day_2_en","libraries.troubleshoot.impl_TroubleshootNotificationsView_Night_2_en",20511,], +["libraries.troubleshoot.impl_TroubleshootNotificationsView_Day_3_en","libraries.troubleshoot.impl_TroubleshootNotificationsView_Night_3_en",20511,], +["libraries.troubleshoot.impl_TroubleshootNotificationsView_Day_4_en","libraries.troubleshoot.impl_TroubleshootNotificationsView_Night_4_en",20511,], +["libraries.troubleshoot.impl_TroubleshootNotificationsView_Day_5_en","libraries.troubleshoot.impl_TroubleshootNotificationsView_Night_5_en",20511,], +["libraries.troubleshoot.impl_TroubleshootNotificationsView_Day_6_en","libraries.troubleshoot.impl_TroubleshootNotificationsView_Night_6_en",20511,], +["libraries.troubleshoot.impl_TroubleshootNotificationsView_Day_7_en","libraries.troubleshoot.impl_TroubleshootNotificationsView_Night_7_en",20511,], ["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",20504,], -["features.messages.impl.typing_TypingNotificationView_Day_2_en","features.messages.impl.typing_TypingNotificationView_Night_2_en",20504,], -["features.messages.impl.typing_TypingNotificationView_Day_3_en","features.messages.impl.typing_TypingNotificationView_Night_3_en",20504,], -["features.messages.impl.typing_TypingNotificationView_Day_4_en","features.messages.impl.typing_TypingNotificationView_Night_4_en",20504,], -["features.messages.impl.typing_TypingNotificationView_Day_5_en","features.messages.impl.typing_TypingNotificationView_Night_5_en",20504,], -["features.messages.impl.typing_TypingNotificationView_Day_6_en","features.messages.impl.typing_TypingNotificationView_Night_6_en",20504,], +["features.messages.impl.typing_TypingNotificationView_Day_1_en","features.messages.impl.typing_TypingNotificationView_Night_1_en",20511,], +["features.messages.impl.typing_TypingNotificationView_Day_2_en","features.messages.impl.typing_TypingNotificationView_Night_2_en",20511,], +["features.messages.impl.typing_TypingNotificationView_Day_3_en","features.messages.impl.typing_TypingNotificationView_Night_3_en",20511,], +["features.messages.impl.typing_TypingNotificationView_Day_4_en","features.messages.impl.typing_TypingNotificationView_Night_4_en",20511,], +["features.messages.impl.typing_TypingNotificationView_Day_5_en","features.messages.impl.typing_TypingNotificationView_Night_5_en",20511,], +["features.messages.impl.typing_TypingNotificationView_Day_6_en","features.messages.impl.typing_TypingNotificationView_Night_6_en",20511,], ["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","",20504,], +["libraries.matrix.ui.components_UnresolvedUserRow_en","",20511,], ["libraries.designsystem.components.avatar.internal_UserAvatarColors_Day_0_en","libraries.designsystem.components.avatar.internal_UserAvatarColors_Night_0_en",0,], -["features.roomdetails.impl.notificationsettings_UserDefinedRoomNotificationSettingsView_Day_0_en","features.roomdetails.impl.notificationsettings_UserDefinedRoomNotificationSettingsView_Night_0_en",20504,], -["features.startchat.impl.components_UserListView_Day_0_en","features.startchat.impl.components_UserListView_Night_0_en",20504,], -["features.startchat.impl.components_UserListView_Day_1_en","features.startchat.impl.components_UserListView_Night_1_en",20504,], -["features.startchat.impl.components_UserListView_Day_2_en","features.startchat.impl.components_UserListView_Night_2_en",20504,], +["features.roomdetails.impl.notificationsettings_UserDefinedRoomNotificationSettingsView_Day_0_en","features.roomdetails.impl.notificationsettings_UserDefinedRoomNotificationSettingsView_Night_0_en",20511,], +["features.startchat.impl.components_UserListView_Day_0_en","features.startchat.impl.components_UserListView_Night_0_en",20511,], +["features.startchat.impl.components_UserListView_Day_1_en","features.startchat.impl.components_UserListView_Night_1_en",20511,], +["features.startchat.impl.components_UserListView_Day_2_en","features.startchat.impl.components_UserListView_Night_2_en",20511,], ["features.startchat.impl.components_UserListView_Day_3_en","features.startchat.impl.components_UserListView_Night_3_en",0,], ["features.startchat.impl.components_UserListView_Day_4_en","features.startchat.impl.components_UserListView_Night_4_en",0,], ["features.startchat.impl.components_UserListView_Day_5_en","features.startchat.impl.components_UserListView_Night_5_en",0,], ["features.startchat.impl.components_UserListView_Day_6_en","features.startchat.impl.components_UserListView_Night_6_en",0,], -["features.startchat.impl.components_UserListView_Day_7_en","features.startchat.impl.components_UserListView_Night_7_en",20504,], +["features.startchat.impl.components_UserListView_Day_7_en","features.startchat.impl.components_UserListView_Night_7_en",20511,], ["features.startchat.impl.components_UserListView_Day_8_en","features.startchat.impl.components_UserListView_Night_8_en",0,], -["features.startchat.impl.components_UserListView_Day_9_en","features.startchat.impl.components_UserListView_Night_9_en",20504,], +["features.startchat.impl.components_UserListView_Day_9_en","features.startchat.impl.components_UserListView_Night_9_en",20511,], ["features.preferences.impl.user_UserPreferences_Day_0_en","features.preferences.impl.user_UserPreferences_Night_0_en",0,], ["features.preferences.impl.user_UserPreferences_Day_1_en","features.preferences.impl.user_UserPreferences_Night_1_en",0,], ["features.preferences.impl.user_UserPreferences_Day_2_en","features.preferences.impl.user_UserPreferences_Night_2_en",0,], -["features.userprofile.shared_UserProfileHeaderSectionWithVerificationViolation_Day_0_en","features.userprofile.shared_UserProfileHeaderSectionWithVerificationViolation_Night_0_en",20504,], -["features.userprofile.shared_UserProfileHeaderSection_Day_0_en","features.userprofile.shared_UserProfileHeaderSection_Night_0_en",20504,], -["features.userprofile.shared_UserProfileView_Day_0_en","features.userprofile.shared_UserProfileView_Night_0_en",20504,], -["features.userprofile.shared_UserProfileView_Day_1_en","features.userprofile.shared_UserProfileView_Night_1_en",20504,], -["features.userprofile.shared_UserProfileView_Day_2_en","features.userprofile.shared_UserProfileView_Night_2_en",20504,], -["features.userprofile.shared_UserProfileView_Day_3_en","features.userprofile.shared_UserProfileView_Night_3_en",20504,], -["features.userprofile.shared_UserProfileView_Day_4_en","features.userprofile.shared_UserProfileView_Night_4_en",20504,], -["features.userprofile.shared_UserProfileView_Day_5_en","features.userprofile.shared_UserProfileView_Night_5_en",20504,], -["features.userprofile.shared_UserProfileView_Day_6_en","features.userprofile.shared_UserProfileView_Night_6_en",20504,], -["features.userprofile.shared_UserProfileView_Day_7_en","features.userprofile.shared_UserProfileView_Night_7_en",20504,], -["features.userprofile.shared_UserProfileView_Day_8_en","features.userprofile.shared_UserProfileView_Night_8_en",20504,], -["features.userprofile.shared_UserProfileView_Day_9_en","features.userprofile.shared_UserProfileView_Night_9_en",20504,], +["features.userprofile.shared_UserProfileHeaderSectionWithVerificationViolation_Day_0_en","features.userprofile.shared_UserProfileHeaderSectionWithVerificationViolation_Night_0_en",20511,], +["features.userprofile.shared_UserProfileHeaderSection_Day_0_en","features.userprofile.shared_UserProfileHeaderSection_Night_0_en",20511,], +["features.userprofile.shared_UserProfileView_Day_0_en","features.userprofile.shared_UserProfileView_Night_0_en",20511,], +["features.userprofile.shared_UserProfileView_Day_1_en","features.userprofile.shared_UserProfileView_Night_1_en",20511,], +["features.userprofile.shared_UserProfileView_Day_2_en","features.userprofile.shared_UserProfileView_Night_2_en",20511,], +["features.userprofile.shared_UserProfileView_Day_3_en","features.userprofile.shared_UserProfileView_Night_3_en",20511,], +["features.userprofile.shared_UserProfileView_Day_4_en","features.userprofile.shared_UserProfileView_Night_4_en",20511,], +["features.userprofile.shared_UserProfileView_Day_5_en","features.userprofile.shared_UserProfileView_Night_5_en",20511,], +["features.userprofile.shared_UserProfileView_Day_6_en","features.userprofile.shared_UserProfileView_Night_6_en",20511,], +["features.userprofile.shared_UserProfileView_Day_7_en","features.userprofile.shared_UserProfileView_Night_7_en",20511,], +["features.userprofile.shared_UserProfileView_Day_8_en","features.userprofile.shared_UserProfileView_Night_8_en",20511,], +["features.userprofile.shared_UserProfileView_Day_9_en","features.userprofile.shared_UserProfileView_Night_9_en",20511,], ["features.verifysession.impl.ui_VerificationUserProfileContent_Day_0_en","features.verifysession.impl.ui_VerificationUserProfileContent_Night_0_en",0,], ["libraries.designsystem.ruler_VerticalRuler_Day_0_en","libraries.designsystem.ruler_VerticalRuler_Night_0_en",0,], ["libraries.mediaviewer.impl.gallery.ui_VideoItemView_Day_0_en","libraries.mediaviewer.impl.gallery.ui_VideoItemView_Night_0_en",0,], ["libraries.mediaviewer.impl.gallery.ui_VideoItemView_Day_1_en","libraries.mediaviewer.impl.gallery.ui_VideoItemView_Night_1_en",0,], -["features.preferences.impl.advanced_VideoQualitySelectorDialog_Day_0_en","features.preferences.impl.advanced_VideoQualitySelectorDialog_Night_0_en",20504,], -["features.messages.impl.attachments.preview_VideoQualitySelectorDialog_Day_0_en","features.messages.impl.attachments.preview_VideoQualitySelectorDialog_Night_0_en",20504,], +["features.messages.impl.attachments.preview_VideoQualitySelectorDialog_Day_0_en","features.messages.impl.attachments.preview_VideoQualitySelectorDialog_Night_0_en",20511,], +["features.preferences.impl.advanced_VideoQualitySelectorDialog_Day_0_en","features.preferences.impl.advanced_VideoQualitySelectorDialog_Night_0_en",20511,], ["features.viewfolder.impl.file_ViewFileView_Day_0_en","features.viewfolder.impl.file_ViewFileView_Night_0_en",0,], ["features.viewfolder.impl.file_ViewFileView_Day_1_en","features.viewfolder.impl.file_ViewFileView_Night_1_en",0,], ["features.viewfolder.impl.file_ViewFileView_Day_2_en","features.viewfolder.impl.file_ViewFileView_Night_2_en",0,], -["features.viewfolder.impl.file_ViewFileView_Day_3_en","features.viewfolder.impl.file_ViewFileView_Night_3_en",20504,], +["features.viewfolder.impl.file_ViewFileView_Day_3_en","features.viewfolder.impl.file_ViewFileView_Night_3_en",20511,], ["features.viewfolder.impl.file_ViewFileView_Day_4_en","features.viewfolder.impl.file_ViewFileView_Night_4_en",0,], ["features.viewfolder.impl.file_ViewFileView_Day_5_en","features.viewfolder.impl.file_ViewFileView_Night_5_en",0,], ["features.viewfolder.impl.folder_ViewFolderView_Day_0_en","features.viewfolder.impl.folder_ViewFolderView_Night_0_en",0,], From 3eae82890c9443a441e41cc74119d0c8942b1a53 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 2 Mar 2026 14:56:10 +0100 Subject: [PATCH 43/60] Update dependency com.posthog:posthog-android to v3.34.3 (#6272) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index ce3e4966d4..80977f3483 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -219,7 +219,7 @@ haze_materials = { module = "dev.chrisbanes.haze:haze-materials", version.ref = color_picker = "io.mhssn:colorpicker:1.0.0" # Analytics -posthog = "com.posthog:posthog-android:3.34.2" +posthog = "com.posthog:posthog-android:3.34.3" sentry = "io.sentry:sentry-android:8.33.0" # main branch can be tested replacing the version with main-SNAPSHOT matrix_analytics_events = "com.github.matrix-org:matrix-analytics-events:0.29.2" From 70d5e1868a13672fb3c1a5dd18be28e79376daca Mon Sep 17 00:00:00 2001 From: Jorge Martin Espinosa Date: Tue, 3 Mar 2026 13:16:58 +0100 Subject: [PATCH 44/60] Make 'room list catch-up' analytics transaction network aware (#6233) * Make 'room list catch-up' analytics transaction network aware. * Add `RoomListService.isInitialSyncDone`. Use this to simplify `DefaultAnalyticsRoomListStateWatcher`'s logic. --- .../matrix/api/roomlist/RoomListService.kt | 5 ++ .../impl/roomlist/RustRoomListService.kt | 7 +++ .../test/roomlist/FakeRoomListService.kt | 4 ++ .../analytics/api/NoopAnalyticsTransaction.kt | 3 ++ services/analytics/impl/build.gradle.kts | 2 + .../DefaultAnalyticsRoomListStateWatcher.kt | 52 ++++++++++++------- ...efaultAnalyticsRoomListStateWatcherTest.kt | 41 ++++++++------- .../api/AnalyticsTransaction.kt | 7 +++ .../sentry/SentryAnalyticsTransaction.kt | 8 +++ 9 files changed, 91 insertions(+), 38 deletions(-) diff --git a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/roomlist/RoomListService.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/roomlist/RoomListService.kt index 8acfcccdd8..627b5500cf 100644 --- a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/roomlist/RoomListService.kt +++ b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/roomlist/RoomListService.kt @@ -35,6 +35,11 @@ interface RoomListService { data object Hide : SyncIndicator } + /** + * Indicates whether the initial sliding sync request is done or not. + */ + val isInitialSyncDone: Boolean + /** * Creates a room list that can be used to load more rooms and filter them dynamically. * @param pageSize the number of rooms to load at once. diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/roomlist/RustRoomListService.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/roomlist/RustRoomListService.kt index 70a2ac9f93..f5e3c32371 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/roomlist/RustRoomListService.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/roomlist/RustRoomListService.kt @@ -24,6 +24,7 @@ import kotlinx.coroutines.flow.stateIn import org.matrix.rustcomponents.sdk.RoomListServiceState import org.matrix.rustcomponents.sdk.RoomListServiceSyncIndicator import timber.log.Timber +import java.util.concurrent.atomic.AtomicBoolean import org.matrix.rustcomponents.sdk.RoomListService as InnerRustRoomListService internal class RustRoomListService( @@ -33,6 +34,9 @@ internal class RustRoomListService( private val roomSyncSubscriber: RoomSyncSubscriber, private val sessionCoroutineScope: CoroutineScope, ) : RoomListService { + private val _isInitialSyncDone = AtomicBoolean(false) + override val isInitialSyncDone: Boolean get() = _isInitialSyncDone.get() + override fun createRoomList( pageSize: Int, source: RoomList.Source, @@ -75,6 +79,9 @@ internal class RustRoomListService( .map { it.toRoomListState() } .onEach { state -> Timber.d("RoomList state=$state") + if (state == RoomListService.State.Running) { + _isInitialSyncDone.set(true) + } } .distinctUntilChanged() .stateIn(sessionCoroutineScope, SharingStarted.Eagerly, RoomListService.State.Idle) diff --git a/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/roomlist/FakeRoomListService.kt b/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/roomlist/FakeRoomListService.kt index cdac4cd16a..76245250af 100644 --- a/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/roomlist/FakeRoomListService.kt +++ b/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/roomlist/FakeRoomListService.kt @@ -20,10 +20,14 @@ class FakeRoomListService( private val subscribeToVisibleRoomsLambda: (List) -> Unit = {}, private val createRoomListLambda: (pageSize: Int) -> DynamicRoomList = { pageSize -> FakeDynamicRoomList(pageSize = pageSize) }, override val allRooms: RoomList = createRoomListLambda(Int.MAX_VALUE), + private val isInitialSyncLambda: () -> Boolean = { true }, ) : RoomListService { private val roomListStateFlow = MutableStateFlow(RoomListService.State.Idle) private val syncIndicatorStateFlow = MutableStateFlow(RoomListService.SyncIndicator.Hide) + override val isInitialSyncDone: Boolean + get() = isInitialSyncLambda() + suspend fun postState(state: RoomListService.State) { roomListStateFlow.emit(state) } diff --git a/services/analytics/api/src/main/kotlin/io/element/android/services/analytics/api/NoopAnalyticsTransaction.kt b/services/analytics/api/src/main/kotlin/io/element/android/services/analytics/api/NoopAnalyticsTransaction.kt index 914fac1b12..205ce36ad0 100644 --- a/services/analytics/api/src/main/kotlin/io/element/android/services/analytics/api/NoopAnalyticsTransaction.kt +++ b/services/analytics/api/src/main/kotlin/io/element/android/services/analytics/api/NoopAnalyticsTransaction.kt @@ -8,8 +8,11 @@ package io.element.android.services.analytics.api import io.element.android.services.analyticsproviders.api.AnalyticsTransaction +import kotlin.time.Duration +import kotlin.time.Duration.Companion.seconds object NoopAnalyticsTransaction : AnalyticsTransaction { + override val duration: Duration = 0.seconds override fun startChild(operation: String, description: String?): AnalyticsTransaction = NoopAnalyticsTransaction override fun putExtraData(key: String, value: String) {} override fun putIndexableData(key: String, value: String) {} diff --git a/services/analytics/impl/build.gradle.kts b/services/analytics/impl/build.gradle.kts index 15465b1727..cbb714033c 100644 --- a/services/analytics/impl/build.gradle.kts +++ b/services/analytics/impl/build.gradle.kts @@ -26,6 +26,7 @@ dependencies { implementation(projects.libraries.architecture) implementation(projects.libraries.designsystem) implementation(projects.libraries.matrix.api) + implementation(projects.features.networkmonitor.api) implementation(projects.libraries.preferences.api) implementation(projects.libraries.sessionStorage.api) implementation(projects.services.appnavstate.api) @@ -37,6 +38,7 @@ dependencies { testCommonDependencies(libs) testImplementation(projects.libraries.matrix.test) testImplementation(projects.libraries.sessionStorage.test) + testImplementation(projects.features.networkmonitor.test) testImplementation(projects.services.analytics.test) testImplementation(projects.services.analyticsproviders.test) testImplementation(projects.services.appnavstate.test) diff --git a/services/analytics/impl/src/main/kotlin/io/element/android/services/analytics/impl/watchers/DefaultAnalyticsRoomListStateWatcher.kt b/services/analytics/impl/src/main/kotlin/io/element/android/services/analytics/impl/watchers/DefaultAnalyticsRoomListStateWatcher.kt index 75dffd0af1..bffc99911c 100644 --- a/services/analytics/impl/src/main/kotlin/io/element/android/services/analytics/impl/watchers/DefaultAnalyticsRoomListStateWatcher.kt +++ b/services/analytics/impl/src/main/kotlin/io/element/android/services/analytics/impl/watchers/DefaultAnalyticsRoomListStateWatcher.kt @@ -8,29 +8,32 @@ package io.element.android.services.analytics.impl.watchers import dev.zacsweers.metro.ContributesBinding +import io.element.android.features.networkmonitor.api.NetworkMonitor +import io.element.android.features.networkmonitor.api.NetworkStatus import io.element.android.libraries.core.coroutine.CoroutineDispatchers import io.element.android.libraries.core.coroutine.childScope -import io.element.android.libraries.core.coroutine.withPreviousValue import io.element.android.libraries.di.SessionScope import io.element.android.libraries.di.annotations.SessionCoroutineScope import io.element.android.libraries.matrix.api.roomlist.RoomListService import io.element.android.services.analytics.api.AnalyticsLongRunningTransaction import io.element.android.services.analytics.api.AnalyticsService -import io.element.android.services.analytics.api.finishLongRunningTransaction import io.element.android.services.analytics.api.watchers.AnalyticsRoomListStateWatcher -import io.element.android.services.appnavstate.api.AppNavigationStateService +import io.element.android.services.appnavstate.api.AppForegroundStateService import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.cancelChildren +import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.onEach import timber.log.Timber import java.util.concurrent.atomic.AtomicBoolean +import kotlin.time.Duration.Companion.minutes @ContributesBinding(SessionScope::class) class DefaultAnalyticsRoomListStateWatcher( - private val appNavigationStateService: AppNavigationStateService, + private val appForegroundStateService: AppForegroundStateService, + private val networkMonitor: NetworkMonitor, private val roomListService: RoomListService, private val analyticsService: AnalyticsService, @SessionCoroutineScope sessionCoroutineScope: CoroutineScope, @@ -38,7 +41,7 @@ class DefaultAnalyticsRoomListStateWatcher( ) : AnalyticsRoomListStateWatcher { private val coroutineScope: CoroutineScope = sessionCoroutineScope.childScope(dispatchers.computation, "AnalyticsRoomListStateWatcher") private val isStarted = AtomicBoolean(false) - private val isWarmState = AtomicBoolean(false) + private val isNotInitialSync get() = roomListService.isInitialSyncDone override fun start() { if (isStarted.getAndSet(true)) { @@ -48,27 +51,40 @@ class DefaultAnalyticsRoomListStateWatcher( val longRunningTransaction = AnalyticsLongRunningTransaction.CatchUp - appNavigationStateService.appNavigationState - .map { it.isInForeground } + val hasNetworkConnectivityFlow = networkMonitor.connectivity + .map { it == NetworkStatus.Connected } .distinctUntilChanged() - .withPreviousValue() - .onEach { (wasInForeground, isInForeground) -> - if (isInForeground && roomListService.state.value != RoomListService.State.Running) { - analyticsService.startLongRunningTransaction(longRunningTransaction) - } else if (!isInForeground) { - analyticsService.removeLongRunningTransaction(longRunningTransaction) - } - if (wasInForeground == false && isInForeground) { - isWarmState.set(true) + combine( + appForegroundStateService.isInForeground, + hasNetworkConnectivityFlow, + ) { isInForeground, hasNetworkConnectivity -> + val canSync = isInForeground && hasNetworkConnectivity + val isNotSyncing = roomListService.state.value != RoomListService.State.Running + if (isNotInitialSync && canSync && isNotSyncing) { + Timber.d("Catch-up transaction: starting") + analyticsService.startLongRunningTransaction(longRunningTransaction) + } else if (!isInForeground || !hasNetworkConnectivity) { + analyticsService.removeLongRunningTransaction(longRunningTransaction)?.let { + Timber.d("Catch-up transaction: stopping") + } } } .launchIn(coroutineScope) roomListService.state .onEach { state -> - if (state == RoomListService.State.Running && isWarmState.get()) { - analyticsService.finishLongRunningTransaction(longRunningTransaction) + if (state == RoomListService.State.Running && isNotInitialSync) { + val transaction = analyticsService.removeLongRunningTransaction(longRunningTransaction) + if (transaction != null && !transaction.isFinished()) { + val duration = transaction.duration + if (duration > 3.minutes) { + Timber.d("Cancelling catch-up transaction, the elapsed time is too long ($duration), something probably went wrong while measuring") + } else { + Timber.d("Catch-up transaction finished in $duration") + transaction.finish() + } + } } } .launchIn(coroutineScope) diff --git a/services/analytics/impl/src/test/kotlin/io/element/android/services/analytics/impl/watchers/DefaultAnalyticsRoomListStateWatcherTest.kt b/services/analytics/impl/src/test/kotlin/io/element/android/services/analytics/impl/watchers/DefaultAnalyticsRoomListStateWatcherTest.kt index 5e378f6a31..494fa45bde 100644 --- a/services/analytics/impl/src/test/kotlin/io/element/android/services/analytics/impl/watchers/DefaultAnalyticsRoomListStateWatcherTest.kt +++ b/services/analytics/impl/src/test/kotlin/io/element/android/services/analytics/impl/watchers/DefaultAnalyticsRoomListStateWatcherTest.kt @@ -8,13 +8,12 @@ package io.element.android.services.analytics.impl.watchers import com.google.common.truth.Truth.assertThat +import io.element.android.features.networkmonitor.test.FakeNetworkMonitor import io.element.android.libraries.matrix.api.roomlist.RoomListService import io.element.android.libraries.matrix.test.roomlist.FakeRoomListService import io.element.android.services.analytics.api.AnalyticsLongRunningTransaction.CatchUp import io.element.android.services.analytics.test.FakeAnalyticsService -import io.element.android.services.appnavstate.api.AppNavigationState -import io.element.android.services.appnavstate.api.NavigationState -import io.element.android.services.appnavstate.test.FakeAppNavigationStateService +import io.element.android.services.appnavstate.test.FakeAppForegroundStateService import io.element.android.tests.testutils.testCoroutineDispatchers import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.test.TestScope @@ -26,13 +25,13 @@ import org.junit.Test class DefaultAnalyticsRoomListStateWatcherTest { @Test fun `Opening the app in a warm state tracks the time until the room list is synced`() = runTest { - val navigationStateService = FakeAppNavigationStateService() + val appForegroundStateService = FakeAppForegroundStateService() val roomListService = FakeRoomListService().apply { postState(RoomListService.State.Idle) } val analyticsService = FakeAnalyticsService() val watcher = createAnalyticsRoomListStateWatcher( - appNavigationStateService = navigationStateService, + appForegroundStateService = appForegroundStateService, roomListService = roomListService, analyticsService = analyticsService, ) @@ -43,9 +42,9 @@ class DefaultAnalyticsRoomListStateWatcherTest { runCurrent() // Make sure it's warm by changing its internal state - navigationStateService.emitNavigationState(AppNavigationState(navigationState = NavigationState.Root, isInForeground = false)) + appForegroundStateService.givenIsInForeground(false) runCurrent() - navigationStateService.emitNavigationState(AppNavigationState(navigationState = NavigationState.Root, isInForeground = true)) + appForegroundStateService.givenIsInForeground(true) runCurrent() // The transaction should be present now @@ -63,15 +62,15 @@ class DefaultAnalyticsRoomListStateWatcherTest { @Test fun `Opening the app in a cold state does nothing`() = runTest { - val navigationStateService = FakeAppNavigationStateService( - initialAppNavigationState = AppNavigationState(NavigationState.Root, false) + val appForegroundStateService = FakeAppForegroundStateService( + initialForegroundValue = false ) val roomListService = FakeRoomListService().apply { postState(RoomListService.State.Idle) } val analyticsService = FakeAnalyticsService() val watcher = createAnalyticsRoomListStateWatcher( - appNavigationStateService = navigationStateService, + appForegroundStateService = appForegroundStateService, roomListService = roomListService, analyticsService = analyticsService, ) @@ -93,13 +92,13 @@ class DefaultAnalyticsRoomListStateWatcherTest { @Test fun `The transaction won't be finished until the room list is synchronised`() = runTest { - val navigationStateService = FakeAppNavigationStateService() + val appForegroundStateService = FakeAppForegroundStateService() val roomListService = FakeRoomListService().apply { postState(RoomListService.State.Idle) } val analyticsService = FakeAnalyticsService() val watcher = createAnalyticsRoomListStateWatcher( - appNavigationStateService = navigationStateService, + appForegroundStateService = appForegroundStateService, roomListService = roomListService, analyticsService = analyticsService, ) @@ -110,9 +109,9 @@ class DefaultAnalyticsRoomListStateWatcherTest { runCurrent() // Make sure it's warm by changing its internal state - navigationStateService.emitNavigationState(AppNavigationState(navigationState = NavigationState.Root, isInForeground = false)) + appForegroundStateService.givenIsInForeground(false) runCurrent() - navigationStateService.emitNavigationState(AppNavigationState(navigationState = NavigationState.Root, isInForeground = true)) + appForegroundStateService.givenIsInForeground(true) runCurrent() // The transaction should be present now @@ -128,13 +127,13 @@ class DefaultAnalyticsRoomListStateWatcherTest { @Test fun `Opening the app when the room list state was already Running does nothing`() = runTest { - val navigationStateService = FakeAppNavigationStateService() + val appForegroundStateService = FakeAppForegroundStateService() val roomListService = FakeRoomListService().apply { postState(RoomListService.State.Running) } val analyticsService = FakeAnalyticsService() val watcher = createAnalyticsRoomListStateWatcher( - appNavigationStateService = navigationStateService, + appForegroundStateService = appForegroundStateService, roomListService = roomListService, analyticsService = analyticsService, ) @@ -145,9 +144,9 @@ class DefaultAnalyticsRoomListStateWatcherTest { runCurrent() // Make sure it's warm by changing its internal state - navigationStateService.emitNavigationState(AppNavigationState(navigationState = NavigationState.Root, isInForeground = false)) + appForegroundStateService.givenIsInForeground(false) runCurrent() - navigationStateService.emitNavigationState(AppNavigationState(navigationState = NavigationState.Root, isInForeground = true)) + appForegroundStateService.givenIsInForeground(true) runCurrent() // The transaction was never added @@ -157,14 +156,16 @@ class DefaultAnalyticsRoomListStateWatcherTest { } private fun TestScope.createAnalyticsRoomListStateWatcher( - appNavigationStateService: FakeAppNavigationStateService = FakeAppNavigationStateService(), + appForegroundStateService: FakeAppForegroundStateService = FakeAppForegroundStateService(), roomListService: FakeRoomListService = FakeRoomListService(), analyticsService: FakeAnalyticsService = FakeAnalyticsService(), + networkMonitor: FakeNetworkMonitor = FakeNetworkMonitor(), ) = DefaultAnalyticsRoomListStateWatcher( - appNavigationStateService = appNavigationStateService, + appForegroundStateService = appForegroundStateService, roomListService = roomListService, analyticsService = analyticsService, sessionCoroutineScope = backgroundScope, dispatchers = testCoroutineDispatchers(), + networkMonitor = networkMonitor, ) } diff --git a/services/analyticsproviders/api/src/main/kotlin/io/element/android/services/analyticsproviders/api/AnalyticsTransaction.kt b/services/analyticsproviders/api/src/main/kotlin/io/element/android/services/analyticsproviders/api/AnalyticsTransaction.kt index b5f81ac67e..82d337914a 100644 --- a/services/analyticsproviders/api/src/main/kotlin/io/element/android/services/analyticsproviders/api/AnalyticsTransaction.kt +++ b/services/analyticsproviders/api/src/main/kotlin/io/element/android/services/analyticsproviders/api/AnalyticsTransaction.kt @@ -7,7 +7,14 @@ package io.element.android.services.analyticsproviders.api +import kotlin.time.Duration + interface AnalyticsTransaction { + /** + * The time elapsed since the transaction started until now if the transaction is ongoing or the time it finished. + */ + val duration: Duration + /** * Start a child span from this transaction. */ diff --git a/services/analyticsproviders/sentry/src/main/kotlin/io/element/android/services/analyticsproviders/sentry/SentryAnalyticsTransaction.kt b/services/analyticsproviders/sentry/src/main/kotlin/io/element/android/services/analyticsproviders/sentry/SentryAnalyticsTransaction.kt index 6477b2cc5c..a167176284 100644 --- a/services/analyticsproviders/sentry/src/main/kotlin/io/element/android/services/analyticsproviders/sentry/SentryAnalyticsTransaction.kt +++ b/services/analyticsproviders/sentry/src/main/kotlin/io/element/android/services/analyticsproviders/sentry/SentryAnalyticsTransaction.kt @@ -11,7 +11,10 @@ import io.element.android.services.analyticsproviders.api.AnalyticsTransaction import io.sentry.ISpan import io.sentry.ITransaction import io.sentry.Sentry +import io.sentry.SentryInstantDate import timber.log.Timber +import kotlin.time.Duration +import kotlin.time.Duration.Companion.nanoseconds class SentryAnalyticsTransaction private constructor(span: ISpan) : AnalyticsTransaction { constructor(name: String, operation: String?, description: String? = null) : this( @@ -19,6 +22,11 @@ class SentryAnalyticsTransaction private constructor(span: ISpan) : AnalyticsTra ) private val inner = span + @Suppress("UnstableApiUsage") + override val duration: Duration get() { + return (inner.finishDate ?: SentryInstantDate()).diff(inner.startDate).nanoseconds + } + override fun startChild(operation: String, description: String?): AnalyticsTransaction = SentryAnalyticsTransaction( inner.startChild(operation, description) ) From 7c97ec115525b3cc7708b2c22d3362868a55efaf Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 3 Mar 2026 13:39:43 +0100 Subject: [PATCH 45/60] Update metro to v0.11.2 (#6270) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Update metro to v0.11.2 * Bind push tests to the right scope .Add a comment so we don't forget to do it for future ones. --------- Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Co-authored-by: Jorge Martín --- gradle/libs.versions.toml | 2 +- .../NotificationTroubleshootCheckPermissionTest.kt | 4 ++-- .../libraries/push/impl/troubleshoot/PushProvidersTest.kt | 4 ++-- .../firebase/troubleshoot/FirebaseAvailabilityTest.kt | 4 ++-- .../firebase/troubleshoot/FirebaseTokenTest.kt | 4 ++-- .../unifiedpush/troubleshoot/UnifiedPushTest.kt | 4 ++-- .../troubleshoot/api/test/NotificationTroubleshootTest.kt | 8 ++++++++ 7 files changed, 19 insertions(+), 11 deletions(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 1f5f7f4bcb..bb2f62ee07 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -54,7 +54,7 @@ haze = "1.7.2" dependencyAnalysis = "3.6.0" # DI -metro = "0.11.1" +metro = "0.11.2" # Auto service autoservice = "1.1.1" diff --git a/libraries/permissions/impl/src/main/kotlin/io/element/android/libraries/permissions/impl/troubleshoot/NotificationTroubleshootCheckPermissionTest.kt b/libraries/permissions/impl/src/main/kotlin/io/element/android/libraries/permissions/impl/troubleshoot/NotificationTroubleshootCheckPermissionTest.kt index 6f29415968..162ff416c5 100644 --- a/libraries/permissions/impl/src/main/kotlin/io/element/android/libraries/permissions/impl/troubleshoot/NotificationTroubleshootCheckPermissionTest.kt +++ b/libraries/permissions/impl/src/main/kotlin/io/element/android/libraries/permissions/impl/troubleshoot/NotificationTroubleshootCheckPermissionTest.kt @@ -10,8 +10,8 @@ package io.element.android.libraries.permissions.impl.troubleshoot import android.Manifest import android.os.Build -import dev.zacsweers.metro.AppScope import dev.zacsweers.metro.ContributesIntoSet +import io.element.android.libraries.di.SessionScope import io.element.android.libraries.permissions.api.PermissionStateProvider import io.element.android.libraries.permissions.impl.R import io.element.android.libraries.permissions.impl.action.PermissionActions @@ -24,7 +24,7 @@ import io.element.android.services.toolbox.api.strings.StringProvider import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.StateFlow -@ContributesIntoSet(AppScope::class) +@ContributesIntoSet(SessionScope::class) class NotificationTroubleshootCheckPermissionTest( private val permissionStateProvider: PermissionStateProvider, private val sdkVersionProvider: BuildVersionSdkIntProvider, diff --git a/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/troubleshoot/PushProvidersTest.kt b/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/troubleshoot/PushProvidersTest.kt index dbd2c4a16b..1f69c97a95 100644 --- a/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/troubleshoot/PushProvidersTest.kt +++ b/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/troubleshoot/PushProvidersTest.kt @@ -8,8 +8,8 @@ package io.element.android.libraries.push.impl.troubleshoot -import dev.zacsweers.metro.AppScope import dev.zacsweers.metro.ContributesIntoSet +import io.element.android.libraries.di.SessionScope import io.element.android.libraries.push.impl.R import io.element.android.libraries.pushproviders.api.PushProvider import io.element.android.libraries.troubleshoot.api.test.NotificationTroubleshootTest @@ -19,7 +19,7 @@ import io.element.android.services.toolbox.api.strings.StringProvider import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.StateFlow -@ContributesIntoSet(AppScope::class) +@ContributesIntoSet(SessionScope::class) class PushProvidersTest( pushProviders: Set<@JvmSuppressWildcards PushProvider>, private val stringProvider: StringProvider, diff --git a/libraries/pushproviders/firebase/src/main/kotlin/io/element/android/libraries/pushproviders/firebase/troubleshoot/FirebaseAvailabilityTest.kt b/libraries/pushproviders/firebase/src/main/kotlin/io/element/android/libraries/pushproviders/firebase/troubleshoot/FirebaseAvailabilityTest.kt index 3f4eeca305..fde8bbf025 100644 --- a/libraries/pushproviders/firebase/src/main/kotlin/io/element/android/libraries/pushproviders/firebase/troubleshoot/FirebaseAvailabilityTest.kt +++ b/libraries/pushproviders/firebase/src/main/kotlin/io/element/android/libraries/pushproviders/firebase/troubleshoot/FirebaseAvailabilityTest.kt @@ -8,8 +8,8 @@ package io.element.android.libraries.pushproviders.firebase.troubleshoot -import dev.zacsweers.metro.AppScope import dev.zacsweers.metro.ContributesIntoSet +import io.element.android.libraries.di.SessionScope import io.element.android.libraries.pushproviders.firebase.FirebaseConfig import io.element.android.libraries.pushproviders.firebase.IsPlayServiceAvailable import io.element.android.libraries.pushproviders.firebase.R @@ -21,7 +21,7 @@ import io.element.android.services.toolbox.api.strings.StringProvider import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.StateFlow -@ContributesIntoSet(AppScope::class) +@ContributesIntoSet(SessionScope::class) class FirebaseAvailabilityTest( private val isPlayServiceAvailable: IsPlayServiceAvailable, private val stringProvider: StringProvider, diff --git a/libraries/pushproviders/firebase/src/main/kotlin/io/element/android/libraries/pushproviders/firebase/troubleshoot/FirebaseTokenTest.kt b/libraries/pushproviders/firebase/src/main/kotlin/io/element/android/libraries/pushproviders/firebase/troubleshoot/FirebaseTokenTest.kt index 22fa999d08..7ea7c6cee2 100644 --- a/libraries/pushproviders/firebase/src/main/kotlin/io/element/android/libraries/pushproviders/firebase/troubleshoot/FirebaseTokenTest.kt +++ b/libraries/pushproviders/firebase/src/main/kotlin/io/element/android/libraries/pushproviders/firebase/troubleshoot/FirebaseTokenTest.kt @@ -8,8 +8,8 @@ package io.element.android.libraries.pushproviders.firebase.troubleshoot -import dev.zacsweers.metro.AppScope import dev.zacsweers.metro.ContributesIntoSet +import io.element.android.libraries.di.SessionScope import io.element.android.libraries.pushproviders.firebase.FirebaseConfig import io.element.android.libraries.pushproviders.firebase.FirebaseStore import io.element.android.libraries.pushproviders.firebase.FirebaseTroubleshooter @@ -26,7 +26,7 @@ import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach -@ContributesIntoSet(AppScope::class) +@ContributesIntoSet(SessionScope::class) class FirebaseTokenTest( private val firebaseStore: FirebaseStore, private val firebaseTroubleshooter: FirebaseTroubleshooter, diff --git a/libraries/pushproviders/unifiedpush/src/main/kotlin/io/element/android/libraries/pushproviders/unifiedpush/troubleshoot/UnifiedPushTest.kt b/libraries/pushproviders/unifiedpush/src/main/kotlin/io/element/android/libraries/pushproviders/unifiedpush/troubleshoot/UnifiedPushTest.kt index 328b5d8ac2..5bbea6a361 100644 --- a/libraries/pushproviders/unifiedpush/src/main/kotlin/io/element/android/libraries/pushproviders/unifiedpush/troubleshoot/UnifiedPushTest.kt +++ b/libraries/pushproviders/unifiedpush/src/main/kotlin/io/element/android/libraries/pushproviders/unifiedpush/troubleshoot/UnifiedPushTest.kt @@ -8,8 +8,8 @@ package io.element.android.libraries.pushproviders.unifiedpush.troubleshoot -import dev.zacsweers.metro.AppScope import dev.zacsweers.metro.ContributesIntoSet +import io.element.android.libraries.di.SessionScope import io.element.android.libraries.pushproviders.unifiedpush.R import io.element.android.libraries.pushproviders.unifiedpush.UnifiedPushConfig import io.element.android.libraries.pushproviders.unifiedpush.UnifiedPushDistributorProvider @@ -22,7 +22,7 @@ import io.element.android.services.toolbox.api.strings.StringProvider import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.StateFlow -@ContributesIntoSet(AppScope::class) +@ContributesIntoSet(SessionScope::class) class UnifiedPushTest( private val unifiedPushDistributorProvider: UnifiedPushDistributorProvider, private val openDistributorWebPageAction: OpenDistributorWebPageAction, diff --git a/libraries/troubleshoot/api/src/main/kotlin/io/element/android/libraries/troubleshoot/api/test/NotificationTroubleshootTest.kt b/libraries/troubleshoot/api/src/main/kotlin/io/element/android/libraries/troubleshoot/api/test/NotificationTroubleshootTest.kt index 23144644d1..27f3bcf8ed 100644 --- a/libraries/troubleshoot/api/src/main/kotlin/io/element/android/libraries/troubleshoot/api/test/NotificationTroubleshootTest.kt +++ b/libraries/troubleshoot/api/src/main/kotlin/io/element/android/libraries/troubleshoot/api/test/NotificationTroubleshootTest.kt @@ -8,9 +8,17 @@ package io.element.android.libraries.troubleshoot.api.test +import io.element.android.libraries.di.SessionScope import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.StateFlow +/** + * A test to troubleshoot notifications issues. + * Each test has a state that can be observed to update the UI accordingly. + * + * **IMPORTANT**: classes implementing this should be scoped to [SessionScope], otherwise Metro complains about these not being used: + * the component they're injected into is bound to [SessionScope] and so should these (https://github.com/ZacSweers/metro/issues/1932). + */ interface NotificationTroubleshootTest { val order: Int val state: StateFlow From 9c8757e38b76b9d2ef6e4daae9096af6df929f29 Mon Sep 17 00:00:00 2001 From: Jorge Martin Espinosa Date: Tue, 3 Mar 2026 14:12:33 +0100 Subject: [PATCH 46/60] Use `ShareIntentHandler` early to avoid distributing the whole intent (#6274) * Use `ShareIntentHandler` early to avoid distributing the whole intent This would make the intent be serialized as part of `NavTarget` and could potentially lead to `TransactionTooLargeException`s. We now pass a new `ShareIntentData` class around, containing the minimum amount of data needed. We also have a new `OnSharedData` post-processor to revoke uri access after they've been shared. * Move `UriToShare` next to `ShareIntentData` and add docs --- appnav/build.gradle.kts | 1 + .../android/appnav/LoggedInFlowNode.kt | 10 +-- .../io/element/android/appnav/RootFlowNode.kt | 17 ++--- .../android/appnav/intent/IntentResolver.kt | 8 ++- .../appnav/intent/IntentResolverTest.kt | 19 +++++- .../features/share/api/OnSharedData.kt | 15 ++++ .../features/share/api/ShareEntryPoint.kt | 3 +- .../features/share/api/ShareIntentData.kt | 38 +++++++++++ .../features/share/api/ShareIntentHandler.kt | 21 ++++++ features/share/impl/build.gradle.kts | 1 + .../share/impl/DefaultOnSharedData.kt | 50 ++++++++++++++ .../share/impl/DefaultShareEntryPoint.kt | 2 +- ...andler.kt => DefaultShareIntentHandler.kt} | 68 +++++-------------- .../android/features/share/impl/ShareNode.kt | 6 +- .../features/share/impl/SharePresenter.kt | 48 +++++++------ .../share/impl/DefaultShareEntryPointTest.kt | 7 +- .../share/impl/FakeShareIntentHandler.kt | 27 -------- .../features/share/impl/SharePresenterTest.kt | 42 +++++++----- features/share/test/build.gradle.kts | 21 ++++++ .../share/test/FakeShareIntentHandler.kt | 22 ++++++ 20 files changed, 285 insertions(+), 141 deletions(-) create mode 100644 features/share/api/src/main/kotlin/io/element/android/features/share/api/OnSharedData.kt create mode 100644 features/share/api/src/main/kotlin/io/element/android/features/share/api/ShareIntentData.kt create mode 100644 features/share/api/src/main/kotlin/io/element/android/features/share/api/ShareIntentHandler.kt create mode 100644 features/share/impl/src/main/kotlin/io/element/android/features/share/impl/DefaultOnSharedData.kt rename features/share/impl/src/main/kotlin/io/element/android/features/share/impl/{ShareIntentHandler.kt => DefaultShareIntentHandler.kt} (69%) delete mode 100644 features/share/impl/src/test/kotlin/io/element/android/features/share/impl/FakeShareIntentHandler.kt create mode 100644 features/share/test/build.gradle.kts create mode 100644 features/share/test/src/main/kotlin/io/element/android/features/share/test/FakeShareIntentHandler.kt diff --git a/appnav/build.gradle.kts b/appnav/build.gradle.kts index 8bc821f933..ecac391216 100644 --- a/appnav/build.gradle.kts +++ b/appnav/build.gradle.kts @@ -57,6 +57,7 @@ dependencies { testCommonDependencies(libs) testImplementation(projects.features.login.test) + testImplementation(projects.features.share.test) testImplementation(projects.libraries.matrix.test) testImplementation(projects.libraries.oidc.test) testImplementation(projects.libraries.preferences.test) diff --git a/appnav/src/main/kotlin/io/element/android/appnav/LoggedInFlowNode.kt b/appnav/src/main/kotlin/io/element/android/appnav/LoggedInFlowNode.kt index 2fe9e970c4..a676df1d32 100644 --- a/appnav/src/main/kotlin/io/element/android/appnav/LoggedInFlowNode.kt +++ b/appnav/src/main/kotlin/io/element/android/appnav/LoggedInFlowNode.kt @@ -8,7 +8,6 @@ package io.element.android.appnav -import android.content.Intent import android.os.Parcelable import androidx.compose.foundation.layout.Box import androidx.compose.runtime.Composable @@ -63,6 +62,7 @@ import io.element.android.features.roomdirectory.api.RoomDescription import io.element.android.features.roomdirectory.api.RoomDirectoryEntryPoint import io.element.android.features.securebackup.api.SecureBackupEntryPoint import io.element.android.features.share.api.ShareEntryPoint +import io.element.android.features.share.api.ShareIntentData import io.element.android.features.startchat.api.StartChatEntryPoint import io.element.android.features.userprofile.api.UserProfileEntryPoint import io.element.android.features.verifysession.api.IncomingVerificationEntryPoint @@ -307,7 +307,7 @@ class LoggedInFlowNode( data object RoomDirectory : NavTarget @Parcelize - data class IncomingShare(val intent: Intent) : NavTarget + data class IncomingShare(val shareIntentData: ShareIntentData) : NavTarget @Parcelize data class IncomingVerificationRequest(val data: VerificationRequest.Incoming) : NavTarget @@ -570,7 +570,7 @@ class LoggedInFlowNode( shareEntryPoint.createNode( parentNode = this, buildContext = buildContext, - params = ShareEntryPoint.Params(intent = navTarget.intent), + params = ShareEntryPoint.Params(shareIntentData = navTarget.shareIntentData), callback = object : ShareEntryPoint.Callback { override fun onDone(roomIds: List) { // Remove the incoming share screen @@ -649,13 +649,13 @@ class LoggedInFlowNode( } } - internal suspend fun attachIncomingShare(intent: Intent) { + internal suspend fun attachIncomingShare(shareIntentData: ShareIntentData) { waitForNavTargetAttached { navTarget -> navTarget is NavTarget.Home } attachChild { backstack.push( - NavTarget.IncomingShare(intent) + NavTarget.IncomingShare(shareIntentData) ) } } diff --git a/appnav/src/main/kotlin/io/element/android/appnav/RootFlowNode.kt b/appnav/src/main/kotlin/io/element/android/appnav/RootFlowNode.kt index f18fc138c1..745ab390b2 100644 --- a/appnav/src/main/kotlin/io/element/android/appnav/RootFlowNode.kt +++ b/appnav/src/main/kotlin/io/element/android/appnav/RootFlowNode.kt @@ -44,6 +44,7 @@ import io.element.android.features.announcement.api.AnnouncementService import io.element.android.features.login.api.LoginParams import io.element.android.features.login.api.accesscontrol.AccountProviderAccessControl import io.element.android.features.rageshake.api.bugreport.BugReportEntryPoint +import io.element.android.features.share.api.ShareIntentData import io.element.android.features.signedout.api.SignedOutEntryPoint import io.element.android.libraries.accountselect.api.AccountSelectEntryPoint import io.element.android.libraries.architecture.BackstackView @@ -265,7 +266,7 @@ class RootFlowNode( @Parcelize data class AccountSelect( val currentSessionId: SessionId, - val intent: Intent?, + val shareIntentData: ShareIntentData?, val permalinkData: PermalinkData?, ) : NavTarget @@ -357,8 +358,8 @@ class RootFlowNode( backstack.pop() } attachSession(sessionId).apply { - if (navTarget.intent != null) { - attachIncomingShare(navTarget.intent) + if (navTarget.shareIntentData != null) { + attachIncomingShare(navTarget.shareIntentData) } else if (navTarget.permalinkData != null) { attachPermalinkData(navTarget.permalinkData) } @@ -392,7 +393,7 @@ class RootFlowNode( is ResolvedIntent.Login -> onLoginLink(resolvedIntent.params) is ResolvedIntent.Oidc -> onOidcAction(resolvedIntent.oidcAction) is ResolvedIntent.Permalink -> navigateTo(resolvedIntent.permalinkData) - is ResolvedIntent.IncomingShare -> onIncomingShare(resolvedIntent.intent) + is ResolvedIntent.IncomingShare -> onIncomingShare(resolvedIntent.shareIntentData) } } @@ -423,7 +424,7 @@ class RootFlowNode( } } - private suspend fun onIncomingShare(intent: Intent) { + private suspend fun onIncomingShare(shareIntentData: ShareIntentData) { // Is there a session already? val latestSessionId = sessionStore.getLatestSessionId() if (latestSessionId == null) { @@ -437,13 +438,13 @@ class RootFlowNode( backstack.push( NavTarget.AccountSelect( currentSessionId = latestSessionId, - intent = intent, + shareIntentData = shareIntentData, permalinkData = null, ) ) } else { // Only one account, directly attach the incoming share node. - loggedInFlowNode.attachIncomingShare(intent) + loggedInFlowNode.attachIncomingShare(shareIntentData) } } } @@ -467,7 +468,7 @@ class RootFlowNode( backstack.push( NavTarget.AccountSelect( currentSessionId = latestSessionId, - intent = null, + shareIntentData = null, permalinkData = permalinkData, ) ) diff --git a/appnav/src/main/kotlin/io/element/android/appnav/intent/IntentResolver.kt b/appnav/src/main/kotlin/io/element/android/appnav/intent/IntentResolver.kt index 3e26130c78..6844db3ed6 100644 --- a/appnav/src/main/kotlin/io/element/android/appnav/intent/IntentResolver.kt +++ b/appnav/src/main/kotlin/io/element/android/appnav/intent/IntentResolver.kt @@ -12,6 +12,8 @@ import android.content.Intent import dev.zacsweers.metro.Inject import io.element.android.features.login.api.LoginIntentResolver import io.element.android.features.login.api.LoginParams +import io.element.android.features.share.api.ShareIntentData +import io.element.android.features.share.api.ShareIntentHandler import io.element.android.libraries.deeplink.api.DeeplinkData import io.element.android.libraries.deeplink.api.DeeplinkParser import io.element.android.libraries.matrix.api.permalink.PermalinkData @@ -25,7 +27,7 @@ sealed interface ResolvedIntent { data class Oidc(val oidcAction: OidcAction) : ResolvedIntent data class Permalink(val permalinkData: PermalinkData) : ResolvedIntent data class Login(val params: LoginParams) : ResolvedIntent - data class IncomingShare(val intent: Intent) : ResolvedIntent + data class IncomingShare(val shareIntentData: ShareIntentData) : ResolvedIntent } @Inject @@ -34,6 +36,7 @@ class IntentResolver( private val loginIntentResolver: LoginIntentResolver, private val oidcIntentResolver: OidcIntentResolver, private val permalinkParser: PermalinkParser, + private val shareIntentHandler: ShareIntentHandler, ) { fun resolve(intent: Intent): ResolvedIntent? { if (intent.canBeIgnored()) return null @@ -62,7 +65,8 @@ class IntentResolver( if (permalinkData != null) return ResolvedIntent.Permalink(permalinkData) if (intent.action == Intent.ACTION_SEND || intent.action == Intent.ACTION_SEND_MULTIPLE) { - return ResolvedIntent.IncomingShare(intent) + val data = shareIntentHandler.handleIncomingShareIntent(intent) ?: return null + return ResolvedIntent.IncomingShare(data) } // Unknown intent diff --git a/appnav/src/test/kotlin/io/element/android/appnav/intent/IntentResolverTest.kt b/appnav/src/test/kotlin/io/element/android/appnav/intent/IntentResolverTest.kt index bf673602c1..576e1aaea6 100644 --- a/appnav/src/test/kotlin/io/element/android/appnav/intent/IntentResolverTest.kt +++ b/appnav/src/test/kotlin/io/element/android/appnav/intent/IntentResolverTest.kt @@ -15,6 +15,9 @@ import androidx.core.net.toUri import com.google.common.truth.Truth.assertThat import io.element.android.features.login.api.LoginParams import io.element.android.features.login.test.FakeLoginIntentResolver +import io.element.android.features.share.api.ShareIntentData +import io.element.android.features.share.api.UriToShare +import io.element.android.features.share.test.FakeShareIntentHandler import io.element.android.libraries.deeplink.api.DeeplinkData import io.element.android.libraries.matrix.api.core.UserId import io.element.android.libraries.matrix.api.permalink.PermalinkData @@ -239,26 +242,34 @@ class IntentResolverTest { @Test fun `test incoming share simple`() { + val shareIntentData = ShareIntentData.PlainText("Hello") val sut = createIntentResolver( oidcIntentResolverResult = { null }, + onIncomingShareIntent = { shareIntentData }, ) val intent = Intent(RuntimeEnvironment.getApplication(), Activity::class.java).apply { action = Intent.ACTION_SEND + putExtra(Intent.EXTRA_TEXT, "Hello") } val result = sut.resolve(intent) - assertThat(result).isEqualTo(ResolvedIntent.IncomingShare(intent = intent)) + assertThat(result).isEqualTo(ResolvedIntent.IncomingShare(shareIntentData)) } @Test fun `test incoming share multiple`() { + val fileUri = "content://com.example.app/file1.jpg".toUri() + val shareIntentData = ShareIntentData.Uris(text = "Hello", uris = listOf(UriToShare(fileUri, "image/jpg"))) val sut = createIntentResolver( oidcIntentResolverResult = { null }, + onIncomingShareIntent = { shareIntentData }, ) val intent = Intent(RuntimeEnvironment.getApplication(), Activity::class.java).apply { action = Intent.ACTION_SEND_MULTIPLE + putExtra(Intent.EXTRA_TEXT, "Hello") + data = fileUri } val result = sut.resolve(intent) - assertThat(result).isEqualTo(ResolvedIntent.IncomingShare(intent = intent)) + assertThat(result).isEqualTo(ResolvedIntent.IncomingShare(shareIntentData)) } @Test @@ -296,6 +307,7 @@ class IntentResolverTest { permalinkParserResult: (String) -> PermalinkData = { lambdaError() }, loginIntentResolverResult: (String) -> LoginParams? = { lambdaError() }, oidcIntentResolverResult: (Intent) -> OidcAction? = { lambdaError() }, + onIncomingShareIntent: (Intent) -> ShareIntentData? = { null }, ): IntentResolver { return IntentResolver( deeplinkParser = { deeplinkParserResult }, @@ -308,6 +320,9 @@ class IntentResolverTest { permalinkParser = FakePermalinkParser( result = permalinkParserResult ), + shareIntentHandler = FakeShareIntentHandler( + onIncomingShareIntent = onIncomingShareIntent, + ), ) } } diff --git a/features/share/api/src/main/kotlin/io/element/android/features/share/api/OnSharedData.kt b/features/share/api/src/main/kotlin/io/element/android/features/share/api/OnSharedData.kt new file mode 100644 index 0000000000..d7985e8b06 --- /dev/null +++ b/features/share/api/src/main/kotlin/io/element/android/features/share/api/OnSharedData.kt @@ -0,0 +1,15 @@ +/* + * Copyright (c) 2026 Element Creations Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial. + * Please see LICENSE files in the repository root for full details. + */ + +package io.element.android.features.share.api + +/** + * Post-processing to be done once a [ShareIntentData] has been consumed. + */ +fun interface OnSharedData { + operator fun invoke(data: ShareIntentData) +} diff --git a/features/share/api/src/main/kotlin/io/element/android/features/share/api/ShareEntryPoint.kt b/features/share/api/src/main/kotlin/io/element/android/features/share/api/ShareEntryPoint.kt index 4d8eef9116..c83d4fbdc6 100644 --- a/features/share/api/src/main/kotlin/io/element/android/features/share/api/ShareEntryPoint.kt +++ b/features/share/api/src/main/kotlin/io/element/android/features/share/api/ShareEntryPoint.kt @@ -8,7 +8,6 @@ package io.element.android.features.share.api -import android.content.Intent import com.bumble.appyx.core.modality.BuildContext import com.bumble.appyx.core.node.Node import com.bumble.appyx.core.plugin.Plugin @@ -16,7 +15,7 @@ import io.element.android.libraries.architecture.FeatureEntryPoint import io.element.android.libraries.matrix.api.core.RoomId interface ShareEntryPoint : FeatureEntryPoint { - data class Params(val intent: Intent) + data class Params(val shareIntentData: ShareIntentData) fun createNode( parentNode: Node, diff --git a/features/share/api/src/main/kotlin/io/element/android/features/share/api/ShareIntentData.kt b/features/share/api/src/main/kotlin/io/element/android/features/share/api/ShareIntentData.kt new file mode 100644 index 0000000000..e5407c57d9 --- /dev/null +++ b/features/share/api/src/main/kotlin/io/element/android/features/share/api/ShareIntentData.kt @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2026 Element Creations Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial. + * Please see LICENSE files in the repository root for full details. + */ + +package io.element.android.features.share.api + +import android.net.Uri +import android.os.Parcelable +import kotlinx.parcelize.Parcelize + +/** + * Share intent data, mapped from the original [android.content.Intent]. + */ +sealed interface ShareIntentData : Parcelable { + /** + * A list of [Uri]s to share and their mime types, with an optional [text] to be used as caption. + */ + @Parcelize + data class Uris(val text: String?, val uris: List) : ShareIntentData + + /** + * A plain text to share. + */ + @Parcelize + data class PlainText(val content: String) : ShareIntentData +} + +/** + * A [Uri] coming from an external share intent, with its associated [mimeType]. + */ +@Parcelize +data class UriToShare( + val uri: Uri, + val mimeType: String, +) : Parcelable diff --git a/features/share/api/src/main/kotlin/io/element/android/features/share/api/ShareIntentHandler.kt b/features/share/api/src/main/kotlin/io/element/android/features/share/api/ShareIntentHandler.kt new file mode 100644 index 0000000000..d689c57398 --- /dev/null +++ b/features/share/api/src/main/kotlin/io/element/android/features/share/api/ShareIntentHandler.kt @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2026 Element Creations Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial. + * Please see LICENSE files in the repository root for full details. + */ + +package io.element.android.features.share.api + +import android.content.Intent + +interface ShareIntentHandler { + /** + * This methods aims to handle incoming share intents and parse its data. + * + * @return the [ShareIntentData] if it could be resolved, or null. + */ + fun handleIncomingShareIntent( + intent: Intent + ): ShareIntentData? +} diff --git a/features/share/impl/build.gradle.kts b/features/share/impl/build.gradle.kts index 73748095a9..255263cf02 100644 --- a/features/share/impl/build.gradle.kts +++ b/features/share/impl/build.gradle.kts @@ -44,6 +44,7 @@ dependencies { api(projects.features.share.api) testCommonDependencies(libs, true) + testImplementation(projects.features.share.test) testImplementation(projects.libraries.matrix.test) testImplementation(projects.libraries.mediaupload.test) testImplementation(projects.libraries.preferences.test) diff --git a/features/share/impl/src/main/kotlin/io/element/android/features/share/impl/DefaultOnSharedData.kt b/features/share/impl/src/main/kotlin/io/element/android/features/share/impl/DefaultOnSharedData.kt new file mode 100644 index 0000000000..3a71f02dc3 --- /dev/null +++ b/features/share/impl/src/main/kotlin/io/element/android/features/share/impl/DefaultOnSharedData.kt @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2026 Element Creations Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial. + * Please see LICENSE files in the repository root for full details. + */ + +package io.element.android.features.share.impl + +import android.content.Context +import android.content.Intent +import android.net.Uri +import android.os.Build +import dev.zacsweers.metro.AppScope +import dev.zacsweers.metro.ContributesBinding +import io.element.android.features.share.api.OnSharedData +import io.element.android.features.share.api.ShareIntentData +import io.element.android.libraries.di.annotations.ApplicationContext +import timber.log.Timber +import kotlin.collections.forEach + +@ContributesBinding(AppScope::class) +class DefaultOnSharedData( + @ApplicationContext private val context: Context, +) : OnSharedData { + override fun invoke(data: ShareIntentData) { + when (data) { + is ShareIntentData.PlainText -> { + // No-op, there is nothing to do for plain text intents. + } + is ShareIntentData.Uris -> { + revokeUriPermissions(data.uris.map { it.uri }) + } + } + } + + private fun revokeUriPermissions(uris: List) { + uris.forEach { uri -> + try { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + context.revokeUriPermission(context.packageName, uri, Intent.FLAG_GRANT_READ_URI_PERMISSION) + } else { + context.revokeUriPermission(uri, Intent.FLAG_GRANT_READ_URI_PERMISSION) + } + } catch (e: Exception) { + Timber.w(e, "Unable to revoke Uri permission") + } + } + } +} diff --git a/features/share/impl/src/main/kotlin/io/element/android/features/share/impl/DefaultShareEntryPoint.kt b/features/share/impl/src/main/kotlin/io/element/android/features/share/impl/DefaultShareEntryPoint.kt index a8ae4d71c6..98d4acc472 100644 --- a/features/share/impl/src/main/kotlin/io/element/android/features/share/impl/DefaultShareEntryPoint.kt +++ b/features/share/impl/src/main/kotlin/io/element/android/features/share/impl/DefaultShareEntryPoint.kt @@ -26,7 +26,7 @@ class DefaultShareEntryPoint : ShareEntryPoint { return parentNode.createNode( buildContext = buildContext, plugins = listOf( - ShareNode.Inputs(intent = params.intent), + ShareNode.Inputs(shareIntentData = params.shareIntentData), callback, ) ) diff --git a/features/share/impl/src/main/kotlin/io/element/android/features/share/impl/ShareIntentHandler.kt b/features/share/impl/src/main/kotlin/io/element/android/features/share/impl/DefaultShareIntentHandler.kt similarity index 69% rename from features/share/impl/src/main/kotlin/io/element/android/features/share/impl/ShareIntentHandler.kt rename to features/share/impl/src/main/kotlin/io/element/android/features/share/impl/DefaultShareIntentHandler.kt index 9342ef60d4..cfa06c3a97 100644 --- a/features/share/impl/src/main/kotlin/io/element/android/features/share/impl/ShareIntentHandler.kt +++ b/features/share/impl/src/main/kotlin/io/element/android/features/share/impl/DefaultShareIntentHandler.kt @@ -1,6 +1,5 @@ /* - * Copyright (c) 2025 Element Creations Ltd. - * Copyright 2024, 2025 New Vector Ltd. + * Copyright (c) 2026 Element Creations Ltd. * * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial. * Please see LICENSE files in the repository root for full details. @@ -14,10 +13,12 @@ import android.content.Intent import android.content.pm.PackageManager import android.content.pm.ResolveInfo import android.net.Uri -import android.os.Build import androidx.core.content.IntentCompat import dev.zacsweers.metro.AppScope import dev.zacsweers.metro.ContributesBinding +import io.element.android.features.share.api.ShareIntentData +import io.element.android.features.share.api.ShareIntentHandler +import io.element.android.features.share.api.UriToShare import io.element.android.libraries.androidutils.compat.queryIntentActivitiesCompat import io.element.android.libraries.core.mimetype.MimeTypes import io.element.android.libraries.core.mimetype.MimeTypes.isMimeTypeAny @@ -30,37 +31,17 @@ import io.element.android.libraries.core.mimetype.MimeTypes.isMimeTypeVideo import io.element.android.libraries.di.annotations.ApplicationContext import timber.log.Timber -interface ShareIntentHandler { - data class UriToShare( - val uri: Uri, - val mimeType: String, - ) - - /** - * This methods aims to handle incoming share intents. - * - * @return true if it can handle the intent data, false otherwise - */ - suspend fun handleIncomingShareIntent( - intent: Intent, - onUris: suspend (List) -> Boolean, - onPlainText: suspend (String) -> Boolean, - ): Boolean -} - @ContributesBinding(AppScope::class) class DefaultShareIntentHandler( @ApplicationContext private val context: Context, ) : ShareIntentHandler { - override suspend fun handleIncomingShareIntent( + override fun handleIncomingShareIntent( intent: Intent, - onUris: suspend (List) -> Boolean, - onPlainText: suspend (String) -> Boolean, - ): Boolean { - val type = intent.resolveType(context) ?: return false + ): ShareIntentData? { + val type = intent.resolveType(context) ?: return null val uris = getIncomingUris(intent, type) return when { - uris.isEmpty() && type == MimeTypes.PlainText -> handlePlainText(intent, onPlainText) + uris.isEmpty() && type == MimeTypes.PlainText -> handlePlainText(intent) type.isMimeTypeImage() || type.isMimeTypeVideo() || type.isMimeTypeAudio() || @@ -68,20 +49,21 @@ class DefaultShareIntentHandler( type.isMimeTypeFile() || type.isMimeTypeText() || type.isMimeTypeAny() -> { - val result = onUris(uris) - revokeUriPermissions(uris.map { it.uri }) - result + ShareIntentData.Uris( + text = intent.getCharSequenceExtra(Intent.EXTRA_TEXT)?.toString()?.takeIf { it.isNotEmpty() }, + uris = uris, + ) } - else -> false + else -> null } } - private suspend fun handlePlainText(intent: Intent, onPlainText: suspend (String) -> Boolean): Boolean { + private fun handlePlainText(intent: Intent): ShareIntentData.PlainText? { val content = intent.getCharSequenceExtra(Intent.EXTRA_TEXT)?.toString() return if (content?.isNotEmpty() == true) { - onPlainText(content) + ShareIntentData.PlainText(content) } else { - false + null } } @@ -89,7 +71,7 @@ class DefaultShareIntentHandler( * Use this function to retrieve files which are shared from another application or internally * by using android.intent.action.SEND or android.intent.action.SEND_MULTIPLE actions. */ - private fun getIncomingUris(intent: Intent, fallbackMimeType: String): List { + private fun getIncomingUris(intent: Intent, fallbackMimeType: String): List { val uriList = mutableListOf() if (intent.action == Intent.ACTION_SEND) { IntentCompat.getParcelableExtra(intent, Intent.EXTRA_STREAM, Uri::class.java) @@ -118,24 +100,10 @@ class DefaultShareIntentHandler( // The value in fallbackMimeType can be wrong, especially if several uris were received // in the same intent (i.e. 'image/*'). We need to check the mime type of each uri. val mimeType = context.contentResolver.getType(uri) ?: fallbackMimeType - ShareIntentHandler.UriToShare( + UriToShare( uri = uri, mimeType = mimeType, ) } } - - private fun revokeUriPermissions(uris: List) { - uris.forEach { uri -> - try { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - context.revokeUriPermission(context.packageName, uri, Intent.FLAG_GRANT_READ_URI_PERMISSION) - } else { - context.revokeUriPermission(uri, Intent.FLAG_GRANT_READ_URI_PERMISSION) - } - } catch (e: Exception) { - Timber.w(e, "Unable to revoke Uri permission") - } - } - } } diff --git a/features/share/impl/src/main/kotlin/io/element/android/features/share/impl/ShareNode.kt b/features/share/impl/src/main/kotlin/io/element/android/features/share/impl/ShareNode.kt index b91c484ef3..0597b3b678 100644 --- a/features/share/impl/src/main/kotlin/io/element/android/features/share/impl/ShareNode.kt +++ b/features/share/impl/src/main/kotlin/io/element/android/features/share/impl/ShareNode.kt @@ -8,7 +8,6 @@ package io.element.android.features.share.impl -import android.content.Intent import android.os.Parcelable import androidx.compose.foundation.layout.Box import androidx.compose.runtime.Composable @@ -23,6 +22,7 @@ import dev.zacsweers.metro.Assisted import dev.zacsweers.metro.AssistedInject import io.element.android.annotations.ContributesNode import io.element.android.features.share.api.ShareEntryPoint +import io.element.android.features.share.api.ShareIntentData import io.element.android.libraries.architecture.NodeInputs import io.element.android.libraries.architecture.callback import io.element.android.libraries.architecture.inputs @@ -50,10 +50,10 @@ class ShareNode( @Parcelize object NavTarget : Parcelable - data class Inputs(val intent: Intent) : NodeInputs + data class Inputs(val shareIntentData: ShareIntentData) : NodeInputs private val inputs = inputs() - private val presenter = presenterFactory.create(inputs.intent) + private val presenter = presenterFactory.create(inputs.shareIntentData) private val callback: ShareEntryPoint.Callback = callback() override fun resolve(navTarget: NavTarget, buildContext: BuildContext): Node { diff --git a/features/share/impl/src/main/kotlin/io/element/android/features/share/impl/SharePresenter.kt b/features/share/impl/src/main/kotlin/io/element/android/features/share/impl/SharePresenter.kt index 4a4086ed87..93a9ae3bf4 100644 --- a/features/share/impl/src/main/kotlin/io/element/android/features/share/impl/SharePresenter.kt +++ b/features/share/impl/src/main/kotlin/io/element/android/features/share/impl/SharePresenter.kt @@ -8,13 +8,14 @@ package io.element.android.features.share.impl -import android.content.Intent import androidx.compose.runtime.Composable import androidx.compose.runtime.MutableState import androidx.compose.runtime.mutableStateOf import dev.zacsweers.metro.Assisted import dev.zacsweers.metro.AssistedFactory import dev.zacsweers.metro.AssistedInject +import io.element.android.features.share.api.OnSharedData +import io.element.android.features.share.api.ShareIntentData import io.element.android.libraries.architecture.AsyncAction import io.element.android.libraries.architecture.Presenter import io.element.android.libraries.architecture.runCatchingUpdatingState @@ -32,24 +33,24 @@ import kotlin.coroutines.cancellation.CancellationException @AssistedInject class SharePresenter( - @Assisted private val intent: Intent, + @Assisted private val shareIntentData: ShareIntentData, @SessionCoroutineScope private val sessionCoroutineScope: CoroutineScope, - private val shareIntentHandler: ShareIntentHandler, private val matrixClient: MatrixClient, private val mediaSenderRoomFactory: MediaSenderRoomFactory, private val activeRoomsHolder: ActiveRoomsHolder, private val mediaOptimizationConfigProvider: MediaOptimizationConfigProvider, + private val onSharedData: OnSharedData, ) : Presenter { @AssistedFactory fun interface Factory { - fun create(intent: Intent): SharePresenter + fun create(shareIntentData: ShareIntentData): SharePresenter } private val shareActionState: MutableState>> = mutableStateOf(AsyncAction.Uninitialized) fun onRoomSelected(roomIds: List) { - sessionCoroutineScope.share(intent, roomIds) + sessionCoroutineScope.share(shareIntentData, roomIds) } @Composable @@ -73,13 +74,24 @@ class SharePresenter( } private fun CoroutineScope.share( - intent: Intent, + shareIntentData: ShareIntentData, roomIds: List, ) = launch { suspend { - val result = shareIntentHandler.handleIncomingShareIntent( - intent, - onUris = { filesToShare -> + val result = when (shareIntentData) { + is ShareIntentData.PlainText -> { + roomIds + .map { roomId -> + getJoinedRoom(roomId)?.liveTimeline?.sendMessage( + body = shareIntentData.content, + htmlBody = null, + intentionalMentions = emptyList(), + )?.isSuccess.orFalse() + } + .all { it } + } + is ShareIntentData.Uris -> { + val filesToShare = shareIntentData.uris if (filesToShare.isEmpty()) { false } else { @@ -90,6 +102,7 @@ class SharePresenter( filesToShare .map { fileToShare -> val result = mediaSender.sendMedia( + caption = shareIntentData.text, uri = fileToShare.uri, mimeType = fileToShare.mimeType, mediaOptimizationConfig = mediaOptimizationConfigProvider.get(), @@ -113,19 +126,12 @@ class SharePresenter( } .all { it } } - }, - onPlainText = { text -> - roomIds - .map { roomId -> - getJoinedRoom(roomId)?.liveTimeline?.sendMessage( - body = text, - htmlBody = null, - intentionalMentions = emptyList(), - )?.isSuccess.orFalse() - } - .all { it } } - ) + } + + // Handle post-processing of shared data + onSharedData(shareIntentData) + if (!result) { error("Failed to handle incoming share intent") } diff --git a/features/share/impl/src/test/kotlin/io/element/android/features/share/impl/DefaultShareEntryPointTest.kt b/features/share/impl/src/test/kotlin/io/element/android/features/share/impl/DefaultShareEntryPointTest.kt index 83a32929ff..459fa423ec 100644 --- a/features/share/impl/src/test/kotlin/io/element/android/features/share/impl/DefaultShareEntryPointTest.kt +++ b/features/share/impl/src/test/kotlin/io/element/android/features/share/impl/DefaultShareEntryPointTest.kt @@ -8,13 +8,14 @@ package io.element.android.features.share.impl -import android.content.Intent import androidx.arch.core.executor.testing.InstantTaskExecutorRule import com.bumble.appyx.core.modality.BuildContext import com.bumble.appyx.testing.junit4.util.MainDispatcherRule import com.google.common.truth.Truth.assertThat import io.element.android.features.share.api.ShareEntryPoint +import io.element.android.features.share.api.ShareIntentData import io.element.android.libraries.matrix.api.core.RoomId +import io.element.android.libraries.matrix.test.A_MESSAGE import io.element.android.libraries.roomselect.test.FakeRoomSelectEntryPoint import io.element.android.tests.testutils.lambda.lambdaError import io.element.android.tests.testutils.node.TestParentNode @@ -44,7 +45,7 @@ class DefaultShareEntryPointTest { override fun onDone(roomIds: List) = lambdaError() } val params = ShareEntryPoint.Params( - intent = Intent(), + shareIntentData = ShareIntentData.PlainText(A_MESSAGE), ) val result = entryPoint.createNode( parentNode = parentNode, @@ -53,7 +54,7 @@ class DefaultShareEntryPointTest { callback = callback, ) assertThat(result).isInstanceOf(ShareNode::class.java) - assertThat(result.plugins).contains(ShareNode.Inputs(params.intent)) + assertThat(result.plugins).contains(ShareNode.Inputs(params.shareIntentData)) assertThat(result.plugins).contains(callback) } } diff --git a/features/share/impl/src/test/kotlin/io/element/android/features/share/impl/FakeShareIntentHandler.kt b/features/share/impl/src/test/kotlin/io/element/android/features/share/impl/FakeShareIntentHandler.kt deleted file mode 100644 index dbb9d1c704..0000000000 --- a/features/share/impl/src/test/kotlin/io/element/android/features/share/impl/FakeShareIntentHandler.kt +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright (c) 2025 Element Creations Ltd. - * Copyright 2024, 2025 New Vector Ltd. - * - * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial. - * Please see LICENSE files in the repository root for full details. - */ - -package io.element.android.features.share.impl - -import android.content.Intent - -class FakeShareIntentHandler( - private val onIncomingShareIntent: suspend ( - Intent, - suspend (List) -> Boolean, - suspend (String) -> Boolean, - ) -> Boolean = { _, _, _ -> false }, -) : ShareIntentHandler { - override suspend fun handleIncomingShareIntent( - intent: Intent, - onUris: suspend (List) -> Boolean, - onPlainText: suspend (String) -> Boolean, - ): Boolean { - return onIncomingShareIntent(intent, onUris, onPlainText) - } -} diff --git a/features/share/impl/src/test/kotlin/io/element/android/features/share/impl/SharePresenterTest.kt b/features/share/impl/src/test/kotlin/io/element/android/features/share/impl/SharePresenterTest.kt index 0df1ed7bab..fee1278fce 100644 --- a/features/share/impl/src/test/kotlin/io/element/android/features/share/impl/SharePresenterTest.kt +++ b/features/share/impl/src/test/kotlin/io/element/android/features/share/impl/SharePresenterTest.kt @@ -8,12 +8,14 @@ package io.element.android.features.share.impl -import android.content.Intent import android.net.Uri 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.share.api.OnSharedData +import io.element.android.features.share.api.ShareIntentData +import io.element.android.features.share.api.UriToShare import io.element.android.libraries.architecture.AsyncAction import io.element.android.libraries.core.mimetype.MimeTypes import io.element.android.libraries.matrix.api.MatrixClient @@ -72,8 +74,17 @@ class SharePresenterTest { @Test fun `present - on room selected ok`() = runTest { + val joinedRoom = FakeJoinedRoom( + liveTimeline = FakeTimeline().apply { + sendMessageLambda = { _, _, _ -> Result.success(Unit) } + }, + ) + val matrixClient = FakeMatrixClient().apply { + givenGetRoomResult(A_ROOM_ID, joinedRoom) + } val presenter = createSharePresenter( - shareIntentHandler = FakeShareIntentHandler { _, _, _ -> true } + matrixClient = matrixClient, + shareIntentData = ShareIntentData.PlainText(A_MESSAGE), ) moleculeFlow(RecompositionMode.Immediate) { presenter.present() @@ -100,9 +111,7 @@ class SharePresenterTest { } val presenter = createSharePresenter( matrixClient = matrixClient, - shareIntentHandler = FakeShareIntentHandler { _, _, onText -> - onText(A_MESSAGE) - } + shareIntentData = ShareIntentData.PlainText(A_MESSAGE), ) moleculeFlow(RecompositionMode.Immediate) { presenter.present() @@ -131,16 +140,15 @@ class SharePresenterTest { ) val presenter = createSharePresenter( matrixClient = matrixClient, - shareIntentHandler = FakeShareIntentHandler { _, onFile, _ -> - onFile( - listOf( - ShareIntentHandler.UriToShare( - uri = Uri.parse("content://image.jpg"), - mimeType = MimeTypes.Jpeg, - ) + shareIntentData = ShareIntentData.Uris( + text = A_MESSAGE, + listOf( + UriToShare( + uri = Uri.parse("content://image.jpg"), + mimeType = MimeTypes.Jpeg, ) ) - }, + ), mediaSenderRoomFactory = MediaSenderRoomFactory { mediaSender }, ) moleculeFlow(RecompositionMode.Immediate) { @@ -159,20 +167,20 @@ class SharePresenterTest { } internal fun TestScope.createSharePresenter( - intent: Intent = Intent(), - shareIntentHandler: ShareIntentHandler = FakeShareIntentHandler(), + shareIntentData: ShareIntentData = ShareIntentData.PlainText(A_MESSAGE), matrixClient: MatrixClient = FakeMatrixClient(), activeRoomsHolder: ActiveRoomsHolder = DefaultActiveRoomsHolder(), mediaSenderRoomFactory: MediaSenderRoomFactory = MediaSenderRoomFactory { FakeMediaSender() }, mediaOptimizationConfigProvider: MediaOptimizationConfigProvider = FakeMediaOptimizationConfigProvider(), + onSharedData: OnSharedData = OnSharedData {}, ): SharePresenter { return SharePresenter( - intent = intent, + shareIntentData = shareIntentData, sessionCoroutineScope = this, - shareIntentHandler = shareIntentHandler, matrixClient = matrixClient, activeRoomsHolder = activeRoomsHolder, mediaSenderRoomFactory = mediaSenderRoomFactory, mediaOptimizationConfigProvider = mediaOptimizationConfigProvider, + onSharedData = onSharedData, ) } diff --git a/features/share/test/build.gradle.kts b/features/share/test/build.gradle.kts new file mode 100644 index 0000000000..e4a987c113 --- /dev/null +++ b/features/share/test/build.gradle.kts @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2026 Element Creations Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial. + * Please see LICENSE files in the repository root for full details. + */ + +plugins { + id("io.element.android-library") +} + +android { + namespace = "io.element.android.features.share.test" +} + +dependencies { + implementation(projects.features.share.api) + implementation(projects.libraries.architecture) + implementation(projects.libraries.matrix.api) + implementation(projects.tests.testutils) +} diff --git a/features/share/test/src/main/kotlin/io/element/android/features/share/test/FakeShareIntentHandler.kt b/features/share/test/src/main/kotlin/io/element/android/features/share/test/FakeShareIntentHandler.kt new file mode 100644 index 0000000000..9fe04735fd --- /dev/null +++ b/features/share/test/src/main/kotlin/io/element/android/features/share/test/FakeShareIntentHandler.kt @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2026 Element Creations Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial. + * Please see LICENSE files in the repository root for full details. + */ + +package io.element.android.features.share.test + +import android.content.Intent +import io.element.android.features.share.api.ShareIntentData +import io.element.android.features.share.api.ShareIntentHandler + +class FakeShareIntentHandler( + private val onIncomingShareIntent: (Intent) -> ShareIntentData? = { null }, +) : ShareIntentHandler { + override fun handleIncomingShareIntent( + intent: Intent, + ): ShareIntentData? { + return onIncomingShareIntent(intent) + } +} From 69d63f1eacb73ae8dc5a89c0c9b8473ece32900b Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 3 Mar 2026 14:41:06 +0100 Subject: [PATCH 47/60] Update dependencyAnalysis to v3.6.1 (#6259) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index bb2f62ee07..07b852ff96 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -51,7 +51,7 @@ telephoto = "0.18.0" haze = "1.7.2" # Dependency analysis -dependencyAnalysis = "3.6.0" +dependencyAnalysis = "3.6.1" # DI metro = "0.11.2" From 721add707cc65a98a8e90a6f2284f9237badbe1e Mon Sep 17 00:00:00 2001 From: Jorge Martin Espinosa Date: Tue, 3 Mar 2026 16:14:36 +0100 Subject: [PATCH 48/60] Simplify push notification flow by using locally stored values for pending pushes (#6258) * Create `PushRequest` in push history DB: this will be used to store requests for push notifications, either pending or completed ones. * Rename `WorkManagerRequest` to `WorkManagerRequestBuilder`: make its `build` method return a list of `WorkManagerRequestWrapper`, which can be used to enqueue normal or unique workers. * Rename `PerformDatabaseVacuumRequestBuilder` and adapt it to the new API. * Adjust other components using `WorkManagerRequest`. * Replace `SyncNotificationWorkManagerRequestBuilder` with `SyncPendingNotificationsRequestBuilder` and `FetchNotificationsWorker` with `FetchPendingNotificationsWorker`: this new pair of request builder and worker allow enqueuing requests for a session id and, once the worker runs, retrieve all the pending request data and use it to fetch the associated events. This simplifies quite a bit how this data had to be passed or grouped, since it's no longer necessary to do so * Add new methods to `PushHistoryService` to modify the `PushDatabase`: - insertOrUpdatePushRequest - insertOrUpdatePushRequests - getPendingPushRequests - removeOldPushRequests * Make `PushHandler` just handle incoming pushes: those will be inserted into the pending push request table in DB, then handled by the new worker. Once the process finished, a new `NotificationResultProcessor` will handle the results and what needs to be done with them (call ringing, displaying notifications, etc.) * Add `requestType` optional parameter to `WorkManagerScheduler.cancel` so we can decide to only cancel some kinds of requests. * Add migration to remove existing work manager requests for fetching notifications, since the previous worker class no longer exists. --- .../logout/impl/LogoutPresenterTest.kt | 5 +- features/migration/impl/build.gradle.kts | 1 + .../impl/migrations/AppMigration10.kt | 39 ++ .../libraries/matrix/impl/RustMatrixClient.kt | 6 +- ...=> PerformDatabaseVacuumRequestBuilder.kt} | 12 +- .../impl/RustMatrixClientFactoryTest.kt | 4 +- .../push/api/push/NotificationEventRequest.kt | 20 - .../push/api/push/SyncOnNotifiableEvent.kt | 13 - libraries/push/impl/build.gradle.kts | 1 + .../impl/history/DefaultPushHistoryService.kt | 35 +- .../push/impl/history/PushHistoryService.kt | 36 +- .../DefaultNotifiableEventResolver.kt | 16 +- .../NotificationResolverQueue.kt | 125 ---- .../NotificationResultProcessor.kt | 238 +++++++ .../push/impl/push/DefaultPushHandler.kt | 267 ++------ .../impl/push/DefaultSyncOnNotifiableEvent.kt | 11 +- .../push/impl/push/SyncOnNotifiableEvent.kt | 14 + .../workmanager/FetchNotificationsWorker.kt | 191 ------ .../FetchPendingNotificationsWorker.kt | 239 +++++++ .../SyncNotificationWorkManagerRequest.kt | 68 -- .../SyncNotificationsWorkerDataConverter.kt | 129 ---- .../SyncPendingNotificationsRequestBuilder.kt | 51 ++ .../impl/src/main/sqldelight/databases/1.db | Bin 0 -> 8192 bytes .../impl/src/main/sqldelight/databases/2.db | Bin 0 -> 20480 bytes .../libraries/push/impl/db/PushHistory.sq | 1 - .../libraries/push/impl/db/PushRequest.sq | 24 + .../impl/src/main/sqldelight/migrations/1.sqm | 14 + .../impl/history/FakePushHistoryService.kt | 26 +- .../DefaultNotifiableEventResolverTest.kt | 69 +- .../DefaultNotificationResultProcessorTest.kt | 310 +++++++++ .../FakeNotifiableEventResolver.kt | 8 +- .../FakeNotificationResultProcessor.kt | 30 + ...equestFixture.kt => PushRequestFixture.kt} | 23 +- .../push/impl/push/DefaultPushHandlerTest.kt | 600 ++---------------- .../impl/push/SyncOnNotifiableEventTest.kt | 5 +- .../FetchNotificationWorkerTest.kt | 210 ------ .../FetchPendingNotificationWorkerTest.kt | 278 ++++++++ .../SyncNotificationWorkManagerRequestTest.kt | 98 --- ...cPendingNotificationsRequestBuilderTest.kt | 74 +++ .../workmanager/WorkerDataConverterTest.kt | 141 ---- .../FakeNotificationResolverQueue.kt | 24 - .../impl/src/main/sqldelight/migrations/0.sqm | 2 +- .../workmanager/api/WorkManagerRequest.kt | 15 - .../api/WorkManagerRequestBuilder.kt | 45 ++ .../workmanager/api/WorkManagerScheduler.kt | 16 +- .../impl/DefaultWorkManagerScheduler.kt | 32 +- .../impl/DefaultWorkManagerSchedulerTest.kt | 27 +- .../test/FakeWorkManagerScheduler.kt | 14 +- 48 files changed, 1715 insertions(+), 1892 deletions(-) create mode 100644 features/migration/impl/src/main/kotlin/io/element/android/features/migration/impl/migrations/AppMigration10.kt rename libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/workmanager/{PerformDatabaseVacuumWorkManagerRequest.kt => PerformDatabaseVacuumRequestBuilder.kt} (83%) delete mode 100644 libraries/push/api/src/main/kotlin/io/element/android/libraries/push/api/push/NotificationEventRequest.kt delete mode 100644 libraries/push/api/src/main/kotlin/io/element/android/libraries/push/api/push/SyncOnNotifiableEvent.kt delete mode 100644 libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/notifications/NotificationResolverQueue.kt create mode 100644 libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/notifications/NotificationResultProcessor.kt create mode 100644 libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/push/SyncOnNotifiableEvent.kt delete mode 100644 libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/workmanager/FetchNotificationsWorker.kt create mode 100644 libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/workmanager/FetchPendingNotificationsWorker.kt delete mode 100644 libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/workmanager/SyncNotificationWorkManagerRequest.kt delete mode 100644 libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/workmanager/SyncNotificationsWorkerDataConverter.kt create mode 100644 libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/workmanager/SyncPendingNotificationsRequestBuilder.kt create mode 100644 libraries/push/impl/src/main/sqldelight/databases/1.db create mode 100644 libraries/push/impl/src/main/sqldelight/databases/2.db create mode 100644 libraries/push/impl/src/main/sqldelight/io/element/android/libraries/push/impl/db/PushRequest.sq create mode 100644 libraries/push/impl/src/main/sqldelight/migrations/1.sqm create mode 100644 libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/DefaultNotificationResultProcessorTest.kt create mode 100644 libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/FakeNotificationResultProcessor.kt rename libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/fixtures/{NotificationEventRequestFixture.kt => PushRequestFixture.kt} (58%) delete mode 100644 libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/workmanager/FetchNotificationWorkerTest.kt create mode 100644 libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/workmanager/FetchPendingNotificationWorkerTest.kt delete mode 100644 libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/workmanager/SyncNotificationWorkManagerRequestTest.kt create mode 100644 libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/workmanager/SyncPendingNotificationsRequestBuilderTest.kt delete mode 100644 libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/workmanager/WorkerDataConverterTest.kt delete mode 100644 libraries/push/test/src/main/kotlin/io/element/android/libraries/push/test/notifications/FakeNotificationResolverQueue.kt delete mode 100644 libraries/workmanager/api/src/main/kotlin/io/element/android/libraries/workmanager/api/WorkManagerRequest.kt create mode 100644 libraries/workmanager/api/src/main/kotlin/io/element/android/libraries/workmanager/api/WorkManagerRequestBuilder.kt diff --git a/features/logout/impl/src/test/kotlin/io/element/android/features/logout/impl/LogoutPresenterTest.kt b/features/logout/impl/src/test/kotlin/io/element/android/features/logout/impl/LogoutPresenterTest.kt index 236b013837..274234a338 100644 --- a/features/logout/impl/src/test/kotlin/io/element/android/features/logout/impl/LogoutPresenterTest.kt +++ b/features/logout/impl/src/test/kotlin/io/element/android/features/logout/impl/LogoutPresenterTest.kt @@ -23,6 +23,7 @@ import io.element.android.libraries.matrix.api.encryption.RecoveryState import io.element.android.libraries.matrix.test.AN_EXCEPTION import io.element.android.libraries.matrix.test.FakeMatrixClient import io.element.android.libraries.matrix.test.encryption.FakeEncryptionService +import io.element.android.libraries.workmanager.api.WorkManagerRequestType import io.element.android.libraries.workmanager.test.FakeWorkManagerScheduler import io.element.android.tests.testutils.WarmUpRule import io.element.android.tests.testutils.lambda.lambdaRecorder @@ -149,7 +150,7 @@ class LogoutPresenterTest { @Test fun `present - logout then confirm`() = runTest { - val cancelWorkManagerJobsLambda = lambdaRecorder {} + val cancelWorkManagerJobsLambda = lambdaRecorder { _, _ -> } val workManagerScheduler = FakeWorkManagerScheduler(cancelLambda = cancelWorkManagerJobsLambda) val presenter = createLogoutPresenter(workManagerScheduler = workManagerScheduler) moleculeFlow(RecompositionMode.Immediate) { @@ -238,7 +239,7 @@ class LogoutPresenterTest { internal fun createLogoutPresenter( matrixClient: MatrixClient = FakeMatrixClient(), encryptionService: EncryptionService = FakeEncryptionService(), - workManagerScheduler: FakeWorkManagerScheduler = FakeWorkManagerScheduler(cancelLambda = {}), + workManagerScheduler: FakeWorkManagerScheduler = FakeWorkManagerScheduler(cancelLambda = { _, _ -> }), ): LogoutPresenter = LogoutPresenter( matrixClient = matrixClient, encryptionService = encryptionService, diff --git a/features/migration/impl/build.gradle.kts b/features/migration/impl/build.gradle.kts index eb22d06399..a37c3be882 100644 --- a/features/migration/impl/build.gradle.kts +++ b/features/migration/impl/build.gradle.kts @@ -31,6 +31,7 @@ dependencies { implementation(projects.libraries.matrix.api) implementation(projects.libraries.sessionStorage.api) implementation(projects.libraries.uiStrings) + implementation(projects.libraries.workmanager.api) testCommonDependencies(libs) testImplementation(projects.libraries.matrix.test) diff --git a/features/migration/impl/src/main/kotlin/io/element/android/features/migration/impl/migrations/AppMigration10.kt b/features/migration/impl/src/main/kotlin/io/element/android/features/migration/impl/migrations/AppMigration10.kt new file mode 100644 index 0000000000..26f033c604 --- /dev/null +++ b/features/migration/impl/src/main/kotlin/io/element/android/features/migration/impl/migrations/AppMigration10.kt @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2026 Element Creations Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial. + * Please see LICENSE files in the repository root for full details. + */ + +package io.element.android.features.migration.impl.migrations + +import dev.zacsweers.metro.AppScope +import dev.zacsweers.metro.ContributesIntoSet +import io.element.android.libraries.matrix.api.core.SessionId +import io.element.android.libraries.sessionstorage.api.SessionStore +import io.element.android.libraries.workmanager.api.WorkManagerRequestType +import io.element.android.libraries.workmanager.api.WorkManagerScheduler + +/** + * Remove existing fetch notifications work manager requests since their format has changed. + */ +@ContributesIntoSet(AppScope::class) +class AppMigration10( + private val sessionStore: SessionStore, + private val workManagerScheduler: WorkManagerScheduler, +) : AppMigration { + override val order: Int = 10 + + override suspend fun migrate(isFreshInstall: Boolean) { + if (isFreshInstall) return + + val sessions = sessionStore.getAllSessions() + + for (session in sessions) { + workManagerScheduler.cancel( + sessionId = SessionId(session.userId), + requestType = WorkManagerRequestType.NOTIFICATION_SYNC + ) + } + } +} diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/RustMatrixClient.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/RustMatrixClient.kt index 124db3dd1f..1c87e73ba2 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/RustMatrixClient.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/RustMatrixClient.kt @@ -83,7 +83,7 @@ import io.element.android.libraries.matrix.impl.util.SessionPathsProvider import io.element.android.libraries.matrix.impl.util.cancelAndDestroy import io.element.android.libraries.matrix.impl.util.mxCallbackFlow import io.element.android.libraries.matrix.impl.verification.RustSessionVerificationService -import io.element.android.libraries.matrix.impl.workmanager.PerformDatabaseVacuumWorkManagerRequest +import io.element.android.libraries.matrix.impl.workmanager.PerformDatabaseVacuumRequestBuilder import io.element.android.libraries.sessionstorage.api.SessionStore import io.element.android.libraries.workmanager.api.WorkManagerRequestType import io.element.android.libraries.workmanager.api.WorkManagerScheduler @@ -832,8 +832,8 @@ class RustMatrixClient( if (workManagerScheduler.hasPendingWork(sessionId, WorkManagerRequestType.DB_VACUUM)) return Timber.i("Scheduling periodic database vacuuming for session $sessionId") - val request = PerformDatabaseVacuumWorkManagerRequest(sessionId) - workManagerScheduler.submit(request) + val request = PerformDatabaseVacuumRequestBuilder(sessionId) + sessionCoroutineScope.launch { workManagerScheduler.submit(request) } } } diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/workmanager/PerformDatabaseVacuumWorkManagerRequest.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/workmanager/PerformDatabaseVacuumRequestBuilder.kt similarity index 83% rename from libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/workmanager/PerformDatabaseVacuumWorkManagerRequest.kt rename to libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/workmanager/PerformDatabaseVacuumRequestBuilder.kt index a8636eb5d9..fdaae25535 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/workmanager/PerformDatabaseVacuumWorkManagerRequest.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/workmanager/PerformDatabaseVacuumRequestBuilder.kt @@ -10,18 +10,18 @@ package io.element.android.libraries.matrix.impl.workmanager import androidx.work.Constraints import androidx.work.Data import androidx.work.PeriodicWorkRequest -import androidx.work.WorkRequest import io.element.android.libraries.matrix.api.core.SessionId import io.element.android.libraries.matrix.impl.workmanager.VacuumDatabaseWorker.Companion.SESSION_ID_PARAM -import io.element.android.libraries.workmanager.api.WorkManagerRequest +import io.element.android.libraries.workmanager.api.WorkManagerRequestBuilder import io.element.android.libraries.workmanager.api.WorkManagerRequestType +import io.element.android.libraries.workmanager.api.WorkManagerRequestWrapper import io.element.android.libraries.workmanager.api.workManagerTag import java.util.concurrent.TimeUnit -class PerformDatabaseVacuumWorkManagerRequest( +class PerformDatabaseVacuumRequestBuilder( private val sessionId: SessionId, -) : WorkManagerRequest { - override fun build(): Result> { +) : WorkManagerRequestBuilder { + override suspend fun build(): Result> { val data = Data.Builder().putString(SESSION_ID_PARAM, sessionId.value).build() val workRequest = PeriodicWorkRequest.Builder( workerClass = VacuumDatabaseWorker::class, @@ -41,6 +41,6 @@ class PerformDatabaseVacuumWorkManagerRequest( ) .build() - return Result.success(listOf(workRequest)) + return Result.success(listOf(WorkManagerRequestWrapper(workRequest))) } } diff --git a/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/RustMatrixClientFactoryTest.kt b/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/RustMatrixClientFactoryTest.kt index 5e53d015e9..670430e23e 100644 --- a/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/RustMatrixClientFactoryTest.kt +++ b/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/RustMatrixClientFactoryTest.kt @@ -19,7 +19,7 @@ import io.element.android.libraries.network.useragent.SimpleUserAgentProvider import io.element.android.libraries.sessionstorage.api.SessionStore import io.element.android.libraries.sessionstorage.test.InMemorySessionStore import io.element.android.libraries.sessionstorage.test.aSessionData -import io.element.android.libraries.workmanager.api.WorkManagerRequest +import io.element.android.libraries.workmanager.api.WorkManagerRequestBuilder import io.element.android.libraries.workmanager.test.FakeWorkManagerScheduler import io.element.android.services.analytics.test.FakeAnalyticsService import io.element.android.services.toolbox.test.systemclock.FakeSystemClock @@ -33,7 +33,7 @@ import java.io.File class RustMatrixClientFactoryTest { @Test fun test() = runTest { - val scheduleVacuumLambda = lambdaRecorder {} + val scheduleVacuumLambda = lambdaRecorder {} val workManagerScheduler = FakeWorkManagerScheduler(submitLambda = scheduleVacuumLambda) val sut = createRustMatrixClientFactory(workManagerScheduler = workManagerScheduler) diff --git a/libraries/push/api/src/main/kotlin/io/element/android/libraries/push/api/push/NotificationEventRequest.kt b/libraries/push/api/src/main/kotlin/io/element/android/libraries/push/api/push/NotificationEventRequest.kt deleted file mode 100644 index ff38c7a726..0000000000 --- a/libraries/push/api/src/main/kotlin/io/element/android/libraries/push/api/push/NotificationEventRequest.kt +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) 2025 Element Creations Ltd. - * Copyright 2025 New Vector Ltd. - * - * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial. - * Please see LICENSE files in the repository root for full details. - */ - -package io.element.android.libraries.push.api.push - -import io.element.android.libraries.matrix.api.core.EventId -import io.element.android.libraries.matrix.api.core.RoomId -import io.element.android.libraries.matrix.api.core.SessionId - -data class NotificationEventRequest( - val sessionId: SessionId, - val roomId: RoomId, - val eventId: EventId, - val providerInfo: String, -) diff --git a/libraries/push/api/src/main/kotlin/io/element/android/libraries/push/api/push/SyncOnNotifiableEvent.kt b/libraries/push/api/src/main/kotlin/io/element/android/libraries/push/api/push/SyncOnNotifiableEvent.kt deleted file mode 100644 index bc7bf44ae2..0000000000 --- a/libraries/push/api/src/main/kotlin/io/element/android/libraries/push/api/push/SyncOnNotifiableEvent.kt +++ /dev/null @@ -1,13 +0,0 @@ -/* - * Copyright (c) 2025 Element Creations Ltd. - * Copyright 2025 New Vector Ltd. - * - * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial. - * Please see LICENSE files in the repository root for full details. - */ - -package io.element.android.libraries.push.api.push - -fun interface SyncOnNotifiableEvent { - suspend operator fun invoke(requests: List) -} diff --git a/libraries/push/impl/build.gradle.kts b/libraries/push/impl/build.gradle.kts index 705c1c713c..e8acda59da 100644 --- a/libraries/push/impl/build.gradle.kts +++ b/libraries/push/impl/build.gradle.kts @@ -97,6 +97,7 @@ sqldelight { databases { create("PushDatabase") { schemaOutputDirectory = File("src/main/sqldelight/databases") + verifyMigrations = true } } } diff --git a/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/history/DefaultPushHistoryService.kt b/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/history/DefaultPushHistoryService.kt index 2c8dc5480a..ab6f01e423 100644 --- a/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/history/DefaultPushHistoryService.kt +++ b/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/history/DefaultPushHistoryService.kt @@ -14,13 +14,16 @@ import android.os.PowerManager import androidx.core.content.getSystemService import dev.zacsweers.metro.AppScope import dev.zacsweers.metro.ContributesBinding +import io.element.android.libraries.core.extensions.runCatchingExceptions import io.element.android.libraries.di.annotations.ApplicationContext import io.element.android.libraries.matrix.api.core.EventId import io.element.android.libraries.matrix.api.core.RoomId import io.element.android.libraries.matrix.api.core.SessionId import io.element.android.libraries.push.impl.PushDatabase import io.element.android.libraries.push.impl.db.PushHistory +import io.element.android.libraries.push.impl.db.PushRequest import io.element.android.services.toolbox.api.systemclock.SystemClock +import kotlin.time.Instant @ContributesBinding(AppScope::class) class DefaultPushHistoryService( @@ -31,7 +34,37 @@ class DefaultPushHistoryService( private val powerManager = context.getSystemService() private val packageName = context.packageName - override fun onPushReceived( + override suspend fun insertOrUpdatePushRequest(pushRequest: PushRequest): Result { + return runCatchingExceptions { pushDatabase.pushRequestQueries.insertPushRequest(pushRequest).await() } + } + + override suspend fun insertOrUpdatePushRequests(pushRequests: List): Result { + return runCatchingExceptions { + pushDatabase.transaction { + for (request in pushRequests) { + pushDatabase.pushRequestQueries.insertPushRequest(request) + } + } + } + } + + override suspend fun getPendingPushRequests(sessionId: SessionId, since: Instant?): Result> { + return runCatchingExceptions { + pushDatabase.transactionWithResult { + val sinceTimeMillis = since?.toEpochMilliseconds() ?: 0 + pushDatabase.pushRequestQueries.selectAllPendingForSession(sessionId.value, sinceTimeMillis).executeAsList() + } + } + } + + override suspend fun removeOldPushRequests(sessionId: SessionId): Result { + return runCatchingExceptions { + val keepAmount = 100L + pushDatabase.pushRequestQueries.removeOldest(keepAmount) + } + } + + override fun onPushResult( providerInfo: String, eventId: EventId?, roomId: RoomId?, diff --git a/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/history/PushHistoryService.kt b/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/history/PushHistoryService.kt index 8096ad222e..3996924322 100644 --- a/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/history/PushHistoryService.kt +++ b/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/history/PushHistoryService.kt @@ -11,13 +11,16 @@ package io.element.android.libraries.push.impl.history import io.element.android.libraries.matrix.api.core.EventId import io.element.android.libraries.matrix.api.core.RoomId import io.element.android.libraries.matrix.api.core.SessionId +import io.element.android.libraries.push.impl.db.PushRequest +import io.element.android.libraries.push.impl.push.PushRequestStatus +import kotlin.time.Instant interface PushHistoryService { /** * Create a new push history entry. * Do not use directly, prefer using the extension functions. */ - fun onPushReceived( + fun onPushResult( providerInfo: String, eventId: EventId?, roomId: RoomId?, @@ -26,12 +29,33 @@ interface PushHistoryService { includeDeviceState: Boolean, comment: String?, ) + + /** + * Adds or replaces an existing [PushRequest] in the local database. + */ + suspend fun insertOrUpdatePushRequest(pushRequest: PushRequest): Result + + /** + * Replace a list of [PushRequest] in the database. + */ + suspend fun insertOrUpdatePushRequests(pushRequests: List): Result + + /** + * Gets [PushRequestStatus.PENDING] push requests from the local database for a [SessionId]. + * A [since] param can optionally be provided to only return those received after that date. + */ + suspend fun getPendingPushRequests(sessionId: SessionId, since: Instant?): Result> + + /** + * Removes the oldest push requests for a [SessionId]. + */ + suspend fun removeOldPushRequests(sessionId: SessionId): Result } fun PushHistoryService.onInvalidPushReceived( providerInfo: String, data: String, -) = onPushReceived( +) = onPushResult( providerInfo = providerInfo, eventId = null, roomId = null, @@ -46,7 +70,7 @@ fun PushHistoryService.onUnableToRetrieveSession( eventId: EventId, roomId: RoomId, reason: String, -) = onPushReceived( +) = onPushResult( providerInfo = providerInfo, eventId = eventId, roomId = roomId, @@ -62,7 +86,7 @@ fun PushHistoryService.onUnableToResolveEvent( roomId: RoomId, sessionId: SessionId, reason: String, -) = onPushReceived( +) = onPushResult( providerInfo = providerInfo, eventId = eventId, roomId = roomId, @@ -78,7 +102,7 @@ fun PushHistoryService.onSuccess( roomId: RoomId, sessionId: SessionId, comment: String?, -) = onPushReceived( +) = onPushResult( providerInfo = providerInfo, eventId = eventId, roomId = roomId, @@ -95,7 +119,7 @@ fun PushHistoryService.onSuccess( fun PushHistoryService.onDiagnosticPush( providerInfo: String, -) = onPushReceived( +) = onPushResult( providerInfo = providerInfo, eventId = null, roomId = null, diff --git a/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/notifications/DefaultNotifiableEventResolver.kt b/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/notifications/DefaultNotifiableEventResolver.kt index c0eb07b091..cf76b26e64 100644 --- a/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/notifications/DefaultNotifiableEventResolver.kt +++ b/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/notifications/DefaultNotifiableEventResolver.kt @@ -50,8 +50,8 @@ import io.element.android.libraries.matrix.api.timeline.item.event.TextMessageTy 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.ui.messages.toPlainText -import io.element.android.libraries.push.api.push.NotificationEventRequest import io.element.android.libraries.push.impl.R +import io.element.android.libraries.push.impl.db.PushRequest import io.element.android.libraries.push.impl.notifications.model.InviteNotifiableEvent import io.element.android.libraries.push.impl.notifications.model.NotifiableMessageEvent import io.element.android.libraries.push.impl.notifications.model.ResolvedPushEvent @@ -64,10 +64,10 @@ private val loggerTag = LoggerTag("DefaultNotifiableEventResolver", LoggerTag.No /** * Result of resolving a batch of push events. * The outermost [Result] indicates whether the setup to resolve the events was successful. - * The results for each push notification will be a map of [NotificationEventRequest] to [Result] of [ResolvedPushEvent]. + * The results for each push notification will be a map of [PushRequest] to [Result] of [ResolvedPushEvent]. * If the resolution of a specific event fails, the innermost [Result] will contain an exception. */ -typealias ResolvePushEventsResult = Result>> +typealias ResolvePushEventsResult = Result>> /** * The notifiable event resolver is able to create a NotifiableEvent (view model for notifications) from an sdk Event. @@ -78,7 +78,7 @@ typealias ResolvePushEventsResult = Result + notificationEventRequests: List ): ResolvePushEventsResult } @@ -96,15 +96,15 @@ class DefaultNotifiableEventResolver( ) : NotifiableEventResolver { override suspend fun resolveEvents( sessionId: SessionId, - notificationEventRequests: List + notificationEventRequests: List ): ResolvePushEventsResult { Timber.d("Queueing notifications: $notificationEventRequests") val client = matrixClientProvider.getOrRestore(sessionId).getOrElse { return Result.failure(it) } - val ids = notificationEventRequests.groupBy { it.roomId } + val ids = notificationEventRequests.groupBy { RoomId(it.roomId) } .mapValues { (_, requests) -> - requests.map { it.eventId } + requests.map { EventId(it.eventId) } } // TODO this notificationData is not always valid at the moment, sometimes the Rust SDK can't fetch the matching event @@ -125,7 +125,7 @@ class DefaultNotifiableEventResolver( return Result.success( notificationEventRequests.associate { request -> - val notificationDataResult = notificationDataMap[request.eventId] + val notificationDataResult = notificationDataMap[EventId(request.eventId)] if (notificationDataResult == null) { request to Result.failure(NotificationResolverException.UnknownError("No notification data for ${request.roomId} - ${request.eventId}")) } else { diff --git a/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/notifications/NotificationResolverQueue.kt b/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/notifications/NotificationResolverQueue.kt deleted file mode 100644 index b40b3fe79f..0000000000 --- a/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/notifications/NotificationResolverQueue.kt +++ /dev/null @@ -1,125 +0,0 @@ -/* - * Copyright (c) 2025 Element Creations Ltd. - * Copyright 2025 New Vector Ltd. - * - * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial. - * Please see LICENSE files in the repository root for full details. - */ - -package io.element.android.libraries.push.impl.notifications - -import dev.zacsweers.metro.AppScope -import dev.zacsweers.metro.ContributesBinding -import dev.zacsweers.metro.SingleIn -import io.element.android.libraries.di.annotations.AppCoroutineScope -import io.element.android.libraries.featureflag.api.FeatureFlagService -import io.element.android.libraries.featureflag.api.FeatureFlags -import io.element.android.libraries.push.api.push.NotificationEventRequest -import io.element.android.libraries.push.impl.notifications.model.ResolvedPushEvent -import io.element.android.libraries.push.impl.workmanager.SyncNotificationWorkManagerRequest -import io.element.android.libraries.push.impl.workmanager.SyncNotificationsWorkerDataConverter -import io.element.android.libraries.workmanager.api.WorkManagerScheduler -import io.element.android.services.toolbox.api.sdk.BuildVersionSdkIntProvider -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.ExperimentalCoroutinesApi -import kotlinx.coroutines.Job -import kotlinx.coroutines.SupervisorJob -import kotlinx.coroutines.channels.Channel -import kotlinx.coroutines.delay -import kotlinx.coroutines.flow.MutableSharedFlow -import kotlinx.coroutines.flow.SharedFlow -import kotlinx.coroutines.launch -import timber.log.Timber -import kotlin.time.Duration.Companion.milliseconds - -interface NotificationResolverQueue { - val results: SharedFlow, Map>>> - suspend fun enqueue(request: NotificationEventRequest) -} - -/** - * This class is responsible for periodically batching notification requests and resolving them in a single call, - * so that we can avoid having to resolve each notification individually in the SDK. - */ -@OptIn(ExperimentalCoroutinesApi::class) -@SingleIn(AppScope::class) -@ContributesBinding(AppScope::class) -class DefaultNotificationResolverQueue( - private val notifiableEventResolver: NotifiableEventResolver, - @AppCoroutineScope - private val appCoroutineScope: CoroutineScope, - private val workManagerScheduler: WorkManagerScheduler, - private val featureFlagService: FeatureFlagService, - private val workerDataConverter: SyncNotificationsWorkerDataConverter, - private val buildVersionSdkIntProvider: BuildVersionSdkIntProvider, -) : NotificationResolverQueue { - companion object { - private const val BATCH_WINDOW_MS = 250L - } - - private val requestQueue = Channel(capacity = 100) - - private var currentProcessingJob: Job? = null - - /** - * A flow that emits pairs of a list of notification event requests and a map of the resolved events. - * The map contains the original request as the key and the resolved event as the value. - */ - override val results = MutableSharedFlow, Map>>>() - - /** - * Enqueues a notification event request to be resolved. - * The request will be processed in batches, so it may not be resolved immediately. - * - * @param request The notification event request to enqueue. - */ - override suspend fun enqueue(request: NotificationEventRequest) { - // Cancel previous processing job if it exists, acting as a debounce operation - Timber.d("Cancelling job: $currentProcessingJob") - currentProcessingJob?.cancel() - - // Enqueue the request and start a delayed processing job - requestQueue.send(request) - currentProcessingJob = processQueue() - Timber.d("Starting processing job for request: $request") - } - - private fun processQueue() = appCoroutineScope.launch(SupervisorJob()) { - delay(BATCH_WINDOW_MS.milliseconds) - - // If this job is still active (so this is the latest job), we launch a separate one that won't be cancelled when enqueueing new items - // to process the existing queued items. - appCoroutineScope.launch { - val groupedRequestsById = buildList { - while (!requestQueue.isEmpty) { - requestQueue.receiveCatching().getOrNull()?.let(::add) - } - }.groupBy { it.sessionId } - - if (featureFlagService.isFeatureEnabled(FeatureFlags.SyncNotificationsWithWorkManager)) { - for ((sessionId, requests) in groupedRequestsById) { - workManagerScheduler.submit( - SyncNotificationWorkManagerRequest( - sessionId = sessionId, - notificationEventRequests = requests, - workerDataConverter = workerDataConverter, - buildVersionSdkIntProvider = buildVersionSdkIntProvider, - ) - ) - } - } else { - val sessionIds = groupedRequestsById.keys - for (sessionId in sessionIds) { - val requests = groupedRequestsById[sessionId].orEmpty() - Timber.d("Fetching notifications for $sessionId: $requests. Pending requests: ${!requestQueue.isEmpty}") - // Resolving the events in parallel should improve performance since each session id will query a different Client - launch { - // No need for a Mutex since the SDK already has one internally - val notifications = notifiableEventResolver.resolveEvents(sessionId, requests).getOrNull().orEmpty() - results.emit(requests to notifications) - } - } - } - } - } -} diff --git a/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/notifications/NotificationResultProcessor.kt b/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/notifications/NotificationResultProcessor.kt new file mode 100644 index 0000000000..d799cc414d --- /dev/null +++ b/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/notifications/NotificationResultProcessor.kt @@ -0,0 +1,238 @@ +/* + * Copyright (c) 2026 Element Creations Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial. + * Please see LICENSE files in the repository root for full details. + */ + +package io.element.android.libraries.push.impl.notifications + +import dev.zacsweers.metro.AppScope +import dev.zacsweers.metro.ContributesBinding +import dev.zacsweers.metro.SingleIn +import io.element.android.features.call.api.CallType +import io.element.android.features.call.api.ElementCallEntryPoint +import io.element.android.libraries.di.annotations.AppCoroutineScope +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.core.RoomId +import io.element.android.libraries.matrix.api.core.SessionId +import io.element.android.libraries.matrix.api.exception.NotificationResolverException +import io.element.android.libraries.push.impl.db.PushRequest +import io.element.android.libraries.push.impl.history.PushHistoryService +import io.element.android.libraries.push.impl.history.onSuccess +import io.element.android.libraries.push.impl.history.onUnableToResolveEvent +import io.element.android.libraries.push.impl.notifications.channels.NotificationChannels +import io.element.android.libraries.push.impl.notifications.model.FallbackNotifiableEvent +import io.element.android.libraries.push.impl.notifications.model.NotifiableEvent +import io.element.android.libraries.push.impl.notifications.model.NotifiableRingingCallEvent +import io.element.android.libraries.push.impl.notifications.model.ResolvedPushEvent +import io.element.android.libraries.push.impl.push.MutableBatteryOptimizationStore +import io.element.android.libraries.push.impl.push.OnNotifiableEventReceived +import io.element.android.libraries.push.impl.push.OnRedactedEventReceived +import io.element.android.libraries.push.impl.push.SyncOnNotifiableEvent +import io.element.android.libraries.pushstore.api.UserPushStoreFactory +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Job +import kotlinx.coroutines.flow.MutableSharedFlow +import kotlinx.coroutines.flow.first +import kotlinx.coroutines.flow.launchIn +import kotlinx.coroutines.flow.onEach +import kotlinx.coroutines.launch +import timber.log.Timber + +private const val TAG = "NotifResultProcessor" + +interface NotificationResultProcessor { + suspend fun emit(results: Map>) + fun start() + fun stop() +} + +@ContributesBinding(AppScope::class) +@SingleIn(AppScope::class) +class DefaultNotificationResultProcessor( + private val pushHistoryService: PushHistoryService, + private val batteryOptimizationStore: MutableBatteryOptimizationStore, + private val fallbackNotificationFactory: FallbackNotificationFactory, + private val userPushStoreFactory: UserPushStoreFactory, + private val onRedactedEventReceived: OnRedactedEventReceived, + private val onNotifiableEventReceived: OnNotifiableEventReceived, + private val featureFlagService: FeatureFlagService, + private val syncOnNotifiableEvent: SyncOnNotifiableEvent, + private val elementCallEntryPoint: ElementCallEntryPoint, + private val notificationChannels: NotificationChannels, + @AppCoroutineScope private val coroutineScope: CoroutineScope, +) : NotificationResultProcessor { + private val resultFlow = MutableSharedFlow>>(extraBufferCapacity = Int.MAX_VALUE) + private var processJob: Job? = null + + override suspend fun emit(results: Map>) { + resultFlow.emit(results) + } + + override fun start() { + if (processJob?.isActive == true) { + Timber.tag(TAG).w("Is already processing, not starting again") + return + } + processJob = resultFlow + .onEach(::processResults) + .launchIn(coroutineScope) + } + + override fun stop() { + if (processJob?.isActive != true) { + Timber.tag(TAG).w("Is not processing, not stopping") + return + } + + processJob?.cancel() + processJob = null + } + + private suspend fun processResults(results: Map>) { + // TODO what happens with items that weren't reported back? + for ((request, result) in results) { + result.fold( + onSuccess = { + if (it is ResolvedPushEvent.Event && it.notifiableEvent is FallbackNotifiableEvent) { + pushHistoryService.onUnableToResolveEvent( + providerInfo = request.providerInfo, + eventId = EventId(request.eventId), + roomId = RoomId(request.roomId), + sessionId = SessionId(request.sessionId), + reason = it.notifiableEvent.cause.orEmpty(), + ) + } else { + pushHistoryService.onSuccess( + providerInfo = request.providerInfo, + eventId = EventId(request.eventId), + roomId = RoomId(request.roomId), + sessionId = SessionId(request.sessionId), + comment = "Push handled successfully", + ) + } + }, + onFailure = { exception -> + if (exception is NotificationResolverException.EventFilteredOut) { + pushHistoryService.onSuccess( + providerInfo = request.providerInfo, + eventId = EventId(request.eventId), + roomId = RoomId(request.roomId), + sessionId = SessionId(request.sessionId), + comment = "Push handled successfully but notification was filtered out", + ) + } else if (exception is NotificationResolverException.EventRedacted) { + pushHistoryService.onSuccess( + providerInfo = request.providerInfo, + eventId = EventId(request.eventId), + roomId = RoomId(request.roomId), + sessionId = SessionId(request.sessionId), + comment = "Push handled successfully but event has been redacted", + ) + } else { + val reason = when (exception) { + is NotificationResolverException.EventNotFound -> "Event not found" + else -> "Unknown error: ${exception.message}" + } + pushHistoryService.onUnableToResolveEvent( + providerInfo = request.providerInfo, + eventId = EventId(request.eventId), + roomId = RoomId(request.roomId), + sessionId = SessionId(request.sessionId), + reason = "$reason - Showing fallback notification", + ) + batteryOptimizationStore.showBatteryOptimizationBanner() + } + } + ) + } + + val events = mutableListOf() + val redactions = mutableListOf() + + @Suppress("LoopWithTooManyJumpStatements") + for ((request, result) in results) { + val event = result.recover { exception -> + // If the event could not be resolved, we create a fallback notification + when (exception) { + is NotificationResolverException.EventFilteredOut -> { + // Do nothing, we don't want to show a notification for filtered out events + null + } + is NotificationResolverException.EventRedacted -> { + // Do nothing, we don't want to show a notification for redacted events + null + } + else -> { + Timber.tag(TAG).e(exception, "Failed to resolve push event") + ResolvedPushEvent.Event( + fallbackNotificationFactory.create( + sessionId = SessionId(request.sessionId), + roomId = RoomId(request.roomId), + eventId = EventId(request.eventId), + cause = exception.message, + ) + ) + } + } + }.getOrNull() ?: continue + + val userPushStore = userPushStoreFactory.getOrCreate(event.sessionId) + val areNotificationsEnabled = userPushStore.getNotificationEnabledForDevice().first() + // If notifications are disabled for this session and device, we don't want to show the notification + // But if it's a ringing call, we want to show it anyway + val isRingingCall = (event as? ResolvedPushEvent.Event)?.notifiableEvent is NotifiableRingingCallEvent + if (!areNotificationsEnabled && !isRingingCall) continue + + // We categorise each result into either a NotifiableEvent or a Redaction + when (event) { + is ResolvedPushEvent.Event -> { + events.add(event.notifiableEvent) + } + is ResolvedPushEvent.Redaction -> { + redactions.add(event) + } + } + } + + // Process redactions of messages in background to not block operations with higher priority + if (redactions.isNotEmpty()) { + coroutineScope.launch { onRedactedEventReceived.onRedactedEventsReceived(redactions) } + } + + // Find and process ringing call notifications separately + val (ringingCallEvents, nonRingingCallEvents) = events.partition { it is NotifiableRingingCallEvent } + for (ringingCallEvent in ringingCallEvents) { + Timber.tag(TAG).d("Ringing call event: $ringingCallEvent") + handleRingingCallEvent(ringingCallEvent as NotifiableRingingCallEvent) + } + + // Finally, process other notifications (messages, invites, generic notifications, etc.) + if (nonRingingCallEvents.isNotEmpty()) { + onNotifiableEventReceived.onNotifiableEventsReceived(nonRingingCallEvents) + } + + if (!featureFlagService.isFeatureEnabled(FeatureFlags.SyncNotificationsWithWorkManager)) { + syncOnNotifiableEvent(results.keys.toList()) + } + } + + private suspend fun handleRingingCallEvent(notifiableEvent: NotifiableRingingCallEvent) { + Timber.i("## handleInternal() : Incoming call.") + elementCallEntryPoint.handleIncomingCall( + callType = CallType.RoomCall(notifiableEvent.sessionId, notifiableEvent.roomId), + eventId = notifiableEvent.eventId, + senderId = notifiableEvent.senderId, + roomName = notifiableEvent.roomName, + senderName = notifiableEvent.senderDisambiguatedDisplayName, + avatarUrl = notifiableEvent.roomAvatarUrl, + timestamp = notifiableEvent.timestamp, + expirationTimestamp = notifiableEvent.expirationTimestamp, + notificationChannelId = notificationChannels.getChannelForIncomingCall(ring = true), + textContent = notifiableEvent.description, + ) + } +} diff --git a/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/push/DefaultPushHandler.kt b/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/push/DefaultPushHandler.kt index 0053a18838..5ed4223616 100644 --- a/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/push/DefaultPushHandler.kt +++ b/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/push/DefaultPushHandler.kt @@ -11,42 +11,28 @@ package io.element.android.libraries.push.impl.push import dev.zacsweers.metro.AppScope import dev.zacsweers.metro.ContributesBinding import dev.zacsweers.metro.SingleIn -import io.element.android.features.call.api.CallType -import io.element.android.features.call.api.ElementCallEntryPoint import io.element.android.libraries.core.log.logger.LoggerTag import io.element.android.libraries.core.meta.BuildMeta -import io.element.android.libraries.di.annotations.AppCoroutineScope -import io.element.android.libraries.featureflag.api.FeatureFlagService -import io.element.android.libraries.featureflag.api.FeatureFlags -import io.element.android.libraries.matrix.api.exception.NotificationResolverException -import io.element.android.libraries.push.api.push.NotificationEventRequest -import io.element.android.libraries.push.api.push.SyncOnNotifiableEvent +import io.element.android.libraries.push.impl.db.PushRequest import io.element.android.libraries.push.impl.history.PushHistoryService import io.element.android.libraries.push.impl.history.onDiagnosticPush import io.element.android.libraries.push.impl.history.onInvalidPushReceived -import io.element.android.libraries.push.impl.history.onSuccess -import io.element.android.libraries.push.impl.history.onUnableToResolveEvent import io.element.android.libraries.push.impl.history.onUnableToRetrieveSession -import io.element.android.libraries.push.impl.notifications.FallbackNotificationFactory -import io.element.android.libraries.push.impl.notifications.NotificationResolverQueue -import io.element.android.libraries.push.impl.notifications.channels.NotificationChannels -import io.element.android.libraries.push.impl.notifications.model.FallbackNotifiableEvent -import io.element.android.libraries.push.impl.notifications.model.NotifiableEvent -import io.element.android.libraries.push.impl.notifications.model.NotifiableRingingCallEvent -import io.element.android.libraries.push.impl.notifications.model.ResolvedPushEvent +import io.element.android.libraries.push.impl.notifications.NotificationResultProcessor import io.element.android.libraries.push.impl.test.DefaultTestPush import io.element.android.libraries.push.impl.troubleshoot.DiagnosticPushHandler +import io.element.android.libraries.push.impl.workmanager.SyncPendingNotificationsRequestBuilder import io.element.android.libraries.pushproviders.api.PushData import io.element.android.libraries.pushproviders.api.PushHandler import io.element.android.libraries.pushstore.api.UserPushStoreFactory import io.element.android.libraries.pushstore.api.clientsecret.PushClientSecret +import io.element.android.libraries.workmanager.api.WorkManagerRequestType +import io.element.android.libraries.workmanager.api.WorkManagerScheduler import io.element.android.services.analytics.api.AnalyticsLongRunningTransaction import io.element.android.services.analytics.api.AnalyticsService -import kotlinx.coroutines.CoroutineScope +import io.element.android.services.toolbox.api.sdk.BuildVersionSdkIntProvider +import io.element.android.services.toolbox.api.systemclock.SystemClock import kotlinx.coroutines.flow.first -import kotlinx.coroutines.flow.launchIn -import kotlinx.coroutines.flow.map -import kotlinx.coroutines.launch import timber.log.Timber private val loggerTag = LoggerTag("PushHandler", LoggerTag.PushLoggerTag) @@ -54,173 +40,20 @@ private val loggerTag = LoggerTag("PushHandler", LoggerTag.PushLoggerTag) @SingleIn(AppScope::class) @ContributesBinding(AppScope::class) class DefaultPushHandler( - private val onNotifiableEventReceived: OnNotifiableEventReceived, - private val onRedactedEventReceived: OnRedactedEventReceived, private val incrementPushDataStore: IncrementPushDataStore, - private val mutableBatteryOptimizationStore: MutableBatteryOptimizationStore, - private val userPushStoreFactory: UserPushStoreFactory, private val pushClientSecret: PushClientSecret, private val buildMeta: BuildMeta, private val diagnosticPushHandler: DiagnosticPushHandler, - private val elementCallEntryPoint: ElementCallEntryPoint, - private val notificationChannels: NotificationChannels, private val pushHistoryService: PushHistoryService, - private val resolverQueue: NotificationResolverQueue, - @AppCoroutineScope - private val appCoroutineScope: CoroutineScope, - private val fallbackNotificationFactory: FallbackNotificationFactory, - private val syncOnNotifiableEvent: SyncOnNotifiableEvent, - private val featureFlagService: FeatureFlagService, + private val userPushStoreFactory: UserPushStoreFactory, private val analyticsService: AnalyticsService, + private val systemClock: SystemClock, + private val workManagerScheduler: WorkManagerScheduler, + private val buildVersionSdkIntProvider: BuildVersionSdkIntProvider, + resultProcessor: NotificationResultProcessor, ) : PushHandler { init { - processPushEventResults() - } - - /** - * Process the push notification event results emitted by the [resolverQueue]. - */ - private fun processPushEventResults() { - resolverQueue.results - .map { (requests, resolvedEvents) -> - for (request in requests) { - // Log the result of the push notification event - val result = resolvedEvents[request] - if (result == null) { - pushHistoryService.onUnableToResolveEvent( - providerInfo = request.providerInfo, - eventId = request.eventId, - roomId = request.roomId, - sessionId = request.sessionId, - reason = "Push not handled: no result found for request", - ) - } else { - result.fold( - onSuccess = { - if (it is ResolvedPushEvent.Event && it.notifiableEvent is FallbackNotifiableEvent) { - pushHistoryService.onUnableToResolveEvent( - providerInfo = request.providerInfo, - eventId = request.eventId, - roomId = request.roomId, - sessionId = request.sessionId, - reason = it.notifiableEvent.cause.orEmpty(), - ) - } else { - pushHistoryService.onSuccess( - providerInfo = request.providerInfo, - eventId = request.eventId, - roomId = request.roomId, - sessionId = request.sessionId, - comment = "Push handled successfully", - ) - } - }, - onFailure = { exception -> - if (exception is NotificationResolverException.EventFilteredOut) { - pushHistoryService.onSuccess( - providerInfo = request.providerInfo, - eventId = request.eventId, - roomId = request.roomId, - sessionId = request.sessionId, - comment = "Push handled successfully but notification was filtered out", - ) - } else if (exception is NotificationResolverException.EventRedacted) { - pushHistoryService.onSuccess( - providerInfo = request.providerInfo, - eventId = request.eventId, - roomId = request.roomId, - sessionId = request.sessionId, - comment = "Push handled successfully but event has been redacted", - ) - } else { - val reason = when (exception) { - is NotificationResolverException.EventNotFound -> "Event not found" - else -> "Unknown error: ${exception.message}" - } - pushHistoryService.onUnableToResolveEvent( - providerInfo = request.providerInfo, - eventId = request.eventId, - roomId = request.roomId, - sessionId = request.sessionId, - reason = "$reason - Showing fallback notification", - ) - mutableBatteryOptimizationStore.showBatteryOptimizationBanner() - } - } - ) - } - } - - val events = mutableListOf() - val redactions = mutableListOf() - - @Suppress("LoopWithTooManyJumpStatements") - for ((request, result) in resolvedEvents) { - val event = result.recover { exception -> - // If the event could not be resolved, we create a fallback notification - when (exception) { - is NotificationResolverException.EventFilteredOut -> { - // Do nothing, we don't want to show a notification for filtered out events - null - } - is NotificationResolverException.EventRedacted -> { - // Do nothing, we don't want to show a notification for redacted events - null - } - else -> { - Timber.tag(loggerTag.value).e(exception, "Failed to resolve push event") - ResolvedPushEvent.Event( - fallbackNotificationFactory.create( - sessionId = request.sessionId, - roomId = request.roomId, - eventId = request.eventId, - cause = exception.message, - ) - ) - } - } - }.getOrNull() ?: continue - - val userPushStore = userPushStoreFactory.getOrCreate(event.sessionId) - val areNotificationsEnabled = userPushStore.getNotificationEnabledForDevice().first() - // If notifications are disabled for this session and device, we don't want to show the notification - // But if it's a ringing call, we want to show it anyway - val isRingingCall = (event as? ResolvedPushEvent.Event)?.notifiableEvent is NotifiableRingingCallEvent - if (!areNotificationsEnabled && !isRingingCall) continue - - // We categorise each result into either a NotifiableEvent or a Redaction - when (event) { - is ResolvedPushEvent.Event -> { - events.add(event.notifiableEvent) - } - is ResolvedPushEvent.Redaction -> { - redactions.add(event) - } - } - } - - // Process redactions of messages in background to not block operations with higher priority - if (redactions.isNotEmpty()) { - appCoroutineScope.launch { onRedactedEventReceived.onRedactedEventsReceived(redactions) } - } - - // Find and process ringing call notifications separately - val (ringingCallEvents, nonRingingCallEvents) = events.partition { it is NotifiableRingingCallEvent } - for (ringingCallEvent in ringingCallEvents) { - Timber.tag(loggerTag.value).d("Ringing call event: $ringingCallEvent") - handleRingingCallEvent(ringingCallEvent as NotifiableRingingCallEvent) - } - - // Finally, process other notifications (messages, invites, generic notifications, etc.) - if (nonRingingCallEvents.isNotEmpty()) { - onNotifiableEventReceived.onNotifiableEventsReceived(nonRingingCallEvents) - } - - if (!featureFlagService.isFeatureEnabled(FeatureFlags.SyncNotificationsWithWorkManager)) { - syncOnNotifiableEvent(requests) - } - } - .launchIn(appCoroutineScope) + resultProcessor.start() } /** @@ -233,9 +66,7 @@ class DefaultPushHandler( // Start measuring how long it takes to display a notification from when the push is received Timber.d("Calculating push-to-notification for event ${pushData.eventId}") val parent = analyticsService.startLongRunningTransaction(AnalyticsLongRunningTransaction.PushToNotification(pushData.eventId.value)) - if (featureFlagService.isFeatureEnabled(FeatureFlags.SyncNotificationsWithWorkManager)) { - analyticsService.startLongRunningTransaction(AnalyticsLongRunningTransaction.PushToWorkManager(pushData.eventId.value), parent) - } + analyticsService.startLongRunningTransaction(AnalyticsLongRunningTransaction.PushToWorkManager(pushData.eventId.value), parent) Timber.tag(loggerTag.value).d("## handling pushData: ${pushData.roomId}/${pushData.eventId}") if (buildMeta.lowPrivacyLoggingEnabled) { @@ -282,34 +113,56 @@ class DefaultPushHandler( return } - appCoroutineScope.launch { - val notificationEventRequest = NotificationEventRequest( - sessionId = userId, - roomId = pushData.roomId, - eventId = pushData.eventId, - providerInfo = providerInfo, + val areNotificationsEnabled = userPushStoreFactory.getOrCreate(userId).getNotificationEnabledForDevice().first() + if (!areNotificationsEnabled) { + Timber.w("Push notification received when push notifications are disabled.") + return + } + + val pushRequest = PushRequest( + pushDate = systemClock.epochMillis(), + providerInfo = providerInfo, + eventId = pushData.eventId.value, + roomId = pushData.roomId.value, + sessionId = userId.value, + status = PushRequestStatus.PENDING.value, + retries = 0L, + ) + + Timber.d("Queueing notification: $pushRequest") + pushHistoryService.insertOrUpdatePushRequest(pushRequest) + + if (!workManagerScheduler.hasPendingWork(userId, WorkManagerRequestType.NOTIFICATION_SYNC)) { + Timber.d("No pending worker for push notifications found") + workManagerScheduler.submit( + SyncPendingNotificationsRequestBuilder( + sessionId = userId, + buildVersionSdkIntProvider = buildVersionSdkIntProvider, + ) ) - Timber.d("Queueing notification: $notificationEventRequest") - resolverQueue.enqueue(notificationEventRequest) } } catch (e: Exception) { Timber.tag(loggerTag.value).e(e, "## handleInternal() failed") } } - - private suspend fun handleRingingCallEvent(notifiableEvent: NotifiableRingingCallEvent) { - Timber.i("## handleInternal() : Incoming call.") - elementCallEntryPoint.handleIncomingCall( - callType = CallType.RoomCall(notifiableEvent.sessionId, notifiableEvent.roomId), - eventId = notifiableEvent.eventId, - senderId = notifiableEvent.senderId, - roomName = notifiableEvent.roomName, - senderName = notifiableEvent.senderDisambiguatedDisplayName, - avatarUrl = notifiableEvent.roomAvatarUrl, - timestamp = notifiableEvent.timestamp, - expirationTimestamp = notifiableEvent.expirationTimestamp, - notificationChannelId = notificationChannels.getChannelForIncomingCall(ring = true), - textContent = notifiableEvent.description, - ) - } +} + +/** + * Represents the status of a [PushRequest]. + */ +enum class PushRequestStatus(val value: Long) { + /** + * Either it was enqueued, and we never tried to fetch it, or it failed with a recoverable error. + */ + PENDING(0), + + /** + * The event for the [PushRequest] was fetched successfully. + */ + SUCCESS(1), + + /** + * Fetching the event for the [PushRequest] failed with an unrecoverable error, and it won't be retried. + */ + FAILED(2), } diff --git a/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/push/DefaultSyncOnNotifiableEvent.kt b/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/push/DefaultSyncOnNotifiableEvent.kt index 8b8e671fcc..f3a52f9e15 100644 --- a/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/push/DefaultSyncOnNotifiableEvent.kt +++ b/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/push/DefaultSyncOnNotifiableEvent.kt @@ -14,8 +14,9 @@ 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.push.api.push.NotificationEventRequest -import io.element.android.libraries.push.api.push.SyncOnNotifiableEvent +import io.element.android.libraries.matrix.api.core.RoomId +import io.element.android.libraries.matrix.api.core.SessionId +import io.element.android.libraries.push.impl.db.PushRequest import io.element.android.services.appnavstate.api.AppForegroundStateService import kotlinx.coroutines.delay import kotlinx.coroutines.withContext @@ -29,7 +30,7 @@ class DefaultSyncOnNotifiableEvent( private val appForegroundStateService: AppForegroundStateService, private val dispatchers: CoroutineDispatchers, ) : SyncOnNotifiableEvent { - override suspend operator fun invoke(requests: List) = withContext(dispatchers.io) { + override suspend operator fun invoke(requests: List) = withContext(dispatchers.io) { if (!featureFlagService.isFeatureEnabled(FeatureFlags.SyncOnPush)) { return@withContext } @@ -41,8 +42,8 @@ class DefaultSyncOnNotifiableEvent( Timber.d("Starting opportunistic room list sync | In foreground: ${appForegroundStateService.isInForeground.value}") for ((sessionId, events) in eventsBySession) { - val client = matrixClientProvider.getOrRestore(sessionId).getOrNull() ?: continue - val roomIds = events.map { it.roomId }.distinct() + val client = matrixClientProvider.getOrRestore(SessionId(sessionId)).getOrNull() ?: continue + val roomIds = events.map { RoomId(it.roomId) }.distinct() client.roomListService.subscribeToVisibleRooms(roomIds) 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..5d584986f1 --- /dev/null +++ b/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/push/SyncOnNotifiableEvent.kt @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2026 Element Creations Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial. + * Please see LICENSE files in the repository root for full details. + */ + +package io.element.android.libraries.push.impl.push + +import io.element.android.libraries.push.impl.db.PushRequest + +fun interface SyncOnNotifiableEvent { + suspend operator fun invoke(requests: List) +} diff --git a/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/workmanager/FetchNotificationsWorker.kt b/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/workmanager/FetchNotificationsWorker.kt deleted file mode 100644 index 23220cf366..0000000000 --- a/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/workmanager/FetchNotificationsWorker.kt +++ /dev/null @@ -1,191 +0,0 @@ -/* - * Copyright (c) 2025 Element Creations Ltd. - * Copyright 2025 New Vector Ltd. - * - * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial. - * Please see LICENSE files in the repository root for full details. - */ - -package io.element.android.libraries.push.impl.workmanager - -import android.content.Context -import androidx.work.CoroutineWorker -import androidx.work.WorkerParameters -import dev.zacsweers.metro.AppScope -import dev.zacsweers.metro.Assisted -import dev.zacsweers.metro.AssistedFactory -import dev.zacsweers.metro.AssistedInject -import dev.zacsweers.metro.ContributesIntoMap -import dev.zacsweers.metro.binding -import io.element.android.features.networkmonitor.api.NetworkMonitor -import io.element.android.features.networkmonitor.api.NetworkStatus -import io.element.android.libraries.core.extensions.runCatchingExceptions -import io.element.android.libraries.di.annotations.ApplicationContext -import io.element.android.libraries.matrix.api.auth.SessionRestorationException -import io.element.android.libraries.matrix.api.core.SessionId -import io.element.android.libraries.push.api.push.NotificationEventRequest -import io.element.android.libraries.push.api.push.SyncOnNotifiableEvent -import io.element.android.libraries.push.impl.notifications.NotifiableEventResolver -import io.element.android.libraries.push.impl.notifications.NotificationResolverQueue -import io.element.android.libraries.workmanager.api.WorkManagerScheduler -import io.element.android.libraries.workmanager.api.di.MetroWorkerFactory -import io.element.android.libraries.workmanager.api.di.WorkerKey -import io.element.android.services.analytics.api.AnalyticsLongRunningTransaction -import io.element.android.services.analytics.api.AnalyticsService -import io.element.android.services.analytics.api.finishLongRunningTransaction -import io.element.android.services.analytics.api.recordTransaction -import io.element.android.services.analyticsproviders.api.AnalyticsTransaction -import io.element.android.services.toolbox.api.sdk.BuildVersionSdkIntProvider -import kotlinx.coroutines.flow.MutableSharedFlow -import kotlinx.coroutines.flow.first -import kotlinx.coroutines.withTimeoutOrNull -import timber.log.Timber -import kotlin.time.Duration.Companion.seconds - -@AssistedInject -class FetchNotificationsWorker( - @Assisted params: WorkerParameters, - @ApplicationContext private val context: Context, - private val networkMonitor: NetworkMonitor, - private val eventResolver: NotifiableEventResolver, - private val queue: NotificationResolverQueue, - private val workManagerScheduler: WorkManagerScheduler, - private val syncOnNotifiableEvent: SyncOnNotifiableEvent, - private val workerDataConverter: SyncNotificationsWorkerDataConverter, - private val buildVersionSdkIntProvider: BuildVersionSdkIntProvider, - private val analyticsService: AnalyticsService, -) : CoroutineWorker(context, params) { - override suspend fun doWork(): Result { - Timber.d("FetchNotificationsWorker started") - val requests = workerDataConverter.deserialize(inputData) ?: return Result.failure() - - val networkTimeoutSpans = requests.mapNotNull { request -> - val parent = analyticsService.getLongRunningTransaction(AnalyticsLongRunningTransaction.PushToWorkManager(request.eventId.value)) - parent?.startChild("Waiting for network connectivity", "await_network") - } - - // Wait for network to be available, but not more than 10 seconds - val hasNetwork = withTimeoutOrNull(10.seconds) { - networkMonitor.connectivity.first { it == NetworkStatus.Connected } - } != null - - networkTimeoutSpans.finish() - - // If there is a problem with the updated network values, report it and retry if needed - if (reportConnectivityError(requests = requests, hasNetwork = hasNetwork, isNetworkBlocked = networkMonitor.isNetworkBlocked())) { - return Result.retry() - } - - val pendingAnalyticTransactions = requests.mapNotNull { request -> - analyticsService.finishLongRunningTransaction(AnalyticsLongRunningTransaction.PushToWorkManager(request.eventId.value)) - val parent = analyticsService.getLongRunningTransaction(AnalyticsLongRunningTransaction.PushToNotification(request.eventId.value)) - val transactionName = "WorkManager to event fetched" - parent?.startChild(transactionName)?.let { request.eventId to it } - }.toMap() - - val failedSyncForSessions = mutableMapOf() - - val groupedRequests = requests.groupBy { it.sessionId }.toMutableMap() - for ((sessionId, notificationRequests) in groupedRequests) { - Timber.d("Processing notification requests for session $sessionId") - eventResolver.resolveEvents(sessionId, notificationRequests) - .fold( - onSuccess = { result -> - for ((_, transaction) in pendingAnalyticTransactions) { - transaction.finish() - } - // Update the resolved results in the queue - (queue.results as MutableSharedFlow).emit(requests to result) - }, - onFailure = { - for ((_, transaction) in pendingAnalyticTransactions) { - transaction.attachError(it) - transaction.finish() - } - failedSyncForSessions[sessionId] = it - Timber.e(it, "Failed to resolve notification events for session $sessionId") - } - ) - } - - // If there were failures for whole sessions, we retry all their requests - if (failedSyncForSessions.isNotEmpty()) { - @Suppress("LoopWithTooManyJumpStatements") - for ((failedSessionId, exception) in failedSyncForSessions) { - if (exception.cause is SessionRestorationException) { - Timber.e(exception, "Session $failedSessionId could not be restored, not retrying notification fetching") - groupedRequests.remove(failedSessionId) - continue - } - val requestsToRetry = groupedRequests[failedSessionId] ?: continue - - for (request in requestsToRetry) { - val failedTransaction = pendingAnalyticTransactions[request.eventId] - failedTransaction?.attachError(exception) - failedTransaction?.finish() - - val eventId = request.eventId.value - val parent = analyticsService.getLongRunningTransaction(AnalyticsLongRunningTransaction.PushToNotification(eventId)) - // Since we're retrying, start a new transaction - analyticsService.startLongRunningTransaction(AnalyticsLongRunningTransaction.PushToWorkManager(eventId), parent) - } - - Timber.d("Re-scheduling ${requestsToRetry.size} failed notification requests for session $failedSessionId") - workManagerScheduler.submit( - SyncNotificationWorkManagerRequest( - sessionId = failedSessionId, - notificationEventRequests = requestsToRetry, - workerDataConverter = workerDataConverter, - buildVersionSdkIntProvider = buildVersionSdkIntProvider, - ) - ) - } - } - - Timber.d("Notifications processed successfully") - - analyticsService.recordTransaction("Opportunistic sync", "opportunistic_sync") { - performOpportunisticSyncIfNeeded(groupedRequests) - } - - return Result.success() - } - - private fun reportConnectivityError(requests: List, hasNetwork: Boolean, isNetworkBlocked: Boolean): Boolean { - return if (!hasNetwork || isNetworkBlocked) { - for (request in requests) { - val eventId = request.eventId.value - analyticsService.finishLongRunningTransaction(AnalyticsLongRunningTransaction.PushToWorkManager(eventId)) { - it.putExtraData("has_network_connection", hasNetwork.toString()) - it.putExtraData("is_network_blocked", isNetworkBlocked.toString()) - } - val parent = analyticsService.getLongRunningTransaction(AnalyticsLongRunningTransaction.PushToNotification(eventId)) - // Since we're retrying, start a new transaction - analyticsService.startLongRunningTransaction(AnalyticsLongRunningTransaction.PushToWorkManager(eventId), parent) - } - Timber.w("FetchNotificationsWorker will retry. Has network connectivity: $hasNetwork. Is network blocked: $isNetworkBlocked") - true - } else { - false - } - } - - private suspend fun performOpportunisticSyncIfNeeded( - groupedRequests: Map>, - ) { - for ((sessionId, notificationRequests) in groupedRequests) { - runCatchingExceptions { - syncOnNotifiableEvent(notificationRequests) - }.onFailure { - Timber.e(it, "Failed to sync on notifiable events for session $sessionId") - } - } - } - - @ContributesIntoMap(AppScope::class, binding = binding>()) - @WorkerKey(FetchNotificationsWorker::class) - @AssistedFactory - interface Factory : MetroWorkerFactory.WorkerInstanceFactory -} - -private fun Collection.finish() = forEach { it.finish() } diff --git a/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/workmanager/FetchPendingNotificationsWorker.kt b/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/workmanager/FetchPendingNotificationsWorker.kt new file mode 100644 index 0000000000..fd9008839f --- /dev/null +++ b/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/workmanager/FetchPendingNotificationsWorker.kt @@ -0,0 +1,239 @@ +/* + * Copyright (c) 2025 Element Creations Ltd. + * Copyright 2025 New Vector Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial. + * Please see LICENSE files in the repository root for full details. + */ + +package io.element.android.libraries.push.impl.workmanager + +import android.content.Context +import androidx.work.CoroutineWorker +import androidx.work.WorkerParameters +import dev.zacsweers.metro.AppScope +import dev.zacsweers.metro.Assisted +import dev.zacsweers.metro.AssistedFactory +import dev.zacsweers.metro.AssistedInject +import dev.zacsweers.metro.ContributesIntoMap +import dev.zacsweers.metro.binding +import io.element.android.features.networkmonitor.api.NetworkMonitor +import io.element.android.features.networkmonitor.api.NetworkStatus +import io.element.android.libraries.core.extensions.runCatchingExceptions +import io.element.android.libraries.di.annotations.ApplicationContext +import io.element.android.libraries.matrix.api.auth.SessionRestorationException +import io.element.android.libraries.matrix.api.core.SessionId +import io.element.android.libraries.matrix.api.exception.ClientException +import io.element.android.libraries.matrix.api.exception.isNetworkError +import io.element.android.libraries.push.impl.db.PushRequest +import io.element.android.libraries.push.impl.history.PushHistoryService +import io.element.android.libraries.push.impl.notifications.NotifiableEventResolver +import io.element.android.libraries.push.impl.notifications.NotificationResultProcessor +import io.element.android.libraries.push.impl.push.PushRequestStatus +import io.element.android.libraries.push.impl.push.SyncOnNotifiableEvent +import io.element.android.libraries.workmanager.api.di.MetroWorkerFactory +import io.element.android.libraries.workmanager.api.di.WorkerKey +import io.element.android.services.analytics.api.AnalyticsLongRunningTransaction +import io.element.android.services.analytics.api.AnalyticsService +import io.element.android.services.analytics.api.finishLongRunningTransaction +import io.element.android.services.analytics.api.recordTransaction +import io.element.android.services.analyticsproviders.api.AnalyticsTransaction +import io.element.android.services.toolbox.api.systemclock.SystemClock +import kotlinx.coroutines.flow.first +import kotlinx.coroutines.withTimeoutOrNull +import timber.log.Timber +import kotlin.time.Duration.Companion.days +import kotlin.time.Duration.Companion.seconds +import kotlin.time.Instant + +@AssistedInject +class FetchPendingNotificationsWorker( + @Assisted private val params: WorkerParameters, + @ApplicationContext private val context: Context, + private val pushHistoryService: PushHistoryService, + private val networkMonitor: NetworkMonitor, + private val eventResolver: NotifiableEventResolver, + private val syncOnNotifiableEvent: SyncOnNotifiableEvent, + private val resultProcessor: NotificationResultProcessor, + private val analyticsService: AnalyticsService, + private val systemClock: SystemClock, +) : CoroutineWorker(context, params) { + override suspend fun doWork(): Result { + Timber.d("FetchNotificationsWorker started") + // RunCatching for test in debug mode + val sessionId = runCatchingExceptions { + inputData.getString(SyncPendingNotificationsRequestBuilder.SESSION_ID)?.let(::SessionId) + }.getOrNull() ?: return Result.failure() + + // Fetch pending requests in the last 24 hours + val fetchSince = Instant.fromEpochMilliseconds(systemClock.epochMillis()).minus(1.days) + val requests = pushHistoryService.getPendingPushRequests(sessionId, fetchSince).getOrNull() ?: return Result.failure() + + pushHistoryService.removeOldPushRequests(sessionId).onFailure { + Timber.e(it, "Could not remove outdated push requests") + } + + if (requests.isEmpty()) { + Timber.d("No pending notifications to fetch, returning early") + return Result.success() + } + + checkNetworkConnection(requests)?.let { failure -> return failure } + + Timber.d("Fetching ${requests.size} push requests") + + val pendingAnalyticTransactions = requests.mapNotNull { request -> + analyticsService.finishLongRunningTransaction(AnalyticsLongRunningTransaction.PushToWorkManager(request.eventId)) + val parent = analyticsService.getLongRunningTransaction(AnalyticsLongRunningTransaction.PushToNotification(request.eventId)) + val transactionName = "WorkManager to event fetched" + parent?.startChild(transactionName)?.let { request.eventId to it } + }.toMap() + + Timber.d("Processing notification requests for session $sessionId") + val results = eventResolver.resolveEvents(sessionId, requests) + .fold( + onSuccess = { results -> + for ((_, transaction) in pendingAnalyticTransactions) { + transaction.finish() + } + // Update the resolved results in the queue + resultProcessor.emit(results) + + results + }, + onFailure = { + // This is a failure at the fetch notification setup, not a failure for a single fetch notification operation + return handleSetupError(sessionId, requests, pendingAnalyticTransactions, it) + } + ) + + val updatedRequests = mutableListOf() + for (request in requests) { + val result = results[request] ?: continue + result.fold( + onSuccess = { updatedRequests.add(request.copy(status = PushRequestStatus.SUCCESS.value)) }, + onFailure = { exception -> + if (exception is ClientException && exception.isNetworkError()) { + // Reset to pending so we can retry it later + updatedRequests.add(request.copy(status = PushRequestStatus.PENDING.value)) + } else { + updatedRequests.add(request.copy(status = PushRequestStatus.FAILED.value)) + } + } + ) + } + + Timber.d("Notifications processed successfully") + + pushHistoryService.insertOrUpdatePushRequests(updatedRequests) + + analyticsService.recordTransaction("Opportunistic sync", "opportunistic_sync") { + performOpportunisticSyncIfNeeded(mapOf(sessionId to requests)) + } + + return if (updatedRequests.any { it.status == PushRequestStatus.PENDING.value }) Result.retry() else Result.success() + } + + private suspend fun performOpportunisticSyncIfNeeded( + groupedRequests: Map>, + ) { + for ((sessionId, notificationRequests) in groupedRequests) { + runCatchingExceptions { + syncOnNotifiableEvent(notificationRequests) + }.onFailure { + Timber.e(it, "Failed to sync on notifiable events for session $sessionId") + } + } + } + + private suspend fun checkNetworkConnection(requests: List): Result? { + val networkTimeoutSpans = requests.mapNotNull { request -> + val parent = analyticsService.getLongRunningTransaction(AnalyticsLongRunningTransaction.PushToWorkManager(request.eventId)) + parent?.startChild("Waiting for network connectivity", "await_network") + } + + // Wait for network to be available, but not more than 10 seconds + val hasNetwork = withTimeoutOrNull(10.seconds) { + networkMonitor.connectivity.first { it == NetworkStatus.Connected } + } != null + + networkTimeoutSpans.finish() + + // If there is a problem with the updated network values, report it and retry if needed + if (reportConnectivityError(requests = requests, hasNetwork = hasNetwork, isNetworkBlocked = networkMonitor.isNetworkBlocked())) { + pushHistoryService.insertOrUpdatePushRequests(requests.map { request -> + request.copy(retries = request.retries + 1) + }) + return Result.retry() + } + + return null + } + + private fun reportConnectivityError(requests: List, hasNetwork: Boolean, isNetworkBlocked: Boolean): Boolean { + return if (!hasNetwork || isNetworkBlocked) { + for (request in requests) { + val eventId = request.eventId + analyticsService.finishLongRunningTransaction(AnalyticsLongRunningTransaction.PushToWorkManager(eventId)) { + it.putExtraData("has_network_connection", hasNetwork.toString()) + it.putExtraData("is_network_blocked", isNetworkBlocked.toString()) + } + val parent = analyticsService.getLongRunningTransaction(AnalyticsLongRunningTransaction.PushToNotification(eventId)) + // Since we're retrying, start a new transaction + analyticsService.startLongRunningTransaction(AnalyticsLongRunningTransaction.PushToWorkManager(eventId), parent) + } + Timber.w("FetchNotificationsWorker will retry. Has network connectivity: $hasNetwork. Is network blocked: $isNetworkBlocked") + true + } else { + false + } + } + + private suspend fun handleSetupError( + sessionId: SessionId, + requests: List, + pendingAnalyticTransactions: Map, + throwable: Throwable, + ): Result { + for ((_, transaction) in pendingAnalyticTransactions) { + transaction.attachError(throwable) + transaction.finish() + } + + // If there were failures on the setup step and they weren't recoverable, update the requests and fail + if (throwable.cause is SessionRestorationException) { + Timber.e(throwable, "Session $sessionId could not be restored, not retrying notification fetching") + pushHistoryService.insertOrUpdatePushRequests(requests.map { request -> + request.copy(status = PushRequestStatus.FAILED.value) + }) + return Result.failure() + } + + // If the failure is recoverable, retry + for (request in requests) { + val failedTransaction = pendingAnalyticTransactions[request.eventId] + failedTransaction?.attachError(throwable) + failedTransaction?.finish() + + val eventId = request.eventId + val parent = analyticsService.getLongRunningTransaction(AnalyticsLongRunningTransaction.PushToNotification(eventId)) + // Since we're retrying, start a new transaction + analyticsService.startLongRunningTransaction(AnalyticsLongRunningTransaction.PushToWorkManager(eventId), parent) + } + + Timber.d("Re-scheduling ${requests.size} failed notification requests for session $sessionId") + + pushHistoryService.insertOrUpdatePushRequests(requests.map { request -> + request.copy(retries = request.retries + 1) + }) + + return Result.retry() + } + + @ContributesIntoMap(AppScope::class, binding = binding>()) + @WorkerKey(FetchPendingNotificationsWorker::class) + @AssistedFactory + interface Factory : MetroWorkerFactory.WorkerInstanceFactory +} + +private fun Collection.finish() = forEach { it.finish() } diff --git a/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/workmanager/SyncNotificationWorkManagerRequest.kt b/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/workmanager/SyncNotificationWorkManagerRequest.kt deleted file mode 100644 index 50ef28903c..0000000000 --- a/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/workmanager/SyncNotificationWorkManagerRequest.kt +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright (c) 2025 Element Creations Ltd. - * Copyright 2025 New Vector Ltd. - * - * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial. - * Please see LICENSE files in the repository root for full details. - */ - -package io.element.android.libraries.push.impl.workmanager - -import android.os.Build -import androidx.work.OneTimeWorkRequestBuilder -import androidx.work.OutOfQuotaPolicy -import androidx.work.WorkRequest -import io.element.android.libraries.matrix.api.core.SessionId -import io.element.android.libraries.push.api.push.NotificationEventRequest -import io.element.android.libraries.workmanager.api.WorkManagerRequest -import io.element.android.libraries.workmanager.api.WorkManagerRequestType -import io.element.android.libraries.workmanager.api.workManagerTag -import io.element.android.services.toolbox.api.sdk.BuildVersionSdkIntProvider -import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable -import timber.log.Timber -import java.security.InvalidParameterException - -class SyncNotificationWorkManagerRequest( - private val sessionId: SessionId, - private val notificationEventRequests: List, - private val workerDataConverter: SyncNotificationsWorkerDataConverter, - private val buildVersionSdkIntProvider: BuildVersionSdkIntProvider, -) : WorkManagerRequest { - override fun build(): Result> { - if (notificationEventRequests.isEmpty()) { - return Result.failure(InvalidParameterException("notificationEventRequests cannot be empty")) - } - Timber.d("Scheduling ${notificationEventRequests.size} notification requests with WorkManager for $sessionId") - return workerDataConverter.serialize(notificationEventRequests).map { dataList -> - dataList.map { data -> - OneTimeWorkRequestBuilder() - .setInputData(data) - .apply { - // Expedited workers aren't needed on Android 12 or lower: - // They force displaying a foreground sync notification for no good reason, since they sync almost immediately anyway - // See https://developer.android.com/develop/background-work/background-tasks/persistent/getting-started/define-work#backwards-compat - if (buildVersionSdkIntProvider.isAtLeast(Build.VERSION_CODES.TIRAMISU)) { - setExpedited(OutOfQuotaPolicy.RUN_AS_NON_EXPEDITED_WORK_REQUEST) - } - } - .setTraceTag(workManagerTag(sessionId, WorkManagerRequestType.NOTIFICATION_SYNC)) - // TODO investigate using this instead of the resolver queue - // .setInputMerger() - .build() - } - } - } - - @Serializable - data class Data( - @SerialName("session_id") - val sessionId: String, - @SerialName("room_id") - val roomId: String, - @SerialName("event_id") - val eventId: String, - @SerialName("provider_info") - val providerInfo: String, - ) -} diff --git a/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/workmanager/SyncNotificationsWorkerDataConverter.kt b/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/workmanager/SyncNotificationsWorkerDataConverter.kt deleted file mode 100644 index 46b7d760c0..0000000000 --- a/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/workmanager/SyncNotificationsWorkerDataConverter.kt +++ /dev/null @@ -1,129 +0,0 @@ -/* - * Copyright (c) 2025 Element Creations Ltd. - * Copyright 2025 New Vector Ltd. - * - * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial. - * Please see LICENSE files in the repository root for full details. - */ - -package io.element.android.libraries.push.impl.workmanager - -import androidx.work.Data -import androidx.work.workDataOf -import dev.zacsweers.metro.Inject -import io.element.android.libraries.androidutils.json.JsonProvider -import io.element.android.libraries.core.extensions.mapCatchingExceptions -import io.element.android.libraries.core.extensions.runCatchingExceptions -import io.element.android.libraries.matrix.api.core.EventId -import io.element.android.libraries.matrix.api.core.RoomId -import io.element.android.libraries.matrix.api.core.SessionId -import io.element.android.libraries.push.api.push.NotificationEventRequest -import timber.log.Timber - -@Inject -class SyncNotificationsWorkerDataConverter( - private val json: JsonProvider, -) { - fun serialize(notificationEventRequests: List): Result> { - // First try to serialize all requests at once. In the vast majority of cases this will work. - return serializeRequests(notificationEventRequests) - .map { listOf(it) } - .recoverCatching { t -> - if (t is DataForWorkManagerIsTooBig) { - // Perform serialization on sublists, workDataOf have failed because of size limit - Timber.w(t, "Failed to serialize ${notificationEventRequests.size} notification requests, split the requests per room.") - // Group the requests per rooms - val requestsSortedPerRoom = notificationEventRequests.groupBy { it.roomId }.values - // Build a list of sublist with size at most CHUNK_SIZE, and with all rooms kept together - buildList { - val currentChunk = mutableListOf() - for (requests in requestsSortedPerRoom) { - if (currentChunk.size + requests.size <= CHUNK_SIZE) { - // Can add the whole room requests to the current chunk - currentChunk.addAll(requests) - } else { - // Add the current chunk - add(currentChunk.toList()) - // Start a new chunk with the current room requests - currentChunk.clear() - // If a room has more requests than CHUNK_SIZE, we need to split them - requests.chunked(CHUNK_SIZE) { chunk -> - if (chunk.size == CHUNK_SIZE) { - add(chunk.toList()) - } else { - currentChunk.addAll(chunk) - } - } - } - } - // Add any remaining requests - add(currentChunk.toList()) - } - .filter { it.isNotEmpty() } - .also { - Timber.d("Split notification requests into ${it.size} chunks for WorkManager serialization") - it.forEach { requests -> - Timber.d(" - Chunk with ${requests.size} requests") - } - } - .mapNotNull { serializeRequests(it).getOrNull() } - } else { - throw t - } - } - } - - private fun serializeRequests(notificationEventRequests: List): Result { - return runCatchingExceptions { json().encodeToString(notificationEventRequests.map { it.toData() }) } - .onFailure { - Timber.e(it, "Failed to serialize notification requests") - } - .mapCatchingExceptions { str -> - // Note: workDataOf can fail if the data is too large - try { - workDataOf(REQUESTS_KEY to str) - } catch (_: IllegalStateException) { - throw DataForWorkManagerIsTooBig() - } - } - } - - fun deserialize(data: Data): List? { - val rawRequestsJson = data.getString(REQUESTS_KEY) ?: return null - return runCatchingExceptions { - json().decodeFromString>(rawRequestsJson).map { it.toRequest() } - }.fold( - onSuccess = { - Timber.d("Deserialized ${it.size} requests") - it - }, - onFailure = { - Timber.e(it, "Failed to deserialize notification requests") - null - } - ) - } - - companion object { - private const val REQUESTS_KEY = "requests" - internal const val CHUNK_SIZE = 20 - } -} - -private fun NotificationEventRequest.toData(): SyncNotificationWorkManagerRequest.Data { - return SyncNotificationWorkManagerRequest.Data( - sessionId = sessionId.value, - roomId = roomId.value, - eventId = eventId.value, - providerInfo = providerInfo, - ) -} - -private fun SyncNotificationWorkManagerRequest.Data.toRequest(): NotificationEventRequest { - return NotificationEventRequest( - sessionId = SessionId(sessionId), - roomId = RoomId(roomId), - eventId = EventId(eventId), - providerInfo = providerInfo, - ) -} diff --git a/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/workmanager/SyncPendingNotificationsRequestBuilder.kt b/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/workmanager/SyncPendingNotificationsRequestBuilder.kt new file mode 100644 index 0000000000..5aa40cadb5 --- /dev/null +++ b/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/workmanager/SyncPendingNotificationsRequestBuilder.kt @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2025 Element Creations Ltd. + * Copyright 2025 New Vector Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial. + * Please see LICENSE files in the repository root for full details. + */ + +package io.element.android.libraries.push.impl.workmanager + +import android.os.Build +import androidx.work.ExistingWorkPolicy +import androidx.work.OneTimeWorkRequestBuilder +import androidx.work.OutOfQuotaPolicy +import androidx.work.workDataOf +import io.element.android.libraries.matrix.api.core.SessionId +import io.element.android.libraries.workmanager.api.WorkManagerRequestBuilder +import io.element.android.libraries.workmanager.api.WorkManagerRequestType +import io.element.android.libraries.workmanager.api.WorkManagerRequestWrapper +import io.element.android.libraries.workmanager.api.WorkManagerWorkerType +import io.element.android.libraries.workmanager.api.workManagerTag +import io.element.android.services.toolbox.api.sdk.BuildVersionSdkIntProvider + +class SyncPendingNotificationsRequestBuilder( + private val sessionId: SessionId, + private val buildVersionSdkIntProvider: BuildVersionSdkIntProvider, +) : WorkManagerRequestBuilder { + companion object { + const val SESSION_ID = "session_id" + } + + override suspend fun build(): Result> { + val type = WorkManagerWorkerType.Unique( + name = workManagerTag(sessionId = sessionId, requestType = WorkManagerRequestType.NOTIFICATION_SYNC), + policy = ExistingWorkPolicy.APPEND_OR_REPLACE, + ) + val request = OneTimeWorkRequestBuilder() + .setInputData(workDataOf(SESSION_ID to sessionId.value)) + .apply { + // Expedited workers aren't needed on Android 12 or lower: + // They force displaying a foreground sync notification for no good reason, since they sync almost immediately anyway + // See https://developer.android.com/develop/background-work/background-tasks/persistent/getting-started/define-work#backwards-compat + if (buildVersionSdkIntProvider.isAtLeast(Build.VERSION_CODES.TIRAMISU)) { + setExpedited(OutOfQuotaPolicy.RUN_AS_NON_EXPEDITED_WORK_REQUEST) + } + } + .setTraceTag(workManagerTag(sessionId, WorkManagerRequestType.NOTIFICATION_SYNC)) + .build() + return Result.success(listOf(WorkManagerRequestWrapper(request, type))) + } +} diff --git a/libraries/push/impl/src/main/sqldelight/databases/1.db b/libraries/push/impl/src/main/sqldelight/databases/1.db new file mode 100644 index 0000000000000000000000000000000000000000..fa2978d82d79b0c918bd78f3f4b6a75f3af0392c GIT binary patch literal 8192 zcmeI#O-sZu5C-665rhR%PaYlEi-LIZ54fvA3#Dp};I-OWw$L_`#DYih?Em%XbeDzg zLA;8*Lqa>5e86*?`@6J?OmpX(BGQ@KQ(CKYBBhj;Ig+`KKHpj=^6m5ALaWoyuN~Q? zclVVH1Oy-e0SG_<0uX=z1Rwwb2teR(2)x&N`(QHBABVAcs`>UcEUv2%oqyZ-9bM#R zY7N=xEH$)IprbKKyvV7`Li*|?v*ya=l-*d$9@6w=Rrao{O7=-RcVx|@)CP6#xQ$7< zEUiv>=bFJn;1DX;4%QY$m@&6G2UmAo{_yy-YZ|$JdHMLb@6Dy@M?e4q5P$##AOHaf QKmY;|fB*y_@Q($)0n9v3=l}o! literal 0 HcmV?d00001 diff --git a/libraries/push/impl/src/main/sqldelight/databases/2.db b/libraries/push/impl/src/main/sqldelight/databases/2.db new file mode 100644 index 0000000000000000000000000000000000000000..42e0dfaa90e127975ff3d392e2b41c9c04b7eee1 GIT binary patch literal 20480 zcmeI%L2KJE6bEp*N!JmUwYMDiz?TNf*ciLdO|;F-bvws}_7uEXrG~_6EhTIW2Hket zKGeQdkCPR*C@E!^!65tvcBDK>&ihF@2#?-Jg%)%st7)d`1>0es$6gUJ##-juG}le3 z+wGf%`ShInebp9w`s=#8ea+h4N9^&J?cd#>rh)5)*XkY!NjBc17)azdMfga;|7Fdp&~assPk=rDG}w5t}A zhWQ>TJ8S=H(%S0zzW4o!&OS^;J=xnrX<2=Cs_o{1X|Nx0J7d#_b~|Lsg&8%>%#kjP zQ~ri06d$G(A4k#NB3#LNk&7xU&m^V%#Ke~3VlGM@<~Fn#QAs&n`r`J7JDtumwJ$`O z2qhB(1k8(OS)7x>K{i9`0EEJB|7*|FHhMb?e(seM5l&1Rwwb2tWV=5P$##AOHafKww=3I(1?=|F7%vA} ? ORDER BY pushDate ASC; + +insertPushRequest: +INSERT OR REPLACE INTO PushRequest VALUES ?; + +removeAll: +DELETE FROM PushRequest; + +removeOldest: +DELETE FROM PushRequest WHERE rowid NOT IN (SELECT rowid FROM PushRequest ORDER BY pushDate DESC LIMIT ?); diff --git a/libraries/push/impl/src/main/sqldelight/migrations/1.sqm b/libraries/push/impl/src/main/sqldelight/migrations/1.sqm new file mode 100644 index 0000000000..4f9edb2b08 --- /dev/null +++ b/libraries/push/impl/src/main/sqldelight/migrations/1.sqm @@ -0,0 +1,14 @@ +-- Migrate DB from version 1 + +CREATE TABLE PushRequest ( + pushDate INTEGER NOT NULL, + providerInfo TEXT NOT NULL, + eventId TEXT NOT NULL, + roomId TEXT NOT NULL, + sessionId TEXT NOT NULL, + status INTEGER NOT NULL DEFAULT 0, + retries INTEGER NOT NULL DEFAULT 0, + PRIMARY KEY(sessionId, eventId) +); + +CREATE INDEX PushRequestSessionAndStatus ON PushRequest (sessionId, status); diff --git a/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/history/FakePushHistoryService.kt b/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/history/FakePushHistoryService.kt index aac8f8f26d..aa9612717a 100644 --- a/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/history/FakePushHistoryService.kt +++ b/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/history/FakePushHistoryService.kt @@ -11,7 +11,9 @@ package io.element.android.libraries.push.impl.history import io.element.android.libraries.matrix.api.core.EventId import io.element.android.libraries.matrix.api.core.RoomId import io.element.android.libraries.matrix.api.core.SessionId +import io.element.android.libraries.push.impl.db.PushRequest import io.element.android.tests.testutils.lambda.lambdaError +import kotlin.time.Instant class FakePushHistoryService( private val onPushReceivedResult: ( @@ -22,9 +24,13 @@ class FakePushHistoryService( Boolean, Boolean, String? - ) -> Unit = { _, _, _, _, _, _, _ -> lambdaError() } + ) -> Unit = { _, _, _, _, _, _, _ -> lambdaError() }, + private val enqueuePushRequest: (PushRequest) -> Result = { lambdaError() }, + private val replacePushRequests: (List) -> Result = { lambdaError() }, + private val getPendingPushRequests: (SessionId, Instant?) -> Result> = { _, _ -> lambdaError() }, + private val removeOldPushRequests: (SessionId) -> Result = { lambdaError() }, ) : PushHistoryService { - override fun onPushReceived( + override fun onPushResult( providerInfo: String, eventId: EventId?, roomId: RoomId?, @@ -43,4 +49,20 @@ class FakePushHistoryService( comment ) } + + override suspend fun insertOrUpdatePushRequest(pushRequest: PushRequest): Result { + return enqueuePushRequest.invoke(pushRequest) + } + + override suspend fun insertOrUpdatePushRequests(pushRequests: List): Result { + return replacePushRequests.invoke(pushRequests) + } + + override suspend fun getPendingPushRequests(sessionId: SessionId, since: Instant?): Result> { + return getPendingPushRequests.invoke(sessionId, since) + } + + override suspend fun removeOldPushRequests(sessionId: SessionId): Result { + return removeOldPushRequests.invoke(sessionId) + } } diff --git a/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/DefaultNotifiableEventResolverTest.kt b/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/DefaultNotifiableEventResolverTest.kt index ba58db2a3c..19ef74d0b9 100644 --- a/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/DefaultNotifiableEventResolverTest.kt +++ b/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/DefaultNotifiableEventResolverTest.kt @@ -47,9 +47,10 @@ import io.element.android.libraries.matrix.test.FakeMatrixClientProvider import io.element.android.libraries.matrix.test.notification.FakeNotificationService import io.element.android.libraries.matrix.test.notification.aNotificationData import io.element.android.libraries.matrix.test.permalink.FakePermalinkParser -import io.element.android.libraries.push.api.push.NotificationEventRequest +import io.element.android.libraries.push.impl.db.PushRequest import io.element.android.libraries.push.impl.notifications.fake.FakeNotificationMediaRepo import io.element.android.libraries.push.impl.notifications.fixtures.aNotifiableMessageEvent +import io.element.android.libraries.push.impl.notifications.fixtures.aPushRequest import io.element.android.libraries.push.impl.notifications.model.FallbackNotifiableEvent import io.element.android.libraries.push.impl.notifications.model.InviteNotifiableEvent import io.element.android.libraries.push.impl.notifications.model.NotifiableMessageEvent @@ -71,7 +72,7 @@ class DefaultNotifiableEventResolverTest { @Test fun `resolve event no session`() = runTest { val sut = createDefaultNotifiableEventResolver(notificationService = null) - val result = sut.resolveEvents(A_SESSION_ID, listOf(NotificationEventRequest(A_SESSION_ID, A_ROOM_ID, AN_EVENT_ID, "firebase"))) + val result = sut.resolveEvents(A_SESSION_ID, listOf(aPushRequest(A_SESSION_ID, A_ROOM_ID, AN_EVENT_ID, "firebase"))) assertThat(result.isFailure).isTrue() } @@ -80,7 +81,7 @@ class DefaultNotifiableEventResolverTest { val sut = createDefaultNotifiableEventResolver( notificationResult = Result.failure(AN_EXCEPTION) ) - val request = NotificationEventRequest(A_SESSION_ID, A_ROOM_ID, AN_EVENT_ID, "firebase") + val request = aPushRequest(A_SESSION_ID, A_ROOM_ID, AN_EVENT_ID, "firebase") val result = sut.resolveEvents(A_SESSION_ID, listOf(request)) assertThat(result.isFailure).isTrue() } @@ -90,7 +91,7 @@ class DefaultNotifiableEventResolverTest { val sut = createDefaultNotifiableEventResolver( notificationResult = Result.success(mapOf(AN_EVENT_ID to Result.failure(AN_EXCEPTION))) ) - val request = NotificationEventRequest(A_SESSION_ID, A_ROOM_ID, AN_EVENT_ID, "firebase") + val request = aPushRequest(A_SESSION_ID, A_ROOM_ID, AN_EVENT_ID, "firebase") val result = sut.resolveEvents(A_SESSION_ID, listOf(request)) assertThat(result.getEvent(request)?.isFailure).isTrue() } @@ -109,7 +110,7 @@ class DefaultNotifiableEventResolverTest { ) ) ) - val request = NotificationEventRequest(A_SESSION_ID, A_ROOM_ID, AN_EVENT_ID, "firebase") + val request = aPushRequest(A_SESSION_ID, A_ROOM_ID, AN_EVENT_ID, "firebase") val result = sut.resolveEvents(A_SESSION_ID, listOf(request)) val expectedResult = ResolvedPushEvent.Event( aNotifiableMessageEvent(body = "Hello world") @@ -133,7 +134,7 @@ class DefaultNotifiableEventResolverTest { ) ) ) - val request = NotificationEventRequest(A_SESSION_ID, A_ROOM_ID, AN_EVENT_ID, "firebase") + val request = aPushRequest(A_SESSION_ID, A_ROOM_ID, AN_EVENT_ID, "firebase") val result = sut.resolveEvents(A_SESSION_ID, listOf(request)) val expectedResult = ResolvedPushEvent.Event( aNotifiableMessageEvent(body = "Hello world", hasMentionOrReply = true) @@ -161,7 +162,7 @@ class DefaultNotifiableEventResolverTest { ) ) ) - val request = NotificationEventRequest(A_SESSION_ID, A_ROOM_ID, AN_EVENT_ID, "firebase") + val request = aPushRequest(A_SESSION_ID, A_ROOM_ID, AN_EVENT_ID, "firebase") val result = sut.resolveEvents(A_SESSION_ID, listOf(request)) val expectedResult = ResolvedPushEvent.Event( aNotifiableMessageEvent(body = "Hello world") @@ -189,7 +190,7 @@ class DefaultNotifiableEventResolverTest { ) ) ) - val request = NotificationEventRequest(A_SESSION_ID, A_ROOM_ID, AN_EVENT_ID, "firebase") + val request = aPushRequest(A_SESSION_ID, A_ROOM_ID, AN_EVENT_ID, "firebase") val result = sut.resolveEvents(A_SESSION_ID, listOf(request)) val expectedResult = ResolvedPushEvent.Event( aNotifiableMessageEvent(body = "Hello world") @@ -211,7 +212,7 @@ class DefaultNotifiableEventResolverTest { ) ) ) - val request = NotificationEventRequest(A_SESSION_ID, A_ROOM_ID, AN_EVENT_ID, "firebase") + val request = aPushRequest(A_SESSION_ID, A_ROOM_ID, AN_EVENT_ID, "firebase") val result = sut.resolveEvents(A_SESSION_ID, listOf(request)) val expectedResult = ResolvedPushEvent.Event( aNotifiableMessageEvent(body = "Audio") @@ -233,7 +234,7 @@ class DefaultNotifiableEventResolverTest { ) ) ) - val request = NotificationEventRequest(A_SESSION_ID, A_ROOM_ID, AN_EVENT_ID, "firebase") + val request = aPushRequest(A_SESSION_ID, A_ROOM_ID, AN_EVENT_ID, "firebase") val result = sut.resolveEvents(A_SESSION_ID, listOf(request)) val expectedResult = ResolvedPushEvent.Event( aNotifiableMessageEvent(body = "Video") @@ -255,7 +256,7 @@ class DefaultNotifiableEventResolverTest { ) ) ) - val request = NotificationEventRequest(A_SESSION_ID, A_ROOM_ID, AN_EVENT_ID, "firebase") + val request = aPushRequest(A_SESSION_ID, A_ROOM_ID, AN_EVENT_ID, "firebase") val result = sut.resolveEvents(A_SESSION_ID, listOf(request)) val expectedResult = ResolvedPushEvent.Event( aNotifiableMessageEvent(body = "Voice message") @@ -277,7 +278,7 @@ class DefaultNotifiableEventResolverTest { ) ) ) - val request = NotificationEventRequest(A_SESSION_ID, A_ROOM_ID, AN_EVENT_ID, "firebase") + val request = aPushRequest(A_SESSION_ID, A_ROOM_ID, AN_EVENT_ID, "firebase") val result = sut.resolveEvents(A_SESSION_ID, listOf(request)) val expectedResult = ResolvedPushEvent.Event( aNotifiableMessageEvent(body = "Image") @@ -299,7 +300,7 @@ class DefaultNotifiableEventResolverTest { ) ) ) - val request = NotificationEventRequest(A_SESSION_ID, A_ROOM_ID, AN_EVENT_ID, "firebase") + val request = aPushRequest(A_SESSION_ID, A_ROOM_ID, AN_EVENT_ID, "firebase") val result = sut.resolveEvents(A_SESSION_ID, listOf(request)) val expectedResult = ResolvedPushEvent.Event( aNotifiableMessageEvent(body = "Sticker") @@ -321,7 +322,7 @@ class DefaultNotifiableEventResolverTest { ) ) ) - val request = NotificationEventRequest(A_SESSION_ID, A_ROOM_ID, AN_EVENT_ID, "firebase") + val request = aPushRequest(A_SESSION_ID, A_ROOM_ID, AN_EVENT_ID, "firebase") val result = sut.resolveEvents(A_SESSION_ID, listOf(request)) val expectedResult = ResolvedPushEvent.Event( aNotifiableMessageEvent(body = "File") @@ -343,7 +344,7 @@ class DefaultNotifiableEventResolverTest { ) ) ) - val request = NotificationEventRequest(A_SESSION_ID, A_ROOM_ID, AN_EVENT_ID, "firebase") + val request = aPushRequest(A_SESSION_ID, A_ROOM_ID, AN_EVENT_ID, "firebase") val result = sut.resolveEvents(A_SESSION_ID, listOf(request)) val expectedResult = ResolvedPushEvent.Event( aNotifiableMessageEvent(body = "Location") @@ -365,7 +366,7 @@ class DefaultNotifiableEventResolverTest { ) ) ) - val request = NotificationEventRequest(A_SESSION_ID, A_ROOM_ID, AN_EVENT_ID, "firebase") + val request = aPushRequest(A_SESSION_ID, A_ROOM_ID, AN_EVENT_ID, "firebase") val result = sut.resolveEvents(A_SESSION_ID, listOf(request)) val expectedResult = ResolvedPushEvent.Event( aNotifiableMessageEvent(body = "Notice") @@ -387,7 +388,7 @@ class DefaultNotifiableEventResolverTest { ) ) ) - val request = NotificationEventRequest(A_SESSION_ID, A_ROOM_ID, AN_EVENT_ID, "firebase") + val request = aPushRequest(A_SESSION_ID, A_ROOM_ID, AN_EVENT_ID, "firebase") val result = sut.resolveEvents(A_SESSION_ID, listOf(request)) val expectedResult = ResolvedPushEvent.Event( aNotifiableMessageEvent(body = "* Bob is happy") @@ -409,7 +410,7 @@ class DefaultNotifiableEventResolverTest { ) ) ) - val request = NotificationEventRequest(A_SESSION_ID, A_ROOM_ID, AN_EVENT_ID, "firebase") + val request = aPushRequest(A_SESSION_ID, A_ROOM_ID, AN_EVENT_ID, "firebase") val result = sut.resolveEvents(A_SESSION_ID, listOf(request)) val expectedResult = ResolvedPushEvent.Event( aNotifiableMessageEvent(body = "Poll: A question") @@ -432,7 +433,7 @@ class DefaultNotifiableEventResolverTest { ) ) ) - val request = NotificationEventRequest(A_SESSION_ID, A_ROOM_ID, AN_EVENT_ID, "firebase") + val request = aPushRequest(A_SESSION_ID, A_ROOM_ID, AN_EVENT_ID, "firebase") val result = sut.resolveEvents(A_SESSION_ID, listOf(request)) assertThat(result.getEvent(request)?.getOrNull()).isNull() } @@ -451,7 +452,7 @@ class DefaultNotifiableEventResolverTest { ) ) ) - val request = NotificationEventRequest(A_SESSION_ID, A_ROOM_ID, AN_EVENT_ID, "firebase") + val request = aPushRequest(A_SESSION_ID, A_ROOM_ID, AN_EVENT_ID, "firebase") val result = sut.resolveEvents(A_SESSION_ID, listOf(request)) val expectedResult = ResolvedPushEvent.Event( InviteNotifiableEvent( @@ -490,7 +491,7 @@ class DefaultNotifiableEventResolverTest { ) ) ) - val request = NotificationEventRequest(A_SESSION_ID, A_ROOM_ID, AN_EVENT_ID, "firebase") + val request = aPushRequest(A_SESSION_ID, A_ROOM_ID, AN_EVENT_ID, "firebase") val result = sut.resolveEvents(A_SESSION_ID, listOf(request)) val expectedResult = ResolvedPushEvent.Event( InviteNotifiableEvent( @@ -527,7 +528,7 @@ class DefaultNotifiableEventResolverTest { ) ) ) - val request = NotificationEventRequest(A_SESSION_ID, A_ROOM_ID, AN_EVENT_ID, "firebase") + val request = aPushRequest(A_SESSION_ID, A_ROOM_ID, AN_EVENT_ID, "firebase") val result = sut.resolveEvents(A_SESSION_ID, listOf(request)) val expectedResult = ResolvedPushEvent.Event( InviteNotifiableEvent( @@ -565,7 +566,7 @@ class DefaultNotifiableEventResolverTest { ) ) ) - val request = NotificationEventRequest(A_SESSION_ID, A_ROOM_ID, AN_EVENT_ID, "firebase") + val request = aPushRequest(A_SESSION_ID, A_ROOM_ID, AN_EVENT_ID, "firebase") val result = sut.resolveEvents(A_SESSION_ID, listOf(request)) val expectedResult = ResolvedPushEvent.Event( InviteNotifiableEvent( @@ -605,7 +606,7 @@ class DefaultNotifiableEventResolverTest { ) ) ) - val request = NotificationEventRequest(A_SESSION_ID, A_ROOM_ID, AN_EVENT_ID, "firebase") + val request = aPushRequest(A_SESSION_ID, A_ROOM_ID, AN_EVENT_ID, "firebase") val result = sut.resolveEvents(A_SESSION_ID, listOf(request)) val expectedResult = ResolvedPushEvent.Event( InviteNotifiableEvent( @@ -642,7 +643,7 @@ class DefaultNotifiableEventResolverTest { ) ) ) - val request = NotificationEventRequest(A_SESSION_ID, A_ROOM_ID, AN_EVENT_ID, "firebase") + val request = aPushRequest(A_SESSION_ID, A_ROOM_ID, AN_EVENT_ID, "firebase") val result = sut.resolveEvents(A_SESSION_ID, listOf(request)) assertThat(result.getEvent(request)?.getOrNull()).isNull() } @@ -654,7 +655,7 @@ class DefaultNotifiableEventResolverTest { mapOf(AN_EVENT_ID to Result.success(aNotificationData(content = NotificationContent.MessageLike.RoomEncrypted))) ) ) - val request = NotificationEventRequest(A_SESSION_ID, A_ROOM_ID, AN_EVENT_ID, "firebase") + val request = aPushRequest(A_SESSION_ID, A_ROOM_ID, AN_EVENT_ID, "firebase") val result = sut.resolveEvents(A_SESSION_ID, listOf(request)) val expectedResult = ResolvedPushEvent.Event( FallbackNotifiableEvent( @@ -680,7 +681,7 @@ class DefaultNotifiableEventResolverTest { mapOf(AN_EVENT_ID to Result.failure(NotificationResolverException.EventNotFound)) ) ) - val request = NotificationEventRequest(A_SESSION_ID, A_ROOM_ID, AN_EVENT_ID, "firebase") + val request = aPushRequest(A_SESSION_ID, A_ROOM_ID, AN_EVENT_ID, "firebase") val result = sut.resolveEvents(A_SESSION_ID, listOf(request)) assertThat(result.getEvent(request)).isEqualTo(Result.failure(NotificationResolverException.EventNotFound)) } @@ -698,7 +699,7 @@ class DefaultNotifiableEventResolverTest { ) ) ) - val request = NotificationEventRequest(A_SESSION_ID, A_ROOM_ID, AN_EVENT_ID, "firebase") + val request = aPushRequest(A_SESSION_ID, A_ROOM_ID, AN_EVENT_ID, "firebase") val result = sut.resolveEvents(A_SESSION_ID, listOf(request)) val expectedResult = ResolvedPushEvent.Event( NotifiableMessageEvent( @@ -766,7 +767,7 @@ class DefaultNotifiableEventResolverTest { ) ) callNotificationEventResolver.resolveEventLambda = { _, _, _ -> Result.success(expectedResult.notifiableEvent) } - val request = NotificationEventRequest(A_SESSION_ID, A_ROOM_ID, AN_EVENT_ID, "firebase") + val request = aPushRequest(A_SESSION_ID, A_ROOM_ID, AN_EVENT_ID, "firebase") val result = sut.resolveEvents(A_SESSION_ID, listOf(request)) assertThat(result.getEvent(request)).isEqualTo(Result.success(expectedResult)) } @@ -791,7 +792,7 @@ class DefaultNotifiableEventResolverTest { redactedEventId = AN_EVENT_ID_2, reason = A_REDACTION_REASON, ) - val request = NotificationEventRequest(A_SESSION_ID, A_ROOM_ID, AN_EVENT_ID, "firebase") + val request = aPushRequest(A_SESSION_ID, A_ROOM_ID, AN_EVENT_ID, "firebase") val result = sut.resolveEvents(A_SESSION_ID, listOf(request)) assertThat(result.getEvent(request)).isEqualTo(Result.success(expectedResult)) } @@ -810,7 +811,7 @@ class DefaultNotifiableEventResolverTest { ) ) ) - val request = NotificationEventRequest(A_SESSION_ID, A_ROOM_ID, AN_EVENT_ID, "firebase") + val request = aPushRequest(A_SESSION_ID, A_ROOM_ID, AN_EVENT_ID, "firebase") val result = sut.resolveEvents(A_SESSION_ID, listOf(request)) assertThat(result.getEvent(request)?.getOrNull()).isNull() } @@ -857,13 +858,13 @@ class DefaultNotifiableEventResolverTest { mapOf(AN_EVENT_ID to Result.success(aNotificationData(content = content))) ) ) - val request = NotificationEventRequest(A_SESSION_ID, A_ROOM_ID, AN_EVENT_ID, "firebase") + val request = aPushRequest(A_SESSION_ID, A_ROOM_ID, AN_EVENT_ID, "firebase") val result = sut.resolveEvents(A_SESSION_ID, listOf(request)) assertThat(result.getEvent(request)?.getOrNull()).isNull() } - private fun Result>>.getEvent( - request: NotificationEventRequest + private fun Result>>.getEvent( + request: PushRequest ): Result? { return getOrNull()?.get(request) } diff --git a/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/DefaultNotificationResultProcessorTest.kt b/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/DefaultNotificationResultProcessorTest.kt new file mode 100644 index 0000000000..5a0d95c017 --- /dev/null +++ b/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/DefaultNotificationResultProcessorTest.kt @@ -0,0 +1,310 @@ +/* + * Copyright (c) 2026 Element Creations Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial. + * Please see LICENSE files in the repository root for full details. + */ + +package io.element.android.libraries.push.impl.notifications + +import com.google.common.truth.Truth.assertThat +import io.element.android.features.call.api.CallType +import io.element.android.features.call.test.FakeElementCallEntryPoint +import io.element.android.libraries.featureflag.test.FakeFeatureFlagService +import io.element.android.libraries.matrix.api.core.EventId +import io.element.android.libraries.matrix.api.core.RoomId +import io.element.android.libraries.matrix.api.core.SessionId +import io.element.android.libraries.matrix.api.core.UserId +import io.element.android.libraries.matrix.api.exception.NotificationResolverException +import io.element.android.libraries.matrix.api.timeline.item.event.EventType +import io.element.android.libraries.matrix.test.AN_EVENT_ID +import io.element.android.libraries.matrix.test.AN_EVENT_ID_2 +import io.element.android.libraries.matrix.test.A_ROOM_ID +import io.element.android.libraries.matrix.test.A_SESSION_ID +import io.element.android.libraries.matrix.test.A_USER_ID +import io.element.android.libraries.push.impl.db.PushRequest +import io.element.android.libraries.push.impl.history.FakePushHistoryService +import io.element.android.libraries.push.impl.notifications.channels.FakeNotificationChannels +import io.element.android.libraries.push.impl.notifications.fixtures.aFallbackNotifiableEvent +import io.element.android.libraries.push.impl.notifications.fixtures.aNotifiableCallEvent +import io.element.android.libraries.push.impl.notifications.fixtures.aNotifiableMessageEvent +import io.element.android.libraries.push.impl.notifications.fixtures.aPushRequest +import io.element.android.libraries.push.impl.notifications.model.NotifiableEvent +import io.element.android.libraries.push.impl.notifications.model.ResolvedPushEvent +import io.element.android.libraries.push.impl.push.FakeMutableBatteryOptimizationStore +import io.element.android.libraries.push.impl.push.FakeOnNotifiableEventReceived +import io.element.android.libraries.push.impl.push.FakeOnRedactedEventReceived +import io.element.android.libraries.push.impl.push.SyncOnNotifiableEvent +import io.element.android.libraries.pushstore.test.userpushstore.FakeUserPushStoreFactory +import io.element.android.services.toolbox.test.systemclock.FakeSystemClock +import io.element.android.tests.testutils.lambda.any +import io.element.android.tests.testutils.lambda.lambdaRecorder +import io.element.android.tests.testutils.lambda.value +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.test.TestScope +import kotlinx.coroutines.test.advanceTimeBy +import kotlinx.coroutines.test.runCurrent +import kotlinx.coroutines.test.runTest +import org.junit.Test +import kotlin.time.Duration.Companion.milliseconds + +@OptIn(ExperimentalCoroutinesApi::class) +class DefaultNotificationResultProcessorTest { + @Test + fun `when not able to resolve the event, the banner to disable battery optimization will be displayed`() { + `test notification resolver failure`( + notificationResolveResult = { requests: List -> + Result.success( + requests.associateWith { Result.failure(NotificationResolverException.UnknownError("Unable to resolve event")) } + ) + }, + shouldSetOptimizationBatteryBanner = true, + ) + } + + private fun `test notification resolver failure`( + notificationResolveResult: (List) -> Result>>, + shouldSetOptimizationBatteryBanner: Boolean, + ) { + runTest { + val notifiableEventResult = + lambdaRecorder, Result>>> { _, requests -> + notificationResolveResult(requests) + } + val onPushReceivedResult = lambdaRecorder { _, _, _, _, _, _, _ -> } + val pushHistoryService = FakePushHistoryService( + onPushReceivedResult = onPushReceivedResult, + ) + val showBatteryOptimizationBannerResult = lambdaRecorder {} + val processor = createDefaultNotificationResultProcessor( + mutableBatteryOptimizationStore = FakeMutableBatteryOptimizationStore( + showBatteryOptimizationBannerResult = showBatteryOptimizationBannerResult, + ), + pushHistoryService = pushHistoryService, + ) + + runningProcessor(processor) { + emit(mapOf(aPushRequest() to Result.failure(IllegalStateException("boom")))) + } + + notifiableEventResult.assertions() + .isNeverCalled() + onPushReceivedResult.assertions() + .isCalledOnce() + .with(any(), value(AN_EVENT_ID), value(A_ROOM_ID), value(A_USER_ID), value(false), value(true), any()) + showBatteryOptimizationBannerResult.assertions().let { + if (shouldSetOptimizationBatteryBanner) { + it.isCalledOnce() + } else { + it.isNeverCalled() + } + } + } + } + + @Test + fun `when ringing call PushData is received, the incoming call will be handled`() = runTest { + val handleIncomingCallLambda = lambdaRecorder< + CallType.RoomCall, + EventId, + UserId, + String?, + String?, + String?, + String, + String?, + Unit, + > { _, _, _, _, _, _, _, _ -> } + val elementCallEntryPoint = FakeElementCallEntryPoint(handleIncomingCallResult = handleIncomingCallLambda) + val onNotifiableEventsReceived = lambdaRecorder, Unit> {} + val onPushReceivedResult = lambdaRecorder { _, _, _, _, _, _, _ -> } + val pushHistoryService = FakePushHistoryService( + onPushReceivedResult = onPushReceivedResult, + ) + val processor = createDefaultNotificationResultProcessor( + elementCallEntryPoint = elementCallEntryPoint, + onNotifiableEventsReceived = onNotifiableEventsReceived, + pushHistoryService = pushHistoryService, + ) + runningProcessor(processor) { + emit(mapOf(aPushRequest() to Result.success(ResolvedPushEvent.Event(aNotifiableCallEvent())))) + } + + advanceTimeBy(300.milliseconds) + + handleIncomingCallLambda.assertions().isCalledOnce() + onNotifiableEventsReceived.assertions().isNeverCalled() + onPushReceivedResult.assertions().isCalledOnce() + } + + @Test + fun `when notify call PushData is received, the incoming call will be treated as a normal notification`() = runTest { + val onNotifiableEventsReceived = lambdaRecorder, Unit> {} + val handleIncomingCallLambda = lambdaRecorder< + CallType.RoomCall, + EventId, + UserId, + String?, + String?, + String?, + String, + String?, + Unit, + > { _, _, _, _, _, _, _, _ -> } + val elementCallEntryPoint = FakeElementCallEntryPoint(handleIncomingCallResult = handleIncomingCallLambda) + val onPushReceivedResult = lambdaRecorder { _, _, _, _, _, _, _ -> } + val pushHistoryService = FakePushHistoryService( + onPushReceivedResult = onPushReceivedResult, + ) + val processor = createDefaultNotificationResultProcessor( + elementCallEntryPoint = elementCallEntryPoint, + onNotifiableEventsReceived = onNotifiableEventsReceived, + pushHistoryService = pushHistoryService, + ) + + runningProcessor(processor) { + processor.emit(mapOf(aPushRequest() to Result.success(ResolvedPushEvent.Event(aNotifiableMessageEvent(type = EventType.RTC_NOTIFICATION))))) + } + + advanceTimeBy(300.milliseconds) + + handleIncomingCallLambda.assertions().isNeverCalled() + onNotifiableEventsReceived.assertions().isCalledOnce() + onPushReceivedResult.assertions().isCalledOnce() + } + + @Test + fun `when notify call PushData is received, the incoming call will be treated as a normal notification even if notification are disabled`() = runTest { + val onNotifiableEventsReceived = lambdaRecorder, Unit> {} + val handleIncomingCallLambda = lambdaRecorder< + CallType.RoomCall, + EventId, + UserId, + String?, + String?, + String?, + String, + String?, + Unit, + > { _, _, _, _, _, _, _, _ -> } + val elementCallEntryPoint = FakeElementCallEntryPoint(handleIncomingCallResult = handleIncomingCallLambda) + val onPushReceivedResult = lambdaRecorder { _, _, _, _, _, _, _ -> } + val pushHistoryService = FakePushHistoryService( + onPushReceivedResult = onPushReceivedResult, + ) + val processor = createDefaultNotificationResultProcessor( + elementCallEntryPoint = elementCallEntryPoint, + onNotifiableEventsReceived = onNotifiableEventsReceived, + pushHistoryService = pushHistoryService, + ) + + runningProcessor(processor) { + processor.emit(mapOf(aPushRequest() to Result.success(ResolvedPushEvent.Event(aNotifiableCallEvent())))) + } + + advanceTimeBy(300.milliseconds) + + handleIncomingCallLambda.assertions().isCalledOnce() + onNotifiableEventsReceived.assertions().isNeverCalled() + onPushReceivedResult.assertions().isCalledOnce() + } + + @Test + fun `when a redaction is received, the onRedactedEventReceived is informed`() = runTest { + val aRedaction = ResolvedPushEvent.Redaction( + sessionId = A_SESSION_ID, + roomId = A_ROOM_ID, + redactedEventId = AN_EVENT_ID_2, + reason = null + ) + val onRedactedEventReceived = lambdaRecorder, Unit> { } + val onPushReceivedResult = lambdaRecorder { _, _, _, _, _, _, _ -> } + val pushHistoryService = FakePushHistoryService( + onPushReceivedResult = onPushReceivedResult, + ) + val processor = createDefaultNotificationResultProcessor( + onRedactedEventReceived = onRedactedEventReceived, + pushHistoryService = pushHistoryService, + ) + + runningProcessor(processor) { + emit(mapOf(aPushRequest() to Result.success(aRedaction))) + } + + advanceTimeBy(300.milliseconds) + + onRedactedEventReceived.assertions().isCalledOnce() + .with(value(listOf(aRedaction))) + onPushReceivedResult.assertions() + .isCalledOnce() + } + + @Test + fun `when receiving a fallback event, we notify the push history service about it not being resolved`() = runTest { + val aNotifiableFallbackEvent = aFallbackNotifiableEvent() + val onNotifiableEventsReceived = lambdaRecorder, Unit> {} + var receivedFallbackEvent = false + val onPushReceivedResult = + lambdaRecorder { _, _, _, _, isResolved, _, comment -> + receivedFallbackEvent = !isResolved && comment == "Unable to resolve event: ${aNotifiableFallbackEvent.cause}" + } + val pushHistoryService = FakePushHistoryService( + onPushReceivedResult = onPushReceivedResult, + ) + + val processor = createDefaultNotificationResultProcessor( + onNotifiableEventsReceived = onNotifiableEventsReceived, + pushHistoryService = pushHistoryService, + ) + + runningProcessor(processor) { + emit(mapOf(aPushRequest() to Result.success(ResolvedPushEvent.Event(aNotifiableFallbackEvent)))) + } + + advanceTimeBy(300.milliseconds) + + onNotifiableEventsReceived.assertions().isCalledOnce() + + assertThat(receivedFallbackEvent).isTrue() + } + + private suspend fun TestScope.runningProcessor(processor: NotificationResultProcessor, block: suspend NotificationResultProcessor.() -> Unit) { + processor.start() + + runCurrent() + + block(processor) + + runCurrent() + + processor.stop() + } + + private fun TestScope.createDefaultNotificationResultProcessor( + systemClock: FakeSystemClock = FakeSystemClock(), + pushHistoryService: FakePushHistoryService = FakePushHistoryService(), + mutableBatteryOptimizationStore: FakeMutableBatteryOptimizationStore = FakeMutableBatteryOptimizationStore(), + fallbackNotificationFactory: FallbackNotificationFactory = FallbackNotificationFactory(systemClock), + userPushStoreFactory: FakeUserPushStoreFactory = FakeUserPushStoreFactory(), + onRedactedEventReceived: (List) -> Unit = {}, + onNotifiableEventsReceived: (List) -> Unit = {}, + featureFlagService: FakeFeatureFlagService = FakeFeatureFlagService(), + syncOnNotifiableEvent: SyncOnNotifiableEvent = {}, + elementCallEntryPoint: FakeElementCallEntryPoint = FakeElementCallEntryPoint(), + notificationChannels: FakeNotificationChannels = FakeNotificationChannels(), + coroutineScope: CoroutineScope = backgroundScope, + ) = DefaultNotificationResultProcessor( + pushHistoryService = pushHistoryService, + batteryOptimizationStore = mutableBatteryOptimizationStore, + fallbackNotificationFactory = fallbackNotificationFactory, + userPushStoreFactory = userPushStoreFactory, + onRedactedEventReceived = FakeOnRedactedEventReceived(onRedactedEventReceived), + onNotifiableEventReceived = FakeOnNotifiableEventReceived(onNotifiableEventsReceived), + featureFlagService = featureFlagService, + syncOnNotifiableEvent = syncOnNotifiableEvent, + elementCallEntryPoint = elementCallEntryPoint, + notificationChannels = notificationChannels, + coroutineScope = coroutineScope, + ) +} diff --git a/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/FakeNotifiableEventResolver.kt b/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/FakeNotifiableEventResolver.kt index 17ba7448ec..a83f582a58 100644 --- a/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/FakeNotifiableEventResolver.kt +++ b/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/FakeNotifiableEventResolver.kt @@ -9,18 +9,18 @@ package io.element.android.libraries.push.impl.notifications import io.element.android.libraries.matrix.api.core.SessionId -import io.element.android.libraries.push.api.push.NotificationEventRequest +import io.element.android.libraries.push.impl.db.PushRequest import io.element.android.libraries.push.impl.notifications.model.ResolvedPushEvent import io.element.android.tests.testutils.lambda.lambdaError class FakeNotifiableEventResolver( - private val resolveEventsResult: (SessionId, List) -> Result>> = + private val resolveEventsResult: (SessionId, List) -> Result>> = { _, _ -> lambdaError() } ) : NotifiableEventResolver { override suspend fun resolveEvents( sessionId: SessionId, - notificationEventRequests: List - ): Result>> { + notificationEventRequests: List + ): Result>> { return resolveEventsResult(sessionId, notificationEventRequests) } } diff --git a/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/FakeNotificationResultProcessor.kt b/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/FakeNotificationResultProcessor.kt new file mode 100644 index 0000000000..da73cd4560 --- /dev/null +++ b/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/FakeNotificationResultProcessor.kt @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2026 Element Creations Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial. + * Please see LICENSE files in the repository root for full details. + */ + +package io.element.android.libraries.push.impl.notifications + +import io.element.android.libraries.push.impl.db.PushRequest +import io.element.android.libraries.push.impl.notifications.model.ResolvedPushEvent +import io.element.android.tests.testutils.lambda.lambdaError + +class FakeNotificationResultProcessor( + private val emit: (Map>) -> Unit = { lambdaError() }, + private val start: () -> Unit = { lambdaError() }, + private val stop: () -> Unit = { lambdaError() }, +) : NotificationResultProcessor { + override suspend fun emit(results: Map>) { + return emit.invoke(results) + } + + override fun start() { + start.invoke() + } + + override fun stop() { + stop.invoke() + } +} diff --git a/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/fixtures/NotificationEventRequestFixture.kt b/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/fixtures/PushRequestFixture.kt similarity index 58% rename from libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/fixtures/NotificationEventRequestFixture.kt rename to libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/fixtures/PushRequestFixture.kt index c450287fbd..4d2e475fa1 100644 --- a/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/fixtures/NotificationEventRequestFixture.kt +++ b/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/fixtures/PushRequestFixture.kt @@ -1,6 +1,5 @@ /* - * Copyright (c) 2025 Element Creations Ltd. - * Copyright 2025 New Vector Ltd. + * Copyright (c) 2026 Element Creations Ltd. * * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial. * Please see LICENSE files in the repository root for full details. @@ -14,16 +13,22 @@ import io.element.android.libraries.matrix.api.core.SessionId 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.push.api.push.NotificationEventRequest +import io.element.android.libraries.push.impl.db.PushRequest +import io.element.android.libraries.push.impl.push.PushRequestStatus -fun aNotificationEventRequest( +fun aPushRequest( sessionId: SessionId = A_SESSION_ID, roomId: RoomId = A_ROOM_ID, eventId: EventId = AN_EVENT_ID, - providerInfo: String = "providerInfo", -) = NotificationEventRequest( - sessionId = sessionId, - roomId = roomId, - eventId = eventId, + providerInfo: String = "firebase", + status: PushRequestStatus = PushRequestStatus.PENDING, + retries: Int = 0, +) = PushRequest( + pushDate = System.currentTimeMillis(), providerInfo = providerInfo, + eventId = eventId.value, + roomId = roomId.value, + sessionId = sessionId.value, + status = status.value, + retries = retries.toLong(), ) diff --git a/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/push/DefaultPushHandlerTest.kt b/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/push/DefaultPushHandlerTest.kt index 5d3af86eea..733b2b64be 100644 --- a/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/push/DefaultPushHandlerTest.kt +++ b/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/push/DefaultPushHandlerTest.kt @@ -11,65 +11,38 @@ package io.element.android.libraries.push.impl.push import app.cash.turbine.test -import com.google.common.truth.Truth.assertThat -import io.element.android.features.call.api.CallType -import io.element.android.features.call.test.FakeElementCallEntryPoint -import io.element.android.libraries.androidutils.json.DefaultJsonProvider import io.element.android.libraries.core.meta.BuildMeta -import io.element.android.libraries.featureflag.api.FeatureFlags -import io.element.android.libraries.featureflag.test.FakeFeatureFlagService import io.element.android.libraries.matrix.api.core.EventId import io.element.android.libraries.matrix.api.core.RoomId import io.element.android.libraries.matrix.api.core.SessionId -import io.element.android.libraries.matrix.api.core.UserId -import io.element.android.libraries.matrix.api.exception.NotificationResolverException -import io.element.android.libraries.matrix.api.notification.RtcNotificationType -import io.element.android.libraries.matrix.api.timeline.item.event.EventType import io.element.android.libraries.matrix.test.AN_EVENT_ID -import io.element.android.libraries.matrix.test.AN_EVENT_ID_2 import io.element.android.libraries.matrix.test.A_ROOM_ID import io.element.android.libraries.matrix.test.A_SECRET -import io.element.android.libraries.matrix.test.A_SESSION_ID import io.element.android.libraries.matrix.test.A_USER_ID import io.element.android.libraries.matrix.test.core.aBuildMeta -import io.element.android.libraries.push.api.push.NotificationEventRequest -import io.element.android.libraries.push.api.push.SyncOnNotifiableEvent +import io.element.android.libraries.push.impl.db.PushRequest import io.element.android.libraries.push.impl.history.FakePushHistoryService import io.element.android.libraries.push.impl.history.PushHistoryService -import io.element.android.libraries.push.impl.notifications.DefaultNotificationResolverQueue -import io.element.android.libraries.push.impl.notifications.FakeNotifiableEventResolver -import io.element.android.libraries.push.impl.notifications.FallbackNotificationFactory -import io.element.android.libraries.push.impl.notifications.channels.FakeNotificationChannels -import io.element.android.libraries.push.impl.notifications.fixtures.aFallbackNotifiableEvent -import io.element.android.libraries.push.impl.notifications.fixtures.aNotifiableCallEvent -import io.element.android.libraries.push.impl.notifications.fixtures.aNotifiableMessageEvent -import io.element.android.libraries.push.impl.notifications.model.NotifiableEvent -import io.element.android.libraries.push.impl.notifications.model.ResolvedPushEvent +import io.element.android.libraries.push.impl.notifications.FakeNotificationResultProcessor import io.element.android.libraries.push.impl.test.DefaultTestPush import io.element.android.libraries.push.impl.troubleshoot.DiagnosticPushHandler -import io.element.android.libraries.push.impl.workmanager.SyncNotificationsWorkerDataConverter import io.element.android.libraries.pushproviders.api.PushData -import io.element.android.libraries.pushstore.api.UserPushStore import io.element.android.libraries.pushstore.api.clientsecret.PushClientSecret import io.element.android.libraries.pushstore.test.userpushstore.FakeUserPushStore import io.element.android.libraries.pushstore.test.userpushstore.FakeUserPushStoreFactory import io.element.android.libraries.pushstore.test.userpushstore.clientsecret.FakePushClientSecret -import io.element.android.libraries.workmanager.api.WorkManagerRequest +import io.element.android.libraries.workmanager.api.WorkManagerRequestBuilder import io.element.android.libraries.workmanager.test.FakeWorkManagerScheduler import io.element.android.services.analytics.test.FakeAnalyticsService import io.element.android.services.toolbox.test.sdk.FakeBuildVersionSdkIntProvider import io.element.android.services.toolbox.test.systemclock.FakeSystemClock -import io.element.android.tests.testutils.lambda.any import io.element.android.tests.testutils.lambda.lambdaError import io.element.android.tests.testutils.lambda.lambdaRecorder -import io.element.android.tests.testutils.lambda.matching import io.element.android.tests.testutils.lambda.value import kotlinx.coroutines.ExperimentalCoroutinesApi -import kotlinx.coroutines.test.TestScope import kotlinx.coroutines.test.advanceTimeBy import kotlinx.coroutines.test.runTest import org.junit.Test -import java.time.Instant import kotlin.time.Duration.Companion.milliseconds private const val A_PUSHER_INFO = "info" @@ -96,84 +69,36 @@ class DefaultPushHandlerTest { } @Test - fun `when classical PushData is received, the notification drawer is informed`() = runTest { - val aNotifiableMessageEvent = aNotifiableMessageEvent() - val notifiableEventResult = - lambdaRecorder, Result>>> { _, _ -> - val request = NotificationEventRequest(A_SESSION_ID, A_ROOM_ID, AN_EVENT_ID, A_PUSHER_INFO) - Result.success(mapOf(request to Result.success(ResolvedPushEvent.Event(aNotifiableMessageEvent)))) - } - val onNotifiableEventsReceived = lambdaRecorder, Unit> {} + fun `when classical PushData is received, the work is scheduled`() = runTest { val incrementPushCounterResult = lambdaRecorder {} - val onPushReceivedResult = lambdaRecorder { _, _, _, _, _, _, _ -> } - val pushHistoryService = FakePushHistoryService( - onPushReceivedResult = onPushReceivedResult, - ) val aPushData = PushData( eventId = AN_EVENT_ID, roomId = A_ROOM_ID, unread = 0, clientSecret = A_SECRET, ) + + val enqueuePushRequestResult = lambdaRecorder> { Result.success(Unit) } + val pushHistoryService = FakePushHistoryService( + enqueuePushRequest = enqueuePushRequestResult, + ) + val submitWorkLambda = lambdaRecorder {} + val workManagerScheduler = FakeWorkManagerScheduler(submitLambda = submitWorkLambda) + val defaultPushHandler = createDefaultPushHandler( - onNotifiableEventsReceived = onNotifiableEventsReceived, - notifiableEventsResult = notifiableEventResult, pushClientSecret = FakePushClientSecret( getUserIdFromSecretResult = { A_USER_ID } ), incrementPushCounterResult = incrementPushCounterResult, + workManagerScheduler = workManagerScheduler, pushHistoryService = pushHistoryService, ) defaultPushHandler.handle(aPushData, A_PUSHER_INFO) advanceTimeBy(300.milliseconds) - incrementPushCounterResult.assertions() + submitWorkLambda.assertions() .isCalledOnce() - notifiableEventResult.assertions() - .isCalledOnce() - .with(value(A_USER_ID), any()) - onNotifiableEventsReceived.assertions() - .isCalledOnce() - .with(value(listOf(aNotifiableMessageEvent))) - onPushReceivedResult.assertions() - .isCalledOnce() - } - - @Test - fun `when classical PushData is received and the workmanager flag is enabled, the work is scheduled`() = runTest { - val aNotifiableMessageEvent = aNotifiableMessageEvent() - val notifiableEventResult = - lambdaRecorder, Result>>> { _, _ -> - val request = NotificationEventRequest(A_SESSION_ID, A_ROOM_ID, AN_EVENT_ID, A_PUSHER_INFO) - Result.success(mapOf(request to Result.success(ResolvedPushEvent.Event(aNotifiableMessageEvent)))) - } - val incrementPushCounterResult = lambdaRecorder {} - val aPushData = PushData( - eventId = AN_EVENT_ID, - roomId = A_ROOM_ID, - unread = 0, - clientSecret = A_SECRET, - ) - - val featureFlagService = FakeFeatureFlagService(mapOf(FeatureFlags.SyncNotificationsWithWorkManager.key to true)) - val submitWorkLambda = lambdaRecorder {} - val workManagerScheduler = FakeWorkManagerScheduler(submitLambda = submitWorkLambda) - - val defaultPushHandler = createDefaultPushHandler( - notifiableEventsResult = notifiableEventResult, - pushClientSecret = FakePushClientSecret( - getUserIdFromSecretResult = { A_USER_ID } - ), - incrementPushCounterResult = incrementPushCounterResult, - featureFlagService = featureFlagService, - workManagerScheduler = workManagerScheduler, - ) - defaultPushHandler.handle(aPushData, A_PUSHER_INFO) - - advanceTimeBy(300.milliseconds) - - submitWorkLambda.assertions().isCalledOnce() incrementPushCounterResult.assertions() .isCalledOnce() @@ -182,13 +107,6 @@ class DefaultPushHandlerTest { @Test fun `when classical PushData is received, but notifications are disabled, nothing happen`() = runTest { - val aNotifiableMessageEvent = aNotifiableMessageEvent() - val notifiableEventResult = - lambdaRecorder, Result>>> { _, _ -> - val request = NotificationEventRequest(A_SESSION_ID, A_ROOM_ID, AN_EVENT_ID, A_PUSHER_INFO) - Result.success(mapOf(request to Result.success(ResolvedPushEvent.Event(aNotifiableMessageEvent)))) - } - val onNotifiableEventsReceived = lambdaRecorder, Unit> {} val incrementPushCounterResult = lambdaRecorder {} val aPushData = PushData( eventId = AN_EVENT_ID, @@ -197,12 +115,15 @@ class DefaultPushHandlerTest { clientSecret = A_SECRET, ) val onPushReceivedResult = lambdaRecorder { _, _, _, _, _, _, _ -> } + val enqueuePushRequestResult = lambdaRecorder> { Result.success(Unit) } val pushHistoryService = FakePushHistoryService( onPushReceivedResult = onPushReceivedResult, + enqueuePushRequest = enqueuePushRequestResult, ) + val submitWorkLambda = lambdaRecorder {} + val workManagerScheduler = FakeWorkManagerScheduler(submitLambda = submitWorkLambda) + val defaultPushHandler = createDefaultPushHandler( - onNotifiableEventsReceived = onNotifiableEventsReceived, - notifiableEventsResult = notifiableEventResult, pushClientSecret = FakePushClientSecret( getUserIdFromSecretResult = { A_USER_ID } ), @@ -211,31 +132,24 @@ class DefaultPushHandlerTest { }, incrementPushCounterResult = incrementPushCounterResult, pushHistoryService = pushHistoryService, + workManagerScheduler = workManagerScheduler, ) defaultPushHandler.handle(aPushData, A_PUSHER_INFO) advanceTimeBy(300.milliseconds) + submitWorkLambda.assertions() + .isNeverCalled() + enqueuePushRequestResult.assertions() + .isNeverCalled() incrementPushCounterResult.assertions() .isCalledOnce() - notifiableEventResult.assertions() - .isCalledOnce() - onNotifiableEventsReceived.assertions() - .isNeverCalled() onPushReceivedResult.assertions() - .isCalledOnce() + .isNeverCalled() } @Test - fun `when PushData is received, but client secret is not known, nothing happen`() = - runTest { - val aNotifiableMessageEvent = aNotifiableMessageEvent() - val notifiableEventResult = - lambdaRecorder, Result>>> { _, _ -> - val request = NotificationEventRequest(A_SESSION_ID, A_ROOM_ID, AN_EVENT_ID, A_PUSHER_INFO) - Result.success(mapOf(request to Result.success(ResolvedPushEvent.Event(aNotifiableMessageEvent)))) - } - val onNotifiableEventsReceived = lambdaRecorder, Unit> {} + fun `when PushData is received, but client secret is not known, nothing happen`() = runTest { val incrementPushCounterResult = lambdaRecorder {} val aPushData = PushData( eventId = AN_EVENT_ID, @@ -247,477 +161,85 @@ class DefaultPushHandlerTest { val pushHistoryService = FakePushHistoryService( onPushReceivedResult = onPushReceivedResult, ) + val submitWorkLambda = lambdaRecorder {} + val workManagerScheduler = FakeWorkManagerScheduler(submitLambda = submitWorkLambda) val defaultPushHandler = createDefaultPushHandler( - onNotifiableEventsReceived = onNotifiableEventsReceived, - notifiableEventsResult = notifiableEventResult, pushClientSecret = FakePushClientSecret( getUserIdFromSecretResult = { null } ), incrementPushCounterResult = incrementPushCounterResult, pushHistoryService = pushHistoryService, + workManagerScheduler = workManagerScheduler, ) defaultPushHandler.handle(aPushData, A_PUSHER_INFO) + submitWorkLambda.assertions() + .isNeverCalled() incrementPushCounterResult.assertions() .isCalledOnce() - notifiableEventResult.assertions() - .isNeverCalled() - onNotifiableEventsReceived.assertions() - .isNeverCalled() onPushReceivedResult.assertions() .isCalledOnce() } @Test - fun `when classical PushData is received, but a failure occurs (session not found), nothing happen`() { - `test notification resolver failure`( - notificationResolveResult = { _ -> - Result.failure(NotificationResolverException.UnknownError("Unable to restore session")) - }, - shouldSetOptimizationBatteryBanner = false, + fun `when diagnostic PushData is received, the diagnostic push handler is informed`() = runTest { + val aPushData = PushData( + eventId = DefaultTestPush.TEST_EVENT_ID, + roomId = A_ROOM_ID, + unread = 0, + clientSecret = A_SECRET, ) - } - - @Test - fun `when classical PushData is received, but not able to resolve the event, the banner to disable battery optimization will be displayed`() { - `test notification resolver failure`( - notificationResolveResult = { requests: List -> - Result.success( - requests.associateWith { Result.failure(NotificationResolverException.UnknownError("Unable to resolve event")) } - ) - }, - shouldSetOptimizationBatteryBanner = true, + val diagnosticPushHandler = DiagnosticPushHandler() + val onPushReceivedResult = lambdaRecorder { _, _, _, _, _, _, _ -> } + val pushHistoryService = FakePushHistoryService( + onPushReceivedResult = onPushReceivedResult, ) - } - - private fun `test notification resolver failure`( - notificationResolveResult: (List) -> Result>>, - shouldSetOptimizationBatteryBanner: Boolean, - ) { - runTest { - val notifiableEventResult = - lambdaRecorder, Result>>> { _, requests -> - notificationResolveResult(requests) - } - val onNotifiableEventsReceived = lambdaRecorder, Unit> {} - val incrementPushCounterResult = lambdaRecorder {} - val aPushData = PushData( - eventId = AN_EVENT_ID, - roomId = A_ROOM_ID, - unread = 0, - clientSecret = A_SECRET, - ) - val onPushReceivedResult = lambdaRecorder { _, _, _, _, _, _, _ -> } - val pushHistoryService = FakePushHistoryService( - onPushReceivedResult = onPushReceivedResult, - ) - val showBatteryOptimizationBannerResult = lambdaRecorder {} - val defaultPushHandler = createDefaultPushHandler( - onNotifiableEventsReceived = onNotifiableEventsReceived, - notifiableEventsResult = notifiableEventResult, - buildMeta = aBuildMeta( - // Also test `lowPrivacyLoggingEnabled = false` here - lowPrivacyLoggingEnabled = false - ), - pushClientSecret = FakePushClientSecret( - getUserIdFromSecretResult = { A_USER_ID } - ), - incrementPushCounterResult = incrementPushCounterResult, - mutableBatteryOptimizationStore = FakeMutableBatteryOptimizationStore( - showBatteryOptimizationBannerResult = showBatteryOptimizationBannerResult, - ), - pushHistoryService = pushHistoryService, - ) + val defaultPushHandler = createDefaultPushHandler( + diagnosticPushHandler = diagnosticPushHandler, + incrementPushCounterResult = { }, + pushHistoryService = pushHistoryService, + ) + diagnosticPushHandler.state.test { defaultPushHandler.handle(aPushData, A_PUSHER_INFO) - - advanceTimeBy(300.milliseconds) - - incrementPushCounterResult.assertions() - .isCalledOnce() - notifiableEventResult.assertions() - .isCalledOnce() - .with(value(A_USER_ID), any()) - onPushReceivedResult.assertions() - .isCalledOnce() - .with(any(), value(AN_EVENT_ID), value(A_ROOM_ID), value(A_USER_ID), value(false), value(true), any()) - showBatteryOptimizationBannerResult.assertions().let { - if (shouldSetOptimizationBatteryBanner) { - it.isCalledOnce() - } else { - it.isNeverCalled() - } - } + awaitItem() } - } - - @Test - fun `when ringing call PushData is received, the incoming call will be handled`() = runTest { - val aPushData = PushData( - eventId = AN_EVENT_ID, - roomId = A_ROOM_ID, - unread = 0, - clientSecret = A_SECRET, - ) - val handleIncomingCallLambda = lambdaRecorder< - CallType.RoomCall, - EventId, - UserId, - String?, - String?, - String?, - String, - String?, - Unit, - > { _, _, _, _, _, _, _, _ -> } - val elementCallEntryPoint = FakeElementCallEntryPoint(handleIncomingCallResult = handleIncomingCallLambda) - val onNotifiableEventsReceived = lambdaRecorder, Unit> {} - val onPushReceivedResult = lambdaRecorder { _, _, _, _, _, _, _ -> } - val pushHistoryService = FakePushHistoryService( - onPushReceivedResult = onPushReceivedResult, - ) - val defaultPushHandler = createDefaultPushHandler( - elementCallEntryPoint = elementCallEntryPoint, - notifiableEventsResult = { _, _ -> - val request = NotificationEventRequest(A_SESSION_ID, A_ROOM_ID, AN_EVENT_ID, A_PUSHER_INFO) - Result.success( - mapOf( - request to Result.success( - ResolvedPushEvent.Event( - aNotifiableCallEvent(rtcNotificationType = RtcNotificationType.RING, timestamp = Instant.now().toEpochMilli()) - ) - ) - ) - ) - }, - incrementPushCounterResult = {}, - pushClientSecret = FakePushClientSecret( - getUserIdFromSecretResult = { A_USER_ID } - ), - onNotifiableEventsReceived = onNotifiableEventsReceived, - pushHistoryService = pushHistoryService, - ) - defaultPushHandler.handle(aPushData, A_PUSHER_INFO) - - advanceTimeBy(300.milliseconds) - - handleIncomingCallLambda.assertions().isCalledOnce() - onNotifiableEventsReceived.assertions().isNeverCalled() - onPushReceivedResult.assertions().isCalledOnce() - } - - @Test - fun `when notify call PushData is received, the incoming call will be treated as a normal notification`() = runTest { - val aPushData = PushData( - eventId = AN_EVENT_ID, - roomId = A_ROOM_ID, - unread = 0, - clientSecret = A_SECRET, - ) - val onNotifiableEventsReceived = lambdaRecorder, Unit> {} - val handleIncomingCallLambda = lambdaRecorder< - CallType.RoomCall, - EventId, - UserId, - String?, - String?, - String?, - String, - String?, - Unit, - > { _, _, _, _, _, _, _, _ -> } - val elementCallEntryPoint = FakeElementCallEntryPoint(handleIncomingCallResult = handleIncomingCallLambda) - val onPushReceivedResult = lambdaRecorder { _, _, _, _, _, _, _ -> } - val pushHistoryService = FakePushHistoryService( - onPushReceivedResult = onPushReceivedResult, - ) - val defaultPushHandler = createDefaultPushHandler( - elementCallEntryPoint = elementCallEntryPoint, - onNotifiableEventsReceived = onNotifiableEventsReceived, - notifiableEventsResult = { _, _ -> - val request = NotificationEventRequest(A_SESSION_ID, A_ROOM_ID, AN_EVENT_ID, A_PUSHER_INFO) - Result.success(mapOf(request to Result.success(ResolvedPushEvent.Event(aNotifiableMessageEvent(type = EventType.RTC_NOTIFICATION))))) - }, - incrementPushCounterResult = {}, - pushClientSecret = FakePushClientSecret( - getUserIdFromSecretResult = { A_USER_ID } - ), - pushHistoryService = pushHistoryService, - ) - defaultPushHandler.handle(aPushData, A_PUSHER_INFO) - - advanceTimeBy(300.milliseconds) - - handleIncomingCallLambda.assertions().isNeverCalled() - onNotifiableEventsReceived.assertions().isCalledOnce() - onPushReceivedResult.assertions().isCalledOnce() - } - - @Test - fun `when notify call PushData is received, the incoming call will be treated as a normal notification even if notification are disabled`() = runTest { - val aPushData = PushData( - eventId = AN_EVENT_ID, - roomId = A_ROOM_ID, - unread = 0, - clientSecret = A_SECRET, - ) - val onNotifiableEventsReceived = lambdaRecorder, Unit> {} - val handleIncomingCallLambda = lambdaRecorder< - CallType.RoomCall, - EventId, - UserId, - String?, - String?, - String?, - String, - String?, - Unit, - > { _, _, _, _, _, _, _, _ -> } - val elementCallEntryPoint = FakeElementCallEntryPoint(handleIncomingCallResult = handleIncomingCallLambda) - val onPushReceivedResult = lambdaRecorder { _, _, _, _, _, _, _ -> } - val pushHistoryService = FakePushHistoryService( - onPushReceivedResult = onPushReceivedResult, - ) - val defaultPushHandler = createDefaultPushHandler( - elementCallEntryPoint = elementCallEntryPoint, - onNotifiableEventsReceived = onNotifiableEventsReceived, - notifiableEventsResult = { _, _ -> - val request = NotificationEventRequest(A_SESSION_ID, A_ROOM_ID, AN_EVENT_ID, A_PUSHER_INFO) - Result.success(mapOf(request to Result.success(ResolvedPushEvent.Event(aNotifiableCallEvent())))) - }, - incrementPushCounterResult = {}, - userPushStore = FakeUserPushStore().apply { - setNotificationEnabledForDevice(false) - }, - pushClientSecret = FakePushClientSecret( - getUserIdFromSecretResult = { A_USER_ID } - ), - pushHistoryService = pushHistoryService, - ) - defaultPushHandler.handle(aPushData, A_PUSHER_INFO) - - advanceTimeBy(300.milliseconds) - - handleIncomingCallLambda.assertions().isCalledOnce() - onNotifiableEventsReceived.assertions().isNeverCalled() - onPushReceivedResult.assertions().isCalledOnce() - } - - @Test - fun `when a redaction is received, the onRedactedEventReceived is informed`() = runTest { - val aPushData = PushData( - eventId = AN_EVENT_ID, - roomId = A_ROOM_ID, - unread = 0, - clientSecret = A_SECRET, - ) - val aRedaction = ResolvedPushEvent.Redaction( - sessionId = A_SESSION_ID, - roomId = A_ROOM_ID, - redactedEventId = AN_EVENT_ID_2, - reason = null - ) - val onRedactedEventReceived = lambdaRecorder, Unit> { } - val incrementPushCounterResult = lambdaRecorder {} - val onPushReceivedResult = lambdaRecorder { _, _, _, _, _, _, _ -> } - val pushHistoryService = FakePushHistoryService( - onPushReceivedResult = onPushReceivedResult, - ) - val defaultPushHandler = createDefaultPushHandler( - onRedactedEventsReceived = onRedactedEventReceived, - incrementPushCounterResult = incrementPushCounterResult, - notifiableEventsResult = { _, _ -> - val request = NotificationEventRequest(A_SESSION_ID, A_ROOM_ID, AN_EVENT_ID, A_PUSHER_INFO) - Result.success(mapOf(request to Result.success(aRedaction))) - }, - pushClientSecret = FakePushClientSecret( - getUserIdFromSecretResult = { A_USER_ID } - ), - pushHistoryService = pushHistoryService, - ) - defaultPushHandler.handle(aPushData, A_PUSHER_INFO) - - advanceTimeBy(300.milliseconds) - - incrementPushCounterResult.assertions() - .isCalledOnce() - onRedactedEventReceived.assertions().isCalledOnce() - .with(value(listOf(aRedaction))) onPushReceivedResult.assertions() .isCalledOnce() } - @Test - fun `when diagnostic PushData is received, the diagnostic push handler is informed`() = - runTest { - val aPushData = PushData( - eventId = DefaultTestPush.TEST_EVENT_ID, - roomId = A_ROOM_ID, - unread = 0, - clientSecret = A_SECRET, - ) - val diagnosticPushHandler = DiagnosticPushHandler() - val onPushReceivedResult = lambdaRecorder { _, _, _, _, _, _, _ -> } - val pushHistoryService = FakePushHistoryService( - onPushReceivedResult = onPushReceivedResult, - ) - val defaultPushHandler = createDefaultPushHandler( - diagnosticPushHandler = diagnosticPushHandler, - incrementPushCounterResult = { }, - pushHistoryService = pushHistoryService, - ) - diagnosticPushHandler.state.test { - defaultPushHandler.handle(aPushData, A_PUSHER_INFO) - awaitItem() - } - onPushReceivedResult.assertions() - .isCalledOnce() - } - - @Test - fun `when receiving several push notifications at the same time, those are batched before being processed`() = runTest { - val aNotifiableMessageEvent = aNotifiableMessageEvent() - val notifiableEventResult = - lambdaRecorder, Result>>> { _, _ -> - val request = NotificationEventRequest(A_SESSION_ID, A_ROOM_ID, AN_EVENT_ID, A_PUSHER_INFO) - Result.success(mapOf(request to Result.success(ResolvedPushEvent.Event(aNotifiableMessageEvent)))) - } - val onNotifiableEventsReceived = lambdaRecorder, Unit> {} - val incrementPushCounterResult = lambdaRecorder {} - val onPushReceivedResult = lambdaRecorder { _, _, _, _, _, _, _ -> } - val pushHistoryService = FakePushHistoryService( - onPushReceivedResult = onPushReceivedResult, - ) - val aPushData = PushData( - eventId = AN_EVENT_ID, - roomId = A_ROOM_ID, - unread = 0, - clientSecret = A_SECRET, - ) - val anotherPushData = PushData( - eventId = AN_EVENT_ID_2, - roomId = A_ROOM_ID, - unread = 0, - clientSecret = A_SECRET, - ) - val defaultPushHandler = createDefaultPushHandler( - onNotifiableEventsReceived = onNotifiableEventsReceived, - notifiableEventsResult = notifiableEventResult, - pushClientSecret = FakePushClientSecret( - getUserIdFromSecretResult = { A_USER_ID } - ), - incrementPushCounterResult = incrementPushCounterResult, - pushHistoryService = pushHistoryService, - ) - defaultPushHandler.handle(aPushData, A_PUSHER_INFO) - defaultPushHandler.handle(anotherPushData, A_PUSHER_INFO) - - advanceTimeBy(300.milliseconds) - - incrementPushCounterResult.assertions() - .isCalledExactly(2) - notifiableEventResult.assertions() - .isCalledOnce() - .with(value(A_USER_ID), matching> { requests -> - requests.size == 2 && requests.first().eventId == AN_EVENT_ID && requests.last().eventId == AN_EVENT_ID_2 - }) - onNotifiableEventsReceived.assertions() - .isCalledOnce() - onPushReceivedResult.assertions() - .isCalledExactly(2) - } - - @Test - fun `when receiving a fallback event, we notify the push history service about it not being resolved`() = runTest { - val aNotifiableFallbackEvent = aFallbackNotifiableEvent() - val notifiableEventResult = - lambdaRecorder, Result>>> { _, _ -> - val request = NotificationEventRequest(A_SESSION_ID, A_ROOM_ID, AN_EVENT_ID, A_PUSHER_INFO) - Result.success(mapOf(request to Result.success(ResolvedPushEvent.Event(aNotifiableFallbackEvent)))) - } - val onNotifiableEventsReceived = lambdaRecorder, Unit> {} - val incrementPushCounterResult = lambdaRecorder {} - var receivedFallbackEvent = false - val onPushReceivedResult = - lambdaRecorder { _, _, _, _, isResolved, _, comment -> - receivedFallbackEvent = !isResolved && comment == "Unable to resolve event: ${aNotifiableFallbackEvent.cause}" - } - val pushHistoryService = FakePushHistoryService( - onPushReceivedResult = onPushReceivedResult, - ) - val aPushData = PushData( - eventId = AN_EVENT_ID, - roomId = A_ROOM_ID, - unread = 0, - clientSecret = A_SECRET, - ) - val defaultPushHandler = createDefaultPushHandler( - onNotifiableEventsReceived = onNotifiableEventsReceived, - notifiableEventsResult = notifiableEventResult, - pushClientSecret = FakePushClientSecret( - getUserIdFromSecretResult = { A_USER_ID } - ), - incrementPushCounterResult = incrementPushCounterResult, - pushHistoryService = pushHistoryService, - ) - defaultPushHandler.handle(aPushData, A_PUSHER_INFO) - - advanceTimeBy(300.milliseconds) - - onNotifiableEventsReceived.assertions().isCalledOnce() - - assertThat(receivedFallbackEvent).isTrue() - } - - private fun TestScope.createDefaultPushHandler( - onNotifiableEventsReceived: (List) -> Unit = { lambdaError() }, - onRedactedEventsReceived: (List) -> Unit = { lambdaError() }, - notifiableEventsResult: (SessionId, List) -> Result>> = - { _, _ -> lambdaError() }, + private fun createDefaultPushHandler( incrementPushCounterResult: () -> Unit = { lambdaError() }, - mutableBatteryOptimizationStore: MutableBatteryOptimizationStore = FakeMutableBatteryOptimizationStore(), - userPushStore: UserPushStore = FakeUserPushStore(), + userPushStore: FakeUserPushStore = FakeUserPushStore(), pushClientSecret: PushClientSecret = FakePushClientSecret(), buildMeta: BuildMeta = aBuildMeta(), diagnosticPushHandler: DiagnosticPushHandler = DiagnosticPushHandler(), - elementCallEntryPoint: FakeElementCallEntryPoint = FakeElementCallEntryPoint(), - notificationChannels: FakeNotificationChannels = FakeNotificationChannels(), pushHistoryService: PushHistoryService = FakePushHistoryService(), - syncOnNotifiableEvent: SyncOnNotifiableEvent = SyncOnNotifiableEvent {}, - featureFlagService: FakeFeatureFlagService = FakeFeatureFlagService(initialState = mapOf(FeatureFlags.SyncNotificationsWithWorkManager.key to false)), workManagerScheduler: FakeWorkManagerScheduler = FakeWorkManagerScheduler(), analyticsService: FakeAnalyticsService = FakeAnalyticsService(), + systemClock: FakeSystemClock = FakeSystemClock(), + buildVersionSdkIntProvider: FakeBuildVersionSdkIntProvider = FakeBuildVersionSdkIntProvider(33), + resultProcessor: FakeNotificationResultProcessor = FakeNotificationResultProcessor( + emit = { Result.success(Unit) }, + start = {}, + stop = {}, + ), ): DefaultPushHandler { return DefaultPushHandler( - onNotifiableEventReceived = FakeOnNotifiableEventReceived(onNotifiableEventsReceived), - onRedactedEventReceived = FakeOnRedactedEventReceived(onRedactedEventsReceived), incrementPushDataStore = object : IncrementPushDataStore { override suspend fun incrementPushCounter() { incrementPushCounterResult() } }, - mutableBatteryOptimizationStore = mutableBatteryOptimizationStore, userPushStoreFactory = FakeUserPushStoreFactory { userPushStore }, pushClientSecret = pushClientSecret, buildMeta = buildMeta, diagnosticPushHandler = diagnosticPushHandler, - elementCallEntryPoint = elementCallEntryPoint, - notificationChannels = notificationChannels, pushHistoryService = pushHistoryService, // We don't use a fake here so we can perform tests that are a bit more end to end - resolverQueue = DefaultNotificationResolverQueue( - notifiableEventResolver = FakeNotifiableEventResolver(notifiableEventsResult), - appCoroutineScope = backgroundScope, - workManagerScheduler = workManagerScheduler, - featureFlagService = featureFlagService, - workerDataConverter = SyncNotificationsWorkerDataConverter(DefaultJsonProvider()), - buildVersionSdkIntProvider = FakeBuildVersionSdkIntProvider(33), - ), - appCoroutineScope = backgroundScope, - fallbackNotificationFactory = FallbackNotificationFactory( - clock = FakeSystemClock(), - ), - syncOnNotifiableEvent = syncOnNotifiableEvent, - featureFlagService = featureFlagService, analyticsService = analyticsService, + systemClock = systemClock, + workManagerScheduler = workManagerScheduler, + buildVersionSdkIntProvider = buildVersionSdkIntProvider, + resultProcessor = resultProcessor, ) } } 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 index 6c88e7bf12..0032e95029 100644 --- 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 @@ -20,8 +20,7 @@ import io.element.android.libraries.matrix.test.FakeMatrixClientProvider import io.element.android.libraries.matrix.test.room.FakeBaseRoom import io.element.android.libraries.matrix.test.room.FakeJoinedRoom import io.element.android.libraries.matrix.test.sync.FakeSyncService -import io.element.android.libraries.push.api.push.SyncOnNotifiableEvent -import io.element.android.libraries.push.impl.notifications.fixtures.aNotificationEventRequest +import io.element.android.libraries.push.impl.notifications.fixtures.aPushRequest import io.element.android.services.appnavstate.test.FakeAppForegroundStateService import io.element.android.tests.testutils.lambda.assert import io.element.android.tests.testutils.lambda.lambdaRecorder @@ -53,7 +52,7 @@ class SyncOnNotifiableEventTest { givenGetRoomResult(A_ROOM_ID, room) } - private val notificationRequest = aNotificationEventRequest() + private val notificationRequest = aPushRequest() @Test fun `when feature flag is disabled, nothing happens`() = runTest { diff --git a/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/workmanager/FetchNotificationWorkerTest.kt b/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/workmanager/FetchNotificationWorkerTest.kt deleted file mode 100644 index 99451027a8..0000000000 --- a/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/workmanager/FetchNotificationWorkerTest.kt +++ /dev/null @@ -1,210 +0,0 @@ -/* - * Copyright (c) 2025 Element Creations Ltd. - * Copyright 2025 New Vector Ltd. - * - * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial. - * Please see LICENSE files in the repository root for full details. - */ - -package io.element.android.libraries.push.impl.workmanager - -import androidx.test.ext.junit.runners.AndroidJUnit4 -import androidx.test.platform.app.InstrumentationRegistry -import androidx.work.Data -import androidx.work.ListenableWorker -import androidx.work.WorkerParameters -import androidx.work.impl.utils.taskexecutor.WorkManagerTaskExecutor -import androidx.work.workDataOf -import com.google.common.truth.Truth.assertThat -import com.google.common.util.concurrent.ListenableFuture -import io.element.android.features.networkmonitor.api.NetworkStatus -import io.element.android.features.networkmonitor.test.FakeNetworkMonitor -import io.element.android.libraries.androidutils.json.DefaultJsonProvider -import io.element.android.libraries.push.api.push.SyncOnNotifiableEvent -import io.element.android.libraries.push.impl.notifications.FakeNotifiableEventResolver -import io.element.android.libraries.push.impl.notifications.NotificationResolverQueue -import io.element.android.libraries.push.impl.notifications.fixtures.aNotifiableMessageEvent -import io.element.android.libraries.push.impl.notifications.model.ResolvedPushEvent -import io.element.android.libraries.push.test.notifications.FakeNotificationResolverQueue -import io.element.android.libraries.workmanager.api.WorkManagerRequest -import io.element.android.libraries.workmanager.api.di.MetroWorkerFactory -import io.element.android.libraries.workmanager.test.FakeWorkManagerScheduler -import io.element.android.services.analytics.test.FakeAnalyticsService -import io.element.android.services.toolbox.test.sdk.FakeBuildVersionSdkIntProvider -import io.element.android.tests.testutils.lambda.lambdaRecorder -import kotlinx.coroutines.ExperimentalCoroutinesApi -import kotlinx.coroutines.test.TestScope -import kotlinx.coroutines.test.advanceTimeBy -import kotlinx.coroutines.test.runTest -import org.junit.Test -import org.junit.runner.RunWith -import java.util.UUID -import java.util.concurrent.Executor -import java.util.concurrent.Executors -import java.util.concurrent.TimeUnit -import kotlin.time.Duration.Companion.seconds - -@OptIn(ExperimentalCoroutinesApi::class) -@RunWith(AndroidJUnit4::class) -class FetchNotificationWorkerTest { - @Test - fun `test - success`() = runTest { - var synced = false - val syncOnNotifiableEventLambda = SyncOnNotifiableEvent { synced = true } - - val queue = FakeNotificationResolverQueue( - processingLambda = { Result.success(ResolvedPushEvent.Event(aNotifiableMessageEvent())) } - ) - val worker = createWorker( - input = """ - [ - { - "session_id": "@alice:matrix.org", - "room_id": "!roomid:matrix.org", - "event_id": "$1436ebk:matrix.org", - "provider_info": "some_info" - } - ] - """.trimIndent(), - queue = queue, - syncOnNotifiableEvent = syncOnNotifiableEventLambda, - ) - - val result = worker.doWork() - - // The process finished successfully - assertThat(result).isEqualTo(ListenableWorker.Result.success()) - - // A result was emitted - assertThat(queue.results.replayCache).isNotEmpty() - - // An opportunistic sync was triggered - assertThat(synced).isTrue() - } - - @Test - fun `test - invalid input fails the work`() = runTest { - val worker = createWorker( - input = """ - [ - { - "session_id": "!alice:matrix.org", - "room_id": "!roomid:matrix.org", - "event_id": "$1436ebk:matrix.org", - "provider_info": "some_info" - } - ] - """.trimIndent(), - ) - - val result = worker.doWork() - - // The process failed - assertThat(result).isEqualTo(ListenableWorker.Result.failure()) - } - - @Test - fun `test - no network connectivity fails the work`() = runTest { - val networkMonitor = FakeNetworkMonitor(initialStatus = NetworkStatus.Disconnected) - val worker = createWorker( - input = """ - [ - { - "session_id": "@alice:matrix.org", - "room_id": "!roomid:matrix.org", - "event_id": "$1436ebk:matrix.org", - "provider_info": "some_info" - } - ] - """.trimIndent(), - networkMonitor = networkMonitor, - ) - - val result = worker.doWork() - - advanceTimeBy(10.seconds) - - // The process failed due to a timeout in getting the network connectivity, a retry is scheduled - assertThat(result).isEqualTo(ListenableWorker.Result.retry()) - } - - @Test - fun `test - failing to resolve events re-schedules the work`() = runTest { - val submitWorkerLambda = lambdaRecorder {} - val scheduler = FakeWorkManagerScheduler(submitLambda = submitWorkerLambda) - - val resolver = FakeNotifiableEventResolver( - resolveEventsResult = { _, _ -> Result.failure(Exception("Failed to resolve events")) } - ) - - val worker = createWorker( - input = """ - [ - { - "session_id": "@alice:matrix.org", - "room_id": "!roomid:matrix.org", - "event_id": "$1436ebk:matrix.org", - "provider_info": "some_info" - } - ] - """.trimIndent(), - eventResolver = resolver, - workManagerScheduler = scheduler, - ) - - val result = worker.doWork() - - // The process was considered successful, but a retry was scheduled due to the failure to resolve events - assertThat(result).isEqualTo(ListenableWorker.Result.success()) - submitWorkerLambda.assertions().isCalledOnce() - } - - private fun TestScope.createWorker( - input: String, - networkMonitor: FakeNetworkMonitor = FakeNetworkMonitor(), - eventResolver: FakeNotifiableEventResolver = FakeNotifiableEventResolver(resolveEventsResult = { _, _ -> Result.success(emptyMap()) }), - queue: NotificationResolverQueue = FakeNotificationResolverQueue( - processingLambda = { Result.success(ResolvedPushEvent.Event(aNotifiableMessageEvent())) } - ), - workManagerScheduler: FakeWorkManagerScheduler = FakeWorkManagerScheduler(), - syncOnNotifiableEvent: SyncOnNotifiableEvent = SyncOnNotifiableEvent {}, - analyticsService: FakeAnalyticsService = FakeAnalyticsService(), - ) = FetchNotificationsWorker( - params = createWorkerParams(workDataOf("requests" to input)), - context = InstrumentationRegistry.getInstrumentation().context, - networkMonitor = networkMonitor, - eventResolver = eventResolver, - queue = queue, - workManagerScheduler = workManagerScheduler, - syncOnNotifiableEvent = syncOnNotifiableEvent, - workerDataConverter = SyncNotificationsWorkerDataConverter(DefaultJsonProvider()), - buildVersionSdkIntProvider = FakeBuildVersionSdkIntProvider(33), - analyticsService = analyticsService, - ) - - private fun TestScope.createWorkerParams( - inputData: Data = Data.EMPTY, - ): WorkerParameters = WorkerParameters( - UUID.randomUUID(), - inputData, - emptySet(), - WorkerParameters.RuntimeExtras(), - 0, - 0, - Executors.newSingleThreadExecutor(), - backgroundScope.coroutineContext, - WorkManagerTaskExecutor(Executors.newSingleThreadExecutor()), - MetroWorkerFactory(emptyMap()), - { context, id, data -> FakeListenableFuture() }, - { context, id, foregroundInfo -> FakeListenableFuture() }, - ) -} - -class FakeListenableFuture : ListenableFuture { - override fun addListener(listener: Runnable, executor: Executor) = Unit - override fun cancel(mayInterruptIfRunning: Boolean): Boolean = true - override fun get(): T? = null - override fun get(timeout: Long, unit: TimeUnit?): T? = null - override fun isCancelled(): Boolean = false - override fun isDone(): Boolean = false -} diff --git a/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/workmanager/FetchPendingNotificationWorkerTest.kt b/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/workmanager/FetchPendingNotificationWorkerTest.kt new file mode 100644 index 0000000000..b39c3d3f05 --- /dev/null +++ b/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/workmanager/FetchPendingNotificationWorkerTest.kt @@ -0,0 +1,278 @@ +/* + * Copyright (c) 2025 Element Creations Ltd. + * Copyright 2025 New Vector Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial. + * Please see LICENSE files in the repository root for full details. + */ + +package io.element.android.libraries.push.impl.workmanager + +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.platform.app.InstrumentationRegistry +import androidx.work.Data +import androidx.work.ListenableWorker +import androidx.work.WorkerParameters +import androidx.work.impl.utils.taskexecutor.WorkManagerTaskExecutor +import androidx.work.workDataOf +import com.google.common.truth.Truth.assertThat +import com.google.common.util.concurrent.ListenableFuture +import io.element.android.features.networkmonitor.api.NetworkStatus +import io.element.android.features.networkmonitor.test.FakeNetworkMonitor +import io.element.android.libraries.matrix.api.core.SessionId +import io.element.android.libraries.matrix.api.exception.ClientException +import io.element.android.libraries.push.impl.db.PushRequest +import io.element.android.libraries.push.impl.history.FakePushHistoryService +import io.element.android.libraries.push.impl.notifications.FakeNotifiableEventResolver +import io.element.android.libraries.push.impl.notifications.FakeNotificationResultProcessor +import io.element.android.libraries.push.impl.notifications.fixtures.aPushRequest +import io.element.android.libraries.push.impl.notifications.model.ResolvedPushEvent +import io.element.android.libraries.push.impl.push.SyncOnNotifiableEvent +import io.element.android.libraries.workmanager.api.WorkManagerRequestBuilder +import io.element.android.libraries.workmanager.api.di.MetroWorkerFactory +import io.element.android.services.analytics.test.FakeAnalyticsService +import io.element.android.services.toolbox.test.systemclock.FakeSystemClock +import io.element.android.tests.testutils.lambda.lambdaRecorder +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.test.TestScope +import kotlinx.coroutines.test.advanceTimeBy +import kotlinx.coroutines.test.runTest +import org.junit.Test +import org.junit.runner.RunWith +import java.util.UUID +import java.util.concurrent.Executor +import java.util.concurrent.Executors +import java.util.concurrent.TimeUnit +import kotlin.time.Duration.Companion.seconds +import kotlin.time.Instant + +@OptIn(ExperimentalCoroutinesApi::class) +@RunWith(AndroidJUnit4::class) +class FetchPendingNotificationWorkerTest { + @Test + fun `test - success`() = runTest { + var synced = false + val syncOnNotifiableEventLambda = SyncOnNotifiableEvent { synced = true } + val emitResultLambda = lambdaRecorder>, Unit> {} + val processor = FakeNotificationResultProcessor(emit = emitResultLambda) + + val getPendingResultsLambda = lambdaRecorder>> { _, _ -> Result.success(listOf(aPushRequest())) } + val replacePushRequestsLambda = lambdaRecorder, Result> { Result.success(Unit) } + val removeOldPushRequestsLambda = lambdaRecorder> { Result.success(Unit) } + val pushHistoryService = FakePushHistoryService( + getPendingPushRequests = getPendingResultsLambda, + replacePushRequests = replacePushRequestsLambda, + removeOldPushRequests = removeOldPushRequestsLambda, + ) + + val worker = createWorker( + input = "@alice:matrix.org", + pushHistoryService = pushHistoryService, + resultProcessor = processor, + syncOnNotifiableEvent = syncOnNotifiableEventLambda, + ) + + val result = worker.doWork() + + // The expected data is fetched and replaced from the service + getPendingResultsLambda.assertions().isCalledOnce() + replacePushRequestsLambda.assertions().isCalledOnce() + removeOldPushRequestsLambda.assertions().isCalledOnce() + + // The process finished successfully + assertThat(result).isEqualTo(ListenableWorker.Result.success()) + + // A result was emitted + emitResultLambda.assertions().isCalledOnce() + + // An opportunistic sync was triggered + assertThat(synced).isTrue() + } + + @Test + fun `test - invalid input fails the work`() = runTest { + val worker = createWorker(input = "!alice:matrix.org") + + val result = worker.doWork() + + // The process failed + assertThat(result).isEqualTo(ListenableWorker.Result.failure()) + } + + @Test + fun `test - no network connectivity fails the work`() = runTest { + val networkMonitor = FakeNetworkMonitor(initialStatus = NetworkStatus.Disconnected) + val emitResultLambda = lambdaRecorder>, Unit> {} + val processor = FakeNotificationResultProcessor(emit = emitResultLambda) + val pushHistoryService = FakePushHistoryService( + getPendingPushRequests = { _, _ -> Result.success(listOf(aPushRequest())) }, + replacePushRequests = { Result.success(Unit) }, + removeOldPushRequests = { Result.success(Unit) }, + ) + val worker = createWorker( + input = "@alice:matrix.org", + networkMonitor = networkMonitor, + resultProcessor = processor, + pushHistoryService = pushHistoryService, + ) + + val result = worker.doWork() + + advanceTimeBy(10.seconds) + + // The process failed due to a timeout in getting the network connectivity, a retry is scheduled + assertThat(result).isEqualTo(ListenableWorker.Result.retry()) + } + + @Test + fun `test - failing to setup retries the work`() = runTest { + val submitWorkerLambda = lambdaRecorder {} + val emitResultLambda = lambdaRecorder>, Unit> {} + val processor = FakeNotificationResultProcessor(emit = emitResultLambda) + val pushHistoryService = FakePushHistoryService( + getPendingPushRequests = { _, _ -> Result.success(listOf(aPushRequest())) }, + replacePushRequests = { Result.success(Unit) }, + removeOldPushRequests = { Result.success(Unit) }, + ) + + val resolver = FakeNotifiableEventResolver( + resolveEventsResult = { _, _ -> Result.failure(Exception("Failed to resolve events")) } + ) + + val worker = createWorker( + input = "@alice:matrix.org", + eventResolver = resolver, + resultProcessor = processor, + pushHistoryService = pushHistoryService, + ) + + val result = worker.doWork() + + assertThat(result).isEqualTo(ListenableWorker.Result.retry()) + // Never called since we don't need to re-submit + submitWorkerLambda.assertions().isNeverCalled() + } + + @Test + fun `test - failing to resolve events with recoverable error retries the work`() { + val pushRequest = aPushRequest() + runTest { + val submitWorkerLambda = lambdaRecorder {} + val emitResultLambda = lambdaRecorder>, Unit> {} + val processor = FakeNotificationResultProcessor(emit = emitResultLambda) + val pushHistoryService = FakePushHistoryService( + getPendingPushRequests = { _, _ -> Result.success(listOf(pushRequest)) }, + replacePushRequests = { Result.success(Unit) }, + removeOldPushRequests = { Result.success(Unit) }, + ) + + val resolver = FakeNotifiableEventResolver( + resolveEventsResult = { _, _ -> + Result.success(mapOf(pushRequest to Result.failure(ClientException.Generic("error sending request for url", null)))) + } + ) + + val worker = createWorker( + input = "@alice:matrix.org", + eventResolver = resolver, + resultProcessor = processor, + pushHistoryService = pushHistoryService, + ) + + val result = worker.doWork() + + assertThat(result).isEqualTo(ListenableWorker.Result.retry()) + + // Never called since we don't need to re-submit + submitWorkerLambda.assertions().isNeverCalled() + + // We do save the updated events to the push DB + emitResultLambda.assertions().isCalledOnce() + } + } + + @Test + fun `test - failing to resolve events with unrecoverable error saves the new state and ends as success`() { + val pushRequest = aPushRequest() + runTest { + val submitWorkerLambda = lambdaRecorder {} + val emitResultLambda = lambdaRecorder>, Unit> {} + val processor = FakeNotificationResultProcessor(emit = emitResultLambda) + val pushHistoryService = FakePushHistoryService( + getPendingPushRequests = { _, _ -> Result.success(listOf(pushRequest)) }, + replacePushRequests = { Result.success(Unit) }, + removeOldPushRequests = { Result.success(Unit) }, + ) + + val resolver = FakeNotifiableEventResolver( + resolveEventsResult = { _, _ -> + Result.success(mapOf(pushRequest to Result.failure(IllegalStateException("Unrecoverable")))) + } + ) + + val worker = createWorker( + input = "@alice:matrix.org", + eventResolver = resolver, + resultProcessor = processor, + pushHistoryService = pushHistoryService, + ) + + val result = worker.doWork() + + assertThat(result).isEqualTo(ListenableWorker.Result.success()) + + // Never called since we don't need to re-submit + submitWorkerLambda.assertions().isNeverCalled() + + // We do save the updated events to the push DB + emitResultLambda.assertions().isCalledOnce() + } + } + + private fun TestScope.createWorker( + input: String, + networkMonitor: FakeNetworkMonitor = FakeNetworkMonitor(), + eventResolver: FakeNotifiableEventResolver = FakeNotifiableEventResolver(resolveEventsResult = { _, _ -> Result.success(emptyMap()) }), + syncOnNotifiableEvent: SyncOnNotifiableEvent = SyncOnNotifiableEvent {}, + analyticsService: FakeAnalyticsService = FakeAnalyticsService(), + pushHistoryService: FakePushHistoryService = FakePushHistoryService(), + resultProcessor: FakeNotificationResultProcessor = FakeNotificationResultProcessor(), + systemClock: FakeSystemClock = FakeSystemClock(), + ) = FetchPendingNotificationsWorker( + params = createWorkerParams(workDataOf("session_id" to input)), + context = InstrumentationRegistry.getInstrumentation().context, + networkMonitor = networkMonitor, + eventResolver = eventResolver, + syncOnNotifiableEvent = syncOnNotifiableEvent, + analyticsService = analyticsService, + pushHistoryService = pushHistoryService, + resultProcessor = resultProcessor, + systemClock = systemClock, + ) + + private fun TestScope.createWorkerParams( + inputData: Data = Data.EMPTY, + ): WorkerParameters = WorkerParameters( + UUID.randomUUID(), + inputData, + emptySet(), + WorkerParameters.RuntimeExtras(), + 0, + 0, + Executors.newSingleThreadExecutor(), + backgroundScope.coroutineContext, + WorkManagerTaskExecutor(Executors.newSingleThreadExecutor()), + MetroWorkerFactory(emptyMap()), + { context, id, data -> FakeListenableFuture() }, + { context, id, foregroundInfo -> FakeListenableFuture() }, + ) +} + +class FakeListenableFuture : ListenableFuture { + override fun addListener(listener: Runnable, executor: Executor) = Unit + override fun cancel(mayInterruptIfRunning: Boolean): Boolean = true + override fun get(): T? = null + override fun get(timeout: Long, unit: TimeUnit?): T? = null + override fun isCancelled(): Boolean = false + override fun isDone(): Boolean = false +} diff --git a/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/workmanager/SyncNotificationWorkManagerRequestTest.kt b/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/workmanager/SyncNotificationWorkManagerRequestTest.kt deleted file mode 100644 index 1f8d646e2b..0000000000 --- a/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/workmanager/SyncNotificationWorkManagerRequestTest.kt +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Copyright (c) 2025 Element Creations Ltd. - * Copyright 2025 New Vector Ltd. - * - * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial. - * Please see LICENSE files in the repository root for full details. - */ - -package io.element.android.libraries.push.impl.workmanager - -import androidx.work.OneTimeWorkRequest -import androidx.work.hasKeyWithValueOfType -import com.google.common.truth.Truth.assertThat -import io.element.android.libraries.androidutils.json.DefaultJsonProvider -import io.element.android.libraries.matrix.api.core.SessionId -import io.element.android.libraries.matrix.test.A_SESSION_ID -import io.element.android.libraries.push.api.push.NotificationEventRequest -import io.element.android.libraries.push.impl.notifications.fixtures.aNotificationEventRequest -import io.element.android.libraries.workmanager.api.WorkManagerRequestType -import io.element.android.libraries.workmanager.api.workManagerTag -import io.element.android.services.toolbox.test.sdk.FakeBuildVersionSdkIntProvider -import kotlinx.coroutines.test.runTest -import org.junit.Test -import kotlin.collections.first - -class SyncNotificationWorkManagerRequestTest { - @Test - fun `build - success API 33`() = runTest { - val request = createSyncNotificationWorkManagerRequest( - sessionId = A_SESSION_ID, - notificationEventRequests = listOf(aNotificationEventRequest()), - sdkVersion = 33, - ) - - val result = request.build() - assertThat(result.isSuccess).isTrue() - result.getOrNull()!!.first().run { - assertThat(this).isInstanceOf(OneTimeWorkRequest::class.java) - assertThat(workSpec.input.hasKeyWithValueOfType("requests")).isTrue() - // True in API 33+ - assertThat(workSpec.expedited).isTrue() - assertThat(workSpec.traceTag).isEqualTo(workManagerTag(A_SESSION_ID, WorkManagerRequestType.NOTIFICATION_SYNC)) - } - } - - @Test - fun `build - success API 32 and lower`() = runTest { - val request = createSyncNotificationWorkManagerRequest( - sessionId = A_SESSION_ID, - notificationEventRequests = listOf(aNotificationEventRequest()), - sdkVersion = 32, - ) - - val result = request.build() - assertThat(result.isSuccess).isTrue() - result.getOrNull()!!.first().run { - assertThat(this).isInstanceOf(OneTimeWorkRequest::class.java) - assertThat(workSpec.input.hasKeyWithValueOfType("requests")).isTrue() - // False before API 33 - assertThat(workSpec.expedited).isFalse() - assertThat(workSpec.traceTag).isEqualTo(workManagerTag(A_SESSION_ID, WorkManagerRequestType.NOTIFICATION_SYNC)) - } - } - - @Test - fun `build - empty list of requests fails`() = runTest { - val request = createSyncNotificationWorkManagerRequest( - sessionId = A_SESSION_ID, - notificationEventRequests = emptyList() - ) - - val result = request.build() - assertThat(result.isFailure).isTrue() - } - - @Test - fun `build - invalid serialization`() = runTest { - val request = createSyncNotificationWorkManagerRequest( - sessionId = A_SESSION_ID, - notificationEventRequests = listOf(aNotificationEventRequest()), - workerDataConverter = SyncNotificationsWorkerDataConverter({ error("error during serialization") }) - ) - val result = request.build() - assertThat(result.isFailure).isTrue() - } -} - -private fun createSyncNotificationWorkManagerRequest( - sessionId: SessionId, - notificationEventRequests: List, - workerDataConverter: SyncNotificationsWorkerDataConverter = SyncNotificationsWorkerDataConverter(DefaultJsonProvider()), - sdkVersion: Int = 33, -) = SyncNotificationWorkManagerRequest( - sessionId = sessionId, - notificationEventRequests = notificationEventRequests, - workerDataConverter = workerDataConverter, - buildVersionSdkIntProvider = FakeBuildVersionSdkIntProvider(sdkVersion), -) diff --git a/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/workmanager/SyncPendingNotificationsRequestBuilderTest.kt b/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/workmanager/SyncPendingNotificationsRequestBuilderTest.kt new file mode 100644 index 0000000000..c7d54973e3 --- /dev/null +++ b/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/workmanager/SyncPendingNotificationsRequestBuilderTest.kt @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2025 Element Creations Ltd. + * Copyright 2025 New Vector Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial. + * Please see LICENSE files in the repository root for full details. + */ + +package io.element.android.libraries.push.impl.workmanager + +import androidx.work.OneTimeWorkRequest +import androidx.work.hasKeyWithValueOfType +import com.google.common.truth.Truth.assertThat +import io.element.android.libraries.matrix.api.core.SessionId +import io.element.android.libraries.matrix.test.A_SESSION_ID +import io.element.android.libraries.workmanager.api.WorkManagerRequestType +import io.element.android.libraries.workmanager.api.WorkManagerWorkerType +import io.element.android.libraries.workmanager.api.workManagerTag +import io.element.android.services.toolbox.test.sdk.FakeBuildVersionSdkIntProvider +import kotlinx.coroutines.test.runTest +import org.junit.Test + +class SyncPendingNotificationsRequestBuilderTest { + @Test + fun `build - success API 33`() = runTest { + val request = createSyncPendingNotificationsRequestBuilder( + sessionId = A_SESSION_ID, + sdkVersion = 33, + ) + + val results = request.build() + assertThat(results.isSuccess).isTrue() + results.getOrNull()!!.first().let { result -> + assertThat(result.type).isInstanceOf(WorkManagerWorkerType.Unique::class.java) + result.request.run { + assertThat(this).isInstanceOf(OneTimeWorkRequest::class.java) + assertThat(workSpec.input.hasKeyWithValueOfType(SyncPendingNotificationsRequestBuilder.SESSION_ID)).isTrue() + // True in API 33+ + assertThat(workSpec.expedited).isTrue() + assertThat(workSpec.traceTag).isEqualTo(workManagerTag(A_SESSION_ID, WorkManagerRequestType.NOTIFICATION_SYNC)) + } + } + } + + @Test + fun `build - success API 32 and lower`() = runTest { + val request = createSyncPendingNotificationsRequestBuilder( + sessionId = A_SESSION_ID, + sdkVersion = 32, + ) + + val results = request.build() + assertThat(results.isSuccess).isTrue() + + results.getOrNull()!!.first().let { result -> + assertThat(result.type).isInstanceOf(WorkManagerWorkerType.Unique::class.java) + result.request.run { + assertThat(this).isInstanceOf(OneTimeWorkRequest::class.java) + assertThat(workSpec.input.hasKeyWithValueOfType(SyncPendingNotificationsRequestBuilder.SESSION_ID)).isTrue() + // False before API 33 + assertThat(workSpec.expedited).isFalse() + assertThat(workSpec.traceTag).isEqualTo(workManagerTag(A_SESSION_ID, WorkManagerRequestType.NOTIFICATION_SYNC)) + } + } + } +} + +private fun createSyncPendingNotificationsRequestBuilder( + sessionId: SessionId, + sdkVersion: Int = 33, +) = SyncPendingNotificationsRequestBuilder( + sessionId = sessionId, + buildVersionSdkIntProvider = FakeBuildVersionSdkIntProvider(sdkVersion), +) diff --git a/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/workmanager/WorkerDataConverterTest.kt b/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/workmanager/WorkerDataConverterTest.kt deleted file mode 100644 index 85b55e0d62..0000000000 --- a/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/workmanager/WorkerDataConverterTest.kt +++ /dev/null @@ -1,141 +0,0 @@ -/* - * Copyright (c) 2025 Element Creations Ltd. - * Copyright 2025 New Vector Ltd. - * - * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial. - * Please see LICENSE files in the repository root for full details. - */ - -package io.element.android.libraries.push.impl.workmanager - -import com.google.common.truth.Truth.assertThat -import io.element.android.libraries.androidutils.json.DefaultJsonProvider -import io.element.android.libraries.matrix.api.core.EventId -import io.element.android.libraries.matrix.test.AN_EVENT_ID -import io.element.android.libraries.matrix.test.AN_EVENT_ID_2 -import io.element.android.libraries.matrix.test.A_ROOM_ID -import io.element.android.libraries.matrix.test.A_ROOM_ID_2 -import io.element.android.libraries.matrix.test.A_ROOM_ID_3 -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.push.api.push.NotificationEventRequest -import org.junit.Test - -class WorkerDataConverterTest { - @Test - fun `ensure identity when serializing - deserializing an empty list`() { - testIdentity(emptyList()) - } - - @Test - fun `ensure identity when serializing - deserializing a list`() { - testIdentity( - listOf( - NotificationEventRequest( - sessionId = A_SESSION_ID, - roomId = A_ROOM_ID, - eventId = AN_EVENT_ID, - providerInfo = "info1", - ), - NotificationEventRequest( - sessionId = A_SESSION_ID_2, - roomId = A_ROOM_ID_2, - eventId = AN_EVENT_ID_2, - providerInfo = "info2", - ), - ) - ) - } - - @Test - fun `serializing lots of data leads to several work data generated - one room - 100 events should be split in 5 chunks`() { - val data = List(100) { - NotificationEventRequest( - sessionId = A_SESSION_ID, - roomId = A_ROOM_ID, - eventId = EventId(AN_EVENT_ID.value + it), - providerInfo = "info$it", - ) - } - val sut = SyncNotificationsWorkerDataConverter(DefaultJsonProvider()) - val serialized = sut.serialize(data) - assertThat(serialized.getOrNull()?.size).isGreaterThan(1) - assertThat(serialized.getOrNull()?.size).isEqualTo(100 / SyncNotificationsWorkerDataConverter.CHUNK_SIZE) - // All the items are present - val deserialized = serialized.getOrNull()?.flatMap { sut.deserialize(it)!! } - assertThat(deserialized).containsExactlyElementsIn(data) - } - - @Test - fun `serializing lots of data leads to several work data generated - one room - 101 events should be split in 6 chunks`() { - val data = List(101) { - NotificationEventRequest( - sessionId = A_SESSION_ID, - roomId = A_ROOM_ID, - eventId = EventId(AN_EVENT_ID.value + it), - providerInfo = "info$it", - ) - } - val sut = SyncNotificationsWorkerDataConverter(DefaultJsonProvider()) - val serialized = sut.serialize(data) - assertThat(serialized.getOrNull()?.size).isGreaterThan(1) - assertThat(serialized.getOrNull()?.size).isEqualTo(100 / SyncNotificationsWorkerDataConverter.CHUNK_SIZE + 1) - // All the items are present - val deserialized = serialized.getOrNull()?.flatMap { sut.deserialize(it)!! } - assertThat(deserialized).containsExactlyElementsIn(data) - } - - @Test - fun `serializing lots of data leads to several work data generated - 3 rooms - 25 events should be split in 2 chunks and room not mixed`() { - val data1 = List(15) { - NotificationEventRequest( - sessionId = A_SESSION_ID, - roomId = A_ROOM_ID, - eventId = EventId(AN_EVENT_ID.value + it), - providerInfo = "info".repeat(100) + it, - ) - } - val data2 = List(3) { - NotificationEventRequest( - sessionId = A_SESSION_ID, - roomId = A_ROOM_ID_2, - eventId = EventId(AN_EVENT_ID.value + it), - providerInfo = "info".repeat(100) + it, - ) - } - val data3 = List(7) { - NotificationEventRequest( - sessionId = A_SESSION_ID, - roomId = A_ROOM_ID_3, - eventId = EventId(AN_EVENT_ID.value + it), - providerInfo = "info".repeat(100) + it, - ) - } - val data = (data1 + data2 + data3).shuffled() - val sut = SyncNotificationsWorkerDataConverter(DefaultJsonProvider()) - val serialized = sut.serialize(data) - assertThat(serialized.getOrNull()?.size).isEqualTo(2) - // All the items are present - val deserialized = serialized.getOrNull()?.flatMap { sut.deserialize(it)!! } - assertThat(deserialized).containsExactlyElementsIn(data) - // Rooms are not mixed between the chunks - val setsOfRooms = serialized.getOrNull()!! - .map { workData -> sut.deserialize(workData)!! } - .map { - it.map { request -> request.roomId }.toSet() - } - // Ensure that all sets are distinct - assertThat(setsOfRooms.size).isEqualTo(2) - // 3 roomId are present - assertThat(setsOfRooms.flatten().toSet()).containsExactly(A_ROOM_ID, A_ROOM_ID_2, A_ROOM_ID_3) - // No intersection between sets - assertThat(setsOfRooms[0].intersect(setsOfRooms[1])).isEmpty() - } - - private fun testIdentity(data: List) { - val sut = SyncNotificationsWorkerDataConverter(DefaultJsonProvider()) - val serialized = sut.serialize(data).getOrThrow() - val result = sut.deserialize(serialized.first()) - assertThat(result).isEqualTo(data) - } -} diff --git a/libraries/push/test/src/main/kotlin/io/element/android/libraries/push/test/notifications/FakeNotificationResolverQueue.kt b/libraries/push/test/src/main/kotlin/io/element/android/libraries/push/test/notifications/FakeNotificationResolverQueue.kt deleted file mode 100644 index d4279ab028..0000000000 --- a/libraries/push/test/src/main/kotlin/io/element/android/libraries/push/test/notifications/FakeNotificationResolverQueue.kt +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright (c) 2025 Element Creations Ltd. - * Copyright 2025 New Vector Ltd. - * - * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial. - * Please see LICENSE files in the repository root for full details. - */ - -package io.element.android.libraries.push.test.notifications - -import io.element.android.libraries.push.api.push.NotificationEventRequest -import io.element.android.libraries.push.impl.notifications.NotificationResolverQueue -import io.element.android.libraries.push.impl.notifications.model.ResolvedPushEvent -import kotlinx.coroutines.flow.MutableSharedFlow - -class FakeNotificationResolverQueue( - private val processingLambda: suspend (NotificationEventRequest) -> Result, -) : NotificationResolverQueue { - override val results = MutableSharedFlow, Map>>>(replay = 1) - - override suspend fun enqueue(request: NotificationEventRequest) { - results.emit(listOf(request) to mapOf(request to processingLambda(request))) - } -} diff --git a/libraries/session-storage/impl/src/main/sqldelight/migrations/0.sqm b/libraries/session-storage/impl/src/main/sqldelight/migrations/0.sqm index 4577105e3d..238e4514f0 100644 --- a/libraries/session-storage/impl/src/main/sqldelight/migrations/0.sqm +++ b/libraries/session-storage/impl/src/main/sqldelight/migrations/0.sqm @@ -1,4 +1,4 @@ --- This file is not striclty necessary, since the first +-- This file is not strictly necessary, since the first -- version of the DB is 1, so we will never migrate from 0 CREATE TABLE SessionData ( diff --git a/libraries/workmanager/api/src/main/kotlin/io/element/android/libraries/workmanager/api/WorkManagerRequest.kt b/libraries/workmanager/api/src/main/kotlin/io/element/android/libraries/workmanager/api/WorkManagerRequest.kt deleted file mode 100644 index af49c3dc87..0000000000 --- a/libraries/workmanager/api/src/main/kotlin/io/element/android/libraries/workmanager/api/WorkManagerRequest.kt +++ /dev/null @@ -1,15 +0,0 @@ -/* - * Copyright (c) 2025 Element Creations Ltd. - * Copyright 2025 New Vector Ltd. - * - * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial. - * Please see LICENSE files in the repository root for full details. - */ - -package io.element.android.libraries.workmanager.api - -import androidx.work.WorkRequest - -interface WorkManagerRequest { - fun build(): Result> -} diff --git a/libraries/workmanager/api/src/main/kotlin/io/element/android/libraries/workmanager/api/WorkManagerRequestBuilder.kt b/libraries/workmanager/api/src/main/kotlin/io/element/android/libraries/workmanager/api/WorkManagerRequestBuilder.kt new file mode 100644 index 0000000000..a82ddf165d --- /dev/null +++ b/libraries/workmanager/api/src/main/kotlin/io/element/android/libraries/workmanager/api/WorkManagerRequestBuilder.kt @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2025 Element Creations Ltd. + * Copyright 2025 New Vector Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial. + * Please see LICENSE files in the repository root for full details. + */ + +package io.element.android.libraries.workmanager.api + +import androidx.work.ExistingWorkPolicy +import androidx.work.WorkRequest + +/** + * A base class that can be customized to [build] work requests to schedule in `WorkManager`. + */ +interface WorkManagerRequestBuilder { + /** + * Builds a work request wrapper using the provided data. + */ + suspend fun build(): Result> +} + +/** + * A wrapper that allows us to avoid using Android APIs directly when scheduling workers. + */ +data class WorkManagerRequestWrapper( + val request: WorkRequest, + val type: WorkManagerWorkerType = WorkManagerWorkerType.Default, +) + +/** + * The type of worker to use when scheduling the task. + */ +sealed interface WorkManagerWorkerType { + /** + * This allows a single worker instance with the [name] id to run at the same time. Its [policy] can be customized. + */ + data class Unique(val name: String, val policy: ExistingWorkPolicy) : WorkManagerWorkerType + + /** + * The default worker type, with no custom rules. + */ + data object Default : WorkManagerWorkerType +} diff --git a/libraries/workmanager/api/src/main/kotlin/io/element/android/libraries/workmanager/api/WorkManagerScheduler.kt b/libraries/workmanager/api/src/main/kotlin/io/element/android/libraries/workmanager/api/WorkManagerScheduler.kt index b538486d35..a616e01573 100644 --- a/libraries/workmanager/api/src/main/kotlin/io/element/android/libraries/workmanager/api/WorkManagerScheduler.kt +++ b/libraries/workmanager/api/src/main/kotlin/io/element/android/libraries/workmanager/api/WorkManagerScheduler.kt @@ -11,9 +11,21 @@ package io.element.android.libraries.workmanager.api import io.element.android.libraries.matrix.api.core.SessionId interface WorkManagerScheduler { - fun submit(workManagerRequest: WorkManagerRequest) + /** + * Submits a new work request built from [workManagerRequestBuilder] to run in `WorkManager`. + */ + suspend fun submit(workManagerRequestBuilder: WorkManagerRequestBuilder) + + /** + * Checks if there are any pending requests scheduled for the provided [sessionId] and [requestType]. + */ fun hasPendingWork(sessionId: SessionId, requestType: WorkManagerRequestType): Boolean - fun cancel(sessionId: SessionId) + + /** + * Cancel pending work requests for the session [SessionId]. + * If [requestType] is provided, it will only cancel requests for that type, otherwise it will cancel all requests. + */ + fun cancel(sessionId: SessionId, requestType: WorkManagerRequestType? = null) } fun workManagerTag(sessionId: SessionId, requestType: WorkManagerRequestType): String { diff --git a/libraries/workmanager/impl/src/main/kotlin/io/element/android/libraries/workmanager/impl/DefaultWorkManagerScheduler.kt b/libraries/workmanager/impl/src/main/kotlin/io/element/android/libraries/workmanager/impl/DefaultWorkManagerScheduler.kt index 4f3806db62..aa645c9a17 100644 --- a/libraries/workmanager/impl/src/main/kotlin/io/element/android/libraries/workmanager/impl/DefaultWorkManagerScheduler.kt +++ b/libraries/workmanager/impl/src/main/kotlin/io/element/android/libraries/workmanager/impl/DefaultWorkManagerScheduler.kt @@ -8,6 +8,7 @@ package io.element.android.libraries.workmanager.impl +import androidx.work.OneTimeWorkRequest import androidx.work.WorkInfo import androidx.work.WorkManager import dev.zacsweers.metro.AppScope @@ -16,9 +17,10 @@ import dev.zacsweers.metro.SingleIn import io.element.android.libraries.matrix.api.core.SessionId import io.element.android.libraries.sessionstorage.api.observer.SessionListener import io.element.android.libraries.sessionstorage.api.observer.SessionObserver -import io.element.android.libraries.workmanager.api.WorkManagerRequest +import io.element.android.libraries.workmanager.api.WorkManagerRequestBuilder import io.element.android.libraries.workmanager.api.WorkManagerRequestType import io.element.android.libraries.workmanager.api.WorkManagerScheduler +import io.element.android.libraries.workmanager.api.WorkManagerWorkerType import io.element.android.libraries.workmanager.api.workManagerTag import timber.log.Timber @@ -41,13 +43,22 @@ class DefaultWorkManagerScheduler( }) } - override fun submit(workManagerRequest: WorkManagerRequest) { - workManagerRequest.build().fold( - onSuccess = { workRequests -> - workManager.enqueue(workRequests) + override suspend fun submit(workManagerRequestBuilder: WorkManagerRequestBuilder) { + workManagerRequestBuilder.build().fold( + onSuccess = { wrappers -> + for (wrapper in wrappers) { + when (wrapper.type) { + WorkManagerWorkerType.Default -> workManager.enqueue(wrapper.request) + is WorkManagerWorkerType.Unique -> { + val type = wrapper.type as WorkManagerWorkerType.Unique + val requests = wrapper.request as OneTimeWorkRequest + workManager.enqueueUniqueWork(type.name, type.policy, requests) + } + } + } }, onFailure = { - Timber.e(it, "Failed to build WorkManager request $workManagerRequest") + Timber.e(it, "Failed to build WorkManager request $workManagerRequestBuilder") } ) } @@ -64,10 +75,15 @@ class DefaultWorkManagerScheduler( } } - override fun cancel(sessionId: SessionId) { + override fun cancel(sessionId: SessionId, requestType: WorkManagerRequestType?) { Timber.d("Cancelling work for sessionId: $sessionId") - for (requestType in WorkManagerRequestType.entries) { + + if (requestType != null) { workManager.cancelAllWorkByTag(workManagerTag(sessionId, requestType)) + } else { + for (requestType in WorkManagerRequestType.entries) { + workManager.cancelAllWorkByTag(workManagerTag(sessionId, requestType)) + } } } } diff --git a/libraries/workmanager/impl/src/test/kotlin/io/element/android/libraries/workmanager/impl/DefaultWorkManagerSchedulerTest.kt b/libraries/workmanager/impl/src/test/kotlin/io/element/android/libraries/workmanager/impl/DefaultWorkManagerSchedulerTest.kt index b4f964ed12..761a82e0f4 100644 --- a/libraries/workmanager/impl/src/test/kotlin/io/element/android/libraries/workmanager/impl/DefaultWorkManagerSchedulerTest.kt +++ b/libraries/workmanager/impl/src/test/kotlin/io/element/android/libraries/workmanager/impl/DefaultWorkManagerSchedulerTest.kt @@ -7,12 +7,17 @@ package io.element.android.libraries.workmanager.impl +import android.content.Context +import androidx.work.OneTimeWorkRequest import androidx.work.WorkManager import androidx.work.WorkRequest +import androidx.work.Worker +import androidx.work.WorkerParameters import io.element.android.libraries.matrix.api.core.SessionId import io.element.android.libraries.sessionstorage.test.observer.FakeSessionObserver -import io.element.android.libraries.workmanager.api.WorkManagerRequest +import io.element.android.libraries.workmanager.api.WorkManagerRequestBuilder import io.element.android.libraries.workmanager.api.WorkManagerRequestType +import io.element.android.libraries.workmanager.api.WorkManagerRequestWrapper import io.element.android.libraries.workmanager.api.workManagerTag import io.mockk.every import io.mockk.mockk @@ -55,7 +60,7 @@ class DefaultWorkManagerSchedulerTest { sessionObserver = FakeSessionObserver(), ) - scheduler.submit(FakeWorkManagerRequest()) + scheduler.submit(FakeWorkManagerRequestBuilder()) verify { workManager.enqueue(any>()) } } @@ -69,7 +74,7 @@ class DefaultWorkManagerSchedulerTest { sessionObserver = FakeSessionObserver(), ) - scheduler.submit(FakeWorkManagerRequest(result = Result.failure(IllegalStateException("Test error")))) + scheduler.submit(FakeWorkManagerRequestBuilder(result = Result.failure(IllegalStateException("Test error")))) verify(exactly = 0) { workManager.enqueue(any>()) } } @@ -88,7 +93,7 @@ class DefaultWorkManagerSchedulerTest { val mockSessionA = mockk { every { tags } returns setOf(tagToRemove) } - scheduler.submit(FakeWorkManagerRequest(result = Result.success(listOf(mockSessionA)))) + scheduler.submit(FakeWorkManagerRequestBuilder(result = Result.success(listOf(WorkManagerRequestWrapper(mockSessionA))))) scheduler.cancel(sessionId) @@ -96,10 +101,16 @@ class DefaultWorkManagerSchedulerTest { } } -private class FakeWorkManagerRequest( - private val result: Result> = Result.success(listOf()), -) : WorkManagerRequest { - override fun build(): Result> { +private val workRequest = OneTimeWorkRequest.Builder(FakeWorker::class.java).build() + +private class FakeWorkManagerRequestBuilder( + private val result: Result> = Result.success(listOf(WorkManagerRequestWrapper(workRequest))), +) : WorkManagerRequestBuilder { + override suspend fun build(): Result> { return result } } + +internal class FakeWorker(context: Context, params: WorkerParameters) : Worker(context, params) { + override fun doWork(): Result = Result.success() +} diff --git a/libraries/workmanager/test/src/main/kotlin/io/element/android/libraries/workmanager/test/FakeWorkManagerScheduler.kt b/libraries/workmanager/test/src/main/kotlin/io/element/android/libraries/workmanager/test/FakeWorkManagerScheduler.kt index f2caa8c743..aa39b48ed7 100644 --- a/libraries/workmanager/test/src/main/kotlin/io/element/android/libraries/workmanager/test/FakeWorkManagerScheduler.kt +++ b/libraries/workmanager/test/src/main/kotlin/io/element/android/libraries/workmanager/test/FakeWorkManagerScheduler.kt @@ -9,25 +9,25 @@ package io.element.android.libraries.workmanager.test import io.element.android.libraries.matrix.api.core.SessionId -import io.element.android.libraries.workmanager.api.WorkManagerRequest +import io.element.android.libraries.workmanager.api.WorkManagerRequestBuilder import io.element.android.libraries.workmanager.api.WorkManagerRequestType import io.element.android.libraries.workmanager.api.WorkManagerScheduler import io.element.android.tests.testutils.lambda.lambdaError class FakeWorkManagerScheduler( - private val submitLambda: (WorkManagerRequest) -> Unit = { lambdaError() }, + private val submitLambda: (WorkManagerRequestBuilder) -> Unit = { lambdaError() }, private val hasPendingWorkLambda: (SessionId, WorkManagerRequestType) -> Boolean = { _, _ -> false }, - private val cancelLambda: (SessionId) -> Unit = { lambdaError() }, + private val cancelLambda: (SessionId, WorkManagerRequestType?) -> Unit = { _, _ -> lambdaError() }, ) : WorkManagerScheduler { - override fun submit(workManagerRequest: WorkManagerRequest) { - submitLambda(workManagerRequest) + override suspend fun submit(workManagerRequestBuilder: WorkManagerRequestBuilder) { + submitLambda(workManagerRequestBuilder) } override fun hasPendingWork(sessionId: SessionId, requestType: WorkManagerRequestType): Boolean { return hasPendingWorkLambda(sessionId, requestType) } - override fun cancel(sessionId: SessionId) { - cancelLambda(sessionId) + override fun cancel(sessionId: SessionId, requestType: WorkManagerRequestType?) { + cancelLambda(sessionId, requestType) } } From 5cfcffc45ef691f33b1c7bcc52e4935ab1e7f099 Mon Sep 17 00:00:00 2001 From: Andy Balaam Date: Wed, 4 Mar 2026 14:37:16 +0000 Subject: [PATCH 49/60] Adjust the build-rust-sdk script to allow non-interactive use --- docs/_developer_onboarding.md | 4 +- tools/sdk/build-rust-sdk | 241 ++++++++++++++++++++++++++++++++++ tools/sdk/build_rust_sdk.sh | 101 -------------- 3 files changed, 243 insertions(+), 103 deletions(-) create mode 100755 tools/sdk/build-rust-sdk delete mode 100755 tools/sdk/build_rust_sdk.sh diff --git a/docs/_developer_onboarding.md b/docs/_developer_onboarding.md index 7770c016fc..6035c875e1 100644 --- a/docs/_developer_onboarding.md +++ b/docs/_developer_onboarding.md @@ -144,8 +144,8 @@ Prerequisites: ``` You can then build the Rust SDK by running the script -[`tools/sdk/build_rust_sdk.sh`](../tools/sdk/build_rust_sdk.sh) and just answering -the questions. +[`tools/sdk/build-rust-sdk`](../tools/sdk/build-rust-sdk). Type +`./tools/sdk/build-rust-sdk --help` for help. This will prompt you for the path to the Rust SDK, then build it and `matrix-rust-components-kotlin`, eventually producing an aar file at diff --git a/tools/sdk/build-rust-sdk b/tools/sdk/build-rust-sdk new file mode 100755 index 0000000000..ea1b80c469 --- /dev/null +++ b/tools/sdk/build-rust-sdk @@ -0,0 +1,241 @@ +#!/usr/bin/env bash + +# Copyright (c) 2025-2026 Element Creations Ltd. +# Copyright 2024 New Vector Ltd. +# +# SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial. +# Please see LICENSE files in the repository root for full details. + +set -e +set -u + +# Usage: +# +# ./tools/sdk/build-rust-sdk --help +# + +# Notes: +# +# * matrix-rust-components-kotlin will be cloned into +# ../matrix-rust-components-kotlin and any changes in there will be +# overwritten (without prompting!) +# +# * If you opt to build a remote repo, it will be cloned into +# ../matrix-rust-sdk-<> + +## Defaults + +buildLocal=0 +rustSdkPath="../matrix-rust-sdk/" +rustSdkUrl="https://github.com/matrix-org/matrix-rust-sdk.git" +rustSdkBranch="main" +buildApp=1 + +default_arch="$(uname -m)-linux-android" +# On ARM MacOS, `uname -m` returns arm64, but the toolchain is called aarch64 +default_arch="${default_arch/arm64/aarch64}" + +target_arch="${default_arch}" + +sdkArg="" + +## Argument parsing + +TEMP=$(getopt -o 'rs:b:at:h' --long 'remote,sdk:,branch:,build-app,target-arch,help' -- "$@") + +if [ $? -ne 0 ]; then + echo 'Terminating...' >&2 + exit 1 +fi + +eval set -- "$TEMP" +unset TEMP + +while true; do + case "$1" in + 'r'|'--remote') + buildLocal=1 + shift + continue + ;; + 's'|'--sdk') + sdkArg="$2" + shift 2 + continue + ;; + 'b'|'--branch') + rustSdkBranch="$2" + shift 2 + continue + ;; + 'a'|'--build-app') + buildApp=0 + shift + continue + ;; + 't'|'--target-arch') + target_arch="$2" + shift 2 + continue + ;; + 'h'|'--help') + cat << END +SYNOPSIS + + $0 [-s|--sdk=PATH] [-a|--build-app] [-t|--target-arch=TARGET]" + + $0 --remote [-s|--sdk=URL] [-b|--branch=BRANCH] [-a|--build-app] [-t|--target-arch=TARGET]" + +ARGUMENTS + + -a --build-app + Build the Android app after the SDK is built. + + -b --branch + If --remote is supplied, the branch of the remote repo to build. + + -r --remote + Fetch the SDK code from a remote repo instead of building a local version. + + -s --sdk + The local path of the SDK to build, or the URL of the remote repo if --remote is provided. + + -t --target-arch + The architecture for which to build the app. Defaults to the architecture of this machine (${default_arch}). + +EXAMPLES + + $0 + Build the default local rust SDK (../matrix-rust-sdk) + + $0 --sdk=/home/andy/code/matrix-rust-sdk + Build the supplied local rust SDK + + $0 --remote + Build the default remote SDK + + $0 --remote --branch=featureA + Build the "featureA" branch of the remote SDK + + $0 --remote --sdk=https://github.com/andybalaam/matrix-rust-sdk.git + Build an alternative remote SDK + + $0 --build-app + Build the app after building the SDK + + $0 --build-app --target-arch=x86_64-linux-android + Build the app after building the SDK, for the x86_64 target architecture + +END + exit 0 + ;; + '--') + shift + break + ;; + *) + echo 'Unrecognised argument!' >&2 + exit 2 + ;; + esac +done + +if [ -n "${sdkArg}" ]; then + if [ "${buildLocal}" == "0" ]; then + rustSdkPath="${sdkArg}" + else + rustSdkUrl="${sdkArg}" + fi +fi + +#echo "buildLocal=${buildLocal}" +#echo "rustSdkPath=${rustSdkPath}" +#echo "rustSdkUrl=${rustSdkUrl}" +#echo "rustSdkBranch=${rustSdkBranch}" +#echo "buildApp=${buildApp}" + +## Find the date + +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) + +## Check the local build dir is valid, or clone the remote repo + +if [ "${buildLocal}" == "0" ]; then + if [ ! -d "${rustSdkPath}" ]; then + printf "\nFolder ${rustSdkPath} does not exist. Please clone the\n" >&2 + printf "matrix-rust-sdk repository into ../matrix-rust-sdk\n" >&2 + printf "or supply the --sdk argument.\n\n" >&2 + exit 3 + fi +else + printf "\n## Cloning the SDK repo...\n\n" + + cd .. + git clone "${rustSdkUrl}" matrix-rust-sdk-"$date" + cd matrix-rust-sdk-"$date" + git checkout "${rustSdkBranch}" + rustSdkPath=$(pwd) +fi + +cd "${elementPwd}" + +## Clone matrix-rust-components-kotlin if needed + +if [ ! -d "../matrix-rust-components-kotlin" ]; then + printf "\nFolder ../matrix-rust-components-kotlin does not exist." + printf "Cloning the repository into ../matrix-rust-components-kotlin.\n\n" + git clone \ + https://github.com/matrix-org/matrix-rust-components-kotlin.git \ + ../matrix-rust-components-kotlin +fi + +printf "\n## Resetting matrix-rust-components-kotlin to the latest main...\n\n" + +cd ../matrix-rust-components-kotlin +git reset --hard +git checkout main +git pull + +## Build the SDK + +printf "\n## Building the SDK for ${target_arch}...\n\n" + +./scripts/build.sh \ + -p "${rustSdkPath}" \ + -m sdk \ + -t "${target_arch}" \ + -o "${elementPwd}/libraries/rustsdk" + +cd "${elementPwd}" + +mv \ + ./libraries/rustsdk/sdk-android-debug.aar \ + ./libraries/rustsdk/matrix-rust-sdk.aar + +mkdir -p ./libraries/rustsdk/sdks + +cp \ + "./libraries/rustsdk/matrix-rust-sdk.aar" \ + "./libraries/rustsdk/sdks/matrix-rust-sdk-${date}.aar" + +## Build the app + +if [ "${buildApp}" == "0" ]; then + printf "\n## Building the application...\n\n" + ./gradlew assembleDebug +fi + +## Clean remote checkout of SDK repo + +if [ "${buildLocal}" != "0" ]; then + printf "\n## Cleaning up...\n\n" + rm -rf "../matrix-rust-sdk-$date" +fi + +printf "\n## Done!\n" diff --git a/tools/sdk/build_rust_sdk.sh b/tools/sdk/build_rust_sdk.sh deleted file mode 100755 index 0b74b0c4cb..0000000000 --- a/tools/sdk/build_rust_sdk.sh +++ /dev/null @@ -1,101 +0,0 @@ -#!/usr/bin/env bash - -# Copyright (c) 2025 Element Creations Ltd. -# Copyright 2024 New Vector Ltd. -# -# SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial. -# Please see LICENSE files in the repository root for full details. - -# Exit on error -set -e - -# Ask to build from local source or to clone the repository -read -p "Do you want to build the Rust SDK from local source (yes/no) default to yes? " buildLocal -buildLocal=${buildLocal:-yes} - -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 -# if folder rustSdk/ exists, use it as default -if [ "${buildLocal}" == "yes" ]; then - read -p "Please enter the path to the Rust SDK local source, default to ../matrix-rust-sdk" rustSdkPath - rustSdkPath=${rustSdkPath:-../matrix-rust-sdk/} - if [ ! -d "${rustSdkPath}" ]; then - printf "\nFolder ${rustSdkPath} does not exist. Please clone the matrix-rust-sdk repository in the folder ../matrix-rust-sdk.\n\n" - exit 0 - fi -else - read -p "Please enter the Rust SDK repository url, default to https://github.com/matrix-org/matrix-rust-sdk.git " rustSdkUrl - rustSdkUrl=${rustSdkUrl:-https://github.com/matrix-org/matrix-rust-sdk.git} - read -p "Please enter the Rust SDK branch, default to main " rustSdkBranch - rustSdkBranch=${rustSdkBranch:-main} - cd .. - git clone "${rustSdkUrl}" matrix-rust-sdk-"$date" - cd matrix-rust-sdk-"$date" - git checkout "${rustSdkBranch}" - rustSdkPath=$(pwd) - cd "${elementPwd}" -fi - - -cd "${rustSdkPath}" -git status - -read -p "Will build with this version of the Rust SDK ^. Is it correct (yes/no) default to yes? " sdkCorrect -sdkCorrect=${sdkCorrect:-yes} - -if [ "${sdkCorrect}" != "yes" ]; then - exit 0 -fi - -# Ask if the user wants to build the app after -read -p "Do you want to build the app after (yes/no) default to no? " buildApp -buildApp=${buildApp:-no} - -cd "${elementPwd}" - -default_arch="$(uname -m)-linux-android" -# On ARM MacOS, `uname -m` returns arm64, but the toolchain is called aarch64 -default_arch="${default_arch/arm64/aarch64}" - -read -p "Enter the architecture you want to build for (default '$default_arch'): " target_arch -target_arch="${target_arch:-${default_arch}}" - -# If folder ../matrix-rust-components-kotlin does not exist, clone the repo -if [ ! -d "../matrix-rust-components-kotlin" ]; then - printf "\nFolder ../matrix-rust-components-kotlin does not exist. Cloning the repository into ../matrix-rust-components-kotlin.\n\n" - git clone https://github.com/matrix-org/matrix-rust-components-kotlin.git ../matrix-rust-components-kotlin -fi - -printf "\nResetting matrix-rust-components-kotlin to the latest main branch...\n\n" -cd ../matrix-rust-components-kotlin -git reset --hard -git checkout main -git pull - -printf "\nBuilding the SDK for ${target_arch}...\n\n" -./scripts/build.sh -p "${rustSdkPath}" -m sdk -t "${target_arch}" -o "${elementPwd}/libraries/rustsdk" - -cd "${elementPwd}" -mv ./libraries/rustsdk/sdk-android-debug.aar ./libraries/rustsdk/matrix-rust-sdk.aar -mkdir -p ./libraries/rustsdk/sdks -cp ./libraries/rustsdk/matrix-rust-sdk.aar ./libraries/rustsdk/sdks/matrix-rust-sdk-"${date}".aar - - -if [ "${buildApp}" == "yes" ]; then - printf "\nBuilding the application...\n\n" - ./gradlew assembleDebug -fi - -if [ "${buildLocal}" == "no" ]; then - printf "\nCleaning up...\n\n" - rm -rf ../matrix-rust-sdk-"$date" -fi - -printf "\nDone!\n" From 3e1d2f6d10b75873bb66f73718e6adc3e24862f8 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 4 Mar 2026 15:37:49 +0000 Subject: [PATCH 50/60] Update dependency org.matrix.rustcomponents:sdk-android to v26.03.4 --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 07b852ff96..7e42af3778 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -178,7 +178,7 @@ test_detekt_test = { module = "io.gitlab.arturbosch.detekt:detekt-test", version # https://github.com/matrix-org/matrix-rust-components-kotlin/commits/main/sdk/sdk-android/src/main/kotlin/org/matrix/rustcomponents/sdk/matrix_sdk_ffi.kt # All new features should not be implemented in the pull request that upgrades the version, developers should # only fix API breaks and may add some TODOs. -matrix_sdk = "org.matrix.rustcomponents:sdk-android:26.03.1" +matrix_sdk = "org.matrix.rustcomponents:sdk-android:26.03.4" # Others coil = { module = "io.coil-kt.coil3:coil", version.ref = "coil" } From 576b8d84849bfd43654c5405a5d11eeeffa2ee01 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 4 Mar 2026 17:12:25 +0100 Subject: [PATCH 51/60] Fix API break. --- .../libraries/matrix/impl/oidc/AccountManagementAction.kt | 6 +++--- .../matrix/impl/oidc/AccountManagementActionKtTest.kt | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/oidc/AccountManagementAction.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/oidc/AccountManagementAction.kt index f998126e17..76e60e90f4 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/oidc/AccountManagementAction.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/oidc/AccountManagementAction.kt @@ -14,8 +14,8 @@ import org.matrix.rustcomponents.sdk.AccountManagementAction as RustAccountManag fun AccountManagementAction.toRustAction(): RustAccountManagementAction { return when (this) { AccountManagementAction.Profile -> RustAccountManagementAction.Profile - is AccountManagementAction.SessionEnd -> RustAccountManagementAction.SessionEnd(deviceId.value) - is AccountManagementAction.SessionView -> RustAccountManagementAction.SessionView(deviceId.value) - AccountManagementAction.SessionsList -> RustAccountManagementAction.SessionsList + is AccountManagementAction.SessionEnd -> RustAccountManagementAction.DeviceDelete(deviceId.value) + is AccountManagementAction.SessionView -> RustAccountManagementAction.DeviceView(deviceId.value) + AccountManagementAction.SessionsList -> RustAccountManagementAction.DevicesList } } diff --git a/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/oidc/AccountManagementActionKtTest.kt b/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/oidc/AccountManagementActionKtTest.kt index 8115465679..0e0cab414e 100644 --- a/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/oidc/AccountManagementActionKtTest.kt +++ b/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/oidc/AccountManagementActionKtTest.kt @@ -20,10 +20,10 @@ class AccountManagementActionKtTest { assertThat(AccountManagementAction.Profile.toRustAction()) .isEqualTo(RustAccountManagementAction.Profile) assertThat(AccountManagementAction.SessionEnd(A_DEVICE_ID).toRustAction()) - .isEqualTo(RustAccountManagementAction.SessionEnd(A_DEVICE_ID.value)) + .isEqualTo(RustAccountManagementAction.DeviceDelete(A_DEVICE_ID.value)) assertThat(AccountManagementAction.SessionView(A_DEVICE_ID).toRustAction()) - .isEqualTo(RustAccountManagementAction.SessionView(A_DEVICE_ID.value)) + .isEqualTo(RustAccountManagementAction.DeviceView(A_DEVICE_ID.value)) assertThat(AccountManagementAction.SessionsList.toRustAction()) - .isEqualTo(RustAccountManagementAction.SessionsList) + .isEqualTo(RustAccountManagementAction.DevicesList) } } From e6c707968363951bb63b6a89f571bc22d4f8c25c Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 4 Mar 2026 17:23:31 +0100 Subject: [PATCH 52/60] Update dependency io.sentry:sentry-android to v8.34.0 (#6280) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 07b852ff96..537203e6b3 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -220,7 +220,7 @@ color_picker = "io.mhssn:colorpicker:1.0.0" # Analytics posthog = "com.posthog:posthog-android:3.34.3" -sentry = "io.sentry:sentry-android:8.33.0" +sentry = "io.sentry:sentry-android:8.34.0" # main branch can be tested replacing the version with main-SNAPSHOT matrix_analytics_events = "com.github.matrix-org:matrix-analytics-events:0.29.2" From 1682ae88e7dd7f497174ad3bf770f996e78ba73b Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 4 Mar 2026 17:41:44 +0100 Subject: [PATCH 53/60] Rename our classes too. --- .../io/element/android/appnav/loggedin/LoggedInPresenter.kt | 2 +- .../android/appnav/loggedin/LoggedInPresenterTest.kt | 2 +- .../preferences/impl/root/PreferencesRootPresenter.kt | 2 +- .../preferences/impl/root/PreferencesRootPresenterTest.kt | 2 +- .../libraries/matrix/api/oidc/AccountManagementAction.kt | 6 +++--- .../libraries/matrix/impl/oidc/AccountManagementAction.kt | 6 +++--- .../matrix/impl/oidc/AccountManagementActionKtTest.kt | 6 +++--- 7 files changed, 13 insertions(+), 13 deletions(-) diff --git a/appnav/src/main/kotlin/io/element/android/appnav/loggedin/LoggedInPresenter.kt b/appnav/src/main/kotlin/io/element/android/appnav/loggedin/LoggedInPresenter.kt index 184766e323..757dd73395 100644 --- a/appnav/src/main/kotlin/io/element/android/appnav/loggedin/LoggedInPresenter.kt +++ b/appnav/src/main/kotlin/io/element/android/appnav/loggedin/LoggedInPresenter.kt @@ -167,6 +167,6 @@ class LoggedInPresenter( private fun CoroutineScope.preloadAccountManagementUrl() = launch { matrixClient.getAccountManagementUrl(AccountManagementAction.Profile) - matrixClient.getAccountManagementUrl(AccountManagementAction.SessionsList) + matrixClient.getAccountManagementUrl(AccountManagementAction.DevicesList) } } diff --git a/appnav/src/test/kotlin/io/element/android/appnav/loggedin/LoggedInPresenterTest.kt b/appnav/src/test/kotlin/io/element/android/appnav/loggedin/LoggedInPresenterTest.kt index 849dfa85b2..f1759eab3e 100644 --- a/appnav/src/test/kotlin/io/element/android/appnav/loggedin/LoggedInPresenterTest.kt +++ b/appnav/src/test/kotlin/io/element/android/appnav/loggedin/LoggedInPresenterTest.kt @@ -81,7 +81,7 @@ class LoggedInPresenterTest { accountManagementUrlResult.assertions().isCalledExactly(2) .withSequence( listOf(value(AccountManagementAction.Profile)), - listOf(value(AccountManagementAction.SessionsList)), + listOf(value(AccountManagementAction.DevicesList)), ) } } diff --git a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/root/PreferencesRootPresenter.kt b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/root/PreferencesRootPresenter.kt index 59aa6ece8e..3d6a829167 100644 --- a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/root/PreferencesRootPresenter.kt +++ b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/root/PreferencesRootPresenter.kt @@ -165,6 +165,6 @@ class PreferencesRootPresenter( devicesManagementUrl: MutableState, ) = launch { accountManagementUrl.value = matrixClient.getAccountManagementUrl(AccountManagementAction.Profile).getOrNull() - devicesManagementUrl.value = matrixClient.getAccountManagementUrl(AccountManagementAction.SessionsList).getOrNull() + devicesManagementUrl.value = matrixClient.getAccountManagementUrl(AccountManagementAction.DevicesList).getOrNull() } } diff --git a/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/root/PreferencesRootPresenterTest.kt b/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/root/PreferencesRootPresenterTest.kt index d10f860f0d..c41550134a 100644 --- a/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/root/PreferencesRootPresenterTest.kt +++ b/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/root/PreferencesRootPresenterTest.kt @@ -98,7 +98,7 @@ class PreferencesRootPresenterTest { accountManagementUrlResult.assertions().isCalledExactly(2) .withSequence( listOf(value(AccountManagementAction.Profile)), - listOf(value(AccountManagementAction.SessionsList)), + listOf(value(AccountManagementAction.DevicesList)), ) assertThat(finalState.accountManagementUrl).isEqualTo("Profile url") assertThat(finalState.devicesManagementUrl).isEqualTo("SessionsList url") diff --git a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/oidc/AccountManagementAction.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/oidc/AccountManagementAction.kt index 77e8854417..e1c7764e58 100644 --- a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/oidc/AccountManagementAction.kt +++ b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/oidc/AccountManagementAction.kt @@ -12,7 +12,7 @@ import io.element.android.libraries.matrix.api.core.DeviceId sealed interface AccountManagementAction { data object Profile : AccountManagementAction - data object SessionsList : AccountManagementAction - data class SessionView(val deviceId: DeviceId) : AccountManagementAction - data class SessionEnd(val deviceId: DeviceId) : AccountManagementAction + data object DevicesList : AccountManagementAction + data class DeviceView(val deviceId: DeviceId) : AccountManagementAction + data class DeviceDelete(val deviceId: DeviceId) : AccountManagementAction } diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/oidc/AccountManagementAction.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/oidc/AccountManagementAction.kt index 76e60e90f4..f86c57543a 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/oidc/AccountManagementAction.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/oidc/AccountManagementAction.kt @@ -14,8 +14,8 @@ import org.matrix.rustcomponents.sdk.AccountManagementAction as RustAccountManag fun AccountManagementAction.toRustAction(): RustAccountManagementAction { return when (this) { AccountManagementAction.Profile -> RustAccountManagementAction.Profile - is AccountManagementAction.SessionEnd -> RustAccountManagementAction.DeviceDelete(deviceId.value) - is AccountManagementAction.SessionView -> RustAccountManagementAction.DeviceView(deviceId.value) - AccountManagementAction.SessionsList -> RustAccountManagementAction.DevicesList + is AccountManagementAction.DeviceDelete -> RustAccountManagementAction.DeviceDelete(deviceId.value) + is AccountManagementAction.DeviceView -> RustAccountManagementAction.DeviceView(deviceId.value) + AccountManagementAction.DevicesList -> RustAccountManagementAction.DevicesList } } diff --git a/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/oidc/AccountManagementActionKtTest.kt b/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/oidc/AccountManagementActionKtTest.kt index 0e0cab414e..3637ef78cc 100644 --- a/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/oidc/AccountManagementActionKtTest.kt +++ b/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/oidc/AccountManagementActionKtTest.kt @@ -19,11 +19,11 @@ class AccountManagementActionKtTest { fun `test AccountManagementAction to RustAccountManagementAction`() { assertThat(AccountManagementAction.Profile.toRustAction()) .isEqualTo(RustAccountManagementAction.Profile) - assertThat(AccountManagementAction.SessionEnd(A_DEVICE_ID).toRustAction()) + assertThat(AccountManagementAction.DeviceDelete(A_DEVICE_ID).toRustAction()) .isEqualTo(RustAccountManagementAction.DeviceDelete(A_DEVICE_ID.value)) - assertThat(AccountManagementAction.SessionView(A_DEVICE_ID).toRustAction()) + assertThat(AccountManagementAction.DeviceView(A_DEVICE_ID).toRustAction()) .isEqualTo(RustAccountManagementAction.DeviceView(A_DEVICE_ID.value)) - assertThat(AccountManagementAction.SessionsList.toRustAction()) + assertThat(AccountManagementAction.DevicesList.toRustAction()) .isEqualTo(RustAccountManagementAction.DevicesList) } } From 4b61bb1e421b306378fdd5a9a0267abf7c7812d9 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 4 Mar 2026 21:02:37 +0100 Subject: [PATCH 54/60] Fix test --- .../preferences/impl/root/PreferencesRootPresenterTest.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/root/PreferencesRootPresenterTest.kt b/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/root/PreferencesRootPresenterTest.kt index c41550134a..f0dc58ef22 100644 --- a/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/root/PreferencesRootPresenterTest.kt +++ b/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/root/PreferencesRootPresenterTest.kt @@ -101,7 +101,7 @@ class PreferencesRootPresenterTest { listOf(value(AccountManagementAction.DevicesList)), ) assertThat(finalState.accountManagementUrl).isEqualTo("Profile url") - assertThat(finalState.devicesManagementUrl).isEqualTo("SessionsList url") + assertThat(finalState.devicesManagementUrl).isEqualTo("DevicesList url") } } From f1058365cc9515f346bef9a1a5c4f5220a14c58c Mon Sep 17 00:00:00 2001 From: Timur Gilfanov Date: Thu, 5 Mar 2026 10:43:31 +0400 Subject: [PATCH 55/60] Fix Markdown text input losing scroll position while typing --- .../textcomposer/components/markdown/MarkdownTextInput.kt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/components/markdown/MarkdownTextInput.kt b/libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/components/markdown/MarkdownTextInput.kt index 725abe3dae..e3c1fb5dd3 100644 --- a/libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/components/markdown/MarkdownTextInput.kt +++ b/libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/components/markdown/MarkdownTextInput.kt @@ -103,6 +103,9 @@ fun MarkdownTextInput( } addTextChangedListener { editable -> onTyping(!editable.isNullOrEmpty()) + if (state.lineCount != lineCount) { + post { bringPointIntoView(selectionStart) } + } state.text.update(editable, false) state.lineCount = lineCount From 84164ccad1be414a1ff41ca76619436f5524f21d Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 5 Mar 2026 09:48:30 +0000 Subject: [PATCH 56/60] Update dependency org.unifiedpush.android:connector to v3.3.2 --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 537203e6b3..e4fcfb7583 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -202,7 +202,7 @@ sqldelight-driver-jvm = { module = "app.cash.sqldelight:sqlite-driver", version. sqldelight-coroutines = { module = "app.cash.sqldelight:coroutines-extensions", version.ref = "sqldelight" } sqlcipher = "net.zetetic:sqlcipher-android:4.13.0" sqlite = "androidx.sqlite:sqlite-ktx:2.6.2" -unifiedpush = "org.unifiedpush.android:connector:3.3.1" +unifiedpush = "org.unifiedpush.android:connector:3.3.2" 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" } From 4b1a3ac326bbb9a848359a8e30948bffe9f07aaa Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 5 Mar 2026 15:48:52 +0000 Subject: [PATCH 57/60] Update dependency org.matrix.rustcomponents:sdk-android to v26.03.05 --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 8e189d9025..236846169c 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -178,7 +178,7 @@ test_detekt_test = { module = "io.gitlab.arturbosch.detekt:detekt-test", version # https://github.com/matrix-org/matrix-rust-components-kotlin/commits/main/sdk/sdk-android/src/main/kotlin/org/matrix/rustcomponents/sdk/matrix_sdk_ffi.kt # All new features should not be implemented in the pull request that upgrades the version, developers should # only fix API breaks and may add some TODOs. -matrix_sdk = "org.matrix.rustcomponents:sdk-android:26.03.4" +matrix_sdk = "org.matrix.rustcomponents:sdk-android:26.03.05" # Others coil = { module = "io.coil-kt.coil3:coil", version.ref = "coil" } From cb94ff8c01e3bd9e93da31f046307a8cfc1c5858 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 5 Mar 2026 15:49:02 +0000 Subject: [PATCH 58/60] Update plugin ktlint to v14.1.0 --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 8e189d9025..21cd4e903b 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -258,7 +258,7 @@ ksp = { id = "com.google.devtools.ksp", version.ref = "ksp" } # Note: used in DependencyInjectionExtensions.kt metro = { id = "dev.zacsweers.metro", version.ref = "metro" } detekt = { id = "io.gitlab.arturbosch.detekt", version.ref = "detekt" } -ktlint = "org.jlleitschuh.gradle.ktlint:14.0.1" +ktlint = "org.jlleitschuh.gradle.ktlint:14.1.0" dependencygraph = "com.savvasdalkitsis.module-dependency-graph:0.12" dependencycheck = "org.owasp.dependencycheck:12.2.0" dependencyanalysis = { id = "com.autonomousapps.dependency-analysis", version.ref = "dependencyAnalysis" } From fc597688d2fc1c515e4da0776a3f5321c8f940ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jorge=20Mart=C3=ADn?= Date: Fri, 6 Mar 2026 11:25:44 +0100 Subject: [PATCH 59/60] Setting version for the release 26.03.2 --- plugins/src/main/kotlin/Versions.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/src/main/kotlin/Versions.kt b/plugins/src/main/kotlin/Versions.kt index f64ee814bb..4da556e48b 100644 --- a/plugins/src/main/kotlin/Versions.kt +++ b/plugins/src/main/kotlin/Versions.kt @@ -45,7 +45,7 @@ private const val versionMonth = 3 * Release number in the month. Value must be in [0,99]. * Do not update this value. it is updated by the release script. */ -private const val versionReleaseNumber = 0 +private const val versionReleaseNumber = 2 object Versions { /** From b1215e22a16bd5c824f5a889e6af45602672c9ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jorge=20Mart=C3=ADn?= Date: Fri, 6 Mar 2026 11:25:54 +0100 Subject: [PATCH 60/60] Adding fastlane file for version 26.03.2 --- fastlane/metadata/android/en-US/changelogs/202603020.txt | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 fastlane/metadata/android/en-US/changelogs/202603020.txt diff --git a/fastlane/metadata/android/en-US/changelogs/202603020.txt b/fastlane/metadata/android/en-US/changelogs/202603020.txt new file mode 100644 index 0000000000..7a33071c39 --- /dev/null +++ b/fastlane/metadata/android/en-US/changelogs/202603020.txt @@ -0,0 +1,2 @@ +Main changes in this version: fixed an issue that could cause a crash when instantiating the cryptographic database. +Full changelog: https://github.com/element-hq/element-x-android/releases