From 00ee1ce4738a9aa6273adabd6d55f83c42833e0d Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 21 Nov 2024 11:36:48 +0000 Subject: [PATCH 01/96] Update mobile-dev-inc/action-maestro-cloud action to v1.9.7 --- .github/workflows/maestro.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/maestro.yml b/.github/workflows/maestro.yml index 136dfb1f203..74696c9a229 100644 --- a/.github/workflows/maestro.yml +++ b/.github/workflows/maestro.yml @@ -79,7 +79,7 @@ jobs: uses: actions/download-artifact@v4 with: name: elementx-apk-maestro - - uses: mobile-dev-inc/action-maestro-cloud@v1.9.6 + - uses: mobile-dev-inc/action-maestro-cloud@v1.9.7 if: (github.event_name == 'pull_request' && github.event.pull_request.fork == null) || github.event_name == 'workflow_dispatch' with: api-key: ${{ secrets.MAESTRO_CLOUD_API_KEY }} From 6e936ff21923a21148d939bbedc191dc2114c7e2 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 21 Nov 2024 14:53:40 +0100 Subject: [PATCH 02/96] Enable all notification actions. --- .../android/appconfig/NotificationConfig.kt | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/appconfig/src/main/kotlin/io/element/android/appconfig/NotificationConfig.kt b/appconfig/src/main/kotlin/io/element/android/appconfig/NotificationConfig.kt index c5f605e5fe3..e44deeb2f47 100644 --- a/appconfig/src/main/kotlin/io/element/android/appconfig/NotificationConfig.kt +++ b/appconfig/src/main/kotlin/io/element/android/appconfig/NotificationConfig.kt @@ -11,14 +11,20 @@ import android.graphics.Color import androidx.annotation.ColorInt object NotificationConfig { - // TODO EAx Implement and set to true at some point - const val SUPPORT_MARK_AS_READ_ACTION = false + /** + * If set to true, the notification will have a "Mark as read" action. + */ + const val SUPPORT_MARK_AS_READ_ACTION = true - // TODO EAx Implement and set to true at some point - const val SUPPORT_JOIN_DECLINE_INVITE = false + /** + * If set to true, the notification for invitation will have two actions to accept or decline the invite. + */ + const val SUPPORT_JOIN_DECLINE_INVITE = true - // TODO EAx Implement and set to true at some point - const val SUPPORT_QUICK_REPLY_ACTION = false + /** + * If set to true, the notification will have a "Quick reply" action, allow to compose and send a message to the room. + */ + const val SUPPORT_QUICK_REPLY_ACTION = true @ColorInt val NOTIFICATION_ACCENT_COLOR: Int = Color.parseColor("#FF0DBD8B") From 40a0427abdb19c3ca3aba8aa6b35fb31836481d5 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 21 Nov 2024 21:51:19 +0100 Subject: [PATCH 03/96] Fix test --- .../DefaultRoomGroupMessageCreatorTest.kt | 17 ++++++++++++++++- .../factories/DefaultNotificationCreatorTest.kt | 13 +++++++++---- 2 files changed, 25 insertions(+), 5 deletions(-) diff --git a/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/DefaultRoomGroupMessageCreatorTest.kt b/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/DefaultRoomGroupMessageCreatorTest.kt index d0255aa4528..8d17fd3901c 100644 --- a/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/DefaultRoomGroupMessageCreatorTest.kt +++ b/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/DefaultRoomGroupMessageCreatorTest.kt @@ -11,6 +11,7 @@ import android.content.Context import android.os.Build import androidx.core.app.NotificationCompat import com.google.common.truth.Truth.assertThat +import io.element.android.appconfig.NotificationConfig import io.element.android.libraries.matrix.api.media.MediaSource import io.element.android.libraries.matrix.test.A_ROOM_ID import io.element.android.libraries.matrix.test.A_TIMESTAMP @@ -18,6 +19,8 @@ import io.element.android.libraries.matrix.ui.components.aMatrixUser import io.element.android.libraries.matrix.ui.media.AVATAR_THUMBNAIL_SIZE_IN_PIXEL import io.element.android.libraries.matrix.ui.media.MediaRequestData import io.element.android.libraries.push.impl.notifications.factories.createNotificationCreator +import io.element.android.libraries.push.impl.notifications.factories.markAsReadActionTitle +import io.element.android.libraries.push.impl.notifications.factories.quickReplyActionTitle import io.element.android.libraries.push.impl.notifications.fixtures.aNotifiableMessageEvent import io.element.android.libraries.push.test.notifications.FakeImageLoader import io.element.android.services.toolbox.api.sdk.BuildVersionSdkIntProvider @@ -156,6 +159,13 @@ class DefaultRoomGroupMessageCreatorTest { ) assertThat(result.number).isEqualTo(2) assertThat(result.`when`).isEqualTo(A_TIMESTAMP + 10) + val actionTitles = result.actions?.map { it.title } + assertThat(actionTitles).isEqualTo( + listOfNotNull( + markAsReadActionTitle.takeIf { NotificationConfig.SUPPORT_MARK_AS_READ_ACTION }, + quickReplyActionTitle.takeIf { NotificationConfig.SUPPORT_QUICK_REPLY_ACTION }, + ) + ) assertThat(fakeImageLoader.getCoilRequests().size).isEqualTo(0) } @@ -175,7 +185,12 @@ class DefaultRoomGroupMessageCreatorTest { imageLoader = fakeImageLoader.getImageLoader(), existingNotification = null, ) - assertThat(result.actions).isNull() + val actionTitles = result.actions?.map { it.title } + assertThat(actionTitles).isEqualTo( + listOfNotNull( + markAsReadActionTitle.takeIf { NotificationConfig.SUPPORT_MARK_AS_READ_ACTION } + ) + ) assertThat(fakeImageLoader.getCoilRequests().size).isEqualTo(0) } diff --git a/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/factories/DefaultNotificationCreatorTest.kt b/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/factories/DefaultNotificationCreatorTest.kt index 9e2f3c10389..ae8d7f7d0bb 100644 --- a/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/factories/DefaultNotificationCreatorTest.kt +++ b/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/factories/DefaultNotificationCreatorTest.kt @@ -271,6 +271,11 @@ class DefaultNotificationCreatorTest { } } +const val markAsReadActionTitle = "MarkAsReadAction" +const val quickReplyActionTitle = "QuickReplyAction" +const val acceptInvitationActionTitle = "AcceptInvitationAction" +const val rejectInvitationActionTitle = "RejectInvitationAction" + fun createNotificationCreator( context: Context = RuntimeEnvironment.getApplication(), buildMeta: BuildMeta = aBuildMeta(), @@ -291,26 +296,26 @@ fun createNotificationCreator( markAsReadActionFactory = MarkAsReadActionFactory( context = context, actionIds = NotificationActionIds(buildMeta), - stringProvider = FakeStringProvider("MarkAsReadActionFactory"), + stringProvider = FakeStringProvider(markAsReadActionTitle), clock = FakeSystemClock(), ), quickReplyActionFactory = QuickReplyActionFactory( context = context, actionIds = NotificationActionIds(buildMeta), - stringProvider = FakeStringProvider("QuickReplyActionFactory"), + stringProvider = FakeStringProvider(quickReplyActionTitle), clock = FakeSystemClock(), ), bitmapLoader = bitmapLoader, acceptInvitationActionFactory = AcceptInvitationActionFactory( context = context, actionIds = NotificationActionIds(buildMeta), - stringProvider = FakeStringProvider("AcceptInvitationActionFactory"), + stringProvider = FakeStringProvider(acceptInvitationActionTitle), clock = FakeSystemClock(), ), rejectInvitationActionFactory = RejectInvitationActionFactory( context = context, actionIds = NotificationActionIds(buildMeta), - stringProvider = FakeStringProvider("RejectInvitationActionFactory"), + stringProvider = FakeStringProvider(rejectInvitationActionTitle), clock = FakeSystemClock(), ), ) From f01a15d54ad44af14e202862bf4618973b0c044a Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Fri, 22 Nov 2024 14:00:34 +0100 Subject: [PATCH 04/96] Change wording of quick action for invitations. --- .../factories/action/AcceptInvitationActionFactory.kt | 4 ++-- .../factories/action/RejectInvitationActionFactory.kt | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/notifications/factories/action/AcceptInvitationActionFactory.kt b/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/notifications/factories/action/AcceptInvitationActionFactory.kt index ee3d392c1fb..9cc903939f7 100644 --- a/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/notifications/factories/action/AcceptInvitationActionFactory.kt +++ b/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/notifications/factories/action/AcceptInvitationActionFactory.kt @@ -17,6 +17,7 @@ import io.element.android.libraries.push.impl.R import io.element.android.libraries.push.impl.notifications.NotificationActionIds import io.element.android.libraries.push.impl.notifications.NotificationBroadcastReceiver import io.element.android.libraries.push.impl.notifications.model.InviteNotifiableEvent +import io.element.android.libraries.ui.strings.CommonStrings import io.element.android.services.toolbox.api.strings.StringProvider import io.element.android.services.toolbox.api.systemclock.SystemClock import javax.inject.Inject @@ -27,7 +28,6 @@ class AcceptInvitationActionFactory @Inject constructor( private val stringProvider: StringProvider, private val clock: SystemClock, ) { - // offer to type a quick accept button fun create(inviteNotifiableEvent: InviteNotifiableEvent): NotificationCompat.Action { val sessionId = inviteNotifiableEvent.sessionId.value val roomId = inviteNotifiableEvent.roomId.value @@ -44,7 +44,7 @@ class AcceptInvitationActionFactory @Inject constructor( ) return NotificationCompat.Action.Builder( R.drawable.vector_notification_accept_invitation, - stringProvider.getString(R.string.notification_invitation_action_join), + stringProvider.getString(CommonStrings.action_accept), pendingIntent ).build() } diff --git a/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/notifications/factories/action/RejectInvitationActionFactory.kt b/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/notifications/factories/action/RejectInvitationActionFactory.kt index 309acce44cf..271ea0dcc32 100644 --- a/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/notifications/factories/action/RejectInvitationActionFactory.kt +++ b/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/notifications/factories/action/RejectInvitationActionFactory.kt @@ -17,6 +17,7 @@ import io.element.android.libraries.push.impl.R import io.element.android.libraries.push.impl.notifications.NotificationActionIds import io.element.android.libraries.push.impl.notifications.NotificationBroadcastReceiver import io.element.android.libraries.push.impl.notifications.model.InviteNotifiableEvent +import io.element.android.libraries.ui.strings.CommonStrings import io.element.android.services.toolbox.api.strings.StringProvider import io.element.android.services.toolbox.api.systemclock.SystemClock import javax.inject.Inject @@ -41,10 +42,9 @@ class RejectInvitationActionFactory @Inject constructor( intent, PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE ) - return NotificationCompat.Action.Builder( R.drawable.vector_notification_reject_invitation, - stringProvider.getString(R.string.notification_invitation_action_reject), + stringProvider.getString(CommonStrings.action_reject), pendingIntent ).build() } From ab6f4d5b0e72ba2e07a915e55ab2e9e8ce15bba3 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Fri, 22 Nov 2024 14:04:21 +0100 Subject: [PATCH 05/96] Rename const for clarity and convention --- .../io/element/android/appconfig/NotificationConfig.kt | 6 +++--- .../impl/notifications/factories/NotificationCreator.kt | 2 +- .../factories/action/MarkAsReadActionFactory.kt | 2 +- .../factories/action/QuickReplyActionFactory.kt | 2 +- .../notifications/DefaultRoomGroupMessageCreatorTest.kt | 6 +++--- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/appconfig/src/main/kotlin/io/element/android/appconfig/NotificationConfig.kt b/appconfig/src/main/kotlin/io/element/android/appconfig/NotificationConfig.kt index e44deeb2f47..83ea9e3b77d 100644 --- a/appconfig/src/main/kotlin/io/element/android/appconfig/NotificationConfig.kt +++ b/appconfig/src/main/kotlin/io/element/android/appconfig/NotificationConfig.kt @@ -14,17 +14,17 @@ object NotificationConfig { /** * If set to true, the notification will have a "Mark as read" action. */ - const val SUPPORT_MARK_AS_READ_ACTION = true + const val SHOW_MARK_AS_READ_ACTION = true /** * If set to true, the notification for invitation will have two actions to accept or decline the invite. */ - const val SUPPORT_JOIN_DECLINE_INVITE = true + const val SHOW_ACCEPT_AND_DECLINE_INVITE_ACTIONS = true /** * If set to true, the notification will have a "Quick reply" action, allow to compose and send a message to the room. */ - const val SUPPORT_QUICK_REPLY_ACTION = true + const val SHOW_QUICK_REPLY_ACTION = true @ColorInt val NOTIFICATION_ACCENT_COLOR: Int = Color.parseColor("#FF0DBD8B") diff --git a/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/notifications/factories/NotificationCreator.kt b/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/notifications/factories/NotificationCreator.kt index 559322eaaef..b421585ddd0 100755 --- a/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/notifications/factories/NotificationCreator.kt +++ b/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/notifications/factories/NotificationCreator.kt @@ -230,7 +230,7 @@ class DefaultNotificationCreator @Inject constructor( .setSmallIcon(smallIcon) .setColor(accentColor) .apply { - if (NotificationConfig.SUPPORT_JOIN_DECLINE_INVITE) { + if (NotificationConfig.SHOW_ACCEPT_AND_DECLINE_INVITE_ACTIONS) { addAction(rejectInvitationActionFactory.create(inviteNotifiableEvent)) addAction(acceptInvitationActionFactory.create(inviteNotifiableEvent)) } diff --git a/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/notifications/factories/action/MarkAsReadActionFactory.kt b/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/notifications/factories/action/MarkAsReadActionFactory.kt index b77e36cfc00..e6a2594bb83 100644 --- a/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/notifications/factories/action/MarkAsReadActionFactory.kt +++ b/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/notifications/factories/action/MarkAsReadActionFactory.kt @@ -29,7 +29,7 @@ class MarkAsReadActionFactory @Inject constructor( private val clock: SystemClock, ) { fun create(roomInfo: RoomEventGroupInfo): NotificationCompat.Action? { - if (!NotificationConfig.SUPPORT_MARK_AS_READ_ACTION) return null + if (!NotificationConfig.SHOW_MARK_AS_READ_ACTION) return null val sessionId = roomInfo.sessionId.value val roomId = roomInfo.roomId.value val intent = Intent(context, NotificationBroadcastReceiver::class.java) diff --git a/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/notifications/factories/action/QuickReplyActionFactory.kt b/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/notifications/factories/action/QuickReplyActionFactory.kt index 3ada849026a..bced0abd904 100644 --- a/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/notifications/factories/action/QuickReplyActionFactory.kt +++ b/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/notifications/factories/action/QuickReplyActionFactory.kt @@ -34,7 +34,7 @@ class QuickReplyActionFactory @Inject constructor( private val clock: SystemClock, ) { fun create(roomInfo: RoomEventGroupInfo, threadId: ThreadId?): NotificationCompat.Action? { - if (!NotificationConfig.SUPPORT_QUICK_REPLY_ACTION) return null + if (!NotificationConfig.SHOW_QUICK_REPLY_ACTION) return null val sessionId = roomInfo.sessionId val roomId = roomInfo.roomId val replyPendingIntent = buildQuickReplyIntent(sessionId, roomId, threadId) diff --git a/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/DefaultRoomGroupMessageCreatorTest.kt b/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/DefaultRoomGroupMessageCreatorTest.kt index 8d17fd3901c..4f2e254dcdc 100644 --- a/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/DefaultRoomGroupMessageCreatorTest.kt +++ b/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/DefaultRoomGroupMessageCreatorTest.kt @@ -162,8 +162,8 @@ class DefaultRoomGroupMessageCreatorTest { val actionTitles = result.actions?.map { it.title } assertThat(actionTitles).isEqualTo( listOfNotNull( - markAsReadActionTitle.takeIf { NotificationConfig.SUPPORT_MARK_AS_READ_ACTION }, - quickReplyActionTitle.takeIf { NotificationConfig.SUPPORT_QUICK_REPLY_ACTION }, + markAsReadActionTitle.takeIf { NotificationConfig.SHOW_MARK_AS_READ_ACTION }, + quickReplyActionTitle.takeIf { NotificationConfig.SHOW_QUICK_REPLY_ACTION }, ) ) assertThat(fakeImageLoader.getCoilRequests().size).isEqualTo(0) @@ -188,7 +188,7 @@ class DefaultRoomGroupMessageCreatorTest { val actionTitles = result.actions?.map { it.title } assertThat(actionTitles).isEqualTo( listOfNotNull( - markAsReadActionTitle.takeIf { NotificationConfig.SUPPORT_MARK_AS_READ_ACTION } + markAsReadActionTitle.takeIf { NotificationConfig.SHOW_MARK_AS_READ_ACTION } ) ) assertThat(fakeImageLoader.getCoilRequests().size).isEqualTo(0) From 99da8959ac0d50bec99851cb425bc91a18c7f568 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Fri, 22 Nov 2024 14:05:48 +0100 Subject: [PATCH 06/96] Code iteration for parity with other Factories. --- .../impl/notifications/factories/NotificationCreator.kt | 6 ++---- .../factories/action/AcceptInvitationActionFactory.kt | 4 +++- .../factories/action/RejectInvitationActionFactory.kt | 2 ++ 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/notifications/factories/NotificationCreator.kt b/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/notifications/factories/NotificationCreator.kt index b421585ddd0..6788410468a 100755 --- a/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/notifications/factories/NotificationCreator.kt +++ b/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/notifications/factories/NotificationCreator.kt @@ -230,10 +230,8 @@ class DefaultNotificationCreator @Inject constructor( .setSmallIcon(smallIcon) .setColor(accentColor) .apply { - if (NotificationConfig.SHOW_ACCEPT_AND_DECLINE_INVITE_ACTIONS) { - addAction(rejectInvitationActionFactory.create(inviteNotifiableEvent)) - addAction(acceptInvitationActionFactory.create(inviteNotifiableEvent)) - } + addAction(rejectInvitationActionFactory.create(inviteNotifiableEvent)) + addAction(acceptInvitationActionFactory.create(inviteNotifiableEvent)) // Build the pending intent for when the notification is clicked setContentIntent(pendingIntentFactory.createOpenRoomPendingIntent(inviteNotifiableEvent.sessionId, inviteNotifiableEvent.roomId)) diff --git a/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/notifications/factories/action/AcceptInvitationActionFactory.kt b/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/notifications/factories/action/AcceptInvitationActionFactory.kt index 9cc903939f7..9b2cf64a7d4 100644 --- a/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/notifications/factories/action/AcceptInvitationActionFactory.kt +++ b/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/notifications/factories/action/AcceptInvitationActionFactory.kt @@ -11,6 +11,7 @@ import android.app.PendingIntent import android.content.Context import android.content.Intent import androidx.core.app.NotificationCompat +import io.element.android.appconfig.NotificationConfig import io.element.android.libraries.androidutils.uri.createIgnoredUri import io.element.android.libraries.di.ApplicationContext import io.element.android.libraries.push.impl.R @@ -28,7 +29,8 @@ class AcceptInvitationActionFactory @Inject constructor( private val stringProvider: StringProvider, private val clock: SystemClock, ) { - fun create(inviteNotifiableEvent: InviteNotifiableEvent): NotificationCompat.Action { + fun create(inviteNotifiableEvent: InviteNotifiableEvent): NotificationCompat.Action? { + if (!NotificationConfig.SHOW_ACCEPT_AND_DECLINE_INVITE_ACTIONS) return null val sessionId = inviteNotifiableEvent.sessionId.value val roomId = inviteNotifiableEvent.roomId.value val intent = Intent(context, NotificationBroadcastReceiver::class.java) diff --git a/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/notifications/factories/action/RejectInvitationActionFactory.kt b/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/notifications/factories/action/RejectInvitationActionFactory.kt index 271ea0dcc32..d4eb28f1411 100644 --- a/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/notifications/factories/action/RejectInvitationActionFactory.kt +++ b/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/notifications/factories/action/RejectInvitationActionFactory.kt @@ -11,6 +11,7 @@ import android.app.PendingIntent import android.content.Context import android.content.Intent import androidx.core.app.NotificationCompat +import io.element.android.appconfig.NotificationConfig import io.element.android.libraries.androidutils.uri.createIgnoredUri import io.element.android.libraries.di.ApplicationContext import io.element.android.libraries.push.impl.R @@ -29,6 +30,7 @@ class RejectInvitationActionFactory @Inject constructor( private val clock: SystemClock, ) { fun create(inviteNotifiableEvent: InviteNotifiableEvent): NotificationCompat.Action? { + if (!NotificationConfig.SHOW_ACCEPT_AND_DECLINE_INVITE_ACTIONS) return null val sessionId = inviteNotifiableEvent.sessionId.value val roomId = inviteNotifiableEvent.roomId.value val intent = Intent(context, NotificationBroadcastReceiver::class.java) From abbdc934dc8ec6c19e35369a1d55185dd285a46e Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Fri, 22 Nov 2024 14:51:07 +0100 Subject: [PATCH 07/96] Check that action to accept or reject an invitation is added to the notification. --- .../factories/DefaultNotificationCreatorTest.kt | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/factories/DefaultNotificationCreatorTest.kt b/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/factories/DefaultNotificationCreatorTest.kt index ae8d7f7d0bb..ba9bc5e1640 100644 --- a/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/factories/DefaultNotificationCreatorTest.kt +++ b/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/factories/DefaultNotificationCreatorTest.kt @@ -13,6 +13,7 @@ import android.os.Build import androidx.core.app.NotificationCompat import androidx.core.app.NotificationManagerCompat import com.google.common.truth.Truth.assertThat +import io.element.android.appconfig.NotificationConfig import io.element.android.libraries.core.meta.BuildMeta import io.element.android.libraries.matrix.test.AN_EVENT_ID import io.element.android.libraries.matrix.test.A_ROOM_ID @@ -151,6 +152,13 @@ class DefaultNotificationCreatorTest { result.commonAssertions( expectedCategory = null, ) + val actionTitles = result.actions?.map { it.title } + assertThat(actionTitles).isEqualTo( + listOfNotNull( + rejectInvitationActionTitle.takeIf { NotificationConfig.SHOW_ACCEPT_AND_DECLINE_INVITE_ACTIONS }, + acceptInvitationActionTitle.takeIf { NotificationConfig.SHOW_ACCEPT_AND_DECLINE_INVITE_ACTIONS }, + ) + ) } @Test From b271dc550a78c652b50e0e9a51694abd69b17057 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Fri, 22 Nov 2024 15:45:41 +0100 Subject: [PATCH 08/96] naming convention --- .../DefaultRoomGroupMessageCreatorTest.kt | 10 +++++----- .../DefaultNotificationCreatorTest.kt | 20 +++++++++---------- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/DefaultRoomGroupMessageCreatorTest.kt b/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/DefaultRoomGroupMessageCreatorTest.kt index 4f2e254dcdc..44846f80107 100644 --- a/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/DefaultRoomGroupMessageCreatorTest.kt +++ b/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/DefaultRoomGroupMessageCreatorTest.kt @@ -18,9 +18,9 @@ import io.element.android.libraries.matrix.test.A_TIMESTAMP import io.element.android.libraries.matrix.ui.components.aMatrixUser import io.element.android.libraries.matrix.ui.media.AVATAR_THUMBNAIL_SIZE_IN_PIXEL import io.element.android.libraries.matrix.ui.media.MediaRequestData +import io.element.android.libraries.push.impl.notifications.factories.MARK_AS_READ_ACTION_TITLE +import io.element.android.libraries.push.impl.notifications.factories.QUICK_REPLY_ACTION_TITLE import io.element.android.libraries.push.impl.notifications.factories.createNotificationCreator -import io.element.android.libraries.push.impl.notifications.factories.markAsReadActionTitle -import io.element.android.libraries.push.impl.notifications.factories.quickReplyActionTitle import io.element.android.libraries.push.impl.notifications.fixtures.aNotifiableMessageEvent import io.element.android.libraries.push.test.notifications.FakeImageLoader import io.element.android.services.toolbox.api.sdk.BuildVersionSdkIntProvider @@ -162,8 +162,8 @@ class DefaultRoomGroupMessageCreatorTest { val actionTitles = result.actions?.map { it.title } assertThat(actionTitles).isEqualTo( listOfNotNull( - markAsReadActionTitle.takeIf { NotificationConfig.SHOW_MARK_AS_READ_ACTION }, - quickReplyActionTitle.takeIf { NotificationConfig.SHOW_QUICK_REPLY_ACTION }, + MARK_AS_READ_ACTION_TITLE.takeIf { NotificationConfig.SHOW_MARK_AS_READ_ACTION }, + QUICK_REPLY_ACTION_TITLE.takeIf { NotificationConfig.SHOW_QUICK_REPLY_ACTION }, ) ) assertThat(fakeImageLoader.getCoilRequests().size).isEqualTo(0) @@ -188,7 +188,7 @@ class DefaultRoomGroupMessageCreatorTest { val actionTitles = result.actions?.map { it.title } assertThat(actionTitles).isEqualTo( listOfNotNull( - markAsReadActionTitle.takeIf { NotificationConfig.SHOW_MARK_AS_READ_ACTION } + MARK_AS_READ_ACTION_TITLE.takeIf { NotificationConfig.SHOW_MARK_AS_READ_ACTION } ) ) assertThat(fakeImageLoader.getCoilRequests().size).isEqualTo(0) diff --git a/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/factories/DefaultNotificationCreatorTest.kt b/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/factories/DefaultNotificationCreatorTest.kt index ba9bc5e1640..9a25ad2a726 100644 --- a/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/factories/DefaultNotificationCreatorTest.kt +++ b/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/factories/DefaultNotificationCreatorTest.kt @@ -155,8 +155,8 @@ class DefaultNotificationCreatorTest { val actionTitles = result.actions?.map { it.title } assertThat(actionTitles).isEqualTo( listOfNotNull( - rejectInvitationActionTitle.takeIf { NotificationConfig.SHOW_ACCEPT_AND_DECLINE_INVITE_ACTIONS }, - acceptInvitationActionTitle.takeIf { NotificationConfig.SHOW_ACCEPT_AND_DECLINE_INVITE_ACTIONS }, + REJECT_INVITATION_ACTION_TITLE.takeIf { NotificationConfig.SHOW_ACCEPT_AND_DECLINE_INVITE_ACTIONS }, + ACCEPT_INVITATION_ACTION_TITLE.takeIf { NotificationConfig.SHOW_ACCEPT_AND_DECLINE_INVITE_ACTIONS }, ) ) } @@ -279,10 +279,10 @@ class DefaultNotificationCreatorTest { } } -const val markAsReadActionTitle = "MarkAsReadAction" -const val quickReplyActionTitle = "QuickReplyAction" -const val acceptInvitationActionTitle = "AcceptInvitationAction" -const val rejectInvitationActionTitle = "RejectInvitationAction" +const val MARK_AS_READ_ACTION_TITLE = "MarkAsReadAction" +const val QUICK_REPLY_ACTION_TITLE = "QuickReplyAction" +const val ACCEPT_INVITATION_ACTION_TITLE = "AcceptInvitationAction" +const val REJECT_INVITATION_ACTION_TITLE = "RejectInvitationAction" fun createNotificationCreator( context: Context = RuntimeEnvironment.getApplication(), @@ -304,26 +304,26 @@ fun createNotificationCreator( markAsReadActionFactory = MarkAsReadActionFactory( context = context, actionIds = NotificationActionIds(buildMeta), - stringProvider = FakeStringProvider(markAsReadActionTitle), + stringProvider = FakeStringProvider(MARK_AS_READ_ACTION_TITLE), clock = FakeSystemClock(), ), quickReplyActionFactory = QuickReplyActionFactory( context = context, actionIds = NotificationActionIds(buildMeta), - stringProvider = FakeStringProvider(quickReplyActionTitle), + stringProvider = FakeStringProvider(QUICK_REPLY_ACTION_TITLE), clock = FakeSystemClock(), ), bitmapLoader = bitmapLoader, acceptInvitationActionFactory = AcceptInvitationActionFactory( context = context, actionIds = NotificationActionIds(buildMeta), - stringProvider = FakeStringProvider(acceptInvitationActionTitle), + stringProvider = FakeStringProvider(ACCEPT_INVITATION_ACTION_TITLE), clock = FakeSystemClock(), ), rejectInvitationActionFactory = RejectInvitationActionFactory( context = context, actionIds = NotificationActionIds(buildMeta), - stringProvider = FakeStringProvider(rejectInvitationActionTitle), + stringProvider = FakeStringProvider(REJECT_INVITATION_ACTION_TITLE), clock = FakeSystemClock(), ), ) From c1507fb24e77092d589de0b260786ebad5a338ee Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Mon, 25 Nov 2024 14:37:37 +0100 Subject: [PATCH 09/96] Pre-process media during the attachment preview --- .../preview/AttachmentsPreviewPresenter.kt | 133 +++++++++++++++--- .../preview/AttachmentsPreviewState.kt | 1 + .../preview/AttachmentsPreviewView.kt | 15 +- .../AttachmentsPreviewPresenterTest.kt | 125 +++++++++++++++- .../libraries/mediaupload/api/MediaSender.kt | 29 ++++ .../mediaupload/api/MediaUploadInfo.kt | 9 ++ .../mediaupload/test/FakeMediaPreProcessor.kt | 6 +- 7 files changed, 290 insertions(+), 28 deletions(-) diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/attachments/preview/AttachmentsPreviewPresenter.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/attachments/preview/AttachmentsPreviewPresenter.kt index bc3e121070d..c447e2ce5b0 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/attachments/preview/AttachmentsPreviewPresenter.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/attachments/preview/AttachmentsPreviewPresenter.kt @@ -8,6 +8,7 @@ package io.element.android.features.messages.impl.attachments.preview import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.MutableState import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf @@ -19,26 +20,39 @@ import dagger.assisted.AssistedFactory import dagger.assisted.AssistedInject import io.element.android.features.messages.impl.attachments.Attachment import io.element.android.libraries.androidutils.file.TemporaryUriDeleter +import io.element.android.libraries.androidutils.file.safeDelete +import io.element.android.libraries.architecture.AsyncData import io.element.android.libraries.architecture.Presenter +import io.element.android.libraries.featureflag.api.FeatureFlagService +import io.element.android.libraries.featureflag.api.FeatureFlags import io.element.android.libraries.matrix.api.core.ProgressCallback import io.element.android.libraries.matrix.api.permalink.PermalinkBuilder import io.element.android.libraries.mediaupload.api.MediaSender +import io.element.android.libraries.mediaupload.api.MediaUploadInfo +import io.element.android.libraries.mediaupload.api.allFiles import io.element.android.libraries.textcomposer.model.TextEditorState import io.element.android.libraries.textcomposer.model.rememberMarkdownTextEditorState import kotlinx.coroutines.CancellationException import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.Job +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.distinctUntilChanged +import kotlinx.coroutines.flow.filter +import kotlinx.coroutines.flow.flatMapConcat import kotlinx.coroutines.isActive import kotlinx.coroutines.launch import timber.log.Timber import kotlin.coroutines.coroutineContext +@OptIn(ExperimentalCoroutinesApi::class) class AttachmentsPreviewPresenter @AssistedInject constructor( @Assisted private val attachment: Attachment, @Assisted private val onDoneListener: OnDoneListener, private val mediaSender: MediaSender, private val permalinkBuilder: PermalinkBuilder, private val temporaryUriDeleter: TemporaryUriDeleter, + private val featureFlagsService: FeatureFlagService, ) : Presenter { @AssistedFactory interface Factory { @@ -63,19 +77,61 @@ class AttachmentsPreviewPresenter @AssistedInject constructor( val ongoingSendAttachmentJob = remember { mutableStateOf(null) } + val userSentAttachment = remember { + MutableStateFlow(false) + } + + val mediaUploadInfoStateFlow = remember { MutableStateFlow>(AsyncData.Uninitialized) } + var prePropressingJob: Job? = null + LaunchedEffect(Unit) { + prePropressingJob = preProcessAttachment( + attachment, + mediaUploadInfoStateFlow, + ) + } + + LaunchedEffect(Unit) { + userSentAttachment.filter { it } + .flatMapConcat { + mediaUploadInfoStateFlow.filter { it.isReady() } + } + .distinctUntilChanged() + .collect { mediaUploadInfo -> + if (mediaUploadInfo is AsyncData.Success) { + val caption = markdownTextEditorState.getMessageMarkdown(permalinkBuilder) + .takeIf { it.isNotEmpty() } + ongoingSendAttachmentJob.value = coroutineScope.launch { + sendPreProcessedMedia( + mediaUploadInfo = mediaUploadInfo.data, + caption = caption, + sendActionState = sendActionState, + ) + } + } else if (mediaUploadInfo is AsyncData.Failure) { + sendActionState.value = SendActionState.Failure(mediaUploadInfo.error) + } + // else: cannot happen since we filtered with isReady() + } + } + fun handleEvents(attachmentsPreviewEvents: AttachmentsPreviewEvents) { when (attachmentsPreviewEvents) { - is AttachmentsPreviewEvents.SendAttachment -> { - val caption = markdownTextEditorState.getMessageMarkdown(permalinkBuilder) - .takeIf { it.isNotEmpty() } - ongoingSendAttachmentJob.value = coroutineScope.sendAttachment( - attachment = attachment, - caption = caption, - sendActionState = sendActionState, - ) + is AttachmentsPreviewEvents.SendAttachment -> coroutineScope.launch { + val useSendQueue = featureFlagsService.isFeatureEnabled(FeatureFlags.MediaUploadOnSendQueue) + userSentAttachment.value = true + val instantSending = mediaUploadInfoStateFlow.value.isReady() && useSendQueue + sendActionState.value = if (instantSending) { + SendActionState.Sending.InstantSending + } else { + SendActionState.Sending.Processing + } } AttachmentsPreviewEvents.Cancel -> { - coroutineScope.cancel(attachment) + coroutineScope.cancel( + attachment, + prePropressingJob, + mediaUploadInfoStateFlow.value, + ) } AttachmentsPreviewEvents.ClearSendState -> { ongoingSendAttachmentJob.value?.let { @@ -95,56 +151,91 @@ class AttachmentsPreviewPresenter @AssistedInject constructor( ) } - private fun CoroutineScope.sendAttachment( + private fun CoroutineScope.preProcessAttachment( attachment: Attachment, - caption: String?, - sendActionState: MutableState, + mediaUploadInfoState: MutableStateFlow>, ) = launch { when (attachment) { is Attachment.Media -> { - sendMedia( + preProcessMedia( mediaAttachment = attachment, - caption = caption, - sendActionState = sendActionState, + mediaUploadInfoState = mediaUploadInfoState, ) } } } + private suspend fun preProcessMedia( + mediaAttachment: Attachment.Media, + mediaUploadInfoState: MutableStateFlow>, + ) { + mediaUploadInfoState.emit(AsyncData.Loading()) + mediaSender.preProcessMedia( + uri = mediaAttachment.localMedia.uri, + mimeType = mediaAttachment.localMedia.info.mimeType, + ).fold( + onSuccess = { mediaUploadInfo -> + mediaUploadInfoState.emit(AsyncData.Success(mediaUploadInfo)) + }, + onFailure = { + Timber.e(it, "Failed to pre-process media") + if (it is CancellationException) { + throw it + } else { + mediaUploadInfoState.emit(AsyncData.Failure(it)) + } + } + ) + } + private fun CoroutineScope.cancel( attachment: Attachment, + preProcessingJob: Job?, + mediaUploadInfo: AsyncData, ) = launch { // Delete the temporary file when (attachment) { is Attachment.Media -> { temporaryUriDeleter.delete(attachment.localMedia.uri) + preProcessingJob?.cancel() + mediaUploadInfo.dataOrNull()?.let { data -> + cleanUp(data) + } } } onDoneListener() } - private suspend fun sendMedia( - mediaAttachment: Attachment.Media, + private fun cleanUp( + mediaUploadInfo: MediaUploadInfo, + ) { + mediaUploadInfo.allFiles().forEach { file -> + file.safeDelete() + } + } + + private suspend fun sendPreProcessedMedia( + mediaUploadInfo: MediaUploadInfo, caption: String?, sendActionState: MutableState, ) = runCatching { val context = coroutineContext val progressCallback = object : ProgressCallback { override fun onProgress(current: Long, total: Long) { + // Note will not happen if useSendQueue is true if (context.isActive) { sendActionState.value = SendActionState.Sending.Uploading(current.toFloat() / total.toFloat()) } } } - sendActionState.value = SendActionState.Sending.Processing - mediaSender.sendMedia( - uri = mediaAttachment.localMedia.uri, - mimeType = mediaAttachment.localMedia.info.mimeType, + mediaSender.sendPreProcessedMedia( + mediaUploadInfo = mediaUploadInfo, caption = caption, progressCallback = progressCallback ).getOrThrow() }.fold( onSuccess = { + cleanUp(mediaUploadInfo) onDoneListener() }, onFailure = { error -> diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/attachments/preview/AttachmentsPreviewState.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/attachments/preview/AttachmentsPreviewState.kt index 5fed2acfb2e..5d5f058375c 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/attachments/preview/AttachmentsPreviewState.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/attachments/preview/AttachmentsPreviewState.kt @@ -27,6 +27,7 @@ sealed interface SendActionState { @Immutable sealed interface Sending : SendActionState { + data object InstantSending : Sending data object Processing : Sending data class Uploading(val progress: Float) : Sending } diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/attachments/preview/AttachmentsPreviewView.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/attachments/preview/AttachmentsPreviewView.kt index 1380add3298..21450922820 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/attachments/preview/AttachmentsPreviewView.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/attachments/preview/AttachmentsPreviewView.kt @@ -99,12 +99,17 @@ private fun AttachmentSendStateView( onRetryClick: () -> Unit ) { when (sendActionState) { - is SendActionState.Sending -> { + is SendActionState.Sending.Processing -> { ProgressDialog( - type = when (sendActionState) { - is SendActionState.Sending.Uploading -> ProgressDialogType.Determinate(sendActionState.progress) - SendActionState.Sending.Processing -> ProgressDialogType.Indeterminate - }, + type = ProgressDialogType.Indeterminate, + text = stringResource(id = CommonStrings.common_sending), + showCancelButton = true, + onDismissRequest = onDismissClick, + ) + } + is SendActionState.Sending.Uploading -> { + ProgressDialog( + type = ProgressDialogType.Determinate(sendActionState.progress), text = stringResource(id = CommonStrings.common_sending), showCancelButton = true, onDismissRequest = onDismissClick, diff --git a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/attachments/AttachmentsPreviewPresenterTest.kt b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/attachments/AttachmentsPreviewPresenterTest.kt index 4f35c592f14..b1c2fbfcd6f 100644 --- a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/attachments/AttachmentsPreviewPresenterTest.kt +++ b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/attachments/AttachmentsPreviewPresenterTest.kt @@ -20,6 +20,8 @@ import io.element.android.features.messages.impl.attachments.preview.OnDoneListe import io.element.android.features.messages.impl.attachments.preview.SendActionState import io.element.android.features.messages.impl.fixtures.aMediaAttachment import io.element.android.libraries.androidutils.file.TemporaryUriDeleter +import io.element.android.libraries.featureflag.api.FeatureFlags +import io.element.android.libraries.featureflag.test.FakeFeatureFlagService import io.element.android.libraries.matrix.api.core.ProgressCallback import io.element.android.libraries.matrix.api.media.AudioInfo import io.element.android.libraries.matrix.api.media.FileInfo @@ -40,10 +42,12 @@ import io.element.android.libraries.preferences.test.InMemorySessionPreferencesS import io.element.android.tests.testutils.WarmUpRule import io.element.android.tests.testutils.fake.FakeTemporaryUriDeleter 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.value import io.element.android.tests.testutils.test import io.mockk.mockk +import kotlinx.coroutines.CompletableDeferred import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.test.advanceUntilIdle import kotlinx.coroutines.test.runTest @@ -94,6 +98,121 @@ class AttachmentsPreviewPresenterTest { } } + @Test + fun `present - send media after pre-processing success scenario`() = runTest { + val sendFileResult = lambdaRecorder> { _, _, _, _, _ -> + Result.success(FakeMediaUploadHandler()) + } + val room = FakeMatrixRoom( + sendFileResult = sendFileResult, + ) + val onDoneListener = lambdaRecorder { } + val processLatch = CompletableDeferred() + val presenter = createAttachmentsPreviewPresenter( + room = room, + mediaPreProcessor = FakeMediaPreProcessor( + processLatch = processLatch, + ), + onDoneListener = { onDoneListener() }, + ) + moleculeFlow(RecompositionMode.Immediate) { + presenter.present() + }.test { + val initialState = awaitItem() + assertThat(initialState.sendActionState).isEqualTo(SendActionState.Idle) + // Pre-processing finishes + processLatch.complete(Unit) + advanceUntilIdle() + initialState.eventSink(AttachmentsPreviewEvents.SendAttachment) + assertThat(awaitItem().sendActionState).isEqualTo(SendActionState.Sending.InstantSending) + advanceUntilIdle() + sendFileResult.assertions().isCalledOnce() + onDoneListener.assertions().isCalledOnce() + } + } + + @Test + fun `present - send media before pre-processing success scenario`() = runTest { + val sendFileResult = lambdaRecorder> { _, _, _, _, _ -> + Result.success(FakeMediaUploadHandler()) + } + val room = FakeMatrixRoom( + sendFileResult = sendFileResult, + ) + val onDoneListener = lambdaRecorder { } + val processLatch = CompletableDeferred() + val presenter = createAttachmentsPreviewPresenter( + room = room, + mediaPreProcessor = FakeMediaPreProcessor( + processLatch = processLatch, + ), + onDoneListener = { onDoneListener() }, + ) + moleculeFlow(RecompositionMode.Immediate) { + presenter.present() + }.test { + val initialState = awaitItem() + assertThat(initialState.sendActionState).isEqualTo(SendActionState.Idle) + initialState.eventSink(AttachmentsPreviewEvents.SendAttachment) + assertThat(awaitItem().sendActionState).isEqualTo(SendActionState.Sending.Processing) + // Pre-processing finishes + processLatch.complete(Unit) + advanceUntilIdle() + sendFileResult.assertions().isCalledOnce() + onDoneListener.assertions().isCalledOnce() + } + } + + @Test + fun `present - send media with pre-processing failure after user sends media`() = runTest { + val room = FakeMatrixRoom() + val onDoneListener = lambdaRecorder { } + val processLatch = CompletableDeferred() + val presenter = createAttachmentsPreviewPresenter( + room = room, + mediaPreProcessor = FakeMediaPreProcessor().apply { + givenResult(Result.failure(Exception())) + }, + onDoneListener = { onDoneListener() }, + ) + moleculeFlow(RecompositionMode.Immediate) { + presenter.present() + }.test { + val initialState = awaitItem() + assertThat(initialState.sendActionState).isEqualTo(SendActionState.Idle) + initialState.eventSink(AttachmentsPreviewEvents.SendAttachment) + assertThat(awaitItem().sendActionState).isEqualTo(SendActionState.Sending.Processing) + // Pre-processing finishes + processLatch.complete(Unit) + assertThat(awaitItem().sendActionState).isInstanceOf(SendActionState.Failure::class.java) + } + } + + @Test + fun `present - send media with pre-processing failure before user sends media`() = runTest { + val room = FakeMatrixRoom() + val onDoneListener = lambdaRecorder { } + val processLatch = CompletableDeferred() + val presenter = createAttachmentsPreviewPresenter( + room = room, + mediaPreProcessor = FakeMediaPreProcessor().apply { + givenResult(Result.failure(Exception())) + }, + onDoneListener = { onDoneListener() }, + ) + moleculeFlow(RecompositionMode.Immediate) { + presenter.present() + }.test { + val initialState = awaitItem() + assertThat(initialState.sendActionState).isEqualTo(SendActionState.Idle) + // Pre-processing finishes + processLatch.complete(Unit) + advanceUntilIdle() + initialState.eventSink(AttachmentsPreviewEvents.SendAttachment) + assertThat(awaitItem().sendActionState).isInstanceOf(SendActionState.Failure::class.java) + } + } + @Test fun `present - cancel scenario`() = runTest { val onDoneListener = lambdaRecorder { } @@ -277,7 +396,8 @@ class AttachmentsPreviewPresenterTest { permalinkBuilder: PermalinkBuilder = FakePermalinkBuilder(), mediaPreProcessor: MediaPreProcessor = FakeMediaPreProcessor(), temporaryUriDeleter: TemporaryUriDeleter = FakeTemporaryUriDeleter(), - onDoneListener: OnDoneListener = OnDoneListener {}, + onDoneListener: OnDoneListener = OnDoneListener { lambdaError() }, + mediaUploadOnSendQueueEnabled: Boolean = true, ): AttachmentsPreviewPresenter { return AttachmentsPreviewPresenter( attachment = aMediaAttachment(localMedia), @@ -285,6 +405,9 @@ class AttachmentsPreviewPresenterTest { mediaSender = MediaSender(mediaPreProcessor, room, InMemorySessionPreferencesStore()), permalinkBuilder = permalinkBuilder, temporaryUriDeleter = temporaryUriDeleter, + featureFlagsService = FakeFeatureFlagService( + initialState = mapOf(FeatureFlags.MediaUploadOnSendQueue.key to mediaUploadOnSendQueueEnabled), + ) ) } } diff --git a/libraries/mediaupload/api/src/main/kotlin/io/element/android/libraries/mediaupload/api/MediaSender.kt b/libraries/mediaupload/api/src/main/kotlin/io/element/android/libraries/mediaupload/api/MediaSender.kt index 77e6d021d50..567315f9db0 100644 --- a/libraries/mediaupload/api/src/main/kotlin/io/element/android/libraries/mediaupload/api/MediaSender.kt +++ b/libraries/mediaupload/api/src/main/kotlin/io/element/android/libraries/mediaupload/api/MediaSender.kt @@ -27,6 +27,35 @@ class MediaSender @Inject constructor( private val ongoingUploadJobs = ConcurrentHashMap() val hasOngoingMediaUploads get() = ongoingUploadJobs.isNotEmpty() + suspend fun preProcessMedia( + uri: Uri, + mimeType: String, + ): Result { + val compressIfPossible = sessionPreferencesStore.doesCompressMedia().first() + return preProcessor + .process( + uri = uri, + mimeType = mimeType, + deleteOriginal = false, + compressIfPossible = compressIfPossible, + ) + } + + suspend fun sendPreProcessedMedia( + mediaUploadInfo: MediaUploadInfo, + caption: String? = null, + formattedCaption: String? = null, + progressCallback: ProgressCallback? = null + ): Result { + return room.sendMedia( + uploadInfo = mediaUploadInfo, + progressCallback = progressCallback, + caption = caption, + formattedCaption = formattedCaption + ) + .handleSendResult() + } + suspend fun sendMedia( uri: Uri, mimeType: String, diff --git a/libraries/mediaupload/api/src/main/kotlin/io/element/android/libraries/mediaupload/api/MediaUploadInfo.kt b/libraries/mediaupload/api/src/main/kotlin/io/element/android/libraries/mediaupload/api/MediaUploadInfo.kt index 279acd1719f..f9786b9b4f9 100644 --- a/libraries/mediaupload/api/src/main/kotlin/io/element/android/libraries/mediaupload/api/MediaUploadInfo.kt +++ b/libraries/mediaupload/api/src/main/kotlin/io/element/android/libraries/mediaupload/api/MediaUploadInfo.kt @@ -22,3 +22,12 @@ sealed interface MediaUploadInfo { data class VoiceMessage(override val file: File, val audioInfo: AudioInfo, val waveform: List) : MediaUploadInfo data class AnyFile(override val file: File, val fileInfo: FileInfo) : MediaUploadInfo } + +fun MediaUploadInfo.allFiles(): List { + return listOfNotNull( + file, + (this@allFiles as? MediaUploadInfo.Image)?.thumbnailFile, + (this@allFiles as? MediaUploadInfo.Video)?.thumbnailFile, + ) +} + diff --git a/libraries/mediaupload/test/src/main/kotlin/io/element/android/libraries/mediaupload/test/FakeMediaPreProcessor.kt b/libraries/mediaupload/test/src/main/kotlin/io/element/android/libraries/mediaupload/test/FakeMediaPreProcessor.kt index efb3b77ed81..3ec4efcfaa0 100644 --- a/libraries/mediaupload/test/src/main/kotlin/io/element/android/libraries/mediaupload/test/FakeMediaPreProcessor.kt +++ b/libraries/mediaupload/test/src/main/kotlin/io/element/android/libraries/mediaupload/test/FakeMediaPreProcessor.kt @@ -16,10 +16,13 @@ import io.element.android.libraries.matrix.api.media.VideoInfo import io.element.android.libraries.mediaupload.api.MediaPreProcessor import io.element.android.libraries.mediaupload.api.MediaUploadInfo import io.element.android.tests.testutils.simulateLongTask +import kotlinx.coroutines.CompletableDeferred import java.io.File import kotlin.time.Duration.Companion.seconds -class FakeMediaPreProcessor : MediaPreProcessor { +class FakeMediaPreProcessor( + private val processLatch: CompletableDeferred? = null, +) : MediaPreProcessor { var processCallCount = 0 private set @@ -41,6 +44,7 @@ class FakeMediaPreProcessor : MediaPreProcessor { deleteOriginal: Boolean, compressIfPossible: Boolean ): Result = simulateLongTask { + processLatch?.await() processCallCount++ result } From 9a1f36409d6f05f7a4eeb41182394d30ce23dba8 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Mon, 25 Nov 2024 17:18:07 +0100 Subject: [PATCH 10/96] Close the progress dialog when the treatment is over (avoid UI glitch) --- .../preview/AttachmentsPreviewPresenter.kt | 6 ++++++ .../attachments/preview/AttachmentsPreviewState.kt | 1 + .../attachments/AttachmentsPreviewPresenterTest.kt | 13 +++++++------ 3 files changed, 14 insertions(+), 6 deletions(-) diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/attachments/preview/AttachmentsPreviewPresenter.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/attachments/preview/AttachmentsPreviewPresenter.kt index c447e2ce5b0..a4482514b73 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/attachments/preview/AttachmentsPreviewPresenter.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/attachments/preview/AttachmentsPreviewPresenter.kt @@ -131,6 +131,7 @@ class AttachmentsPreviewPresenter @AssistedInject constructor( attachment, prePropressingJob, mediaUploadInfoStateFlow.value, + sendActionState, ) } AttachmentsPreviewEvents.ClearSendState -> { @@ -192,6 +193,7 @@ class AttachmentsPreviewPresenter @AssistedInject constructor( attachment: Attachment, preProcessingJob: Job?, mediaUploadInfo: AsyncData, + sendActionState: MutableState, ) = launch { // Delete the temporary file when (attachment) { @@ -203,6 +205,8 @@ class AttachmentsPreviewPresenter @AssistedInject constructor( } } } + // Reset the sendActionState to ensure that dialog is closed before the screen + sendActionState.value = SendActionState.Done onDoneListener() } @@ -236,6 +240,8 @@ class AttachmentsPreviewPresenter @AssistedInject constructor( }.fold( onSuccess = { cleanUp(mediaUploadInfo) + // Reset the sendActionState to ensure that dialog is closed before the screen + sendActionState.value = SendActionState.Done onDoneListener() }, onFailure = { error -> diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/attachments/preview/AttachmentsPreviewState.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/attachments/preview/AttachmentsPreviewState.kt index 5d5f058375c..0e9724c4606 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/attachments/preview/AttachmentsPreviewState.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/attachments/preview/AttachmentsPreviewState.kt @@ -33,4 +33,5 @@ sealed interface SendActionState { } data class Failure(val error: Throwable) : SendActionState + data object Done : SendActionState } diff --git a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/attachments/AttachmentsPreviewPresenterTest.kt b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/attachments/AttachmentsPreviewPresenterTest.kt index b1c2fbfcd6f..204a5b5b761 100644 --- a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/attachments/AttachmentsPreviewPresenterTest.kt +++ b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/attachments/AttachmentsPreviewPresenterTest.kt @@ -92,7 +92,7 @@ class AttachmentsPreviewPresenterTest { assertThat(awaitItem().sendActionState).isEqualTo(SendActionState.Sending.Uploading(0f)) assertThat(awaitItem().sendActionState).isEqualTo(SendActionState.Sending.Uploading(0.5f)) assertThat(awaitItem().sendActionState).isEqualTo(SendActionState.Sending.Uploading(1f)) - advanceUntilIdle() + assertThat(awaitItem().sendActionState).isEqualTo(SendActionState.Done) sendFileResult.assertions().isCalledOnce() onDoneListener.assertions().isCalledOnce() } @@ -125,7 +125,7 @@ class AttachmentsPreviewPresenterTest { advanceUntilIdle() initialState.eventSink(AttachmentsPreviewEvents.SendAttachment) assertThat(awaitItem().sendActionState).isEqualTo(SendActionState.Sending.InstantSending) - advanceUntilIdle() + assertThat(awaitItem().sendActionState).isEqualTo(SendActionState.Done) sendFileResult.assertions().isCalledOnce() onDoneListener.assertions().isCalledOnce() } @@ -157,7 +157,7 @@ class AttachmentsPreviewPresenterTest { assertThat(awaitItem().sendActionState).isEqualTo(SendActionState.Sending.Processing) // Pre-processing finishes processLatch.complete(Unit) - advanceUntilIdle() + assertThat(awaitItem().sendActionState).isEqualTo(SendActionState.Done) sendFileResult.assertions().isCalledOnce() onDoneListener.assertions().isCalledOnce() } @@ -227,6 +227,7 @@ class AttachmentsPreviewPresenterTest { val initialState = awaitItem() assertThat(initialState.sendActionState).isEqualTo(SendActionState.Idle) initialState.eventSink(AttachmentsPreviewEvents.Cancel) + assertThat(awaitItem().sendActionState).isEqualTo(SendActionState.Done) deleteCallback.assertions().isCalledOnce() onDoneListener.assertions().isCalledOnce() } @@ -258,7 +259,7 @@ class AttachmentsPreviewPresenterTest { initialState.textEditorState.setMarkdown(A_CAPTION) initialState.eventSink(AttachmentsPreviewEvents.SendAttachment) assertThat(awaitItem().sendActionState).isEqualTo(SendActionState.Sending.Processing) - advanceUntilIdle() + assertThat(awaitItem().sendActionState).isEqualTo(SendActionState.Done) sendImageResult.assertions().isCalledOnce().with( any(), any(), @@ -297,7 +298,7 @@ class AttachmentsPreviewPresenterTest { initialState.textEditorState.setMarkdown(A_CAPTION) initialState.eventSink(AttachmentsPreviewEvents.SendAttachment) assertThat(awaitItem().sendActionState).isEqualTo(SendActionState.Sending.Processing) - advanceUntilIdle() + assertThat(awaitItem().sendActionState).isEqualTo(SendActionState.Done) sendVideoResult.assertions().isCalledOnce().with( any(), any(), @@ -334,7 +335,7 @@ class AttachmentsPreviewPresenterTest { initialState.textEditorState.setMarkdown(A_CAPTION) initialState.eventSink(AttachmentsPreviewEvents.SendAttachment) assertThat(awaitItem().sendActionState).isEqualTo(SendActionState.Sending.Processing) - advanceUntilIdle() + assertThat(awaitItem().sendActionState).isEqualTo(SendActionState.Done) sendAudioResult.assertions().isCalledOnce().with( any(), any(), From 79208eb83ffc736e203df12f0f09d3cee7c4bede Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 25 Nov 2024 20:23:41 +0000 Subject: [PATCH 11/96] Update plugin ktlint to v12.1.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 7d29344cbc8..5eafe2f7ea8 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -233,7 +233,7 @@ kapt = { id = "org.jetbrains.kotlin.kapt", version.ref = "kotlin" } ksp = { id = "com.google.devtools.ksp", version.ref = "ksp" } anvil = { id = "dev.zacsweers.anvil", version.ref = "anvil" } detekt = "io.gitlab.arturbosch.detekt:1.23.7" -ktlint = "org.jlleitschuh.gradle.ktlint:12.1.1" +ktlint = "org.jlleitschuh.gradle.ktlint:12.1.2" dependencygraph = "com.savvasdalkitsis.module-dependency-graph:0.12" dependencycheck = "org.owasp.dependencycheck:11.1.0" dependencyanalysis = { id = "com.autonomousapps.dependency-analysis", version.ref = "dependencyAnalysis" } From 984487e81b960acd2caf052f21900057f1a0a236 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 26 Nov 2024 03:27:08 +0000 Subject: [PATCH 12/96] Update dependency com.lemonappdev:konsist to v0.17.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 7d29344cbc8..6ef4e632cea 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -150,7 +150,7 @@ test_arch_core = "androidx.arch.core:core-testing:2.2.0" test_junit = "junit:junit:4.13.2" test_runner = "androidx.test:runner:1.6.2" test_mockk = "io.mockk:mockk:1.13.13" -test_konsist = "com.lemonappdev:konsist:0.16.1" +test_konsist = "com.lemonappdev:konsist:0.17.0" test_turbine = "app.cash.turbine:turbine:1.2.0" test_truth = "com.google.truth:truth:1.4.4" test_parameter_injector = "com.google.testparameterinjector:test-parameter-injector:1.18" From b9caede2d3620e696a337c6c5bb342430890b0d4 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Tue, 26 Nov 2024 09:17:39 +0100 Subject: [PATCH 13/96] Remove blank line --- .../element/android/libraries/mediaupload/api/MediaUploadInfo.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/libraries/mediaupload/api/src/main/kotlin/io/element/android/libraries/mediaupload/api/MediaUploadInfo.kt b/libraries/mediaupload/api/src/main/kotlin/io/element/android/libraries/mediaupload/api/MediaUploadInfo.kt index f9786b9b4f9..dfc36a40f52 100644 --- a/libraries/mediaupload/api/src/main/kotlin/io/element/android/libraries/mediaupload/api/MediaUploadInfo.kt +++ b/libraries/mediaupload/api/src/main/kotlin/io/element/android/libraries/mediaupload/api/MediaUploadInfo.kt @@ -30,4 +30,3 @@ fun MediaUploadInfo.allFiles(): List { (this@allFiles as? MediaUploadInfo.Video)?.thumbnailFile, ) } - From 008a554ca68c0b30e7d2ad48e31d750c5267dae4 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Tue, 26 Nov 2024 09:18:11 +0100 Subject: [PATCH 14/96] Remove default parameter values. This improve code coverage since some default value was never used. --- .../impl/attachments/preview/AttachmentsPreviewPresenter.kt | 1 + .../android/libraries/mediaupload/api/MediaSender.kt | 6 +++--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/attachments/preview/AttachmentsPreviewPresenter.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/attachments/preview/AttachmentsPreviewPresenter.kt index a4482514b73..f87ea3fb24e 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/attachments/preview/AttachmentsPreviewPresenter.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/attachments/preview/AttachmentsPreviewPresenter.kt @@ -235,6 +235,7 @@ class AttachmentsPreviewPresenter @AssistedInject constructor( mediaSender.sendPreProcessedMedia( mediaUploadInfo = mediaUploadInfo, caption = caption, + formattedCaption = null, progressCallback = progressCallback ).getOrThrow() }.fold( diff --git a/libraries/mediaupload/api/src/main/kotlin/io/element/android/libraries/mediaupload/api/MediaSender.kt b/libraries/mediaupload/api/src/main/kotlin/io/element/android/libraries/mediaupload/api/MediaSender.kt index 567315f9db0..b9618d86ddd 100644 --- a/libraries/mediaupload/api/src/main/kotlin/io/element/android/libraries/mediaupload/api/MediaSender.kt +++ b/libraries/mediaupload/api/src/main/kotlin/io/element/android/libraries/mediaupload/api/MediaSender.kt @@ -43,9 +43,9 @@ class MediaSender @Inject constructor( suspend fun sendPreProcessedMedia( mediaUploadInfo: MediaUploadInfo, - caption: String? = null, - formattedCaption: String? = null, - progressCallback: ProgressCallback? = null + caption: String?, + formattedCaption: String?, + progressCallback: ProgressCallback?, ): Result { return room.sendMedia( uploadInfo = mediaUploadInfo, From 1087ad6a1652b6c24b2fbfe45dc9f44caf3ac69d Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Tue, 26 Nov 2024 09:19:26 +0100 Subject: [PATCH 15/96] Add preview for the Processing state. --- .../impl/attachments/preview/AttachmentsPreviewStateProvider.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/attachments/preview/AttachmentsPreviewStateProvider.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/attachments/preview/AttachmentsPreviewStateProvider.kt index 78f3ffc81ad..1c55245e469 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/attachments/preview/AttachmentsPreviewStateProvider.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/attachments/preview/AttachmentsPreviewStateProvider.kt @@ -26,6 +26,7 @@ open class AttachmentsPreviewStateProvider : PreviewParameterProvider Date: Tue, 26 Nov 2024 08:34:11 +0000 Subject: [PATCH 16/96] Update screenshots --- ...messages.impl.attachments.preview_AttachmentsView_4_en.png | 4 ++-- ...messages.impl.attachments.preview_AttachmentsView_5_en.png | 4 ++-- ...messages.impl.attachments.preview_AttachmentsView_6_en.png | 3 +++ 3 files changed, 7 insertions(+), 4 deletions(-) create mode 100644 tests/uitests/src/test/snapshots/images/features.messages.impl.attachments.preview_AttachmentsView_6_en.png diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.attachments.preview_AttachmentsView_4_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.attachments.preview_AttachmentsView_4_en.png index e799726c52b..8510d977be9 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.attachments.preview_AttachmentsView_4_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.attachments.preview_AttachmentsView_4_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:361ff23fd2ff99aecfdffd10b45e9235d86183d4856cb2a3e99f85b9e04c2d59 -size 51376 +oid sha256:3a92cb782d97553f364fab3df3fe159557a26aad8b7e5c176b40616c2f05abdd +size 51410 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.attachments.preview_AttachmentsView_5_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.attachments.preview_AttachmentsView_5_en.png index df965394aa5..e799726c52b 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.attachments.preview_AttachmentsView_5_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.attachments.preview_AttachmentsView_5_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:efbfed755b29293009f45fca33f58863b612772de9a1d55593c979dbb04ff6f2 -size 88981 +oid sha256:361ff23fd2ff99aecfdffd10b45e9235d86183d4856cb2a3e99f85b9e04c2d59 +size 51376 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.attachments.preview_AttachmentsView_6_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.attachments.preview_AttachmentsView_6_en.png new file mode 100644 index 00000000000..df965394aa5 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.attachments.preview_AttachmentsView_6_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:efbfed755b29293009f45fca33f58863b612772de9a1d55593c979dbb04ff6f2 +size 88981 From c433bab0a8d06e94b988a2cffbc42449ffd01cd2 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Tue, 26 Nov 2024 10:15:53 +0100 Subject: [PATCH 17/96] Ensure `Sealed interface used in Composable MUST be Immutable or Stable` is detecting error by adding a failing case. --- ...mposableWithNonImmutableSealedInterface.kt | 20 +++++++++++++++++++ .../tests/konsist/KonsistArchitectureTest.kt | 12 +++++++++-- 2 files changed, 30 insertions(+), 2 deletions(-) create mode 100644 tests/konsist/src/main/kotlin/io/element/android/tests/konsist/failures/FailingComposableWithNonImmutableSealedInterface.kt diff --git a/tests/konsist/src/main/kotlin/io/element/android/tests/konsist/failures/FailingComposableWithNonImmutableSealedInterface.kt b/tests/konsist/src/main/kotlin/io/element/android/tests/konsist/failures/FailingComposableWithNonImmutableSealedInterface.kt new file mode 100644 index 00000000000..1e90577ca66 --- /dev/null +++ b/tests/konsist/src/main/kotlin/io/element/android/tests/konsist/failures/FailingComposableWithNonImmutableSealedInterface.kt @@ -0,0 +1,20 @@ +/* + * Copyright 2024 New Vector Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only + * Please see LICENSE in the repository root for full details. + */ + +package io.element.android.tests.konsist.failures + +import androidx.compose.runtime.Composable + +// Make test `Sealed interface used in Composable MUST be Immutable or Stable` fails + +sealed interface SealedInterface + +@Composable +fun FailingComposableWithNonImmutableSealedInterface( + sealedInterface: SealedInterface +) { +} diff --git a/tests/konsist/src/test/kotlin/io/element/android/tests/konsist/KonsistArchitectureTest.kt b/tests/konsist/src/test/kotlin/io/element/android/tests/konsist/KonsistArchitectureTest.kt index 7cc848d825f..365449a91d4 100644 --- a/tests/konsist/src/test/kotlin/io/element/android/tests/konsist/KonsistArchitectureTest.kt +++ b/tests/konsist/src/test/kotlin/io/element/android/tests/konsist/KonsistArchitectureTest.kt @@ -22,6 +22,7 @@ import com.lemonappdev.konsist.api.ext.list.withoutName import com.lemonappdev.konsist.api.ext.list.withoutParents import com.lemonappdev.konsist.api.verify.assertEmpty import com.lemonappdev.konsist.api.verify.assertTrue +import org.junit.Assert.assertTrue import org.junit.Test class KonsistArchitectureTest { @@ -66,18 +67,18 @@ class KonsistArchitectureTest { @Test fun `Sealed interface used in Composable MUST be Immutable or Stable`() { + var failingTestFound = false // List all sealed interface without Immutable nor Stable annotation in the project val forbiddenInterfacesForComposableParameter = Konsist.scopeFromProject() .interfaces() .withSealedModifier() .withoutAnnotationOf(Immutable::class, Stable::class) .map { it.fullyQualifiedName } - Konsist.scopeFromProject() .functions() .withAnnotationOf(Composable::class) .assertTrue(additionalMessage = "Consider adding the @Immutable or @Stable annotation to the sealed interface") { - it.parameters.all { param -> + val result = it.parameters.all { param -> val type = param.type.text return@all if (type.startsWith("@") || type.startsWith("(") || type.startsWith("suspend")) { true @@ -94,6 +95,13 @@ class KonsistArchitectureTest { fullyQualifiedName !in forbiddenInterfacesForComposableParameter } } + if (!result && !failingTestFound && it.name == "FailingComposableWithNonImmutableSealedInterface") { + failingTestFound = true + true + } else { + result + } } + assertTrue("FailingComposableWithNonImmutableSealedInterface should make this test fail.", failingTestFound) } } From 1b490488a27e1fe23b0fe39e233fafb82e45cc56 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Tue, 26 Nov 2024 10:29:54 +0100 Subject: [PATCH 18/96] Exclude non-prod code from quality checks. --- build.gradle.kts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/build.gradle.kts b/build.gradle.kts index 187b09de548..31edb5b08cc 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -52,6 +52,10 @@ allprojects { detektPlugins("io.nlopez.compose.rules:detekt:0.4.19") } + tasks.withType().configureEach { + exclude("io/element/android/tests/konsist/failures/**") + } + // KtLint apply { plugin("org.jlleitschuh.gradle.ktlint") @@ -75,6 +79,7 @@ allprojects { val generatedPath = "${layout.buildDirectory.asFile.get()}/generated/" filter { exclude { element -> element.file.path.contains(generatedPath) } + exclude("io/element/android/tests/konsist/failures/**") } } // Dependency check From c16015eefb547d2273aed8634326217e7abeb88f Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 26 Nov 2024 09:31:58 +0000 Subject: [PATCH 19/96] Update wysiwyg to v2.37.14 (#3948) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Update wysiwyg to v2.37.14 * Add needed `isEditor` parameter to `DefaultHtmlConverterProvider` --------- Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Co-authored-by: Jorge Martín --- .../messages/impl/timeline/DefaultHtmlConverterProvider.kt | 1 + gradle/libs.versions.toml | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/DefaultHtmlConverterProvider.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/DefaultHtmlConverterProvider.kt index 5aab1a5bf1e..2234aa09a91 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/DefaultHtmlConverterProvider.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/DefaultHtmlConverterProvider.kt @@ -63,6 +63,7 @@ class DefaultHtmlConverterProvider @Inject constructor( return TextDisplay.Custom(mentionSpan) } }, + isEditor = false, isMention = { _, url -> mentionDetector?.isMention(url).orFalse() } ).apply { configureWith(editorStyle) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 5eafe2f7ea8..b6ffa887e06 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -46,7 +46,7 @@ coil = "2.7.0" showkase = "1.0.3" appyx = "1.5.1" sqldelight = "2.0.2" -wysiwyg = "2.37.13" +wysiwyg = "2.37.14" telephoto = "0.14.0" # Dependency analysis From 878bd29b67572cc9d85f80df06b047ee830e9d80 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Tue, 26 Nov 2024 10:48:01 +0100 Subject: [PATCH 20/96] Ensure `Fake classes must be named using Fake and the interface it fakes` is detecting error by adding failing cases. --- .../konsist/failures/FakeWrongClassName.kt | 22 +++++++++++++++++++ .../tests/konsist/KonsistClassNameTest.kt | 14 +++++++++++- 2 files changed, 35 insertions(+), 1 deletion(-) create mode 100644 tests/konsist/src/main/kotlin/io/element/android/tests/konsist/failures/FakeWrongClassName.kt diff --git a/tests/konsist/src/main/kotlin/io/element/android/tests/konsist/failures/FakeWrongClassName.kt b/tests/konsist/src/main/kotlin/io/element/android/tests/konsist/failures/FakeWrongClassName.kt new file mode 100644 index 00000000000..68ea557b534 --- /dev/null +++ b/tests/konsist/src/main/kotlin/io/element/android/tests/konsist/failures/FakeWrongClassName.kt @@ -0,0 +1,22 @@ +/* + * Copyright 2024 New Vector Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only + * Please see LICENSE in the repository root for full details. + */ + +package io.element.android.tests.konsist.failures + +// Make test `Fake classes must be named using Fake and the interface it fakes` fails + +interface MyInterface + +// This class should be named FakeMyInterface +class FakeWrongClassName : MyInterface + +class MyClass { + interface MyFactory +} + +// This class should be named FakeMyClassMyFactory +class FakeWrongClassSubInterfaceName : MyClass.MyFactory diff --git a/tests/konsist/src/test/kotlin/io/element/android/tests/konsist/KonsistClassNameTest.kt b/tests/konsist/src/test/kotlin/io/element/android/tests/konsist/KonsistClassNameTest.kt index adc2b9ceb75..cc76c3fedde 100644 --- a/tests/konsist/src/test/kotlin/io/element/android/tests/konsist/KonsistClassNameTest.kt +++ b/tests/konsist/src/test/kotlin/io/element/android/tests/konsist/KonsistClassNameTest.kt @@ -73,6 +73,11 @@ class KonsistClassNameTest { @Test fun `Fake classes must be named using Fake and the interface it fakes`() { + var failingCases = 0 + val failingCasesList = listOf( + "FakeWrongClassName", + "FakeWrongClassSubInterfaceName", + ) Konsist.scopeFromProject() .classes() .withNameContaining("Fake") @@ -84,7 +89,7 @@ class KonsistClassNameTest { val interfaceName = it.name .replace("FakeRust", "") .replace("Fake", "") - (it.name.startsWith("Fake") || it.name.startsWith("FakeRust")) && + val result = (it.name.startsWith("Fake") || it.name.startsWith("FakeRust")) && it.parents().any { parent -> // Workaround to get the parent name. For instance: // parent.name used to return `UserListPresenter.Factory` but is now returning `Factory`. @@ -93,7 +98,14 @@ class KonsistClassNameTest { val parentName = parent.fullyQualifiedName!!.substringAfter("$packageName.").replace(".", "") parentName == interfaceName } + if (!result && it.name in failingCasesList) { + failingCases++ + true + } else { + result + } } + assertThat(failingCases).isEqualTo(failingCasesList.size) } @Test From e261f6f36ec1b07c32f9465689da9188519c3c3b Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Tue, 26 Nov 2024 11:09:38 +0100 Subject: [PATCH 21/96] Fix API break in `Fake classes must be named using Fake and the interface it fakes` It seems that the workaround is not necessary anymore. --- .../element/android/tests/konsist/KonsistClassNameTest.kt | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/tests/konsist/src/test/kotlin/io/element/android/tests/konsist/KonsistClassNameTest.kt b/tests/konsist/src/test/kotlin/io/element/android/tests/konsist/KonsistClassNameTest.kt index cc76c3fedde..9d8e23e7dc3 100644 --- a/tests/konsist/src/test/kotlin/io/element/android/tests/konsist/KonsistClassNameTest.kt +++ b/tests/konsist/src/test/kotlin/io/element/android/tests/konsist/KonsistClassNameTest.kt @@ -91,11 +91,7 @@ class KonsistClassNameTest { .replace("Fake", "") val result = (it.name.startsWith("Fake") || it.name.startsWith("FakeRust")) && it.parents().any { parent -> - // Workaround to get the parent name. For instance: - // parent.name used to return `UserListPresenter.Factory` but is now returning `Factory`. - // So we need to retrieve the name of the parent class differently. - val packageName = parent.packagee!!.name - val parentName = parent.fullyQualifiedName!!.substringAfter("$packageName.").replace(".", "") + val parentName = parent.name.replace(".", "") parentName == interfaceName } if (!result && it.name in failingCasesList) { From a84ca7ee8e29157a63fd17afd143bfebe2d64d46 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Tue, 26 Nov 2024 11:39:33 +0100 Subject: [PATCH 22/96] Fix API break in `Sealed interface used in Composable MUST be Immutable or Stable` --- .../tests/konsist/KonsistArchitectureTest.kt | 23 +++++++++++-------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/tests/konsist/src/test/kotlin/io/element/android/tests/konsist/KonsistArchitectureTest.kt b/tests/konsist/src/test/kotlin/io/element/android/tests/konsist/KonsistArchitectureTest.kt index 365449a91d4..d334d88b552 100644 --- a/tests/konsist/src/test/kotlin/io/element/android/tests/konsist/KonsistArchitectureTest.kt +++ b/tests/konsist/src/test/kotlin/io/element/android/tests/konsist/KonsistArchitectureTest.kt @@ -80,19 +80,22 @@ class KonsistArchitectureTest { .assertTrue(additionalMessage = "Consider adding the @Immutable or @Stable annotation to the sealed interface") { val result = it.parameters.all { param -> val type = param.type.text - return@all if (type.startsWith("@") || type.startsWith("(") || type.startsWith("suspend")) { + return@all if (type.startsWith("@") || type.contains("->") || type.startsWith("suspend")) { true } else { - var typePackage = param.type.declaration.packagee?.name - if (typePackage == type) { - // Workaround, now that packagee.fullyQualifiedName is not available anymore - // It seems that when the type in in the same package as the function, - // the package is equal to the type (which is wrong). - // So in this case, use the package of the function - typePackage = it.packagee?.name + val typePackage = param.type.sourceDeclaration?.let { declaration -> + declaration.asTypeParameterDeclaration()?.packagee + ?: declaration.asExternalDeclaration()?.packagee + ?: declaration.asClassOrInterfaceDeclaration()?.packagee + ?: declaration.asKotlinTypeDeclaration()?.packagee + ?: declaration.asObjectDeclaration()?.packagee + }?.name + if (typePackage == null) { + false + } else { + val fullyQualifiedName = "$typePackage.$type" + fullyQualifiedName !in forbiddenInterfacesForComposableParameter } - val fullyQualifiedName = "$typePackage.$type" - fullyQualifiedName !in forbiddenInterfacesForComposableParameter } } if (!result && !failingTestFound && it.name == "FailingComposableWithNonImmutableSealedInterface") { From e01ebb40ac1268b226506e9cc2499ab7100648d5 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Tue, 26 Nov 2024 12:06:24 +0100 Subject: [PATCH 23/96] Avoid using MutableStateFlow, just MutableState in presenter. --- .../preview/AttachmentsPreviewPresenter.kt | 63 ++++++++----------- .../AttachmentsPreviewPresenterTest.kt | 25 +++++++- 2 files changed, 48 insertions(+), 40 deletions(-) diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/attachments/preview/AttachmentsPreviewPresenter.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/attachments/preview/AttachmentsPreviewPresenter.kt index f87ea3fb24e..1ca48848a2c 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/attachments/preview/AttachmentsPreviewPresenter.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/attachments/preview/AttachmentsPreviewPresenter.kt @@ -34,18 +34,12 @@ import io.element.android.libraries.textcomposer.model.TextEditorState import io.element.android.libraries.textcomposer.model.rememberMarkdownTextEditorState import kotlinx.coroutines.CancellationException import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.Job -import kotlinx.coroutines.flow.MutableStateFlow -import kotlinx.coroutines.flow.distinctUntilChanged -import kotlinx.coroutines.flow.filter -import kotlinx.coroutines.flow.flatMapConcat import kotlinx.coroutines.isActive import kotlinx.coroutines.launch import timber.log.Timber import kotlin.coroutines.coroutineContext -@OptIn(ExperimentalCoroutinesApi::class) class AttachmentsPreviewPresenter @AssistedInject constructor( @Assisted private val attachment: Attachment, @Assisted private val onDoneListener: OnDoneListener, @@ -77,41 +71,34 @@ class AttachmentsPreviewPresenter @AssistedInject constructor( val ongoingSendAttachmentJob = remember { mutableStateOf(null) } - val userSentAttachment = remember { - MutableStateFlow(false) - } + val userSentAttachment = remember { mutableStateOf(false) } - val mediaUploadInfoStateFlow = remember { MutableStateFlow>(AsyncData.Uninitialized) } + val mediaUploadInfoState = remember { mutableStateOf>(AsyncData.Uninitialized) } var prePropressingJob: Job? = null LaunchedEffect(Unit) { prePropressingJob = preProcessAttachment( attachment, - mediaUploadInfoStateFlow, + mediaUploadInfoState, ) } - LaunchedEffect(Unit) { - userSentAttachment.filter { it } - .flatMapConcat { - mediaUploadInfoStateFlow.filter { it.isReady() } - } - .distinctUntilChanged() - .collect { mediaUploadInfo -> - if (mediaUploadInfo is AsyncData.Success) { - val caption = markdownTextEditorState.getMessageMarkdown(permalinkBuilder) - .takeIf { it.isNotEmpty() } - ongoingSendAttachmentJob.value = coroutineScope.launch { - sendPreProcessedMedia( - mediaUploadInfo = mediaUploadInfo.data, - caption = caption, - sendActionState = sendActionState, - ) - } - } else if (mediaUploadInfo is AsyncData.Failure) { - sendActionState.value = SendActionState.Failure(mediaUploadInfo.error) + LaunchedEffect(userSentAttachment.value, mediaUploadInfoState.value) { + val mediaUploadInfo = mediaUploadInfoState.value + if (userSentAttachment.value && mediaUploadInfo.isReady()) + if (mediaUploadInfo is AsyncData.Success) { + val caption = markdownTextEditorState.getMessageMarkdown(permalinkBuilder) + .takeIf { it.isNotEmpty() } + ongoingSendAttachmentJob.value = coroutineScope.launch { + sendPreProcessedMedia( + mediaUploadInfo = mediaUploadInfo.data, + caption = caption, + sendActionState = sendActionState, + ) } - // else: cannot happen since we filtered with isReady() + } else if (mediaUploadInfo is AsyncData.Failure) { + sendActionState.value = SendActionState.Failure(mediaUploadInfo.error) } + // else: cannot happen since we filtered with isReady() } fun handleEvents(attachmentsPreviewEvents: AttachmentsPreviewEvents) { @@ -119,7 +106,7 @@ class AttachmentsPreviewPresenter @AssistedInject constructor( is AttachmentsPreviewEvents.SendAttachment -> coroutineScope.launch { val useSendQueue = featureFlagsService.isFeatureEnabled(FeatureFlags.MediaUploadOnSendQueue) userSentAttachment.value = true - val instantSending = mediaUploadInfoStateFlow.value.isReady() && useSendQueue + val instantSending = mediaUploadInfoState.value.isReady() && useSendQueue sendActionState.value = if (instantSending) { SendActionState.Sending.InstantSending } else { @@ -130,7 +117,7 @@ class AttachmentsPreviewPresenter @AssistedInject constructor( coroutineScope.cancel( attachment, prePropressingJob, - mediaUploadInfoStateFlow.value, + mediaUploadInfoState.value, sendActionState, ) } @@ -154,7 +141,7 @@ class AttachmentsPreviewPresenter @AssistedInject constructor( private fun CoroutineScope.preProcessAttachment( attachment: Attachment, - mediaUploadInfoState: MutableStateFlow>, + mediaUploadInfoState: MutableState>, ) = launch { when (attachment) { is Attachment.Media -> { @@ -168,22 +155,22 @@ class AttachmentsPreviewPresenter @AssistedInject constructor( private suspend fun preProcessMedia( mediaAttachment: Attachment.Media, - mediaUploadInfoState: MutableStateFlow>, + mediaUploadInfoState: MutableState>, ) { - mediaUploadInfoState.emit(AsyncData.Loading()) + mediaUploadInfoState.value = AsyncData.Loading() mediaSender.preProcessMedia( uri = mediaAttachment.localMedia.uri, mimeType = mediaAttachment.localMedia.info.mimeType, ).fold( onSuccess = { mediaUploadInfo -> - mediaUploadInfoState.emit(AsyncData.Success(mediaUploadInfo)) + mediaUploadInfoState.value = AsyncData.Success(mediaUploadInfo) }, onFailure = { Timber.e(it, "Failed to pre-process media") if (it is CancellationException) { throw it } else { - mediaUploadInfoState.emit(AsyncData.Failure(it)) + mediaUploadInfoState.value = AsyncData.Failure(it) } } ) diff --git a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/attachments/AttachmentsPreviewPresenterTest.kt b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/attachments/AttachmentsPreviewPresenterTest.kt index 204a5b5b761..48e5c208b6c 100644 --- a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/attachments/AttachmentsPreviewPresenterTest.kt +++ b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/attachments/AttachmentsPreviewPresenterTest.kt @@ -88,6 +88,8 @@ class AttachmentsPreviewPresenterTest { val initialState = awaitItem() assertThat(initialState.sendActionState).isEqualTo(SendActionState.Idle) initialState.eventSink(AttachmentsPreviewEvents.SendAttachment) + assertThat(awaitItem().sendActionState).isEqualTo(SendActionState.Idle) + assertThat(awaitItem().sendActionState).isEqualTo(SendActionState.Sending.Processing) assertThat(awaitItem().sendActionState).isEqualTo(SendActionState.Sending.Processing) assertThat(awaitItem().sendActionState).isEqualTo(SendActionState.Sending.Uploading(0f)) assertThat(awaitItem().sendActionState).isEqualTo(SendActionState.Sending.Uploading(0.5f)) @@ -124,6 +126,8 @@ class AttachmentsPreviewPresenterTest { processLatch.complete(Unit) advanceUntilIdle() initialState.eventSink(AttachmentsPreviewEvents.SendAttachment) + assertThat(awaitItem().sendActionState).isEqualTo(SendActionState.Idle) + assertThat(awaitItem().sendActionState).isEqualTo(SendActionState.Idle) assertThat(awaitItem().sendActionState).isEqualTo(SendActionState.Sending.InstantSending) assertThat(awaitItem().sendActionState).isEqualTo(SendActionState.Done) sendFileResult.assertions().isCalledOnce() @@ -154,9 +158,11 @@ class AttachmentsPreviewPresenterTest { val initialState = awaitItem() assertThat(initialState.sendActionState).isEqualTo(SendActionState.Idle) initialState.eventSink(AttachmentsPreviewEvents.SendAttachment) + assertThat(awaitItem().sendActionState).isEqualTo(SendActionState.Idle) assertThat(awaitItem().sendActionState).isEqualTo(SendActionState.Sending.Processing) // Pre-processing finishes processLatch.complete(Unit) + assertThat(awaitItem().sendActionState).isEqualTo(SendActionState.Sending.Processing) assertThat(awaitItem().sendActionState).isEqualTo(SendActionState.Done) sendFileResult.assertions().isCalledOnce() onDoneListener.assertions().isCalledOnce() @@ -181,6 +187,8 @@ class AttachmentsPreviewPresenterTest { val initialState = awaitItem() assertThat(initialState.sendActionState).isEqualTo(SendActionState.Idle) initialState.eventSink(AttachmentsPreviewEvents.SendAttachment) + assertThat(awaitItem().sendActionState).isEqualTo(SendActionState.Idle) + assertThat(awaitItem().sendActionState).isEqualTo(SendActionState.Sending.Processing) assertThat(awaitItem().sendActionState).isEqualTo(SendActionState.Sending.Processing) // Pre-processing finishes processLatch.complete(Unit) @@ -209,6 +217,9 @@ class AttachmentsPreviewPresenterTest { processLatch.complete(Unit) advanceUntilIdle() initialState.eventSink(AttachmentsPreviewEvents.SendAttachment) + assertThat(awaitItem().sendActionState).isEqualTo(SendActionState.Idle) + assertThat(awaitItem().sendActionState).isEqualTo(SendActionState.Idle) + assertThat(awaitItem().sendActionState).isEqualTo(SendActionState.Sending.InstantSending) assertThat(awaitItem().sendActionState).isInstanceOf(SendActionState.Failure::class.java) } } @@ -227,6 +238,7 @@ class AttachmentsPreviewPresenterTest { val initialState = awaitItem() assertThat(initialState.sendActionState).isEqualTo(SendActionState.Idle) initialState.eventSink(AttachmentsPreviewEvents.Cancel) + assertThat(awaitItem().sendActionState).isEqualTo(SendActionState.Idle) assertThat(awaitItem().sendActionState).isEqualTo(SendActionState.Done) deleteCallback.assertions().isCalledOnce() onDoneListener.assertions().isCalledOnce() @@ -258,6 +270,8 @@ class AttachmentsPreviewPresenterTest { assertThat(initialState.sendActionState).isEqualTo(SendActionState.Idle) initialState.textEditorState.setMarkdown(A_CAPTION) initialState.eventSink(AttachmentsPreviewEvents.SendAttachment) + assertThat(awaitItem().sendActionState).isEqualTo(SendActionState.Idle) + assertThat(awaitItem().sendActionState).isEqualTo(SendActionState.Sending.Processing) assertThat(awaitItem().sendActionState).isEqualTo(SendActionState.Sending.Processing) assertThat(awaitItem().sendActionState).isEqualTo(SendActionState.Done) sendImageResult.assertions().isCalledOnce().with( @@ -297,6 +311,8 @@ class AttachmentsPreviewPresenterTest { assertThat(initialState.sendActionState).isEqualTo(SendActionState.Idle) initialState.textEditorState.setMarkdown(A_CAPTION) initialState.eventSink(AttachmentsPreviewEvents.SendAttachment) + assertThat(awaitItem().sendActionState).isEqualTo(SendActionState.Idle) + assertThat(awaitItem().sendActionState).isEqualTo(SendActionState.Sending.Processing) assertThat(awaitItem().sendActionState).isEqualTo(SendActionState.Sending.Processing) assertThat(awaitItem().sendActionState).isEqualTo(SendActionState.Done) sendVideoResult.assertions().isCalledOnce().with( @@ -334,6 +350,8 @@ class AttachmentsPreviewPresenterTest { assertThat(initialState.sendActionState).isEqualTo(SendActionState.Idle) initialState.textEditorState.setMarkdown(A_CAPTION) initialState.eventSink(AttachmentsPreviewEvents.SendAttachment) + assertThat(awaitItem().sendActionState).isEqualTo(SendActionState.Idle) + assertThat(awaitItem().sendActionState).isEqualTo(SendActionState.Sending.Processing) assertThat(awaitItem().sendActionState).isEqualTo(SendActionState.Sending.Processing) assertThat(awaitItem().sendActionState).isEqualTo(SendActionState.Done) sendAudioResult.assertions().isCalledOnce().with( @@ -363,8 +381,9 @@ class AttachmentsPreviewPresenterTest { val initialState = awaitItem() assertThat(initialState.sendActionState).isEqualTo(SendActionState.Idle) initialState.eventSink(AttachmentsPreviewEvents.SendAttachment) - val loadingState = awaitItem() - assertThat(loadingState.sendActionState).isEqualTo(SendActionState.Sending.Processing) + assertThat(awaitItem().sendActionState).isEqualTo(SendActionState.Idle) + assertThat(awaitItem().sendActionState).isEqualTo(SendActionState.Sending.Processing) + assertThat(awaitItem().sendActionState).isEqualTo(SendActionState.Sending.Processing) val failureState = awaitItem() assertThat(failureState.sendActionState).isEqualTo(SendActionState.Failure(failure)) sendFileResult.assertions().isCalledOnce() @@ -383,6 +402,8 @@ class AttachmentsPreviewPresenterTest { val initialState = awaitItem() assertThat(initialState.sendActionState).isEqualTo(SendActionState.Idle) initialState.eventSink(AttachmentsPreviewEvents.SendAttachment) + assertThat(awaitItem().sendActionState).isEqualTo(SendActionState.Idle) + assertThat(awaitItem().sendActionState).isEqualTo(SendActionState.Sending.Processing) assertThat(awaitItem().sendActionState).isEqualTo(SendActionState.Sending.Processing) initialState.eventSink(AttachmentsPreviewEvents.ClearSendState) assertThat(awaitItem().sendActionState).isEqualTo(SendActionState.Idle) From fe2d75700f75f4a69490ab7d68e8871d7cc74c30 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Tue, 26 Nov 2024 15:07:22 +0100 Subject: [PATCH 24/96] No need to keep the Job instance. --- .../impl/attachments/preview/AttachmentsPreviewPresenter.kt | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/attachments/preview/AttachmentsPreviewPresenter.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/attachments/preview/AttachmentsPreviewPresenter.kt index 1ca48848a2c..4ac8eecc5cb 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/attachments/preview/AttachmentsPreviewPresenter.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/attachments/preview/AttachmentsPreviewPresenter.kt @@ -74,9 +74,8 @@ class AttachmentsPreviewPresenter @AssistedInject constructor( val userSentAttachment = remember { mutableStateOf(false) } val mediaUploadInfoState = remember { mutableStateOf>(AsyncData.Uninitialized) } - var prePropressingJob: Job? = null LaunchedEffect(Unit) { - prePropressingJob = preProcessAttachment( + preProcessAttachment( attachment, mediaUploadInfoState, ) @@ -116,7 +115,6 @@ class AttachmentsPreviewPresenter @AssistedInject constructor( AttachmentsPreviewEvents.Cancel -> { coroutineScope.cancel( attachment, - prePropressingJob, mediaUploadInfoState.value, sendActionState, ) @@ -178,7 +176,6 @@ class AttachmentsPreviewPresenter @AssistedInject constructor( private fun CoroutineScope.cancel( attachment: Attachment, - preProcessingJob: Job?, mediaUploadInfo: AsyncData, sendActionState: MutableState, ) = launch { @@ -186,7 +183,6 @@ class AttachmentsPreviewPresenter @AssistedInject constructor( when (attachment) { is Attachment.Media -> { temporaryUriDeleter.delete(attachment.localMedia.uri) - preProcessingJob?.cancel() mediaUploadInfo.dataOrNull()?.let { data -> cleanUp(data) } From c209245c2b657548859c746afc9914815596b45a Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Tue, 26 Nov 2024 15:59:29 +0100 Subject: [PATCH 25/96] Exclude Konsist code from Kover. --- plugins/src/main/kotlin/extension/KoverExtension.kt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/plugins/src/main/kotlin/extension/KoverExtension.kt b/plugins/src/main/kotlin/extension/KoverExtension.kt index ccc077b0a32..6fbb18e1874 100644 --- a/plugins/src/main/kotlin/extension/KoverExtension.kt +++ b/plugins/src/main/kotlin/extension/KoverExtension.kt @@ -98,6 +98,8 @@ fun Project.setupKover() { "io.element.android.libraries.designsystem.theme.components.bottomsheet.*", // Test presenters "io.element.android.features.leaveroom.fake.FakeLeaveRoomPresenter", + // Konsist code to make test fails + "io.element.android.tests.konsist.failures", ) annotatedBy( "androidx.compose.ui.tooling.preview.Preview", From 75f3556d61eff2d9627636d2a9b98c4864b93936 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Tue, 26 Nov 2024 16:08:19 +0100 Subject: [PATCH 26/96] Rework and comment the code. --- .../preview/AttachmentsPreviewPresenter.kt | 37 ++++++++++++------- 1 file changed, 23 insertions(+), 14 deletions(-) diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/attachments/preview/AttachmentsPreviewPresenter.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/attachments/preview/AttachmentsPreviewPresenter.kt index 4ac8eecc5cb..69d28d8f202 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/attachments/preview/AttachmentsPreviewPresenter.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/attachments/preview/AttachmentsPreviewPresenter.kt @@ -82,22 +82,31 @@ class AttachmentsPreviewPresenter @AssistedInject constructor( } LaunchedEffect(userSentAttachment.value, mediaUploadInfoState.value) { - val mediaUploadInfo = mediaUploadInfoState.value - if (userSentAttachment.value && mediaUploadInfo.isReady()) - if (mediaUploadInfo is AsyncData.Success) { - val caption = markdownTextEditorState.getMessageMarkdown(permalinkBuilder) - .takeIf { it.isNotEmpty() } - ongoingSendAttachmentJob.value = coroutineScope.launch { - sendPreProcessedMedia( - mediaUploadInfo = mediaUploadInfo.data, - caption = caption, - sendActionState = sendActionState, - ) + if (userSentAttachment.value) { + // User confirmed sending the attachment + when (val mediaUploadInfo = mediaUploadInfoState.value) { + is AsyncData.Success -> { + // Pre-processing is done, send the attachment + val caption = markdownTextEditorState.getMessageMarkdown(permalinkBuilder) + .takeIf { it.isNotEmpty() } + ongoingSendAttachmentJob.value = coroutineScope.launch { + sendPreProcessedMedia( + mediaUploadInfo = mediaUploadInfo.data, + caption = caption, + sendActionState = sendActionState, + ) + } + } + is AsyncData.Failure -> { + // Pre-processing has failed, show the error + sendActionState.value = SendActionState.Failure(mediaUploadInfo.error) + } + AsyncData.Uninitialized, + is AsyncData.Loading -> { + // Pre-processing is still in progress, do nothing } - } else if (mediaUploadInfo is AsyncData.Failure) { - sendActionState.value = SendActionState.Failure(mediaUploadInfo.error) } - // else: cannot happen since we filtered with isReady() + } } fun handleEvents(attachmentsPreviewEvents: AttachmentsPreviewEvents) { From 9d6ea2175fa5b0a1e3ddd48ec77d557bdedcf985 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 27 Nov 2024 10:54:20 +0100 Subject: [PATCH 27/96] Add feature flag to temporary disable sending caption by default in production. --- .../impl/actionlist/ActionListPresenter.kt | 9 ++- .../preview/AttachmentsPreviewPresenter.kt | 7 ++- .../preview/AttachmentsPreviewState.kt | 6 +- .../AttachmentsPreviewStateProvider.kt | 3 + .../actionlist/ActionListPresenterTest.kt | 61 ++++++++++++++++++- .../AttachmentsPreviewPresenterTest.kt | 30 ++++++++- .../libraries/featureflag/api/FeatureFlags.kt | 7 +++ 7 files changed, 112 insertions(+), 11 deletions(-) diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/actionlist/ActionListPresenter.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/actionlist/ActionListPresenter.kt index e228f3eb736..f2b97769c03 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/actionlist/ActionListPresenter.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/actionlist/ActionListPresenter.kt @@ -37,6 +37,8 @@ import io.element.android.features.messages.impl.timeline.model.event.canBeForwa import io.element.android.features.messages.impl.timeline.model.event.canReact import io.element.android.libraries.architecture.Presenter import io.element.android.libraries.di.RoomScope +import io.element.android.libraries.featureflag.api.FeatureFlagService +import io.element.android.libraries.featureflag.api.FeatureFlags import io.element.android.libraries.matrix.api.core.EventId import io.element.android.libraries.matrix.api.room.MatrixRoom import io.element.android.libraries.preferences.api.store.AppPreferencesStore @@ -60,6 +62,7 @@ class DefaultActionListPresenter @AssistedInject constructor( private val isPinnedMessagesFeatureEnabled: IsPinnedMessagesFeatureEnabled, private val room: MatrixRoom, private val userSendFailureFactory: VerifiedUserSendFailureFactory, + private val featureFlagService: FeatureFlagService, ) : ActionListPresenter { @AssistedFactory @ContributesBinding(RoomScope::class) @@ -134,7 +137,7 @@ class DefaultActionListPresenter @AssistedInject constructor( } } - private fun buildActions( + private suspend fun buildActions( timelineItem: TimelineItem.Event, usersEventPermissions: UserEventPermissions, isDeveloperModeEnabled: Boolean, @@ -157,7 +160,9 @@ class DefaultActionListPresenter @AssistedInject constructor( if (timelineItem.content is TimelineItemEventContentWithAttachment) { // Caption if (timelineItem.content.caption == null) { - add(TimelineItemAction.AddCaption) + if (featureFlagService.isFeatureEnabled(FeatureFlags.MediaCaptionCreation)) { + add(TimelineItemAction.AddCaption) + } } else { add(TimelineItemAction.EditCaption) add(TimelineItemAction.RemoveCaption) diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/attachments/preview/AttachmentsPreviewPresenter.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/attachments/preview/AttachmentsPreviewPresenter.kt index 69d28d8f202..606e91863d3 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/attachments/preview/AttachmentsPreviewPresenter.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/attachments/preview/AttachmentsPreviewPresenter.kt @@ -10,6 +10,7 @@ package io.element.android.features.messages.impl.attachments.preview import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.MutableState +import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember @@ -46,7 +47,7 @@ class AttachmentsPreviewPresenter @AssistedInject constructor( private val mediaSender: MediaSender, private val permalinkBuilder: PermalinkBuilder, private val temporaryUriDeleter: TemporaryUriDeleter, - private val featureFlagsService: FeatureFlagService, + private val featureFlagService: FeatureFlagService, ) : Presenter { @AssistedFactory interface Factory { @@ -72,6 +73,7 @@ class AttachmentsPreviewPresenter @AssistedInject constructor( val ongoingSendAttachmentJob = remember { mutableStateOf(null) } val userSentAttachment = remember { mutableStateOf(false) } + val allowCaption by featureFlagService.isFeatureEnabledFlow(FeatureFlags.MediaCaptionCreation).collectAsState(initial = false) val mediaUploadInfoState = remember { mutableStateOf>(AsyncData.Uninitialized) } LaunchedEffect(Unit) { @@ -112,7 +114,7 @@ class AttachmentsPreviewPresenter @AssistedInject constructor( fun handleEvents(attachmentsPreviewEvents: AttachmentsPreviewEvents) { when (attachmentsPreviewEvents) { is AttachmentsPreviewEvents.SendAttachment -> coroutineScope.launch { - val useSendQueue = featureFlagsService.isFeatureEnabled(FeatureFlags.MediaUploadOnSendQueue) + val useSendQueue = featureFlagService.isFeatureEnabled(FeatureFlags.MediaUploadOnSendQueue) userSentAttachment.value = true val instantSending = mediaUploadInfoState.value.isReady() && useSendQueue sendActionState.value = if (instantSending) { @@ -142,6 +144,7 @@ class AttachmentsPreviewPresenter @AssistedInject constructor( attachment = attachment, sendActionState = sendActionState.value, textEditorState = textEditorState, + allowCaption = allowCaption, eventSink = ::handleEvents ) } diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/attachments/preview/AttachmentsPreviewState.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/attachments/preview/AttachmentsPreviewState.kt index 0e9724c4606..0878b52f803 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/attachments/preview/AttachmentsPreviewState.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/attachments/preview/AttachmentsPreviewState.kt @@ -15,11 +15,9 @@ data class AttachmentsPreviewState( val attachment: Attachment, val sendActionState: SendActionState, val textEditorState: TextEditorState, + val allowCaption: Boolean, val eventSink: (AttachmentsPreviewEvents) -> Unit -) { - // Keep the val to eventually set to false for some mimetypes. - val allowCaption: Boolean = true -} +) @Immutable sealed interface SendActionState { diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/attachments/preview/AttachmentsPreviewStateProvider.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/attachments/preview/AttachmentsPreviewStateProvider.kt index 1c55245e469..f7e215fa222 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/attachments/preview/AttachmentsPreviewStateProvider.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/attachments/preview/AttachmentsPreviewStateProvider.kt @@ -29,6 +29,7 @@ open class AttachmentsPreviewStateProvider : PreviewParameterProvider> { _, _, _, _, _ -> @@ -420,6 +442,7 @@ class AttachmentsPreviewPresenterTest { temporaryUriDeleter: TemporaryUriDeleter = FakeTemporaryUriDeleter(), onDoneListener: OnDoneListener = OnDoneListener { lambdaError() }, mediaUploadOnSendQueueEnabled: Boolean = true, + allowCaption: Boolean = true, ): AttachmentsPreviewPresenter { return AttachmentsPreviewPresenter( attachment = aMediaAttachment(localMedia), @@ -427,8 +450,11 @@ class AttachmentsPreviewPresenterTest { mediaSender = MediaSender(mediaPreProcessor, room, InMemorySessionPreferencesStore()), permalinkBuilder = permalinkBuilder, temporaryUriDeleter = temporaryUriDeleter, - featureFlagsService = FakeFeatureFlagService( - initialState = mapOf(FeatureFlags.MediaUploadOnSendQueue.key to mediaUploadOnSendQueueEnabled), + featureFlagService = FakeFeatureFlagService( + initialState = mapOf( + FeatureFlags.MediaUploadOnSendQueue.key to mediaUploadOnSendQueueEnabled, + FeatureFlags.MediaCaptionCreation.key to allowCaption, + ), ) ) } diff --git a/libraries/featureflag/api/src/main/kotlin/io/element/android/libraries/featureflag/api/FeatureFlags.kt b/libraries/featureflag/api/src/main/kotlin/io/element/android/libraries/featureflag/api/FeatureFlags.kt index 490c12ebe0d..42d9f309207 100644 --- a/libraries/featureflag/api/src/main/kotlin/io/element/android/libraries/featureflag/api/FeatureFlags.kt +++ b/libraries/featureflag/api/src/main/kotlin/io/element/android/libraries/featureflag/api/FeatureFlags.kt @@ -140,4 +140,11 @@ enum class FeatureFlags( defaultValue = { buildMeta -> buildMeta.buildType != BuildType.RELEASE }, isFinished = false, ), + MediaCaptionCreation( + key = "feature.media_caption_creation", + title = "Allow creation of media captions", + description = null, + defaultValue = { buildMeta -> buildMeta.buildType != BuildType.RELEASE }, + isFinished = false, + ), } From ae30b9fb3d898a857ffaacb92a03169b6f8ef342 Mon Sep 17 00:00:00 2001 From: ElementBot Date: Wed, 27 Nov 2024 10:04:23 +0000 Subject: [PATCH 28/96] Update screenshots --- ....messages.impl.attachments.preview_AttachmentsView_7_en.png | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 tests/uitests/src/test/snapshots/images/features.messages.impl.attachments.preview_AttachmentsView_7_en.png diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.attachments.preview_AttachmentsView_7_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.attachments.preview_AttachmentsView_7_en.png new file mode 100644 index 00000000000..6920a089ef4 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.attachments.preview_AttachmentsView_7_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:507c7dffae1aabfa687174f1f964e2c40b004183b6bc3a70b56d764e0d308b47 +size 392923 From 456752551a71e4256290f9b3f22a521a88d24184 Mon Sep 17 00:00:00 2001 From: ganfra Date: Wed, 27 Nov 2024 15:23:16 +0100 Subject: [PATCH 29/96] deps : update rust sdk to 0.2.67 and fix breaking changes --- gradle/libs.versions.toml | 2 +- .../android/libraries/matrix/impl/media/RustMediaLoader.kt | 3 +-- .../matrix/impl/room/preview/RoomPreviewInfoMapper.kt | 3 ++- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 30b2fbe0ccb..1bcab24c19f 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -173,7 +173,7 @@ jsoup = "org.jsoup:jsoup:1.18.1" appyx_core = { module = "com.bumble.appyx:core", version.ref = "appyx" } molecule-runtime = "app.cash.molecule:molecule-runtime:2.0.0" timber = "com.jakewharton.timber:timber:5.0.1" -matrix_sdk = "org.matrix.rustcomponents:sdk-android:0.2.65" +matrix_sdk = "org.matrix.rustcomponents:sdk-android:0.2.67" matrix_richtexteditor = { module = "io.element.android:wysiwyg", version.ref = "wysiwyg" } matrix_richtexteditor_compose = { module = "io.element.android:wysiwyg-compose", version.ref = "wysiwyg" } sqldelight-driver-android = { module = "app.cash.sqldelight:android-driver", version.ref = "sqldelight" } 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 17ba1d2c4d6..1d07a3e0192 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 @@ -15,7 +15,6 @@ import io.element.android.libraries.matrix.api.media.MediaSource import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.withContext import org.matrix.rustcomponents.sdk.Client -import org.matrix.rustcomponents.sdk.mediaSourceFromUrl import org.matrix.rustcomponents.sdk.use import java.io.File import org.matrix.rustcomponents.sdk.MediaSource as RustMediaSource @@ -86,7 +85,7 @@ class RustMediaLoader( return if (json != null) { RustMediaSource.fromJson(json) } else { - mediaSourceFromUrl(url) + RustMediaSource.fromUrl(url) } } } diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/preview/RoomPreviewInfoMapper.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/preview/RoomPreviewInfoMapper.kt index 3ff3c1b0983..0da22426ba7 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/preview/RoomPreviewInfoMapper.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/preview/RoomPreviewInfoMapper.kt @@ -7,6 +7,7 @@ package io.element.android.libraries.matrix.impl.room.preview +import io.element.android.libraries.core.bool.orFalse import io.element.android.libraries.matrix.api.core.RoomAlias import io.element.android.libraries.matrix.api.core.RoomId import io.element.android.libraries.matrix.api.room.preview.RoomPreviewInfo @@ -25,7 +26,7 @@ object RoomPreviewInfoMapper { avatarUrl = info.avatarUrl, numberOfJoinedMembers = info.numJoinedMembers.toLong(), roomType = info.roomType.map(), - isHistoryWorldReadable = info.isHistoryWorldReadable, + isHistoryWorldReadable = info.isHistoryWorldReadable.orFalse(), isJoined = info.membership == Membership.JOINED, isInvited = info.membership == Membership.INVITED, isPublic = info.joinRule == JoinRule.Public, From 41b86ebbd27783a81ab92e9a50febefcbf30f45f Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 27 Nov 2024 14:24:04 +0000 Subject: [PATCH 30/96] Update plugin sonarqube to v6.0.1.5171 --- 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 30b2fbe0ccb..073ae820ecf 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -241,6 +241,6 @@ paparazzi = "app.cash.paparazzi:1.3.5" sqldelight = { id = "app.cash.sqldelight", version.ref = "sqldelight" } firebaseAppDistribution = { id = "com.google.firebase.appdistribution", version.ref = "firebaseAppDistribution" } knit = { id = "org.jetbrains.kotlinx.knit", version = "0.5.0" } -sonarqube = "org.sonarqube:6.0.0.5145" +sonarqube = "org.sonarqube:6.0.1.5171" licensee = "app.cash.licensee:1.12.0" compose-compiler = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" } From 98875a65035ded16e3078feaba4858c47750a626 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 27 Nov 2024 11:40:14 +0100 Subject: [PATCH 31/96] Add a duration formatter. --- libraries/dateformatter/api/build.gradle.kts | 5 +++ .../dateformatter/api/DurationFormatter.kt | 40 +++++++++++++++++ .../api/DurationFormatterTest.kt | 43 +++++++++++++++++++ 3 files changed, 88 insertions(+) create mode 100644 libraries/dateformatter/api/src/main/kotlin/io/element/android/libraries/dateformatter/api/DurationFormatter.kt create mode 100644 libraries/dateformatter/api/src/test/kotlin/io/element/android/libraries/dateformatter/api/DurationFormatterTest.kt diff --git a/libraries/dateformatter/api/build.gradle.kts b/libraries/dateformatter/api/build.gradle.kts index 1aabe2a5634..6ec28b9eb99 100644 --- a/libraries/dateformatter/api/build.gradle.kts +++ b/libraries/dateformatter/api/build.gradle.kts @@ -11,4 +11,9 @@ plugins { android { namespace = "io.element.android.libraries.dateformatter.api" + + dependencies { + testImplementation(libs.test.junit) + testImplementation(libs.test.truth) + } } diff --git a/libraries/dateformatter/api/src/main/kotlin/io/element/android/libraries/dateformatter/api/DurationFormatter.kt b/libraries/dateformatter/api/src/main/kotlin/io/element/android/libraries/dateformatter/api/DurationFormatter.kt new file mode 100644 index 00000000000..50a3b27204b --- /dev/null +++ b/libraries/dateformatter/api/src/main/kotlin/io/element/android/libraries/dateformatter/api/DurationFormatter.kt @@ -0,0 +1,40 @@ +/* + * Copyright 2024 New Vector Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only + * Please see LICENSE in the repository root for full details. + */ + +package io.element.android.libraries.dateformatter.api + +import java.util.Locale + +/** + * Convert milliseconds to human readable duration. + * Hours in 1 digit or more. + * Minutes in 2 digits when hours are available. + * Seconds always on 2 digits. + * Example: + * - when the duration is longer than 1 hour: + * - "10:23:34" + * - "1:23:34" + * - "1:03:04" + * - when the duration is shorter: + * - "4:56" + * - "14:06" + * - Less than one minute: + * - "0:00" + * - "0:01" + * - "0:59" + */ +fun Long.toHumanReadableDuration(): String { + val inSeconds = this / 1_000 + val hours = inSeconds / 3_600 + val minutes = (inSeconds % 3_600) / 60 + val seconds = inSeconds % 60 + return if (hours > 0) { + String.format(Locale.US, "%d:%02d:%02d", hours, minutes, seconds) + } else { + String.format(Locale.US, "%d:%02d", minutes, seconds) + } +} diff --git a/libraries/dateformatter/api/src/test/kotlin/io/element/android/libraries/dateformatter/api/DurationFormatterTest.kt b/libraries/dateformatter/api/src/test/kotlin/io/element/android/libraries/dateformatter/api/DurationFormatterTest.kt new file mode 100644 index 00000000000..1b8c155f9c5 --- /dev/null +++ b/libraries/dateformatter/api/src/test/kotlin/io/element/android/libraries/dateformatter/api/DurationFormatterTest.kt @@ -0,0 +1,43 @@ +/* + * Copyright 2024 New Vector Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only + * Please see LICENSE in the repository root for full details. + */ + +package io.element.android.libraries.dateformatter.api + +import com.google.common.truth.Truth.assertThat +import org.junit.Test + +class DurationFormatterTest { + @Test + fun `format seconds only`() { + assertThat(buildDuration().toHumanReadableDuration()).isEqualTo("0:00") + assertThat(buildDuration(seconds = 1).toHumanReadableDuration()).isEqualTo("0:01") + assertThat(buildDuration(seconds = 59).toHumanReadableDuration()).isEqualTo("0:59") + } + + @Test + fun `format minutes and seconds`() { + assertThat(buildDuration(minutes = 1).toHumanReadableDuration()).isEqualTo("1:00") + assertThat(buildDuration(minutes = 1, seconds = 30).toHumanReadableDuration()).isEqualTo("1:30") + assertThat(buildDuration(minutes = 59, seconds = 59).toHumanReadableDuration()).isEqualTo("59:59") + } + + @Test + fun `format hours, minutes and seconds`() { + assertThat(buildDuration(hours = 1).toHumanReadableDuration()).isEqualTo("1:00:00") + assertThat(buildDuration(hours = 1, minutes = 1, seconds = 1).toHumanReadableDuration()).isEqualTo("1:01:01") + assertThat(buildDuration(hours = 24, minutes = 59, seconds = 59).toHumanReadableDuration()).isEqualTo("24:59:59") + assertThat(buildDuration(hours = 25, minutes = 0, seconds = 0).toHumanReadableDuration()).isEqualTo("25:00:00") + } + + private fun buildDuration( + hours: Int = 0, + minutes: Int = 0, + seconds: Int = 0 + ): Long { + return (hours * 60 * 60 + minutes * 60 + seconds) * 1000L + } +} From 7a8b942dfb78c142605179cdb42b824ff33544e4 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 27 Nov 2024 15:34:24 +0100 Subject: [PATCH 32/96] Slider: import design. --- .../designsystem/theme/components/Slider.kt | 76 ++++++++++++++++++- 1 file changed, 75 insertions(+), 1 deletion(-) diff --git a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/theme/components/Slider.kt b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/theme/components/Slider.kt index b5edbb2d657..5c0095b7b65 100644 --- a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/theme/components/Slider.kt +++ b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/theme/components/Slider.kt @@ -5,19 +5,32 @@ * Please see LICENSE in the repository root for full details. */ +@file:OptIn(ExperimentalMaterial3Api::class) + package io.element.android.libraries.designsystem.theme.components +import androidx.compose.foundation.interaction.DragInteraction import androidx.compose.foundation.interaction.MutableInteractionSource +import androidx.compose.foundation.interaction.PressInteraction import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.height +import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.SliderColors import androidx.compose.material3.SliderDefaults import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableFloatStateOf +import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.drawWithContent +import androidx.compose.ui.graphics.Color import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.DpSize +import androidx.compose.ui.unit.dp +import io.element.android.compound.theme.ElementTheme import io.element.android.libraries.designsystem.preview.ElementThemedPreview import io.element.android.libraries.designsystem.preview.PreviewGroup @@ -32,8 +45,20 @@ fun Slider( steps: Int = 0, onValueChangeFinish: (() -> Unit)? = null, colors: SliderColors = SliderDefaults.colors(), - interactionSource: MutableInteractionSource = remember { MutableInteractionSource() } + interactionSource: MutableInteractionSource = remember { MutableInteractionSource() }, + useCustomLayout: Boolean = false, ) { + val thumbColor = ElementTheme.colors.iconOnSolidPrimary + var isUserInteracting by remember { mutableStateOf(false) } + LaunchedEffect(interactionSource) { + interactionSource.interactions.collect { interaction -> + isUserInteracting = when (interaction) { + is DragInteraction.Start, + is PressInteraction.Press -> true + else -> false + } + } + } androidx.compose.material3.Slider( value = value, onValueChange = onValueChange, @@ -43,6 +68,54 @@ fun Slider( steps = steps, onValueChangeFinished = onValueChangeFinish, colors = colors, + thumb = { + if (useCustomLayout) { + SliderDefaults.Thumb( + modifier = Modifier.drawWithContent { + drawContent() + if (isUserInteracting.not()) { + drawCircle(thumbColor, radius = 8.dp.toPx()) + } + }, + interactionSource = interactionSource, + colors = colors.copy( + thumbColor = ElementTheme.colors.iconPrimary, + ), + enabled = enabled, + thumbSize = DpSize( + if (isUserInteracting) 44.dp else 22.dp, + 22.dp, + ), + ) + } else { + SliderDefaults.Thumb( + interactionSource = interactionSource, + colors = colors, + enabled = enabled + ) + } + }, + track = { sliderState -> + if (useCustomLayout) { + SliderDefaults.Track( + modifier = Modifier.height(8.dp), + colors = colors.copy( + activeTrackColor = Color(0x66E0EDFF), + inactiveTrackColor = Color(0x66E0EDFF), + ), + enabled = enabled, + sliderState = sliderState, + thumbTrackGapSize = 0.dp, + drawStopIndicator = { }, + ) + } else { + SliderDefaults.Track( + colors = colors, + enabled = enabled, + sliderState = sliderState, + ) + } + }, interactionSource = interactionSource, ) } @@ -55,5 +128,6 @@ internal fun SlidersPreview() = ElementThemedPreview { Slider(onValueChange = { value = it }, value = value, enabled = true) Slider(steps = 10, onValueChange = { value = it }, value = value, enabled = true) Slider(onValueChange = { value = it }, value = value, enabled = false) + Slider(onValueChange = { value = it }, value = value, enabled = true, useCustomLayout = true) } } From 9c1ccdfe627857e265658f2a344c38c784a0c0a3 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 27 Nov 2024 16:00:28 +0100 Subject: [PATCH 33/96] Add custom video player controller --- libraries/mediaviewer/api/build.gradle.kts | 1 + .../mediaviewer/api/local/LocalMediaView.kt | 155 +++++++++++++----- .../api/local/LocalMediaViewState.kt | 5 +- .../api/player/MediaPlayerControllerState.kt | 15 ++ .../MediaPlayerControllerStateProvider.kt | 55 +++++++ .../api/player/MediaPlayerControllerView.kt | 151 +++++++++++++++++ 6 files changed, 343 insertions(+), 39 deletions(-) create mode 100644 libraries/mediaviewer/api/src/main/kotlin/io/element/android/libraries/mediaviewer/api/player/MediaPlayerControllerState.kt create mode 100644 libraries/mediaviewer/api/src/main/kotlin/io/element/android/libraries/mediaviewer/api/player/MediaPlayerControllerStateProvider.kt create mode 100644 libraries/mediaviewer/api/src/main/kotlin/io/element/android/libraries/mediaviewer/api/player/MediaPlayerControllerView.kt diff --git a/libraries/mediaviewer/api/build.gradle.kts b/libraries/mediaviewer/api/build.gradle.kts index d55528bbe33..5d434ae0946 100644 --- a/libraries/mediaviewer/api/build.gradle.kts +++ b/libraries/mediaviewer/api/build.gradle.kts @@ -35,6 +35,7 @@ dependencies { implementation(projects.libraries.androidutils) implementation(projects.libraries.architecture) implementation(projects.libraries.core) + implementation(projects.libraries.dateformatter.api) implementation(projects.libraries.di) implementation(projects.libraries.designsystem) implementation(projects.libraries.matrix.api) diff --git a/libraries/mediaviewer/api/src/main/kotlin/io/element/android/libraries/mediaviewer/api/local/LocalMediaView.kt b/libraries/mediaviewer/api/src/main/kotlin/io/element/android/libraries/mediaviewer/api/local/LocalMediaView.kt index 7b63c22121e..b644ebc6857 100644 --- a/libraries/mediaviewer/api/src/main/kotlin/io/element/android/libraries/mediaviewer/api/local/LocalMediaView.kt +++ b/libraries/mediaviewer/api/src/main/kotlin/io/element/android/libraries/mediaviewer/api/local/LocalMediaView.kt @@ -9,7 +9,6 @@ package io.element.android.libraries.mediaviewer.api.local import android.annotation.SuppressLint import android.net.Uri -import android.view.View import android.view.ViewGroup.LayoutParams.MATCH_PARENT import android.widget.FrameLayout import androidx.compose.foundation.Image @@ -19,6 +18,8 @@ import androidx.compose.foundation.interaction.MutableInteractionSource import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size @@ -30,6 +31,7 @@ import androidx.compose.material3.MaterialTheme import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableIntStateOf import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue @@ -49,6 +51,7 @@ import androidx.compose.ui.viewinterop.AndroidView import androidx.lifecycle.Lifecycle import androidx.media3.common.MediaItem import androidx.media3.common.Player +import androidx.media3.common.Timeline import androidx.media3.ui.AspectRatioFrameLayout import androidx.media3.ui.PlayerView import io.element.android.compound.theme.ElementTheme @@ -67,9 +70,13 @@ import io.element.android.libraries.mediaviewer.api.helper.formatFileExtensionAn import io.element.android.libraries.mediaviewer.api.local.exoplayer.ExoPlayerWrapper import io.element.android.libraries.mediaviewer.api.local.pdf.PdfViewer import io.element.android.libraries.mediaviewer.api.local.pdf.rememberPdfViewerState +import io.element.android.libraries.mediaviewer.api.player.MediaPlayerControllerState +import io.element.android.libraries.mediaviewer.api.player.MediaPlayerControllerView import io.element.android.libraries.ui.strings.CommonStrings +import kotlinx.coroutines.delay import me.saket.telephoto.zoomable.coil.ZoomableAsyncImage import me.saket.telephoto.zoomable.rememberZoomableImageState +import kotlin.time.Duration.Companion.seconds @Composable fun LocalMediaView( @@ -91,7 +98,6 @@ fun LocalMediaView( localMediaViewState = localMediaViewState, localMedia = localMedia, modifier = modifier, - onClick = onClick, ) mimeType == MimeTypes.Pdf -> MediaPDFView( localMediaViewState = localMediaViewState, @@ -141,7 +147,6 @@ private fun MediaImageView( private fun MediaVideoView( localMediaViewState: LocalMediaViewState, localMedia: LocalMedia?, - onClick: () -> Unit, modifier: Modifier = Modifier, ) { if (LocalInspectionMode.current) { @@ -155,7 +160,6 @@ private fun MediaVideoView( ExoPlayerMediaVideoView( localMediaViewState = localMediaViewState, localMedia = localMedia, - onClick = onClick, modifier = modifier, ) } @@ -166,15 +170,25 @@ private fun MediaVideoView( private fun ExoPlayerMediaVideoView( localMediaViewState: LocalMediaViewState, localMedia: LocalMedia?, - onClick: () -> Unit, modifier: Modifier = Modifier, ) { var playableState: PlayableState.Playable by remember { - mutableStateOf(PlayableState.Playable(isPlaying = false, isShowingControls = false)) + mutableStateOf( + PlayableState.Playable( + isPlaying = false, + progressInMillis = 0, + durationInMillis = 0, + isShowingControls = false, + isMuted = false, + ) + ) } localMediaViewState.playableState = playableState val context = LocalContext.current + val exoPlayer = remember { + ExoPlayerWrapper.create(context) + } val playerListener = object : Player.Listener { override fun onRenderedFirstFrame() { localMediaViewState.isReady = true @@ -183,13 +197,48 @@ private fun ExoPlayerMediaVideoView( override fun onIsPlayingChanged(isPlaying: Boolean) { playableState = playableState.copy(isPlaying = isPlaying) } + + override fun onVolumeChanged(volume: Float) { + playableState = playableState.copy(isMuted = volume == 0f) + } + + override fun onTimelineChanged(timeline: Timeline, reason: Int) { + if (reason == Player.TIMELINE_CHANGE_REASON_SOURCE_UPDATE) { + playableState = playableState.copy( + durationInMillis = exoPlayer.duration, + ) + } + } } - val exoPlayer = remember { - ExoPlayerWrapper.create(context) - .apply { - addListener(playerListener) - this.prepare() + + LaunchedEffect(Unit) { + exoPlayer.addListener(playerListener) + exoPlayer.prepare() + } + + var autoHideController by remember { mutableIntStateOf(0) } + + LaunchedEffect(autoHideController) { + delay(5.seconds) + if (exoPlayer.isPlaying) { + playableState = playableState.copy(isShowingControls = false) + } + } + + LaunchedEffect(exoPlayer.isPlaying) { + if (exoPlayer.isPlaying) { + while (true) { + playableState = playableState.copy( + progressInMillis = exoPlayer.currentPosition, + ) + delay(200) } + } else { + // Ensure we render the final state + playableState = playableState.copy( + progressInMillis = exoPlayer.currentPosition, + ) + } } if (localMedia?.uri != null) { LaunchedEffect(localMedia.uri) { @@ -200,34 +249,64 @@ private fun ExoPlayerMediaVideoView( exoPlayer.setMediaItems(emptyList()) } KeepScreenOn(playableState.isPlaying) - AndroidView( - factory = { - PlayerView(context).apply { - player = exoPlayer - resizeMode = AspectRatioFrameLayout.RESIZE_MODE_FIT - layoutParams = FrameLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT) - setOnClickListener { - onClick() - } - setControllerVisibilityListener(PlayerView.ControllerVisibilityListener { visibility -> - val isShowingControls = visibility == View.VISIBLE - playableState = playableState.copy(isShowingControls = isShowingControls) - }) - controllerShowTimeoutMs = 1500 - setShowPreviousButton(false) - setShowFastForwardButton(false) - setShowRewindButton(false) - setShowNextButton(false) - showController() - } - }, - onRelease = { playerView -> - playerView.setOnClickListener(null) - playerView.setControllerVisibilityListener(null as PlayerView.ControllerVisibilityListener?) - playerView.player = null - }, + Box( modifier = modifier - ) + .background(ElementTheme.colors.bgSubtlePrimary) + .wrapContentSize(), + ) { + AndroidView( + modifier = Modifier.fillMaxSize(), + factory = { + PlayerView(context).apply { + player = exoPlayer + resizeMode = AspectRatioFrameLayout.RESIZE_MODE_FIT + layoutParams = FrameLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT) + setOnClickListener { + autoHideController++ + playableState = playableState.copy(isShowingControls = !playableState.isShowingControls) + } + useController = false + } + }, + onRelease = { playerView -> + playerView.setOnClickListener(null) + playerView.setControllerVisibilityListener(null as PlayerView.ControllerVisibilityListener?) + playerView.player = null + }, + ) + MediaPlayerControllerView( + state = MediaPlayerControllerState( + isVisible = playableState.isShowingControls, + playableState = playableState, + ), + onTogglePlay = { + autoHideController++ + if (exoPlayer.isPlaying) { + exoPlayer.pause() + } else { + if (exoPlayer.playbackState == Player.STATE_ENDED) { + exoPlayer.seekTo(0) + } else { + exoPlayer.play() + } + } + }, + onSeekChange = { + autoHideController++ + if (exoPlayer.isPlaying.not()) { + exoPlayer.play() + } + exoPlayer.seekTo(it.toLong()) + }, + onToggleMute = { + autoHideController++ + exoPlayer.volume = if (exoPlayer.volume == 1f) 0f else 1f + }, + modifier = Modifier + .fillMaxWidth() + .align(Alignment.BottomCenter), + ) + } OnLifecycleEvent { _, event -> when (event) { diff --git a/libraries/mediaviewer/api/src/main/kotlin/io/element/android/libraries/mediaviewer/api/local/LocalMediaViewState.kt b/libraries/mediaviewer/api/src/main/kotlin/io/element/android/libraries/mediaviewer/api/local/LocalMediaViewState.kt index 0c4e2af3086..54eb3f09707 100644 --- a/libraries/mediaviewer/api/src/main/kotlin/io/element/android/libraries/mediaviewer/api/local/LocalMediaViewState.kt +++ b/libraries/mediaviewer/api/src/main/kotlin/io/element/android/libraries/mediaviewer/api/local/LocalMediaViewState.kt @@ -30,7 +30,10 @@ sealed interface PlayableState { data object NotPlayable : PlayableState data class Playable( val isPlaying: Boolean, - val isShowingControls: Boolean + val progressInMillis: Long, + val durationInMillis: Long, + val isShowingControls: Boolean, + val isMuted: Boolean, ) : PlayableState } diff --git a/libraries/mediaviewer/api/src/main/kotlin/io/element/android/libraries/mediaviewer/api/player/MediaPlayerControllerState.kt b/libraries/mediaviewer/api/src/main/kotlin/io/element/android/libraries/mediaviewer/api/player/MediaPlayerControllerState.kt new file mode 100644 index 00000000000..b6963a16b13 --- /dev/null +++ b/libraries/mediaviewer/api/src/main/kotlin/io/element/android/libraries/mediaviewer/api/player/MediaPlayerControllerState.kt @@ -0,0 +1,15 @@ +/* + * Copyright 2024 New Vector Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only + * Please see LICENSE in the repository root for full details. + */ + +package io.element.android.libraries.mediaviewer.api.player + +import io.element.android.libraries.mediaviewer.api.local.PlayableState + +data class MediaPlayerControllerState( + val isVisible: Boolean, + val playableState: PlayableState.Playable, +) diff --git a/libraries/mediaviewer/api/src/main/kotlin/io/element/android/libraries/mediaviewer/api/player/MediaPlayerControllerStateProvider.kt b/libraries/mediaviewer/api/src/main/kotlin/io/element/android/libraries/mediaviewer/api/player/MediaPlayerControllerStateProvider.kt new file mode 100644 index 00000000000..64b8ef241e4 --- /dev/null +++ b/libraries/mediaviewer/api/src/main/kotlin/io/element/android/libraries/mediaviewer/api/player/MediaPlayerControllerStateProvider.kt @@ -0,0 +1,55 @@ +/* + * Copyright 2024 New Vector Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only + * Please see LICENSE in the repository root for full details. + */ + +package io.element.android.libraries.mediaviewer.api.player + +import androidx.compose.ui.tooling.preview.PreviewParameterProvider +import io.element.android.libraries.mediaviewer.api.local.PlayableState + +open class MediaPlayerControllerStateProvider : PreviewParameterProvider { + override val values: Sequence = sequenceOf( + aMediaPlayerControllerState(), + aMediaPlayerControllerState( + isPlaying = false, + progressInMillis = 59_000, + durationInMillis = 83_000, + isMuted = true, + ), + ) +} + +private fun aMediaPlayerControllerState( + isVisible: Boolean = true, + isPlaying: Boolean = false, + progressInMillis: Long = 0, + // Default to 1 minute and 23 seconds + durationInMillis: Long = 83_000, + isMuted: Boolean = false, +) = MediaPlayerControllerState( + isVisible = isVisible, + playableState = aPlayableState( + isPlaying = isPlaying, + progressInMillis = progressInMillis, + durationInMillis = durationInMillis, + isMuted = isMuted, + ), +) + +private fun aPlayableState( + isPlaying: Boolean = false, + progressInMillis: Long = 0, + // Default to 1 minute and 23 seconds + durationInMillis: Long = 83_000, + isShowingControls: Boolean = false, + isMuted: Boolean = false, +) = PlayableState.Playable( + isPlaying = isPlaying, + progressInMillis = progressInMillis, + durationInMillis = durationInMillis, + isShowingControls = isShowingControls, + isMuted = isMuted, +) diff --git a/libraries/mediaviewer/api/src/main/kotlin/io/element/android/libraries/mediaviewer/api/player/MediaPlayerControllerView.kt b/libraries/mediaviewer/api/src/main/kotlin/io/element/android/libraries/mediaviewer/api/player/MediaPlayerControllerView.kt new file mode 100644 index 00000000000..b3c25edbdbe --- /dev/null +++ b/libraries/mediaviewer/api/src/main/kotlin/io/element/android/libraries/mediaviewer/api/player/MediaPlayerControllerView.kt @@ -0,0 +1,151 @@ +/* + * Copyright 2024 New Vector Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only + * Please see LICENSE in the repository root for full details. + */ + +package io.element.android.libraries.mediaviewer.api.player + +import androidx.compose.animation.AnimatedVisibility +import androidx.compose.animation.fadeIn +import androidx.compose.animation.fadeOut +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.widthIn +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableFloatStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.style.TextAlign +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.dateformatter.api.toHumanReadableDuration +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.theme.components.Slider +import io.element.android.libraries.designsystem.theme.components.Text +import io.element.android.libraries.ui.strings.CommonStrings + +@Composable +fun MediaPlayerControllerView( + state: MediaPlayerControllerState, + onTogglePlay: () -> Unit, + onSeekChange: (Float) -> Unit, + onToggleMute: () -> Unit, + modifier: Modifier = Modifier, +) { + AnimatedVisibility( + visible = state.isVisible, + modifier = modifier, + enter = fadeIn(), + exit = fadeOut(), + ) { + Box( + modifier = Modifier + .background(color = Color(0x99101317)) + .padding(horizontal = 8.dp, vertical = 4.dp), + contentAlignment = Alignment.Center, + ) { + Row( + modifier = Modifier + .widthIn(max = 480.dp), + verticalAlignment = Alignment.CenterVertically, + ) { + IconButton( + onClick = onTogglePlay, + ) { + if (state.playableState.isPlaying) { + Icon( + imageVector = CompoundIcons.PauseSolid(), + tint = ElementTheme.colors.iconPrimary, + contentDescription = stringResource(CommonStrings.a11y_pause) + ) + } else { + Icon( + imageVector = CompoundIcons.PlaySolid(), + tint = ElementTheme.colors.iconPrimary, + contentDescription = stringResource(CommonStrings.a11y_play) + ) + } + } + Text( + modifier = Modifier + .widthIn(min = 48.dp) + .padding(horizontal = 8.dp), + text = state.playableState.progressInMillis.toHumanReadableDuration(), + textAlign = TextAlign.Center, + color = ElementTheme.colors.textPrimary, + style = ElementTheme.typography.fontBodyXsMedium, + ) + var lastSelectedValue by remember { mutableFloatStateOf(-1f) } + Slider( + modifier = Modifier.weight(1f), + valueRange = 0f..state.playableState.durationInMillis.toFloat(), + value = lastSelectedValue.takeIf { it >= 0 } ?: state.playableState.progressInMillis.toFloat(), + onValueChange = { + lastSelectedValue = it + }, + onValueChangeFinish = { + onSeekChange(lastSelectedValue) + lastSelectedValue = -1f + }, + useCustomLayout = true, + ) + val formattedDuration = remember(state.playableState.durationInMillis) { + state.playableState.durationInMillis.toHumanReadableDuration() + } + Text( + modifier = Modifier + .widthIn(min = 48.dp) + .padding(horizontal = 8.dp), + text = formattedDuration, + textAlign = TextAlign.Center, + color = ElementTheme.colors.textPrimary, + style = ElementTheme.typography.fontBodyXsMedium, + ) + IconButton( + onClick = onToggleMute, + ) { + if (state.playableState.isMuted) { + Icon( + imageVector = CompoundIcons.VolumeOffSolid(), + tint = ElementTheme.colors.iconPrimary, + contentDescription = stringResource(CommonStrings.common_unmute) + ) + } else { + Icon( + imageVector = CompoundIcons.VolumeOnSolid(), + tint = ElementTheme.colors.iconPrimary, + contentDescription = stringResource(CommonStrings.common_mute) + ) + } + } + } + } + } +} + +@PreviewsDayNight +@Composable +private fun MediaPlayerControlBarPreview( + @PreviewParameter(MediaPlayerControllerStateProvider::class) state: MediaPlayerControllerState +) = ElementPreview { + MediaPlayerControllerView( + state = state, + onTogglePlay = {}, + onSeekChange = {}, + onToggleMute = {}, + ) +} From 28ed0920a4c37234252334a931e233a97ebcbf46 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 27 Nov 2024 16:12:28 +0100 Subject: [PATCH 34/96] Cleanup --- .../android/libraries/dateformatter/api/DurationFormatter.kt | 2 +- .../mediaviewer/api/player/MediaPlayerControllerView.kt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/dateformatter/api/src/main/kotlin/io/element/android/libraries/dateformatter/api/DurationFormatter.kt b/libraries/dateformatter/api/src/main/kotlin/io/element/android/libraries/dateformatter/api/DurationFormatter.kt index 50a3b27204b..7f8473b416f 100644 --- a/libraries/dateformatter/api/src/main/kotlin/io/element/android/libraries/dateformatter/api/DurationFormatter.kt +++ b/libraries/dateformatter/api/src/main/kotlin/io/element/android/libraries/dateformatter/api/DurationFormatter.kt @@ -30,7 +30,7 @@ import java.util.Locale fun Long.toHumanReadableDuration(): String { val inSeconds = this / 1_000 val hours = inSeconds / 3_600 - val minutes = (inSeconds % 3_600) / 60 + val minutes = inSeconds % 3_600 / 60 val seconds = inSeconds % 60 return if (hours > 0) { String.format(Locale.US, "%d:%02d:%02d", hours, minutes, seconds) diff --git a/libraries/mediaviewer/api/src/main/kotlin/io/element/android/libraries/mediaviewer/api/player/MediaPlayerControllerView.kt b/libraries/mediaviewer/api/src/main/kotlin/io/element/android/libraries/mediaviewer/api/player/MediaPlayerControllerView.kt index b3c25edbdbe..75a15421142 100644 --- a/libraries/mediaviewer/api/src/main/kotlin/io/element/android/libraries/mediaviewer/api/player/MediaPlayerControllerView.kt +++ b/libraries/mediaviewer/api/src/main/kotlin/io/element/android/libraries/mediaviewer/api/player/MediaPlayerControllerView.kt @@ -139,7 +139,7 @@ fun MediaPlayerControllerView( @PreviewsDayNight @Composable -private fun MediaPlayerControlBarPreview( +internal fun MediaPlayerControllerViewPreview( @PreviewParameter(MediaPlayerControllerStateProvider::class) state: MediaPlayerControllerState ) = ElementPreview { MediaPlayerControllerView( From c8519b3d082609a82b1237310064c42f25b92bd6 Mon Sep 17 00:00:00 2001 From: ElementBot Date: Wed, 27 Nov 2024 15:25:40 +0000 Subject: [PATCH 35/96] Update screenshots --- ...aries.designsystem.theme.components_Sliders_Sliders_en.png | 4 ++-- ...iaviewer.api.player_MediaPlayerControllerView_Day_0_en.png | 3 +++ ...iaviewer.api.player_MediaPlayerControllerView_Day_1_en.png | 3 +++ ...viewer.api.player_MediaPlayerControllerView_Night_0_en.png | 3 +++ ...viewer.api.player_MediaPlayerControllerView_Night_1_en.png | 3 +++ 5 files changed, 14 insertions(+), 2 deletions(-) create mode 100644 tests/uitests/src/test/snapshots/images/libraries.mediaviewer.api.player_MediaPlayerControllerView_Day_0_en.png create mode 100644 tests/uitests/src/test/snapshots/images/libraries.mediaviewer.api.player_MediaPlayerControllerView_Day_1_en.png create mode 100644 tests/uitests/src/test/snapshots/images/libraries.mediaviewer.api.player_MediaPlayerControllerView_Night_0_en.png create mode 100644 tests/uitests/src/test/snapshots/images/libraries.mediaviewer.api.player_MediaPlayerControllerView_Night_1_en.png diff --git a/tests/uitests/src/test/snapshots/images/libraries.designsystem.theme.components_Sliders_Sliders_en.png b/tests/uitests/src/test/snapshots/images/libraries.designsystem.theme.components_Sliders_Sliders_en.png index 432ee9660e1..cdd5065f25e 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.designsystem.theme.components_Sliders_Sliders_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.designsystem.theme.components_Sliders_Sliders_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:99102e56ca747eb69e03543032915e9a6a608d6013843889ad0dcd3e1953141c -size 11451 +oid sha256:05c37f69de81b26ce0083047cb18120300cc0e76aa7e3c0d3c24ba5de39681bd +size 14134 diff --git a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.api.player_MediaPlayerControllerView_Day_0_en.png b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.api.player_MediaPlayerControllerView_Day_0_en.png new file mode 100644 index 00000000000..5a9251549c9 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.api.player_MediaPlayerControllerView_Day_0_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:e7a7ea1da7e7602cc53cc162c4a685516a7a46ca148eafca6e19a5748630bda5 +size 7036 diff --git a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.api.player_MediaPlayerControllerView_Day_1_en.png b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.api.player_MediaPlayerControllerView_Day_1_en.png new file mode 100644 index 00000000000..79c67135de1 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.api.player_MediaPlayerControllerView_Day_1_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1d3346676b7c7d227f9512749d3a9b89ca50b70e3133475321fe8f063f65654c +size 7312 diff --git a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.api.player_MediaPlayerControllerView_Night_0_en.png b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.api.player_MediaPlayerControllerView_Night_0_en.png new file mode 100644 index 00000000000..08774369135 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.api.player_MediaPlayerControllerView_Night_0_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:9f69e358ddd7e00f7301598f5dd235a2f5b9077f8926c2bfa3a4bca1168900f0 +size 7173 diff --git a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.api.player_MediaPlayerControllerView_Night_1_en.png b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.api.player_MediaPlayerControllerView_Night_1_en.png new file mode 100644 index 00000000000..957aa8261f0 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.api.player_MediaPlayerControllerView_Night_1_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:71415f1799612db09acf890773bbeed1f060ab986930f77276fff5ddd81ea018 +size 7518 From da8056dcdbfdc99bbf2356ceac0436c8286a9f29 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 27 Nov 2024 17:11:30 +0100 Subject: [PATCH 36/96] Fix navigation issue when entering recovery key after navigating from the banner. --- .../io/element/android/appnav/LoggedInFlowNode.kt | 5 +++++ .../securebackup/impl/SecureBackupFlowNode.kt | 13 +++++++++---- 2 files changed, 14 insertions(+), 4 deletions(-) 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 5677d3834d5..fa161554cdf 100644 --- a/appnav/src/main/kotlin/io/element/android/appnav/LoggedInFlowNode.kt +++ b/appnav/src/main/kotlin/io/element/android/appnav/LoggedInFlowNode.kt @@ -400,6 +400,11 @@ class LoggedInFlowNode @AssistedInject constructor( is NavTarget.SecureBackup -> { secureBackupEntryPoint.nodeBuilder(this, buildContext) .params(SecureBackupEntryPoint.Params(initialElement = navTarget.initialElement)) + .callback(object : SecureBackupEntryPoint.Callback { + override fun onDone() { + backstack.pop() + } + }) .build() } NavTarget.Ftue -> { diff --git a/features/securebackup/impl/src/main/kotlin/io/element/android/features/securebackup/impl/SecureBackupFlowNode.kt b/features/securebackup/impl/src/main/kotlin/io/element/android/features/securebackup/impl/SecureBackupFlowNode.kt index 5d9aeec21e2..3fb2d0949a4 100644 --- a/features/securebackup/impl/src/main/kotlin/io/element/android/features/securebackup/impl/SecureBackupFlowNode.kt +++ b/features/securebackup/impl/src/main/kotlin/io/element/android/features/securebackup/impl/SecureBackupFlowNode.kt @@ -111,10 +111,15 @@ class SecureBackupFlowNode @AssistedInject constructor( NavTarget.EnterRecoveryKey -> { val callback = object : SecureBackupEnterRecoveryKeyNode.Callback { override fun onEnterRecoveryKeySuccess() { - if (callbacks.isNotEmpty()) { - callbacks.forEach { it.onDone() } - } else { - backstack.pop() + when (plugins.filterIsInstance().first().initialElement) { + SecureBackupEntryPoint.InitialTarget.EnterRecoveryKey -> { + callbacks.forEach { it.onDone() } + } + SecureBackupEntryPoint.InitialTarget.ResetIdentity, + SecureBackupEntryPoint.InitialTarget.Root, + SecureBackupEntryPoint.InitialTarget.SetUpRecovery -> { + backstack.pop() + } } } } From b013b312b83bb36742c488a498de605139e0fed9 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 28 Nov 2024 09:12:14 +0100 Subject: [PATCH 37/96] Change wording of message action "Copy" from "Copy" to "Copy text" --- .../messages/impl/MessagesPresenter.kt | 2 +- .../impl/actionlist/ActionListPresenter.kt | 2 +- .../actionlist/ActionListStateProvider.kt | 4 ++-- .../actionlist/model/TimelineItemAction.kt | 2 +- .../messages/impl/MessagesPresenterTest.kt | 2 +- .../actionlist/ActionListPresenterTest.kt | 24 +++++++++---------- .../src/main/res/values/localazy.xml | 2 ++ 7 files changed, 20 insertions(+), 18 deletions(-) diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesPresenter.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesPresenter.kt index e39056ec9b7..2aed85c5fb8 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesPresenter.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesPresenter.kt @@ -272,7 +272,7 @@ class MessagesPresenter @AssistedInject constructor( timelineState: TimelineState, ) = launch { when (action) { - TimelineItemAction.Copy -> handleCopyContents(targetEvent) + TimelineItemAction.CopyText -> handleCopyContents(targetEvent) TimelineItemAction.CopyLink -> handleCopyLink(targetEvent) TimelineItemAction.Redact -> handleActionRedact(targetEvent) TimelineItemAction.Edit -> handleActionEdit(targetEvent, composerState, enableTextFormatting) diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/actionlist/ActionListPresenter.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/actionlist/ActionListPresenter.kt index f2b97769c03..17813ef1392 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/actionlist/ActionListPresenter.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/actionlist/ActionListPresenter.kt @@ -183,7 +183,7 @@ class DefaultActionListPresenter @AssistedInject constructor( } } if (timelineItem.content.canBeCopied()) { - add(TimelineItemAction.Copy) + add(TimelineItemAction.CopyText) } if (timelineItem.isRemote) { add(TimelineItemAction.CopyLink) diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/actionlist/ActionListStateProvider.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/actionlist/ActionListStateProvider.kt index 78e65c839a7..90e412d2dbc 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/actionlist/ActionListStateProvider.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/actionlist/ActionListStateProvider.kt @@ -165,7 +165,7 @@ fun aTimelineItemActionList(): ImmutableList { return persistentListOf( TimelineItemAction.Reply, TimelineItemAction.Forward, - TimelineItemAction.Copy, + TimelineItemAction.CopyText, TimelineItemAction.CopyLink, TimelineItemAction.Edit, TimelineItemAction.Redact, @@ -178,7 +178,7 @@ fun aTimelineItemPollActionList(): ImmutableList { return persistentListOf( TimelineItemAction.EndPoll, TimelineItemAction.Reply, - TimelineItemAction.Copy, + TimelineItemAction.CopyText, TimelineItemAction.CopyLink, TimelineItemAction.ViewSource, TimelineItemAction.ReportContent, diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/actionlist/model/TimelineItemAction.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/actionlist/model/TimelineItemAction.kt index 979f0412974..668c97d6972 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/actionlist/model/TimelineItemAction.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/actionlist/model/TimelineItemAction.kt @@ -22,7 +22,7 @@ sealed class TimelineItemAction( ) { data object ViewInTimeline : TimelineItemAction(CommonStrings.action_view_in_timeline, CompoundDrawables.ic_compound_visibility_on) data object Forward : TimelineItemAction(CommonStrings.action_forward, CompoundDrawables.ic_compound_forward) - data object Copy : TimelineItemAction(CommonStrings.action_copy, CompoundDrawables.ic_compound_copy) + data object CopyText : TimelineItemAction(CommonStrings.action_copy_text, CompoundDrawables.ic_compound_copy) data object CopyLink : TimelineItemAction(CommonStrings.action_copy_link_to_message, CompoundDrawables.ic_compound_link) data object Redact : TimelineItemAction(CommonStrings.action_remove, CompoundDrawables.ic_compound_delete, destructive = true) data object Reply : TimelineItemAction(CommonStrings.action_reply, CompoundDrawables.ic_compound_reply) diff --git a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/MessagesPresenterTest.kt b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/MessagesPresenterTest.kt index 61606a51de9..057694590cf 100644 --- a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/MessagesPresenterTest.kt +++ b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/MessagesPresenterTest.kt @@ -242,7 +242,7 @@ class MessagesPresenterTest { presenter.present() }.test { val initialState = awaitItem() - initialState.eventSink(MessagesEvents.HandleAction(TimelineItemAction.Copy, event)) + initialState.eventSink(MessagesEvents.HandleAction(TimelineItemAction.CopyText, event)) skipItems(2) assertThat(clipboardHelper.clipboardContents).isEqualTo((event.content as TimelineItemTextContent).body) } diff --git a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/actionlist/ActionListPresenterTest.kt b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/actionlist/ActionListPresenterTest.kt index aedd0cdc14b..5d5b69a48e3 100644 --- a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/actionlist/ActionListPresenterTest.kt +++ b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/actionlist/ActionListPresenterTest.kt @@ -176,7 +176,7 @@ class ActionListPresenterTest { TimelineItemAction.Reply, TimelineItemAction.Forward, TimelineItemAction.Pin, - TimelineItemAction.Copy, + TimelineItemAction.CopyText, TimelineItemAction.CopyLink, TimelineItemAction.ViewSource, TimelineItemAction.ReportContent, @@ -221,7 +221,7 @@ class ActionListPresenterTest { TimelineItemAction.ReplyInThread, TimelineItemAction.Forward, TimelineItemAction.Pin, - TimelineItemAction.Copy, + TimelineItemAction.CopyText, TimelineItemAction.CopyLink, TimelineItemAction.ViewSource, TimelineItemAction.ReportContent, @@ -268,7 +268,7 @@ class ActionListPresenterTest { actions = persistentListOf( TimelineItemAction.Forward, TimelineItemAction.Pin, - TimelineItemAction.Copy, + TimelineItemAction.CopyText, TimelineItemAction.CopyLink, TimelineItemAction.ViewSource, TimelineItemAction.ReportContent, @@ -314,7 +314,7 @@ class ActionListPresenterTest { TimelineItemAction.Reply, TimelineItemAction.Forward, TimelineItemAction.Pin, - TimelineItemAction.Copy, + TimelineItemAction.CopyText, TimelineItemAction.CopyLink, TimelineItemAction.ViewSource, TimelineItemAction.ReportContent, @@ -361,7 +361,7 @@ class ActionListPresenterTest { TimelineItemAction.Reply, TimelineItemAction.Forward, TimelineItemAction.Pin, - TimelineItemAction.Copy, + TimelineItemAction.CopyText, TimelineItemAction.CopyLink, TimelineItemAction.ViewSource, TimelineItemAction.ReportContent, @@ -410,7 +410,7 @@ class ActionListPresenterTest { TimelineItemAction.Forward, TimelineItemAction.Edit, TimelineItemAction.Pin, - TimelineItemAction.Copy, + TimelineItemAction.CopyText, TimelineItemAction.CopyLink, TimelineItemAction.ViewSource, TimelineItemAction.Redact, @@ -455,7 +455,7 @@ class ActionListPresenterTest { TimelineItemAction.Forward, TimelineItemAction.Edit, TimelineItemAction.Pin, - TimelineItemAction.Copy, + TimelineItemAction.CopyText, TimelineItemAction.CopyLink, TimelineItemAction.ViewSource, TimelineItemAction.Redact, @@ -503,7 +503,7 @@ class ActionListPresenterTest { TimelineItemAction.Forward, TimelineItemAction.Edit, TimelineItemAction.Pin, - TimelineItemAction.Copy, + TimelineItemAction.CopyText, TimelineItemAction.CopyLink, TimelineItemAction.ViewSource, ) @@ -766,7 +766,7 @@ class ActionListPresenterTest { TimelineItemAction.Forward, TimelineItemAction.Edit, TimelineItemAction.Pin, - TimelineItemAction.Copy, + TimelineItemAction.CopyText, TimelineItemAction.CopyLink, TimelineItemAction.Redact, ) @@ -812,7 +812,7 @@ class ActionListPresenterTest { TimelineItemAction.Reply, TimelineItemAction.Forward, TimelineItemAction.Edit, - TimelineItemAction.Copy, + TimelineItemAction.CopyText, TimelineItemAction.CopyLink, TimelineItemAction.ViewSource, TimelineItemAction.Redact, @@ -867,7 +867,7 @@ class ActionListPresenterTest { TimelineItemAction.Forward, TimelineItemAction.Edit, TimelineItemAction.Unpin, - TimelineItemAction.Copy, + TimelineItemAction.CopyText, TimelineItemAction.CopyLink, TimelineItemAction.ViewSource, TimelineItemAction.Redact, @@ -961,7 +961,7 @@ class ActionListPresenterTest { verifiedUserSendFailure = VerifiedUserSendFailure.None, actions = persistentListOf( TimelineItemAction.Edit, - TimelineItemAction.Copy, + TimelineItemAction.CopyText, TimelineItemAction.Redact, ) ) diff --git a/libraries/ui-strings/src/main/res/values/localazy.xml b/libraries/ui-strings/src/main/res/values/localazy.xml index 18d580d9f4c..4f7af2d51c3 100644 --- a/libraries/ui-strings/src/main/res/values/localazy.xml +++ b/libraries/ui-strings/src/main/res/values/localazy.xml @@ -46,8 +46,10 @@ "Confirm password" "Continue" "Copy" + "Copy caption" "Copy link" "Copy link to message" + "Copy text" "Create" "Create a room" "Deactivate" From 37f3e259f819aa92edb755102e30a6cb3c267220 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 28 Nov 2024 09:31:48 +0100 Subject: [PATCH 38/96] Add "Copy caption" action for Event with Caption --- .../messages/impl/MessagesPresenter.kt | 11 +++- .../impl/actionlist/ActionListPresenter.kt | 3 ++ .../actionlist/model/TimelineItemAction.kt | 1 + .../actionlist/ActionListPresenterTest.kt | 53 ++++++++++++++++++- 4 files changed, 65 insertions(+), 3 deletions(-) diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesPresenter.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesPresenter.kt index 2aed85c5fb8..a32f33d6ce6 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesPresenter.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesPresenter.kt @@ -273,6 +273,7 @@ class MessagesPresenter @AssistedInject constructor( ) = launch { when (action) { TimelineItemAction.CopyText -> handleCopyContents(targetEvent) + TimelineItemAction.CopyCaption -> handleCopyCaption(targetEvent) TimelineItemAction.CopyLink -> handleCopyLink(targetEvent) TimelineItemAction.Redact -> handleActionRedact(targetEvent) TimelineItemAction.Edit -> handleActionEdit(targetEvent, composerState, enableTextFormatting) @@ -488,11 +489,17 @@ class MessagesPresenter @AssistedInject constructor( is TimelineItemStateContent -> event.content.body else -> return } - clipboardHelper.copyPlainText(content) - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) { snackbarDispatcher.post(SnackbarMessage(R.string.screen_room_timeline_message_copied)) } } + + private suspend fun handleCopyCaption(event: TimelineItem.Event) { + val content = (event.content as? TimelineItemEventContentWithAttachment)?.caption ?: return + clipboardHelper.copyPlainText(content) + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) { + snackbarDispatcher.post(SnackbarMessage(CommonStrings.common_copied_to_clipboard)) + } + } } diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/actionlist/ActionListPresenter.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/actionlist/ActionListPresenter.kt index 17813ef1392..ae324aab0e8 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/actionlist/ActionListPresenter.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/actionlist/ActionListPresenter.kt @@ -137,6 +137,7 @@ class DefaultActionListPresenter @AssistedInject constructor( } } + // See order in https://www.figma.com/design/ux3tYoZV9WghC7hHT9Fhk0/Compound-iOS-Components?node-id=2946-2392 private suspend fun buildActions( timelineItem: TimelineItem.Event, usersEventPermissions: UserEventPermissions, @@ -184,6 +185,8 @@ class DefaultActionListPresenter @AssistedInject constructor( } if (timelineItem.content.canBeCopied()) { add(TimelineItemAction.CopyText) + } else if ((timelineItem.content as? TimelineItemEventContentWithAttachment)?.caption.isNullOrBlank().not()) { + add(TimelineItemAction.CopyCaption) } if (timelineItem.isRemote) { add(TimelineItemAction.CopyLink) diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/actionlist/model/TimelineItemAction.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/actionlist/model/TimelineItemAction.kt index 668c97d6972..f700dcc6b1e 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/actionlist/model/TimelineItemAction.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/actionlist/model/TimelineItemAction.kt @@ -23,6 +23,7 @@ sealed class TimelineItemAction( data object ViewInTimeline : TimelineItemAction(CommonStrings.action_view_in_timeline, CompoundDrawables.ic_compound_visibility_on) data object Forward : TimelineItemAction(CommonStrings.action_forward, CompoundDrawables.ic_compound_forward) data object CopyText : TimelineItemAction(CommonStrings.action_copy_text, CompoundDrawables.ic_compound_copy) + data object CopyCaption : TimelineItemAction(CommonStrings.action_copy_caption, CompoundDrawables.ic_compound_copy) data object CopyLink : TimelineItemAction(CommonStrings.action_copy_link_to_message, CompoundDrawables.ic_compound_link) data object Redact : TimelineItemAction(CommonStrings.action_remove, CompoundDrawables.ic_compound_delete, destructive = true) data object Reply : TimelineItemAction(CommonStrings.action_reply, CompoundDrawables.ic_compound_reply) diff --git a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/actionlist/ActionListPresenterTest.kt b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/actionlist/ActionListPresenterTest.kt index 5d5b69a48e3..1e4b92d91d0 100644 --- a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/actionlist/ActionListPresenterTest.kt +++ b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/actionlist/ActionListPresenterTest.kt @@ -647,6 +647,7 @@ class ActionListPresenterTest { TimelineItemAction.Reply, TimelineItemAction.Forward, TimelineItemAction.EditCaption, + TimelineItemAction.CopyCaption, TimelineItemAction.RemoveCaption, TimelineItemAction.Pin, TimelineItemAction.CopyLink, @@ -660,6 +661,54 @@ class ActionListPresenterTest { } } + @Test + fun `present - compute for a media with caption item - other user event`() = runTest { + val presenter = createActionListPresenter(isDeveloperModeEnabled = true, isPinFeatureEnabled = true) + moleculeFlow(RecompositionMode.Immediate) { + presenter.present() + }.test { + val initialState = awaitItem() + val messageEvent = aMessageEvent( + isMine = false, + isEditable = false, + content = aTimelineItemImageContent( + caption = A_CAPTION, + ), + ) + initialState.eventSink.invoke( + ActionListEvents.ComputeForMessage( + event = messageEvent, + userEventPermissions = aUserEventPermissions( + canRedactOwn = true, + canRedactOther = false, + canSendMessage = true, + canSendReaction = true, + canPinUnpin = true, + ), + ) + ) + val successState = awaitItem() + assertThat(successState.target).isEqualTo( + ActionListState.Target.Success( + event = messageEvent, + displayEmojiReactions = true, + verifiedUserSendFailure = VerifiedUserSendFailure.None, + actions = persistentListOf( + TimelineItemAction.Reply, + TimelineItemAction.Forward, + TimelineItemAction.CopyCaption, + TimelineItemAction.Pin, + TimelineItemAction.CopyLink, + TimelineItemAction.ViewSource, + TimelineItemAction.Redact, + ) + ) + ) + initialState.eventSink.invoke(ActionListEvents.Clear) + assertThat(awaitItem().target).isEqualTo(ActionListState.Target.None) + } + } + @Test fun `present - compute for a state item in debug build`() = runTest { val presenter = createActionListPresenter(isDeveloperModeEnabled = true, isPinFeatureEnabled = true) @@ -1105,7 +1154,9 @@ class ActionListPresenterTest { val messageEvent = aMessageEvent( isMine = true, isEditable = false, - content = aTimelineItemVoiceContent(), + content = aTimelineItemVoiceContent( + caption = null, + ), ) initialState.eventSink.invoke( ActionListEvents.ComputeForMessage( From 98578681ffd98ad989e68b1644e727aa4dec5a6f Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 28 Nov 2024 09:37:39 +0100 Subject: [PATCH 39/96] Improve the preview --- .../actionlist/ActionListStateProvider.kt | 33 +++++++++++++------ 1 file changed, 23 insertions(+), 10 deletions(-) diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/actionlist/ActionListStateProvider.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/actionlist/ActionListStateProvider.kt index 90e412d2dbc..0323a2e6c69 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/actionlist/ActionListStateProvider.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/actionlist/ActionListStateProvider.kt @@ -23,6 +23,7 @@ import io.element.android.features.messages.impl.timeline.model.event.aTimelineI import io.element.android.libraries.matrix.api.timeline.item.event.MessageShield import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.persistentListOf +import kotlinx.collections.immutable.toPersistentList open class ActionListStateProvider : PreviewParameterProvider { override val values: Sequence @@ -50,7 +51,9 @@ open class ActionListStateProvider : PreviewParameterProvider { ), displayEmojiReactions = true, verifiedUserSendFailure = VerifiedUserSendFailure.None, - actions = aTimelineItemActionList(), + actions = aTimelineItemActionList( + copyAction = TimelineItemAction.CopyCaption, + ), ) ), anActionListState( @@ -61,7 +64,9 @@ open class ActionListStateProvider : PreviewParameterProvider { ), displayEmojiReactions = true, verifiedUserSendFailure = VerifiedUserSendFailure.None, - actions = aTimelineItemActionList(), + actions = aTimelineItemActionList( + copyAction = TimelineItemAction.CopyCaption, + ), ) ), anActionListState( @@ -72,7 +77,9 @@ open class ActionListStateProvider : PreviewParameterProvider { ), displayEmojiReactions = true, verifiedUserSendFailure = VerifiedUserSendFailure.None, - actions = aTimelineItemActionList(), + actions = aTimelineItemActionList( + copyAction = null, + ), ) ), anActionListState( @@ -83,18 +90,22 @@ open class ActionListStateProvider : PreviewParameterProvider { ), displayEmojiReactions = true, verifiedUserSendFailure = VerifiedUserSendFailure.None, - actions = aTimelineItemActionList(), + actions = aTimelineItemActionList( + copyAction = TimelineItemAction.CopyCaption, + ), ) ), anActionListState( target = ActionListState.Target.Success( event = aTimelineItemEvent( - content = aTimelineItemVoiceContent(), + content = aTimelineItemVoiceContent(caption = null), timelineItemReactions = reactionsState ), displayEmojiReactions = true, verifiedUserSendFailure = VerifiedUserSendFailure.None, - actions = aTimelineItemActionList(), + actions = aTimelineItemActionList( + copyAction = null, + ), ) ), anActionListState( @@ -161,17 +172,19 @@ fun anActionListState( eventSink = eventSink ) -fun aTimelineItemActionList(): ImmutableList { - return persistentListOf( +fun aTimelineItemActionList( + copyAction: TimelineItemAction? = TimelineItemAction.CopyText +): ImmutableList { + return listOfNotNull( TimelineItemAction.Reply, TimelineItemAction.Forward, - TimelineItemAction.CopyText, + copyAction, TimelineItemAction.CopyLink, TimelineItemAction.Edit, TimelineItemAction.Redact, TimelineItemAction.ReportContent, TimelineItemAction.ViewSource, - ) + ).toPersistentList() } fun aTimelineItemPollActionList(): ImmutableList { From 67be3f08513b7fe31899a0ab212904c4a9f4927d Mon Sep 17 00:00:00 2001 From: Jorge Martin Espinosa Date: Thu, 28 Nov 2024 10:14:53 +0100 Subject: [PATCH 40/96] Element Call: display error dialog only when loading the main URL (#3962) --- .../utils/WebViewWidgetMessageInterceptor.kt | 21 ++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/features/call/impl/src/main/kotlin/io/element/android/features/call/impl/utils/WebViewWidgetMessageInterceptor.kt b/features/call/impl/src/main/kotlin/io/element/android/features/call/impl/utils/WebViewWidgetMessageInterceptor.kt index 609c04a0e61..588fd25ac06 100644 --- a/features/call/impl/src/main/kotlin/io/element/android/features/call/impl/utils/WebViewWidgetMessageInterceptor.kt +++ b/features/call/impl/src/main/kotlin/io/element/android/features/call/impl/utils/WebViewWidgetMessageInterceptor.kt @@ -66,19 +66,34 @@ class WebViewWidgetMessageInterceptor( override fun onReceivedError(view: WebView?, request: WebResourceRequest?, error: WebResourceError?) { // No network for instance, transmit the error Timber.e("onReceivedError error: ${error?.errorCode} ${error?.description}") - onError(error?.description?.toString()) + + // Only propagate the error if it happens while loading the current page + if (view?.url == request?.url.toString()) { + onError(error?.description.toString()) + } + super.onReceivedError(view, request, error) } override fun onReceivedHttpError(view: WebView?, request: WebResourceRequest?, errorResponse: WebResourceResponse?) { Timber.e("onReceivedHttpError error: ${errorResponse?.statusCode} ${errorResponse?.reasonPhrase}") - onError(errorResponse?.statusCode.toString()) + + // Only propagate the error if it happens while loading the current page + if (view?.url == request?.url.toString()) { + onError(errorResponse?.statusCode.toString()) + } + super.onReceivedHttpError(view, request, errorResponse) } override fun onReceivedSslError(view: WebView?, handler: SslErrorHandler?, error: SslError?) { Timber.e("onReceivedSslError error: ${error?.primaryError}") - onError(error?.primaryError?.toString()) + + // Only propagate the error if it happens while loading the current page + if (view?.url == error?.url.toString()) { + onError(error?.toString()) + } + super.onReceivedSslError(view, handler, error) } } From 1f991693049978eee1c9be4f9adb11cea79cd708 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 28 Nov 2024 10:04:00 +0100 Subject: [PATCH 41/96] Sort action list item. It will also ensure that the preview are closer to reality. --- .../impl/actionlist/ActionListPresenter.kt | 9 ++-- .../actionlist/ActionListStateProvider.kt | 16 ++++--- .../model/TimelineItemActionComparator.kt | 37 ++++++++++++++ .../actionlist/ActionListPresenterTest.kt | 48 +++++++++---------- 4 files changed, 76 insertions(+), 34 deletions(-) create mode 100644 features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/actionlist/model/TimelineItemActionComparator.kt diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/actionlist/ActionListPresenter.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/actionlist/ActionListPresenter.kt index ae324aab0e8..411ff37c8f8 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/actionlist/ActionListPresenter.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/actionlist/ActionListPresenter.kt @@ -21,6 +21,7 @@ import dagger.assisted.AssistedInject import io.element.android.features.messages.api.pinned.IsPinnedMessagesFeatureEnabled import io.element.android.features.messages.impl.UserEventPermissions import io.element.android.features.messages.impl.actionlist.model.TimelineItemAction +import io.element.android.features.messages.impl.actionlist.model.TimelineItemActionComparator import io.element.android.features.messages.impl.actionlist.model.TimelineItemActionPostProcessor import io.element.android.features.messages.impl.crypto.sendfailure.VerifiedUserSendFailure import io.element.android.features.messages.impl.crypto.sendfailure.VerifiedUserSendFailureFactory @@ -70,6 +71,8 @@ class DefaultActionListPresenter @AssistedInject constructor( override fun create(postProcessor: TimelineItemActionPostProcessor): DefaultActionListPresenter } + private val comparator = TimelineItemActionComparator() + @Composable override fun present(): ActionListState { val localCoroutineScope = rememberCoroutineScope() @@ -137,7 +140,6 @@ class DefaultActionListPresenter @AssistedInject constructor( } } - // See order in https://www.figma.com/design/ux3tYoZV9WghC7hHT9Fhk0/Compound-iOS-Components?node-id=2946-2392 private suspend fun buildActions( timelineItem: TimelineItem.Event, usersEventPermissions: UserEventPermissions, @@ -146,7 +148,7 @@ class DefaultActionListPresenter @AssistedInject constructor( isEventPinned: Boolean, ): List { val canRedact = timelineItem.isMine && usersEventPermissions.canRedactOwn || !timelineItem.isMine && usersEventPermissions.canRedactOther - return buildList { + return buildSet { if (timelineItem.canBeRepliedTo && usersEventPermissions.canSendMessage) { if (timelineItem.isThreaded) { add(TimelineItemAction.ReplyInThread) @@ -202,6 +204,7 @@ class DefaultActionListPresenter @AssistedInject constructor( } } .postFilter(timelineItem.content) + .sortedWith(comparator) .let(postProcessor::process) } } @@ -209,7 +212,7 @@ class DefaultActionListPresenter @AssistedInject constructor( /** * Post filter the actions based on the content of the event. */ -private fun List.postFilter(content: TimelineItemEventContent): List { +private fun Iterable.postFilter(content: TimelineItemEventContent): Iterable { return filter { action -> when (content) { is TimelineItemCallNotifyContent, diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/actionlist/ActionListStateProvider.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/actionlist/ActionListStateProvider.kt index 0323a2e6c69..a5f027a5355 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/actionlist/ActionListStateProvider.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/actionlist/ActionListStateProvider.kt @@ -9,6 +9,7 @@ package io.element.android.features.messages.impl.actionlist import androidx.compose.ui.tooling.preview.PreviewParameterProvider import io.element.android.features.messages.impl.actionlist.model.TimelineItemAction +import io.element.android.features.messages.impl.actionlist.model.TimelineItemActionComparator import io.element.android.features.messages.impl.crypto.sendfailure.VerifiedUserSendFailure import io.element.android.features.messages.impl.crypto.sendfailure.resolve.anUnsignedDeviceSendFailure import io.element.android.features.messages.impl.timeline.aTimelineItemEvent @@ -22,7 +23,6 @@ import io.element.android.features.messages.impl.timeline.model.event.aTimelineI import io.element.android.features.messages.impl.timeline.model.event.aTimelineItemVoiceContent import io.element.android.libraries.matrix.api.timeline.item.event.MessageShield import kotlinx.collections.immutable.ImmutableList -import kotlinx.collections.immutable.persistentListOf import kotlinx.collections.immutable.toPersistentList open class ActionListStateProvider : PreviewParameterProvider { @@ -175,7 +175,7 @@ fun anActionListState( fun aTimelineItemActionList( copyAction: TimelineItemAction? = TimelineItemAction.CopyText ): ImmutableList { - return listOfNotNull( + return setOfNotNull( TimelineItemAction.Reply, TimelineItemAction.Forward, copyAction, @@ -184,17 +184,19 @@ fun aTimelineItemActionList( TimelineItemAction.Redact, TimelineItemAction.ReportContent, TimelineItemAction.ViewSource, - ).toPersistentList() + ) + .sortedWith(TimelineItemActionComparator()) + .toPersistentList() } fun aTimelineItemPollActionList(): ImmutableList { - return persistentListOf( + return setOf( TimelineItemAction.EndPoll, TimelineItemAction.Reply, - TimelineItemAction.CopyText, + TimelineItemAction.Pin, TimelineItemAction.CopyLink, - TimelineItemAction.ViewSource, - TimelineItemAction.ReportContent, TimelineItemAction.Redact, ) + .sortedWith(TimelineItemActionComparator()) + .toPersistentList() } diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/actionlist/model/TimelineItemActionComparator.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/actionlist/model/TimelineItemActionComparator.kt new file mode 100644 index 00000000000..8eef2d76199 --- /dev/null +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/actionlist/model/TimelineItemActionComparator.kt @@ -0,0 +1,37 @@ +/* + * Copyright 2024 New Vector Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only + * Please see LICENSE in the repository root for full details. + */ + +package io.element.android.features.messages.impl.actionlist.model + +class TimelineItemActionComparator : Comparator { + // See order in https://www.figma.com/design/ux3tYoZV9WghC7hHT9Fhk0/Compound-iOS-Components?node-id=2946-2392 + private val orderedList = listOf( + TimelineItemAction.EndPoll, + TimelineItemAction.ViewInTimeline, + TimelineItemAction.Reply, + TimelineItemAction.ReplyInThread, + TimelineItemAction.Forward, + TimelineItemAction.Pin, + TimelineItemAction.Unpin, + TimelineItemAction.CopyLink, + TimelineItemAction.Edit, + TimelineItemAction.CopyText, + TimelineItemAction.AddCaption, + TimelineItemAction.EditCaption, + TimelineItemAction.CopyCaption, + TimelineItemAction.RemoveCaption, + TimelineItemAction.ViewSource, + TimelineItemAction.ReportContent, + TimelineItemAction.Redact, + ) + + override fun compare(o1: TimelineItemAction, o2: TimelineItemAction): Int { + val index1 = orderedList.indexOf(o1) + val index2 = orderedList.indexOf(o2) + return index1.compareTo(index2) + } +} diff --git a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/actionlist/ActionListPresenterTest.kt b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/actionlist/ActionListPresenterTest.kt index 1e4b92d91d0..49db6f6c955 100644 --- a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/actionlist/ActionListPresenterTest.kt +++ b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/actionlist/ActionListPresenterTest.kt @@ -176,8 +176,8 @@ class ActionListPresenterTest { TimelineItemAction.Reply, TimelineItemAction.Forward, TimelineItemAction.Pin, - TimelineItemAction.CopyText, TimelineItemAction.CopyLink, + TimelineItemAction.CopyText, TimelineItemAction.ViewSource, TimelineItemAction.ReportContent, ) @@ -221,8 +221,8 @@ class ActionListPresenterTest { TimelineItemAction.ReplyInThread, TimelineItemAction.Forward, TimelineItemAction.Pin, - TimelineItemAction.CopyText, TimelineItemAction.CopyLink, + TimelineItemAction.CopyText, TimelineItemAction.ViewSource, TimelineItemAction.ReportContent, ) @@ -268,8 +268,8 @@ class ActionListPresenterTest { actions = persistentListOf( TimelineItemAction.Forward, TimelineItemAction.Pin, - TimelineItemAction.CopyText, TimelineItemAction.CopyLink, + TimelineItemAction.CopyText, TimelineItemAction.ViewSource, TimelineItemAction.ReportContent, ) @@ -314,8 +314,8 @@ class ActionListPresenterTest { TimelineItemAction.Reply, TimelineItemAction.Forward, TimelineItemAction.Pin, - TimelineItemAction.CopyText, TimelineItemAction.CopyLink, + TimelineItemAction.CopyText, TimelineItemAction.ViewSource, TimelineItemAction.ReportContent, TimelineItemAction.Redact, @@ -361,8 +361,8 @@ class ActionListPresenterTest { TimelineItemAction.Reply, TimelineItemAction.Forward, TimelineItemAction.Pin, - TimelineItemAction.CopyText, TimelineItemAction.CopyLink, + TimelineItemAction.CopyText, TimelineItemAction.ViewSource, TimelineItemAction.ReportContent, TimelineItemAction.Redact, @@ -408,10 +408,10 @@ class ActionListPresenterTest { actions = persistentListOf( TimelineItemAction.Reply, TimelineItemAction.Forward, - TimelineItemAction.Edit, TimelineItemAction.Pin, - TimelineItemAction.CopyText, TimelineItemAction.CopyLink, + TimelineItemAction.Edit, + TimelineItemAction.CopyText, TimelineItemAction.ViewSource, TimelineItemAction.Redact, ) @@ -453,10 +453,10 @@ class ActionListPresenterTest { actions = persistentListOf( TimelineItemAction.ReplyInThread, TimelineItemAction.Forward, - TimelineItemAction.Edit, TimelineItemAction.Pin, - TimelineItemAction.CopyText, TimelineItemAction.CopyLink, + TimelineItemAction.Edit, + TimelineItemAction.CopyText, TimelineItemAction.ViewSource, TimelineItemAction.Redact, ) @@ -501,10 +501,10 @@ class ActionListPresenterTest { actions = persistentListOf( TimelineItemAction.Reply, TimelineItemAction.Forward, - TimelineItemAction.Edit, TimelineItemAction.Pin, - TimelineItemAction.CopyText, TimelineItemAction.CopyLink, + TimelineItemAction.Edit, + TimelineItemAction.CopyText, TimelineItemAction.ViewSource, ) ) @@ -547,9 +547,9 @@ class ActionListPresenterTest { actions = persistentListOf( TimelineItemAction.Reply, TimelineItemAction.Forward, - TimelineItemAction.AddCaption, TimelineItemAction.Pin, TimelineItemAction.CopyLink, + TimelineItemAction.AddCaption, TimelineItemAction.ViewSource, TimelineItemAction.Redact, ) @@ -646,11 +646,11 @@ class ActionListPresenterTest { actions = persistentListOf( TimelineItemAction.Reply, TimelineItemAction.Forward, + TimelineItemAction.Pin, + TimelineItemAction.CopyLink, TimelineItemAction.EditCaption, TimelineItemAction.CopyCaption, TimelineItemAction.RemoveCaption, - TimelineItemAction.Pin, - TimelineItemAction.CopyLink, TimelineItemAction.ViewSource, TimelineItemAction.Redact, ) @@ -696,11 +696,11 @@ class ActionListPresenterTest { actions = persistentListOf( TimelineItemAction.Reply, TimelineItemAction.Forward, - TimelineItemAction.CopyCaption, TimelineItemAction.Pin, TimelineItemAction.CopyLink, + TimelineItemAction.CopyCaption, TimelineItemAction.ViewSource, - TimelineItemAction.Redact, + TimelineItemAction.ReportContent, ) ) ) @@ -813,10 +813,10 @@ class ActionListPresenterTest { actions = persistentListOf( TimelineItemAction.Reply, TimelineItemAction.Forward, - TimelineItemAction.Edit, TimelineItemAction.Pin, - TimelineItemAction.CopyText, TimelineItemAction.CopyLink, + TimelineItemAction.Edit, + TimelineItemAction.CopyText, TimelineItemAction.Redact, ) ) @@ -860,9 +860,9 @@ class ActionListPresenterTest { actions = persistentListOf( TimelineItemAction.Reply, TimelineItemAction.Forward, + TimelineItemAction.CopyLink, TimelineItemAction.Edit, TimelineItemAction.CopyText, - TimelineItemAction.CopyLink, TimelineItemAction.ViewSource, TimelineItemAction.Redact, ) @@ -914,10 +914,10 @@ class ActionListPresenterTest { actions = persistentListOf( TimelineItemAction.Reply, TimelineItemAction.Forward, - TimelineItemAction.Edit, TimelineItemAction.Unpin, - TimelineItemAction.CopyText, TimelineItemAction.CopyLink, + TimelineItemAction.Edit, + TimelineItemAction.CopyText, TimelineItemAction.ViewSource, TimelineItemAction.Redact, ) @@ -1049,11 +1049,11 @@ class ActionListPresenterTest { displayEmojiReactions = true, verifiedUserSendFailure = VerifiedUserSendFailure.None, actions = persistentListOf( - TimelineItemAction.Reply, - TimelineItemAction.Edit, TimelineItemAction.EndPoll, + TimelineItemAction.Reply, TimelineItemAction.Pin, TimelineItemAction.CopyLink, + TimelineItemAction.Edit, TimelineItemAction.Redact, ) ) @@ -1092,8 +1092,8 @@ class ActionListPresenterTest { displayEmojiReactions = true, verifiedUserSendFailure = VerifiedUserSendFailure.None, actions = persistentListOf( - TimelineItemAction.Reply, TimelineItemAction.EndPoll, + TimelineItemAction.Reply, TimelineItemAction.Pin, TimelineItemAction.CopyLink, TimelineItemAction.Redact, From c47f1b62b831da6d269bce8d1f42f014839994a1 Mon Sep 17 00:00:00 2001 From: ElementBot Date: Thu, 28 Nov 2024 09:22:40 +0000 Subject: [PATCH 42/96] Update screenshots --- ...ssages.impl.actionlist_ActionListViewContent_Day_10_en.png | 4 ++-- ...ssages.impl.actionlist_ActionListViewContent_Day_11_en.png | 4 ++-- ...ssages.impl.actionlist_ActionListViewContent_Day_12_en.png | 4 ++-- ...essages.impl.actionlist_ActionListViewContent_Day_2_en.png | 4 ++-- ...essages.impl.actionlist_ActionListViewContent_Day_3_en.png | 4 ++-- ...essages.impl.actionlist_ActionListViewContent_Day_4_en.png | 4 ++-- ...essages.impl.actionlist_ActionListViewContent_Day_5_en.png | 4 ++-- ...essages.impl.actionlist_ActionListViewContent_Day_6_en.png | 4 ++-- ...essages.impl.actionlist_ActionListViewContent_Day_7_en.png | 4 ++-- ...essages.impl.actionlist_ActionListViewContent_Day_8_en.png | 4 ++-- ...essages.impl.actionlist_ActionListViewContent_Day_9_en.png | 4 ++-- ...ages.impl.actionlist_ActionListViewContent_Night_10_en.png | 4 ++-- ...ages.impl.actionlist_ActionListViewContent_Night_11_en.png | 4 ++-- ...ages.impl.actionlist_ActionListViewContent_Night_12_en.png | 4 ++-- ...sages.impl.actionlist_ActionListViewContent_Night_2_en.png | 4 ++-- ...sages.impl.actionlist_ActionListViewContent_Night_3_en.png | 4 ++-- ...sages.impl.actionlist_ActionListViewContent_Night_4_en.png | 4 ++-- ...sages.impl.actionlist_ActionListViewContent_Night_5_en.png | 4 ++-- ...sages.impl.actionlist_ActionListViewContent_Night_6_en.png | 4 ++-- ...sages.impl.actionlist_ActionListViewContent_Night_7_en.png | 4 ++-- ...sages.impl.actionlist_ActionListViewContent_Night_8_en.png | 4 ++-- ...sages.impl.actionlist_ActionListViewContent_Night_9_en.png | 4 ++-- 22 files changed, 44 insertions(+), 44 deletions(-) diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.actionlist_ActionListViewContent_Day_10_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.actionlist_ActionListViewContent_Day_10_en.png index 102de3524f8..0e0342e192a 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.actionlist_ActionListViewContent_Day_10_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.actionlist_ActionListViewContent_Day_10_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ab41e6b8fe6c235a4915d88a3d42e29cc84678a2b41bafbe38f55111632d1eec -size 31740 +oid sha256:e67a540966100272311381e87011149cdb15c8191a6f2bbc40d1febff999c431 +size 24067 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.actionlist_ActionListViewContent_Day_11_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.actionlist_ActionListViewContent_Day_11_en.png index 51af3e4480c..f500ff60dd2 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.actionlist_ActionListViewContent_Day_11_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.actionlist_ActionListViewContent_Day_11_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:2fb57605dad290919daa4c331442d69651e26db88235f77e4912ffb9631a36c0 -size 45151 +oid sha256:65023f7233f112547ccd0850c321b2d6610cfb6a1371c494f68722e75874f871 +size 45915 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.actionlist_ActionListViewContent_Day_12_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.actionlist_ActionListViewContent_Day_12_en.png index 87c7906ea29..c80b8639e0b 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.actionlist_ActionListViewContent_Day_12_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.actionlist_ActionListViewContent_Day_12_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:baadc64d3b4f9464bc6063cc9cc10adfa256d25308c83f647e508f42fd45ef1c -size 46852 +oid sha256:e2c2e01bd133c7b84e381141b6baf22783cb585cb3af9f790785dbf8aeaeeed6 +size 47644 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.actionlist_ActionListViewContent_Day_2_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.actionlist_ActionListViewContent_Day_2_en.png index 0d058f06397..4088be4e1e2 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.actionlist_ActionListViewContent_Day_2_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.actionlist_ActionListViewContent_Day_2_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:1009af703a11348dac63dc071333e077f4bba76c73bd64bf9e532381c7607c1d -size 39624 +oid sha256:9bd6fb63059cebc7dc7b850b5aa73549ab9846eda68b1b6d9a4f8e0716d42c3c +size 40419 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.actionlist_ActionListViewContent_Day_3_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.actionlist_ActionListViewContent_Day_3_en.png index 07d4116d650..b3dbf77d1d2 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.actionlist_ActionListViewContent_Day_3_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.actionlist_ActionListViewContent_Day_3_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:0f5adfb435286a84587a66d6970b1a7f03a8cb53eac86956f61092d97ea16951 -size 43121 +oid sha256:6b4e4a075bcb4b95455c27ce2e5f9f1bdac4a1aca22ad944dd53fdbaeb6ca970 +size 44550 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.actionlist_ActionListViewContent_Day_4_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.actionlist_ActionListViewContent_Day_4_en.png index 74dc1f4978d..87c07faab3c 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.actionlist_ActionListViewContent_Day_4_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.actionlist_ActionListViewContent_Day_4_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:d3843655f4b2f55b5eb2cdb014e1ca03f9570e312e725fe074a5191e0350c079 -size 40677 +oid sha256:1a2bc7e9098301d17e72a61a7baf01e52aa11566e1da4ffe3b43a66fa37652b2 +size 42103 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.actionlist_ActionListViewContent_Day_5_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.actionlist_ActionListViewContent_Day_5_en.png index 5a2491caa48..25da7b8bf1f 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.actionlist_ActionListViewContent_Day_5_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.actionlist_ActionListViewContent_Day_5_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ce1c3d6c04316fd9f43b86edb04ba209eb6df450f40438f98b8503fb116d4ea4 -size 40271 +oid sha256:f097af2773ff2ecf70a69e4292dc118b4c8616f1c8f979e7d121e86a16ef3072 +size 38506 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.actionlist_ActionListViewContent_Day_6_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.actionlist_ActionListViewContent_Day_6_en.png index eb710cb8efc..2bf210d5907 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.actionlist_ActionListViewContent_Day_6_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.actionlist_ActionListViewContent_Day_6_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:4839112543c6ab57848c1dd30440b12703da1a35a6457bf9fa5f5aabd1dd08b9 -size 40963 +oid sha256:8f49870a5333cbaf1c6c3ac5ddcb85290d04efc79ffec93d8dc39b59f9712820 +size 42391 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.actionlist_ActionListViewContent_Day_7_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.actionlist_ActionListViewContent_Day_7_en.png index a4293ee7441..6de43e00eed 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.actionlist_ActionListViewContent_Day_7_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.actionlist_ActionListViewContent_Day_7_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:41528c85820cbe666c719536022fb52ce510055c8c8ef3f1ce36da32731f0a0b -size 41615 +oid sha256:883f160afa3fc3d2c0be5098205ea616875084ee0f122ebf994d0fee53a8ecd1 +size 39847 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.actionlist_ActionListViewContent_Day_8_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.actionlist_ActionListViewContent_Day_8_en.png index 8a828912e45..cf03f3c12f4 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.actionlist_ActionListViewContent_Day_8_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.actionlist_ActionListViewContent_Day_8_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ac14f7921bedaf7135655775b524fde596120d6ea9b708ba5653b3805f567067 -size 41469 +oid sha256:7790c892daeee8910ce17caac2c957d09fffec0d41a51b3adc1d5bef8dcee1a1 +size 42261 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.actionlist_ActionListViewContent_Day_9_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.actionlist_ActionListViewContent_Day_9_en.png index 1adcf8bbaab..63da19cb016 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.actionlist_ActionListViewContent_Day_9_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.actionlist_ActionListViewContent_Day_9_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ce9244eb3b531a4c2816a32c8f806476cd0776f6394f32cebcb82f8a48cd64d7 -size 30837 +oid sha256:bc7b733680a0d86ee1231345e58641fb3a208da21de62a50f624d9ae04c6e140 +size 31661 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.actionlist_ActionListViewContent_Night_10_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.actionlist_ActionListViewContent_Night_10_en.png index 46e42eb3900..7e43e760b28 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.actionlist_ActionListViewContent_Night_10_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.actionlist_ActionListViewContent_Night_10_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:4aa886aa0f70c7c85fc25e9366792bd6e2c9e1a9b6c8864282834d9f72b3fcb2 -size 30809 +oid sha256:20504466241e36817557812f6b378aceab9c2e271a596bd3d037c6be41af7c54 +size 23624 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.actionlist_ActionListViewContent_Night_11_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.actionlist_ActionListViewContent_Night_11_en.png index 0c6ae9106a0..1667fe5ff02 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.actionlist_ActionListViewContent_Night_11_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.actionlist_ActionListViewContent_Night_11_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:756255463c3747888878fef57ec4c3204075993d3fb5bdaf3d1bbe436648862c -size 44345 +oid sha256:48028e4c3ca7e9b871683165f029430bcd4e0fc2411e4ffc83a93abb641d96a2 +size 45132 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.actionlist_ActionListViewContent_Night_12_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.actionlist_ActionListViewContent_Night_12_en.png index 30c644a80b8..e44f3240152 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.actionlist_ActionListViewContent_Night_12_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.actionlist_ActionListViewContent_Night_12_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:2bdc999259dabe20157611f27925d6f0c8f9f77eebc1914fa8f793b62aa8c299 -size 45864 +oid sha256:b040fe47521f5d9d76d7892412bb2b5cf7e2b93b951f5de5f772503797fb6b24 +size 46548 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.actionlist_ActionListViewContent_Night_2_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.actionlist_ActionListViewContent_Night_2_en.png index bbf069a81cc..5797dc53458 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.actionlist_ActionListViewContent_Night_2_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.actionlist_ActionListViewContent_Night_2_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ffb565c4d790e24a2f395b12d8dbbfa1ba4abadd7cf9951deae049696e04b206 -size 38843 +oid sha256:6db046a97f14f2df3db2415d71a02ffd6e706fe73def67c21f0d844be279da59 +size 39617 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.actionlist_ActionListViewContent_Night_3_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.actionlist_ActionListViewContent_Night_3_en.png index eed6d921be9..9b837817e6f 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.actionlist_ActionListViewContent_Night_3_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.actionlist_ActionListViewContent_Night_3_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:87d68af6f69c67de710145b3fabbff40bc6c9a767542e5a62be80d084972cb28 -size 42221 +oid sha256:7ee53243923d7b5adcc2094d3fe6bb87be00a179cae11966dcb230f2c3e8246e +size 43681 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.actionlist_ActionListViewContent_Night_4_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.actionlist_ActionListViewContent_Night_4_en.png index 201ce10bc69..6d0c2a905bf 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.actionlist_ActionListViewContent_Night_4_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.actionlist_ActionListViewContent_Night_4_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:08c6685bec4751c852ce2440c5b3dd006d46b80dfd0f5986a3392278f486e181 -size 39863 +oid sha256:b88e54ba4743e1e245b5a4c7d6b4045f816241f6cfc8716b8cede0b62666222b +size 41286 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.actionlist_ActionListViewContent_Night_5_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.actionlist_ActionListViewContent_Night_5_en.png index d20ad88b3ce..c479ebef749 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.actionlist_ActionListViewContent_Night_5_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.actionlist_ActionListViewContent_Night_5_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:04a1cbb1d1e98f87446ad911b61b002e34ceb2725ec24dfd884561d3585b9d83 -size 39518 +oid sha256:d88b4d82bb0d416aff7b32647479181ac9702c36c08370e7671d6e5ef80687c7 +size 37825 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.actionlist_ActionListViewContent_Night_6_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.actionlist_ActionListViewContent_Night_6_en.png index 4113521ddd1..885d6afaedd 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.actionlist_ActionListViewContent_Night_6_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.actionlist_ActionListViewContent_Night_6_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:d5ba01dbb6e8d1d238fcfdecbd67ee74bf833a3592087ec5ffc24b8ddeb85178 -size 40124 +oid sha256:b3d4dd1766a3f46acd86bdd5ec920c56a5e5f897c81c1477df10ba59dcd3d5b7 +size 41554 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.actionlist_ActionListViewContent_Night_7_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.actionlist_ActionListViewContent_Night_7_en.png index cfb777592f9..13b4a76016a 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.actionlist_ActionListViewContent_Night_7_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.actionlist_ActionListViewContent_Night_7_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:dd84e6907dc39e1ad7e6db95d8453aa51e18b14c881499c05a233678fa0e7094 -size 40762 +oid sha256:842fbea74e53c8804fd0a3e9fe96dcb21b5c91a099e1de33d8ec983fd9a8a80a +size 39112 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.actionlist_ActionListViewContent_Night_8_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.actionlist_ActionListViewContent_Night_8_en.png index ec719563228..18e022f292c 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.actionlist_ActionListViewContent_Night_8_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.actionlist_ActionListViewContent_Night_8_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:b5c35af3e85d906c6ed24fbb454cf32c7b25f87471e631af8b6ccc1d8465de00 -size 40631 +oid sha256:1311ec5e008b44d81e6556164f780c57dea3e4721cc47caccdbf337dd4027eb7 +size 41402 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.actionlist_ActionListViewContent_Night_9_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.actionlist_ActionListViewContent_Night_9_en.png index 6d28d9d7994..99c6f765a55 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.actionlist_ActionListViewContent_Night_9_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.actionlist_ActionListViewContent_Night_9_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:486f9e142212d3864dfb936905feb37421fd4e8c9b5734c5f9ee4f29ec1166f6 -size 29964 +oid sha256:d2cf27d2f053f33c67d944a8f45e0206165b2db2f3b959eb9e0bb943f84fe6a1 +size 30657 From 207e4f8b1eff78ab39db9e0b2df5705f256cd7d0 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 28 Nov 2024 10:57:10 +0100 Subject: [PATCH 43/96] Add unit test for PinnedMessagesListTimelineActionPostProcessor --- ...agesListTimelineActionPostProcessorTest.kt | 58 +++++++++++++++++++ 1 file changed, 58 insertions(+) create mode 100644 features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/pinned/list/PinnedMessagesListTimelineActionPostProcessorTest.kt diff --git a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/pinned/list/PinnedMessagesListTimelineActionPostProcessorTest.kt b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/pinned/list/PinnedMessagesListTimelineActionPostProcessorTest.kt new file mode 100644 index 00000000000..7043d3f8484 --- /dev/null +++ b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/pinned/list/PinnedMessagesListTimelineActionPostProcessorTest.kt @@ -0,0 +1,58 @@ +/* + * Copyright 2024 New Vector Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only + * Please see LICENSE in the repository root for full details. + */ + +package io.element.android.features.messages.impl.pinned.list + +import com.google.common.truth.Truth.assertThat +import io.element.android.features.messages.impl.actionlist.model.TimelineItemAction +import org.junit.Test + +class PinnedMessagesListTimelineActionPostProcessorTest { + @Test + fun `ensure that ViewInTimeline is added`() { + val sut = PinnedMessagesListTimelineActionPostProcessor() + val result = sut.process( + listOf() + ) + assertThat(result).isEqualTo( + listOf(TimelineItemAction.ViewInTimeline) + ) + } + + @Test + fun `ensure that some actions are kept and some other are filtered out`() { + val sut = PinnedMessagesListTimelineActionPostProcessor() + val result = sut.process( + listOf( + TimelineItemAction.Forward, + TimelineItemAction.CopyText, + TimelineItemAction.CopyCaption, + TimelineItemAction.CopyLink, + TimelineItemAction.Redact, + TimelineItemAction.Reply, + TimelineItemAction.ReplyInThread, + TimelineItemAction.Edit, + TimelineItemAction.EditCaption, + TimelineItemAction.AddCaption, + TimelineItemAction.RemoveCaption, + TimelineItemAction.ViewSource, + TimelineItemAction.ReportContent, + TimelineItemAction.EndPoll, + TimelineItemAction.Pin, + TimelineItemAction.Unpin, + ) + ) + assertThat(result).isEqualTo( + listOf( + TimelineItemAction.ViewInTimeline, + TimelineItemAction.Unpin, + TimelineItemAction.Forward, + TimelineItemAction.ViewSource, + ) + ) + } +} From 13ae18983cf99269439d92aa42df325cab885030 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 28 Nov 2024 11:08:06 +0100 Subject: [PATCH 44/96] Let the factory for ActionListPresenter be injected in Node. --- .../features/messages/impl/MessagesNode.kt | 4 ++++ .../messages/impl/MessagesPresenter.kt | 8 +++---- .../pinned/list/PinnedMessagesListNode.kt | 7 +++++- .../list/PinnedMessagesListPresenter.kt | 10 ++++---- .../messages/impl/MessagesPresenterTest.kt | 4 ++-- .../actionlist/FakeActionListPresenter.kt | 24 ------------------- .../list/PinnedMessagesListPresenterTest.kt | 4 ++-- 7 files changed, 23 insertions(+), 38 deletions(-) delete mode 100644 features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/actionlist/FakeActionListPresenter.kt diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesNode.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesNode.kt index 17985848537..7d5bad4d639 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesNode.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesNode.kt @@ -28,6 +28,8 @@ import dagger.assisted.Assisted import dagger.assisted.AssistedInject import io.element.android.anvilannotations.ContributesNode import io.element.android.compound.theme.ElementTheme +import io.element.android.features.messages.impl.actionlist.ActionListPresenter +import io.element.android.features.messages.impl.actionlist.model.TimelineItemActionPostProcessor import io.element.android.features.messages.impl.attachments.Attachment import io.element.android.features.messages.impl.messagecomposer.MessageComposerEvents import io.element.android.features.messages.impl.messagecomposer.MessageComposerPresenter @@ -65,6 +67,7 @@ class MessagesNode @AssistedInject constructor( messageComposerPresenterFactory: MessageComposerPresenter.Factory, timelinePresenterFactory: TimelinePresenter.Factory, presenterFactory: MessagesPresenter.Factory, + actionListPresenterFactory: ActionListPresenter.Factory, private val timelineItemPresenterFactories: TimelineItemPresenterFactories, private val mediaPlayer: MediaPlayer, private val permalinkParser: PermalinkParser, @@ -73,6 +76,7 @@ class MessagesNode @AssistedInject constructor( navigator = this, composerPresenter = messageComposerPresenterFactory.create(this), timelinePresenter = timelinePresenterFactory.create(this), + actionListPresenter = actionListPresenterFactory.create(TimelineItemActionPostProcessor.Default) ) private val callbacks = plugins() diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesPresenter.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesPresenter.kt index a32f33d6ce6..5a68b5cc9ee 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesPresenter.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesPresenter.kt @@ -28,9 +28,8 @@ import im.vector.app.features.analytics.plan.PinUnpinAction import io.element.android.appconfig.MessageComposerConfig import io.element.android.features.messages.api.timeline.HtmlConverterProvider import io.element.android.features.messages.impl.actionlist.ActionListEvents -import io.element.android.features.messages.impl.actionlist.ActionListPresenter +import io.element.android.features.messages.impl.actionlist.ActionListState import io.element.android.features.messages.impl.actionlist.model.TimelineItemAction -import io.element.android.features.messages.impl.actionlist.model.TimelineItemActionPostProcessor import io.element.android.features.messages.impl.crypto.identity.IdentityChangeState import io.element.android.features.messages.impl.messagecomposer.MessageComposerEvents import io.element.android.features.messages.impl.messagecomposer.MessageComposerState @@ -93,7 +92,7 @@ class MessagesPresenter @AssistedInject constructor( @Assisted private val timelinePresenter: Presenter, private val timelineProtectionPresenter: Presenter, private val identityChangeStatePresenter: Presenter, - actionListPresenterFactory: ActionListPresenter.Factory, + @Assisted private val actionListPresenter: Presenter, private val customReactionPresenter: Presenter, private val reactionSummaryPresenter: Presenter, private val readReceiptBottomSheetPresenter: Presenter, @@ -110,14 +109,13 @@ class MessagesPresenter @AssistedInject constructor( private val permalinkParser: PermalinkParser, private val analyticsService: AnalyticsService, ) : Presenter { - private val actionListPresenter = actionListPresenterFactory.create(TimelineItemActionPostProcessor.Default) - @AssistedFactory interface Factory { fun create( navigator: MessagesNavigator, composerPresenter: Presenter, timelinePresenter: Presenter, + actionListPresenter: Presenter, ): MessagesPresenter } diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/pinned/list/PinnedMessagesListNode.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/pinned/list/PinnedMessagesListNode.kt index 688b392fb6f..148aa3d2ad8 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/pinned/list/PinnedMessagesListNode.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/pinned/list/PinnedMessagesListNode.kt @@ -19,6 +19,7 @@ import com.bumble.appyx.core.plugin.plugins import dagger.assisted.Assisted import dagger.assisted.AssistedInject import io.element.android.anvilannotations.ContributesNode +import io.element.android.features.messages.impl.actionlist.ActionListPresenter import io.element.android.features.messages.impl.timeline.di.LocalTimelineItemPresenterFactories import io.element.android.features.messages.impl.timeline.di.TimelineItemPresenterFactories import io.element.android.features.messages.impl.timeline.model.TimelineItem @@ -35,6 +36,7 @@ class PinnedMessagesListNode @AssistedInject constructor( @Assisted buildContext: BuildContext, @Assisted plugins: List, presenterFactory: PinnedMessagesListPresenter.Factory, + actionListPresenterFactory: ActionListPresenter.Factory, private val timelineItemPresenterFactories: TimelineItemPresenterFactories, private val permalinkParser: PermalinkParser, ) : Node(buildContext, plugins = plugins), PinnedMessagesListNavigator { @@ -47,7 +49,10 @@ class PinnedMessagesListNode @AssistedInject constructor( fun onForwardEventClick(eventId: EventId) } - private val presenter = presenterFactory.create(this) + private val presenter = presenterFactory.create( + navigator = this, + actionListPresenter = actionListPresenterFactory.create(PinnedMessagesListTimelineActionPostProcessor()) + ) private val callbacks = plugins() private fun onEventClick(event: TimelineItem.Event) { diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/pinned/list/PinnedMessagesListPresenter.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/pinned/list/PinnedMessagesListPresenter.kt index 4673ae57b21..eb3412b30c3 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/pinned/list/PinnedMessagesListPresenter.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/pinned/list/PinnedMessagesListPresenter.kt @@ -23,7 +23,7 @@ import dagger.assisted.AssistedInject import im.vector.app.features.analytics.plan.Interaction import im.vector.app.features.analytics.plan.PinUnpinAction import io.element.android.features.messages.impl.UserEventPermissions -import io.element.android.features.messages.impl.actionlist.ActionListPresenter +import io.element.android.features.messages.impl.actionlist.ActionListState import io.element.android.features.messages.impl.actionlist.model.TimelineItemAction import io.element.android.features.messages.impl.pinned.PinnedEventsTimelineProvider import io.element.android.features.messages.impl.timeline.TimelineRoomInfo @@ -64,13 +64,16 @@ class PinnedMessagesListPresenter @AssistedInject constructor( private val timelineProvider: PinnedEventsTimelineProvider, private val timelineProtectionPresenter: Presenter, private val snackbarDispatcher: SnackbarDispatcher, - actionListPresenterFactory: ActionListPresenter.Factory, + @Assisted private val actionListPresenter: Presenter, private val appCoroutineScope: CoroutineScope, private val analyticsService: AnalyticsService, ) : Presenter { @AssistedFactory interface Factory { - fun create(navigator: PinnedMessagesListNavigator): PinnedMessagesListPresenter + fun create( + navigator: PinnedMessagesListNavigator, + actionListPresenter: Presenter, + ): PinnedMessagesListPresenter } private val timelineItemsFactory: TimelineItemsFactory = timelineItemsFactoryCreator.create( @@ -79,7 +82,6 @@ class PinnedMessagesListPresenter @AssistedInject constructor( computeReactions = false, ) ) - private val actionListPresenter = actionListPresenterFactory.create(PinnedMessagesListTimelineActionPostProcessor()) @Composable override fun present(): PinnedMessagesListState { diff --git a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/MessagesPresenterTest.kt b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/MessagesPresenterTest.kt index 057694590cf..77f12f2ffd6 100644 --- a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/MessagesPresenterTest.kt +++ b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/MessagesPresenterTest.kt @@ -14,7 +14,7 @@ import com.google.common.truth.Truth.assertThat import im.vector.app.features.analytics.plan.PinUnpinAction import io.element.android.features.messages.impl.actionlist.ActionListEvents import io.element.android.features.messages.impl.actionlist.ActionListState -import io.element.android.features.messages.impl.actionlist.FakeActionListPresenter +import io.element.android.features.messages.impl.actionlist.anActionListState import io.element.android.features.messages.impl.actionlist.model.TimelineItemAction import io.element.android.features.messages.impl.crypto.identity.anIdentityChangeState import io.element.android.features.messages.impl.fixtures.aMessageEvent @@ -1116,7 +1116,7 @@ class MessagesPresenterTest { voiceMessageComposerPresenter = { aVoiceMessageComposerState() }, timelinePresenter = { aTimelineState(eventSink = timelineEventSink) }, timelineProtectionPresenter = { aTimelineProtectionState() }, - actionListPresenterFactory = FakeActionListPresenter.Factory(actionListEventSink), + actionListPresenter = { anActionListState(eventSink = actionListEventSink) }, customReactionPresenter = { aCustomReactionState() }, reactionSummaryPresenter = { aReactionSummaryState() }, readReceiptBottomSheetPresenter = { aReadReceiptBottomSheetState() }, diff --git a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/actionlist/FakeActionListPresenter.kt b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/actionlist/FakeActionListPresenter.kt deleted file mode 100644 index 14f62a1daf6..00000000000 --- a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/actionlist/FakeActionListPresenter.kt +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright 2024 New Vector Ltd. - * - * SPDX-License-Identifier: AGPL-3.0-only - * Please see LICENSE in the repository root for full details. - */ - -package io.element.android.features.messages.impl.actionlist - -import androidx.compose.runtime.Composable -import io.element.android.features.messages.impl.actionlist.model.TimelineItemActionPostProcessor - -class FakeActionListPresenter(private val eventSink: (ActionListEvents) -> Unit = {}) : ActionListPresenter { - class Factory(private val eventSink: (ActionListEvents) -> Unit = {}) : ActionListPresenter.Factory { - override fun create(postProcessor: TimelineItemActionPostProcessor): ActionListPresenter { - return FakeActionListPresenter(eventSink) - } - } - - @Composable - override fun present(): ActionListState { - return anActionListState(eventSink = eventSink) - } -} diff --git a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/pinned/list/PinnedMessagesListPresenterTest.kt b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/pinned/list/PinnedMessagesListPresenterTest.kt index 1036788cbb3..ed92a34df3b 100644 --- a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/pinned/list/PinnedMessagesListPresenterTest.kt +++ b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/pinned/list/PinnedMessagesListPresenterTest.kt @@ -9,7 +9,7 @@ package io.element.android.features.messages.impl.pinned.list import com.google.common.truth.Truth.assertThat import im.vector.app.features.analytics.plan.PinUnpinAction -import io.element.android.features.messages.impl.actionlist.FakeActionListPresenter +import io.element.android.features.messages.impl.actionlist.anActionListState import io.element.android.features.messages.impl.actionlist.model.TimelineItemAction import io.element.android.features.messages.impl.fixtures.aTimelineItemsFactoryCreator import io.element.android.features.messages.impl.pinned.PinnedEventsTimelineProvider @@ -312,7 +312,7 @@ class PinnedMessagesListPresenterTest { timelineProvider = timelineProvider, timelineProtectionPresenter = { aTimelineProtectionState() }, snackbarDispatcher = SnackbarDispatcher(), - actionListPresenterFactory = FakeActionListPresenter.Factory(), + actionListPresenter = { anActionListState() }, analyticsService = analyticsService, appCoroutineScope = this, ) From 62134022bbfa3939d3dd28a2aab77b57561f98d7 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 28 Nov 2024 14:38:58 +0100 Subject: [PATCH 45/96] PlayableState.Playable should only contain data useful for other components. --- .../mediaviewer/api/local/LocalMediaView.kt | 45 ++++++++++++------- .../api/local/LocalMediaViewState.kt | 4 -- .../api/player/MediaPlayerControllerState.kt | 7 +-- .../MediaPlayerControllerStateProvider.kt | 20 +-------- .../api/player/MediaPlayerControllerView.kt | 14 +++--- 5 files changed, 42 insertions(+), 48 deletions(-) diff --git a/libraries/mediaviewer/api/src/main/kotlin/io/element/android/libraries/mediaviewer/api/local/LocalMediaView.kt b/libraries/mediaviewer/api/src/main/kotlin/io/element/android/libraries/mediaviewer/api/local/LocalMediaView.kt index b644ebc6857..b7102b0f845 100644 --- a/libraries/mediaviewer/api/src/main/kotlin/io/element/android/libraries/mediaviewer/api/local/LocalMediaView.kt +++ b/libraries/mediaviewer/api/src/main/kotlin/io/element/android/libraries/mediaviewer/api/local/LocalMediaView.kt @@ -30,6 +30,7 @@ import androidx.compose.material.icons.outlined.GraphicEq import androidx.compose.material3.MaterialTheme import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.derivedStateOf import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableIntStateOf import androidx.compose.runtime.mutableStateOf @@ -172,17 +173,26 @@ private fun ExoPlayerMediaVideoView( localMedia: LocalMedia?, modifier: Modifier = Modifier, ) { - var playableState: PlayableState.Playable by remember { + var mediaPlayerControllerState: MediaPlayerControllerState by remember { mutableStateOf( - PlayableState.Playable( + MediaPlayerControllerState( + isVisible = false, isPlaying = false, progressInMillis = 0, durationInMillis = 0, - isShowingControls = false, isMuted = false, ) ) } + + val playableState: PlayableState.Playable by remember { + derivedStateOf { + PlayableState.Playable( + isShowingControls = mediaPlayerControllerState.isVisible, + ) + } + } + localMediaViewState.playableState = playableState val context = LocalContext.current @@ -195,16 +205,20 @@ private fun ExoPlayerMediaVideoView( } override fun onIsPlayingChanged(isPlaying: Boolean) { - playableState = playableState.copy(isPlaying = isPlaying) + mediaPlayerControllerState = mediaPlayerControllerState.copy( + isPlaying = isPlaying, + ) } override fun onVolumeChanged(volume: Float) { - playableState = playableState.copy(isMuted = volume == 0f) + mediaPlayerControllerState = mediaPlayerControllerState.copy( + isMuted = volume == 0f, + ) } override fun onTimelineChanged(timeline: Timeline, reason: Int) { if (reason == Player.TIMELINE_CHANGE_REASON_SOURCE_UPDATE) { - playableState = playableState.copy( + mediaPlayerControllerState = mediaPlayerControllerState.copy( durationInMillis = exoPlayer.duration, ) } @@ -221,21 +235,23 @@ private fun ExoPlayerMediaVideoView( LaunchedEffect(autoHideController) { delay(5.seconds) if (exoPlayer.isPlaying) { - playableState = playableState.copy(isShowingControls = false) + mediaPlayerControllerState = mediaPlayerControllerState.copy( + isVisible = false, + ) } } LaunchedEffect(exoPlayer.isPlaying) { if (exoPlayer.isPlaying) { while (true) { - playableState = playableState.copy( + mediaPlayerControllerState = mediaPlayerControllerState.copy( progressInMillis = exoPlayer.currentPosition, ) delay(200) } } else { // Ensure we render the final state - playableState = playableState.copy( + mediaPlayerControllerState = mediaPlayerControllerState.copy( progressInMillis = exoPlayer.currentPosition, ) } @@ -248,7 +264,7 @@ private fun ExoPlayerMediaVideoView( } else { exoPlayer.setMediaItems(emptyList()) } - KeepScreenOn(playableState.isPlaying) + KeepScreenOn(mediaPlayerControllerState.isPlaying) Box( modifier = modifier .background(ElementTheme.colors.bgSubtlePrimary) @@ -263,7 +279,9 @@ private fun ExoPlayerMediaVideoView( layoutParams = FrameLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT) setOnClickListener { autoHideController++ - playableState = playableState.copy(isShowingControls = !playableState.isShowingControls) + mediaPlayerControllerState = mediaPlayerControllerState.copy( + isVisible = !mediaPlayerControllerState.isVisible, + ) } useController = false } @@ -275,10 +293,7 @@ private fun ExoPlayerMediaVideoView( }, ) MediaPlayerControllerView( - state = MediaPlayerControllerState( - isVisible = playableState.isShowingControls, - playableState = playableState, - ), + state = mediaPlayerControllerState, onTogglePlay = { autoHideController++ if (exoPlayer.isPlaying) { diff --git a/libraries/mediaviewer/api/src/main/kotlin/io/element/android/libraries/mediaviewer/api/local/LocalMediaViewState.kt b/libraries/mediaviewer/api/src/main/kotlin/io/element/android/libraries/mediaviewer/api/local/LocalMediaViewState.kt index 54eb3f09707..b7237c26eb5 100644 --- a/libraries/mediaviewer/api/src/main/kotlin/io/element/android/libraries/mediaviewer/api/local/LocalMediaViewState.kt +++ b/libraries/mediaviewer/api/src/main/kotlin/io/element/android/libraries/mediaviewer/api/local/LocalMediaViewState.kt @@ -29,11 +29,7 @@ class LocalMediaViewState internal constructor( sealed interface PlayableState { data object NotPlayable : PlayableState data class Playable( - val isPlaying: Boolean, - val progressInMillis: Long, - val durationInMillis: Long, val isShowingControls: Boolean, - val isMuted: Boolean, ) : PlayableState } diff --git a/libraries/mediaviewer/api/src/main/kotlin/io/element/android/libraries/mediaviewer/api/player/MediaPlayerControllerState.kt b/libraries/mediaviewer/api/src/main/kotlin/io/element/android/libraries/mediaviewer/api/player/MediaPlayerControllerState.kt index b6963a16b13..f5197af99be 100644 --- a/libraries/mediaviewer/api/src/main/kotlin/io/element/android/libraries/mediaviewer/api/player/MediaPlayerControllerState.kt +++ b/libraries/mediaviewer/api/src/main/kotlin/io/element/android/libraries/mediaviewer/api/player/MediaPlayerControllerState.kt @@ -7,9 +7,10 @@ package io.element.android.libraries.mediaviewer.api.player -import io.element.android.libraries.mediaviewer.api.local.PlayableState - data class MediaPlayerControllerState( val isVisible: Boolean, - val playableState: PlayableState.Playable, + val isPlaying: Boolean, + val progressInMillis: Long, + val durationInMillis: Long, + val isMuted: Boolean, ) diff --git a/libraries/mediaviewer/api/src/main/kotlin/io/element/android/libraries/mediaviewer/api/player/MediaPlayerControllerStateProvider.kt b/libraries/mediaviewer/api/src/main/kotlin/io/element/android/libraries/mediaviewer/api/player/MediaPlayerControllerStateProvider.kt index 64b8ef241e4..a5f3664941f 100644 --- a/libraries/mediaviewer/api/src/main/kotlin/io/element/android/libraries/mediaviewer/api/player/MediaPlayerControllerStateProvider.kt +++ b/libraries/mediaviewer/api/src/main/kotlin/io/element/android/libraries/mediaviewer/api/player/MediaPlayerControllerStateProvider.kt @@ -8,7 +8,6 @@ package io.element.android.libraries.mediaviewer.api.player import androidx.compose.ui.tooling.preview.PreviewParameterProvider -import io.element.android.libraries.mediaviewer.api.local.PlayableState open class MediaPlayerControllerStateProvider : PreviewParameterProvider { override val values: Sequence = sequenceOf( @@ -24,32 +23,15 @@ open class MediaPlayerControllerStateProvider : PreviewParameterProvider= 0 } ?: state.playableState.progressInMillis.toFloat(), + valueRange = 0f..state.durationInMillis.toFloat(), + value = lastSelectedValue.takeIf { it >= 0 } ?: state.progressInMillis.toFloat(), onValueChange = { lastSelectedValue = it }, @@ -103,8 +103,8 @@ fun MediaPlayerControllerView( }, useCustomLayout = true, ) - val formattedDuration = remember(state.playableState.durationInMillis) { - state.playableState.durationInMillis.toHumanReadableDuration() + val formattedDuration = remember(state.durationInMillis) { + state.durationInMillis.toHumanReadableDuration() } Text( modifier = Modifier @@ -118,7 +118,7 @@ fun MediaPlayerControllerView( IconButton( onClick = onToggleMute, ) { - if (state.playableState.isMuted) { + if (state.isMuted) { Icon( imageVector = CompoundIcons.VolumeOffSolid(), tint = ElementTheme.colors.iconPrimary, From 9a6b39852b424ccbb591cb62dddc646646c1d4c1 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 28 Nov 2024 16:15:45 +0100 Subject: [PATCH 46/96] Improve preview --- .../api/player/MediaPlayerControllerStateProvider.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/mediaviewer/api/src/main/kotlin/io/element/android/libraries/mediaviewer/api/player/MediaPlayerControllerStateProvider.kt b/libraries/mediaviewer/api/src/main/kotlin/io/element/android/libraries/mediaviewer/api/player/MediaPlayerControllerStateProvider.kt index a5f3664941f..5cffb639904 100644 --- a/libraries/mediaviewer/api/src/main/kotlin/io/element/android/libraries/mediaviewer/api/player/MediaPlayerControllerStateProvider.kt +++ b/libraries/mediaviewer/api/src/main/kotlin/io/element/android/libraries/mediaviewer/api/player/MediaPlayerControllerStateProvider.kt @@ -13,7 +13,7 @@ open class MediaPlayerControllerStateProvider : PreviewParameterProvider = sequenceOf( aMediaPlayerControllerState(), aMediaPlayerControllerState( - isPlaying = false, + isPlaying = true, progressInMillis = 59_000, durationInMillis = 83_000, isMuted = true, @@ -23,7 +23,7 @@ open class MediaPlayerControllerStateProvider : PreviewParameterProvider Date: Thu, 28 Nov 2024 15:26:55 +0000 Subject: [PATCH 47/96] Update screenshots --- ...iaviewer.api.player_MediaPlayerControllerView_Day_1_en.png | 4 ++-- ...viewer.api.player_MediaPlayerControllerView_Night_1_en.png | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.api.player_MediaPlayerControllerView_Day_1_en.png b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.api.player_MediaPlayerControllerView_Day_1_en.png index 79c67135de1..3a2eb1a1032 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.api.player_MediaPlayerControllerView_Day_1_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.api.player_MediaPlayerControllerView_Day_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:1d3346676b7c7d227f9512749d3a9b89ca50b70e3133475321fe8f063f65654c -size 7312 +oid sha256:bc35254c6962b5b113a2c25c4c9dd0c94449521152ffd73f41a0c36429fabbb0 +size 7258 diff --git a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.api.player_MediaPlayerControllerView_Night_1_en.png b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.api.player_MediaPlayerControllerView_Night_1_en.png index 957aa8261f0..bc5633f7b6f 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.api.player_MediaPlayerControllerView_Night_1_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.api.player_MediaPlayerControllerView_Night_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:71415f1799612db09acf890773bbeed1f060ab986930f77276fff5ddd81ea018 -size 7518 +oid sha256:b096093e04eb187fce0a85496c8a5b251afe0d0bccd977abcfb4d1e3dbe32a20 +size 7436 From 3ae5d61cf07e2365dc773b83a785d2642b957dc6 Mon Sep 17 00:00:00 2001 From: ganfra Date: Thu, 28 Nov 2024 17:51:22 +0100 Subject: [PATCH 48/96] changes: iterate on room create screen #3965 --- .../android/features/createroom/impl/CreateRoomDataStore.kt | 5 ++++- .../createroom/impl/configureroom/ConfigureRoomView.kt | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/CreateRoomDataStore.kt b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/CreateRoomDataStore.kt index 67e697e8e45..164a82af62e 100644 --- a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/CreateRoomDataStore.kt +++ b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/CreateRoomDataStore.kt @@ -102,7 +102,10 @@ class CreateRoomDataStore @Inject constructor( createRoomConfigFlow.getAndUpdate { config -> config.copy( roomVisibility = when (config.roomVisibility) { - is RoomVisibilityState.Public -> config.roomVisibility.copy(roomAddress = RoomAddress.Edited(address)) + is RoomVisibilityState.Public -> { + val sanitizedAddress = address.lowercase() + config.roomVisibility.copy(roomAddress = RoomAddress.Edited(sanitizedAddress)) + } else -> config.roomVisibility } ) diff --git a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomView.kt b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomView.kt index e34bb27a8b4..fabbe2aecc6 100644 --- a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomView.kt +++ b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomView.kt @@ -240,9 +240,9 @@ private fun RoomTopic( modifier = modifier, label = stringResource(R.string.screen_create_room_topic_label), value = topic, - placeholder = stringResource(CommonStrings.common_topic_placeholder), onValueChange = onTopicChange, maxLines = 3, + supportingText = stringResource(CommonStrings.common_topic_placeholder), keyboardOptions = KeyboardOptions( capitalization = KeyboardCapitalization.Sentences, ), From 6c9e97405763ae6aaeba9cd982d7bab80a0ec8c1 Mon Sep 17 00:00:00 2001 From: ElementBot Date: Thu, 28 Nov 2024 17:08:08 +0000 Subject: [PATCH 49/96] Update screenshots --- ...eateroom.impl.configureroom_ConfigureRoomViewDark_0_en.png | 4 ++-- ...eateroom.impl.configureroom_ConfigureRoomViewDark_1_en.png | 4 ++-- ...eateroom.impl.configureroom_ConfigureRoomViewDark_2_en.png | 4 ++-- ...eateroom.impl.configureroom_ConfigureRoomViewDark_3_en.png | 4 ++-- ...eateroom.impl.configureroom_ConfigureRoomViewDark_4_en.png | 4 ++-- ...eateroom.impl.configureroom_ConfigureRoomViewDark_5_en.png | 4 ++-- ...ateroom.impl.configureroom_ConfigureRoomViewLight_0_en.png | 4 ++-- ...ateroom.impl.configureroom_ConfigureRoomViewLight_1_en.png | 4 ++-- ...ateroom.impl.configureroom_ConfigureRoomViewLight_2_en.png | 4 ++-- ...ateroom.impl.configureroom_ConfigureRoomViewLight_3_en.png | 4 ++-- ...ateroom.impl.configureroom_ConfigureRoomViewLight_4_en.png | 4 ++-- ...ateroom.impl.configureroom_ConfigureRoomViewLight_5_en.png | 4 ++-- 12 files changed, 24 insertions(+), 24 deletions(-) diff --git a/tests/uitests/src/test/snapshots/images/features.createroom.impl.configureroom_ConfigureRoomViewDark_0_en.png b/tests/uitests/src/test/snapshots/images/features.createroom.impl.configureroom_ConfigureRoomViewDark_0_en.png index 33a9d65ee42..249dd286497 100644 --- a/tests/uitests/src/test/snapshots/images/features.createroom.impl.configureroom_ConfigureRoomViewDark_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.createroom.impl.configureroom_ConfigureRoomViewDark_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:3b380df8a4e69e9e11337db374b682e01f96738948e69eb33886817894a049b0 -size 30716 +oid sha256:72855bb6717291b00777e21711c0a5c8a7049e7b09cac7684dee9ae28e5be9f8 +size 29925 diff --git a/tests/uitests/src/test/snapshots/images/features.createroom.impl.configureroom_ConfigureRoomViewDark_1_en.png b/tests/uitests/src/test/snapshots/images/features.createroom.impl.configureroom_ConfigureRoomViewDark_1_en.png index cba7000f487..1adbbfa52ae 100644 --- a/tests/uitests/src/test/snapshots/images/features.createroom.impl.configureroom_ConfigureRoomViewDark_1_en.png +++ b/tests/uitests/src/test/snapshots/images/features.createroom.impl.configureroom_ConfigureRoomViewDark_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:5053e8716e3bfe5703f6d00e304101bbbf6cdebaf5eb5088a6043171a1f34e47 -size 41328 +oid sha256:2fa0cc7a8cfa1e1726d0ec75186cfd99fd67e9d5b168b0c6be669e355af2a1d6 +size 43007 diff --git a/tests/uitests/src/test/snapshots/images/features.createroom.impl.configureroom_ConfigureRoomViewDark_2_en.png b/tests/uitests/src/test/snapshots/images/features.createroom.impl.configureroom_ConfigureRoomViewDark_2_en.png index 9bcb3813ac2..edb45bb3046 100644 --- a/tests/uitests/src/test/snapshots/images/features.createroom.impl.configureroom_ConfigureRoomViewDark_2_en.png +++ b/tests/uitests/src/test/snapshots/images/features.createroom.impl.configureroom_ConfigureRoomViewDark_2_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ffbdcd28c32808fba8ffb7071b6440578716d3ae89149eb319c22d3f3b78b1ff -size 59499 +oid sha256:79c69f5ca1c04d4e6544decea4150eb5f43bdde58070d1dfe57d0a4c94022dd5 +size 58850 diff --git a/tests/uitests/src/test/snapshots/images/features.createroom.impl.configureroom_ConfigureRoomViewDark_3_en.png b/tests/uitests/src/test/snapshots/images/features.createroom.impl.configureroom_ConfigureRoomViewDark_3_en.png index e9d68af4eeb..80352e80836 100644 --- a/tests/uitests/src/test/snapshots/images/features.createroom.impl.configureroom_ConfigureRoomViewDark_3_en.png +++ b/tests/uitests/src/test/snapshots/images/features.createroom.impl.configureroom_ConfigureRoomViewDark_3_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ccbb514ad9bd6a95ecff2e278574ac5bff9bd8a63a5fc91fa35302dbaa9e71f2 -size 55276 +oid sha256:564e7609bc44d06e095e01113333793a85b1ffa5f5ad2eb0523ad073661a941a +size 56894 diff --git a/tests/uitests/src/test/snapshots/images/features.createroom.impl.configureroom_ConfigureRoomViewDark_4_en.png b/tests/uitests/src/test/snapshots/images/features.createroom.impl.configureroom_ConfigureRoomViewDark_4_en.png index 43814bce075..3aa9167cfe4 100644 --- a/tests/uitests/src/test/snapshots/images/features.createroom.impl.configureroom_ConfigureRoomViewDark_4_en.png +++ b/tests/uitests/src/test/snapshots/images/features.createroom.impl.configureroom_ConfigureRoomViewDark_4_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a2ea9839e3dd1288d99c2115c37bc7fe72716af9785c4de3e328a77a57d12d70 -size 56633 +oid sha256:e6f28ae60d74769a903228a58ed97f5753ec6e9a054b8e94d39d6c83ecb363d5 +size 58260 diff --git a/tests/uitests/src/test/snapshots/images/features.createroom.impl.configureroom_ConfigureRoomViewDark_5_en.png b/tests/uitests/src/test/snapshots/images/features.createroom.impl.configureroom_ConfigureRoomViewDark_5_en.png index b254eeceb38..5382ae80f44 100644 --- a/tests/uitests/src/test/snapshots/images/features.createroom.impl.configureroom_ConfigureRoomViewDark_5_en.png +++ b/tests/uitests/src/test/snapshots/images/features.createroom.impl.configureroom_ConfigureRoomViewDark_5_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:5b28da0e8ff5cbedf8777b5af8ff6bab2bd5c476df80878b2c28dd96a354d978 -size 54383 +oid sha256:2e987390f164dcacfafd455a3ccd3f4ae9af7d8e057d91772670d28c6f6e6310 +size 56056 diff --git a/tests/uitests/src/test/snapshots/images/features.createroom.impl.configureroom_ConfigureRoomViewLight_0_en.png b/tests/uitests/src/test/snapshots/images/features.createroom.impl.configureroom_ConfigureRoomViewLight_0_en.png index 851051fa3d7..d3c00e7c2f9 100644 --- a/tests/uitests/src/test/snapshots/images/features.createroom.impl.configureroom_ConfigureRoomViewLight_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.createroom.impl.configureroom_ConfigureRoomViewLight_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:9dc23b7e9533aa94245efa2089956259b00882809157cf32decaaa22827aeb59 -size 31678 +oid sha256:5b420340d9471294fce2458149f14c55df979060b248dba7cdd8bacfe71a39da +size 30808 diff --git a/tests/uitests/src/test/snapshots/images/features.createroom.impl.configureroom_ConfigureRoomViewLight_1_en.png b/tests/uitests/src/test/snapshots/images/features.createroom.impl.configureroom_ConfigureRoomViewLight_1_en.png index 0371868836f..234cf0b7052 100644 --- a/tests/uitests/src/test/snapshots/images/features.createroom.impl.configureroom_ConfigureRoomViewLight_1_en.png +++ b/tests/uitests/src/test/snapshots/images/features.createroom.impl.configureroom_ConfigureRoomViewLight_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:150b375f3fa9c180ec221b3fcc3ed0397b75920cb760e25e327fd6be46370618 -size 41954 +oid sha256:05e71ef5a6fa821961c2a78885bab91eeeb783bac1fdaa495f32fd4173ecc615 +size 43621 diff --git a/tests/uitests/src/test/snapshots/images/features.createroom.impl.configureroom_ConfigureRoomViewLight_2_en.png b/tests/uitests/src/test/snapshots/images/features.createroom.impl.configureroom_ConfigureRoomViewLight_2_en.png index bd45e398b40..80d7d0808c4 100644 --- a/tests/uitests/src/test/snapshots/images/features.createroom.impl.configureroom_ConfigureRoomViewLight_2_en.png +++ b/tests/uitests/src/test/snapshots/images/features.createroom.impl.configureroom_ConfigureRoomViewLight_2_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:9dc54d0a6c3cb3069482b1c27ed6d80fd63b0bcad1a550bf5c4edb09f69db3a7 -size 60749 +oid sha256:cca307360497a2a298bb9968678c35afb44cdc68e2dd46a350868833bf770464 +size 59968 diff --git a/tests/uitests/src/test/snapshots/images/features.createroom.impl.configureroom_ConfigureRoomViewLight_3_en.png b/tests/uitests/src/test/snapshots/images/features.createroom.impl.configureroom_ConfigureRoomViewLight_3_en.png index ae54d119d73..800d6888075 100644 --- a/tests/uitests/src/test/snapshots/images/features.createroom.impl.configureroom_ConfigureRoomViewLight_3_en.png +++ b/tests/uitests/src/test/snapshots/images/features.createroom.impl.configureroom_ConfigureRoomViewLight_3_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:71c42c595070733ac8ac2c50da116e73ea6eea7dc120f6f0d28022b5a5f925bd -size 57099 +oid sha256:f3dfce838e3fb0ba5cc3063f5057926872b85a213ad8852f98ff609386ca18f5 +size 58705 diff --git a/tests/uitests/src/test/snapshots/images/features.createroom.impl.configureroom_ConfigureRoomViewLight_4_en.png b/tests/uitests/src/test/snapshots/images/features.createroom.impl.configureroom_ConfigureRoomViewLight_4_en.png index 9229891a5f0..a6393e62c04 100644 --- a/tests/uitests/src/test/snapshots/images/features.createroom.impl.configureroom_ConfigureRoomViewLight_4_en.png +++ b/tests/uitests/src/test/snapshots/images/features.createroom.impl.configureroom_ConfigureRoomViewLight_4_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:e10c1c3f2b4045d20c9513c70bc4ea041e091976df5385b93d45c2d03b8f6e5f -size 58513 +oid sha256:6527ca9d39895038bf0fec9cb9c1426f95db9f4b9460eff699c34bb59d11aaf8 +size 60122 diff --git a/tests/uitests/src/test/snapshots/images/features.createroom.impl.configureroom_ConfigureRoomViewLight_5_en.png b/tests/uitests/src/test/snapshots/images/features.createroom.impl.configureroom_ConfigureRoomViewLight_5_en.png index a9ab02f20e0..9215e348fd7 100644 --- a/tests/uitests/src/test/snapshots/images/features.createroom.impl.configureroom_ConfigureRoomViewLight_5_en.png +++ b/tests/uitests/src/test/snapshots/images/features.createroom.impl.configureroom_ConfigureRoomViewLight_5_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:cb54ae79de75af32e32642063d9dc9e0c24b0089f187a043f0fc330151c72c75 -size 56170 +oid sha256:c5d4014d2701847fadd4e163c26e7ba220577c4b1e10ebd35c95b1c6aa81507b +size 57814 From 646b92ac620dfefa36652e6bbfdd845a1f160068 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Fri, 29 Nov 2024 09:07:47 +0100 Subject: [PATCH 50/96] Change to better solution. --- .../securebackup/impl/SecureBackupFlowNode.kt | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/features/securebackup/impl/src/main/kotlin/io/element/android/features/securebackup/impl/SecureBackupFlowNode.kt b/features/securebackup/impl/src/main/kotlin/io/element/android/features/securebackup/impl/SecureBackupFlowNode.kt index 3fb2d0949a4..241f1322521 100644 --- a/features/securebackup/impl/src/main/kotlin/io/element/android/features/securebackup/impl/SecureBackupFlowNode.kt +++ b/features/securebackup/impl/src/main/kotlin/io/element/android/features/securebackup/impl/SecureBackupFlowNode.kt @@ -28,6 +28,7 @@ import io.element.android.features.securebackup.impl.root.SecureBackupRootNode import io.element.android.features.securebackup.impl.setup.SecureBackupSetupNode import io.element.android.libraries.architecture.BackstackView import io.element.android.libraries.architecture.BaseFlowNode +import io.element.android.libraries.architecture.appyx.canPop import io.element.android.libraries.architecture.createNode import io.element.android.libraries.di.SessionScope import kotlinx.parcelize.Parcelize @@ -111,15 +112,10 @@ class SecureBackupFlowNode @AssistedInject constructor( NavTarget.EnterRecoveryKey -> { val callback = object : SecureBackupEnterRecoveryKeyNode.Callback { override fun onEnterRecoveryKeySuccess() { - when (plugins.filterIsInstance().first().initialElement) { - SecureBackupEntryPoint.InitialTarget.EnterRecoveryKey -> { - callbacks.forEach { it.onDone() } - } - SecureBackupEntryPoint.InitialTarget.ResetIdentity, - SecureBackupEntryPoint.InitialTarget.Root, - SecureBackupEntryPoint.InitialTarget.SetUpRecovery -> { - backstack.pop() - } + if (backstack.canPop()) { + backstack.pop() + } else { + callbacks.forEach { it.onDone() } } } } From 96d7fbfadc3c923cd42bc3de12c0765585debc47 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 28 Nov 2024 16:07:37 +0100 Subject: [PATCH 51/96] Move code to the `impl` module --- .../messages/impl/MessagesFlowNode.kt | 18 ++++-- .../preview/AttachmentsPreviewNode.kt | 3 + .../AttachmentsPreviewStateProvider.kt | 10 +-- .../preview/AttachmentsPreviewView.kt | 34 +++++----- .../fixtures/TimelineItemsFactoryFixtures.kt | 2 +- .../TimelineItemContentMessageFactoryTest.kt | 2 +- .../roomdetails/impl/RoomDetailsFlowNode.kt | 36 +++++------ .../userprofile/impl/UserProfileFlowNode.kt | 34 ++++------ .../shared/avatar/AvatarPreviewNode.kt | 24 ------- libraries/mediaviewer/api/build.gradle.kts | 35 +--------- .../mediaviewer/api/{local => }/MediaInfo.kt | 4 +- .../mediaviewer/api/MediaViewerEntryPoint.kt | 38 +++++++++++ .../mediaviewer/api/local/LocalMedia.kt | 1 + .../api/local/LocalMediaFactory.kt | 1 + .../api/local/LocalMediaRenderer.kt | 15 +++++ .../api/util/FileExtensionExtractor.kt | 24 ------- libraries/mediaviewer/impl/build.gradle.kts | 24 +++++++ .../impl/DefaultMediaViewerEntryPoint.kt | 64 +++++++++++++++++++ .../impl/local/AndroidLocalMediaActions.kt | 1 - .../impl/local/AndroidLocalMediaFactory.kt | 2 +- .../impl/local/DefaultLocalMediaRenderer.kt | 37 +++++++++++ .../impl}/local/LocalMediaActions.kt | 3 +- .../mediaviewer/impl}/local/LocalMediaView.kt | 48 +++++++------- .../impl}/local/LocalMediaViewState.kt | 2 +- .../impl}/local/exoplayer/ExoPlayerWrapper.kt | 2 +- .../local/pdf/ParcelFileDescriptorFactory.kt | 2 +- .../mediaviewer/impl}/local/pdf/PdfPage.kt | 2 +- .../impl}/local/pdf/PdfRendererManager.kt | 2 +- .../mediaviewer/impl}/local/pdf/PdfViewer.kt | 2 +- .../impl}/local/pdf/PdfViewerState.kt | 2 +- .../player/MediaPlayerControllerState.kt | 2 +- .../MediaPlayerControllerStateProvider.kt | 2 +- .../impl}/player/MediaPlayerControllerView.kt | 2 +- .../impl/util/FileExtensionExtractor.kt | 27 ++++++++ .../impl}/viewer/MediaViewerEvents.kt | 2 +- .../impl}/viewer/MediaViewerNode.kt | 23 +++---- .../impl}/viewer/MediaViewerPresenter.kt | 9 +-- .../impl}/viewer/MediaViewerState.kt | 4 +- .../impl}/viewer/MediaViewerStateProvider.kt | 14 ++-- .../impl}/viewer/MediaViewerView.kt | 22 ++++--- .../src/main/res/drawable/ic_apk_install.xml | 0 .../local/AndroidLocalMediaFactoryTest.kt | 6 +- .../impl}/util/FileExtensionExtractorTest.kt | 3 +- .../impl/viewer}/MediaViewerPresenterTest.kt | 10 ++- .../impl}/viewer/MediaViewerViewTest.kt | 4 +- .../mediaviewer/test/FakeLocalMediaActions.kt | 2 +- .../mediaviewer/test/FakeLocalMediaFactory.kt | 4 +- ...FileExtensionExtractorWithoutValidation.kt | 16 +++++ .../mediaviewer/test/viewer/LocalMedia.kt | 4 +- 49 files changed, 386 insertions(+), 244 deletions(-) delete mode 100644 features/userprofile/shared/src/main/kotlin/io/element/android/features/userprofile/shared/avatar/AvatarPreviewNode.kt rename libraries/mediaviewer/api/src/main/kotlin/io/element/android/libraries/mediaviewer/api/{local => }/MediaInfo.kt (93%) create mode 100644 libraries/mediaviewer/api/src/main/kotlin/io/element/android/libraries/mediaviewer/api/MediaViewerEntryPoint.kt create mode 100644 libraries/mediaviewer/api/src/main/kotlin/io/element/android/libraries/mediaviewer/api/local/LocalMediaRenderer.kt create mode 100644 libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/DefaultMediaViewerEntryPoint.kt create mode 100644 libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/DefaultLocalMediaRenderer.kt rename libraries/mediaviewer/{api/src/main/kotlin/io/element/android/libraries/mediaviewer/api => impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl}/local/LocalMediaActions.kt (87%) rename libraries/mediaviewer/{api/src/main/kotlin/io/element/android/libraries/mediaviewer/api => impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl}/local/LocalMediaView.kt (91%) rename libraries/mediaviewer/{api/src/main/kotlin/io/element/android/libraries/mediaviewer/api => impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl}/local/LocalMediaViewState.kt (95%) rename libraries/mediaviewer/{api/src/main/kotlin/io/element/android/libraries/mediaviewer/api => impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl}/local/exoplayer/ExoPlayerWrapper.kt (93%) rename libraries/mediaviewer/{api/src/main/kotlin/io/element/android/libraries/mediaviewer/api => impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl}/local/pdf/ParcelFileDescriptorFactory.kt (91%) rename libraries/mediaviewer/{api/src/main/kotlin/io/element/android/libraries/mediaviewer/api => impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl}/local/pdf/PdfPage.kt (98%) rename libraries/mediaviewer/{api/src/main/kotlin/io/element/android/libraries/mediaviewer/api => impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl}/local/pdf/PdfRendererManager.kt (97%) rename libraries/mediaviewer/{api/src/main/kotlin/io/element/android/libraries/mediaviewer/api => impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl}/local/pdf/PdfViewer.kt (98%) rename libraries/mediaviewer/{api/src/main/kotlin/io/element/android/libraries/mediaviewer/api => impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl}/local/pdf/PdfViewerState.kt (97%) rename libraries/mediaviewer/{api/src/main/kotlin/io/element/android/libraries/mediaviewer/api => impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl}/player/MediaPlayerControllerState.kt (84%) rename libraries/mediaviewer/{api/src/main/kotlin/io/element/android/libraries/mediaviewer/api => impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl}/player/MediaPlayerControllerStateProvider.kt (94%) rename libraries/mediaviewer/{api/src/main/kotlin/io/element/android/libraries/mediaviewer/api => impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl}/player/MediaPlayerControllerView.kt (99%) create mode 100644 libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/util/FileExtensionExtractor.kt rename libraries/mediaviewer/{api/src/main/kotlin/io/element/android/libraries/mediaviewer/api => impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl}/viewer/MediaViewerEvents.kt (87%) rename libraries/mediaviewer/{api/src/main/kotlin/io/element/android/libraries/mediaviewer/api => impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl}/viewer/MediaViewerNode.kt (69%) rename libraries/mediaviewer/{api/src/main/kotlin/io/element/android/libraries/mediaviewer/api => impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl}/viewer/MediaViewerPresenter.kt (94%) rename libraries/mediaviewer/{api/src/main/kotlin/io/element/android/libraries/mediaviewer/api => impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl}/viewer/MediaViewerState.kt (85%) rename libraries/mediaviewer/{api/src/main/kotlin/io/element/android/libraries/mediaviewer/api => impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl}/viewer/MediaViewerStateProvider.kt (84%) rename libraries/mediaviewer/{api/src/main/kotlin/io/element/android/libraries/mediaviewer/api => impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl}/viewer/MediaViewerView.kt (95%) rename libraries/mediaviewer/{api => impl}/src/main/res/drawable/ic_apk_install.xml (100%) rename libraries/mediaviewer/{api/src/test/kotlin/io/element/android/libraries/mediaviewer/api => impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl}/util/FileExtensionExtractorTest.kt (88%) rename libraries/mediaviewer/{api/src/test/kotlin/io/element/android/libraries/mediaviewer => impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/viewer}/MediaViewerPresenterTest.kt (94%) rename libraries/mediaviewer/{api/src/test/kotlin/io/element/android/libraries/mediaviewer/api => impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl}/viewer/MediaViewerViewTest.kt (97%) create mode 100644 libraries/mediaviewer/test/src/main/kotlin/io/element/android/libraries/mediaviewer/test/util/FileExtensionExtractorWithoutValidation.kt diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesFlowNode.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesFlowNode.kt index fc3fba9c59a..d092dbbb130 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesFlowNode.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesFlowNode.kt @@ -19,6 +19,7 @@ import com.bumble.appyx.core.node.node import com.bumble.appyx.core.plugin.Plugin import com.bumble.appyx.core.plugin.plugins import com.bumble.appyx.navmodel.backstack.BackStack +import com.bumble.appyx.navmodel.backstack.operation.pop import com.bumble.appyx.navmodel.backstack.operation.push import dagger.assisted.Assisted import dagger.assisted.AssistedInject @@ -66,8 +67,8 @@ import io.element.android.libraries.matrix.api.room.joinedRoomMembers import io.element.android.libraries.matrix.api.timeline.item.TimelineItemDebugInfo import io.element.android.libraries.matrix.ui.messages.LocalRoomMemberProfilesCache import io.element.android.libraries.matrix.ui.messages.RoomMemberProfilesCache -import io.element.android.libraries.mediaviewer.api.local.MediaInfo -import io.element.android.libraries.mediaviewer.api.viewer.MediaViewerNode +import io.element.android.libraries.mediaviewer.api.MediaInfo +import io.element.android.libraries.mediaviewer.api.MediaViewerEntryPoint import io.element.android.libraries.textcomposer.mentions.LocalMentionSpanTheme import io.element.android.libraries.textcomposer.mentions.MentionSpanTheme import io.element.android.services.analytics.api.AnalyticsService @@ -86,6 +87,7 @@ class MessagesFlowNode @AssistedInject constructor( private val showLocationEntryPoint: ShowLocationEntryPoint, private val createPollEntryPoint: CreatePollEntryPoint, private val elementCallEntryPoint: ElementCallEntryPoint, + private val mediaViewerEntryPoint: MediaViewerEntryPoint, private val analyticsService: AnalyticsService, private val room: MatrixRoom, private val roomMemberProfilesCache: RoomMemberProfilesCache, @@ -228,14 +230,22 @@ class MessagesFlowNode @AssistedInject constructor( createNode(buildContext, listOf(callback, inputs)) } is NavTarget.MediaViewer -> { - val inputs = MediaViewerNode.Inputs( + val params = MediaViewerEntryPoint.Params( mediaInfo = navTarget.mediaInfo, mediaSource = navTarget.mediaSource, thumbnailSource = navTarget.thumbnailSource, canDownload = true, canShare = true, ) - createNode(buildContext, listOf(inputs)) + val callback = object : MediaViewerEntryPoint.Callback { + override fun onDone() { + backstack.pop() + } + } + mediaViewerEntryPoint.nodeBuilder(this, buildContext) + .params(params) + .callback(callback) + .build() } is NavTarget.AttachmentPreview -> { val inputs = AttachmentsPreviewNode.Inputs(navTarget.attachment) diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/attachments/preview/AttachmentsPreviewNode.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/attachments/preview/AttachmentsPreviewNode.kt index 2417d8346ea..e89d9a50524 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/attachments/preview/AttachmentsPreviewNode.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/attachments/preview/AttachmentsPreviewNode.kt @@ -20,12 +20,14 @@ import io.element.android.features.messages.impl.attachments.Attachment import io.element.android.libraries.architecture.NodeInputs import io.element.android.libraries.architecture.inputs import io.element.android.libraries.di.RoomScope +import io.element.android.libraries.mediaviewer.api.local.LocalMediaRenderer @ContributesNode(RoomScope::class) class AttachmentsPreviewNode @AssistedInject constructor( @Assisted buildContext: BuildContext, @Assisted plugins: List, presenterFactory: AttachmentsPreviewPresenter.Factory, + private val localMediaRenderer: LocalMediaRenderer, ) : Node(buildContext, plugins = plugins) { data class Inputs(val attachment: Attachment) : NodeInputs @@ -46,6 +48,7 @@ class AttachmentsPreviewNode @AssistedInject constructor( val state = presenter.present() AttachmentsPreviewView( state = state, + localMediaRenderer = localMediaRenderer, modifier = modifier ) } diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/attachments/preview/AttachmentsPreviewStateProvider.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/attachments/preview/AttachmentsPreviewStateProvider.kt index f7e215fa222..1a52316735c 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/attachments/preview/AttachmentsPreviewStateProvider.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/attachments/preview/AttachmentsPreviewStateProvider.kt @@ -10,12 +10,9 @@ package io.element.android.features.messages.impl.attachments.preview import androidx.compose.ui.tooling.preview.PreviewParameterProvider import androidx.core.net.toUri import io.element.android.features.messages.impl.attachments.Attachment +import io.element.android.libraries.mediaviewer.api.MediaInfo +import io.element.android.libraries.mediaviewer.api.anImageMediaInfo import io.element.android.libraries.mediaviewer.api.local.LocalMedia -import io.element.android.libraries.mediaviewer.api.local.MediaInfo -import io.element.android.libraries.mediaviewer.api.local.aVideoMediaInfo -import io.element.android.libraries.mediaviewer.api.local.anApkMediaInfo -import io.element.android.libraries.mediaviewer.api.local.anAudioMediaInfo -import io.element.android.libraries.mediaviewer.api.local.anImageMediaInfo import io.element.android.libraries.textcomposer.model.TextEditorState import io.element.android.libraries.textcomposer.model.aTextEditorStateMarkdown @@ -23,9 +20,6 @@ open class AttachmentsPreviewStateProvider : PreviewParameterProvider get() = sequenceOf( anAttachmentsPreviewState(), - anAttachmentsPreviewState(mediaInfo = aVideoMediaInfo()), - anAttachmentsPreviewState(mediaInfo = anAudioMediaInfo()), - anAttachmentsPreviewState(mediaInfo = anApkMediaInfo()), anAttachmentsPreviewState(sendActionState = SendActionState.Sending.Processing), anAttachmentsPreviewState(sendActionState = SendActionState.Sending.Uploading(0.5f)), anAttachmentsPreviewState(sendActionState = SendActionState.Failure(RuntimeException("error"))), diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/attachments/preview/AttachmentsPreviewView.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/attachments/preview/AttachmentsPreviewView.kt index 21450922820..876f6f9bdf2 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/attachments/preview/AttachmentsPreviewView.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/attachments/preview/AttachmentsPreviewView.kt @@ -8,6 +8,7 @@ package io.element.android.features.messages.impl.attachments.preview import androidx.activity.compose.BackHandler +import androidx.compose.foundation.Image import androidx.compose.foundation.background import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.IntrinsicSize @@ -20,6 +21,7 @@ import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.PreviewParameter @@ -34,20 +36,20 @@ import io.element.android.libraries.designsystem.components.dialogs.RetryDialog import io.element.android.libraries.designsystem.preview.ElementPreviewDark import io.element.android.libraries.designsystem.theme.components.Scaffold import io.element.android.libraries.designsystem.theme.components.TopAppBar -import io.element.android.libraries.mediaviewer.api.local.LocalMediaView -import io.element.android.libraries.mediaviewer.api.local.rememberLocalMediaViewState +import io.element.android.libraries.designsystem.utils.CommonDrawables +import io.element.android.libraries.mediaviewer.api.local.LocalMedia +import io.element.android.libraries.mediaviewer.api.local.LocalMediaRenderer import io.element.android.libraries.textcomposer.TextComposer import io.element.android.libraries.textcomposer.model.MessageComposerMode import io.element.android.libraries.textcomposer.model.VoiceMessageState import io.element.android.libraries.ui.strings.CommonStrings import io.element.android.wysiwyg.display.TextDisplay -import me.saket.telephoto.zoomable.ZoomSpec -import me.saket.telephoto.zoomable.rememberZoomableState @OptIn(ExperimentalMaterial3Api::class) @Composable fun AttachmentsPreviewView( state: AttachmentsPreviewState, + localMediaRenderer: LocalMediaRenderer, modifier: Modifier = Modifier, ) { fun postSendAttachment() { @@ -82,6 +84,7 @@ fun AttachmentsPreviewView( ) { AttachmentPreviewContent( state = state, + localMediaRenderer = localMediaRenderer, onSendClick = ::postSendAttachment, ) } @@ -129,6 +132,7 @@ private fun AttachmentSendStateView( @Composable private fun AttachmentPreviewContent( state: AttachmentsPreviewState, + localMediaRenderer: LocalMediaRenderer, onSendClick: () -> Unit, ) { Box( @@ -142,17 +146,7 @@ private fun AttachmentPreviewContent( ) { when (val attachment = state.attachment) { is Attachment.Media -> { - val localMediaViewState = rememberLocalMediaViewState( - zoomableState = rememberZoomableState( - zoomSpec = ZoomSpec(maxZoomFactor = 4f, preventOverOrUnderZoom = false) - ) - ) - LocalMediaView( - modifier = Modifier.fillMaxSize(), - localMedia = attachment.localMedia, - localMediaViewState = localMediaViewState, - onClick = {} - ) + localMediaRenderer.Render(attachment.localMedia) } } } @@ -205,5 +199,15 @@ private fun AttachmentsPreviewBottomActions( internal fun AttachmentsPreviewViewPreview(@PreviewParameter(AttachmentsPreviewStateProvider::class) state: AttachmentsPreviewState) = ElementPreviewDark { AttachmentsPreviewView( state = state, + localMediaRenderer = object : LocalMediaRenderer { + @Composable + override fun Render(localMedia: LocalMedia) { + Image( + painter = painterResource(id = CommonDrawables.sample_background), + modifier = Modifier.fillMaxSize(), + contentDescription = null, + ) + } + } ) } diff --git a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/fixtures/TimelineItemsFactoryFixtures.kt b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/fixtures/TimelineItemsFactoryFixtures.kt index 405d356edf0..51c4cb43ba0 100644 --- a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/fixtures/TimelineItemsFactoryFixtures.kt +++ b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/fixtures/TimelineItemsFactoryFixtures.kt @@ -35,7 +35,7 @@ import io.element.android.libraries.featureflag.test.FakeFeatureFlagService import io.element.android.libraries.matrix.api.timeline.item.event.EventTimelineItem import io.element.android.libraries.matrix.test.FakeMatrixClient import io.element.android.libraries.matrix.test.permalink.FakePermalinkParser -import io.element.android.libraries.mediaviewer.api.util.FileExtensionExtractorWithoutValidation +import io.element.android.libraries.mediaviewer.test.util.FileExtensionExtractorWithoutValidation import io.element.android.tests.testutils.testCoroutineDispatchers import kotlinx.coroutines.test.TestScope diff --git a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/timeline/factories/event/TimelineItemContentMessageFactoryTest.kt b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/timeline/factories/event/TimelineItemContentMessageFactoryTest.kt index 07ff31690e6..b771141ce33 100644 --- a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/timeline/factories/event/TimelineItemContentMessageFactoryTest.kt +++ b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/timeline/factories/event/TimelineItemContentMessageFactoryTest.kt @@ -64,7 +64,7 @@ import io.element.android.libraries.matrix.test.media.aMediaSource import io.element.android.libraries.matrix.test.permalink.FakePermalinkParser import io.element.android.libraries.matrix.test.timeline.aStickerContent import io.element.android.libraries.matrix.ui.components.A_BLUR_HASH -import io.element.android.libraries.mediaviewer.api.util.FileExtensionExtractorWithoutValidation +import io.element.android.libraries.mediaviewer.test.util.FileExtensionExtractorWithoutValidation import kotlinx.collections.immutable.persistentListOf import kotlinx.collections.immutable.toImmutableList import kotlinx.coroutines.test.runTest diff --git a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsFlowNode.kt b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsFlowNode.kt index 4030e302721..166a22d694e 100644 --- a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsFlowNode.kt +++ b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsFlowNode.kt @@ -15,6 +15,7 @@ import com.bumble.appyx.core.node.Node import com.bumble.appyx.core.plugin.Plugin import com.bumble.appyx.core.plugin.plugins import com.bumble.appyx.navmodel.backstack.BackStack +import com.bumble.appyx.navmodel.backstack.operation.pop import com.bumble.appyx.navmodel.backstack.operation.push import dagger.assisted.Assisted import dagger.assisted.AssistedInject @@ -32,20 +33,16 @@ import io.element.android.features.roomdetails.impl.members.details.RoomMemberDe import io.element.android.features.roomdetails.impl.notificationsettings.RoomNotificationSettingsNode import io.element.android.features.roomdetails.impl.rolesandpermissions.RolesAndPermissionsFlowNode import io.element.android.features.userprofile.shared.UserProfileNodeHelper -import io.element.android.features.userprofile.shared.avatar.AvatarPreviewNode import io.element.android.libraries.architecture.BackstackWithOverlayBox import io.element.android.libraries.architecture.BaseFlowNode import io.element.android.libraries.architecture.createNode import io.element.android.libraries.architecture.overlay.operation.show -import io.element.android.libraries.core.mimetype.MimeTypes import io.element.android.libraries.di.RoomScope import io.element.android.libraries.matrix.api.core.RoomId import io.element.android.libraries.matrix.api.core.UserId -import io.element.android.libraries.matrix.api.media.MediaSource import io.element.android.libraries.matrix.api.permalink.PermalinkData import io.element.android.libraries.matrix.api.room.MatrixRoom -import io.element.android.libraries.mediaviewer.api.local.MediaInfo -import io.element.android.libraries.mediaviewer.api.viewer.MediaViewerNode +import io.element.android.libraries.mediaviewer.api.MediaViewerEntryPoint import io.element.android.services.analytics.api.AnalyticsService import io.element.android.services.analyticsproviders.api.trackers.captureInteraction import kotlinx.parcelize.Parcelize @@ -59,6 +56,7 @@ class RoomDetailsFlowNode @AssistedInject constructor( private val room: MatrixRoom, private val analyticsService: AnalyticsService, private val messagesEntryPoint: MessagesEntryPoint, + private val mediaViewerEntryPoint: MediaViewerEntryPoint, ) : BaseFlowNode( backstack = BackStack( initialElement = plugins.filterIsInstance().first().initialElement.toNavTarget(), @@ -202,22 +200,18 @@ class RoomDetailsFlowNode @AssistedInject constructor( createNode(buildContext, plugins) } is NavTarget.AvatarPreview -> { - // We need to fake the MimeType here for the viewer to work. - val mimeType = MimeTypes.Images - val input = MediaViewerNode.Inputs( - mediaInfo = MediaInfo( - filename = navTarget.name, - caption = null, - mimeType = mimeType, - formattedFileSize = "", - fileExtension = "" - ), - mediaSource = MediaSource(url = navTarget.avatarUrl), - thumbnailSource = null, - canDownload = false, - canShare = false, - ) - createNode(buildContext, listOf(input)) + val callback = object : MediaViewerEntryPoint.Callback { + override fun onDone() { + backstack.pop() + } + } + mediaViewerEntryPoint.nodeBuilder(this, buildContext) + .avatar( + navTarget.name, + navTarget.avatarUrl, + ) + .callback(callback) + .build() } is NavTarget.PollHistory -> { diff --git a/features/userprofile/impl/src/main/kotlin/io/element/android/features/userprofile/impl/UserProfileFlowNode.kt b/features/userprofile/impl/src/main/kotlin/io/element/android/features/userprofile/impl/UserProfileFlowNode.kt index b544ad4750b..ce0d4a07f0a 100644 --- a/features/userprofile/impl/src/main/kotlin/io/element/android/features/userprofile/impl/UserProfileFlowNode.kt +++ b/features/userprofile/impl/src/main/kotlin/io/element/android/features/userprofile/impl/UserProfileFlowNode.kt @@ -15,6 +15,7 @@ import com.bumble.appyx.core.node.Node import com.bumble.appyx.core.plugin.Plugin import com.bumble.appyx.core.plugin.plugins import com.bumble.appyx.navmodel.backstack.BackStack +import com.bumble.appyx.navmodel.backstack.operation.pop import com.bumble.appyx.navmodel.backstack.operation.push import dagger.assisted.Assisted import dagger.assisted.AssistedInject @@ -24,18 +25,14 @@ import io.element.android.features.call.api.ElementCallEntryPoint import io.element.android.features.userprofile.api.UserProfileEntryPoint import io.element.android.features.userprofile.impl.root.UserProfileNode import io.element.android.features.userprofile.shared.UserProfileNodeHelper -import io.element.android.features.userprofile.shared.avatar.AvatarPreviewNode import io.element.android.libraries.architecture.BackstackView import io.element.android.libraries.architecture.BaseFlowNode import io.element.android.libraries.architecture.createNode import io.element.android.libraries.architecture.inputs -import io.element.android.libraries.core.mimetype.MimeTypes import io.element.android.libraries.di.SessionScope import io.element.android.libraries.matrix.api.core.RoomId -import io.element.android.libraries.matrix.api.media.MediaSource import io.element.android.libraries.matrix.api.user.CurrentSessionIdHolder -import io.element.android.libraries.mediaviewer.api.local.MediaInfo -import io.element.android.libraries.mediaviewer.api.viewer.MediaViewerNode +import io.element.android.libraries.mediaviewer.api.MediaViewerEntryPoint import kotlinx.parcelize.Parcelize @ContributesNode(SessionScope::class) @@ -44,6 +41,7 @@ class UserProfileFlowNode @AssistedInject constructor( @Assisted plugins: List, private val elementCallEntryPoint: ElementCallEntryPoint, private val sessionIdHolder: CurrentSessionIdHolder, + private val mediaViewerEntryPoint: MediaViewerEntryPoint, ) : BaseFlowNode( backstack = BackStack( initialElement = NavTarget.Root, @@ -80,22 +78,18 @@ class UserProfileFlowNode @AssistedInject constructor( createNode(buildContext, listOf(callback, params)) } is NavTarget.AvatarPreview -> { - // We need to fake the MimeType here for the viewer to work. - val mimeType = MimeTypes.Images - val input = MediaViewerNode.Inputs( - mediaInfo = MediaInfo( + val callback = object : MediaViewerEntryPoint.Callback { + override fun onDone() { + backstack.pop() + } + } + mediaViewerEntryPoint.nodeBuilder(this, buildContext) + .avatar( filename = navTarget.name, - caption = null, - mimeType = mimeType, - formattedFileSize = "", - fileExtension = "", - ), - mediaSource = MediaSource(url = navTarget.avatarUrl), - thumbnailSource = null, - canDownload = false, - canShare = false, - ) - createNode(buildContext, listOf(input)) + avatarUrl = navTarget.avatarUrl + ) + .callback(callback) + .build() } } } diff --git a/features/userprofile/shared/src/main/kotlin/io/element/android/features/userprofile/shared/avatar/AvatarPreviewNode.kt b/features/userprofile/shared/src/main/kotlin/io/element/android/features/userprofile/shared/avatar/AvatarPreviewNode.kt deleted file mode 100644 index 159b7f56f67..00000000000 --- a/features/userprofile/shared/src/main/kotlin/io/element/android/features/userprofile/shared/avatar/AvatarPreviewNode.kt +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright 2024 New Vector Ltd. - * - * SPDX-License-Identifier: AGPL-3.0-only - * Please see LICENSE in the repository root for full details. - */ - -package io.element.android.features.userprofile.shared.avatar - -import com.bumble.appyx.core.modality.BuildContext -import com.bumble.appyx.core.plugin.Plugin -import dagger.assisted.Assisted -import dagger.assisted.AssistedInject -import io.element.android.anvilannotations.ContributesNode -import io.element.android.libraries.di.SessionScope -import io.element.android.libraries.mediaviewer.api.viewer.MediaViewerNode -import io.element.android.libraries.mediaviewer.api.viewer.MediaViewerPresenter - -@ContributesNode(SessionScope::class) -class AvatarPreviewNode @AssistedInject constructor( - @Assisted buildContext: BuildContext, - @Assisted plugins: List, - presenterFactory: MediaViewerPresenter.Factory, -) : MediaViewerNode(buildContext, plugins, presenterFactory) diff --git a/libraries/mediaviewer/api/build.gradle.kts b/libraries/mediaviewer/api/build.gradle.kts index 5d434ae0946..d36a3605d2d 100644 --- a/libraries/mediaviewer/api/build.gradle.kts +++ b/libraries/mediaviewer/api/build.gradle.kts @@ -13,45 +13,12 @@ plugins { android { namespace = "io.element.android.libraries.mediaviewer.api" - testOptions { - unitTests { - isIncludeAndroidResources = true - } - } } setupAnvil() dependencies { - implementation(libs.coil.compose) - implementation(libs.androidx.media3.exoplayer) - implementation(libs.androidx.media3.ui) - implementation(libs.coroutines.core) - implementation(libs.dagger) - implementation(libs.telephoto.zoomableimage) - implementation(libs.vanniktech.blurhash) - implementation(libs.telephoto.flick) - - implementation(projects.libraries.androidutils) - implementation(projects.libraries.architecture) implementation(projects.libraries.core) - implementation(projects.libraries.dateformatter.api) - implementation(projects.libraries.di) - implementation(projects.libraries.designsystem) + implementation(projects.libraries.architecture) implementation(projects.libraries.matrix.api) - implementation(projects.libraries.matrixui) - implementation(projects.libraries.uiStrings) - - testImplementation(projects.libraries.matrix.test) - testImplementation(projects.libraries.mediaviewer.test) - testImplementation(projects.tests.testutils) - testImplementation(libs.test.junit) - testImplementation(libs.test.truth) - testImplementation(libs.test.mockk) - testImplementation(libs.test.robolectric) - testImplementation(libs.test.turbine) - testImplementation(libs.coroutines.core) - testImplementation(libs.coroutines.test) - testImplementation(libs.androidx.compose.ui.test.junit) - testReleaseImplementation(libs.androidx.compose.ui.test.manifest) } diff --git a/libraries/mediaviewer/api/src/main/kotlin/io/element/android/libraries/mediaviewer/api/local/MediaInfo.kt b/libraries/mediaviewer/api/src/main/kotlin/io/element/android/libraries/mediaviewer/api/MediaInfo.kt similarity index 93% rename from libraries/mediaviewer/api/src/main/kotlin/io/element/android/libraries/mediaviewer/api/local/MediaInfo.kt rename to libraries/mediaviewer/api/src/main/kotlin/io/element/android/libraries/mediaviewer/api/MediaInfo.kt index 5ded65b2b34..93cd2f9378f 100644 --- a/libraries/mediaviewer/api/src/main/kotlin/io/element/android/libraries/mediaviewer/api/local/MediaInfo.kt +++ b/libraries/mediaviewer/api/src/main/kotlin/io/element/android/libraries/mediaviewer/api/MediaInfo.kt @@ -1,11 +1,11 @@ /* - * Copyright 2023, 2024 New Vector Ltd. + * Copyright 2024 New Vector Ltd. * * SPDX-License-Identifier: AGPL-3.0-only * Please see LICENSE in the repository root for full details. */ -package io.element.android.libraries.mediaviewer.api.local +package io.element.android.libraries.mediaviewer.api import android.os.Parcelable import io.element.android.libraries.core.mimetype.MimeTypes diff --git a/libraries/mediaviewer/api/src/main/kotlin/io/element/android/libraries/mediaviewer/api/MediaViewerEntryPoint.kt b/libraries/mediaviewer/api/src/main/kotlin/io/element/android/libraries/mediaviewer/api/MediaViewerEntryPoint.kt new file mode 100644 index 00000000000..fb5ee5dece7 --- /dev/null +++ b/libraries/mediaviewer/api/src/main/kotlin/io/element/android/libraries/mediaviewer/api/MediaViewerEntryPoint.kt @@ -0,0 +1,38 @@ +/* + * Copyright 2024 New Vector Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only + * Please see LICENSE in the repository root for full details. + */ + +package io.element.android.libraries.mediaviewer.api + +import com.bumble.appyx.core.modality.BuildContext +import com.bumble.appyx.core.node.Node +import com.bumble.appyx.core.plugin.Plugin +import io.element.android.libraries.architecture.FeatureEntryPoint +import io.element.android.libraries.architecture.NodeInputs +import io.element.android.libraries.matrix.api.media.MediaSource + +interface MediaViewerEntryPoint : FeatureEntryPoint { + fun nodeBuilder(parentNode: Node, buildContext: BuildContext): NodeBuilder + + interface NodeBuilder { + fun callback(callback: Callback): NodeBuilder + fun params(params: Params): NodeBuilder + fun avatar(filename: String, avatarUrl: String): NodeBuilder + fun build(): Node + } + + interface Callback : Plugin { + fun onDone() + } + + data class Params( + val mediaInfo: MediaInfo, + val mediaSource: MediaSource, + val thumbnailSource: MediaSource?, + val canDownload: Boolean, + val canShare: Boolean, + ) : NodeInputs +} diff --git a/libraries/mediaviewer/api/src/main/kotlin/io/element/android/libraries/mediaviewer/api/local/LocalMedia.kt b/libraries/mediaviewer/api/src/main/kotlin/io/element/android/libraries/mediaviewer/api/local/LocalMedia.kt index 56bda259a69..fade6706977 100644 --- a/libraries/mediaviewer/api/src/main/kotlin/io/element/android/libraries/mediaviewer/api/local/LocalMedia.kt +++ b/libraries/mediaviewer/api/src/main/kotlin/io/element/android/libraries/mediaviewer/api/local/LocalMedia.kt @@ -10,6 +10,7 @@ package io.element.android.libraries.mediaviewer.api.local import android.net.Uri import android.os.Parcelable import androidx.compose.runtime.Immutable +import io.element.android.libraries.mediaviewer.api.MediaInfo import kotlinx.parcelize.Parcelize @Parcelize diff --git a/libraries/mediaviewer/api/src/main/kotlin/io/element/android/libraries/mediaviewer/api/local/LocalMediaFactory.kt b/libraries/mediaviewer/api/src/main/kotlin/io/element/android/libraries/mediaviewer/api/local/LocalMediaFactory.kt index 92000702636..beeccb7c488 100644 --- a/libraries/mediaviewer/api/src/main/kotlin/io/element/android/libraries/mediaviewer/api/local/LocalMediaFactory.kt +++ b/libraries/mediaviewer/api/src/main/kotlin/io/element/android/libraries/mediaviewer/api/local/LocalMediaFactory.kt @@ -9,6 +9,7 @@ package io.element.android.libraries.mediaviewer.api.local import android.net.Uri import io.element.android.libraries.matrix.api.media.MediaFile +import io.element.android.libraries.mediaviewer.api.MediaInfo interface LocalMediaFactory { /** diff --git a/libraries/mediaviewer/api/src/main/kotlin/io/element/android/libraries/mediaviewer/api/local/LocalMediaRenderer.kt b/libraries/mediaviewer/api/src/main/kotlin/io/element/android/libraries/mediaviewer/api/local/LocalMediaRenderer.kt new file mode 100644 index 00000000000..3b387ef0d77 --- /dev/null +++ b/libraries/mediaviewer/api/src/main/kotlin/io/element/android/libraries/mediaviewer/api/local/LocalMediaRenderer.kt @@ -0,0 +1,15 @@ +/* + * Copyright 2024 New Vector Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only + * Please see LICENSE in the repository root for full details. + */ + +package io.element.android.libraries.mediaviewer.api.local + +import androidx.compose.runtime.Composable + +interface LocalMediaRenderer { + @Composable + fun Render(localMedia: LocalMedia) +} diff --git a/libraries/mediaviewer/api/src/main/kotlin/io/element/android/libraries/mediaviewer/api/util/FileExtensionExtractor.kt b/libraries/mediaviewer/api/src/main/kotlin/io/element/android/libraries/mediaviewer/api/util/FileExtensionExtractor.kt index 32ca151160b..e7586a6f877 100644 --- a/libraries/mediaviewer/api/src/main/kotlin/io/element/android/libraries/mediaviewer/api/util/FileExtensionExtractor.kt +++ b/libraries/mediaviewer/api/src/main/kotlin/io/element/android/libraries/mediaviewer/api/util/FileExtensionExtractor.kt @@ -7,30 +7,6 @@ package io.element.android.libraries.mediaviewer.api.util -import android.webkit.MimeTypeMap -import com.squareup.anvil.annotations.ContributesBinding -import io.element.android.libraries.di.AppScope -import javax.inject.Inject - interface FileExtensionExtractor { fun extractFromName(name: String): String } - -@ContributesBinding(AppScope::class) -class FileExtensionExtractorWithValidation @Inject constructor() : FileExtensionExtractor { - override fun extractFromName(name: String): String { - val fileExtension = name.substringAfterLast('.', "") - // Makes sure the extension is known by the system, otherwise default to binary extension. - return if (MimeTypeMap.getSingleton().hasExtension(fileExtension)) { - fileExtension - } else { - "bin" - } - } -} - -class FileExtensionExtractorWithoutValidation : FileExtensionExtractor { - override fun extractFromName(name: String): String { - return name.substringAfterLast('.', "") - } -} diff --git a/libraries/mediaviewer/impl/build.gradle.kts b/libraries/mediaviewer/impl/build.gradle.kts index a814f64ab7d..5ebc252343d 100644 --- a/libraries/mediaviewer/impl/build.gradle.kts +++ b/libraries/mediaviewer/impl/build.gradle.kts @@ -13,6 +13,11 @@ plugins { android { namespace = "io.element.android.libraries.mediaviewer.impl" + testOptions { + unitTests { + isIncludeAndroidResources = true + } + } } setupAnvil() @@ -21,6 +26,23 @@ dependencies { implementation(libs.coroutines.core) implementation(libs.dagger) + implementation(libs.coil.compose) + implementation(libs.androidx.media3.exoplayer) + implementation(libs.androidx.media3.ui) + implementation(libs.telephoto.zoomableimage) + implementation(libs.vanniktech.blurhash) + implementation(libs.telephoto.flick) + + implementation(projects.libraries.androidutils) + implementation(projects.libraries.architecture) + implementation(projects.libraries.core) + implementation(projects.libraries.dateformatter.api) + implementation(projects.libraries.di) + implementation(projects.libraries.designsystem) + implementation(projects.libraries.matrix.api) + implementation(projects.libraries.matrixui) + implementation(projects.libraries.uiStrings) + api(projects.libraries.mediaviewer.api) implementation(projects.libraries.androidutils) implementation(projects.libraries.core) @@ -39,4 +61,6 @@ dependencies { testImplementation(libs.test.turbine) testImplementation(libs.coroutines.core) testImplementation(libs.coroutines.test) + testImplementation(libs.androidx.compose.ui.test.junit) + testReleaseImplementation(libs.androidx.compose.ui.test.manifest) } diff --git a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/DefaultMediaViewerEntryPoint.kt b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/DefaultMediaViewerEntryPoint.kt new file mode 100644 index 00000000000..5bd16c840b7 --- /dev/null +++ b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/DefaultMediaViewerEntryPoint.kt @@ -0,0 +1,64 @@ +/* + * Copyright 2024 New Vector Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only + * Please see LICENSE in the repository root for full details. + */ + +package io.element.android.libraries.mediaviewer.impl + +import com.bumble.appyx.core.modality.BuildContext +import com.bumble.appyx.core.node.Node +import com.bumble.appyx.core.plugin.Plugin +import com.squareup.anvil.annotations.ContributesBinding +import io.element.android.libraries.architecture.createNode +import io.element.android.libraries.core.mimetype.MimeTypes +import io.element.android.libraries.di.AppScope +import io.element.android.libraries.matrix.api.media.MediaSource +import io.element.android.libraries.mediaviewer.api.MediaInfo +import io.element.android.libraries.mediaviewer.api.MediaViewerEntryPoint +import io.element.android.libraries.mediaviewer.impl.viewer.MediaViewerNode +import javax.inject.Inject + +@ContributesBinding(AppScope::class) +class DefaultMediaViewerEntryPoint @Inject constructor() : MediaViewerEntryPoint { + override fun nodeBuilder(parentNode: Node, buildContext: BuildContext): MediaViewerEntryPoint.NodeBuilder { + val plugins = ArrayList() + + return object : MediaViewerEntryPoint.NodeBuilder { + override fun callback(callback: MediaViewerEntryPoint.Callback): MediaViewerEntryPoint.NodeBuilder { + plugins += callback + return this + } + + override fun params(params: MediaViewerEntryPoint.Params): MediaViewerEntryPoint.NodeBuilder { + plugins += params + return this + } + + override fun avatar(filename: String, avatarUrl: String): MediaViewerEntryPoint.NodeBuilder { + // We need to fake the MimeType here for the viewer to work. + val mimeType = MimeTypes.Images + return params( + MediaViewerEntryPoint.Params( + mediaInfo = MediaInfo( + filename = filename, + caption = null, + mimeType = mimeType, + formattedFileSize = "", + fileExtension = "" + ), + mediaSource = MediaSource(url = avatarUrl), + thumbnailSource = null, + canDownload = false, + canShare = false, + ) + ) + } + + override fun build(): Node { + return parentNode.createNode(buildContext, plugins) + } + } + } +} diff --git a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/AndroidLocalMediaActions.kt b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/AndroidLocalMediaActions.kt index 66bed465ed9..7bd92a800f0 100644 --- a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/AndroidLocalMediaActions.kt +++ b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/AndroidLocalMediaActions.kt @@ -35,7 +35,6 @@ import io.element.android.libraries.core.mimetype.MimeTypes import io.element.android.libraries.di.AppScope import io.element.android.libraries.di.ApplicationContext import io.element.android.libraries.mediaviewer.api.local.LocalMedia -import io.element.android.libraries.mediaviewer.api.local.LocalMediaActions import kotlinx.coroutines.launch import kotlinx.coroutines.withContext import timber.log.Timber diff --git a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/AndroidLocalMediaFactory.kt b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/AndroidLocalMediaFactory.kt index 06fefa26230..461563f4653 100644 --- a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/AndroidLocalMediaFactory.kt +++ b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/AndroidLocalMediaFactory.kt @@ -20,9 +20,9 @@ import io.element.android.libraries.di.AppScope import io.element.android.libraries.di.ApplicationContext import io.element.android.libraries.matrix.api.media.MediaFile import io.element.android.libraries.matrix.api.media.toFile +import io.element.android.libraries.mediaviewer.api.MediaInfo import io.element.android.libraries.mediaviewer.api.local.LocalMedia import io.element.android.libraries.mediaviewer.api.local.LocalMediaFactory -import io.element.android.libraries.mediaviewer.api.local.MediaInfo import io.element.android.libraries.mediaviewer.api.util.FileExtensionExtractor import javax.inject.Inject diff --git a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/DefaultLocalMediaRenderer.kt b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/DefaultLocalMediaRenderer.kt new file mode 100644 index 00000000000..6b1005dccf7 --- /dev/null +++ b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/DefaultLocalMediaRenderer.kt @@ -0,0 +1,37 @@ +/* + * Copyright 2024 New Vector Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only + * Please see LICENSE in the repository root for full details. + */ + +package io.element.android.libraries.mediaviewer.impl.local + +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import com.squareup.anvil.annotations.ContributesBinding +import io.element.android.libraries.di.AppScope +import io.element.android.libraries.mediaviewer.api.local.LocalMedia +import io.element.android.libraries.mediaviewer.api.local.LocalMediaRenderer +import me.saket.telephoto.zoomable.ZoomSpec +import me.saket.telephoto.zoomable.rememberZoomableState +import javax.inject.Inject + +@ContributesBinding(AppScope::class) +class DefaultLocalMediaRenderer @Inject constructor() : LocalMediaRenderer { + @Composable + override fun Render(localMedia: LocalMedia) { + val localMediaViewState = rememberLocalMediaViewState( + zoomableState = rememberZoomableState( + zoomSpec = ZoomSpec(maxZoomFactor = 4f, preventOverOrUnderZoom = false) + ) + ) + LocalMediaView( + modifier = Modifier.fillMaxSize(), + localMedia = localMedia, + localMediaViewState = localMediaViewState, + onClick = {} + ) + } +} diff --git a/libraries/mediaviewer/api/src/main/kotlin/io/element/android/libraries/mediaviewer/api/local/LocalMediaActions.kt b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/LocalMediaActions.kt similarity index 87% rename from libraries/mediaviewer/api/src/main/kotlin/io/element/android/libraries/mediaviewer/api/local/LocalMediaActions.kt rename to libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/LocalMediaActions.kt index c7f0ba7d90a..92f873e2ea0 100644 --- a/libraries/mediaviewer/api/src/main/kotlin/io/element/android/libraries/mediaviewer/api/local/LocalMediaActions.kt +++ b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/LocalMediaActions.kt @@ -5,9 +5,10 @@ * Please see LICENSE in the repository root for full details. */ -package io.element.android.libraries.mediaviewer.api.local +package io.element.android.libraries.mediaviewer.impl.local import androidx.compose.runtime.Composable +import io.element.android.libraries.mediaviewer.api.local.LocalMedia interface LocalMediaActions { @Composable diff --git a/libraries/mediaviewer/api/src/main/kotlin/io/element/android/libraries/mediaviewer/api/local/LocalMediaView.kt b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/LocalMediaView.kt similarity index 91% rename from libraries/mediaviewer/api/src/main/kotlin/io/element/android/libraries/mediaviewer/api/local/LocalMediaView.kt rename to libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/LocalMediaView.kt index b7102b0f845..be48711bf00 100644 --- a/libraries/mediaviewer/api/src/main/kotlin/io/element/android/libraries/mediaviewer/api/local/LocalMediaView.kt +++ b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/LocalMediaView.kt @@ -5,7 +5,7 @@ * Please see LICENSE in the repository root for full details. */ -package io.element.android.libraries.mediaviewer.api.local +package io.element.android.libraries.mediaviewer.impl.local import android.annotation.SuppressLint import android.net.Uri @@ -67,12 +67,14 @@ import io.element.android.libraries.designsystem.theme.components.Text import io.element.android.libraries.designsystem.utils.CommonDrawables import io.element.android.libraries.designsystem.utils.KeepScreenOn import io.element.android.libraries.designsystem.utils.OnLifecycleEvent +import io.element.android.libraries.mediaviewer.api.MediaInfo import io.element.android.libraries.mediaviewer.api.helper.formatFileExtensionAndSize -import io.element.android.libraries.mediaviewer.api.local.exoplayer.ExoPlayerWrapper -import io.element.android.libraries.mediaviewer.api.local.pdf.PdfViewer -import io.element.android.libraries.mediaviewer.api.local.pdf.rememberPdfViewerState -import io.element.android.libraries.mediaviewer.api.player.MediaPlayerControllerState -import io.element.android.libraries.mediaviewer.api.player.MediaPlayerControllerView +import io.element.android.libraries.mediaviewer.api.local.LocalMedia +import io.element.android.libraries.mediaviewer.impl.local.exoplayer.ExoPlayerWrapper +import io.element.android.libraries.mediaviewer.impl.local.pdf.PdfViewer +import io.element.android.libraries.mediaviewer.impl.local.pdf.rememberPdfViewerState +import io.element.android.libraries.mediaviewer.impl.player.MediaPlayerControllerState +import io.element.android.libraries.mediaviewer.impl.player.MediaPlayerControllerView import io.element.android.libraries.ui.strings.CommonStrings import kotlinx.coroutines.delay import me.saket.telephoto.zoomable.coil.ZoomableAsyncImage @@ -153,8 +155,8 @@ private fun MediaVideoView( if (LocalInspectionMode.current) { Text( modifier = modifier - .background(ElementTheme.colors.bgSubtlePrimary) - .wrapContentSize(), + .background(ElementTheme.colors.bgSubtlePrimary) + .wrapContentSize(), text = "A Video Player will render here", ) } else { @@ -267,8 +269,8 @@ private fun ExoPlayerMediaVideoView( KeepScreenOn(mediaPlayerControllerState.isPlaying) Box( modifier = modifier - .background(ElementTheme.colors.bgSubtlePrimary) - .wrapContentSize(), + .background(ElementTheme.colors.bgSubtlePrimary) + .wrapContentSize(), ) { AndroidView( modifier = Modifier.fillMaxSize(), @@ -318,8 +320,8 @@ private fun ExoPlayerMediaVideoView( exoPlayer.volume = if (exoPlayer.volume == 1f) 0f else 1f }, modifier = Modifier - .fillMaxWidth() - .align(Alignment.BottomCenter), + .fillMaxWidth() + .align(Alignment.BottomCenter), ) } @@ -369,20 +371,20 @@ private fun MediaFileView( val interactionSource = remember { MutableInteractionSource() } Box( modifier = modifier - .padding(horizontal = 8.dp) - .clickable( - onClick = onClick, - interactionSource = interactionSource, - indication = null - ), + .padding(horizontal = 8.dp) + .clickable( + onClick = onClick, + interactionSource = interactionSource, + indication = null + ), contentAlignment = Alignment.Center ) { Column(horizontalAlignment = Alignment.CenterHorizontally) { Box( modifier = Modifier - .size(72.dp) - .clip(CircleShape) - .background(MaterialTheme.colorScheme.onBackground), + .size(72.dp) + .clip(CircleShape) + .background(MaterialTheme.colorScheme.onBackground), contentAlignment = Alignment.Center, ) { Icon( @@ -390,8 +392,8 @@ private fun MediaFileView( contentDescription = null, tint = MaterialTheme.colorScheme.background, modifier = Modifier - .size(32.dp) - .rotate(if (isAudio) 0f else -45f), + .size(32.dp) + .rotate(if (isAudio) 0f else -45f), ) } if (info != null) { diff --git a/libraries/mediaviewer/api/src/main/kotlin/io/element/android/libraries/mediaviewer/api/local/LocalMediaViewState.kt b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/LocalMediaViewState.kt similarity index 95% rename from libraries/mediaviewer/api/src/main/kotlin/io/element/android/libraries/mediaviewer/api/local/LocalMediaViewState.kt rename to libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/LocalMediaViewState.kt index b7237c26eb5..8705ef49d3b 100644 --- a/libraries/mediaviewer/api/src/main/kotlin/io/element/android/libraries/mediaviewer/api/local/LocalMediaViewState.kt +++ b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/LocalMediaViewState.kt @@ -5,7 +5,7 @@ * Please see LICENSE in the repository root for full details. */ -package io.element.android.libraries.mediaviewer.api.local +package io.element.android.libraries.mediaviewer.impl.local import androidx.compose.runtime.Composable import androidx.compose.runtime.Immutable diff --git a/libraries/mediaviewer/api/src/main/kotlin/io/element/android/libraries/mediaviewer/api/local/exoplayer/ExoPlayerWrapper.kt b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/exoplayer/ExoPlayerWrapper.kt similarity index 93% rename from libraries/mediaviewer/api/src/main/kotlin/io/element/android/libraries/mediaviewer/api/local/exoplayer/ExoPlayerWrapper.kt rename to libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/exoplayer/ExoPlayerWrapper.kt index 740f1675e05..41d59b395ba 100644 --- a/libraries/mediaviewer/api/src/main/kotlin/io/element/android/libraries/mediaviewer/api/local/exoplayer/ExoPlayerWrapper.kt +++ b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/exoplayer/ExoPlayerWrapper.kt @@ -5,7 +5,7 @@ * Please see LICENSE in the repository root for full details. */ -package io.element.android.libraries.mediaviewer.api.local.exoplayer +package io.element.android.libraries.mediaviewer.impl.local.exoplayer import android.content.Context import androidx.media3.common.Player diff --git a/libraries/mediaviewer/api/src/main/kotlin/io/element/android/libraries/mediaviewer/api/local/pdf/ParcelFileDescriptorFactory.kt b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/pdf/ParcelFileDescriptorFactory.kt similarity index 91% rename from libraries/mediaviewer/api/src/main/kotlin/io/element/android/libraries/mediaviewer/api/local/pdf/ParcelFileDescriptorFactory.kt rename to libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/pdf/ParcelFileDescriptorFactory.kt index e73f24ea618..bd931cadcb9 100644 --- a/libraries/mediaviewer/api/src/main/kotlin/io/element/android/libraries/mediaviewer/api/local/pdf/ParcelFileDescriptorFactory.kt +++ b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/pdf/ParcelFileDescriptorFactory.kt @@ -5,7 +5,7 @@ * Please see LICENSE in the repository root for full details. */ -package io.element.android.libraries.mediaviewer.api.local.pdf +package io.element.android.libraries.mediaviewer.impl.local.pdf import android.content.Context import android.net.Uri diff --git a/libraries/mediaviewer/api/src/main/kotlin/io/element/android/libraries/mediaviewer/api/local/pdf/PdfPage.kt b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/pdf/PdfPage.kt similarity index 98% rename from libraries/mediaviewer/api/src/main/kotlin/io/element/android/libraries/mediaviewer/api/local/pdf/PdfPage.kt rename to libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/pdf/PdfPage.kt index 137c3e321f8..655d577fda5 100644 --- a/libraries/mediaviewer/api/src/main/kotlin/io/element/android/libraries/mediaviewer/api/local/pdf/PdfPage.kt +++ b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/pdf/PdfPage.kt @@ -5,7 +5,7 @@ * Please see LICENSE in the repository root for full details. */ -package io.element.android.libraries.mediaviewer.api.local.pdf +package io.element.android.libraries.mediaviewer.impl.local.pdf import android.graphics.Bitmap import android.graphics.Canvas diff --git a/libraries/mediaviewer/api/src/main/kotlin/io/element/android/libraries/mediaviewer/api/local/pdf/PdfRendererManager.kt b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/pdf/PdfRendererManager.kt similarity index 97% rename from libraries/mediaviewer/api/src/main/kotlin/io/element/android/libraries/mediaviewer/api/local/pdf/PdfRendererManager.kt rename to libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/pdf/PdfRendererManager.kt index 255822b8533..02f5ef58bf3 100644 --- a/libraries/mediaviewer/api/src/main/kotlin/io/element/android/libraries/mediaviewer/api/local/pdf/PdfRendererManager.kt +++ b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/pdf/PdfRendererManager.kt @@ -5,7 +5,7 @@ * Please see LICENSE in the repository root for full details. */ -package io.element.android.libraries.mediaviewer.api.local.pdf +package io.element.android.libraries.mediaviewer.impl.local.pdf import android.graphics.pdf.PdfRenderer import android.os.ParcelFileDescriptor diff --git a/libraries/mediaviewer/api/src/main/kotlin/io/element/android/libraries/mediaviewer/api/local/pdf/PdfViewer.kt b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/pdf/PdfViewer.kt similarity index 98% rename from libraries/mediaviewer/api/src/main/kotlin/io/element/android/libraries/mediaviewer/api/local/pdf/PdfViewer.kt rename to libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/pdf/PdfViewer.kt index 6202db88b19..ffb8e83d453 100644 --- a/libraries/mediaviewer/api/src/main/kotlin/io/element/android/libraries/mediaviewer/api/local/pdf/PdfViewer.kt +++ b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/pdf/PdfViewer.kt @@ -5,7 +5,7 @@ * Please see LICENSE in the repository root for full details. */ -package io.element.android.libraries.mediaviewer.api.local.pdf +package io.element.android.libraries.mediaviewer.impl.local.pdf import androidx.compose.foundation.Image import androidx.compose.foundation.background diff --git a/libraries/mediaviewer/api/src/main/kotlin/io/element/android/libraries/mediaviewer/api/local/pdf/PdfViewerState.kt b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/pdf/PdfViewerState.kt similarity index 97% rename from libraries/mediaviewer/api/src/main/kotlin/io/element/android/libraries/mediaviewer/api/local/pdf/PdfViewerState.kt rename to libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/pdf/PdfViewerState.kt index 72eb73c3015..095d4d15c4f 100644 --- a/libraries/mediaviewer/api/src/main/kotlin/io/element/android/libraries/mediaviewer/api/local/pdf/PdfViewerState.kt +++ b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/pdf/PdfViewerState.kt @@ -5,7 +5,7 @@ * Please see LICENSE in the repository root for full details. */ -package io.element.android.libraries.mediaviewer.api.local.pdf +package io.element.android.libraries.mediaviewer.impl.local.pdf import android.content.Context import androidx.compose.foundation.lazy.LazyListState diff --git a/libraries/mediaviewer/api/src/main/kotlin/io/element/android/libraries/mediaviewer/api/player/MediaPlayerControllerState.kt b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/player/MediaPlayerControllerState.kt similarity index 84% rename from libraries/mediaviewer/api/src/main/kotlin/io/element/android/libraries/mediaviewer/api/player/MediaPlayerControllerState.kt rename to libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/player/MediaPlayerControllerState.kt index f5197af99be..d922483ff1f 100644 --- a/libraries/mediaviewer/api/src/main/kotlin/io/element/android/libraries/mediaviewer/api/player/MediaPlayerControllerState.kt +++ b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/player/MediaPlayerControllerState.kt @@ -5,7 +5,7 @@ * Please see LICENSE in the repository root for full details. */ -package io.element.android.libraries.mediaviewer.api.player +package io.element.android.libraries.mediaviewer.impl.player data class MediaPlayerControllerState( val isVisible: Boolean, diff --git a/libraries/mediaviewer/api/src/main/kotlin/io/element/android/libraries/mediaviewer/api/player/MediaPlayerControllerStateProvider.kt b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/player/MediaPlayerControllerStateProvider.kt similarity index 94% rename from libraries/mediaviewer/api/src/main/kotlin/io/element/android/libraries/mediaviewer/api/player/MediaPlayerControllerStateProvider.kt rename to libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/player/MediaPlayerControllerStateProvider.kt index 5cffb639904..6aa93547f60 100644 --- a/libraries/mediaviewer/api/src/main/kotlin/io/element/android/libraries/mediaviewer/api/player/MediaPlayerControllerStateProvider.kt +++ b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/player/MediaPlayerControllerStateProvider.kt @@ -5,7 +5,7 @@ * Please see LICENSE in the repository root for full details. */ -package io.element.android.libraries.mediaviewer.api.player +package io.element.android.libraries.mediaviewer.impl.player import androidx.compose.ui.tooling.preview.PreviewParameterProvider diff --git a/libraries/mediaviewer/api/src/main/kotlin/io/element/android/libraries/mediaviewer/api/player/MediaPlayerControllerView.kt b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/player/MediaPlayerControllerView.kt similarity index 99% rename from libraries/mediaviewer/api/src/main/kotlin/io/element/android/libraries/mediaviewer/api/player/MediaPlayerControllerView.kt rename to libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/player/MediaPlayerControllerView.kt index 188d4e0c4a3..c9f548aab25 100644 --- a/libraries/mediaviewer/api/src/main/kotlin/io/element/android/libraries/mediaviewer/api/player/MediaPlayerControllerView.kt +++ b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/player/MediaPlayerControllerView.kt @@ -5,7 +5,7 @@ * Please see LICENSE in the repository root for full details. */ -package io.element.android.libraries.mediaviewer.api.player +package io.element.android.libraries.mediaviewer.impl.player import androidx.compose.animation.AnimatedVisibility import androidx.compose.animation.fadeIn diff --git a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/util/FileExtensionExtractor.kt b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/util/FileExtensionExtractor.kt new file mode 100644 index 00000000000..026be26b2ed --- /dev/null +++ b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/util/FileExtensionExtractor.kt @@ -0,0 +1,27 @@ +/* + * Copyright 2023, 2024 New Vector Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only + * Please see LICENSE in the repository root for full details. + */ + +package io.element.android.libraries.mediaviewer.impl.util + +import android.webkit.MimeTypeMap +import com.squareup.anvil.annotations.ContributesBinding +import io.element.android.libraries.di.AppScope +import io.element.android.libraries.mediaviewer.api.util.FileExtensionExtractor +import javax.inject.Inject + +@ContributesBinding(AppScope::class) +class FileExtensionExtractorWithValidation @Inject constructor() : FileExtensionExtractor { + override fun extractFromName(name: String): String { + val fileExtension = name.substringAfterLast('.', "") + // Makes sure the extension is known by the system, otherwise default to binary extension. + return if (MimeTypeMap.getSingleton().hasExtension(fileExtension)) { + fileExtension + } else { + "bin" + } + } +} diff --git a/libraries/mediaviewer/api/src/main/kotlin/io/element/android/libraries/mediaviewer/api/viewer/MediaViewerEvents.kt b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerEvents.kt similarity index 87% rename from libraries/mediaviewer/api/src/main/kotlin/io/element/android/libraries/mediaviewer/api/viewer/MediaViewerEvents.kt rename to libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerEvents.kt index f72becb58ff..ac2714584c1 100644 --- a/libraries/mediaviewer/api/src/main/kotlin/io/element/android/libraries/mediaviewer/api/viewer/MediaViewerEvents.kt +++ b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerEvents.kt @@ -5,7 +5,7 @@ * Please see LICENSE in the repository root for full details. */ -package io.element.android.libraries.mediaviewer.api.viewer +package io.element.android.libraries.mediaviewer.impl.viewer sealed interface MediaViewerEvents { data object SaveOnDisk : MediaViewerEvents diff --git a/libraries/mediaviewer/api/src/main/kotlin/io/element/android/libraries/mediaviewer/api/viewer/MediaViewerNode.kt b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerNode.kt similarity index 69% rename from libraries/mediaviewer/api/src/main/kotlin/io/element/android/libraries/mediaviewer/api/viewer/MediaViewerNode.kt rename to libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerNode.kt index 7d173f52913..83c7c1aca76 100644 --- a/libraries/mediaviewer/api/src/main/kotlin/io/element/android/libraries/mediaviewer/api/viewer/MediaViewerNode.kt +++ b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerNode.kt @@ -5,22 +5,21 @@ * Please see LICENSE in the repository root for full details. */ -package io.element.android.libraries.mediaviewer.api.viewer +package io.element.android.libraries.mediaviewer.impl.viewer import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import com.bumble.appyx.core.modality.BuildContext import com.bumble.appyx.core.node.Node import com.bumble.appyx.core.plugin.Plugin +import com.bumble.appyx.core.plugin.plugins import dagger.assisted.Assisted import dagger.assisted.AssistedInject import io.element.android.anvilannotations.ContributesNode import io.element.android.compound.theme.ForcedDarkElementTheme -import io.element.android.libraries.architecture.NodeInputs import io.element.android.libraries.architecture.inputs import io.element.android.libraries.di.RoomScope -import io.element.android.libraries.matrix.api.media.MediaSource -import io.element.android.libraries.mediaviewer.api.local.MediaInfo +import io.element.android.libraries.mediaviewer.api.MediaViewerEntryPoint @ContributesNode(RoomScope::class) open class MediaViewerNode @AssistedInject constructor( @@ -28,15 +27,13 @@ open class MediaViewerNode @AssistedInject constructor( @Assisted plugins: List, presenterFactory: MediaViewerPresenter.Factory, ) : Node(buildContext, plugins = plugins) { - data class Inputs( - val mediaInfo: MediaInfo, - val mediaSource: MediaSource, - val thumbnailSource: MediaSource?, - val canDownload: Boolean, - val canShare: Boolean, - ) : NodeInputs + private val inputs = inputs() - private val inputs: Inputs = inputs() + private fun onDone() { + plugins().forEach { + it.onDone() + } + } private val presenter = presenterFactory.create(inputs) @@ -47,7 +44,7 @@ open class MediaViewerNode @AssistedInject constructor( MediaViewerView( state = state, modifier = modifier, - onBackClick = this::navigateUp + onBackClick = ::onDone ) } } diff --git a/libraries/mediaviewer/api/src/main/kotlin/io/element/android/libraries/mediaviewer/api/viewer/MediaViewerPresenter.kt b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerPresenter.kt similarity index 94% rename from libraries/mediaviewer/api/src/main/kotlin/io/element/android/libraries/mediaviewer/api/viewer/MediaViewerPresenter.kt rename to libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerPresenter.kt index 3cef900040b..068fb02b0f7 100644 --- a/libraries/mediaviewer/api/src/main/kotlin/io/element/android/libraries/mediaviewer/api/viewer/MediaViewerPresenter.kt +++ b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerPresenter.kt @@ -5,7 +5,7 @@ * Please see LICENSE in the repository root for full details. */ -package io.element.android.libraries.mediaviewer.api.viewer +package io.element.android.libraries.mediaviewer.impl.viewer import android.content.ActivityNotFoundException import androidx.compose.runtime.Composable @@ -27,16 +27,17 @@ import io.element.android.libraries.designsystem.utils.snackbar.SnackbarMessage import io.element.android.libraries.designsystem.utils.snackbar.collectSnackbarMessageAsState import io.element.android.libraries.matrix.api.media.MatrixMediaLoader import io.element.android.libraries.matrix.api.media.MediaFile +import io.element.android.libraries.mediaviewer.api.MediaViewerEntryPoint import io.element.android.libraries.mediaviewer.api.local.LocalMedia -import io.element.android.libraries.mediaviewer.api.local.LocalMediaActions import io.element.android.libraries.mediaviewer.api.local.LocalMediaFactory +import io.element.android.libraries.mediaviewer.impl.local.LocalMediaActions import io.element.android.libraries.ui.strings.CommonStrings import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.launch import io.element.android.libraries.androidutils.R as UtilsR class MediaViewerPresenter @AssistedInject constructor( - @Assisted private val inputs: MediaViewerNode.Inputs, + @Assisted private val inputs: MediaViewerEntryPoint.Params, private val localMediaFactory: LocalMediaFactory, private val mediaLoader: MatrixMediaLoader, private val localMediaActions: LocalMediaActions, @@ -44,7 +45,7 @@ class MediaViewerPresenter @AssistedInject constructor( ) : Presenter { @AssistedFactory interface Factory { - fun create(inputs: MediaViewerNode.Inputs): MediaViewerPresenter + fun create(inputs: MediaViewerEntryPoint.Params): MediaViewerPresenter } @Composable diff --git a/libraries/mediaviewer/api/src/main/kotlin/io/element/android/libraries/mediaviewer/api/viewer/MediaViewerState.kt b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerState.kt similarity index 85% rename from libraries/mediaviewer/api/src/main/kotlin/io/element/android/libraries/mediaviewer/api/viewer/MediaViewerState.kt rename to libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerState.kt index 3dd9f1b3722..94d6653241c 100644 --- a/libraries/mediaviewer/api/src/main/kotlin/io/element/android/libraries/mediaviewer/api/viewer/MediaViewerState.kt +++ b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerState.kt @@ -5,13 +5,13 @@ * Please see LICENSE in the repository root for full details. */ -package io.element.android.libraries.mediaviewer.api.viewer +package io.element.android.libraries.mediaviewer.impl.viewer import io.element.android.libraries.architecture.AsyncData import io.element.android.libraries.designsystem.utils.snackbar.SnackbarMessage import io.element.android.libraries.matrix.api.media.MediaSource +import io.element.android.libraries.mediaviewer.api.MediaInfo import io.element.android.libraries.mediaviewer.api.local.LocalMedia -import io.element.android.libraries.mediaviewer.api.local.MediaInfo data class MediaViewerState( val mediaInfo: MediaInfo, diff --git a/libraries/mediaviewer/api/src/main/kotlin/io/element/android/libraries/mediaviewer/api/viewer/MediaViewerStateProvider.kt b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerStateProvider.kt similarity index 84% rename from libraries/mediaviewer/api/src/main/kotlin/io/element/android/libraries/mediaviewer/api/viewer/MediaViewerStateProvider.kt rename to libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerStateProvider.kt index 2ae215ac967..4ffcb75b075 100644 --- a/libraries/mediaviewer/api/src/main/kotlin/io/element/android/libraries/mediaviewer/api/viewer/MediaViewerStateProvider.kt +++ b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerStateProvider.kt @@ -5,18 +5,18 @@ * Please see LICENSE in the repository root for full details. */ -package io.element.android.libraries.mediaviewer.api.viewer +package io.element.android.libraries.mediaviewer.impl.viewer import android.net.Uri import androidx.compose.ui.tooling.preview.PreviewParameterProvider import io.element.android.libraries.architecture.AsyncData +import io.element.android.libraries.mediaviewer.api.MediaInfo +import io.element.android.libraries.mediaviewer.api.aPdfMediaInfo +import io.element.android.libraries.mediaviewer.api.aVideoMediaInfo +import io.element.android.libraries.mediaviewer.api.anApkMediaInfo +import io.element.android.libraries.mediaviewer.api.anAudioMediaInfo +import io.element.android.libraries.mediaviewer.api.anImageMediaInfo import io.element.android.libraries.mediaviewer.api.local.LocalMedia -import io.element.android.libraries.mediaviewer.api.local.MediaInfo -import io.element.android.libraries.mediaviewer.api.local.aPdfMediaInfo -import io.element.android.libraries.mediaviewer.api.local.aVideoMediaInfo -import io.element.android.libraries.mediaviewer.api.local.anApkMediaInfo -import io.element.android.libraries.mediaviewer.api.local.anAudioMediaInfo -import io.element.android.libraries.mediaviewer.api.local.anImageMediaInfo open class MediaViewerStateProvider : PreviewParameterProvider { override val values: Sequence diff --git a/libraries/mediaviewer/api/src/main/kotlin/io/element/android/libraries/mediaviewer/api/viewer/MediaViewerView.kt b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerView.kt similarity index 95% rename from libraries/mediaviewer/api/src/main/kotlin/io/element/android/libraries/mediaviewer/api/viewer/MediaViewerView.kt rename to libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerView.kt index 9f362c13fa3..ae5e9401cb9 100644 --- a/libraries/mediaviewer/api/src/main/kotlin/io/element/android/libraries/mediaviewer/api/viewer/MediaViewerView.kt +++ b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerView.kt @@ -7,8 +7,9 @@ @file:OptIn(ExperimentalMaterial3Api::class) -package io.element.android.libraries.mediaviewer.api.viewer +package io.element.android.libraries.mediaviewer.impl.viewer +import androidx.activity.compose.BackHandler import androidx.compose.animation.AnimatedVisibility import androidx.compose.animation.core.animateFloatAsState import androidx.compose.animation.fadeIn @@ -55,12 +56,12 @@ 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.media.MediaSource import io.element.android.libraries.matrix.ui.media.MediaRequestData -import io.element.android.libraries.mediaviewer.api.R +import io.element.android.libraries.mediaviewer.api.MediaInfo import io.element.android.libraries.mediaviewer.api.local.LocalMedia -import io.element.android.libraries.mediaviewer.api.local.LocalMediaView -import io.element.android.libraries.mediaviewer.api.local.MediaInfo -import io.element.android.libraries.mediaviewer.api.local.PlayableState -import io.element.android.libraries.mediaviewer.api.local.rememberLocalMediaViewState +import io.element.android.libraries.mediaviewer.impl.R +import io.element.android.libraries.mediaviewer.impl.local.LocalMediaView +import io.element.android.libraries.mediaviewer.impl.local.PlayableState +import io.element.android.libraries.mediaviewer.impl.local.rememberLocalMediaViewState import io.element.android.libraries.ui.strings.CommonStrings import kotlinx.coroutines.delay import me.saket.telephoto.flick.FlickToDismiss @@ -79,6 +80,7 @@ fun MediaViewerView( val snackbarHostState = rememberSnackbarHostState(snackbarMessage = state.snackbarMessage) var showOverlay by remember { mutableStateOf(true) } + BackHandler { onBackClick() } Scaffold( modifier, containerColor = Color.Transparent, @@ -146,8 +148,8 @@ private fun MediaViewerPage( Box( modifier = Modifier - .fillMaxSize() - .navigationBarsPadding() + .fillMaxSize() + .navigationBarsPadding() ) { Box(contentAlignment = Alignment.Center) { val zoomableState = rememberZoomableState( @@ -191,8 +193,8 @@ private fun MediaViewerPage( if (showProgress) { LinearProgressIndicator( modifier = Modifier - .fillMaxWidth() - .height(2.dp) + .fillMaxWidth() + .height(2.dp) ) } } diff --git a/libraries/mediaviewer/api/src/main/res/drawable/ic_apk_install.xml b/libraries/mediaviewer/impl/src/main/res/drawable/ic_apk_install.xml similarity index 100% rename from libraries/mediaviewer/api/src/main/res/drawable/ic_apk_install.xml rename to libraries/mediaviewer/impl/src/main/res/drawable/ic_apk_install.xml diff --git a/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/local/AndroidLocalMediaFactoryTest.kt b/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/local/AndroidLocalMediaFactoryTest.kt index eb78517a36a..5729c5310da 100644 --- a/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/local/AndroidLocalMediaFactoryTest.kt +++ b/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/local/AndroidLocalMediaFactoryTest.kt @@ -12,9 +12,9 @@ import io.element.android.libraries.androidutils.filesize.FakeFileSizeFormatter import io.element.android.libraries.core.mimetype.MimeTypes import io.element.android.libraries.matrix.api.media.MediaFile import io.element.android.libraries.matrix.test.media.FakeMediaFile -import io.element.android.libraries.mediaviewer.api.local.MediaInfo -import io.element.android.libraries.mediaviewer.api.local.anImageMediaInfo -import io.element.android.libraries.mediaviewer.api.util.FileExtensionExtractorWithoutValidation +import io.element.android.libraries.mediaviewer.api.MediaInfo +import io.element.android.libraries.mediaviewer.api.anImageMediaInfo +import io.element.android.libraries.mediaviewer.test.util.FileExtensionExtractorWithoutValidation import org.junit.Test import org.junit.runner.RunWith import org.robolectric.RobolectricTestRunner diff --git a/libraries/mediaviewer/api/src/test/kotlin/io/element/android/libraries/mediaviewer/api/util/FileExtensionExtractorTest.kt b/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/util/FileExtensionExtractorTest.kt similarity index 88% rename from libraries/mediaviewer/api/src/test/kotlin/io/element/android/libraries/mediaviewer/api/util/FileExtensionExtractorTest.kt rename to libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/util/FileExtensionExtractorTest.kt index a9ab18ce616..5e9ada9f3a8 100644 --- a/libraries/mediaviewer/api/src/test/kotlin/io/element/android/libraries/mediaviewer/api/util/FileExtensionExtractorTest.kt +++ b/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/util/FileExtensionExtractorTest.kt @@ -5,9 +5,10 @@ * Please see LICENSE in the repository root for full details. */ -package io.element.android.libraries.mediaviewer.api.util +package io.element.android.libraries.mediaviewer.impl.util import com.google.common.truth.Truth.assertThat +import io.element.android.libraries.mediaviewer.test.util.FileExtensionExtractorWithoutValidation import org.junit.Test import org.junit.runner.RunWith import org.robolectric.RobolectricTestRunner diff --git a/libraries/mediaviewer/api/src/test/kotlin/io/element/android/libraries/mediaviewer/MediaViewerPresenterTest.kt b/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerPresenterTest.kt similarity index 94% rename from libraries/mediaviewer/api/src/test/kotlin/io/element/android/libraries/mediaviewer/MediaViewerPresenterTest.kt rename to libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerPresenterTest.kt index a54ccf2cc2f..cbe334216cd 100644 --- a/libraries/mediaviewer/api/src/test/kotlin/io/element/android/libraries/mediaviewer/MediaViewerPresenterTest.kt +++ b/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerPresenterTest.kt @@ -7,7 +7,7 @@ @file:OptIn(ExperimentalCoroutinesApi::class) -package io.element.android.libraries.mediaviewer +package io.element.android.libraries.mediaviewer.impl.viewer import android.net.Uri import app.cash.molecule.RecompositionMode @@ -18,10 +18,8 @@ import io.element.android.libraries.architecture.AsyncData import io.element.android.libraries.designsystem.utils.snackbar.SnackbarDispatcher import io.element.android.libraries.matrix.test.media.FakeMatrixMediaLoader import io.element.android.libraries.matrix.test.media.aMediaSource -import io.element.android.libraries.mediaviewer.api.local.anApkMediaInfo -import io.element.android.libraries.mediaviewer.api.viewer.MediaViewerEvents -import io.element.android.libraries.mediaviewer.api.viewer.MediaViewerNode -import io.element.android.libraries.mediaviewer.api.viewer.MediaViewerPresenter +import io.element.android.libraries.mediaviewer.api.MediaViewerEntryPoint +import io.element.android.libraries.mediaviewer.api.anApkMediaInfo import io.element.android.libraries.mediaviewer.test.FakeLocalMediaActions import io.element.android.libraries.mediaviewer.test.FakeLocalMediaFactory import io.element.android.tests.testutils.WarmUpRule @@ -144,7 +142,7 @@ class MediaViewerPresenterTest { canDownload: Boolean = true, ): MediaViewerPresenter { return MediaViewerPresenter( - inputs = MediaViewerNode.Inputs( + inputs = MediaViewerEntryPoint.Params( mediaInfo = TESTED_MEDIA_INFO, mediaSource = aMediaSource(), thumbnailSource = null, diff --git a/libraries/mediaviewer/api/src/test/kotlin/io/element/android/libraries/mediaviewer/api/viewer/MediaViewerViewTest.kt b/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerViewTest.kt similarity index 97% rename from libraries/mediaviewer/api/src/test/kotlin/io/element/android/libraries/mediaviewer/api/viewer/MediaViewerViewTest.kt rename to libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerViewTest.kt index ee5aef8e2ef..acbfb576190 100644 --- a/libraries/mediaviewer/api/src/test/kotlin/io/element/android/libraries/mediaviewer/api/viewer/MediaViewerViewTest.kt +++ b/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerViewTest.kt @@ -5,7 +5,7 @@ * Please see LICENSE in the repository root for full details. */ -package io.element.android.libraries.mediaviewer.api.viewer +package io.element.android.libraries.mediaviewer.impl.viewer import android.net.Uri import androidx.activity.ComponentActivity @@ -18,8 +18,8 @@ import androidx.compose.ui.test.performTouchInput import androidx.compose.ui.test.swipeDown import androidx.test.ext.junit.runners.AndroidJUnit4 import io.element.android.libraries.architecture.AsyncData +import io.element.android.libraries.mediaviewer.api.anImageMediaInfo import io.element.android.libraries.mediaviewer.api.local.LocalMedia -import io.element.android.libraries.mediaviewer.api.local.anImageMediaInfo import io.element.android.libraries.ui.strings.CommonStrings import io.element.android.tests.testutils.EnsureNeverCalled import io.element.android.tests.testutils.EventsRecorder diff --git a/libraries/mediaviewer/test/src/main/kotlin/io/element/android/libraries/mediaviewer/test/FakeLocalMediaActions.kt b/libraries/mediaviewer/test/src/main/kotlin/io/element/android/libraries/mediaviewer/test/FakeLocalMediaActions.kt index b6437c212b4..c8555e5bce3 100644 --- a/libraries/mediaviewer/test/src/main/kotlin/io/element/android/libraries/mediaviewer/test/FakeLocalMediaActions.kt +++ b/libraries/mediaviewer/test/src/main/kotlin/io/element/android/libraries/mediaviewer/test/FakeLocalMediaActions.kt @@ -9,7 +9,7 @@ package io.element.android.libraries.mediaviewer.test import androidx.compose.runtime.Composable import io.element.android.libraries.mediaviewer.api.local.LocalMedia -import io.element.android.libraries.mediaviewer.api.local.LocalMediaActions +import io.element.android.libraries.mediaviewer.impl.local.LocalMediaActions import io.element.android.tests.testutils.simulateLongTask class FakeLocalMediaActions : LocalMediaActions { diff --git a/libraries/mediaviewer/test/src/main/kotlin/io/element/android/libraries/mediaviewer/test/FakeLocalMediaFactory.kt b/libraries/mediaviewer/test/src/main/kotlin/io/element/android/libraries/mediaviewer/test/FakeLocalMediaFactory.kt index 43474e24bb5..df85f2d53d7 100644 --- a/libraries/mediaviewer/test/src/main/kotlin/io/element/android/libraries/mediaviewer/test/FakeLocalMediaFactory.kt +++ b/libraries/mediaviewer/test/src/main/kotlin/io/element/android/libraries/mediaviewer/test/FakeLocalMediaFactory.kt @@ -10,11 +10,11 @@ package io.element.android.libraries.mediaviewer.test import android.net.Uri import io.element.android.libraries.core.mimetype.MimeTypes import io.element.android.libraries.matrix.api.media.MediaFile +import io.element.android.libraries.mediaviewer.api.MediaInfo import io.element.android.libraries.mediaviewer.api.local.LocalMedia import io.element.android.libraries.mediaviewer.api.local.LocalMediaFactory -import io.element.android.libraries.mediaviewer.api.local.MediaInfo import io.element.android.libraries.mediaviewer.api.util.FileExtensionExtractor -import io.element.android.libraries.mediaviewer.api.util.FileExtensionExtractorWithoutValidation +import io.element.android.libraries.mediaviewer.test.util.FileExtensionExtractorWithoutValidation import io.element.android.libraries.mediaviewer.test.viewer.aLocalMedia class FakeLocalMediaFactory( diff --git a/libraries/mediaviewer/test/src/main/kotlin/io/element/android/libraries/mediaviewer/test/util/FileExtensionExtractorWithoutValidation.kt b/libraries/mediaviewer/test/src/main/kotlin/io/element/android/libraries/mediaviewer/test/util/FileExtensionExtractorWithoutValidation.kt new file mode 100644 index 00000000000..c252c216aac --- /dev/null +++ b/libraries/mediaviewer/test/src/main/kotlin/io/element/android/libraries/mediaviewer/test/util/FileExtensionExtractorWithoutValidation.kt @@ -0,0 +1,16 @@ +/* + * Copyright 2024 New Vector Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only + * Please see LICENSE in the repository root for full details. + */ + +package io.element.android.libraries.mediaviewer.test.util + +import io.element.android.libraries.mediaviewer.api.util.FileExtensionExtractor + +class FileExtensionExtractorWithoutValidation : FileExtensionExtractor { + override fun extractFromName(name: String): String { + return name.substringAfterLast('.', "") + } +} diff --git a/libraries/mediaviewer/test/src/main/kotlin/io/element/android/libraries/mediaviewer/test/viewer/LocalMedia.kt b/libraries/mediaviewer/test/src/main/kotlin/io/element/android/libraries/mediaviewer/test/viewer/LocalMedia.kt index ea2953f69c4..4f933b1c008 100644 --- a/libraries/mediaviewer/test/src/main/kotlin/io/element/android/libraries/mediaviewer/test/viewer/LocalMedia.kt +++ b/libraries/mediaviewer/test/src/main/kotlin/io/element/android/libraries/mediaviewer/test/viewer/LocalMedia.kt @@ -8,9 +8,9 @@ package io.element.android.libraries.mediaviewer.test.viewer import android.net.Uri +import io.element.android.libraries.mediaviewer.api.MediaInfo +import io.element.android.libraries.mediaviewer.api.anImageMediaInfo import io.element.android.libraries.mediaviewer.api.local.LocalMedia -import io.element.android.libraries.mediaviewer.api.local.MediaInfo -import io.element.android.libraries.mediaviewer.api.local.anImageMediaInfo fun aLocalMedia( uri: Uri, From c4a4d726a342814eaaa07a7a16bad5d5207bf59d Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 28 Nov 2024 18:27:18 +0100 Subject: [PATCH 52/96] Extract fun from `LocalMediaView` and move some files. --- .../mediaviewer/impl/local/LocalMediaView.kt | 372 +----------------- .../impl/local/file/MediaFileView.kt | 103 +++++ .../impl/local/image/MediaImageView.kt | 49 +++ .../impl/local/pdf/MediaPdfView.kt | 32 ++ .../{exoplayer => video}/ExoPlayerWrapper.kt | 2 +- .../video}/MediaPlayerControllerState.kt | 2 +- .../MediaPlayerControllerStateProvider.kt | 2 +- .../video}/MediaPlayerControllerView.kt | 2 +- .../impl/local/video/MediaVideoView.kt | 237 +++++++++++ 9 files changed, 430 insertions(+), 371 deletions(-) create mode 100644 libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/file/MediaFileView.kt create mode 100644 libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/image/MediaImageView.kt create mode 100644 libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/pdf/MediaPdfView.kt rename libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/{exoplayer => video}/ExoPlayerWrapper.kt (93%) rename libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/{player => local/video}/MediaPlayerControllerState.kt (83%) rename libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/{player => local/video}/MediaPlayerControllerStateProvider.kt (94%) rename libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/{player => local/video}/MediaPlayerControllerView.kt (98%) create mode 100644 libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/video/MediaVideoView.kt diff --git a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/LocalMediaView.kt b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/LocalMediaView.kt index be48711bf00..44392e27b9a 100644 --- a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/LocalMediaView.kt +++ b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/LocalMediaView.kt @@ -7,79 +7,17 @@ package io.element.android.libraries.mediaviewer.impl.local -import android.annotation.SuppressLint -import android.net.Uri -import android.view.ViewGroup.LayoutParams.MATCH_PARENT -import android.widget.FrameLayout -import androidx.compose.foundation.Image -import androidx.compose.foundation.background -import androidx.compose.foundation.clickable -import androidx.compose.foundation.interaction.MutableInteractionSource -import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.Spacer -import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.height -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.size -import androidx.compose.foundation.layout.wrapContentSize -import androidx.compose.foundation.shape.CircleShape -import androidx.compose.material.icons.Icons -import androidx.compose.material.icons.outlined.GraphicEq -import androidx.compose.material3.MaterialTheme import androidx.compose.runtime.Composable -import androidx.compose.runtime.LaunchedEffect -import androidx.compose.runtime.derivedStateOf -import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableIntStateOf -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember -import androidx.compose.runtime.setValue -import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.draw.clip -import androidx.compose.ui.draw.rotate -import androidx.compose.ui.layout.ContentScale -import androidx.compose.ui.platform.LocalContext -import androidx.compose.ui.platform.LocalInspectionMode -import androidx.compose.ui.res.painterResource -import androidx.compose.ui.res.stringResource -import androidx.compose.ui.text.style.TextAlign -import androidx.compose.ui.text.style.TextOverflow -import androidx.compose.ui.unit.dp -import androidx.compose.ui.viewinterop.AndroidView -import androidx.lifecycle.Lifecycle -import androidx.media3.common.MediaItem -import androidx.media3.common.Player -import androidx.media3.common.Timeline -import androidx.media3.ui.AspectRatioFrameLayout -import androidx.media3.ui.PlayerView -import io.element.android.compound.theme.ElementTheme -import io.element.android.compound.tokens.generated.CompoundIcons -import io.element.android.libraries.core.bool.orFalse import io.element.android.libraries.core.mimetype.MimeTypes -import io.element.android.libraries.core.mimetype.MimeTypes.isMimeTypeAudio import io.element.android.libraries.core.mimetype.MimeTypes.isMimeTypeImage import io.element.android.libraries.core.mimetype.MimeTypes.isMimeTypeVideo -import io.element.android.libraries.designsystem.theme.components.Icon -import io.element.android.libraries.designsystem.theme.components.Text -import io.element.android.libraries.designsystem.utils.CommonDrawables -import io.element.android.libraries.designsystem.utils.KeepScreenOn -import io.element.android.libraries.designsystem.utils.OnLifecycleEvent import io.element.android.libraries.mediaviewer.api.MediaInfo -import io.element.android.libraries.mediaviewer.api.helper.formatFileExtensionAndSize import io.element.android.libraries.mediaviewer.api.local.LocalMedia -import io.element.android.libraries.mediaviewer.impl.local.exoplayer.ExoPlayerWrapper -import io.element.android.libraries.mediaviewer.impl.local.pdf.PdfViewer -import io.element.android.libraries.mediaviewer.impl.local.pdf.rememberPdfViewerState -import io.element.android.libraries.mediaviewer.impl.player.MediaPlayerControllerState -import io.element.android.libraries.mediaviewer.impl.player.MediaPlayerControllerView -import io.element.android.libraries.ui.strings.CommonStrings -import kotlinx.coroutines.delay -import me.saket.telephoto.zoomable.coil.ZoomableAsyncImage -import me.saket.telephoto.zoomable.rememberZoomableImageState -import kotlin.time.Duration.Companion.seconds +import io.element.android.libraries.mediaviewer.impl.local.file.MediaFileView +import io.element.android.libraries.mediaviewer.impl.local.image.MediaImageView +import io.element.android.libraries.mediaviewer.impl.local.pdf.MediaPdfView +import io.element.android.libraries.mediaviewer.impl.local.video.MediaVideoView @Composable fun LocalMediaView( @@ -102,7 +40,7 @@ fun LocalMediaView( localMedia = localMedia, modifier = modifier, ) - mimeType == MimeTypes.Pdf -> MediaPDFView( + mimeType == MimeTypes.Pdf -> MediaPdfView( localMediaViewState = localMediaViewState, localMedia = localMedia, modifier = modifier, @@ -118,303 +56,3 @@ fun LocalMediaView( ) } } - -@Composable -private fun MediaImageView( - localMediaViewState: LocalMediaViewState, - localMedia: LocalMedia?, - onClick: () -> Unit, - modifier: Modifier = Modifier, -) { - if (LocalInspectionMode.current) { - Image( - painter = painterResource(id = CommonDrawables.sample_background), - modifier = modifier, - contentDescription = null, - ) - } else { - val zoomableImageState = rememberZoomableImageState(localMediaViewState.zoomableState) - localMediaViewState.isReady = zoomableImageState.isImageDisplayed - ZoomableAsyncImage( - modifier = modifier, - state = zoomableImageState, - model = localMedia?.uri, - contentDescription = stringResource(id = CommonStrings.common_image), - contentScale = ContentScale.Fit, - onClick = { onClick() } - ) - } -} - -@Composable -private fun MediaVideoView( - localMediaViewState: LocalMediaViewState, - localMedia: LocalMedia?, - modifier: Modifier = Modifier, -) { - if (LocalInspectionMode.current) { - Text( - modifier = modifier - .background(ElementTheme.colors.bgSubtlePrimary) - .wrapContentSize(), - text = "A Video Player will render here", - ) - } else { - ExoPlayerMediaVideoView( - localMediaViewState = localMediaViewState, - localMedia = localMedia, - modifier = modifier, - ) - } -} - -@SuppressLint("UnsafeOptInUsageError") -@Composable -private fun ExoPlayerMediaVideoView( - localMediaViewState: LocalMediaViewState, - localMedia: LocalMedia?, - modifier: Modifier = Modifier, -) { - var mediaPlayerControllerState: MediaPlayerControllerState by remember { - mutableStateOf( - MediaPlayerControllerState( - isVisible = false, - isPlaying = false, - progressInMillis = 0, - durationInMillis = 0, - isMuted = false, - ) - ) - } - - val playableState: PlayableState.Playable by remember { - derivedStateOf { - PlayableState.Playable( - isShowingControls = mediaPlayerControllerState.isVisible, - ) - } - } - - localMediaViewState.playableState = playableState - - val context = LocalContext.current - val exoPlayer = remember { - ExoPlayerWrapper.create(context) - } - val playerListener = object : Player.Listener { - override fun onRenderedFirstFrame() { - localMediaViewState.isReady = true - } - - override fun onIsPlayingChanged(isPlaying: Boolean) { - mediaPlayerControllerState = mediaPlayerControllerState.copy( - isPlaying = isPlaying, - ) - } - - override fun onVolumeChanged(volume: Float) { - mediaPlayerControllerState = mediaPlayerControllerState.copy( - isMuted = volume == 0f, - ) - } - - override fun onTimelineChanged(timeline: Timeline, reason: Int) { - if (reason == Player.TIMELINE_CHANGE_REASON_SOURCE_UPDATE) { - mediaPlayerControllerState = mediaPlayerControllerState.copy( - durationInMillis = exoPlayer.duration, - ) - } - } - } - - LaunchedEffect(Unit) { - exoPlayer.addListener(playerListener) - exoPlayer.prepare() - } - - var autoHideController by remember { mutableIntStateOf(0) } - - LaunchedEffect(autoHideController) { - delay(5.seconds) - if (exoPlayer.isPlaying) { - mediaPlayerControllerState = mediaPlayerControllerState.copy( - isVisible = false, - ) - } - } - - LaunchedEffect(exoPlayer.isPlaying) { - if (exoPlayer.isPlaying) { - while (true) { - mediaPlayerControllerState = mediaPlayerControllerState.copy( - progressInMillis = exoPlayer.currentPosition, - ) - delay(200) - } - } else { - // Ensure we render the final state - mediaPlayerControllerState = mediaPlayerControllerState.copy( - progressInMillis = exoPlayer.currentPosition, - ) - } - } - if (localMedia?.uri != null) { - LaunchedEffect(localMedia.uri) { - val mediaItem = MediaItem.fromUri(localMedia.uri) - exoPlayer.setMediaItem(mediaItem) - } - } else { - exoPlayer.setMediaItems(emptyList()) - } - KeepScreenOn(mediaPlayerControllerState.isPlaying) - Box( - modifier = modifier - .background(ElementTheme.colors.bgSubtlePrimary) - .wrapContentSize(), - ) { - AndroidView( - modifier = Modifier.fillMaxSize(), - factory = { - PlayerView(context).apply { - player = exoPlayer - resizeMode = AspectRatioFrameLayout.RESIZE_MODE_FIT - layoutParams = FrameLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT) - setOnClickListener { - autoHideController++ - mediaPlayerControllerState = mediaPlayerControllerState.copy( - isVisible = !mediaPlayerControllerState.isVisible, - ) - } - useController = false - } - }, - onRelease = { playerView -> - playerView.setOnClickListener(null) - playerView.setControllerVisibilityListener(null as PlayerView.ControllerVisibilityListener?) - playerView.player = null - }, - ) - MediaPlayerControllerView( - state = mediaPlayerControllerState, - onTogglePlay = { - autoHideController++ - if (exoPlayer.isPlaying) { - exoPlayer.pause() - } else { - if (exoPlayer.playbackState == Player.STATE_ENDED) { - exoPlayer.seekTo(0) - } else { - exoPlayer.play() - } - } - }, - onSeekChange = { - autoHideController++ - if (exoPlayer.isPlaying.not()) { - exoPlayer.play() - } - exoPlayer.seekTo(it.toLong()) - }, - onToggleMute = { - autoHideController++ - exoPlayer.volume = if (exoPlayer.volume == 1f) 0f else 1f - }, - modifier = Modifier - .fillMaxWidth() - .align(Alignment.BottomCenter), - ) - } - - OnLifecycleEvent { _, event -> - when (event) { - Lifecycle.Event.ON_RESUME -> exoPlayer.play() - Lifecycle.Event.ON_PAUSE -> exoPlayer.pause() - Lifecycle.Event.ON_DESTROY -> { - exoPlayer.release() - exoPlayer.removeListener(playerListener) - } - else -> Unit - } - } -} - -@Composable -private fun MediaPDFView( - localMediaViewState: LocalMediaViewState, - localMedia: LocalMedia?, - onClick: () -> Unit, - modifier: Modifier = Modifier, -) { - val pdfViewerState = rememberPdfViewerState( - model = localMedia?.uri, - zoomableState = localMediaViewState.zoomableState, - ) - localMediaViewState.isReady = pdfViewerState.isLoaded - PdfViewer( - pdfViewerState = pdfViewerState, - onClick = onClick, - modifier = modifier, - ) -} - -@Composable -private fun MediaFileView( - localMediaViewState: LocalMediaViewState, - uri: Uri?, - info: MediaInfo?, - onClick: () -> Unit, - modifier: Modifier = Modifier, -) { - val isAudio = info?.mimeType.isMimeTypeAudio().orFalse() - localMediaViewState.isReady = uri != null - - val interactionSource = remember { MutableInteractionSource() } - Box( - modifier = modifier - .padding(horizontal = 8.dp) - .clickable( - onClick = onClick, - interactionSource = interactionSource, - indication = null - ), - contentAlignment = Alignment.Center - ) { - Column(horizontalAlignment = Alignment.CenterHorizontally) { - Box( - modifier = Modifier - .size(72.dp) - .clip(CircleShape) - .background(MaterialTheme.colorScheme.onBackground), - contentAlignment = Alignment.Center, - ) { - Icon( - imageVector = if (isAudio) Icons.Outlined.GraphicEq else CompoundIcons.Attachment(), - contentDescription = null, - tint = MaterialTheme.colorScheme.background, - modifier = Modifier - .size(32.dp) - .rotate(if (isAudio) 0f else -45f), - ) - } - if (info != null) { - Spacer(modifier = Modifier.height(20.dp)) - Text( - text = info.filename, - maxLines = 2, - style = ElementTheme.typography.fontBodyLgRegular, - overflow = TextOverflow.Ellipsis, - textAlign = TextAlign.Center, - color = MaterialTheme.colorScheme.primary - ) - Spacer(modifier = Modifier.height(4.dp)) - Text( - text = formatFileExtensionAndSize(info.fileExtension, info.formattedFileSize), - style = ElementTheme.typography.fontBodyMdRegular, - maxLines = 1, - overflow = TextOverflow.Ellipsis, - color = MaterialTheme.colorScheme.primary - ) - } - } - } -} diff --git a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/file/MediaFileView.kt b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/file/MediaFileView.kt new file mode 100644 index 00000000000..f0663a5d23a --- /dev/null +++ b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/file/MediaFileView.kt @@ -0,0 +1,103 @@ +/* + * Copyright 2024 New Vector Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only + * Please see LICENSE in the repository root for full details. + */ + +package io.element.android.libraries.mediaviewer.impl.local.file + +import android.net.Uri +import androidx.compose.foundation.background +import androidx.compose.foundation.clickable +import androidx.compose.foundation.interaction.MutableInteractionSource +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.shape.CircleShape +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.outlined.GraphicEq +import androidx.compose.material3.MaterialTheme +import androidx.compose.runtime.Composable +import androidx.compose.runtime.remember +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.draw.rotate +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.text.style.TextOverflow +import androidx.compose.ui.unit.dp +import io.element.android.compound.theme.ElementTheme +import io.element.android.compound.tokens.generated.CompoundIcons +import io.element.android.libraries.core.bool.orFalse +import io.element.android.libraries.core.mimetype.MimeTypes.isMimeTypeAudio +import io.element.android.libraries.designsystem.theme.components.Icon +import io.element.android.libraries.designsystem.theme.components.Text +import io.element.android.libraries.mediaviewer.api.MediaInfo +import io.element.android.libraries.mediaviewer.api.helper.formatFileExtensionAndSize +import io.element.android.libraries.mediaviewer.impl.local.LocalMediaViewState + +@Composable +fun MediaFileView( + localMediaViewState: LocalMediaViewState, + uri: Uri?, + info: MediaInfo?, + onClick: () -> Unit, + modifier: Modifier = Modifier, +) { + val isAudio = info?.mimeType.isMimeTypeAudio().orFalse() + localMediaViewState.isReady = uri != null + + val interactionSource = remember { MutableInteractionSource() } + Box( + modifier = modifier + .padding(horizontal = 8.dp) + .clickable( + onClick = onClick, + interactionSource = interactionSource, + indication = null + ), + contentAlignment = Alignment.Center + ) { + Column(horizontalAlignment = Alignment.CenterHorizontally) { + Box( + modifier = Modifier + .size(72.dp) + .clip(CircleShape) + .background(MaterialTheme.colorScheme.onBackground), + contentAlignment = Alignment.Center, + ) { + Icon( + imageVector = if (isAudio) Icons.Outlined.GraphicEq else CompoundIcons.Attachment(), + contentDescription = null, + tint = MaterialTheme.colorScheme.background, + modifier = Modifier + .size(32.dp) + .rotate(if (isAudio) 0f else -45f), + ) + } + if (info != null) { + Spacer(modifier = Modifier.height(20.dp)) + Text( + text = info.filename, + maxLines = 2, + style = ElementTheme.typography.fontBodyLgRegular, + overflow = TextOverflow.Ellipsis, + textAlign = TextAlign.Center, + color = MaterialTheme.colorScheme.primary + ) + Spacer(modifier = Modifier.height(4.dp)) + Text( + text = formatFileExtensionAndSize(info.fileExtension, info.formattedFileSize), + style = ElementTheme.typography.fontBodyMdRegular, + maxLines = 1, + overflow = TextOverflow.Ellipsis, + color = MaterialTheme.colorScheme.primary + ) + } + } + } +} diff --git a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/image/MediaImageView.kt b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/image/MediaImageView.kt new file mode 100644 index 00000000000..c5792a9828b --- /dev/null +++ b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/image/MediaImageView.kt @@ -0,0 +1,49 @@ +/* + * Copyright 2024 New Vector Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only + * Please see LICENSE in the repository root for full details. + */ + +package io.element.android.libraries.mediaviewer.impl.local.image + +import androidx.compose.foundation.Image +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.layout.ContentScale +import androidx.compose.ui.platform.LocalInspectionMode +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.res.stringResource +import io.element.android.libraries.designsystem.utils.CommonDrawables +import io.element.android.libraries.mediaviewer.api.local.LocalMedia +import io.element.android.libraries.mediaviewer.impl.local.LocalMediaViewState +import io.element.android.libraries.ui.strings.CommonStrings +import me.saket.telephoto.zoomable.coil.ZoomableAsyncImage +import me.saket.telephoto.zoomable.rememberZoomableImageState + +@Composable +fun MediaImageView( + localMediaViewState: LocalMediaViewState, + localMedia: LocalMedia?, + onClick: () -> Unit, + modifier: Modifier = Modifier, +) { + if (LocalInspectionMode.current) { + Image( + painter = painterResource(id = CommonDrawables.sample_background), + modifier = modifier, + contentDescription = null, + ) + } else { + val zoomableImageState = rememberZoomableImageState(localMediaViewState.zoomableState) + localMediaViewState.isReady = zoomableImageState.isImageDisplayed + ZoomableAsyncImage( + modifier = modifier, + state = zoomableImageState, + model = localMedia?.uri, + contentDescription = stringResource(id = CommonStrings.common_image), + contentScale = ContentScale.Fit, + onClick = { onClick() } + ) + } +} diff --git a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/pdf/MediaPdfView.kt b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/pdf/MediaPdfView.kt new file mode 100644 index 00000000000..f2694fb2775 --- /dev/null +++ b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/pdf/MediaPdfView.kt @@ -0,0 +1,32 @@ +/* + * Copyright 2024 New Vector Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only + * Please see LICENSE in the repository root for full details. + */ + +package io.element.android.libraries.mediaviewer.impl.local.pdf + +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import io.element.android.libraries.mediaviewer.api.local.LocalMedia +import io.element.android.libraries.mediaviewer.impl.local.LocalMediaViewState + +@Composable +fun MediaPdfView( + localMediaViewState: LocalMediaViewState, + localMedia: LocalMedia?, + onClick: () -> Unit, + modifier: Modifier = Modifier, +) { + val pdfViewerState = rememberPdfViewerState( + model = localMedia?.uri, + zoomableState = localMediaViewState.zoomableState, + ) + localMediaViewState.isReady = pdfViewerState.isLoaded + PdfViewer( + pdfViewerState = pdfViewerState, + onClick = onClick, + modifier = modifier, + ) +} diff --git a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/exoplayer/ExoPlayerWrapper.kt b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/video/ExoPlayerWrapper.kt similarity index 93% rename from libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/exoplayer/ExoPlayerWrapper.kt rename to libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/video/ExoPlayerWrapper.kt index 41d59b395ba..fef307c155a 100644 --- a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/exoplayer/ExoPlayerWrapper.kt +++ b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/video/ExoPlayerWrapper.kt @@ -5,7 +5,7 @@ * Please see LICENSE in the repository root for full details. */ -package io.element.android.libraries.mediaviewer.impl.local.exoplayer +package io.element.android.libraries.mediaviewer.impl.local.video import android.content.Context import androidx.media3.common.Player diff --git a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/player/MediaPlayerControllerState.kt b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/video/MediaPlayerControllerState.kt similarity index 83% rename from libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/player/MediaPlayerControllerState.kt rename to libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/video/MediaPlayerControllerState.kt index d922483ff1f..c4e4b913a72 100644 --- a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/player/MediaPlayerControllerState.kt +++ b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/video/MediaPlayerControllerState.kt @@ -5,7 +5,7 @@ * Please see LICENSE in the repository root for full details. */ -package io.element.android.libraries.mediaviewer.impl.player +package io.element.android.libraries.mediaviewer.impl.local.video data class MediaPlayerControllerState( val isVisible: Boolean, diff --git a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/player/MediaPlayerControllerStateProvider.kt b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/video/MediaPlayerControllerStateProvider.kt similarity index 94% rename from libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/player/MediaPlayerControllerStateProvider.kt rename to libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/video/MediaPlayerControllerStateProvider.kt index 6aa93547f60..78059bd4eb7 100644 --- a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/player/MediaPlayerControllerStateProvider.kt +++ b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/video/MediaPlayerControllerStateProvider.kt @@ -5,7 +5,7 @@ * Please see LICENSE in the repository root for full details. */ -package io.element.android.libraries.mediaviewer.impl.player +package io.element.android.libraries.mediaviewer.impl.local.video import androidx.compose.ui.tooling.preview.PreviewParameterProvider diff --git a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/player/MediaPlayerControllerView.kt b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/video/MediaPlayerControllerView.kt similarity index 98% rename from libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/player/MediaPlayerControllerView.kt rename to libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/video/MediaPlayerControllerView.kt index c9f548aab25..9cee07728f1 100644 --- a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/player/MediaPlayerControllerView.kt +++ b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/video/MediaPlayerControllerView.kt @@ -5,7 +5,7 @@ * Please see LICENSE in the repository root for full details. */ -package io.element.android.libraries.mediaviewer.impl.player +package io.element.android.libraries.mediaviewer.impl.local.video import androidx.compose.animation.AnimatedVisibility import androidx.compose.animation.fadeIn diff --git a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/video/MediaVideoView.kt b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/video/MediaVideoView.kt new file mode 100644 index 00000000000..7c7d798e93a --- /dev/null +++ b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/video/MediaVideoView.kt @@ -0,0 +1,237 @@ +/* + * Copyright 2024 New Vector Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only + * Please see LICENSE in the repository root for full details. + */ + +package io.element.android.libraries.mediaviewer.impl.local.video + +import android.annotation.SuppressLint +import android.view.ViewGroup.LayoutParams.MATCH_PARENT +import android.widget.FrameLayout +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.wrapContentSize +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.derivedStateOf +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableIntStateOf +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.platform.LocalInspectionMode +import androidx.compose.ui.viewinterop.AndroidView +import androidx.lifecycle.Lifecycle +import androidx.media3.common.MediaItem +import androidx.media3.common.Player +import androidx.media3.common.Timeline +import androidx.media3.ui.AspectRatioFrameLayout +import androidx.media3.ui.PlayerView +import io.element.android.compound.theme.ElementTheme +import io.element.android.libraries.designsystem.theme.components.Text +import io.element.android.libraries.designsystem.utils.KeepScreenOn +import io.element.android.libraries.designsystem.utils.OnLifecycleEvent +import io.element.android.libraries.mediaviewer.api.local.LocalMedia +import io.element.android.libraries.mediaviewer.impl.local.LocalMediaViewState +import io.element.android.libraries.mediaviewer.impl.local.PlayableState +import kotlinx.coroutines.delay +import kotlin.time.Duration.Companion.seconds + +@Composable +fun MediaVideoView( + localMediaViewState: LocalMediaViewState, + localMedia: LocalMedia?, + modifier: Modifier = Modifier, +) { + if (LocalInspectionMode.current) { + Text( + modifier = modifier + .background(ElementTheme.colors.bgSubtlePrimary) + .wrapContentSize(), + text = "A Video Player will render here", + ) + } else { + ExoPlayerMediaVideoView( + localMediaViewState = localMediaViewState, + localMedia = localMedia, + modifier = modifier, + ) + } +} + +@SuppressLint("UnsafeOptInUsageError") +@Composable +private fun ExoPlayerMediaVideoView( + localMediaViewState: LocalMediaViewState, + localMedia: LocalMedia?, + modifier: Modifier = Modifier, +) { + var mediaPlayerControllerState: MediaPlayerControllerState by remember { + mutableStateOf( + MediaPlayerControllerState( + isVisible = false, + isPlaying = false, + progressInMillis = 0, + durationInMillis = 0, + isMuted = false, + ) + ) + } + + val playableState: PlayableState.Playable by remember { + derivedStateOf { + PlayableState.Playable( + isShowingControls = mediaPlayerControllerState.isVisible, + ) + } + } + + localMediaViewState.playableState = playableState + + val context = LocalContext.current + val exoPlayer = remember { + ExoPlayerWrapper.create(context) + } + val playerListener = object : Player.Listener { + override fun onRenderedFirstFrame() { + localMediaViewState.isReady = true + } + + override fun onIsPlayingChanged(isPlaying: Boolean) { + mediaPlayerControllerState = mediaPlayerControllerState.copy( + isPlaying = isPlaying, + ) + } + + override fun onVolumeChanged(volume: Float) { + mediaPlayerControllerState = mediaPlayerControllerState.copy( + isMuted = volume == 0f, + ) + } + + override fun onTimelineChanged(timeline: Timeline, reason: Int) { + if (reason == Player.TIMELINE_CHANGE_REASON_SOURCE_UPDATE) { + mediaPlayerControllerState = mediaPlayerControllerState.copy( + durationInMillis = exoPlayer.duration, + ) + } + } + } + + LaunchedEffect(Unit) { + exoPlayer.addListener(playerListener) + exoPlayer.prepare() + } + + var autoHideController by remember { mutableIntStateOf(0) } + + LaunchedEffect(autoHideController) { + delay(5.seconds) + if (exoPlayer.isPlaying) { + mediaPlayerControllerState = mediaPlayerControllerState.copy( + isVisible = false, + ) + } + } + + LaunchedEffect(exoPlayer.isPlaying) { + if (exoPlayer.isPlaying) { + while (true) { + mediaPlayerControllerState = mediaPlayerControllerState.copy( + progressInMillis = exoPlayer.currentPosition, + ) + delay(200) + } + } else { + // Ensure we render the final state + mediaPlayerControllerState = mediaPlayerControllerState.copy( + progressInMillis = exoPlayer.currentPosition, + ) + } + } + if (localMedia?.uri != null) { + LaunchedEffect(localMedia.uri) { + val mediaItem = MediaItem.fromUri(localMedia.uri) + exoPlayer.setMediaItem(mediaItem) + } + } else { + exoPlayer.setMediaItems(emptyList()) + } + KeepScreenOn(mediaPlayerControllerState.isPlaying) + Box( + modifier = modifier + .background(ElementTheme.colors.bgSubtlePrimary) + .wrapContentSize(), + ) { + AndroidView( + modifier = Modifier.fillMaxSize(), + factory = { + PlayerView(context).apply { + player = exoPlayer + resizeMode = AspectRatioFrameLayout.RESIZE_MODE_FIT + layoutParams = FrameLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT) + setOnClickListener { + autoHideController++ + mediaPlayerControllerState = mediaPlayerControllerState.copy( + isVisible = !mediaPlayerControllerState.isVisible, + ) + } + useController = false + } + }, + onRelease = { playerView -> + playerView.setOnClickListener(null) + playerView.setControllerVisibilityListener(null as PlayerView.ControllerVisibilityListener?) + playerView.player = null + }, + ) + MediaPlayerControllerView( + state = mediaPlayerControllerState, + onTogglePlay = { + autoHideController++ + if (exoPlayer.isPlaying) { + exoPlayer.pause() + } else { + if (exoPlayer.playbackState == Player.STATE_ENDED) { + exoPlayer.seekTo(0) + } else { + exoPlayer.play() + } + } + }, + onSeekChange = { + autoHideController++ + if (exoPlayer.isPlaying.not()) { + exoPlayer.play() + } + exoPlayer.seekTo(it.toLong()) + }, + onToggleMute = { + autoHideController++ + exoPlayer.volume = if (exoPlayer.volume == 1f) 0f else 1f + }, + modifier = Modifier + .fillMaxWidth() + .align(Alignment.BottomCenter), + ) + } + + OnLifecycleEvent { _, event -> + when (event) { + Lifecycle.Event.ON_RESUME -> exoPlayer.play() + Lifecycle.Event.ON_PAUSE -> exoPlayer.pause() + Lifecycle.Event.ON_DESTROY -> { + exoPlayer.release() + exoPlayer.removeListener(playerListener) + } + else -> Unit + } + } +} From 8f0be319ac0da99da8d968d4002466c973bc9e72 Mon Sep 17 00:00:00 2001 From: ElementBot Date: Fri, 29 Nov 2024 08:44:21 +0000 Subject: [PATCH 53/96] Update screenshots --- ...messages.impl.attachments.preview_AttachmentsView_1_en.png | 4 ++-- ...messages.impl.attachments.preview_AttachmentsView_2_en.png | 4 ++-- ...messages.impl.attachments.preview_AttachmentsView_3_en.png | 4 ++-- ...messages.impl.attachments.preview_AttachmentsView_4_en.png | 4 ++-- ...messages.impl.attachments.preview_AttachmentsView_5_en.png | 3 --- ...messages.impl.attachments.preview_AttachmentsView_6_en.png | 3 --- ...messages.impl.attachments.preview_AttachmentsView_7_en.png | 3 --- ...mediaviewer.impl.local.pdf_PdfPagesErrorView_Day_0_en.png} | 0 ...diaviewer.impl.local.pdf_PdfPagesErrorView_Night_0_en.png} | 0 ...r.impl.local.video_MediaPlayerControllerView_Day_0_en.png} | 0 ...r.impl.local.video_MediaPlayerControllerView_Day_1_en.png} | 0 ...impl.local.video_MediaPlayerControllerView_Night_0_en.png} | 0 ...impl.local.video_MediaPlayerControllerView_Night_1_en.png} | 0 ...ibraries.mediaviewer.impl.viewer_MediaViewerView_0_en.png} | 0 ...braries.mediaviewer.impl.viewer_MediaViewerView_10_en.png} | 0 ...ibraries.mediaviewer.impl.viewer_MediaViewerView_1_en.png} | 0 ...ibraries.mediaviewer.impl.viewer_MediaViewerView_2_en.png} | 0 ...ibraries.mediaviewer.impl.viewer_MediaViewerView_3_en.png} | 0 ...ibraries.mediaviewer.impl.viewer_MediaViewerView_4_en.png} | 0 ...ibraries.mediaviewer.impl.viewer_MediaViewerView_5_en.png} | 0 ...ibraries.mediaviewer.impl.viewer_MediaViewerView_6_en.png} | 0 ...ibraries.mediaviewer.impl.viewer_MediaViewerView_7_en.png} | 0 ...ibraries.mediaviewer.impl.viewer_MediaViewerView_8_en.png} | 0 ...ibraries.mediaviewer.impl.viewer_MediaViewerView_9_en.png} | 0 24 files changed, 8 insertions(+), 17 deletions(-) delete mode 100644 tests/uitests/src/test/snapshots/images/features.messages.impl.attachments.preview_AttachmentsView_5_en.png delete mode 100644 tests/uitests/src/test/snapshots/images/features.messages.impl.attachments.preview_AttachmentsView_6_en.png delete mode 100644 tests/uitests/src/test/snapshots/images/features.messages.impl.attachments.preview_AttachmentsView_7_en.png rename tests/uitests/src/test/snapshots/images/{libraries.mediaviewer.api.local.pdf_PdfPagesErrorView_Day_0_en.png => libraries.mediaviewer.impl.local.pdf_PdfPagesErrorView_Day_0_en.png} (100%) rename tests/uitests/src/test/snapshots/images/{libraries.mediaviewer.api.local.pdf_PdfPagesErrorView_Night_0_en.png => libraries.mediaviewer.impl.local.pdf_PdfPagesErrorView_Night_0_en.png} (100%) rename tests/uitests/src/test/snapshots/images/{libraries.mediaviewer.api.player_MediaPlayerControllerView_Day_0_en.png => libraries.mediaviewer.impl.local.video_MediaPlayerControllerView_Day_0_en.png} (100%) rename tests/uitests/src/test/snapshots/images/{libraries.mediaviewer.api.player_MediaPlayerControllerView_Day_1_en.png => libraries.mediaviewer.impl.local.video_MediaPlayerControllerView_Day_1_en.png} (100%) rename tests/uitests/src/test/snapshots/images/{libraries.mediaviewer.api.player_MediaPlayerControllerView_Night_0_en.png => libraries.mediaviewer.impl.local.video_MediaPlayerControllerView_Night_0_en.png} (100%) rename tests/uitests/src/test/snapshots/images/{libraries.mediaviewer.api.player_MediaPlayerControllerView_Night_1_en.png => libraries.mediaviewer.impl.local.video_MediaPlayerControllerView_Night_1_en.png} (100%) rename tests/uitests/src/test/snapshots/images/{libraries.mediaviewer.api.viewer_MediaViewerView_0_en.png => libraries.mediaviewer.impl.viewer_MediaViewerView_0_en.png} (100%) rename tests/uitests/src/test/snapshots/images/{libraries.mediaviewer.api.viewer_MediaViewerView_10_en.png => libraries.mediaviewer.impl.viewer_MediaViewerView_10_en.png} (100%) rename tests/uitests/src/test/snapshots/images/{libraries.mediaviewer.api.viewer_MediaViewerView_1_en.png => libraries.mediaviewer.impl.viewer_MediaViewerView_1_en.png} (100%) rename tests/uitests/src/test/snapshots/images/{libraries.mediaviewer.api.viewer_MediaViewerView_2_en.png => libraries.mediaviewer.impl.viewer_MediaViewerView_2_en.png} (100%) rename tests/uitests/src/test/snapshots/images/{libraries.mediaviewer.api.viewer_MediaViewerView_3_en.png => libraries.mediaviewer.impl.viewer_MediaViewerView_3_en.png} (100%) rename tests/uitests/src/test/snapshots/images/{libraries.mediaviewer.api.viewer_MediaViewerView_4_en.png => libraries.mediaviewer.impl.viewer_MediaViewerView_4_en.png} (100%) rename tests/uitests/src/test/snapshots/images/{libraries.mediaviewer.api.viewer_MediaViewerView_5_en.png => libraries.mediaviewer.impl.viewer_MediaViewerView_5_en.png} (100%) rename tests/uitests/src/test/snapshots/images/{libraries.mediaviewer.api.viewer_MediaViewerView_6_en.png => libraries.mediaviewer.impl.viewer_MediaViewerView_6_en.png} (100%) rename tests/uitests/src/test/snapshots/images/{libraries.mediaviewer.api.viewer_MediaViewerView_7_en.png => libraries.mediaviewer.impl.viewer_MediaViewerView_7_en.png} (100%) rename tests/uitests/src/test/snapshots/images/{libraries.mediaviewer.api.viewer_MediaViewerView_8_en.png => libraries.mediaviewer.impl.viewer_MediaViewerView_8_en.png} (100%) rename tests/uitests/src/test/snapshots/images/{libraries.mediaviewer.api.viewer_MediaViewerView_9_en.png => libraries.mediaviewer.impl.viewer_MediaViewerView_9_en.png} (100%) diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.attachments.preview_AttachmentsView_1_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.attachments.preview_AttachmentsView_1_en.png index 3982a58c4ca..8510d977be9 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.attachments.preview_AttachmentsView_1_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.attachments.preview_AttachmentsView_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:d18f7e2c169f7e4b9e435584d868454ae5f765a32d29bbbfe48d65b45f4161d6 -size 18845 +oid sha256:3a92cb782d97553f364fab3df3fe159557a26aad8b7e5c176b40616c2f05abdd +size 51410 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.attachments.preview_AttachmentsView_2_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.attachments.preview_AttachmentsView_2_en.png index 2cb5dc89f83..e799726c52b 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.attachments.preview_AttachmentsView_2_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.attachments.preview_AttachmentsView_2_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:3250fa9767aec264308719c6fdf6cea94d5ccea21bfa8a735d7df5d79b572555 -size 21214 +oid sha256:361ff23fd2ff99aecfdffd10b45e9235d86183d4856cb2a3e99f85b9e04c2d59 +size 51376 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.attachments.preview_AttachmentsView_3_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.attachments.preview_AttachmentsView_3_en.png index e34eb6e69c0..df965394aa5 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.attachments.preview_AttachmentsView_3_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.attachments.preview_AttachmentsView_3_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:4ba70221a149ce0f8abaa4e4f870011bea82630edf99ecacea560a737f56346f -size 22215 +oid sha256:efbfed755b29293009f45fca33f58863b612772de9a1d55593c979dbb04ff6f2 +size 88981 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.attachments.preview_AttachmentsView_4_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.attachments.preview_AttachmentsView_4_en.png index 8510d977be9..6920a089ef4 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.attachments.preview_AttachmentsView_4_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.attachments.preview_AttachmentsView_4_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:3a92cb782d97553f364fab3df3fe159557a26aad8b7e5c176b40616c2f05abdd -size 51410 +oid sha256:507c7dffae1aabfa687174f1f964e2c40b004183b6bc3a70b56d764e0d308b47 +size 392923 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.attachments.preview_AttachmentsView_5_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.attachments.preview_AttachmentsView_5_en.png deleted file mode 100644 index e799726c52b..00000000000 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.attachments.preview_AttachmentsView_5_en.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:361ff23fd2ff99aecfdffd10b45e9235d86183d4856cb2a3e99f85b9e04c2d59 -size 51376 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.attachments.preview_AttachmentsView_6_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.attachments.preview_AttachmentsView_6_en.png deleted file mode 100644 index df965394aa5..00000000000 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.attachments.preview_AttachmentsView_6_en.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:efbfed755b29293009f45fca33f58863b612772de9a1d55593c979dbb04ff6f2 -size 88981 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.attachments.preview_AttachmentsView_7_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.attachments.preview_AttachmentsView_7_en.png deleted file mode 100644 index 6920a089ef4..00000000000 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.attachments.preview_AttachmentsView_7_en.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:507c7dffae1aabfa687174f1f964e2c40b004183b6bc3a70b56d764e0d308b47 -size 392923 diff --git a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.api.local.pdf_PdfPagesErrorView_Day_0_en.png b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.local.pdf_PdfPagesErrorView_Day_0_en.png similarity index 100% rename from tests/uitests/src/test/snapshots/images/libraries.mediaviewer.api.local.pdf_PdfPagesErrorView_Day_0_en.png rename to tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.local.pdf_PdfPagesErrorView_Day_0_en.png diff --git a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.api.local.pdf_PdfPagesErrorView_Night_0_en.png b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.local.pdf_PdfPagesErrorView_Night_0_en.png similarity index 100% rename from tests/uitests/src/test/snapshots/images/libraries.mediaviewer.api.local.pdf_PdfPagesErrorView_Night_0_en.png rename to tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.local.pdf_PdfPagesErrorView_Night_0_en.png diff --git a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.api.player_MediaPlayerControllerView_Day_0_en.png b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.local.video_MediaPlayerControllerView_Day_0_en.png similarity index 100% rename from tests/uitests/src/test/snapshots/images/libraries.mediaviewer.api.player_MediaPlayerControllerView_Day_0_en.png rename to tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.local.video_MediaPlayerControllerView_Day_0_en.png diff --git a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.api.player_MediaPlayerControllerView_Day_1_en.png b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.local.video_MediaPlayerControllerView_Day_1_en.png similarity index 100% rename from tests/uitests/src/test/snapshots/images/libraries.mediaviewer.api.player_MediaPlayerControllerView_Day_1_en.png rename to tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.local.video_MediaPlayerControllerView_Day_1_en.png diff --git a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.api.player_MediaPlayerControllerView_Night_0_en.png b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.local.video_MediaPlayerControllerView_Night_0_en.png similarity index 100% rename from tests/uitests/src/test/snapshots/images/libraries.mediaviewer.api.player_MediaPlayerControllerView_Night_0_en.png rename to tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.local.video_MediaPlayerControllerView_Night_0_en.png diff --git a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.api.player_MediaPlayerControllerView_Night_1_en.png b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.local.video_MediaPlayerControllerView_Night_1_en.png similarity index 100% rename from tests/uitests/src/test/snapshots/images/libraries.mediaviewer.api.player_MediaPlayerControllerView_Night_1_en.png rename to tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.local.video_MediaPlayerControllerView_Night_1_en.png diff --git a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.api.viewer_MediaViewerView_0_en.png b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.viewer_MediaViewerView_0_en.png similarity index 100% rename from tests/uitests/src/test/snapshots/images/libraries.mediaviewer.api.viewer_MediaViewerView_0_en.png rename to tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.viewer_MediaViewerView_0_en.png diff --git a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.api.viewer_MediaViewerView_10_en.png b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.viewer_MediaViewerView_10_en.png similarity index 100% rename from tests/uitests/src/test/snapshots/images/libraries.mediaviewer.api.viewer_MediaViewerView_10_en.png rename to tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.viewer_MediaViewerView_10_en.png diff --git a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.api.viewer_MediaViewerView_1_en.png b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.viewer_MediaViewerView_1_en.png similarity index 100% rename from tests/uitests/src/test/snapshots/images/libraries.mediaviewer.api.viewer_MediaViewerView_1_en.png rename to tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.viewer_MediaViewerView_1_en.png diff --git a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.api.viewer_MediaViewerView_2_en.png b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.viewer_MediaViewerView_2_en.png similarity index 100% rename from tests/uitests/src/test/snapshots/images/libraries.mediaviewer.api.viewer_MediaViewerView_2_en.png rename to tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.viewer_MediaViewerView_2_en.png diff --git a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.api.viewer_MediaViewerView_3_en.png b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.viewer_MediaViewerView_3_en.png similarity index 100% rename from tests/uitests/src/test/snapshots/images/libraries.mediaviewer.api.viewer_MediaViewerView_3_en.png rename to tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.viewer_MediaViewerView_3_en.png diff --git a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.api.viewer_MediaViewerView_4_en.png b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.viewer_MediaViewerView_4_en.png similarity index 100% rename from tests/uitests/src/test/snapshots/images/libraries.mediaviewer.api.viewer_MediaViewerView_4_en.png rename to tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.viewer_MediaViewerView_4_en.png diff --git a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.api.viewer_MediaViewerView_5_en.png b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.viewer_MediaViewerView_5_en.png similarity index 100% rename from tests/uitests/src/test/snapshots/images/libraries.mediaviewer.api.viewer_MediaViewerView_5_en.png rename to tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.viewer_MediaViewerView_5_en.png diff --git a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.api.viewer_MediaViewerView_6_en.png b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.viewer_MediaViewerView_6_en.png similarity index 100% rename from tests/uitests/src/test/snapshots/images/libraries.mediaviewer.api.viewer_MediaViewerView_6_en.png rename to tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.viewer_MediaViewerView_6_en.png diff --git a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.api.viewer_MediaViewerView_7_en.png b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.viewer_MediaViewerView_7_en.png similarity index 100% rename from tests/uitests/src/test/snapshots/images/libraries.mediaviewer.api.viewer_MediaViewerView_7_en.png rename to tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.viewer_MediaViewerView_7_en.png diff --git a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.api.viewer_MediaViewerView_8_en.png b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.viewer_MediaViewerView_8_en.png similarity index 100% rename from tests/uitests/src/test/snapshots/images/libraries.mediaviewer.api.viewer_MediaViewerView_8_en.png rename to tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.viewer_MediaViewerView_8_en.png diff --git a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.api.viewer_MediaViewerView_9_en.png b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.viewer_MediaViewerView_9_en.png similarity index 100% rename from tests/uitests/src/test/snapshots/images/libraries.mediaviewer.api.viewer_MediaViewerView_9_en.png rename to tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.viewer_MediaViewerView_9_en.png From 6e624cc1989cc51e75b553e07830ab6337f9721c Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Fri, 29 Nov 2024 09:41:03 +0100 Subject: [PATCH 54/96] Rename file and split test. --- ...> FileExtensionExtractorWithValidation.kt} | 0 ...leExtensionExtractorWithValidationTest.kt} | 10 +--------- libraries/mediaviewer/test/build.gradle.kts | 3 +++ ...ExtensionExtractorWithoutValidationTest.kt | 20 +++++++++++++++++++ 4 files changed, 24 insertions(+), 9 deletions(-) rename libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/util/{FileExtensionExtractor.kt => FileExtensionExtractorWithValidation.kt} (100%) rename libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/util/{FileExtensionExtractorTest.kt => FileExtensionExtractorWithValidationTest.kt} (70%) create mode 100644 libraries/mediaviewer/test/src/test/kotlin/io/element/android/libraries/mediaviewer/test/util/FileExtensionExtractorWithoutValidationTest.kt diff --git a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/util/FileExtensionExtractor.kt b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/util/FileExtensionExtractorWithValidation.kt similarity index 100% rename from libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/util/FileExtensionExtractor.kt rename to libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/util/FileExtensionExtractorWithValidation.kt diff --git a/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/util/FileExtensionExtractorTest.kt b/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/util/FileExtensionExtractorWithValidationTest.kt similarity index 70% rename from libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/util/FileExtensionExtractorTest.kt rename to libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/util/FileExtensionExtractorWithValidationTest.kt index 5e9ada9f3a8..df16eb62e87 100644 --- a/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/util/FileExtensionExtractorTest.kt +++ b/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/util/FileExtensionExtractorWithValidationTest.kt @@ -8,13 +8,12 @@ package io.element.android.libraries.mediaviewer.impl.util import com.google.common.truth.Truth.assertThat -import io.element.android.libraries.mediaviewer.test.util.FileExtensionExtractorWithoutValidation import org.junit.Test import org.junit.runner.RunWith import org.robolectric.RobolectricTestRunner @RunWith(RobolectricTestRunner::class) -class FileExtensionExtractorTest { +class FileExtensionExtractorWithValidationTest { @Test fun `test FileExtensionExtractor with validation OK`() { val sut = FileExtensionExtractorWithValidation() @@ -28,11 +27,4 @@ class FileExtensionExtractorTest { val sut = FileExtensionExtractorWithValidation() assertThat(sut.extractFromName("test.bla")).isEqualTo("bin") } - - @Test - fun `test FileExtensionExtractor no validation`() { - val sut = FileExtensionExtractorWithoutValidation() - assertThat(sut.extractFromName("test.png")).isEqualTo("png") - assertThat(sut.extractFromName("test.bla")).isEqualTo("bla") - } } diff --git a/libraries/mediaviewer/test/build.gradle.kts b/libraries/mediaviewer/test/build.gradle.kts index aa182faa987..47adf35975c 100644 --- a/libraries/mediaviewer/test/build.gradle.kts +++ b/libraries/mediaviewer/test/build.gradle.kts @@ -18,4 +18,7 @@ dependencies { implementation(projects.libraries.core) implementation(projects.tests.testutils) implementation(projects.libraries.matrix.api) + + testImplementation(libs.test.junit) + testImplementation(libs.test.truth) } diff --git a/libraries/mediaviewer/test/src/test/kotlin/io/element/android/libraries/mediaviewer/test/util/FileExtensionExtractorWithoutValidationTest.kt b/libraries/mediaviewer/test/src/test/kotlin/io/element/android/libraries/mediaviewer/test/util/FileExtensionExtractorWithoutValidationTest.kt new file mode 100644 index 00000000000..48a6fbac117 --- /dev/null +++ b/libraries/mediaviewer/test/src/test/kotlin/io/element/android/libraries/mediaviewer/test/util/FileExtensionExtractorWithoutValidationTest.kt @@ -0,0 +1,20 @@ +/* + * Copyright 2024 New Vector Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only + * Please see LICENSE in the repository root for full details. + */ + +package io.element.android.libraries.mediaviewer.test.util + +import com.google.common.truth.Truth.assertThat +import org.junit.Test + +class FileExtensionExtractorWithoutValidationTest { + @Test + fun `extension should always be extracted even is invalid`() { + val sut = FileExtensionExtractorWithoutValidation() + assertThat(sut.extractFromName("test.png")).isEqualTo("png") + assertThat(sut.extractFromName("test.bla")).isEqualTo("bla") + } +} From 6e5d7f8f51122d799d6f80004bb4027dd7206fea Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Fri, 29 Nov 2024 11:23:02 +0100 Subject: [PATCH 55/96] Add some previews. --- .../impl/local/file/MediaFileView.kt | 17 ++ .../impl/local/file/MediaInfoFileProvider.kt | 21 ++ .../impl/local/image/MediaImageView.kt | 13 + .../impl/local/video/ExoPlayerForPreview.kt | 252 ++++++++++++++++++ .../impl/local/video/MediaVideoView.kt | 104 +++++--- 5 files changed, 367 insertions(+), 40 deletions(-) create mode 100644 libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/file/MediaInfoFileProvider.kt create mode 100644 libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/video/ExoPlayerForPreview.kt diff --git a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/file/MediaFileView.kt b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/file/MediaFileView.kt index f0663a5d23a..0e345138a05 100644 --- a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/file/MediaFileView.kt +++ b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/file/MediaFileView.kt @@ -29,16 +29,20 @@ import androidx.compose.ui.draw.clip import androidx.compose.ui.draw.rotate import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.style.TextOverflow +import androidx.compose.ui.tooling.preview.PreviewParameter import androidx.compose.ui.unit.dp import io.element.android.compound.theme.ElementTheme import io.element.android.compound.tokens.generated.CompoundIcons import io.element.android.libraries.core.bool.orFalse import io.element.android.libraries.core.mimetype.MimeTypes.isMimeTypeAudio +import io.element.android.libraries.designsystem.preview.ElementPreview +import io.element.android.libraries.designsystem.preview.PreviewsDayNight import io.element.android.libraries.designsystem.theme.components.Icon import io.element.android.libraries.designsystem.theme.components.Text import io.element.android.libraries.mediaviewer.api.MediaInfo import io.element.android.libraries.mediaviewer.api.helper.formatFileExtensionAndSize import io.element.android.libraries.mediaviewer.impl.local.LocalMediaViewState +import io.element.android.libraries.mediaviewer.impl.local.rememberLocalMediaViewState @Composable fun MediaFileView( @@ -101,3 +105,16 @@ fun MediaFileView( } } } + +@PreviewsDayNight +@Composable +internal fun MediaFileViewPreview( + @PreviewParameter(MediaInfoFileProvider::class) info: MediaInfo +) = ElementPreview { + MediaFileView( + localMediaViewState = rememberLocalMediaViewState(), + uri = null, + info = info, + onClick = {}, + ) +} diff --git a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/file/MediaInfoFileProvider.kt b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/file/MediaInfoFileProvider.kt new file mode 100644 index 00000000000..980f9eba89a --- /dev/null +++ b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/file/MediaInfoFileProvider.kt @@ -0,0 +1,21 @@ +/* + * Copyright 2024 New Vector Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only + * Please see LICENSE in the repository root for full details. + */ + +package io.element.android.libraries.mediaviewer.impl.local.file + +import androidx.compose.ui.tooling.preview.PreviewParameterProvider +import io.element.android.libraries.mediaviewer.api.MediaInfo +import io.element.android.libraries.mediaviewer.api.aPdfMediaInfo +import io.element.android.libraries.mediaviewer.api.anAudioMediaInfo + +open class MediaInfoFileProvider : PreviewParameterProvider { + override val values: Sequence + get() = sequenceOf( + aPdfMediaInfo(), + anAudioMediaInfo(), + ) +} diff --git a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/image/MediaImageView.kt b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/image/MediaImageView.kt index c5792a9828b..7057bd8b744 100644 --- a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/image/MediaImageView.kt +++ b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/image/MediaImageView.kt @@ -14,9 +14,12 @@ import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.platform.LocalInspectionMode import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource +import io.element.android.libraries.designsystem.preview.ElementPreview +import io.element.android.libraries.designsystem.preview.PreviewsDayNight import io.element.android.libraries.designsystem.utils.CommonDrawables import io.element.android.libraries.mediaviewer.api.local.LocalMedia import io.element.android.libraries.mediaviewer.impl.local.LocalMediaViewState +import io.element.android.libraries.mediaviewer.impl.local.rememberLocalMediaViewState import io.element.android.libraries.ui.strings.CommonStrings import me.saket.telephoto.zoomable.coil.ZoomableAsyncImage import me.saket.telephoto.zoomable.rememberZoomableImageState @@ -47,3 +50,13 @@ fun MediaImageView( ) } } + +@PreviewsDayNight +@Composable +internal fun MediaImageViewPreview() = ElementPreview { + MediaImageView( + localMediaViewState = rememberLocalMediaViewState(), + localMedia = null, + onClick = {}, + ) +} diff --git a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/video/ExoPlayerForPreview.kt b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/video/ExoPlayerForPreview.kt new file mode 100644 index 00000000000..21f107ec959 --- /dev/null +++ b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/video/ExoPlayerForPreview.kt @@ -0,0 +1,252 @@ +/* + * Copyright 2024 New Vector Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only + * Please see LICENSE in the repository root for full details. + */ + +@file:Suppress( + "OVERRIDE_DEPRECATION", + "RedundantNullableReturnType", + "DEPRECATION", +) + +package io.element.android.libraries.mediaviewer.impl.local.video + +import android.annotation.SuppressLint +import android.media.AudioDeviceInfo +import android.os.Looper +import android.view.Surface +import android.view.SurfaceHolder +import android.view.SurfaceView +import android.view.TextureView +import androidx.media3.common.AudioAttributes +import androidx.media3.common.AuxEffectInfo +import androidx.media3.common.DeviceInfo +import androidx.media3.common.Effect +import androidx.media3.common.Format +import androidx.media3.common.MediaItem +import androidx.media3.common.MediaMetadata +import androidx.media3.common.PlaybackParameters +import androidx.media3.common.Player +import androidx.media3.common.PriorityTaskManager +import androidx.media3.common.Timeline +import androidx.media3.common.TrackSelectionParameters +import androidx.media3.common.Tracks +import androidx.media3.common.VideoSize +import androidx.media3.common.text.CueGroup +import androidx.media3.common.util.Clock +import androidx.media3.common.util.Size +import androidx.media3.exoplayer.DecoderCounters +import androidx.media3.exoplayer.ExoPlaybackException +import androidx.media3.exoplayer.ExoPlayer +import androidx.media3.exoplayer.PlayerMessage +import androidx.media3.exoplayer.Renderer +import androidx.media3.exoplayer.SeekParameters +import androidx.media3.exoplayer.analytics.AnalyticsCollector +import androidx.media3.exoplayer.analytics.AnalyticsListener +import androidx.media3.exoplayer.image.ImageOutput +import androidx.media3.exoplayer.source.MediaSource +import androidx.media3.exoplayer.source.ShuffleOrder +import androidx.media3.exoplayer.source.TrackGroupArray +import androidx.media3.exoplayer.trackselection.TrackSelectionArray +import androidx.media3.exoplayer.trackselection.TrackSelector +import androidx.media3.exoplayer.video.VideoFrameMetadataListener +import androidx.media3.exoplayer.video.spherical.CameraMotionListener + +@SuppressLint("UnsafeOptInUsageError") +class ExoPlayerForPreview( + private val isPlaying: Boolean = false, +) : ExoPlayer { + override fun getApplicationLooper(): Looper = throw NotImplementedError() + override fun addListener(listener: Player.Listener) {} + override fun removeListener(listener: Player.Listener) {} + override fun setMediaItems(mediaItems: MutableList) {} + override fun setMediaItems(mediaItems: MutableList, resetPosition: Boolean) {} + override fun setMediaItems(mediaItems: MutableList, startIndex: Int, startPositionMs: Long) {} + override fun setMediaItem(mediaItem: MediaItem) {} + override fun setMediaItem(mediaItem: MediaItem, startPositionMs: Long) {} + override fun setMediaItem(mediaItem: MediaItem, resetPosition: Boolean) {} + override fun addMediaItem(mediaItem: MediaItem) {} + override fun addMediaItem(index: Int, mediaItem: MediaItem) {} + override fun addMediaItems(mediaItems: MutableList) {} + override fun addMediaItems(index: Int, mediaItems: MutableList) {} + override fun moveMediaItem(currentIndex: Int, newIndex: Int) {} + override fun moveMediaItems(fromIndex: Int, toIndex: Int, newIndex: Int) {} + override fun replaceMediaItem(index: Int, mediaItem: MediaItem) {} + override fun replaceMediaItems(fromIndex: Int, toIndex: Int, mediaItems: MutableList) {} + override fun removeMediaItem(index: Int) {} + override fun removeMediaItems(fromIndex: Int, toIndex: Int) {} + override fun clearMediaItems() {} + override fun isCommandAvailable(command: Int): Boolean = throw NotImplementedError() + override fun canAdvertiseSession(): Boolean = throw NotImplementedError() + override fun getAvailableCommands(): Player.Commands = throw NotImplementedError() + override fun prepare(mediaSource: MediaSource) {} + override fun prepare(mediaSource: MediaSource, resetPosition: Boolean, resetState: Boolean) {} + override fun prepare() {} + override fun getPlaybackState(): Int = throw NotImplementedError() + override fun getPlaybackSuppressionReason(): Int = throw NotImplementedError() + override fun isPlaying() = isPlaying + override fun getPlayerError(): ExoPlaybackException? = null + override fun play() {} + override fun pause() {} + override fun setPlayWhenReady(playWhenReady: Boolean) {} + override fun getPlayWhenReady(): Boolean = throw NotImplementedError() + override fun setRepeatMode(repeatMode: Int) {} + override fun getRepeatMode(): Int = throw NotImplementedError() + override fun setShuffleModeEnabled(shuffleModeEnabled: Boolean) {} + override fun getShuffleModeEnabled(): Boolean = throw NotImplementedError() + override fun isLoading(): Boolean = throw NotImplementedError() + override fun seekToDefaultPosition() {} + override fun seekToDefaultPosition(mediaItemIndex: Int) {} + override fun seekTo(positionMs: Long) {} + override fun seekTo(mediaItemIndex: Int, positionMs: Long) {} + override fun getSeekBackIncrement(): Long = throw NotImplementedError() + override fun seekBack() {} + override fun getSeekForwardIncrement(): Long = throw NotImplementedError() + override fun seekForward() {} + override fun hasPreviousMediaItem(): Boolean = throw NotImplementedError() + override fun seekToPreviousWindow() {} + override fun seekToPreviousMediaItem() {} + override fun getMaxSeekToPreviousPosition(): Long = throw NotImplementedError() + override fun seekToPrevious() {} + override fun hasNext(): Boolean = throw NotImplementedError() + override fun hasNextWindow(): Boolean = throw NotImplementedError() + override fun hasNextMediaItem(): Boolean = throw NotImplementedError() + override fun next() {} + override fun seekToNextWindow() {} + override fun seekToNextMediaItem() {} + override fun seekToNext() {} + override fun setPlaybackParameters(playbackParameters: PlaybackParameters) {} + override fun setPlaybackSpeed(speed: Float) {} + override fun getPlaybackParameters(): PlaybackParameters = throw NotImplementedError() + override fun stop() {} + override fun release() {} + override fun getCurrentTracks(): Tracks = throw NotImplementedError() + override fun getTrackSelectionParameters(): TrackSelectionParameters = throw NotImplementedError() + override fun setTrackSelectionParameters(parameters: TrackSelectionParameters) {} + override fun getMediaMetadata(): MediaMetadata = throw NotImplementedError() + override fun getPlaylistMetadata(): MediaMetadata = throw NotImplementedError() + override fun setPlaylistMetadata(mediaMetadata: MediaMetadata) {} + override fun getCurrentManifest(): Any? = throw NotImplementedError() + override fun getCurrentTimeline(): Timeline = throw NotImplementedError() + override fun getCurrentPeriodIndex(): Int = throw NotImplementedError() + override fun getCurrentWindowIndex(): Int = throw NotImplementedError() + override fun getCurrentMediaItemIndex(): Int = throw NotImplementedError() + override fun getNextWindowIndex(): Int = throw NotImplementedError() + override fun getNextMediaItemIndex(): Int = throw NotImplementedError() + override fun getPreviousWindowIndex(): Int = throw NotImplementedError() + override fun getPreviousMediaItemIndex(): Int = throw NotImplementedError() + override fun getCurrentMediaItem(): MediaItem? = throw NotImplementedError() + override fun getMediaItemCount(): Int = throw NotImplementedError() + override fun getMediaItemAt(index: Int): MediaItem = throw NotImplementedError() + override fun getDuration(): Long = throw NotImplementedError() + override fun getCurrentPosition(): Long = throw NotImplementedError() + override fun getBufferedPosition(): Long = throw NotImplementedError() + override fun getBufferedPercentage(): Int = throw NotImplementedError() + override fun getTotalBufferedDuration(): Long = throw NotImplementedError() + override fun isCurrentWindowDynamic(): Boolean = throw NotImplementedError() + override fun isCurrentMediaItemDynamic(): Boolean = throw NotImplementedError() + override fun isCurrentWindowLive(): Boolean = throw NotImplementedError() + override fun isCurrentMediaItemLive(): Boolean = throw NotImplementedError() + override fun getCurrentLiveOffset(): Long = throw NotImplementedError() + override fun isCurrentWindowSeekable(): Boolean = throw NotImplementedError() + override fun isCurrentMediaItemSeekable(): Boolean = throw NotImplementedError() + override fun isPlayingAd(): Boolean = throw NotImplementedError() + override fun getCurrentAdGroupIndex(): Int = throw NotImplementedError() + override fun getCurrentAdIndexInAdGroup(): Int = throw NotImplementedError() + override fun getContentDuration(): Long = throw NotImplementedError() + override fun getContentPosition(): Long = throw NotImplementedError() + override fun getContentBufferedPosition(): Long = throw NotImplementedError() + override fun getAudioAttributes(): AudioAttributes = throw NotImplementedError() + override fun setVolume(volume: Float) = throw NotImplementedError() + override fun getVolume(): Float = throw NotImplementedError() + override fun clearVideoSurface() {} + override fun clearVideoSurface(surface: Surface?) {} + override fun setVideoSurface(surface: Surface?) {} + override fun setVideoSurfaceHolder(surfaceHolder: SurfaceHolder?) {} + override fun clearVideoSurfaceHolder(surfaceHolder: SurfaceHolder?) {} + override fun setVideoSurfaceView(surfaceView: SurfaceView?) {} + override fun clearVideoSurfaceView(surfaceView: SurfaceView?) {} + override fun setVideoTextureView(textureView: TextureView?) {} + override fun clearVideoTextureView(textureView: TextureView?) {} + override fun getVideoSize(): VideoSize = throw NotImplementedError() + override fun getSurfaceSize(): Size = throw NotImplementedError() + override fun getCurrentCues(): CueGroup = throw NotImplementedError() + override fun getDeviceInfo(): DeviceInfo = throw NotImplementedError() + override fun getDeviceVolume(): Int = throw NotImplementedError() + override fun isDeviceMuted(): Boolean = throw NotImplementedError() + override fun setDeviceVolume(volume: Int) {} + override fun setDeviceVolume(volume: Int, flags: Int) {} + override fun increaseDeviceVolume() {} + override fun increaseDeviceVolume(flags: Int) {} + override fun decreaseDeviceVolume() {} + override fun decreaseDeviceVolume(flags: Int) {} + override fun setDeviceMuted(muted: Boolean) {} + override fun setDeviceMuted(muted: Boolean, flags: Int) {} + override fun setAudioAttributes(audioAttributes: AudioAttributes, handleAudioFocus: Boolean) {} + override fun getAudioComponent(): ExoPlayer.AudioComponent? = throw NotImplementedError() + override fun getVideoComponent(): ExoPlayer.VideoComponent? = throw NotImplementedError() + override fun getTextComponent(): ExoPlayer.TextComponent? = throw NotImplementedError() + override fun getDeviceComponent(): ExoPlayer.DeviceComponent? = throw NotImplementedError() + override fun addAudioOffloadListener(listener: ExoPlayer.AudioOffloadListener) {} + override fun removeAudioOffloadListener(listener: ExoPlayer.AudioOffloadListener) {} + override fun getAnalyticsCollector(): AnalyticsCollector = throw NotImplementedError() + override fun addAnalyticsListener(listener: AnalyticsListener) {} + override fun removeAnalyticsListener(listener: AnalyticsListener) {} + override fun getRendererCount(): Int = throw NotImplementedError() + override fun getRendererType(index: Int): Int = throw NotImplementedError() + override fun getRenderer(index: Int): Renderer = throw NotImplementedError() + override fun getTrackSelector(): TrackSelector? = throw NotImplementedError() + override fun getCurrentTrackGroups(): TrackGroupArray = throw NotImplementedError() + override fun getCurrentTrackSelections(): TrackSelectionArray = throw NotImplementedError() + override fun getPlaybackLooper(): Looper = throw NotImplementedError() + override fun getClock(): Clock = throw NotImplementedError() + override fun setMediaSources(mediaSources: MutableList) {} + override fun setMediaSources(mediaSources: MutableList, resetPosition: Boolean) {} + override fun setMediaSources(mediaSources: MutableList, startMediaItemIndex: Int, startPositionMs: Long) {} + override fun setMediaSource(mediaSource: MediaSource) {} + override fun setMediaSource(mediaSource: MediaSource, startPositionMs: Long) {} + override fun setMediaSource(mediaSource: MediaSource, resetPosition: Boolean) {} + override fun addMediaSource(mediaSource: MediaSource) {} + override fun addMediaSource(index: Int, mediaSource: MediaSource) {} + override fun addMediaSources(mediaSources: MutableList) {} + override fun addMediaSources(index: Int, mediaSources: MutableList) {} + override fun setShuffleOrder(shuffleOrder: ShuffleOrder) {} + override fun setPreloadConfiguration(preloadConfiguration: ExoPlayer.PreloadConfiguration) {} + override fun getPreloadConfiguration(): ExoPlayer.PreloadConfiguration = throw NotImplementedError() + override fun setAudioSessionId(audioSessionId: Int) {} + override fun getAudioSessionId(): Int = throw NotImplementedError() + override fun setAuxEffectInfo(auxEffectInfo: AuxEffectInfo) {} + override fun clearAuxEffectInfo() {} + override fun setPreferredAudioDevice(audioDeviceInfo: AudioDeviceInfo?) {} + override fun setSkipSilenceEnabled(skipSilenceEnabled: Boolean) {} + override fun getSkipSilenceEnabled(): Boolean = throw NotImplementedError() + override fun setVideoEffects(videoEffects: MutableList) {} + override fun setVideoScalingMode(videoScalingMode: Int) {} + override fun getVideoScalingMode(): Int = throw NotImplementedError() + override fun setVideoChangeFrameRateStrategy(videoChangeFrameRateStrategy: Int) {} + override fun getVideoChangeFrameRateStrategy(): Int = throw NotImplementedError() + override fun setVideoFrameMetadataListener(listener: VideoFrameMetadataListener) {} + override fun clearVideoFrameMetadataListener(listener: VideoFrameMetadataListener) {} + override fun setCameraMotionListener(listener: CameraMotionListener) {} + override fun clearCameraMotionListener(listener: CameraMotionListener) {} + override fun createMessage(target: PlayerMessage.Target): PlayerMessage = throw NotImplementedError() + override fun setSeekParameters(seekParameters: SeekParameters?) {} + override fun getSeekParameters(): SeekParameters = throw NotImplementedError() + override fun setForegroundMode(foregroundMode: Boolean) {} + override fun setPauseAtEndOfMediaItems(pauseAtEndOfMediaItems: Boolean) {} + override fun getPauseAtEndOfMediaItems(): Boolean = throw NotImplementedError() + override fun getAudioFormat(): Format? = throw NotImplementedError() + override fun getVideoFormat(): Format? = throw NotImplementedError() + override fun getAudioDecoderCounters(): DecoderCounters? = throw NotImplementedError() + override fun getVideoDecoderCounters(): DecoderCounters? = throw NotImplementedError() + override fun setHandleAudioBecomingNoisy(handleAudioBecomingNoisy: Boolean) {} + override fun setWakeMode(wakeMode: Int) {} + override fun setPriority(priority: Int) {} + override fun setPriorityTaskManager(priorityTaskManager: PriorityTaskManager?) {} + override fun isSleepingForOffload(): Boolean = throw NotImplementedError() + override fun isTunnelingEnabled(): Boolean = throw NotImplementedError() + override fun isReleased(): Boolean = throw NotImplementedError() + override fun setImageOutput(imageOutput: ImageOutput?) {} +} diff --git a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/video/MediaVideoView.kt b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/video/MediaVideoView.kt index 7c7d798e93a..2aef883752f 100644 --- a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/video/MediaVideoView.kt +++ b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/video/MediaVideoView.kt @@ -32,51 +32,60 @@ import androidx.lifecycle.Lifecycle import androidx.media3.common.MediaItem import androidx.media3.common.Player import androidx.media3.common.Timeline +import androidx.media3.exoplayer.ExoPlayer import androidx.media3.ui.AspectRatioFrameLayout import androidx.media3.ui.PlayerView import io.element.android.compound.theme.ElementTheme +import io.element.android.libraries.designsystem.preview.ElementPreview +import io.element.android.libraries.designsystem.preview.PreviewsDayNight import io.element.android.libraries.designsystem.theme.components.Text import io.element.android.libraries.designsystem.utils.KeepScreenOn import io.element.android.libraries.designsystem.utils.OnLifecycleEvent import io.element.android.libraries.mediaviewer.api.local.LocalMedia import io.element.android.libraries.mediaviewer.impl.local.LocalMediaViewState import io.element.android.libraries.mediaviewer.impl.local.PlayableState +import io.element.android.libraries.mediaviewer.impl.local.rememberLocalMediaViewState import kotlinx.coroutines.delay import kotlin.time.Duration.Companion.seconds +@SuppressLint("UnsafeOptInUsageError") @Composable fun MediaVideoView( localMediaViewState: LocalMediaViewState, localMedia: LocalMedia?, modifier: Modifier = Modifier, ) { - if (LocalInspectionMode.current) { - Text( - modifier = modifier - .background(ElementTheme.colors.bgSubtlePrimary) - .wrapContentSize(), - text = "A Video Player will render here", - ) + val exoPlayer = if (LocalInspectionMode.current) { + remember { + ExoPlayerForPreview() + } } else { - ExoPlayerMediaVideoView( - localMediaViewState = localMediaViewState, - localMedia = localMedia, - modifier = modifier, - ) + val context = LocalContext.current + remember { + ExoPlayerWrapper.create(context) + } } + ExoPlayerMediaVideoView( + localMediaViewState = localMediaViewState, + exoPlayer = exoPlayer, + localMedia = localMedia, + modifier = modifier, + ) } @SuppressLint("UnsafeOptInUsageError") @Composable private fun ExoPlayerMediaVideoView( localMediaViewState: LocalMediaViewState, + exoPlayer: ExoPlayer, localMedia: LocalMedia?, modifier: Modifier = Modifier, ) { + val isControllerVisibleByDefault = LocalInspectionMode.current var mediaPlayerControllerState: MediaPlayerControllerState by remember { mutableStateOf( MediaPlayerControllerState( - isVisible = false, + isVisible = isControllerVisibleByDefault, isPlaying = false, progressInMillis = 0, durationInMillis = 0, @@ -95,10 +104,6 @@ private fun ExoPlayerMediaVideoView( localMediaViewState.playableState = playableState - val context = LocalContext.current - val exoPlayer = remember { - ExoPlayerWrapper.create(context) - } val playerListener = object : Player.Listener { override fun onRenderedFirstFrame() { localMediaViewState.isReady = true @@ -167,31 +172,40 @@ private fun ExoPlayerMediaVideoView( KeepScreenOn(mediaPlayerControllerState.isPlaying) Box( modifier = modifier - .background(ElementTheme.colors.bgSubtlePrimary) - .wrapContentSize(), + .background(ElementTheme.colors.bgSubtlePrimary), ) { - AndroidView( - modifier = Modifier.fillMaxSize(), - factory = { - PlayerView(context).apply { - player = exoPlayer - resizeMode = AspectRatioFrameLayout.RESIZE_MODE_FIT - layoutParams = FrameLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT) - setOnClickListener { - autoHideController++ - mediaPlayerControllerState = mediaPlayerControllerState.copy( - isVisible = !mediaPlayerControllerState.isVisible, - ) + val context = LocalContext.current + if (LocalInspectionMode.current) { + Text( + modifier = Modifier + .background(ElementTheme.colors.bgSubtlePrimary) + .wrapContentSize(), + text = "A Video Player will render here", + ) + } else { + AndroidView( + modifier = Modifier.fillMaxSize(), + factory = { + PlayerView(context).apply { + player = exoPlayer + resizeMode = AspectRatioFrameLayout.RESIZE_MODE_FIT + layoutParams = FrameLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT) + setOnClickListener { + autoHideController++ + mediaPlayerControllerState = mediaPlayerControllerState.copy( + isVisible = !mediaPlayerControllerState.isVisible, + ) + } + useController = false } - useController = false - } - }, - onRelease = { playerView -> - playerView.setOnClickListener(null) - playerView.setControllerVisibilityListener(null as PlayerView.ControllerVisibilityListener?) - playerView.player = null - }, - ) + }, + onRelease = { playerView -> + playerView.setOnClickListener(null) + playerView.setControllerVisibilityListener(null as PlayerView.ControllerVisibilityListener?) + playerView.player = null + }, + ) + } MediaPlayerControllerView( state = mediaPlayerControllerState, onTogglePlay = { @@ -235,3 +249,13 @@ private fun ExoPlayerMediaVideoView( } } } + +@PreviewsDayNight +@Composable +internal fun MediaVideoViewPreview() = ElementPreview { + MediaVideoView( + modifier = Modifier.fillMaxSize(), + localMediaViewState = rememberLocalMediaViewState(), + localMedia = null, + ) +} From 2fdb28d61c1ac519baa4dbe91654fa698368cbe1 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Fri, 29 Nov 2024 11:28:35 +0100 Subject: [PATCH 56/96] Fix navigation issue. --- .../element/android/features/messages/impl/MessagesFlowNode.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesFlowNode.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesFlowNode.kt index d092dbbb130..c607d07375d 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesFlowNode.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesFlowNode.kt @@ -52,6 +52,7 @@ import io.element.android.libraries.architecture.BackstackWithOverlayBox import io.element.android.libraries.architecture.BaseFlowNode import io.element.android.libraries.architecture.createNode import io.element.android.libraries.architecture.overlay.Overlay +import io.element.android.libraries.architecture.overlay.operation.hide import io.element.android.libraries.architecture.overlay.operation.show import io.element.android.libraries.di.RoomScope import io.element.android.libraries.matrix.api.MatrixClient @@ -239,7 +240,7 @@ class MessagesFlowNode @AssistedInject constructor( ) val callback = object : MediaViewerEntryPoint.Callback { override fun onDone() { - backstack.pop() + overlay.hide() } } mediaViewerEntryPoint.nodeBuilder(this, buildContext) From d37ec23fa9483de112f101bb79462acbf0b70215 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Fri, 29 Nov 2024 11:49:21 +0100 Subject: [PATCH 57/96] Fix preview rendering --- .../libraries/mediaviewer/impl/local/file/MediaFileView.kt | 2 ++ .../libraries/mediaviewer/impl/local/image/MediaImageView.kt | 2 ++ .../libraries/mediaviewer/impl/local/video/MediaVideoView.kt | 3 +-- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/file/MediaFileView.kt b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/file/MediaFileView.kt index 0e345138a05..ec50ef9f4c1 100644 --- a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/file/MediaFileView.kt +++ b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/file/MediaFileView.kt @@ -14,6 +14,7 @@ import androidx.compose.foundation.interaction.MutableInteractionSource import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size @@ -112,6 +113,7 @@ internal fun MediaFileViewPreview( @PreviewParameter(MediaInfoFileProvider::class) info: MediaInfo ) = ElementPreview { MediaFileView( + modifier = Modifier.fillMaxSize(), localMediaViewState = rememberLocalMediaViewState(), uri = null, info = info, diff --git a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/image/MediaImageView.kt b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/image/MediaImageView.kt index 7057bd8b744..a286b7dc2d0 100644 --- a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/image/MediaImageView.kt +++ b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/image/MediaImageView.kt @@ -8,6 +8,7 @@ package io.element.android.libraries.mediaviewer.impl.local.image import androidx.compose.foundation.Image +import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.layout.ContentScale @@ -55,6 +56,7 @@ fun MediaImageView( @Composable internal fun MediaImageViewPreview() = ElementPreview { MediaImageView( + modifier = Modifier.fillMaxSize(), localMediaViewState = rememberLocalMediaViewState(), localMedia = null, onClick = {}, diff --git a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/video/MediaVideoView.kt b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/video/MediaVideoView.kt index 2aef883752f..d9785491924 100644 --- a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/video/MediaVideoView.kt +++ b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/video/MediaVideoView.kt @@ -14,7 +14,6 @@ import androidx.compose.foundation.background import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.wrapContentSize import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.derivedStateOf @@ -179,7 +178,7 @@ private fun ExoPlayerMediaVideoView( Text( modifier = Modifier .background(ElementTheme.colors.bgSubtlePrimary) - .wrapContentSize(), + .align(Alignment.Center), text = "A Video Player will render here", ) } else { From 99a6723ad5ae7107620a48e558a697ea5cd4e91c Mon Sep 17 00:00:00 2001 From: ElementBot Date: Fri, 29 Nov 2024 10:59:53 +0000 Subject: [PATCH 58/96] Update screenshots --- ...ies.mediaviewer.impl.local.file_MediaFileView_Day_0_en.png | 3 +++ ...ies.mediaviewer.impl.local.file_MediaFileView_Day_1_en.png | 3 +++ ...s.mediaviewer.impl.local.file_MediaFileView_Night_0_en.png | 3 +++ ...s.mediaviewer.impl.local.file_MediaFileView_Night_1_en.png | 3 +++ ...s.mediaviewer.impl.local.image_MediaImageView_Day_0_en.png | 3 +++ ...mediaviewer.impl.local.image_MediaImageView_Night_0_en.png | 3 +++ ...s.mediaviewer.impl.local.video_MediaVideoView_Day_0_en.png | 3 +++ ...mediaviewer.impl.local.video_MediaVideoView_Night_0_en.png | 3 +++ ...libraries.mediaviewer.impl.viewer_MediaViewerView_4_en.png | 4 ++-- 9 files changed, 26 insertions(+), 2 deletions(-) create mode 100644 tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.local.file_MediaFileView_Day_0_en.png create mode 100644 tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.local.file_MediaFileView_Day_1_en.png create mode 100644 tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.local.file_MediaFileView_Night_0_en.png create mode 100644 tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.local.file_MediaFileView_Night_1_en.png create mode 100644 tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.local.image_MediaImageView_Day_0_en.png create mode 100644 tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.local.image_MediaImageView_Night_0_en.png create mode 100644 tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.local.video_MediaVideoView_Day_0_en.png create mode 100644 tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.local.video_MediaVideoView_Night_0_en.png diff --git a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.local.file_MediaFileView_Day_0_en.png b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.local.file_MediaFileView_Day_0_en.png new file mode 100644 index 00000000000..50f49e2d0bd --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.local.file_MediaFileView_Day_0_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2907ba5f75a40e30a37ad4d302797cea4e3d2b77cb1c66a9432319242b8f1995 +size 12188 diff --git a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.local.file_MediaFileView_Day_1_en.png b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.local.file_MediaFileView_Day_1_en.png new file mode 100644 index 00000000000..c4d024965ef --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.local.file_MediaFileView_Day_1_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:5307e90428957819812269b9b3e0c6e9d59238141d54cd959aa5506290797a35 +size 11587 diff --git a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.local.file_MediaFileView_Night_0_en.png b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.local.file_MediaFileView_Night_0_en.png new file mode 100644 index 00000000000..37bc2056260 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.local.file_MediaFileView_Night_0_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:59e981e51595a368745c92f355793b2c0301a9e4929430733876a02f3ac75e2e +size 11881 diff --git a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.local.file_MediaFileView_Night_1_en.png b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.local.file_MediaFileView_Night_1_en.png new file mode 100644 index 00000000000..37f1c2ed228 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.local.file_MediaFileView_Night_1_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:52354bcf471b14e38e582cc29f73407c8ca65026b2b7c6db3d3b28ec94950679 +size 11413 diff --git a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.local.image_MediaImageView_Day_0_en.png b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.local.image_MediaImageView_Day_0_en.png new file mode 100644 index 00000000000..0d80d15a73f --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.local.image_MediaImageView_Day_0_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2a3e650bde2df79bebfc110eb46998ab21b1e5dba471fd5a755371e5027a27a5 +size 388634 diff --git a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.local.image_MediaImageView_Night_0_en.png b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.local.image_MediaImageView_Night_0_en.png new file mode 100644 index 00000000000..c8e897025bc --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.local.image_MediaImageView_Night_0_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:193190902275db6ffd03dcc41b190e8fc3bba60dda9678274481fbbefe89567d +size 387830 diff --git a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.local.video_MediaVideoView_Day_0_en.png b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.local.video_MediaVideoView_Day_0_en.png new file mode 100644 index 00000000000..ec685d363a2 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.local.video_MediaVideoView_Day_0_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:3b7160dc01dd4704bb07a8c91858bef0d4e99c0f55ca1d7dbdc3e22546a25125 +size 12210 diff --git a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.local.video_MediaVideoView_Night_0_en.png b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.local.video_MediaVideoView_Night_0_en.png new file mode 100644 index 00000000000..df1ea796c15 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.local.video_MediaVideoView_Night_0_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2591b742c64d3d058d4638e5014080f8b3eb13eba3a73951d71dfdc60e7676d9 +size 12455 diff --git a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.viewer_MediaViewerView_4_en.png b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.viewer_MediaViewerView_4_en.png index 67b4bf5eae1..d5d6d31f124 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.viewer_MediaViewerView_4_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.viewer_MediaViewerView_4_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:be67078d37af27ed532a6ae3a6194c154ca72b7c87319eed3f0e982cbc677acc -size 10908 +oid sha256:05794effa4c47e3d2b68892e613f18a55c96789a4e65a182dd0bf2ca0c812d44 +size 14474 From 975457d19ebc2f412137b7901fa068fc8ccba9de Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Fri, 29 Nov 2024 12:05:46 +0100 Subject: [PATCH 59/96] Remove unused import --- .../element/android/features/messages/impl/MessagesFlowNode.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesFlowNode.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesFlowNode.kt index c607d07375d..9d5ed6ff8c1 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesFlowNode.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesFlowNode.kt @@ -19,7 +19,6 @@ import com.bumble.appyx.core.node.node import com.bumble.appyx.core.plugin.Plugin import com.bumble.appyx.core.plugin.plugins import com.bumble.appyx.navmodel.backstack.BackStack -import com.bumble.appyx.navmodel.backstack.operation.pop import com.bumble.appyx.navmodel.backstack.operation.push import dagger.assisted.Assisted import dagger.assisted.AssistedInject From 484cb3f2a20c89045fdd79b6b7105becb3ed65f4 Mon Sep 17 00:00:00 2001 From: ganfra Date: Fri, 29 Nov 2024 12:13:23 +0100 Subject: [PATCH 60/96] change : knock message supporting text display number of characters --- .../joinroom/impl/JoinRoomPresenter.kt | 2 -- .../features/joinroom/impl/JoinRoomState.kt | 2 ++ .../joinroom/impl/JoinRoomStateProvider.kt | 34 +++++++++++++------ .../features/joinroom/impl/JoinRoomView.kt | 7 +++- 4 files changed, 31 insertions(+), 14 deletions(-) diff --git a/features/joinroom/impl/src/main/kotlin/io/element/android/features/joinroom/impl/JoinRoomPresenter.kt b/features/joinroom/impl/src/main/kotlin/io/element/android/features/joinroom/impl/JoinRoomPresenter.kt index ba909a147b9..1984c0c4b32 100644 --- a/features/joinroom/impl/src/main/kotlin/io/element/android/features/joinroom/impl/JoinRoomPresenter.kt +++ b/features/joinroom/impl/src/main/kotlin/io/element/android/features/joinroom/impl/JoinRoomPresenter.kt @@ -48,8 +48,6 @@ import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.launch import java.util.Optional -private const val MAX_KNOCK_MESSAGE_LENGTH = 500 - class JoinRoomPresenter @AssistedInject constructor( @Assisted private val roomId: RoomId, @Assisted private val roomIdOrAlias: RoomIdOrAlias, diff --git a/features/joinroom/impl/src/main/kotlin/io/element/android/features/joinroom/impl/JoinRoomState.kt b/features/joinroom/impl/src/main/kotlin/io/element/android/features/joinroom/impl/JoinRoomState.kt index 6049e6cd5ab..b53c1e0f7d6 100644 --- a/features/joinroom/impl/src/main/kotlin/io/element/android/features/joinroom/impl/JoinRoomState.kt +++ b/features/joinroom/impl/src/main/kotlin/io/element/android/features/joinroom/impl/JoinRoomState.kt @@ -18,6 +18,8 @@ import io.element.android.libraries.matrix.api.core.RoomIdOrAlias import io.element.android.libraries.matrix.api.room.RoomType import io.element.android.libraries.matrix.ui.model.InviteSender +internal const val MAX_KNOCK_MESSAGE_LENGTH = 500 + @Immutable data class JoinRoomState( val contentState: ContentState, diff --git a/features/joinroom/impl/src/main/kotlin/io/element/android/features/joinroom/impl/JoinRoomStateProvider.kt b/features/joinroom/impl/src/main/kotlin/io/element/android/features/joinroom/impl/JoinRoomStateProvider.kt index 33dcf786e54..d3bbc59c0cf 100644 --- a/features/joinroom/impl/src/main/kotlin/io/element/android/features/joinroom/impl/JoinRoomStateProvider.kt +++ b/features/joinroom/impl/src/main/kotlin/io/element/android/features/joinroom/impl/JoinRoomStateProvider.kt @@ -40,17 +40,6 @@ open class JoinRoomStateProvider : PreviewParameterProvider { aJoinRoomState( contentState = aLoadedContentState(joinAuthorisationStatus = JoinAuthorisationStatus.CanJoin) ), - aJoinRoomState( - contentState = aLoadedContentState( - joinAuthorisationStatus = JoinAuthorisationStatus.CanKnock, - topic = "lorem ipsum dolor sit amet consectetur adipiscing elit sed do eiusmod tempor incididunt" + - " ut labore et dolore magna aliqua ut enim ad minim veniam quis nostrud exercitation ullamco" + - " laboris nisi ut aliquip ex ea commodo consequat duis aute irure dolor in reprehenderit in" + - " voluptate velit esse cillum dolore eu fugiat nulla pariatur excepteur sint occaecat cupidatat" + - " non proident sunt in culpa qui officia deserunt mollit anim id est laborum", - numberOfMembers = 888, - ) - ), aJoinRoomState( contentState = aLoadedContentState(joinAuthorisationStatus = JoinAuthorisationStatus.IsInvited(null)) ), @@ -81,6 +70,29 @@ open class JoinRoomStateProvider : PreviewParameterProvider { isDm = true, ) ), + aJoinRoomState( + contentState = aLoadedContentState( + joinAuthorisationStatus = JoinAuthorisationStatus.CanKnock, + topic = "lorem ipsum dolor sit amet consectetur adipiscing elit sed do eiusmod tempor incididunt" + + " ut labore et dolore magna aliqua ut enim ad minim veniam quis nostrud exercitation ullamco" + + " laboris nisi ut aliquip ex ea commodo consequat duis aute irure dolor in reprehenderit in" + + " voluptate velit esse cillum dolore eu fugiat nulla pariatur excepteur sint occaecat cupidatat" + + " non proident sunt in culpa qui officia deserunt mollit anim id est laborum", + numberOfMembers = 888, + ) + ), + aJoinRoomState( + knockMessage = "Let me in please!", + contentState = aLoadedContentState( + joinAuthorisationStatus = JoinAuthorisationStatus.CanKnock, + topic = "lorem ipsum dolor sit amet consectetur adipiscing elit sed do eiusmod tempor incididunt" + + " ut labore et dolore magna aliqua ut enim ad minim veniam quis nostrud exercitation ullamco" + + " laboris nisi ut aliquip ex ea commodo consequat duis aute irure dolor in reprehenderit in" + + " voluptate velit esse cillum dolore eu fugiat nulla pariatur excepteur sint occaecat cupidatat" + + " non proident sunt in culpa qui officia deserunt mollit anim id est laborum", + numberOfMembers = 888, + ) + ), aJoinRoomState( contentState = aLoadedContentState( name = "A knocked Room", diff --git a/features/joinroom/impl/src/main/kotlin/io/element/android/features/joinroom/impl/JoinRoomView.kt b/features/joinroom/impl/src/main/kotlin/io/element/android/features/joinroom/impl/JoinRoomView.kt index 3a1c7c8421f..d06b5badf31 100644 --- a/features/joinroom/impl/src/main/kotlin/io/element/android/features/joinroom/impl/JoinRoomView.kt +++ b/features/joinroom/impl/src/main/kotlin/io/element/android/features/joinroom/impl/JoinRoomView.kt @@ -390,13 +390,18 @@ private fun DefaultLoadedContent( ) } else if (contentState.joinAuthorisationStatus is JoinAuthorisationStatus.CanKnock) { Spacer(modifier = Modifier.height(24.dp)) + val supportingText = if (knockMessage.isNotEmpty()) { + "${knockMessage.length}/$MAX_KNOCK_MESSAGE_LENGTH" + } else { + stringResource(R.string.screen_join_room_knock_message_description) + } TextField( value = knockMessage, onValueChange = onKnockMessageUpdate, maxLines = 3, minLines = 3, modifier = Modifier.fillMaxWidth(), - supportingText = stringResource(R.string.screen_join_room_knock_message_description) + supportingText = supportingText ) } } From 1dfabe45a19c1ab049386ebf98219f015c345a36 Mon Sep 17 00:00:00 2001 From: ElementBot Date: Fri, 29 Nov 2024 11:24:50 +0000 Subject: [PATCH 61/96] Update screenshots --- .../images/features.joinroom.impl_JoinRoomView_Day_10_en.png | 4 ++-- .../images/features.joinroom.impl_JoinRoomView_Day_11_en.png | 4 ++-- .../images/features.joinroom.impl_JoinRoomView_Day_12_en.png | 3 +++ .../images/features.joinroom.impl_JoinRoomView_Day_4_en.png | 4 ++-- .../images/features.joinroom.impl_JoinRoomView_Day_5_en.png | 4 ++-- .../images/features.joinroom.impl_JoinRoomView_Day_6_en.png | 4 ++-- .../images/features.joinroom.impl_JoinRoomView_Day_7_en.png | 4 ++-- .../images/features.joinroom.impl_JoinRoomView_Day_8_en.png | 4 ++-- .../images/features.joinroom.impl_JoinRoomView_Day_9_en.png | 4 ++-- .../features.joinroom.impl_JoinRoomView_Night_10_en.png | 4 ++-- .../features.joinroom.impl_JoinRoomView_Night_11_en.png | 4 ++-- .../features.joinroom.impl_JoinRoomView_Night_12_en.png | 3 +++ .../images/features.joinroom.impl_JoinRoomView_Night_4_en.png | 4 ++-- .../images/features.joinroom.impl_JoinRoomView_Night_5_en.png | 4 ++-- .../images/features.joinroom.impl_JoinRoomView_Night_6_en.png | 4 ++-- .../images/features.joinroom.impl_JoinRoomView_Night_7_en.png | 4 ++-- .../images/features.joinroom.impl_JoinRoomView_Night_8_en.png | 4 ++-- .../images/features.joinroom.impl_JoinRoomView_Night_9_en.png | 4 ++-- 18 files changed, 38 insertions(+), 32 deletions(-) create mode 100644 tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Day_12_en.png create mode 100644 tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Night_12_en.png diff --git a/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Day_10_en.png b/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Day_10_en.png index d28af79e36a..6d0ff2554ec 100644 --- a/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Day_10_en.png +++ b/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Day_10_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:916516ede645eaff617b40e6cf50acf2ba1e583827d778d22e9a012fe367fe7a -size 106146 +oid sha256:a9d0338485aabe5296754868ce2fcd5097d914eea28298ec11c16f7161ae2341 +size 111617 diff --git a/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Day_11_en.png b/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Day_11_en.png index 15fef4a0842..deabc9b36a5 100644 --- a/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Day_11_en.png +++ b/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Day_11_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a6eee1185065c82f90cf53d7b9fd62e6de72d907606099b0536b6305ea9537f2 -size 117250 +oid sha256:45040e44ee78a5103ebf1a3963c24f1a201485affa3f24d8f707e4f99be6cafd +size 112406 diff --git a/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Day_12_en.png b/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Day_12_en.png new file mode 100644 index 00000000000..15fef4a0842 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Day_12_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a6eee1185065c82f90cf53d7b9fd62e6de72d907606099b0536b6305ea9537f2 +size 117250 diff --git a/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Day_4_en.png b/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Day_4_en.png index 6d0ff2554ec..3fcad9605e8 100644 --- a/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Day_4_en.png +++ b/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Day_4_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a9d0338485aabe5296754868ce2fcd5097d914eea28298ec11c16f7161ae2341 -size 111617 +oid sha256:3463e70cd08f4d884f8bfafe7d66c5b75ac1fc05bf70cf1478a9f11def071069 +size 111151 diff --git a/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Day_5_en.png b/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Day_5_en.png index 3fcad9605e8..da1fd14667f 100644 --- a/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Day_5_en.png +++ b/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Day_5_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:3463e70cd08f4d884f8bfafe7d66c5b75ac1fc05bf70cf1478a9f11def071069 -size 111151 +oid sha256:70c33e148a040ec24287f9ca48353a76e8167015f24d8249bff405e9cc9f16ff +size 118640 diff --git a/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Day_6_en.png b/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Day_6_en.png index da1fd14667f..aaab740c4f2 100644 --- a/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Day_6_en.png +++ b/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Day_6_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:70c33e148a040ec24287f9ca48353a76e8167015f24d8249bff405e9cc9f16ff -size 118640 +oid sha256:9b3e666dc4693d7c096dd5c0168770f72be41c41797a93e7c728a20b587ddaba +size 92658 diff --git a/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Day_7_en.png b/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Day_7_en.png index aaab740c4f2..28403e285ee 100644 --- a/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Day_7_en.png +++ b/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Day_7_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:9b3e666dc4693d7c096dd5c0168770f72be41c41797a93e7c728a20b587ddaba -size 92658 +oid sha256:9af5a8c8a529eb5f8ea40e9c8028ce2c0ca4b352ef80b2778fa5122cc6bfa937 +size 96826 diff --git a/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Day_8_en.png b/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Day_8_en.png index 28403e285ee..8cb6932f435 100644 --- a/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Day_8_en.png +++ b/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Day_8_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:9af5a8c8a529eb5f8ea40e9c8028ce2c0ca4b352ef80b2778fa5122cc6bfa937 -size 96826 +oid sha256:084e303ed61e399ddbefda7e54cadb69545eb0db9493185aa48a3db7ba69fb04 +size 112515 diff --git a/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Day_9_en.png b/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Day_9_en.png index 8cb6932f435..d28af79e36a 100644 --- a/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Day_9_en.png +++ b/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Day_9_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:084e303ed61e399ddbefda7e54cadb69545eb0db9493185aa48a3db7ba69fb04 -size 112515 +oid sha256:916516ede645eaff617b40e6cf50acf2ba1e583827d778d22e9a012fe367fe7a +size 106146 diff --git a/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Night_10_en.png b/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Night_10_en.png index b1833d04599..17884e72828 100644 --- a/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Night_10_en.png +++ b/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Night_10_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a9f9d59037ba084e60e6324e066736bc08c0b52319664d67eb84779df6806ce4 -size 91377 +oid sha256:88584b1d4a4876e68e2972f9bbd03156127ee9b552de1ec20a9057d8f6cb1828 +size 101296 diff --git a/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Night_11_en.png b/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Night_11_en.png index 29dcd629aa0..1f4cc5b6168 100644 --- a/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Night_11_en.png +++ b/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Night_11_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:07458d183bae7ecfb7ee61bb6f2e0abb9a4399dd373068002fec3722f575e754 -size 102438 +oid sha256:cafbd46dbff04191aeabb2ea403d99728972c1854116022e545b4ca6be7bc675 +size 102209 diff --git a/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Night_12_en.png b/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Night_12_en.png new file mode 100644 index 00000000000..29dcd629aa0 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Night_12_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:07458d183bae7ecfb7ee61bb6f2e0abb9a4399dd373068002fec3722f575e754 +size 102438 diff --git a/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Night_4_en.png b/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Night_4_en.png index 17884e72828..9d57ee0ac22 100644 --- a/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Night_4_en.png +++ b/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Night_4_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:88584b1d4a4876e68e2972f9bbd03156127ee9b552de1ec20a9057d8f6cb1828 -size 101296 +oid sha256:b1e7887e1120c852e5a9086dba35fd8e52485d0e285c2e3724687ffa71babd45 +size 96405 diff --git a/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Night_5_en.png b/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Night_5_en.png index 9d57ee0ac22..e0062f755bb 100644 --- a/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Night_5_en.png +++ b/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Night_5_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:b1e7887e1120c852e5a9086dba35fd8e52485d0e285c2e3724687ffa71babd45 -size 96405 +oid sha256:c3d75eca5904d605b91becebca60199f7e60e6f2bec6b9a945ce8d130cfd7e47 +size 104802 diff --git a/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Night_6_en.png b/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Night_6_en.png index e0062f755bb..c382416a8b0 100644 --- a/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Night_6_en.png +++ b/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Night_6_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c3d75eca5904d605b91becebca60199f7e60e6f2bec6b9a945ce8d130cfd7e47 -size 104802 +oid sha256:e97d78225215b0b5e13f369485e7503d020baa7d157cb1c6826d18759d580c6e +size 78221 diff --git a/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Night_7_en.png b/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Night_7_en.png index c382416a8b0..65edf4ebd39 100644 --- a/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Night_7_en.png +++ b/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Night_7_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:e97d78225215b0b5e13f369485e7503d020baa7d157cb1c6826d18759d580c6e -size 78221 +oid sha256:95f818f0426868414b0ef5cb525254ad67811ec777c31a435072fb2236914f22 +size 82448 diff --git a/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Night_8_en.png b/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Night_8_en.png index 65edf4ebd39..d979aa4f0d7 100644 --- a/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Night_8_en.png +++ b/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Night_8_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:95f818f0426868414b0ef5cb525254ad67811ec777c31a435072fb2236914f22 -size 82448 +oid sha256:050785374d848e773941d858848e34f5d1753fcdada4dcef548a98eb5e78c31a +size 99409 diff --git a/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Night_9_en.png b/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Night_9_en.png index d979aa4f0d7..b1833d04599 100644 --- a/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Night_9_en.png +++ b/tests/uitests/src/test/snapshots/images/features.joinroom.impl_JoinRoomView_Night_9_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:050785374d848e773941d858848e34f5d1753fcdada4dcef548a98eb5e78c31a -size 99409 +oid sha256:a9f9d59037ba084e60e6324e066736bc08c0b52319664d67eb84779df6806ce4 +size 91377 From 9a5d4fc2f5ab0a5d4f1f038e339b47cb876bd180 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Fri, 29 Nov 2024 15:15:24 +0100 Subject: [PATCH 62/96] Fix kover rule (PdfViewerState has moved) Remove obsolete items Reorder items. --- .../main/kotlin/extension/KoverExtension.kt | 28 ++++++++----------- 1 file changed, 11 insertions(+), 17 deletions(-) diff --git a/plugins/src/main/kotlin/extension/KoverExtension.kt b/plugins/src/main/kotlin/extension/KoverExtension.kt index 6fbb18e1874..b690dd492ce 100644 --- a/plugins/src/main/kotlin/extension/KoverExtension.kt +++ b/plugins/src/main/kotlin/extension/KoverExtension.kt @@ -169,26 +169,20 @@ fun Project.setupKover() { filters { excludes.classes( "*State$*", // Exclude inner classes - "io.element.android.appnav.root.RootNavState*", - "io.element.android.libraries.matrix.api.timeline.item.event.OtherState$*", - "io.element.android.libraries.matrix.api.timeline.item.event.EventSendState$*", - "io.element.android.libraries.matrix.api.room.RoomMembershipState*", - "io.element.android.libraries.matrix.api.room.MatrixRoomMembersState*", - "io.element.android.libraries.push.impl.notifications.NotificationState*", - "io.element.android.features.messages.impl.media.local.pdf.PdfViewerState", - "io.element.android.features.messages.impl.media.local.LocalMediaViewState", - "io.element.android.features.location.impl.map.MapState*", - "io.element.android.libraries.matrix.api.timeline.item.event.LocalEventSendState*", - "io.element.android.libraries.designsystem.swipe.SwipeableActionsState*", - "io.element.android.features.messages.impl.timeline.components.ExpandableState*", - "io.element.android.features.messages.impl.timeline.model.bubble.BubbleState*", - "io.element.android.libraries.maplibre.compose.CameraPositionState*", - "io.element.android.libraries.maplibre.compose.SaveableCameraPositionState", - "io.element.android.libraries.maplibre.compose.SymbolState*", + "io.element.android.appnav.root.RootNavState", "io.element.android.features.ftue.api.state.*", "io.element.android.features.ftue.impl.welcome.state.*", + "io.element.android.features.messages.impl.timeline.model.bubble.BubbleState", + "io.element.android.libraries.designsystem.swipe.SwipeableActionsState", "io.element.android.libraries.designsystem.theme.components.bottomsheet.CustomSheetState", - "io.element.android.libraries.mediaviewer.api.local.pdf.PdfViewerState", + "io.element.android.libraries.maplibre.compose.CameraPositionState", + "io.element.android.libraries.maplibre.compose.SaveableCameraPositionState", + "io.element.android.libraries.maplibre.compose.SymbolState", + "io.element.android.libraries.matrix.api.room.RoomMembershipState", + "io.element.android.libraries.matrix.api.room.MatrixRoomMembersState", + "io.element.android.libraries.matrix.api.timeline.item.event.OtherState$*", + "io.element.android.libraries.matrix.api.timeline.item.event.LocalEventSendState*", + "io.element.android.libraries.mediaviewer.impl.local.pdf.PdfViewerState", "io.element.android.libraries.textcomposer.model.TextEditorState", ) includes.classes("*State") From 350a47cc22e634b0447a4529db86f971f379a9ea Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Fri, 29 Nov 2024 15:18:09 +0100 Subject: [PATCH 63/96] Fix wrong name. --- ...omeScreenState.kt => SharedPreferencesWelcomeScreenStore.kt} | 2 +- ...emoryWelcomeScreenState.kt => InMemoryWelcomeScreenStore.kt} | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) rename features/ftue/impl/src/main/kotlin/io/element/android/features/ftue/impl/welcome/state/{SharedPreferencesWelcomeScreenState.kt => SharedPreferencesWelcomeScreenStore.kt} (94%) rename features/ftue/impl/src/test/kotlin/io/element/android/features/ftue/impl/welcome/state/{InMemoryWelcomeScreenState.kt => InMemoryWelcomeScreenStore.kt} (90%) diff --git a/features/ftue/impl/src/main/kotlin/io/element/android/features/ftue/impl/welcome/state/SharedPreferencesWelcomeScreenState.kt b/features/ftue/impl/src/main/kotlin/io/element/android/features/ftue/impl/welcome/state/SharedPreferencesWelcomeScreenStore.kt similarity index 94% rename from features/ftue/impl/src/main/kotlin/io/element/android/features/ftue/impl/welcome/state/SharedPreferencesWelcomeScreenState.kt rename to features/ftue/impl/src/main/kotlin/io/element/android/features/ftue/impl/welcome/state/SharedPreferencesWelcomeScreenStore.kt index 551a00dd209..b03ccae482b 100644 --- a/features/ftue/impl/src/main/kotlin/io/element/android/features/ftue/impl/welcome/state/SharedPreferencesWelcomeScreenState.kt +++ b/features/ftue/impl/src/main/kotlin/io/element/android/features/ftue/impl/welcome/state/SharedPreferencesWelcomeScreenStore.kt @@ -16,7 +16,7 @@ import javax.inject.Inject @ContributesBinding(AppScope::class) @SingleIn(AppScope::class) -class SharedPreferencesWelcomeScreenState @Inject constructor( +class SharedPreferencesWelcomeScreenStore @Inject constructor( private val sharedPreferences: SharedPreferences, ) : WelcomeScreenStore { companion object { diff --git a/features/ftue/impl/src/test/kotlin/io/element/android/features/ftue/impl/welcome/state/InMemoryWelcomeScreenState.kt b/features/ftue/impl/src/test/kotlin/io/element/android/features/ftue/impl/welcome/state/InMemoryWelcomeScreenStore.kt similarity index 90% rename from features/ftue/impl/src/test/kotlin/io/element/android/features/ftue/impl/welcome/state/InMemoryWelcomeScreenState.kt rename to features/ftue/impl/src/test/kotlin/io/element/android/features/ftue/impl/welcome/state/InMemoryWelcomeScreenStore.kt index a310a43a7f3..cf3a73f490a 100644 --- a/features/ftue/impl/src/test/kotlin/io/element/android/features/ftue/impl/welcome/state/InMemoryWelcomeScreenState.kt +++ b/features/ftue/impl/src/test/kotlin/io/element/android/features/ftue/impl/welcome/state/InMemoryWelcomeScreenStore.kt @@ -7,7 +7,7 @@ package io.element.android.features.ftue.impl.welcome.state -class InMemoryWelcomeScreenState : WelcomeScreenStore { +class InMemoryWelcomeScreenStore : WelcomeScreenStore { private var isWelcomeScreenNeeded = true override fun isWelcomeScreenNeeded(): Boolean { From efabf712a8e4291aa124f548efea8f0e1ffcba59 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Fri, 29 Nov 2024 15:19:09 +0100 Subject: [PATCH 64/96] Fix wrong name. --- .../reactionsummary/ReactionSummaryStateProvider.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/reactionsummary/ReactionSummaryStateProvider.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/reactionsummary/ReactionSummaryStateProvider.kt index 7f6f8ee4365..3100d90d452 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/reactionsummary/ReactionSummaryStateProvider.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/reactionsummary/ReactionSummaryStateProvider.kt @@ -12,10 +12,10 @@ import io.element.android.features.messages.impl.timeline.aTimelineItemReactions import io.element.android.libraries.matrix.api.core.EventId open class ReactionSummaryStateProvider : PreviewParameterProvider { - override val values = sequenceOf(anActionListState()) + override val values = sequenceOf(aReactionSummaryState()) } -fun anActionListState(): ReactionSummaryState { +fun aReactionSummaryState(): ReactionSummaryState { val reactions = aTimelineItemReactions(8, true).reactions return ReactionSummaryState( target = ReactionSummaryState.Summary( From 5f8007d6f11bf7abc5354fa45c0b68cef7a7e67e Mon Sep 17 00:00:00 2001 From: bmarty <3940906+bmarty@users.noreply.github.com> Date: Mon, 2 Dec 2024 00:30:02 +0000 Subject: [PATCH 65/96] Sync Strings from Localazy --- .../src/main/res/values-de/translations.xml | 19 +- .../impl/src/main/res/values/localazy.xml | 2 +- .../src/main/res/values-de/translations.xml | 14 + .../src/main/res/values-de/translations.xml | 7 + .../src/main/res/values-de/translations.xml | 1 + .../src/main/res/values-fr/translations.xml | 1 + .../src/main/res/values-ru/translations.xml | 1 + .../src/main/res/values-de/translations.xml | 1 + .../src/main/res/values-de/translations.xml | 1 + .../src/main/res/values-fr/translations.xml | 1 + .../src/main/res/values-de/translations.xml | 2 + .../src/main/res/values-de/translations.xml | 7 +- .../src/main/res/values-de/translations.xml | 21 +- .../src/main/res/values-de/translations.xml | 2 + .../src/main/res/values-de/translations.xml | 14 + .../src/main/res/values-pl/translations.xml | 3 + .../src/main/res/values-de/translations.xml | 2 +- .../src/main/res/values-de/translations.xml | 2 + .../src/main/res/values-de/translations.xml | 1 + .../src/main/res/values-et/translations.xml | 2 +- .../src/main/res/values-de/translations.xml | 55 + .../src/main/res/values-el/translations.xml | 13 + .../src/main/res/values-et/translations.xml | 13 + .../src/main/res/values-fr/translations.xml | 33 + .../src/main/res/values-ru/translations.xml | 13 + .../src/main/res/values/localazy.xml | 11 + ...nfigureroom_ConfigureRoomViewDark_0_de.png | 4 +- ...nfigureroom_ConfigureRoomViewDark_1_de.png | 4 +- ...nfigureroom_ConfigureRoomViewDark_2_de.png | 4 +- ...nfigureroom_ConfigureRoomViewDark_3_de.png | 4 +- ...nfigureroom_ConfigureRoomViewDark_4_de.png | 4 +- ...nfigureroom_ConfigureRoomViewDark_5_de.png | 4 +- ...figureroom_ConfigureRoomViewLight_0_de.png | 4 +- ...figureroom_ConfigureRoomViewLight_1_de.png | 4 +- ...figureroom_ConfigureRoomViewLight_2_de.png | 4 +- ...figureroom_ConfigureRoomViewLight_3_de.png | 4 +- ...figureroom_ConfigureRoomViewLight_4_de.png | 4 +- ...figureroom_ConfigureRoomViewLight_5_de.png | 4 +- ...s.joinroom.impl_JoinRoomView_Day_10_de.png | 3 + ...s.joinroom.impl_JoinRoomView_Day_11_de.png | 3 + ...s.joinroom.impl_JoinRoomView_Day_12_de.png | 3 + ...es.joinroom.impl_JoinRoomView_Day_4_de.png | 4 +- ...es.joinroom.impl_JoinRoomView_Day_5_de.png | 4 +- ...es.joinroom.impl_JoinRoomView_Day_6_de.png | 4 +- ...es.joinroom.impl_JoinRoomView_Day_7_de.png | 4 +- ...es.joinroom.impl_JoinRoomView_Day_8_de.png | 4 +- ...es.joinroom.impl_JoinRoomView_Day_9_de.png | 3 - ....qrcode.intro_QrCodeIntroView_Day_0_de.png | 4 +- ....impl_AccountDeactivationView_Day_0_de.png | 4 +- ....impl_AccountDeactivationView_Day_1_de.png | 3 + ....impl_AccountDeactivationView_Day_2_de.png | 4 +- ....impl_AccountDeactivationView_Day_3_de.png | 4 +- ....impl_AccountDeactivationView_Day_4_de.png | 4 +- ...onlist_ActionListViewContent_Day_10_de.png | 4 +- ...onlist_ActionListViewContent_Day_11_de.png | 4 +- ...onlist_ActionListViewContent_Day_12_de.png | 4 +- ...ionlist_ActionListViewContent_Day_2_de.png | 4 +- ...ionlist_ActionListViewContent_Day_3_de.png | 4 +- ...ionlist_ActionListViewContent_Day_4_de.png | 4 +- ...ionlist_ActionListViewContent_Day_5_de.png | 4 +- ...ionlist_ActionListViewContent_Day_6_de.png | 4 +- ...ionlist_ActionListViewContent_Day_7_de.png | 4 +- ...ionlist_ActionListViewContent_Day_8_de.png | 4 +- ...ionlist_ActionListViewContent_Day_9_de.png | 4 +- ...tachments.preview_AttachmentsView_0_de.png | 3 + ...tachments.preview_AttachmentsView_1_de.png | 3 + ...tachments.preview_AttachmentsView_2_de.png | 3 + ...tachments.preview_AttachmentsView_3_de.png | 3 + ...tachments.preview_AttachmentsView_4_de.png | 4 +- ...tachments.preview_AttachmentsView_5_de.png | 4 +- ...tachments.preview_AttachmentsView_6_de.png | 3 + ...ntity_IdentityChangeStateView_Day_1_de.png | 4 +- ...ntity_IdentityChangeStateView_Day_2_de.png | 4 +- ...essagesViewWithIdentityChange_Day_1_de.png | 4 +- ...essagesViewWithIdentityChange_Day_2_de.png | 4 +- ...ent_TimelineItemEncryptedView_Day_2_de.png | 3 + ...ent_TimelineItemEncryptedView_Day_3_de.png | 3 + ...ItemImageViewHideMediaContent_Day_0_de.png | 3 + ...elineItemLegacyCallInviteView_Day_0_de.png | 3 + ...ItemVideoViewHideMediaContent_Day_0_de.png | 3 + ...nents_TimelineItemEventRowUtd_Day_0_de.png | 4 +- ...line.protection_ProtectedView_Day_0_de.png | 3 + ...line.protection_ProtectedView_Day_1_de.png | 3 + ...line.protection_ProtectedView_Day_2_de.png | 3 + ...line.protection_ProtectedView_Day_3_de.png | 3 + ...advanced_AdvancedSettingsView_Day_0_de.png | 4 +- ...advanced_AdvancedSettingsView_Day_1_de.png | 4 +- ...advanced_AdvancedSettingsView_Day_2_de.png | 4 +- ...advanced_AdvancedSettingsView_Day_3_de.png | 4 +- ...advanced_AdvancedSettingsView_Day_4_de.png | 4 +- ...impl.root_PreferencesRootViewDark_0_de.png | 4 +- ...impl.root_PreferencesRootViewDark_1_de.png | 4 +- ...mpl.root_PreferencesRootViewLight_0_de.png | 4 +- ...mpl.root_PreferencesRootViewLight_1_de.png | 4 +- ...ents_ConfirmRecoveryKeyBanner_Day_0_de.png | 4 +- ...pl.components_RoomSummaryRow_Day_32_de.png | 3 + ...pl.components_RoomSummaryRow_Day_33_de.png | 3 + ...es.roomlist.impl_RoomListView_Day_6_de.png | 4 +- ...ureBackupEnterRecoveryKeyView_Day_0_de.png | 4 +- ...ureBackupEnterRecoveryKeyView_Day_1_de.png | 4 +- ...ureBackupEnterRecoveryKeyView_Day_2_de.png | 4 +- ...ureBackupEnterRecoveryKeyView_Day_3_de.png | 4 +- ...et.root_ResetIdentityRootView_Day_0_de.png | 4 +- ...et.root_ResetIdentityRootView_Day_1_de.png | 4 +- ...mpl.root_SecureBackupRootView_Day_0_de.png | 4 +- ...pl.root_SecureBackupRootView_Day_10_de.png | 4 +- ...pl.root_SecureBackupRootView_Day_11_de.png | 4 +- ...pl.root_SecureBackupRootView_Day_12_de.png | 4 +- ...pl.root_SecureBackupRootView_Day_13_de.png | 4 +- ...pl.root_SecureBackupRootView_Day_14_de.png | 4 +- ...pl.root_SecureBackupRootView_Day_15_de.png | 4 +- ...pl.root_SecureBackupRootView_Day_16_de.png | 4 +- ...pl.root_SecureBackupRootView_Day_17_de.png | 4 +- ...mpl.root_SecureBackupRootView_Day_1_de.png | 4 +- ...mpl.root_SecureBackupRootView_Day_2_de.png | 4 +- ...mpl.root_SecureBackupRootView_Day_3_de.png | 4 +- ...mpl.root_SecureBackupRootView_Day_4_de.png | 4 +- ...mpl.root_SecureBackupRootView_Day_5_de.png | 4 +- ...mpl.root_SecureBackupRootView_Day_6_de.png | 4 +- ...mpl.root_SecureBackupRootView_Day_7_de.png | 4 +- ...mpl.root_SecureBackupRootView_Day_8_de.png | 4 +- ...mpl.root_SecureBackupRootView_Day_9_de.png | 4 +- ...l.setup.views_RecoveryKeyView_Day_0_de.png | 4 +- ...l.setup.views_RecoveryKeyView_Day_1_de.png | 4 +- ...l.setup.views_RecoveryKeyView_Day_4_de.png | 4 +- ...l.setup.views_RecoveryKeyView_Day_5_de.png | 4 +- ...p_SecureBackupSetupViewChange_Day_0_de.png | 4 +- ...p_SecureBackupSetupViewChange_Day_1_de.png | 4 +- ...p_SecureBackupSetupViewChange_Day_2_de.png | 4 +- ...p_SecureBackupSetupViewChange_Day_3_de.png | 4 +- ...l.setup_SecureBackupSetupView_Day_0_de.png | 4 +- ...l.setup_SecureBackupSetupView_Day_1_de.png | 4 +- ...l.setup_SecureBackupSetupView_Day_2_de.png | 4 +- ...l.setup_SecureBackupSetupView_Day_3_de.png | 4 +- ...ared_UserProfileHeaderSection_Day_0_de.png | 3 + ...rofile.shared_UserProfileView_Day_0_de.png | 4 +- ...rofile.shared_UserProfileView_Day_1_de.png | 4 +- ...rofile.shared_UserProfileView_Day_2_de.png | 4 +- ...rofile.shared_UserProfileView_Day_3_de.png | 4 +- ...rofile.shared_UserProfileView_Day_4_de.png | 4 +- ...rofile.shared_UserProfileView_Day_6_de.png | 4 +- ...rofile.shared_UserProfileView_Day_7_de.png | 4 +- ...ncoming.ui_SessionDetailsView_Day_0_de.png | 3 + ...ming_IncomingVerificationView_Day_0_de.png | 3 + ...ming_IncomingVerificationView_Day_1_de.png | 4 +- ...ming_IncomingVerificationView_Day_5_de.png | 4 +- ...ming_IncomingVerificationView_Day_6_de.png | 4 +- ...ming_IncomingVerificationView_Day_7_de.png | 4 +- ...utgoing_VerifySelfSessionView_Day_0_de.png | 4 +- ...tgoing_VerifySelfSessionView_Day_10_de.png | 4 +- ...tgoing_VerifySelfSessionView_Day_13_de.png | 4 +- ...utgoing_VerifySelfSessionView_Day_1_de.png | 4 +- ...utgoing_VerifySelfSessionView_Day_4_de.png | 4 +- ...utgoing_VerifySelfSessionView_Day_7_de.png | 4 +- ...utgoing_VerifySelfSessionView_Day_8_de.png | 4 +- ...mposer_TextComposerAddCaption_Day_0_de.png | 4 +- ...tcomposer_TextComposerCaption_Day_0_de.png | 3 + ...poser_TextComposerEditCaption_Day_0_de.png | 4 +- screenshots/html/data.js | 1323 +++++++++-------- ...nfigureroom_ConfigureRoomViewDark_3_en.png | 4 +- ...figureroom_ConfigureRoomViewLight_3_en.png | 4 +- 161 files changed, 1180 insertions(+), 896 deletions(-) create mode 100644 features/deactivation/impl/src/main/res/values-de/translations.xml create mode 100644 screenshots/de/features.joinroom.impl_JoinRoomView_Day_10_de.png create mode 100644 screenshots/de/features.joinroom.impl_JoinRoomView_Day_11_de.png create mode 100644 screenshots/de/features.joinroom.impl_JoinRoomView_Day_12_de.png delete mode 100644 screenshots/de/features.joinroom.impl_JoinRoomView_Day_9_de.png create mode 100644 screenshots/de/features.logout.impl_AccountDeactivationView_Day_1_de.png create mode 100644 screenshots/de/features.messages.impl.attachments.preview_AttachmentsView_0_de.png create mode 100644 screenshots/de/features.messages.impl.attachments.preview_AttachmentsView_1_de.png create mode 100644 screenshots/de/features.messages.impl.attachments.preview_AttachmentsView_2_de.png create mode 100644 screenshots/de/features.messages.impl.attachments.preview_AttachmentsView_3_de.png create mode 100644 screenshots/de/features.messages.impl.attachments.preview_AttachmentsView_6_de.png create mode 100644 screenshots/de/features.messages.impl.timeline.components.event_TimelineItemEncryptedView_Day_2_de.png create mode 100644 screenshots/de/features.messages.impl.timeline.components.event_TimelineItemEncryptedView_Day_3_de.png create mode 100644 screenshots/de/features.messages.impl.timeline.components.event_TimelineItemImageViewHideMediaContent_Day_0_de.png create mode 100644 screenshots/de/features.messages.impl.timeline.components.event_TimelineItemLegacyCallInviteView_Day_0_de.png create mode 100644 screenshots/de/features.messages.impl.timeline.components.event_TimelineItemVideoViewHideMediaContent_Day_0_de.png create mode 100644 screenshots/de/features.messages.impl.timeline.protection_ProtectedView_Day_0_de.png create mode 100644 screenshots/de/features.messages.impl.timeline.protection_ProtectedView_Day_1_de.png create mode 100644 screenshots/de/features.messages.impl.timeline.protection_ProtectedView_Day_2_de.png create mode 100644 screenshots/de/features.messages.impl.timeline.protection_ProtectedView_Day_3_de.png create mode 100644 screenshots/de/features.roomlist.impl.components_RoomSummaryRow_Day_32_de.png create mode 100644 screenshots/de/features.roomlist.impl.components_RoomSummaryRow_Day_33_de.png create mode 100644 screenshots/de/features.userprofile.shared_UserProfileHeaderSection_Day_0_de.png create mode 100644 screenshots/de/features.verifysession.impl.incoming.ui_SessionDetailsView_Day_0_de.png create mode 100644 screenshots/de/features.verifysession.impl.incoming_IncomingVerificationView_Day_0_de.png create mode 100644 screenshots/de/libraries.textcomposer_TextComposerCaption_Day_0_de.png diff --git a/features/createroom/impl/src/main/res/values-de/translations.xml b/features/createroom/impl/src/main/res/values-de/translations.xml index 441f747e7e2..09ad7532111 100644 --- a/features/createroom/impl/src/main/res/values-de/translations.xml +++ b/features/createroom/impl/src/main/res/values-de/translations.xml @@ -3,11 +3,22 @@ "Neuer Raum" "Personen einladen" "Beim Erstellen des Chats ist ein Fehler aufgetreten" - "Die Nachrichten in diesem Chat sind verschlüsselt. Die Verschlüsselung kann nicht nachträglich deaktiviert werden." - "Privater Raum (nur auf Einladung)" - "Die Nachrichten sind nicht verschlüsselt und können von jedem gelesen werden. Die Verschlüsselung kann zu einem späteren Zeitpunkt aktiviert werden." - "Öffentlicher Raum (für alle)" + "Nur eingeladene Personen haben Zutritt zu diesem Chatroom. Alle Nachrichten sind durchgehend verschlüsselt." + "Privater Chatroom" + "Jeder kann diesen Chatroom finden. +Sie können dies aber jederzeit in den Chatroomeinstellungen ändern." + "Öffentlicher Chatroom" + "Jeder kann diesem Chatroom beitreten" + "Jemand" + "Chatroom Zugang" + "Jeder kann darum bitten, dem Chatroom beizutreten, aber ein Administrator oder ein Moderator muss die Anfrage akzeptieren." + "Beitritt beantragen" + "Einige Zeichen sind nicht erlaubt. Es werden nur Buchstaben, Ziffern und die folgenden Symbole unterstützt: ! $ & ‘ ( ) * + / ; = ? @ [ ] - . _" + "Diese Chatroomadresse existiert bereits. Bitte versuchen Sie, das Adressenfeld des Chatrooms zu bearbeiten oder den Namen des Chatrooms zu ändern" + "Damit dieser Chatroom im öffentlichen Chatroomverzeichnis sichtbar ist, benötigen Sie eine Chatroomadresse." + "Chatroom Adresse" "Raumname" + " Sichtbarkeit des Chatrooms" "Raum erstellen" "Thema (optional)" "Beim Versuch, einen Chat zu starten, ist ein Fehler aufgetreten" diff --git a/features/createroom/impl/src/main/res/values/localazy.xml b/features/createroom/impl/src/main/res/values/localazy.xml index 7900aef8013..7a08c7af877 100644 --- a/features/createroom/impl/src/main/res/values/localazy.xml +++ b/features/createroom/impl/src/main/res/values/localazy.xml @@ -14,7 +14,7 @@ You can change this anytime in room settings." "Anyone can ask to join the room but an administrator or a moderator will have to accept the request" "Ask to join" "Some characters are not allowed. Only letters, digits and the following symbols are supported ! $ & ‘ ( ) * + / ; = ? @ [ ] - . _" - "This room address already exists, please try editing the room address field or change the room name" + "This room address already exists. Please try editing the room address field or change the room name" "In order for this room to be visible in the public room directory, you will need a room address." "Room address" "Room name" diff --git a/features/deactivation/impl/src/main/res/values-de/translations.xml b/features/deactivation/impl/src/main/res/values-de/translations.xml new file mode 100644 index 00000000000..0830d6ba3f9 --- /dev/null +++ b/features/deactivation/impl/src/main/res/values-de/translations.xml @@ -0,0 +1,14 @@ + + + "Bitte bestätigen Sie, dass Sie Ihr Benutzerkonto deaktivieren möchten. Diese Aktion kann nicht rückgängig gemacht werden." + "Lösche alle meine Nachrichten" + "Warnung: Benutzern werden möglicherweise unvollständige Konversationen angezeigt." + "Wenn Sie Ihr Konto deaktivieren%1$s, wird es:" + "irreversibel" + "%1$s Ihr Konto (Sie können sich nicht erneut anmelden und Ihre ID kann nicht wiederverwendet werden)." + "Dauerhaft deaktivieren" + "Sie werden aus allen Chatrooms entfernt." + "Löschen Sie Ihre Kontoinformationen von unserem Identitätsserver." + "Gelöschte Nachrichten werden für bereits registrierte Benutzer weiterhin sichtbar sein, wenn sie auch neuen oder nicht registrierten Benutzern nicht mehr zur Verfügung stehen." + "Benutzerkonto deaktivieren" + diff --git a/features/joinroom/impl/src/main/res/values-de/translations.xml b/features/joinroom/impl/src/main/res/values-de/translations.xml index 95718ce3718..cbdf0c34a37 100644 --- a/features/joinroom/impl/src/main/res/values-de/translations.xml +++ b/features/joinroom/impl/src/main/res/values-de/translations.xml @@ -1,7 +1,14 @@ + "Anfrage abbrechen" + "Ja, abbrechen" + "Möchten Sie Ihre Beitrittsanfrage für diesen Chatroom wirklich stornieren?" + "Beitrittsanfrage stornieren" "Raum beitreten" "Anklopfen" + "Nachricht (optional)" + "Falls Ihre Anfrage, dem Raum beizutreten, akzeptiert wird, werden Sie eine Einladung erhalten." + "Beitrittsanfrage geschickt" "%1$s unterstützt noch keine Spaces. Du kannst auf Spaces im Web zugreifen." "Spaces werden noch nicht unterstützt" "Klopfe an um einen Administrator zu benachrichtigen. Nach der Freigabe kannst du dich an der Unterhaltung beteiligen." diff --git a/features/lockscreen/impl/src/main/res/values-de/translations.xml b/features/lockscreen/impl/src/main/res/values-de/translations.xml index 4042df3d1b0..e56938285cc 100644 --- a/features/lockscreen/impl/src/main/res/values-de/translations.xml +++ b/features/lockscreen/impl/src/main/res/values-de/translations.xml @@ -3,6 +3,7 @@ "biometrische Authentifizierung" "biometrisches Entsperren" "Mit Biometrie entsperren" + "Biometrische Daten bestätigen" "PIN vergessen?" "PIN-Code ändern" "Biometrisches Entsperren zulassen" diff --git a/features/lockscreen/impl/src/main/res/values-fr/translations.xml b/features/lockscreen/impl/src/main/res/values-fr/translations.xml index a8b3757022b..b77df23254c 100644 --- a/features/lockscreen/impl/src/main/res/values-fr/translations.xml +++ b/features/lockscreen/impl/src/main/res/values-fr/translations.xml @@ -3,6 +3,7 @@ "l’authentification biométrique" "déverrouillage biométrique" "Déverrouiller avec la biométrie" + "Confirmer la biométrie" "Code PIN oublié?" "Modifier le code PIN" "Autoriser le déverrouillage biométrique" diff --git a/features/lockscreen/impl/src/main/res/values-ru/translations.xml b/features/lockscreen/impl/src/main/res/values-ru/translations.xml index a70ff5015c0..eae4799f937 100644 --- a/features/lockscreen/impl/src/main/res/values-ru/translations.xml +++ b/features/lockscreen/impl/src/main/res/values-ru/translations.xml @@ -3,6 +3,7 @@ "биометрическая идентификация" "биометрическая разблокировка" "Разблокировать с помощью биометрии" + "Подтвердить биометрические данные" "Забыли PIN-код?" "Изменить PIN-код" "Разрешить биометрическую разблокировку" diff --git a/features/login/impl/src/main/res/values-de/translations.xml b/features/login/impl/src/main/res/values-de/translations.xml index 10ed45beee3..468056f6b7e 100644 --- a/features/login/impl/src/main/res/values-de/translations.xml +++ b/features/login/impl/src/main/res/values-de/translations.xml @@ -60,6 +60,7 @@ Versuche, dich manuell anzumelden, oder scanne den QR-Code mit einem anderen Ger "Wähle %1$s" "\"Neues Gerät verknüpfen\"" "Scanne den QR-Code mit diesem Gerät" + "Nur verfügbar für den Fall dass Ihr Kontoanbieter dies unterstützt." "Öffne %1$s auf einem anderen Gerät, um den QR-Code zu erhalten" "Verwende den QR-Code, der auf dem anderen Gerät angezeigt wird." "Erneut versuchen" diff --git a/features/messages/impl/src/main/res/values-de/translations.xml b/features/messages/impl/src/main/res/values-de/translations.xml index 785a615cab0..e235088a604 100644 --- a/features/messages/impl/src/main/res/values-de/translations.xml +++ b/features/messages/impl/src/main/res/values-de/translations.xml @@ -31,6 +31,7 @@ "Emoji hinzufügen" "Dies ist der Anfang von %1$s." "Dies ist der Anfang dieses Gesprächs." + "Anruftyp wird nicht unterstützt. Fragen Sie nach, ob der Anrufer die neue Element X-App verwenden kann." "Weniger anzeigen" "Nachricht wurde kopiert" "Du bist nicht berechtigt, in diesem Raum zu schreiben" diff --git a/features/messages/impl/src/main/res/values-fr/translations.xml b/features/messages/impl/src/main/res/values-fr/translations.xml index ab47aed0ca9..132d175eb8e 100644 --- a/features/messages/impl/src/main/res/values-fr/translations.xml +++ b/features/messages/impl/src/main/res/values-fr/translations.xml @@ -31,6 +31,7 @@ "Ajouter un émoji" "Ceci est le début de %1$s." "Ceci est le début de cette conversation." + "Appel non pris en charge. Demandez à l’appelant s’il peut utiliser la nouvelle application Element X pour vous appeler." "Afficher moins" "Message copié" "Vous n’êtes pas autorisé à publier dans ce salon" diff --git a/features/preferences/impl/src/main/res/values-de/translations.xml b/features/preferences/impl/src/main/res/values-de/translations.xml index 78046635799..7d83685eda0 100644 --- a/features/preferences/impl/src/main/res/values-de/translations.xml +++ b/features/preferences/impl/src/main/res/values-de/translations.xml @@ -8,6 +8,8 @@ "Benutzerdefinierte Element-Aufruf-Basis-URL" "Lege eine eigene Basis-URL für Element Call fest." "Ungültige URL, bitte stelle sicher, dass du das Protokoll (http/https) und die richtige Adresse angibst." + "Laden Sie Fotos und Videos schneller hoch und reduzieren Sie die Datennutzung" + "Optimieren Sie die Medienqualität" "Anbieter für Push-Benachrichtigungen" "Deaktiviere den Rich-Text-Editor, um Markdown manuell einzugeben." "Lesebestätigungen" diff --git a/features/roomlist/impl/src/main/res/values-de/translations.xml b/features/roomlist/impl/src/main/res/values-de/translations.xml index 8671c381b8b..3b8b70c40f2 100644 --- a/features/roomlist/impl/src/main/res/values-de/translations.xml +++ b/features/roomlist/impl/src/main/res/values-de/translations.xml @@ -7,8 +7,10 @@ "Erstelle einen neuen Wiederherstellungsschlüssel, mit dem du deinen verschlüsselten Nachrichtenverlauf wiederherstellen kannst, wenn du dich an einem neuen Gerät anmeldest." "Wiederherstellung einrichten" "Wiederherstellung einrichten" - "Dein Chat-Backup ist derzeit nicht synchronisiert. Du musst deinen Wiederherstellungsschlüssel bestätigen, um Zugriff auf dein Chat-Backup zu erhalten." - "Wiederherstellungsschlüssel bestätigen." + "Bestätigen Sie die Validität Ihres Wiederherstellungsschlüssels, um weiterhin auf Ihren Schlüsselspeicher und den Nachrichtenverlauf zugreifen zu können." + "Geben Sie Ihren Wiederherstellungsschlüssel ein" + "Haben Sie Ihren Wiederherstellungsschlüssel vergessen?" + "Ihr Schlüsselspeicher ist nicht synchronisiert" "Damit du keinen wichtigen Anruf verpasst, ändere bitte deine Einstellungen so, dass du bei gesperrtem Telefon Benachrichtigungen im Vollbildmodus erhältst." "Verbessere dein Anruferlebnis" "Möchtest du die Einladung zum Betreten von %1$s wirklich ablehnen?" @@ -17,6 +19,7 @@ "Einladung ablehnen" "Keine Einladungen" "%1$s (%2$s) hat dich eingeladen" + "Beitrittsanfrage geschickt" "Dies ist ein einmaliger Vorgang, danke fürs Warten." "Dein Konto wird eingerichtet." "Eine Unterthaltung oder Raum erstellen" diff --git a/features/securebackup/impl/src/main/res/values-de/translations.xml b/features/securebackup/impl/src/main/res/values-de/translations.xml index 7201aaba3ad..29e43e2e2f0 100644 --- a/features/securebackup/impl/src/main/res/values-de/translations.xml +++ b/features/securebackup/impl/src/main/res/values-de/translations.xml @@ -2,11 +2,15 @@ "Backup deaktivieren" "Backup aktivieren" - "Das Backup stellt sicher, dass du deinen Nachrichtenverlauf nicht verlierst. %1$s." - "Backup" + "Speichern Sie Ihre verschlüsselte Identität und Ihre codierten Nachrichtenschlüssel auf dem Server. Auf diese Weise können Sie Ihren Nachrichtenverlauf auf allen neuen Geräten einsehen. %1$s." + "Schlüsselspeicher" + "Der Schlüsselspeicher muss aktiviert sein, um Datenwiederherstellung zu ermöglichen." + "Schlüssel von diesem Gerät hochladen" + "Schlüsselspeicherung zulassen" "Wiederherstellungsschlüssel ändern" + "Stellen Sie Ihre verschlüsselte Identität und Ihren Nachrichtenverlauf mit einem Wiederherstellungsschlüssel wieder her, falls Sie den Zugang zu allen Ihren Geräten verloren haben." "Wiederherstellungsschlüssel eingeben" - "Dein Chat-Backup ist derzeit nicht synchronisiert." + "Dein Schlüssel ist derzeit nicht synchronisiert." "Wiederherstellung einrichten" "Erhalte Zugriff auf deine verschlüsselten Nachrichten, wenn du alle deine Geräte verlierst oder von %1$s überall abgemeldet bist." @@ -33,6 +37,8 @@ "Deine Kontodaten, Kontakte, Einstellungen und die Liste der Chats bleiben erhalten" "Du verlierst alle deine bisherigen Nachrichten sofern sie nicht auf einem anderen Gerät vorliegen" "Du musst alle deine bestehenden Geräte und Kontakte erneut verifizieren." + "Setzen Sie Ihre Identität nur dann zurück, wenn Sie keinen Zugriff auf ein anderes Ihrer angemeldeten Geräte und auch Ihren Wiederherstellungsschlüssel verloren haben." + "Sie können es nicht bestätigen? Dann müssen Sie Ihre Identität zurücksetzen." "Ausschalten" "Du verlierst deine verschlüsselten Nachrichten, wenn du auf allen Geräten abgemeldet bist." "Bist du sicher, dass du das Backup deaktivieren willst?" @@ -42,7 +48,7 @@ "Bist du sicher, dass du das Backup deaktivieren willst?" "Hier kannst Du einen neuen Wiederherstellungsschlüssel erstellen. Nachdem Du einen neuen Wiederherstellungsschlüssel erstellt hast, funktioniert dein alter Schlüssel nicht mehr." "Wiederherstellungsschlüssel erstellen" - "Stelle sicher, dass du deinen Wiederherstellungsschlüssel an einem sicheren Ort aufbewahren kannst" + "Geben Sie dies an niemanden weiter!" "Wiederherstellungsschlüssel geändert" "Wiederherstellungsschlüssel ändern?" @@ -51,23 +57,24 @@ " erstellen" "Sorge dafür, dass niemand diesen Bildschirm sehen kann!" - "Bitte versuche es noch einmal, um den Zugriff auf dein Chat-Backup zu bestätigen." + "Bitte versuchen Sie erneut, den Zugriff auf Ihren Schlüsselspeicher zu bestätigen." "Falscher Wiederherstellungsschlüssel" "Dies funktioniert auch mit einem Sicherheitsschlüssel oder Sicherheitsphrase." "Eingeben…" "Hast du deinen Wiederherstellungschlüssel vergessen?" "Wiederherstellungsschlüssel bestätigt" + "Geben Sie Ihren Wiederherstellungsschlüssel ein" "Wiederherstellungsschlüssel kopiert" "Generieren…" "Wiederherstellungsschlüssel speichern" - "Notiere dir deinen Wiederherstellungsschlüssel an einem sicheren Ort oder speichere ihn in einem Passwort-Manager." + "Schreiben Sie Ihren Wiederherstellungsschlüssel in eine verschlüsselte Datei, oder in einem Passwort-Manager oder in einem Safe. " "Tippe, um den Wiederherstellungsschlüssel zu kopieren" "Speichere deinen Wiederherstellungsschlüssel" "Nach diesem Schritt kannst du nicht mehr auf deinen neuen Wiederherstellungsschlüssel zugreifen." "Hast du deinen Wiederherstellungsschlüssel gespeichert?" "Dein Chat-Backup ist durch einen Wiederherstellungsschlüssel geschützt. Wenn du nach der Einrichtung einen neuen Wiederherstellungsschlüssel brauchst, kannst du ihn über die Option \"Wiederherstellungsschlüssel ändern\" neu erstellen." "Wiederherstellungsschlüssel erstellen" - "Stelle sicher, dass du deinen Wiederherstellungsschlüssel an einem sicheren Ort aufbewahren kannst" + "Geben Sie dies an niemanden weiter!" "Einrichtung der Wiederherstellung erfolgreich" "Wiederherstellung einrichten" "Ja, zurücksetzen" diff --git a/features/userprofile/shared/src/main/res/values-de/translations.xml b/features/userprofile/shared/src/main/res/values-de/translations.xml index ff201019391..f96af58bae5 100644 --- a/features/userprofile/shared/src/main/res/values-de/translations.xml +++ b/features/userprofile/shared/src/main/res/values-de/translations.xml @@ -13,5 +13,7 @@ "Blockierung aufheben" "Der Nutzer kann dir wieder Nachrichten senden & alle Nachrichten des Nutzers werden wieder angezeigt." "Blockierung aufheben" + "Verwenden Sie die Web-App, um diesen Benutzer zu verifizieren." + "Überprüfen Sie %1$s" "Beim Versuch, einen Chat zu starten, ist ein Fehler aufgetreten" diff --git a/features/verifysession/impl/src/main/res/values-de/translations.xml b/features/verifysession/impl/src/main/res/values-de/translations.xml index 1ddda0126bb..4534411033a 100644 --- a/features/verifysession/impl/src/main/res/values-de/translations.xml +++ b/features/verifysession/impl/src/main/res/values-de/translations.xml @@ -1,5 +1,6 @@ + "Sie können es nicht bestätigen?" "Erstelle einen neuen Wiederherstellungsschlüssel" "Verifiziere dieses Gerät, um sicheres Messaging einzurichten." "Bestätige, dass du es bist" @@ -16,6 +17,7 @@ "Vergleiche die Zahlen" "Deine neue Session ist nun verifiziert. Sie hat Zugriff auf deine verschlüsselten Nachrichten und wird von anderen Benutzern als vertrauenswürdig eingestuft." "Wiederherstellungsschlüssel eingeben" + "Entweder ist bei der Anfrage ein Timeout aufgetreten, oder die Anfrage wurde abgelehnt, oder es gab eine Nichtübereinstimmung bei der Überprüfung." "Beweise deine Identität, um auf deinen verschlüsselten Nachrichtenverlauf zuzugreifen." "Öffne eine bestehende Session" "Verifizierung wiederholen" @@ -23,8 +25,20 @@ "Warten auf eine Übereinstimmung" "Vergleiche eine spezielle Reihe von Emojis." "Vergleiche die einzelnen Emojis und stelle sicher, dass sie in der gleichen Reihenfolge erscheinen." + "Angemeldet" + "Entweder ist bei der Anfrage ein Timeout aufgetreten, oder die Anfrage wurde abgelehnt, oder es gab eine Nichtübereinstimmung bei der Überprüfung." + "Überprüfung fehlgeschlagen" + "Fahren Sie nur fort, falls Sie für diese Überprüfung verantwortlich sind.." + "Verifizieren Sie das andere Gerät, um die Sicherheit Ihres Nachrichtenverlaufs zu gewährleisten." + "Jetzt können Sie gesichert Nachrichten auf Ihrem anderen Gerät lesen oder senden." + "Gerät verifiziert" + "Verifizierung angefordert" "Sie stimmen nicht überein" "Sie stimmen überein" + "Stellen Sie sicher, dass die App auf dem anderen Gerät geöffnet ist, bevor Sie die Überprüfung auf diesem Gerät aus starten." + "Öffnen Sie die App auf einem anderen verifizierten Gerät" + "Sie sollten ein Popup-Fenster auf dem anderen Gerät sehen. Starten Sie die Überprüfung von dort aus." + "Starten Sie die Überprüfung auf dem anderen Gerät" "Akzeptiere die Anfrage, um den Verifizierungsprozess in deiner anderen Session zu starten, um fortzufahren." "Warten auf die Annahme der Anfrage" "Abmelden…" diff --git a/features/verifysession/impl/src/main/res/values-pl/translations.xml b/features/verifysession/impl/src/main/res/values-pl/translations.xml index 2ee77b1f7d8..46c24d253e5 100644 --- a/features/verifysession/impl/src/main/res/values-pl/translations.xml +++ b/features/verifysession/impl/src/main/res/values-pl/translations.xml @@ -17,6 +17,7 @@ "Porównaj liczby" "Twoja nowa sesja jest teraz zweryfikowana. Ma ona dostęp do Twoich zaszyfrowanych wiadomości, a inni użytkownicy będą widzieć ją jako zaufaną." "Wprowadź klucz przywracania" + "Albo upłynął limit czasu żądania, albo żądanie zostało odrzucone, albo wystąpił błąd weryfikacji." "Udowodnij, że to ty, aby uzyskać dostęp do historii zaszyfrowanych wiadomości." "Otwórz istniejącą sesję" "Ponów weryfikację" @@ -25,9 +26,11 @@ "Porównaj unikalny zestaw emoji." "Porównaj unikalne emoji, upewniając się, że pojawiły się w tej samej kolejności." "Zalogowano" + "Albo upłynął limit czasu żądania, albo żądanie zostało odrzucone, albo wystąpił błąd weryfikacji." "Weryfikacja nie powiodła się" "Kontynuuj tylko, jeśli to Ty zainicjowałeś tę weryfikację." "Zweryfikuj drugie urządzenie, aby zabezpieczyć historię wiadomości." + "Już możesz bezpiecznie czytać lub wysyłać wiadomości na drugim urządzeniu." "Urządzenie zweryfikowane" "Zażądano weryfikacji" "Nie pasują do siebie" diff --git a/libraries/eventformatter/impl/src/main/res/values-de/translations.xml b/libraries/eventformatter/impl/src/main/res/values-de/translations.xml index 1b99fd2e5df..8c99ba44ded 100644 --- a/libraries/eventformatter/impl/src/main/res/values-de/translations.xml +++ b/libraries/eventformatter/impl/src/main/res/values-de/translations.xml @@ -28,7 +28,7 @@ "%1$s hat dich eingeladen" "%1$s hat den Raum betreten" "Du hast den Raum betreten" - "%1$s hat angefragt beizutreten" + "%1$s beantragt den Beitritt" "%1$s hat %2$s den Beitritt erlaubt" "Du hast %1$s den Beitritt erlaubt." "Du hast angefragt beizutreten" diff --git a/libraries/push/impl/src/main/res/values-de/translations.xml b/libraries/push/impl/src/main/res/values-de/translations.xml index fc5edbf1d9c..f16303f87c8 100644 --- a/libraries/push/impl/src/main/res/values-de/translations.xml +++ b/libraries/push/impl/src/main/res/values-de/translations.xml @@ -23,6 +23,7 @@ "%d Einladungen" "Du wurdest zu einem Chat eingeladen" + "%1$s hat dich zum Chatten eingeladen" "Hat Dich erwähnt: %1$s" "Neue Nachrichten" @@ -33,6 +34,7 @@ "Als gelesen markieren" "Schnelle Antwort" "Du wurdest eingeladen, den Raum zu betreten" + "%1$s hat dich eingeladen, dem Chatroom beizutreten" "Ich" "%1$s hat Dich erwähnt oder geantwortet" "Du siehst dir die Benachrichtigung an! Klicke hier!" diff --git a/libraries/textcomposer/impl/src/main/res/values-de/translations.xml b/libraries/textcomposer/impl/src/main/res/values-de/translations.xml index eb0a752053c..53ea09cfa84 100644 --- a/libraries/textcomposer/impl/src/main/res/values-de/translations.xml +++ b/libraries/textcomposer/impl/src/main/res/values-de/translations.xml @@ -4,6 +4,7 @@ "Aufzählungsliste umschalten" "Formatierungsoptionen schließen" "Codeblock umschalten" + "Optionale Bildunterschrift…" "Nachricht…" "Einen Link erstellen" "Link bearbeiten" diff --git a/libraries/textcomposer/impl/src/main/res/values-et/translations.xml b/libraries/textcomposer/impl/src/main/res/values-et/translations.xml index 1cb9d1a9904..c1a8035e0eb 100644 --- a/libraries/textcomposer/impl/src/main/res/values-et/translations.xml +++ b/libraries/textcomposer/impl/src/main/res/values-et/translations.xml @@ -4,7 +4,7 @@ "Lülita mummudega loend sisse/välja" "Sulge vorminduse valikud" "Lülita lähtekoodi lõik sisse/välja" - "Pealkiri, kui soovid lisada…" + "Selgitus või nimi, kui soovid lisada…" "Sõnum…" "Lisa link" "Muuda linki" diff --git a/libraries/ui-strings/src/main/res/values-de/translations.xml b/libraries/ui-strings/src/main/res/values-de/translations.xml index b2a879cd825..826730030de 100644 --- a/libraries/ui-strings/src/main/res/values-de/translations.xml +++ b/libraries/ui-strings/src/main/res/values-de/translations.xml @@ -32,6 +32,7 @@ "Sprachnachricht aufnehmen." "Aufnahme beenden" "Akzeptieren" + "Bildunterschrift hinzufügen" "Zum Nachrichtenverlauf hinzufügen" "Zurück" "Anruf" @@ -42,18 +43,24 @@ "Schließen" "Verifizierung abschließen" "Bestätigen" + "Passwort bestätigen" "Weiter" "Kopieren" + "Bildunterschrift kopieren" "Link kopieren" "Link zur Nachricht kopieren" + "Text kopieren" "Erstellen" "Raum erstellen" + "Deaktivieren" + "Benutzerkonto deaktivieren" "Ablehnen" "Umfrage löschen" "Deaktivieren" "Verwerfen" "Erledigt" "Bearbeiten" + "Bildunterschrift bearbeiten" "Umfrage bearbeiten" "Aktivieren" "Umfrage beenden" @@ -61,6 +68,7 @@ "Passwort vergessen?" "Weiterleiten" "Zurück" + "Ignorieren" "Einladen" "Personen einladen" "Zu %1$s einladen" @@ -87,6 +95,8 @@ "Reagieren" "Ablehnen" "Entfernen" + "Bildunterschrift entfernen" + "Nachricht löschen" "Antworten" "Im Thread antworten" "Fehler melden" @@ -101,6 +111,7 @@ "Nachricht senden" "Teilen" "Link teilen" + "Zeige" "Erneut anmelden" "Abmelden" "Trotzdem abmelden" @@ -118,6 +129,7 @@ "Ja" "Über" "Nutzungsrichtlinie" + "Hinzufügen einer Bildunterschrift" "Erweiterte Einstellungen" "Analysedaten" "Erscheinungsbild" @@ -126,17 +138,21 @@ "Sprechblasen" "Aufruf gestartet" "Chat-Backup" + "In die Zwischenablage kopiert" "Copyright" "Raum wird erstellt…" "Hat den Raum verlassen" "Dunkel" "Dekodierungsfehler" "Entwickleroptionen" + "Geräte-ID" "Direktnachricht" "Nicht mehr anzeigen" "(bearbeitet)" "Bearbeitung" + "Bearbeitung der Bildunterschrift" "* %1$s %2$s" + "Verschlüsselung" "Verschlüsselung aktiviert" "PIN eingeben" "Fehler" @@ -150,6 +166,7 @@ Grund: %1$s." "Datei" "Datei wurde unter Downloads gespeichert" "Nachricht weiterleiten" + "Häufig verwendet" "GIF" "Bild" "Als Antwort auf %1$s" @@ -230,20 +247,30 @@ Grund: %1$s." "Thema" "Worum geht es in diesem Raum?" "Entschlüsselung nicht möglich" + "Von einem ungesicherten Gerät gesendet" "Du hast kein Recht diese Nachricht zu lesen." + "Die verifizierte Identität des Senders hat sich geändert" "Einladungen konnten nicht an einen oder mehrere Benutzer gesendet werden." "Einladung(en) konnte(n) nicht gesendet werden" "Entsperren" "Stummschaltung aufheben" + "Anruf nicht unterstützt" "Nicht unterstütztes Ereignis" "Benutzername" "Verifizierung abgebrochen" "Verifizierung abgeschlossen" + "Verifizierung fehlgeschlagen" + "Verifiziert" "Gerät verifizieren" + "Identität überprüfen" "Video" "Sprachnachricht" "Warten…" "Warte auf diese Nachricht" + "Sie" + "%1$s\'s Identität has sich offenbar geändert. %2$s" + "%1$s\'s %2$s Identität hat sich offenbar geändert. %3$s" + "(%1$s)" "Bestätigung" "Fehler" "Erfolg" @@ -272,7 +299,22 @@ Grund: %1$s." "Hey, sprich mit mir auf %1$s: %2$s" "%1$s Android" "Schüttel heftig zum Melden von Fehlern" + "Ja, akzeptiere alle" + "Sind Sie sicher, dass Sie alle Beitrittsanfragen akzeptieren möchten?" + "Akzeptiere alle Anfragen" + "Alle akzeptieren" + "Ja, ablehnen und sperren" + "Sind Sie sicher, dass Sie %1$s ablehnen und sperren möchten ? Dieser Benutzer kann keinen erneuten Zugriff auf diesen Raum anfordern." + "Ablehnen und Zugriff verbieten" + "Ja, ablehnen" + "Sind Sie sicher, dass Sie die %1$s Anfrage, diesem Chatroom beizutreten, ablehnen möchten ?" + "Zugriff verweigern" + "Ablehnen und sperren" + "Falls jemand um Aufnahme in den Raum bittet, können Sie dessen Anfrage hier sehen." + "Keine ausstehende Beitrittsanfrage" + "Beitrittsanfragen" "Medienauswahl fehlgeschlagen, bitte versuche es erneut." + "Bildunterschriften sind für Nutzer älterer Apps möglicherweise nicht sichtbar." "Fehler beim Verarbeiten des hochgeladenen Mediums. Bitte versuche es erneut." "Das Hochladen der Medien ist fehlgeschlagen. Bitte versuche es erneut." "Drücke auf eine Nachricht und wähle “%1$s”, um sie hier einzufügen." @@ -290,14 +332,26 @@ Grund: %1$s." "Nachricht trotzdem senden" "%1$s verwendet wenigstens ein nicht verifiziertes Gerät. Du kannst die Nachricht trotzdem verschicken, oder vorerst abbrechen und später erneut versuchen, nachdem %2$s alle Geräte verifiziert hat." "Deine Nachricht wurde nicht gesendet, weil %1$s nicht alle Geräte verifiziert hat" + "Mindestens eines Ihrer Geräte ist nicht verifiziert worden. Sie können die Nachricht trotzdem senden, oder den Vorgang zunächst abbrechen und es später erneut versuchen, nachdem Sie alle Ihrer Geräte verifiziert haben." + "Ihre Nachricht wurde nicht geschickt, da Sie eines oder mehrere Ihrer Geräte nicht verifiziert haben." "Fixierte Nachrichten" + "Beitrittsanfragen" "Fehler beim Verarbeiten des hochgeladenen Mediums. Bitte versuche es erneut." "Benutzerdetails konnten nicht abgerufen werden" + + "%1$s+ %2$d andere wollen diesem Chatroom beitreten" + "%1$s+ %2$d andere wollen diesem Chatroom beitreten" + + "Alles ansehen" "%1$s von %2$s" "%1$s fixierte Nachrichten" "Nachricht wird geladen…" "Alle anzeigen" + "Akzeptieren" + "%1$s möchte diesem Chatroom beitreten" + "Ansicht" "Chat" + "Beitrittsanfrage gesendet" "Standort teilen" "Meinen Standort teilen" "In Apple Maps öffnen" @@ -306,6 +360,7 @@ Grund: %1$s." "Diesen Standort teilen" "Nachricht nicht gesendet, weil sich die verifizierte Identität von %1$s geändert hat." "Nachricht wurde nicht gesendet, weil %1$s nicht alle Geräte verifiziert hat" + "Die Nachricht wurde nicht gesendet, weil Sie eines oder mehrere Ihrer Geräte nicht verifiziert haben." "Standort" "Version: %1$s (%2$s)" "en" 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 b24be973943..39b8bc5b9aa 100644 --- a/libraries/ui-strings/src/main/res/values-el/translations.xml +++ b/libraries/ui-strings/src/main/res/values-el/translations.xml @@ -46,8 +46,10 @@ "Επιβεβαίωση κωδικού πρόσβασης" "Συνέχεια" "Αντιγραφή" + "Αντιγραφή λεζάντας" "Αντιγραφή συνδέσμου" "Αντιγραφή συνδέσμου στο μήνυμα" + "Αντιγραφή κειμένου" "Δημιουργία" "Δημιούργησε ένα δωμάτιο" "Απενεργοποίηση" @@ -94,6 +96,7 @@ "Απόρριψη" "Αφαίρεση" "Αφαίρεση λεζάντας" + "Αφαίρεση μηνύματος" "Απάντηση" "Απάντηση στο θέμα" "Αναφορά σφάλματος" @@ -296,12 +299,22 @@ "Γεια, μίλα μου στην εφαρμογή %1$s :%2$s" "%1$s Android" "Κούνησε δυνατά τη συσκευή σου για να αναφέρεις κάποιο σφάλμα" + "Ναι, αποδοχή όλων" + "Σίγουρα θες να αποδεχτείς όλα τα αιτήματα συμμετοχής;" + "Αποδοχή όλων των αιτημάτων" "Αποδοχή όλων" + "Ναι, απόρριψη και αποκλεισμός" + "Σίγουρα θες να απορρίψειε και να αποκλείσεις τον χρήστη %1$s; Αυτός ο χρήστης δεν θα μπορεί να ζητήσει πρόσβαση για να συμμετάσχει ξανά σε αυτό το δωμάτιο." + "Απόρριψη και αποκλεισμός πρόσβασης" + "Ναι, απόρριψη" + "Σίγουρα θες να απορρίψεις το αίτημα του χρήστη %1$s να συμμετάσχει στο δωμάτιο;" + "Απόρριψη πρόσβασης" "Απόρριψη και αποκλεισμός" "Όταν κάποιος θα ζητήσει να συμμετάσχει στο δωμάτιο, θα μπορείς να δεις το αίτημά του εδώ." "Δεν υπάρχει εκκρεμές αίτημα συμμετοχής" "Αιτήματα συμμετοχής" "Αποτυχία επιλογής πολυμέσου, δοκίμασε ξανά." + "Οι λεζάντες ενδέχεται να μην είναι ορατές σε άτομα που χρησιμοποιούν παλαιότερες εφαρμογές." "Αποτυχία μεταφόρτωσης μέσου, δοκίμασε ξανά." "Αποτυχία μεταφόρτωσης πολυμέσων, δοκίμασε ξανά." "Πάτα σε ένα μήνυμα και επέλεξε «%1$s» για να συμπεριληφθεί εδώ." 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 cd94147870b..3871a58914c 100644 --- a/libraries/ui-strings/src/main/res/values-et/translations.xml +++ b/libraries/ui-strings/src/main/res/values-et/translations.xml @@ -46,8 +46,10 @@ "Kinnita otsust oma salasõnaga" "Jätka" "Kopeeri" + "Kopeeri selgitus" "Kopeeri link" "Kopeeri sõnumi link" + "Kopeeri tekst" "Loo" "Loo jututuba" "Eemalda konto" @@ -94,6 +96,7 @@ "Keeldu" "Eemalda" "Eemalda selgitus" + "Eemalda sõnum" "Vasta" "Vasta jutulõngas" "Teata veast" @@ -296,12 +299,22 @@ Põhjus: %1$s." "Hei, suhtle minuga %1$s võrgus: %2$s" "%1$s Android" "Veast teatamiseks raputa nutiseadet ägedalt" + "Jah, võta kõik vastu" + "Kas sa oled kindel, et soovid kõik vastu liitumist soovinud võtta?" + "Võta kõik vastu" "Nõustu kõigiga" + "Jah, keeldu liitumisest ning keela ligipääs" + "Kas sa oled kindel, et soovid kasutajale %1$s keelata ligipääsu siia jututuppa ning seada talle suhtluskeelu? Seetõttu ta ei saa ka enam hiljem liitumispalvet saata." + "Keeldu liitumisest ja keela ligipääs" + "Jah, keeldu" + "Kas sa oled kindel, et soovid kasutajale %1$s keelata ligipääsu siia jututuppa?" + "Keela ligipääs" "Keeldu ja määra suhtluskeeld" "Kui keegi soovib jututoaga liituda, siis need päringud on kuvatud siin." "Pole ühtegi liitumispalvet" "Liitumispalved" "Meediafaili valimine ei õnnestunud. Palun proovi uuesti." + "Selgitused ja alapealkirjad ei pruugi olla nähtavad vanemate rakenduste kasutajatele." "Meediafaili töötlemine enne üleslaadimist ei õnnestunud. Palun proovi uuesti." "Meediafaili üleslaadimine ei õnnestunud. Palun proovi uuesti." "Siia lisamiseks vajuta sõnumil ja vali „%1$s“." 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 e4092bf388b..24bd75cf463 100644 --- a/libraries/ui-strings/src/main/res/values-fr/translations.xml +++ b/libraries/ui-strings/src/main/res/values-fr/translations.xml @@ -32,6 +32,7 @@ "Enregistrer un message vocal." "Arrêter l’enregistrement" "Accepter" + "Ajouter une légende" "Ajouter à la discussion" "Retour" "Appel" @@ -45,8 +46,10 @@ "Confirmez le mot de passe" "Continuer" "Copier" + "Copier la légende" "Copier le lien" "Copier le lien vers le message" + "Copier le texte" "Créer" "Créer un salon" "Désactiver" @@ -57,6 +60,7 @@ "Annuler" "Terminé" "Modifier" + "Modifier la légende" "Modifier le sondage" "Activer" "Terminer le sondage" @@ -91,6 +95,8 @@ "Réagissez" "Rejeter" "Supprimer" + "Supprimer la légende" + "Supprimer le message" "Répondre" "Répondre dans le fil de discussion" "Signaler un problème" @@ -123,6 +129,7 @@ "Oui" "À propos" "Politique d’utilisation acceptable" + "Ajout d’une légende" "Paramètres avancés" "Statistiques d’utilisation" "Apparence" @@ -143,6 +150,7 @@ "Ne plus afficher" "(modifié)" "Édition" + "Modification de la légende" "* %1$s %2$s" "Chiffrement" "Chiffrement activé" @@ -246,6 +254,7 @@ Raison: %1$s." "Impossible d’envoyer une ou plusieurs invitations" "Déverrouillage" "Retirer la sourdine" + "Appel non pris en charge" "Événement non pris en charge" "Nom d’utilisateur" "Vérification annulée" @@ -290,7 +299,22 @@ Raison: %1$s." "Salut, parle-moi sur %1$s : %2$s" "%1$s Android" "Rageshake pour signaler un problème" + "Oui, tout accepter" + "Êtes-vous sûr de vouloir accepter toutes les demandes pour rejoindre le salon ?" + "Tout accepter" + "Tout accepter" + "Oui, rejeter et bannir" + "Êtes-vous sûr de vouloir rejeter la demande et bannir %1$s? Cet utilisateur ne pourra pas demander à nouveau à rejoindre ce salon." + "Refuser et interdire l’accès" + "Oui, refuser" + "Êtes-vous sûr de vouloir refuser la demande de %1$s à rejoindre le salon?" + "Refuser l’accès" + "Refuser et bannir" + "Lorsque quelqu’un demandera à rejoindre le salon, vous pourrez voir sa demande ici." + "Personne ne demande à rejoindre le salon" + "Demandes en attente" "Échec de la sélection du média, veuillez réessayer." + "Les légendes peuvent ne pas être visibles pour les utilisateurs d’anciennes applications." "Échec du traitement des médias à télécharger, veuillez réessayer." "Échec du téléchargement du média, veuillez réessayer." "Cliquez (clic long) sur un message et choisissez « %1$s » pour qu‘il apparaisse ici." @@ -311,12 +335,21 @@ Raison: %1$s." "Un ou plusieurs de vos appareils ne sont pas vérifiés. Vous pouvez quand même envoyer le message, ou vous pouvez annuler et réessayer plus tard après avoir vérifié tous vos appareils." "Votre message n’a pas été envoyé car vous n’avez pas vérifié tous vos appareils" "Messages épinglés" + "Demandes en attente" "Échec du traitement des médias à télécharger, veuillez réessayer." "Impossible de récupérer les détails de l’utilisateur" + + "%1$s et %2$d autre personne souhaitent rejoindre ce salon" + "%1$s et %2$d autres personnes souhaitent rejoindre ce salon" + + "Tout afficher" "%1$s sur %2$s" "%1$s Messages épinglés" "Chargement du message…" "Voir tout" + "Accepter" + "%1$s souhaite rejoindre ce salon" + "Voir" "Discussion" "Demande d’adhésion envoyée" "Partage de position" 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 72c72951093..35e9388ae76 100644 --- a/libraries/ui-strings/src/main/res/values-ru/translations.xml +++ b/libraries/ui-strings/src/main/res/values-ru/translations.xml @@ -48,8 +48,10 @@ "Подтвердите пароль" "Продолжить" "Копировать" + "Скопировать подпись" "Скопировать ссылку" "Скопировать ссылку в сообщение" + "Копировать текст" "Создать" "Создать комнату" "Отключить" @@ -96,6 +98,7 @@ "Отклонить" "Удалить" "Удалить подпись" + "Удалить сообщение" "Ответить" "Ответить в теме" "Сообщить об ошибке" @@ -300,12 +303,22 @@ "Привет, поговори со мной по %1$s: %2$s" "%1$s Android" "Встряхните устройство, чтобы сообщить об ошибке" + "Да, принять все" + "Вы действительно хотите принять все заявки на присоединение?" + "Принять все запросы" "Принять всё" + "Да, отклонить и запретить" + "Вы уверен, что хочешь отклонить и запретить %1$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 4f7af2d51c3..9d6e87db99a 100644 --- a/libraries/ui-strings/src/main/res/values/localazy.xml +++ b/libraries/ui-strings/src/main/res/values/localazy.xml @@ -96,6 +96,7 @@ "Reject" "Remove" "Remove caption" + "Remove message" "Reply" "Reply in thread" "Report bug" @@ -298,12 +299,22 @@ Reason: %1$s." "Hey, talk to me on %1$s: %2$s" "%1$s Android" "Rageshake to report bug" + "Yes, accept all" + "Are you sure you want to accept all requests to join?" + "Accept all requests" "Accept all" + "Yes, decline and ban" + "Are you sure you want to decline and ban %1$s? This user won’t be able to request access to join this room again." + "Decline and ban from accessing" + "Yes, decline" + "Are you sure you want to decline %1$s request to join this room?" + "Decline access" "Decline and ban" "When somebody will ask to join the room, you’ll be able to see their request here." "No pending request to join" "Requests to join" "Failed selecting media, please try again." + "Captions might not be visible to people using older apps." "Failed processing media to upload, please try again." "Failed uploading media, please try again." "Press on a message and choose “%1$s” to include here." diff --git a/screenshots/de/features.createroom.impl.configureroom_ConfigureRoomViewDark_0_de.png b/screenshots/de/features.createroom.impl.configureroom_ConfigureRoomViewDark_0_de.png index 2e33cce11bf..00bec43e133 100644 --- a/screenshots/de/features.createroom.impl.configureroom_ConfigureRoomViewDark_0_de.png +++ b/screenshots/de/features.createroom.impl.configureroom_ConfigureRoomViewDark_0_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a15fb67f825270cd99686b6ccc41ba96300cd66cd9037a142ca22ea0c97e34b8 -size 39325 +oid sha256:457363c25841925076aaad53d728e631427f699cfb7545b8e1abb94fb6a2e774 +size 36741 diff --git a/screenshots/de/features.createroom.impl.configureroom_ConfigureRoomViewDark_1_de.png b/screenshots/de/features.createroom.impl.configureroom_ConfigureRoomViewDark_1_de.png index a72a126cdae..e09d9d4951b 100644 --- a/screenshots/de/features.createroom.impl.configureroom_ConfigureRoomViewDark_1_de.png +++ b/screenshots/de/features.createroom.impl.configureroom_ConfigureRoomViewDark_1_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:dd301613bba0388dda860f1b9bf17199242b4b2b100306204ce62aa8a8d18475 -size 49352 +oid sha256:baf2c57107cd2f639535fc6fdf5b9885224c0f839d78fdbc85e14398f7439cd2 +size 49576 diff --git a/screenshots/de/features.createroom.impl.configureroom_ConfigureRoomViewDark_2_de.png b/screenshots/de/features.createroom.impl.configureroom_ConfigureRoomViewDark_2_de.png index 46b12584d8e..ba26587c923 100644 --- a/screenshots/de/features.createroom.impl.configureroom_ConfigureRoomViewDark_2_de.png +++ b/screenshots/de/features.createroom.impl.configureroom_ConfigureRoomViewDark_2_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:8bdac3f5bab1b95d1ece1891d8f8eed5280189a4df245f7ed428659b070abfc1 -size 60977 +oid sha256:eba277a783d50012cf4a51ec93c4cf02394befc9c5d04edd27ac8113e9257539 +size 63564 diff --git a/screenshots/de/features.createroom.impl.configureroom_ConfigureRoomViewDark_3_de.png b/screenshots/de/features.createroom.impl.configureroom_ConfigureRoomViewDark_3_de.png index 301811e23dc..09b64115e15 100644 --- a/screenshots/de/features.createroom.impl.configureroom_ConfigureRoomViewDark_3_de.png +++ b/screenshots/de/features.createroom.impl.configureroom_ConfigureRoomViewDark_3_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:3e128c7c58e19420128773da3e7493d23b29318754f16701f15c62b881e0605f -size 60682 +oid sha256:c1f26d21ba37d244fcc5adb5b7580856f8e1a7670fd2defcd4befa3e2d07b8b6 +size 63685 diff --git a/screenshots/de/features.createroom.impl.configureroom_ConfigureRoomViewDark_4_de.png b/screenshots/de/features.createroom.impl.configureroom_ConfigureRoomViewDark_4_de.png index 10500ad8306..81b004f86b6 100644 --- a/screenshots/de/features.createroom.impl.configureroom_ConfigureRoomViewDark_4_de.png +++ b/screenshots/de/features.createroom.impl.configureroom_ConfigureRoomViewDark_4_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:4d3c949a4619265b60081283be9f27eecac606da28efe0802709b2737fee0de0 -size 60782 +oid sha256:52f75d9234a0eace30ec10cbdeda6314cea0634d0ccbd2b8f453ec184a35cd13 +size 63592 diff --git a/screenshots/de/features.createroom.impl.configureroom_ConfigureRoomViewDark_5_de.png b/screenshots/de/features.createroom.impl.configureroom_ConfigureRoomViewDark_5_de.png index 5d46b370bda..5308d79c1e9 100644 --- a/screenshots/de/features.createroom.impl.configureroom_ConfigureRoomViewDark_5_de.png +++ b/screenshots/de/features.createroom.impl.configureroom_ConfigureRoomViewDark_5_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f437ac8ebbb8a07498cfdb79ae559d6c26ef0df7f69ceadf3517a2240df21adf -size 60272 +oid sha256:6c28710d2afe583078a26c8b56c331a942c250cb599d4c00f9dc4cf04286c811 +size 63082 diff --git a/screenshots/de/features.createroom.impl.configureroom_ConfigureRoomViewLight_0_de.png b/screenshots/de/features.createroom.impl.configureroom_ConfigureRoomViewLight_0_de.png index 324e5c0e7c6..1f6bca734e3 100644 --- a/screenshots/de/features.createroom.impl.configureroom_ConfigureRoomViewLight_0_de.png +++ b/screenshots/de/features.createroom.impl.configureroom_ConfigureRoomViewLight_0_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a5b45f72a7fc93c57abf3d660fe90681e5dd4d97f6e85fb13930b778275314bc -size 40243 +oid sha256:9b449faf40487c6f34253b0157ae14c3df6a8a782b2af18fcd2b6f80198fa7d2 +size 37688 diff --git a/screenshots/de/features.createroom.impl.configureroom_ConfigureRoomViewLight_1_de.png b/screenshots/de/features.createroom.impl.configureroom_ConfigureRoomViewLight_1_de.png index fa87cb45809..ba57e7b40be 100644 --- a/screenshots/de/features.createroom.impl.configureroom_ConfigureRoomViewLight_1_de.png +++ b/screenshots/de/features.createroom.impl.configureroom_ConfigureRoomViewLight_1_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ca979acec5b69c530dd7df8f096bb3ed0155e98adb175c3720c51bf8887101d3 -size 50133 +oid sha256:09596614dfe191f7eb046aff9d44642e6ecbbf3fbdcb89181bae75c16d6ba72d +size 50492 diff --git a/screenshots/de/features.createroom.impl.configureroom_ConfigureRoomViewLight_2_de.png b/screenshots/de/features.createroom.impl.configureroom_ConfigureRoomViewLight_2_de.png index 04379c41f0d..08823300da9 100644 --- a/screenshots/de/features.createroom.impl.configureroom_ConfigureRoomViewLight_2_de.png +++ b/screenshots/de/features.createroom.impl.configureroom_ConfigureRoomViewLight_2_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:b3d67f0c62fd3118b5e0dd973e0704ab59e728042103830f4bd3dde3a69ade59 -size 62037 +oid sha256:ae642483fc05fb50555e2fa5b83ac12d84a064c4b840a53a4ebf53d419f87242 +size 65036 diff --git a/screenshots/de/features.createroom.impl.configureroom_ConfigureRoomViewLight_3_de.png b/screenshots/de/features.createroom.impl.configureroom_ConfigureRoomViewLight_3_de.png index 6cf5c6f1425..3b9922cb362 100644 --- a/screenshots/de/features.createroom.impl.configureroom_ConfigureRoomViewLight_3_de.png +++ b/screenshots/de/features.createroom.impl.configureroom_ConfigureRoomViewLight_3_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:63f49c49ed3c99866a9c383e5fa6ff944a936f2050001be4d5868fbb47b702b8 -size 62506 +oid sha256:28606cedfc76d8600f8e935a42c4e98dc13c0b1d1733856bc20d064f99a39c5b +size 65826 diff --git a/screenshots/de/features.createroom.impl.configureroom_ConfigureRoomViewLight_4_de.png b/screenshots/de/features.createroom.impl.configureroom_ConfigureRoomViewLight_4_de.png index 167b944d4ac..837e2badf78 100644 --- a/screenshots/de/features.createroom.impl.configureroom_ConfigureRoomViewLight_4_de.png +++ b/screenshots/de/features.createroom.impl.configureroom_ConfigureRoomViewLight_4_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:678468615a0df5c1ba8add0ec3046e6ce11ab13adf9439635569806ffd29614e -size 62622 +oid sha256:3128a8b8ca419b6862d1e5a3e8713f4aefd6fccd494babf006ccbbe15391c956 +size 65747 diff --git a/screenshots/de/features.createroom.impl.configureroom_ConfigureRoomViewLight_5_de.png b/screenshots/de/features.createroom.impl.configureroom_ConfigureRoomViewLight_5_de.png index 121f527da67..7acd884662d 100644 --- a/screenshots/de/features.createroom.impl.configureroom_ConfigureRoomViewLight_5_de.png +++ b/screenshots/de/features.createroom.impl.configureroom_ConfigureRoomViewLight_5_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:1e72f476868673ddceab4449eb1d64554ccb48be8dcc96f45e4fa3137a4345bd -size 62077 +oid sha256:54396bda85421376b596d885a43f67a19b06e9d7980d01112b90849ae08568e1 +size 65181 diff --git a/screenshots/de/features.joinroom.impl_JoinRoomView_Day_10_de.png b/screenshots/de/features.joinroom.impl_JoinRoomView_Day_10_de.png new file mode 100644 index 00000000000..5cd0ea0b22f --- /dev/null +++ b/screenshots/de/features.joinroom.impl_JoinRoomView_Day_10_de.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:de336859078455943d159d4d5d7fe710ecbce95baff983c4b74fab67ba6c16df +size 109581 diff --git a/screenshots/de/features.joinroom.impl_JoinRoomView_Day_11_de.png b/screenshots/de/features.joinroom.impl_JoinRoomView_Day_11_de.png new file mode 100644 index 00000000000..1f682b74ffa --- /dev/null +++ b/screenshots/de/features.joinroom.impl_JoinRoomView_Day_11_de.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:19de55a1492cdbb55219720334ac6f5432518462e5a19c4783a32828d7fac899 +size 110605 diff --git a/screenshots/de/features.joinroom.impl_JoinRoomView_Day_12_de.png b/screenshots/de/features.joinroom.impl_JoinRoomView_Day_12_de.png new file mode 100644 index 00000000000..afb6b330059 --- /dev/null +++ b/screenshots/de/features.joinroom.impl_JoinRoomView_Day_12_de.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:32c5e9a456ea8a2718e50eea5a90f719eff659ed9ada2ab2a9f8da23b2344644 +size 123199 diff --git a/screenshots/de/features.joinroom.impl_JoinRoomView_Day_4_de.png b/screenshots/de/features.joinroom.impl_JoinRoomView_Day_4_de.png index 1078ac87652..a0cee32c3de 100644 --- a/screenshots/de/features.joinroom.impl_JoinRoomView_Day_4_de.png +++ b/screenshots/de/features.joinroom.impl_JoinRoomView_Day_4_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:d8ec5e94258a92dea64d381284eca656980065cf2b9d1da89a7ec0833c77e263 -size 109815 +oid sha256:45d925186a619b7fbe19211ddfc8c052a3571b53ea6fbc914d819473aed9328f +size 112045 diff --git a/screenshots/de/features.joinroom.impl_JoinRoomView_Day_5_de.png b/screenshots/de/features.joinroom.impl_JoinRoomView_Day_5_de.png index a0cee32c3de..623dada791a 100644 --- a/screenshots/de/features.joinroom.impl_JoinRoomView_Day_5_de.png +++ b/screenshots/de/features.joinroom.impl_JoinRoomView_Day_5_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:45d925186a619b7fbe19211ddfc8c052a3571b53ea6fbc914d819473aed9328f -size 112045 +oid sha256:2cbf98f8a0c6208379c64f62c2c49a858d67a60469f0001e496c248736a2e82f +size 120862 diff --git a/screenshots/de/features.joinroom.impl_JoinRoomView_Day_6_de.png b/screenshots/de/features.joinroom.impl_JoinRoomView_Day_6_de.png index 623dada791a..73ad652a384 100644 --- a/screenshots/de/features.joinroom.impl_JoinRoomView_Day_6_de.png +++ b/screenshots/de/features.joinroom.impl_JoinRoomView_Day_6_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:2cbf98f8a0c6208379c64f62c2c49a858d67a60469f0001e496c248736a2e82f -size 120862 +oid sha256:e79835f689801de55e6c0b0db98b642d58e235d205f23e76c8eca383cbcfa1f4 +size 97392 diff --git a/screenshots/de/features.joinroom.impl_JoinRoomView_Day_7_de.png b/screenshots/de/features.joinroom.impl_JoinRoomView_Day_7_de.png index 73ad652a384..afba2b6c291 100644 --- a/screenshots/de/features.joinroom.impl_JoinRoomView_Day_7_de.png +++ b/screenshots/de/features.joinroom.impl_JoinRoomView_Day_7_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:e79835f689801de55e6c0b0db98b642d58e235d205f23e76c8eca383cbcfa1f4 -size 97392 +oid sha256:fb15d62e0dd87f76ce8c9f8e2909c4f4a5711cfcae89a81cef2bab0468db5054 +size 101310 diff --git a/screenshots/de/features.joinroom.impl_JoinRoomView_Day_8_de.png b/screenshots/de/features.joinroom.impl_JoinRoomView_Day_8_de.png index afba2b6c291..a3aaef18244 100644 --- a/screenshots/de/features.joinroom.impl_JoinRoomView_Day_8_de.png +++ b/screenshots/de/features.joinroom.impl_JoinRoomView_Day_8_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:fb15d62e0dd87f76ce8c9f8e2909c4f4a5711cfcae89a81cef2bab0468db5054 -size 101310 +oid sha256:5a975e41d142e75969ca6e4148c5a87acc57c3fc78c1a1bac65207b09ce3fe38 +size 113797 diff --git a/screenshots/de/features.joinroom.impl_JoinRoomView_Day_9_de.png b/screenshots/de/features.joinroom.impl_JoinRoomView_Day_9_de.png deleted file mode 100644 index a3aaef18244..00000000000 --- a/screenshots/de/features.joinroom.impl_JoinRoomView_Day_9_de.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:5a975e41d142e75969ca6e4148c5a87acc57c3fc78c1a1bac65207b09ce3fe38 -size 113797 diff --git a/screenshots/de/features.login.impl.screens.qrcode.intro_QrCodeIntroView_Day_0_de.png b/screenshots/de/features.login.impl.screens.qrcode.intro_QrCodeIntroView_Day_0_de.png index dc9aece926c..641499630ad 100644 --- a/screenshots/de/features.login.impl.screens.qrcode.intro_QrCodeIntroView_Day_0_de.png +++ b/screenshots/de/features.login.impl.screens.qrcode.intro_QrCodeIntroView_Day_0_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:0d2fadedcac33e4dbc013c9f441ec80a5a60d39e84c3e5aacf9eba0e9f6813f9 -size 56582 +oid sha256:54767f370bf50ae7c8f6d0cc27943b2832777e69d97fce3a3fe87ba4a54144a7 +size 58506 diff --git a/screenshots/de/features.logout.impl_AccountDeactivationView_Day_0_de.png b/screenshots/de/features.logout.impl_AccountDeactivationView_Day_0_de.png index 5318fc864f7..96b5954e8c3 100644 --- a/screenshots/de/features.logout.impl_AccountDeactivationView_Day_0_de.png +++ b/screenshots/de/features.logout.impl_AccountDeactivationView_Day_0_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f7e32f9afa7fcec67740bc0dc541ed9b37655d08e2d4a851d4195480e277616d -size 77420 +oid sha256:53ff3da2a5496f8df3166ad21e8bf65a9d5d25e408ca7c45c11a65e1bc25b08a +size 89302 diff --git a/screenshots/de/features.logout.impl_AccountDeactivationView_Day_1_de.png b/screenshots/de/features.logout.impl_AccountDeactivationView_Day_1_de.png new file mode 100644 index 00000000000..cd650136f55 --- /dev/null +++ b/screenshots/de/features.logout.impl_AccountDeactivationView_Day_1_de.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1dd9b479ba45c82fce5d0dc80088232675671200f05131f39588aff1941c1341 +size 88983 diff --git a/screenshots/de/features.logout.impl_AccountDeactivationView_Day_2_de.png b/screenshots/de/features.logout.impl_AccountDeactivationView_Day_2_de.png index a4cac0b1c38..d19b60e2bd3 100644 --- a/screenshots/de/features.logout.impl_AccountDeactivationView_Day_2_de.png +++ b/screenshots/de/features.logout.impl_AccountDeactivationView_Day_2_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:e554b8fd9bb9b3ddf81518a875588fb852cff3f525ae4a7cd9841bf7adedf8f0 -size 61915 +oid sha256:253cc5c68847a4878f6e9e9d7136f5d3d56157b29987398cc89f85ab4327a866 +size 81565 diff --git a/screenshots/de/features.logout.impl_AccountDeactivationView_Day_3_de.png b/screenshots/de/features.logout.impl_AccountDeactivationView_Day_3_de.png index 87eb704a54f..277f207da88 100644 --- a/screenshots/de/features.logout.impl_AccountDeactivationView_Day_3_de.png +++ b/screenshots/de/features.logout.impl_AccountDeactivationView_Day_3_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:932587c9c20b08576a20c88b06a6a768193d1f0cc342bac332fc72b6dd32ef13 -size 54871 +oid sha256:6f66e99b3632618df51d43688d57ebe152ab91058f4db52e9f33060c0e6b638b +size 69452 diff --git a/screenshots/de/features.logout.impl_AccountDeactivationView_Day_4_de.png b/screenshots/de/features.logout.impl_AccountDeactivationView_Day_4_de.png index 20262d3338e..d8b4b324349 100644 --- a/screenshots/de/features.logout.impl_AccountDeactivationView_Day_4_de.png +++ b/screenshots/de/features.logout.impl_AccountDeactivationView_Day_4_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:1c366667637a46850c80a875736bf79830e1cdde717878bee3087453d484c3dd -size 54105 +oid sha256:49db8bd9f23eb98ef0e378a5b8b727a59715410017e2ab05bbc6a81ffe206a40 +size 72010 diff --git a/screenshots/de/features.messages.impl.actionlist_ActionListViewContent_Day_10_de.png b/screenshots/de/features.messages.impl.actionlist_ActionListViewContent_Day_10_de.png index a323107f353..b0bf21949f7 100644 --- a/screenshots/de/features.messages.impl.actionlist_ActionListViewContent_Day_10_de.png +++ b/screenshots/de/features.messages.impl.actionlist_ActionListViewContent_Day_10_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:3863896937835bad93aec454ea1ac84c0256abecbde4609bc217724e7707a990 -size 35422 +oid sha256:85b0a307f751b991e16ec61e27222fb3a51808c1ea81869eb3513925c18977ee +size 27513 diff --git a/screenshots/de/features.messages.impl.actionlist_ActionListViewContent_Day_11_de.png b/screenshots/de/features.messages.impl.actionlist_ActionListViewContent_Day_11_de.png index 6f08fbcffea..10051a39ee1 100644 --- a/screenshots/de/features.messages.impl.actionlist_ActionListViewContent_Day_11_de.png +++ b/screenshots/de/features.messages.impl.actionlist_ActionListViewContent_Day_11_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f614c45833e18e8aba011073006793824485114488e30e32548303ca55574a97 -size 51406 +oid sha256:0ab5fd552ac94ea96da1403099877e171751d8b4521f425041407c59f3d659cd +size 52022 diff --git a/screenshots/de/features.messages.impl.actionlist_ActionListViewContent_Day_12_de.png b/screenshots/de/features.messages.impl.actionlist_ActionListViewContent_Day_12_de.png index f4afa40ee16..fff94dc871d 100644 --- a/screenshots/de/features.messages.impl.actionlist_ActionListViewContent_Day_12_de.png +++ b/screenshots/de/features.messages.impl.actionlist_ActionListViewContent_Day_12_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c12ba12dca338d5722efc87ff7150d555d825dc2793e3263adb490135d696345 -size 51517 +oid sha256:dc3877eccf0d9fb26445089ead8d8b69ef836929735ca15354be68549690e555 +size 52146 diff --git a/screenshots/de/features.messages.impl.actionlist_ActionListViewContent_Day_2_de.png b/screenshots/de/features.messages.impl.actionlist_ActionListViewContent_Day_2_de.png index 72d8f27d8c0..7f7a3a82b8d 100644 --- a/screenshots/de/features.messages.impl.actionlist_ActionListViewContent_Day_2_de.png +++ b/screenshots/de/features.messages.impl.actionlist_ActionListViewContent_Day_2_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:93e7012184ddeadda396c78b1c70b713e58e96994b69471c26c413f940d4a5aa -size 43500 +oid sha256:906b08c68d09d8c5ca41f518928c92239eb90ab30153e827c37f9d0036daca87 +size 43970 diff --git a/screenshots/de/features.messages.impl.actionlist_ActionListViewContent_Day_3_de.png b/screenshots/de/features.messages.impl.actionlist_ActionListViewContent_Day_3_de.png index 02de885c5f6..6ff70baa530 100644 --- a/screenshots/de/features.messages.impl.actionlist_ActionListViewContent_Day_3_de.png +++ b/screenshots/de/features.messages.impl.actionlist_ActionListViewContent_Day_3_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:23bc2e3eaba71cb846544eb97e89b823f2648c425ae6f00c4d5e1d5498c0e6e2 -size 46829 +oid sha256:aa19b5cd2d27493f0f93820d80649681fda843cc87dab6adf5db6437cc7c1d67 +size 48970 diff --git a/screenshots/de/features.messages.impl.actionlist_ActionListViewContent_Day_4_de.png b/screenshots/de/features.messages.impl.actionlist_ActionListViewContent_Day_4_de.png index b2bc53e5073..a63acd006b7 100644 --- a/screenshots/de/features.messages.impl.actionlist_ActionListViewContent_Day_4_de.png +++ b/screenshots/de/features.messages.impl.actionlist_ActionListViewContent_Day_4_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:06f1353e8cf554102e1c9f778b26c7e07be5a192369d14bc99248509939e4fb8 -size 44540 +oid sha256:cac29a125e8ea11e65d6fdbe1282c0525f12f8aeaf251fa11103ca6abbe79222 +size 46501 diff --git a/screenshots/de/features.messages.impl.actionlist_ActionListViewContent_Day_5_de.png b/screenshots/de/features.messages.impl.actionlist_ActionListViewContent_Day_5_de.png index f5c2a7c1899..ec2c3e8463a 100644 --- a/screenshots/de/features.messages.impl.actionlist_ActionListViewContent_Day_5_de.png +++ b/screenshots/de/features.messages.impl.actionlist_ActionListViewContent_Day_5_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:9835505f8e7675e2a78b82643d6b90baf927501ef14c9f75d39f2a11862b2217 -size 44170 +oid sha256:93f885fa860add5822c93522ff3a85c241f236f514007c9e6be4151842c39848 +size 41845 diff --git a/screenshots/de/features.messages.impl.actionlist_ActionListViewContent_Day_6_de.png b/screenshots/de/features.messages.impl.actionlist_ActionListViewContent_Day_6_de.png index 48b221c3198..8fbc79fcf3d 100644 --- a/screenshots/de/features.messages.impl.actionlist_ActionListViewContent_Day_6_de.png +++ b/screenshots/de/features.messages.impl.actionlist_ActionListViewContent_Day_6_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:8b4587204de12c826dba2920cf04fe58fd6ce5a2e7a8f235dfc658bc2a6b8504 -size 44787 +oid sha256:989f76fb00e26b75827c9e28887db83d27eaa955a26fde20cc4a900f17cba0d8 +size 46727 diff --git a/screenshots/de/features.messages.impl.actionlist_ActionListViewContent_Day_7_de.png b/screenshots/de/features.messages.impl.actionlist_ActionListViewContent_Day_7_de.png index 36ce7804802..b56d48d004d 100644 --- a/screenshots/de/features.messages.impl.actionlist_ActionListViewContent_Day_7_de.png +++ b/screenshots/de/features.messages.impl.actionlist_ActionListViewContent_Day_7_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:1f7940891b92cb8900994c98c9fb5eef7b60569c58fc01c3b204c3ab74283553 -size 45228 +oid sha256:6eb5f6d73426f470d55b81dc83f2b3148c57bd358299775910c2a882ae1a1825 +size 42920 diff --git a/screenshots/de/features.messages.impl.actionlist_ActionListViewContent_Day_8_de.png b/screenshots/de/features.messages.impl.actionlist_ActionListViewContent_Day_8_de.png index d95a8503002..8d10d0b0fbb 100644 --- a/screenshots/de/features.messages.impl.actionlist_ActionListViewContent_Day_8_de.png +++ b/screenshots/de/features.messages.impl.actionlist_ActionListViewContent_Day_8_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:bd5d1ce6dde457a01f0c21a75c37a4ab84f74b0b0c0a5b06c821db88af8e055b -size 45513 +oid sha256:5995b1b0090fcc93144f5305a75b8071e9a77610b9e6d2f2f69a392832386921 +size 45944 diff --git a/screenshots/de/features.messages.impl.actionlist_ActionListViewContent_Day_9_de.png b/screenshots/de/features.messages.impl.actionlist_ActionListViewContent_Day_9_de.png index 5330d62e567..0fda154e008 100644 --- a/screenshots/de/features.messages.impl.actionlist_ActionListViewContent_Day_9_de.png +++ b/screenshots/de/features.messages.impl.actionlist_ActionListViewContent_Day_9_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f7671d88bab4949a79cb1e3fb342f1a9bd398f507bd25a5d08c918e26b588837 -size 35071 +oid sha256:2a71b6ebe1727f31bd147963247ed16c25ba18379e8f98c3ca8ef6ba3c119f9b +size 35606 diff --git a/screenshots/de/features.messages.impl.attachments.preview_AttachmentsView_0_de.png b/screenshots/de/features.messages.impl.attachments.preview_AttachmentsView_0_de.png new file mode 100644 index 00000000000..5fa9d542338 --- /dev/null +++ b/screenshots/de/features.messages.impl.attachments.preview_AttachmentsView_0_de.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:432e20dbee2b01faebb0699d11b83dc08f3995b23db622b2645ebdcec1b9cdbc +size 398406 diff --git a/screenshots/de/features.messages.impl.attachments.preview_AttachmentsView_1_de.png b/screenshots/de/features.messages.impl.attachments.preview_AttachmentsView_1_de.png new file mode 100644 index 00000000000..157f8f6272f --- /dev/null +++ b/screenshots/de/features.messages.impl.attachments.preview_AttachmentsView_1_de.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:db1ad6cc1ca2d83fd389b11eaf7554d3790ed9710e5af524d7c3dfe73987b0c3 +size 19892 diff --git a/screenshots/de/features.messages.impl.attachments.preview_AttachmentsView_2_de.png b/screenshots/de/features.messages.impl.attachments.preview_AttachmentsView_2_de.png new file mode 100644 index 00000000000..4202f8ccbfd --- /dev/null +++ b/screenshots/de/features.messages.impl.attachments.preview_AttachmentsView_2_de.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:cd72e9a88a9aa3dcd012657e218a372e2e0078f2748b62df107b0dc9ae56ec75 +size 22245 diff --git a/screenshots/de/features.messages.impl.attachments.preview_AttachmentsView_3_de.png b/screenshots/de/features.messages.impl.attachments.preview_AttachmentsView_3_de.png new file mode 100644 index 00000000000..d5f291ce6ae --- /dev/null +++ b/screenshots/de/features.messages.impl.attachments.preview_AttachmentsView_3_de.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:13765804d661727d44f40f53d8865183f94651f16d30831ee9ab8b90fd9a4efe +size 23251 diff --git a/screenshots/de/features.messages.impl.attachments.preview_AttachmentsView_4_de.png b/screenshots/de/features.messages.impl.attachments.preview_AttachmentsView_4_de.png index 5b9749175c8..0bf11f09756 100644 --- a/screenshots/de/features.messages.impl.attachments.preview_AttachmentsView_4_de.png +++ b/screenshots/de/features.messages.impl.attachments.preview_AttachmentsView_4_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:0fccf0cc79fa0ff883def2fbda49b9b8a4c6bb3c390c75f5ebd7b779c27cf666 -size 53529 +oid sha256:1f7a22a39cd00987efa645df5626eec5e405f08ca046c23d53ce7e506f1654e5 +size 54411 diff --git a/screenshots/de/features.messages.impl.attachments.preview_AttachmentsView_5_de.png b/screenshots/de/features.messages.impl.attachments.preview_AttachmentsView_5_de.png index 5bdcd840270..732ac86d779 100644 --- a/screenshots/de/features.messages.impl.attachments.preview_AttachmentsView_5_de.png +++ b/screenshots/de/features.messages.impl.attachments.preview_AttachmentsView_5_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:60a9c944110da6fd27fd6a5da2ceff7142f78ece3e40f17e4a27f3b3f9119862 -size 79814 +oid sha256:b415770af2855daf5cc2a09a38ec955ed5c80f958575ff2f5ddfb053df7d7870 +size 54385 diff --git a/screenshots/de/features.messages.impl.attachments.preview_AttachmentsView_6_de.png b/screenshots/de/features.messages.impl.attachments.preview_AttachmentsView_6_de.png new file mode 100644 index 00000000000..f5f28f06a17 --- /dev/null +++ b/screenshots/de/features.messages.impl.attachments.preview_AttachmentsView_6_de.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ff9a1d9f654b9c2cc5e21ffca1c2e85014f9b0b190b534de0667bc49c05e328f +size 80690 diff --git a/screenshots/de/features.messages.impl.crypto.identity_IdentityChangeStateView_Day_1_de.png b/screenshots/de/features.messages.impl.crypto.identity_IdentityChangeStateView_Day_1_de.png index c72cb0ec4ec..5104d537f3a 100644 --- a/screenshots/de/features.messages.impl.crypto.identity_IdentityChangeStateView_Day_1_de.png +++ b/screenshots/de/features.messages.impl.crypto.identity_IdentityChangeStateView_Day_1_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:0466a368266f2958a54307b34dc6d1152c50cded092811268c062c9f86f896e8 -size 25597 +oid sha256:e76cc4015eb6703f77498a0165a77564cbf55e1ee02aeece616270ea95c89c6a +size 25907 diff --git a/screenshots/de/features.messages.impl.crypto.identity_IdentityChangeStateView_Day_2_de.png b/screenshots/de/features.messages.impl.crypto.identity_IdentityChangeStateView_Day_2_de.png index 2281d36854c..6e883fb1551 100644 --- a/screenshots/de/features.messages.impl.crypto.identity_IdentityChangeStateView_Day_2_de.png +++ b/screenshots/de/features.messages.impl.crypto.identity_IdentityChangeStateView_Day_2_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c530c4887b65128e9aceaf9c46196204e0a049386fb796cacfa30ee83d99084c -size 25593 +oid sha256:4c13c7b6350d991737ad44d985c4ab4f1335de3291ced946915a38375ca46f91 +size 25901 diff --git a/screenshots/de/features.messages.impl.crypto.identity_MessagesViewWithIdentityChange_Day_1_de.png b/screenshots/de/features.messages.impl.crypto.identity_MessagesViewWithIdentityChange_Day_1_de.png index 76e6073ca99..69b647a5844 100644 --- a/screenshots/de/features.messages.impl.crypto.identity_MessagesViewWithIdentityChange_Day_1_de.png +++ b/screenshots/de/features.messages.impl.crypto.identity_MessagesViewWithIdentityChange_Day_1_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ac676b093eb1b1afd33a546e64af7bf9cd21f3d71c6b0d6593ae30ca8cb73b00 -size 65474 +oid sha256:398376e9149bd3fd8903b0dc8f8859b58421eb0f600f8cc1a1054f8a87ffea07 +size 65810 diff --git a/screenshots/de/features.messages.impl.crypto.identity_MessagesViewWithIdentityChange_Day_2_de.png b/screenshots/de/features.messages.impl.crypto.identity_MessagesViewWithIdentityChange_Day_2_de.png index c53a7a37575..e028ad00382 100644 --- a/screenshots/de/features.messages.impl.crypto.identity_MessagesViewWithIdentityChange_Day_2_de.png +++ b/screenshots/de/features.messages.impl.crypto.identity_MessagesViewWithIdentityChange_Day_2_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c9ffc962a14719e6a265e7d48ad2bad7fa0cd1fd8dd1ea15b973b3266cf1c466 -size 65609 +oid sha256:cfe7b3d99fefa3b64080589a02741a23381ce03ae751d94a2b1575e63d4b2355 +size 65868 diff --git a/screenshots/de/features.messages.impl.timeline.components.event_TimelineItemEncryptedView_Day_2_de.png b/screenshots/de/features.messages.impl.timeline.components.event_TimelineItemEncryptedView_Day_2_de.png new file mode 100644 index 00000000000..3caf8ac57fe --- /dev/null +++ b/screenshots/de/features.messages.impl.timeline.components.event_TimelineItemEncryptedView_Day_2_de.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:8ceb7481fba9bc16a2b5aa75915f71100a6136804383854cace129d54871492e +size 13673 diff --git a/screenshots/de/features.messages.impl.timeline.components.event_TimelineItemEncryptedView_Day_3_de.png b/screenshots/de/features.messages.impl.timeline.components.event_TimelineItemEncryptedView_Day_3_de.png new file mode 100644 index 00000000000..5e1081e563d --- /dev/null +++ b/screenshots/de/features.messages.impl.timeline.components.event_TimelineItemEncryptedView_Day_3_de.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:221a1d06bb60843e032235b6d67afe5db60aff6f842d4b256fac03e54ad36119 +size 11073 diff --git a/screenshots/de/features.messages.impl.timeline.components.event_TimelineItemImageViewHideMediaContent_Day_0_de.png b/screenshots/de/features.messages.impl.timeline.components.event_TimelineItemImageViewHideMediaContent_Day_0_de.png new file mode 100644 index 00000000000..beeff0d4cd9 --- /dev/null +++ b/screenshots/de/features.messages.impl.timeline.components.event_TimelineItemImageViewHideMediaContent_Day_0_de.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:0a7259349f4b813a21692d498734342a7f038ec437026b96c21599f9470b10c7 +size 56353 diff --git a/screenshots/de/features.messages.impl.timeline.components.event_TimelineItemLegacyCallInviteView_Day_0_de.png b/screenshots/de/features.messages.impl.timeline.components.event_TimelineItemLegacyCallInviteView_Day_0_de.png new file mode 100644 index 00000000000..99d11a266f6 --- /dev/null +++ b/screenshots/de/features.messages.impl.timeline.components.event_TimelineItemLegacyCallInviteView_Day_0_de.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:dec121edb0e8e1aebae588f7d618b191849d9ad17fcef07120f978e0322d6a46 +size 17522 diff --git a/screenshots/de/features.messages.impl.timeline.components.event_TimelineItemVideoViewHideMediaContent_Day_0_de.png b/screenshots/de/features.messages.impl.timeline.components.event_TimelineItemVideoViewHideMediaContent_Day_0_de.png new file mode 100644 index 00000000000..beeff0d4cd9 --- /dev/null +++ b/screenshots/de/features.messages.impl.timeline.components.event_TimelineItemVideoViewHideMediaContent_Day_0_de.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:0a7259349f4b813a21692d498734342a7f038ec437026b96c21599f9470b10c7 +size 56353 diff --git a/screenshots/de/features.messages.impl.timeline.components_TimelineItemEventRowUtd_Day_0_de.png b/screenshots/de/features.messages.impl.timeline.components_TimelineItemEventRowUtd_Day_0_de.png index be189bf864f..c577e8c1119 100644 --- a/screenshots/de/features.messages.impl.timeline.components_TimelineItemEventRowUtd_Day_0_de.png +++ b/screenshots/de/features.messages.impl.timeline.components_TimelineItemEventRowUtd_Day_0_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a85c3167adc0f63911759c6671871cb47d1b8384e9ab2ed04fadb014637137ea -size 32215 +oid sha256:32eeac69c1c30c1df6252b38eaed414f2b316fb08e914778e544481ae79ace7f +size 38115 diff --git a/screenshots/de/features.messages.impl.timeline.protection_ProtectedView_Day_0_de.png b/screenshots/de/features.messages.impl.timeline.protection_ProtectedView_Day_0_de.png new file mode 100644 index 00000000000..727c3651144 --- /dev/null +++ b/screenshots/de/features.messages.impl.timeline.protection_ProtectedView_Day_0_de.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:9f6c85c85a632763d077912c3a1a42d4c0096ff11df6a21fbcb2cabf91626d1b +size 64566 diff --git a/screenshots/de/features.messages.impl.timeline.protection_ProtectedView_Day_1_de.png b/screenshots/de/features.messages.impl.timeline.protection_ProtectedView_Day_1_de.png new file mode 100644 index 00000000000..beeff0d4cd9 --- /dev/null +++ b/screenshots/de/features.messages.impl.timeline.protection_ProtectedView_Day_1_de.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:0a7259349f4b813a21692d498734342a7f038ec437026b96c21599f9470b10c7 +size 56353 diff --git a/screenshots/de/features.messages.impl.timeline.protection_ProtectedView_Day_2_de.png b/screenshots/de/features.messages.impl.timeline.protection_ProtectedView_Day_2_de.png new file mode 100644 index 00000000000..9c7f261915d --- /dev/null +++ b/screenshots/de/features.messages.impl.timeline.protection_ProtectedView_Day_2_de.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:36f05e56560d77a49610d8945e6e71734ae34ffda72e794ec10af5aea0f4fdd3 +size 79861 diff --git a/screenshots/de/features.messages.impl.timeline.protection_ProtectedView_Day_3_de.png b/screenshots/de/features.messages.impl.timeline.protection_ProtectedView_Day_3_de.png new file mode 100644 index 00000000000..31329afbb57 --- /dev/null +++ b/screenshots/de/features.messages.impl.timeline.protection_ProtectedView_Day_3_de.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:31e4b9cbd0dd59ec269b9965ac9ec202b6443aa2a2621f479ec90fda8c8032a1 +size 37360 diff --git a/screenshots/de/features.preferences.impl.advanced_AdvancedSettingsView_Day_0_de.png b/screenshots/de/features.preferences.impl.advanced_AdvancedSettingsView_Day_0_de.png index d27448c6d0a..7aea7b47a7f 100644 --- a/screenshots/de/features.preferences.impl.advanced_AdvancedSettingsView_Day_0_de.png +++ b/screenshots/de/features.preferences.impl.advanced_AdvancedSettingsView_Day_0_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:352fb53b25f4406dd015b751a638b95b6f62c867c78b4f143460a41a49f931dd -size 64158 +oid sha256:e8ce478fe32b1fb8479efb86f5305611e5f1237a98f12392acb1a79bfe43af55 +size 68549 diff --git a/screenshots/de/features.preferences.impl.advanced_AdvancedSettingsView_Day_1_de.png b/screenshots/de/features.preferences.impl.advanced_AdvancedSettingsView_Day_1_de.png index 922c3cd9ffc..55c94e44cff 100644 --- a/screenshots/de/features.preferences.impl.advanced_AdvancedSettingsView_Day_1_de.png +++ b/screenshots/de/features.preferences.impl.advanced_AdvancedSettingsView_Day_1_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c1b44b5f03ec9fc35d70b7ea99f6d80a634ae0b0e054c43b8bbf7edd1bac29de -size 63928 +oid sha256:5fdd3f6aff2518164dd958d3f4b3ff014e2c4c5f6714525ee9fc15eec6df76cb +size 68305 diff --git a/screenshots/de/features.preferences.impl.advanced_AdvancedSettingsView_Day_2_de.png b/screenshots/de/features.preferences.impl.advanced_AdvancedSettingsView_Day_2_de.png index 5c5334c17a5..735c5939a7f 100644 --- a/screenshots/de/features.preferences.impl.advanced_AdvancedSettingsView_Day_2_de.png +++ b/screenshots/de/features.preferences.impl.advanced_AdvancedSettingsView_Day_2_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:8b62f107635c081db2941d1d9eb17be8e2c1ed9a09ba5d87328e3c5cf188eb76 -size 34110 +oid sha256:77258323ec2889688d40e6ea6e43c31b8d433a129ac5429a4234cc112763fb33 +size 34125 diff --git a/screenshots/de/features.preferences.impl.advanced_AdvancedSettingsView_Day_3_de.png b/screenshots/de/features.preferences.impl.advanced_AdvancedSettingsView_Day_3_de.png index 0fa887a89b1..50010c62050 100644 --- a/screenshots/de/features.preferences.impl.advanced_AdvancedSettingsView_Day_3_de.png +++ b/screenshots/de/features.preferences.impl.advanced_AdvancedSettingsView_Day_3_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:4035d14464ba0260626c8bb01f2381f521bdc051e4fae9531b48e748c10d7a20 -size 63965 +oid sha256:80413c20e81da286a97ff62630426bb0700fd48e7fdbf2d039a89c77485c8b36 +size 68356 diff --git a/screenshots/de/features.preferences.impl.advanced_AdvancedSettingsView_Day_4_de.png b/screenshots/de/features.preferences.impl.advanced_AdvancedSettingsView_Day_4_de.png index ca163fb0c82..b908d63738e 100644 --- a/screenshots/de/features.preferences.impl.advanced_AdvancedSettingsView_Day_4_de.png +++ b/screenshots/de/features.preferences.impl.advanced_AdvancedSettingsView_Day_4_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:45123998d710d83e7bf1094493b16c3210a70e34e406b12ce227bd7cc78b3d87 -size 64020 +oid sha256:9182d5dbaad926abfaf55d80a4af3aa7da6e45054ed2a02fdaefdea081b66506 +size 68344 diff --git a/screenshots/de/features.preferences.impl.root_PreferencesRootViewDark_0_de.png b/screenshots/de/features.preferences.impl.root_PreferencesRootViewDark_0_de.png index 1a33248017f..f3a33c216f5 100644 --- a/screenshots/de/features.preferences.impl.root_PreferencesRootViewDark_0_de.png +++ b/screenshots/de/features.preferences.impl.root_PreferencesRootViewDark_0_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:11fa8c3567744e5e9c7020ebdb2b9a6fa45ea5e970db337850a30c12d5eab37b -size 38148 +oid sha256:6352cd3ad10f0f5c85323915efc8549aa6e1a45a722b594a0ddf3a055a29c20e +size 39255 diff --git a/screenshots/de/features.preferences.impl.root_PreferencesRootViewDark_1_de.png b/screenshots/de/features.preferences.impl.root_PreferencesRootViewDark_1_de.png index 1c0c2897301..7993c9035e7 100644 --- a/screenshots/de/features.preferences.impl.root_PreferencesRootViewDark_1_de.png +++ b/screenshots/de/features.preferences.impl.root_PreferencesRootViewDark_1_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:8d24fdf8a38152d2e7800fef245fa62af144281faba4a66e692f9b2ab2e5bb49 -size 37911 +oid sha256:479cb8fd5b10c836691b05901b28c2bb3fd1557c5c9404e42551a8707610270c +size 39008 diff --git a/screenshots/de/features.preferences.impl.root_PreferencesRootViewLight_0_de.png b/screenshots/de/features.preferences.impl.root_PreferencesRootViewLight_0_de.png index 2cb1e4fd51b..612dfdde6b3 100644 --- a/screenshots/de/features.preferences.impl.root_PreferencesRootViewLight_0_de.png +++ b/screenshots/de/features.preferences.impl.root_PreferencesRootViewLight_0_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:7e436f63c5c966f52ea636fb8ce8899f2ec41af253a5c2452929bdf35cf8b7fc -size 39075 +oid sha256:ae6ec5516e850143f886d79cc8b3ea89aa892c7e2cd28bdd613adc605446db57 +size 40263 diff --git a/screenshots/de/features.preferences.impl.root_PreferencesRootViewLight_1_de.png b/screenshots/de/features.preferences.impl.root_PreferencesRootViewLight_1_de.png index a3f61713653..e456d7199f1 100644 --- a/screenshots/de/features.preferences.impl.root_PreferencesRootViewLight_1_de.png +++ b/screenshots/de/features.preferences.impl.root_PreferencesRootViewLight_1_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:3f98728c171887bb999ae38f0ca90aaaa932303dce159aeb35328a6a6bde9ef8 -size 39098 +oid sha256:6ae4cf626f2119a24ccdb459c398277e7f3ed9f0af6449e3c31c192a770f1a53 +size 40266 diff --git a/screenshots/de/features.roomlist.impl.components_ConfirmRecoveryKeyBanner_Day_0_de.png b/screenshots/de/features.roomlist.impl.components_ConfirmRecoveryKeyBanner_Day_0_de.png index b049d02dfa0..ff762510cd1 100644 --- a/screenshots/de/features.roomlist.impl.components_ConfirmRecoveryKeyBanner_Day_0_de.png +++ b/screenshots/de/features.roomlist.impl.components_ConfirmRecoveryKeyBanner_Day_0_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:9ef48f6780db9379564395e728a693fec3ebc10e67a5c8026ccd9b0f82b0eed6 -size 34976 +oid sha256:7b8dd8db1c8726821961ddad6cadb6f5b93e09de680a53a21a7f8eba05dc2b02 +size 35624 diff --git a/screenshots/de/features.roomlist.impl.components_RoomSummaryRow_Day_32_de.png b/screenshots/de/features.roomlist.impl.components_RoomSummaryRow_Day_32_de.png new file mode 100644 index 00000000000..8c19f4b18e0 --- /dev/null +++ b/screenshots/de/features.roomlist.impl.components_RoomSummaryRow_Day_32_de.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2b19b09aca863e75b0bfbc404274f6ce3a2349fdbf2bf0c20c9b6bacdac79f08 +size 12682 diff --git a/screenshots/de/features.roomlist.impl.components_RoomSummaryRow_Day_33_de.png b/screenshots/de/features.roomlist.impl.components_RoomSummaryRow_Day_33_de.png new file mode 100644 index 00000000000..08644eb1387 --- /dev/null +++ b/screenshots/de/features.roomlist.impl.components_RoomSummaryRow_Day_33_de.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:9817f47746af25e3815f8038de109e13641c5ef1c8d18f55585dff1c796ee92a +size 18023 diff --git a/screenshots/de/features.roomlist.impl_RoomListView_Day_6_de.png b/screenshots/de/features.roomlist.impl_RoomListView_Day_6_de.png index 1e81f1545e2..893603d4604 100644 --- a/screenshots/de/features.roomlist.impl_RoomListView_Day_6_de.png +++ b/screenshots/de/features.roomlist.impl_RoomListView_Day_6_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:d7870bb4121a26d26ef0d74a0bb0cff86b80d0d47d82777279963dfe1a73a6e3 -size 106085 +oid sha256:592260b54144926121cab51c04507d52d02b0b26a105d3628a0be7c786311ef1 +size 106443 diff --git a/screenshots/de/features.securebackup.impl.enter_SecureBackupEnterRecoveryKeyView_Day_0_de.png b/screenshots/de/features.securebackup.impl.enter_SecureBackupEnterRecoveryKeyView_Day_0_de.png index dd0e572ffdc..d25e0de53a2 100644 --- a/screenshots/de/features.securebackup.impl.enter_SecureBackupEnterRecoveryKeyView_Day_0_de.png +++ b/screenshots/de/features.securebackup.impl.enter_SecureBackupEnterRecoveryKeyView_Day_0_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:9779f1715cad0e14921e3a3e6a9bd681e604f3d4eba74bc3184a9b0a558a0051 -size 38538 +oid sha256:0e49141bdd0efb68227de5957cbc973e10552e4596786d4687a64256aadc82a1 +size 44720 diff --git a/screenshots/de/features.securebackup.impl.enter_SecureBackupEnterRecoveryKeyView_Day_1_de.png b/screenshots/de/features.securebackup.impl.enter_SecureBackupEnterRecoveryKeyView_Day_1_de.png index 4ee3c0861ad..e1b8666a473 100644 --- a/screenshots/de/features.securebackup.impl.enter_SecureBackupEnterRecoveryKeyView_Day_1_de.png +++ b/screenshots/de/features.securebackup.impl.enter_SecureBackupEnterRecoveryKeyView_Day_1_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:4892294712b7550c0e7eb281bd167f57f7494cd150e310773ce128a927bfc7d0 -size 48197 +oid sha256:6ff26d8fad93fd5c6c0abb70911bae92974ab1977f46104cef3babee23519811 +size 54013 diff --git a/screenshots/de/features.securebackup.impl.enter_SecureBackupEnterRecoveryKeyView_Day_2_de.png b/screenshots/de/features.securebackup.impl.enter_SecureBackupEnterRecoveryKeyView_Day_2_de.png index b4dbdff9fd6..6c9464c6b90 100644 --- a/screenshots/de/features.securebackup.impl.enter_SecureBackupEnterRecoveryKeyView_Day_2_de.png +++ b/screenshots/de/features.securebackup.impl.enter_SecureBackupEnterRecoveryKeyView_Day_2_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:b49405296483544738d2976b2e11475693a7c6929a9e29fef29675ce9a4d1e7c -size 48418 +oid sha256:527c0361bb776783a7b776e5a6ecd61c84868b26aa9fe0da96f665ef17674bfa +size 54078 diff --git a/screenshots/de/features.securebackup.impl.enter_SecureBackupEnterRecoveryKeyView_Day_3_de.png b/screenshots/de/features.securebackup.impl.enter_SecureBackupEnterRecoveryKeyView_Day_3_de.png index 4bd059258f3..fc90557bf5a 100644 --- a/screenshots/de/features.securebackup.impl.enter_SecureBackupEnterRecoveryKeyView_Day_3_de.png +++ b/screenshots/de/features.securebackup.impl.enter_SecureBackupEnterRecoveryKeyView_Day_3_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:8e2a91b44b95d1e3b496338d779748e2bed96f28b49579e7b830b4ae386fd2e8 -size 38458 +oid sha256:0b6722105b7d2db210a97873b6c52902ba1ea3ec5fb318e79d90f96b4b43deb6 +size 51377 diff --git a/screenshots/de/features.securebackup.impl.reset.root_ResetIdentityRootView_Day_0_de.png b/screenshots/de/features.securebackup.impl.reset.root_ResetIdentityRootView_Day_0_de.png index 53b9314e99f..eb84ffe273d 100644 --- a/screenshots/de/features.securebackup.impl.reset.root_ResetIdentityRootView_Day_0_de.png +++ b/screenshots/de/features.securebackup.impl.reset.root_ResetIdentityRootView_Day_0_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c638686810e9c13046d0d84bf77bae9bb2858c4a0c189d0d090a5dae74667093 -size 76313 +oid sha256:9a9cdc1a43c73d3d59a6f45110e78a81e525cb07e6d3d90241f702331545f854 +size 80738 diff --git a/screenshots/de/features.securebackup.impl.reset.root_ResetIdentityRootView_Day_1_de.png b/screenshots/de/features.securebackup.impl.reset.root_ResetIdentityRootView_Day_1_de.png index d226904f506..0e301fc455a 100644 --- a/screenshots/de/features.securebackup.impl.reset.root_ResetIdentityRootView_Day_1_de.png +++ b/screenshots/de/features.securebackup.impl.reset.root_ResetIdentityRootView_Day_1_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ff9b1178dc700652e6528c26ccbb3a1f81e07bbbc745302831c43d59ed6aea13 -size 64732 +oid sha256:b1f1aacf324499608f888cf31360d5305d6f28b4dabd04b404e8299b9a094046 +size 64741 diff --git a/screenshots/de/features.securebackup.impl.root_SecureBackupRootView_Day_0_de.png b/screenshots/de/features.securebackup.impl.root_SecureBackupRootView_Day_0_de.png index 690f086352c..616ccc45812 100644 --- a/screenshots/de/features.securebackup.impl.root_SecureBackupRootView_Day_0_de.png +++ b/screenshots/de/features.securebackup.impl.root_SecureBackupRootView_Day_0_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c323c13474785b3dc08400a7bd408d549c964db66012d09132094526f5de7e4d -size 25252 +oid sha256:815b0cd937d4a1cdd3ea44134146396e60df37d8d44bc2a44a19f07d4f738757 +size 45163 diff --git a/screenshots/de/features.securebackup.impl.root_SecureBackupRootView_Day_10_de.png b/screenshots/de/features.securebackup.impl.root_SecureBackupRootView_Day_10_de.png index 690f086352c..616ccc45812 100644 --- a/screenshots/de/features.securebackup.impl.root_SecureBackupRootView_Day_10_de.png +++ b/screenshots/de/features.securebackup.impl.root_SecureBackupRootView_Day_10_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c323c13474785b3dc08400a7bd408d549c964db66012d09132094526f5de7e4d -size 25252 +oid sha256:815b0cd937d4a1cdd3ea44134146396e60df37d8d44bc2a44a19f07d4f738757 +size 45163 diff --git a/screenshots/de/features.securebackup.impl.root_SecureBackupRootView_Day_11_de.png b/screenshots/de/features.securebackup.impl.root_SecureBackupRootView_Day_11_de.png index 945bc6b0f05..2fa1e1091ed 100644 --- a/screenshots/de/features.securebackup.impl.root_SecureBackupRootView_Day_11_de.png +++ b/screenshots/de/features.securebackup.impl.root_SecureBackupRootView_Day_11_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:5e90577ef426511ba1e63bc179a6acc34cdff38b712e32c4c4b9ab4f98f86783 -size 26037 +oid sha256:7a1d3cd113712fb92a16e5dba4ca654332de17ba9b8bf358c2822ecc15ab4f78 +size 46111 diff --git a/screenshots/de/features.securebackup.impl.root_SecureBackupRootView_Day_12_de.png b/screenshots/de/features.securebackup.impl.root_SecureBackupRootView_Day_12_de.png index 945bc6b0f05..2fa1e1091ed 100644 --- a/screenshots/de/features.securebackup.impl.root_SecureBackupRootView_Day_12_de.png +++ b/screenshots/de/features.securebackup.impl.root_SecureBackupRootView_Day_12_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:5e90577ef426511ba1e63bc179a6acc34cdff38b712e32c4c4b9ab4f98f86783 -size 26037 +oid sha256:7a1d3cd113712fb92a16e5dba4ca654332de17ba9b8bf358c2822ecc15ab4f78 +size 46111 diff --git a/screenshots/de/features.securebackup.impl.root_SecureBackupRootView_Day_13_de.png b/screenshots/de/features.securebackup.impl.root_SecureBackupRootView_Day_13_de.png index 1c65f225b87..b80d9bd4afa 100644 --- a/screenshots/de/features.securebackup.impl.root_SecureBackupRootView_Day_13_de.png +++ b/screenshots/de/features.securebackup.impl.root_SecureBackupRootView_Day_13_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:b0a5ca246bc6a1c2ad9e983e025dd02b9f205ec09293e1e676ee88491e017e37 -size 48712 +oid sha256:f7ecfb9c5ba42edaf1123f7d4fd1dae9d036b51b9a992401ccaefe512abd26b6 +size 74574 diff --git a/screenshots/de/features.securebackup.impl.root_SecureBackupRootView_Day_14_de.png b/screenshots/de/features.securebackup.impl.root_SecureBackupRootView_Day_14_de.png index dc14b8dcbd0..8670a3339f6 100644 --- a/screenshots/de/features.securebackup.impl.root_SecureBackupRootView_Day_14_de.png +++ b/screenshots/de/features.securebackup.impl.root_SecureBackupRootView_Day_14_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:11c25fc7c638ce5ab76981752109fc39aec07f1c3f1a90786b37af98e54233ac -size 48962 +oid sha256:953284ce01229f35b10299ed63200cbb3f43d85cc9a44508651f79696feb3883 +size 68248 diff --git a/screenshots/de/features.securebackup.impl.root_SecureBackupRootView_Day_15_de.png b/screenshots/de/features.securebackup.impl.root_SecureBackupRootView_Day_15_de.png index 564282a8448..f195be70765 100644 --- a/screenshots/de/features.securebackup.impl.root_SecureBackupRootView_Day_15_de.png +++ b/screenshots/de/features.securebackup.impl.root_SecureBackupRootView_Day_15_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:3e596d6454d6edb86d6ec9da01b96f6dd46798d062614da75d27e2a4b5e14f83 -size 40260 +oid sha256:eedcee266e42accc3958a5c09b5abdcc493321e6da5455ceac43649c9f468d5a +size 58773 diff --git a/screenshots/de/features.securebackup.impl.root_SecureBackupRootView_Day_16_de.png b/screenshots/de/features.securebackup.impl.root_SecureBackupRootView_Day_16_de.png index 77f522ed2f9..7be694d95b1 100644 --- a/screenshots/de/features.securebackup.impl.root_SecureBackupRootView_Day_16_de.png +++ b/screenshots/de/features.securebackup.impl.root_SecureBackupRootView_Day_16_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:35c99f0390cfe7dd87cbdd8cd4f931f3fa8aa6d41db578e9c7398c86a23f64e0 -size 46810 +oid sha256:2592bf3e90874c10506b127d3054a7ced3de2acac17f2b03906d9dae1a33d4c4 +size 72494 diff --git a/screenshots/de/features.securebackup.impl.root_SecureBackupRootView_Day_17_de.png b/screenshots/de/features.securebackup.impl.root_SecureBackupRootView_Day_17_de.png index 66ffba64e56..c4277961c15 100644 --- a/screenshots/de/features.securebackup.impl.root_SecureBackupRootView_Day_17_de.png +++ b/screenshots/de/features.securebackup.impl.root_SecureBackupRootView_Day_17_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:acad340964847803a06f3d0ea38c93b706d1b2e35369c122ffe0a1e77ce177ba -size 36929 +oid sha256:40151413a5adabdb8440a8cc1dcd9049171e07502529fbfb1390a46fc452aa84 +size 49058 diff --git a/screenshots/de/features.securebackup.impl.root_SecureBackupRootView_Day_1_de.png b/screenshots/de/features.securebackup.impl.root_SecureBackupRootView_Day_1_de.png index 945bc6b0f05..2fa1e1091ed 100644 --- a/screenshots/de/features.securebackup.impl.root_SecureBackupRootView_Day_1_de.png +++ b/screenshots/de/features.securebackup.impl.root_SecureBackupRootView_Day_1_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:5e90577ef426511ba1e63bc179a6acc34cdff38b712e32c4c4b9ab4f98f86783 -size 26037 +oid sha256:7a1d3cd113712fb92a16e5dba4ca654332de17ba9b8bf358c2822ecc15ab4f78 +size 46111 diff --git a/screenshots/de/features.securebackup.impl.root_SecureBackupRootView_Day_2_de.png b/screenshots/de/features.securebackup.impl.root_SecureBackupRootView_Day_2_de.png index 4e68672dc4f..6563d138b1b 100644 --- a/screenshots/de/features.securebackup.impl.root_SecureBackupRootView_Day_2_de.png +++ b/screenshots/de/features.securebackup.impl.root_SecureBackupRootView_Day_2_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:eee8ee71e1fdbec8b0872fa2b1fd9dfc3094c808a5923e0f4bb21fe565472d50 -size 26310 +oid sha256:5519b95d8ef1f1e58e3a1f212440f382e18d34cd5400da3dbdda0cbb2c125cf7 +size 46489 diff --git a/screenshots/de/features.securebackup.impl.root_SecureBackupRootView_Day_3_de.png b/screenshots/de/features.securebackup.impl.root_SecureBackupRootView_Day_3_de.png index d06959de0df..c5633cd09ba 100644 --- a/screenshots/de/features.securebackup.impl.root_SecureBackupRootView_Day_3_de.png +++ b/screenshots/de/features.securebackup.impl.root_SecureBackupRootView_Day_3_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:206b2f37f6efa2b25bfc84a5a8b0b110703d06197b87676c46faf0daca24d4e3 -size 26688 +oid sha256:b431982e400c16c24b8e97ab4bcc70c8c5af25f929a2f7ae2679c32483cb142d +size 47347 diff --git a/screenshots/de/features.securebackup.impl.root_SecureBackupRootView_Day_4_de.png b/screenshots/de/features.securebackup.impl.root_SecureBackupRootView_Day_4_de.png index 690f086352c..616ccc45812 100644 --- a/screenshots/de/features.securebackup.impl.root_SecureBackupRootView_Day_4_de.png +++ b/screenshots/de/features.securebackup.impl.root_SecureBackupRootView_Day_4_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c323c13474785b3dc08400a7bd408d549c964db66012d09132094526f5de7e4d -size 25252 +oid sha256:815b0cd937d4a1cdd3ea44134146396e60df37d8d44bc2a44a19f07d4f738757 +size 45163 diff --git a/screenshots/de/features.securebackup.impl.root_SecureBackupRootView_Day_5_de.png b/screenshots/de/features.securebackup.impl.root_SecureBackupRootView_Day_5_de.png index 945bc6b0f05..2fa1e1091ed 100644 --- a/screenshots/de/features.securebackup.impl.root_SecureBackupRootView_Day_5_de.png +++ b/screenshots/de/features.securebackup.impl.root_SecureBackupRootView_Day_5_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:5e90577ef426511ba1e63bc179a6acc34cdff38b712e32c4c4b9ab4f98f86783 -size 26037 +oid sha256:7a1d3cd113712fb92a16e5dba4ca654332de17ba9b8bf358c2822ecc15ab4f78 +size 46111 diff --git a/screenshots/de/features.securebackup.impl.root_SecureBackupRootView_Day_6_de.png b/screenshots/de/features.securebackup.impl.root_SecureBackupRootView_Day_6_de.png index 86b5a69e6a1..3ca86ce78c2 100644 --- a/screenshots/de/features.securebackup.impl.root_SecureBackupRootView_Day_6_de.png +++ b/screenshots/de/features.securebackup.impl.root_SecureBackupRootView_Day_6_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:aa0f1d7099c533d80c6420b6e74db32acd9421cdc662873b6d5201dddeacf63d -size 27767 +oid sha256:f4594a9e98992a8bc6367cd3d5ce516e7077c700d433d4b332dd69ecd054c932 +size 38795 diff --git a/screenshots/de/features.securebackup.impl.root_SecureBackupRootView_Day_7_de.png b/screenshots/de/features.securebackup.impl.root_SecureBackupRootView_Day_7_de.png index 945bc6b0f05..2fa1e1091ed 100644 --- a/screenshots/de/features.securebackup.impl.root_SecureBackupRootView_Day_7_de.png +++ b/screenshots/de/features.securebackup.impl.root_SecureBackupRootView_Day_7_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:5e90577ef426511ba1e63bc179a6acc34cdff38b712e32c4c4b9ab4f98f86783 -size 26037 +oid sha256:7a1d3cd113712fb92a16e5dba4ca654332de17ba9b8bf358c2822ecc15ab4f78 +size 46111 diff --git a/screenshots/de/features.securebackup.impl.root_SecureBackupRootView_Day_8_de.png b/screenshots/de/features.securebackup.impl.root_SecureBackupRootView_Day_8_de.png index 945bc6b0f05..2fa1e1091ed 100644 --- a/screenshots/de/features.securebackup.impl.root_SecureBackupRootView_Day_8_de.png +++ b/screenshots/de/features.securebackup.impl.root_SecureBackupRootView_Day_8_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:5e90577ef426511ba1e63bc179a6acc34cdff38b712e32c4c4b9ab4f98f86783 -size 26037 +oid sha256:7a1d3cd113712fb92a16e5dba4ca654332de17ba9b8bf358c2822ecc15ab4f78 +size 46111 diff --git a/screenshots/de/features.securebackup.impl.root_SecureBackupRootView_Day_9_de.png b/screenshots/de/features.securebackup.impl.root_SecureBackupRootView_Day_9_de.png index 945bc6b0f05..2fa1e1091ed 100644 --- a/screenshots/de/features.securebackup.impl.root_SecureBackupRootView_Day_9_de.png +++ b/screenshots/de/features.securebackup.impl.root_SecureBackupRootView_Day_9_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:5e90577ef426511ba1e63bc179a6acc34cdff38b712e32c4c4b9ab4f98f86783 -size 26037 +oid sha256:7a1d3cd113712fb92a16e5dba4ca654332de17ba9b8bf358c2822ecc15ab4f78 +size 46111 diff --git a/screenshots/de/features.securebackup.impl.setup.views_RecoveryKeyView_Day_0_de.png b/screenshots/de/features.securebackup.impl.setup.views_RecoveryKeyView_Day_0_de.png index 49c0d7f6e88..3ca90a2b944 100644 --- a/screenshots/de/features.securebackup.impl.setup.views_RecoveryKeyView_Day_0_de.png +++ b/screenshots/de/features.securebackup.impl.setup.views_RecoveryKeyView_Day_0_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:8a7ea8c219d7d75cad52646affe980ae477dfa33ca065eb10df1b2da5615de45 -size 27463 +oid sha256:2e2a87a2163523d4f9b4a59d19955b3ebdcc6660c14131a4b983e0bf62f846ad +size 20851 diff --git a/screenshots/de/features.securebackup.impl.setup.views_RecoveryKeyView_Day_1_de.png b/screenshots/de/features.securebackup.impl.setup.views_RecoveryKeyView_Day_1_de.png index 8d4f6596fd4..69874f12d82 100644 --- a/screenshots/de/features.securebackup.impl.setup.views_RecoveryKeyView_Day_1_de.png +++ b/screenshots/de/features.securebackup.impl.setup.views_RecoveryKeyView_Day_1_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:cb944176e84eb2b4938d0afd508ef0878ac1b1c75cf13f24d7eca71407c0be89 -size 24280 +oid sha256:bdaead12b54724228ec5c3d0193f2e0d13037825bd224e0f06b36abb1360c189 +size 17051 diff --git a/screenshots/de/features.securebackup.impl.setup.views_RecoveryKeyView_Day_4_de.png b/screenshots/de/features.securebackup.impl.setup.views_RecoveryKeyView_Day_4_de.png index 49c0d7f6e88..3ca90a2b944 100644 --- a/screenshots/de/features.securebackup.impl.setup.views_RecoveryKeyView_Day_4_de.png +++ b/screenshots/de/features.securebackup.impl.setup.views_RecoveryKeyView_Day_4_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:8a7ea8c219d7d75cad52646affe980ae477dfa33ca065eb10df1b2da5615de45 -size 27463 +oid sha256:2e2a87a2163523d4f9b4a59d19955b3ebdcc6660c14131a4b983e0bf62f846ad +size 20851 diff --git a/screenshots/de/features.securebackup.impl.setup.views_RecoveryKeyView_Day_5_de.png b/screenshots/de/features.securebackup.impl.setup.views_RecoveryKeyView_Day_5_de.png index 8d4f6596fd4..69874f12d82 100644 --- a/screenshots/de/features.securebackup.impl.setup.views_RecoveryKeyView_Day_5_de.png +++ b/screenshots/de/features.securebackup.impl.setup.views_RecoveryKeyView_Day_5_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:cb944176e84eb2b4938d0afd508ef0878ac1b1c75cf13f24d7eca71407c0be89 -size 24280 +oid sha256:bdaead12b54724228ec5c3d0193f2e0d13037825bd224e0f06b36abb1360c189 +size 17051 diff --git a/screenshots/de/features.securebackup.impl.setup_SecureBackupSetupViewChange_Day_0_de.png b/screenshots/de/features.securebackup.impl.setup_SecureBackupSetupViewChange_Day_0_de.png index 50fe34193c9..d18129135bc 100644 --- a/screenshots/de/features.securebackup.impl.setup_SecureBackupSetupViewChange_Day_0_de.png +++ b/screenshots/de/features.securebackup.impl.setup_SecureBackupSetupViewChange_Day_0_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ec1ce0a2ee199839e7a29f9ec41cf10c0c922c1516ecc5bffa2ec24abd55f62b -size 65037 +oid sha256:6851b1d71546d2cdbbb063d49fe4ae2fe72338b46c88b1f502838c4b19b9d1a8 +size 57420 diff --git a/screenshots/de/features.securebackup.impl.setup_SecureBackupSetupViewChange_Day_1_de.png b/screenshots/de/features.securebackup.impl.setup_SecureBackupSetupViewChange_Day_1_de.png index 2fa70f2c094..e1874050779 100644 --- a/screenshots/de/features.securebackup.impl.setup_SecureBackupSetupViewChange_Day_1_de.png +++ b/screenshots/de/features.securebackup.impl.setup_SecureBackupSetupViewChange_Day_1_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c9274f47c16777317e8218ffe74f6e084dfc7a9112d5b46f2be7c480ef41af88 -size 61516 +oid sha256:247cba8f887e87a29e1302f19ba0980b5b475d7e424db345417753dd1789f414 +size 53937 diff --git a/screenshots/de/features.securebackup.impl.setup_SecureBackupSetupViewChange_Day_2_de.png b/screenshots/de/features.securebackup.impl.setup_SecureBackupSetupViewChange_Day_2_de.png index 1d60e190407..8f575530981 100644 --- a/screenshots/de/features.securebackup.impl.setup_SecureBackupSetupViewChange_Day_2_de.png +++ b/screenshots/de/features.securebackup.impl.setup_SecureBackupSetupViewChange_Day_2_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:91c28ce4fd47b06d4a20070ec364ce7bcd5b53d6364903eded573f72e07c0f71 -size 65630 +oid sha256:80c9e88ccbc95fc4ba7cd14f4077b07922666c2227401d6029928b3d37108ca0 +size 67131 diff --git a/screenshots/de/features.securebackup.impl.setup_SecureBackupSetupViewChange_Day_3_de.png b/screenshots/de/features.securebackup.impl.setup_SecureBackupSetupViewChange_Day_3_de.png index 1d60e190407..8f575530981 100644 --- a/screenshots/de/features.securebackup.impl.setup_SecureBackupSetupViewChange_Day_3_de.png +++ b/screenshots/de/features.securebackup.impl.setup_SecureBackupSetupViewChange_Day_3_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:91c28ce4fd47b06d4a20070ec364ce7bcd5b53d6364903eded573f72e07c0f71 -size 65630 +oid sha256:80c9e88ccbc95fc4ba7cd14f4077b07922666c2227401d6029928b3d37108ca0 +size 67131 diff --git a/screenshots/de/features.securebackup.impl.setup_SecureBackupSetupView_Day_0_de.png b/screenshots/de/features.securebackup.impl.setup_SecureBackupSetupView_Day_0_de.png index 6be838cbcab..c483727895b 100644 --- a/screenshots/de/features.securebackup.impl.setup_SecureBackupSetupView_Day_0_de.png +++ b/screenshots/de/features.securebackup.impl.setup_SecureBackupSetupView_Day_0_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:be88a4b4c469dee0cad669ec92370f1f76aaea79a899fd38bb3c7277cfc03a31 -size 69951 +oid sha256:2144e09a7a3859cd53048aa93ad4614cb56a2a9686923b9862c7a7fc80d7bad2 +size 62530 diff --git a/screenshots/de/features.securebackup.impl.setup_SecureBackupSetupView_Day_1_de.png b/screenshots/de/features.securebackup.impl.setup_SecureBackupSetupView_Day_1_de.png index f5ff7322b0f..80740d87909 100644 --- a/screenshots/de/features.securebackup.impl.setup_SecureBackupSetupView_Day_1_de.png +++ b/screenshots/de/features.securebackup.impl.setup_SecureBackupSetupView_Day_1_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:78e49c4ae78ec14430b2397b5bdde5d26bc97bec3f4705fc69c605c8eaa1ade5 -size 66631 +oid sha256:eb00965758191b4dc08dfd6ff5cf82af4165cd1f1cad08e5da7aab9a16284d2f +size 59171 diff --git a/screenshots/de/features.securebackup.impl.setup_SecureBackupSetupView_Day_2_de.png b/screenshots/de/features.securebackup.impl.setup_SecureBackupSetupView_Day_2_de.png index 1d60e190407..8f575530981 100644 --- a/screenshots/de/features.securebackup.impl.setup_SecureBackupSetupView_Day_2_de.png +++ b/screenshots/de/features.securebackup.impl.setup_SecureBackupSetupView_Day_2_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:91c28ce4fd47b06d4a20070ec364ce7bcd5b53d6364903eded573f72e07c0f71 -size 65630 +oid sha256:80c9e88ccbc95fc4ba7cd14f4077b07922666c2227401d6029928b3d37108ca0 +size 67131 diff --git a/screenshots/de/features.securebackup.impl.setup_SecureBackupSetupView_Day_3_de.png b/screenshots/de/features.securebackup.impl.setup_SecureBackupSetupView_Day_3_de.png index 1d60e190407..8f575530981 100644 --- a/screenshots/de/features.securebackup.impl.setup_SecureBackupSetupView_Day_3_de.png +++ b/screenshots/de/features.securebackup.impl.setup_SecureBackupSetupView_Day_3_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:91c28ce4fd47b06d4a20070ec364ce7bcd5b53d6364903eded573f72e07c0f71 -size 65630 +oid sha256:80c9e88ccbc95fc4ba7cd14f4077b07922666c2227401d6029928b3d37108ca0 +size 67131 diff --git a/screenshots/de/features.userprofile.shared_UserProfileHeaderSection_Day_0_de.png b/screenshots/de/features.userprofile.shared_UserProfileHeaderSection_Day_0_de.png new file mode 100644 index 00000000000..97877dcb479 --- /dev/null +++ b/screenshots/de/features.userprofile.shared_UserProfileHeaderSection_Day_0_de.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d3a07ae4167cf29cfe165d3acc04e64b0c614d81bc542d57ed1d7a3b68605342 +size 15442 diff --git a/screenshots/de/features.userprofile.shared_UserProfileView_Day_0_de.png b/screenshots/de/features.userprofile.shared_UserProfileView_Day_0_de.png index ff0981041c7..f13d3331493 100644 --- a/screenshots/de/features.userprofile.shared_UserProfileView_Day_0_de.png +++ b/screenshots/de/features.userprofile.shared_UserProfileView_Day_0_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:4d5708cb60a8d4b7a0d1c5c4b1621bc320dc0af3865ed79f17d9fa61ddcdf679 -size 29727 +oid sha256:116f716ad3bc6b519afbc3f6fcd5b019ef61e2846f4c20d516c68bbdce819895 +size 34316 diff --git a/screenshots/de/features.userprofile.shared_UserProfileView_Day_1_de.png b/screenshots/de/features.userprofile.shared_UserProfileView_Day_1_de.png index 89f37b38860..b4a0a02716c 100644 --- a/screenshots/de/features.userprofile.shared_UserProfileView_Day_1_de.png +++ b/screenshots/de/features.userprofile.shared_UserProfileView_Day_1_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:cf667fb981046b9e99c3cb689d5f23292471805b45d6aeefbe76ca876a4cca19 -size 27791 +oid sha256:3df860d4a1953ea868def4b83337dcd46b1e5922a4705739408f36432afd860c +size 31952 diff --git a/screenshots/de/features.userprofile.shared_UserProfileView_Day_2_de.png b/screenshots/de/features.userprofile.shared_UserProfileView_Day_2_de.png index 2179c311ced..18409948e05 100644 --- a/screenshots/de/features.userprofile.shared_UserProfileView_Day_2_de.png +++ b/screenshots/de/features.userprofile.shared_UserProfileView_Day_2_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:8967f48f6c93e957e93c0106f677ad570fdd601f064eb00f42d02f0b51dd9279 -size 25090 +oid sha256:a7a0515afdd3cb84d9eb3fee0e893c9070bedfc3d17590fc4b443f22af5060f0 +size 25230 diff --git a/screenshots/de/features.userprofile.shared_UserProfileView_Day_3_de.png b/screenshots/de/features.userprofile.shared_UserProfileView_Day_3_de.png index bb6d162b419..7b4f2fb7297 100644 --- a/screenshots/de/features.userprofile.shared_UserProfileView_Day_3_de.png +++ b/screenshots/de/features.userprofile.shared_UserProfileView_Day_3_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ebef17540507cfefef165c21e644b3406cfe6cdb149598858b75ef73557edb4e -size 44649 +oid sha256:37636f644edacd051fc73229790a4d91738498e4b11b2a7a262a05c81910da84 +size 44648 diff --git a/screenshots/de/features.userprofile.shared_UserProfileView_Day_4_de.png b/screenshots/de/features.userprofile.shared_UserProfileView_Day_4_de.png index 37e9366a7c7..32495b65fec 100644 --- a/screenshots/de/features.userprofile.shared_UserProfileView_Day_4_de.png +++ b/screenshots/de/features.userprofile.shared_UserProfileView_Day_4_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:4da8f02c7ea4823fb6978066acb901d192be7be2edd449fbf8e56c2e0e960829 -size 38948 +oid sha256:e9cc06c97c578e5d55c619bf022c5e9594aa5f07591e8e48c0e9662feb49e739 +size 38946 diff --git a/screenshots/de/features.userprofile.shared_UserProfileView_Day_6_de.png b/screenshots/de/features.userprofile.shared_UserProfileView_Day_6_de.png index fe0d92427b4..ac1e1a2eaf6 100644 --- a/screenshots/de/features.userprofile.shared_UserProfileView_Day_6_de.png +++ b/screenshots/de/features.userprofile.shared_UserProfileView_Day_6_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:e735d995e2300af280d5533ad4f31ab4dc0d71d58ef5a73f6c597d815691f0ef -size 28501 +oid sha256:e9bcc4faf5570bf743811b7a187a480049e4c859e9c2e827734cf50e85a969d9 +size 31297 diff --git a/screenshots/de/features.userprofile.shared_UserProfileView_Day_7_de.png b/screenshots/de/features.userprofile.shared_UserProfileView_Day_7_de.png index 27cfccb2264..ff87178f4df 100644 --- a/screenshots/de/features.userprofile.shared_UserProfileView_Day_7_de.png +++ b/screenshots/de/features.userprofile.shared_UserProfileView_Day_7_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:042b2541dbc95ef5eb6db6d42da826493e458326ba5a576975263e3774b2c4bd -size 30805 +oid sha256:f0bbb74d86ed26f103141dd43838f6840d514902371d6d379bd1401357a8d155 +size 35357 diff --git a/screenshots/de/features.verifysession.impl.incoming.ui_SessionDetailsView_Day_0_de.png b/screenshots/de/features.verifysession.impl.incoming.ui_SessionDetailsView_Day_0_de.png new file mode 100644 index 00000000000..030bf361b0a --- /dev/null +++ b/screenshots/de/features.verifysession.impl.incoming.ui_SessionDetailsView_Day_0_de.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c36389a6ce4e57de1dc537cf005d1c0479d65b992c51a73fece0af6f437b3c23 +size 14593 diff --git a/screenshots/de/features.verifysession.impl.incoming_IncomingVerificationView_Day_0_de.png b/screenshots/de/features.verifysession.impl.incoming_IncomingVerificationView_Day_0_de.png new file mode 100644 index 00000000000..c7477e89ab7 --- /dev/null +++ b/screenshots/de/features.verifysession.impl.incoming_IncomingVerificationView_Day_0_de.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:69d0b4dd3db9575aa4663f78763c215594858afbabc549657d14050212ee8d27 +size 50042 diff --git a/screenshots/de/features.verifysession.impl.incoming_IncomingVerificationView_Day_1_de.png b/screenshots/de/features.verifysession.impl.incoming_IncomingVerificationView_Day_1_de.png index 11bcf52ef7e..1d8bd2b8030 100644 --- a/screenshots/de/features.verifysession.impl.incoming_IncomingVerificationView_Day_1_de.png +++ b/screenshots/de/features.verifysession.impl.incoming_IncomingVerificationView_Day_1_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:b210b2c570b1128c5b4992997fb3a64122572357796d19c005003e0e814e71d3 -size 41725 +oid sha256:781c009e36cc392fc1fe22e27b6354993e7a9b9bc47e3e0db8b6186e5e0ab6c8 +size 51102 diff --git a/screenshots/de/features.verifysession.impl.incoming_IncomingVerificationView_Day_5_de.png b/screenshots/de/features.verifysession.impl.incoming_IncomingVerificationView_Day_5_de.png index 3e68cea981b..1c1b31a57e6 100644 --- a/screenshots/de/features.verifysession.impl.incoming_IncomingVerificationView_Day_5_de.png +++ b/screenshots/de/features.verifysession.impl.incoming_IncomingVerificationView_Day_5_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:038ff5080cdae88761104d16cd4e8183c0a48baec559bffe85d0b0a86735a884 -size 22229 +oid sha256:e528f5dc047db23984a78359b4997a83c8bdfed49403906fe4322bf2736ac202 +size 23866 diff --git a/screenshots/de/features.verifysession.impl.incoming_IncomingVerificationView_Day_6_de.png b/screenshots/de/features.verifysession.impl.incoming_IncomingVerificationView_Day_6_de.png index 1bf33aa8754..d7e91ecc8c7 100644 --- a/screenshots/de/features.verifysession.impl.incoming_IncomingVerificationView_Day_6_de.png +++ b/screenshots/de/features.verifysession.impl.incoming_IncomingVerificationView_Day_6_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:3079fb1d9f25f6ca86a7c41e7df95a7c1593019e3f27594e004e9be874e67669 -size 24474 +oid sha256:c02bd36e06f22e03032829e6bc3a291bf8706fda27e5cbd56138c3cd036e14ea +size 34833 diff --git a/screenshots/de/features.verifysession.impl.incoming_IncomingVerificationView_Day_7_de.png b/screenshots/de/features.verifysession.impl.incoming_IncomingVerificationView_Day_7_de.png index 1bf33aa8754..d7e91ecc8c7 100644 --- a/screenshots/de/features.verifysession.impl.incoming_IncomingVerificationView_Day_7_de.png +++ b/screenshots/de/features.verifysession.impl.incoming_IncomingVerificationView_Day_7_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:3079fb1d9f25f6ca86a7c41e7df95a7c1593019e3f27594e004e9be874e67669 -size 24474 +oid sha256:c02bd36e06f22e03032829e6bc3a291bf8706fda27e5cbd56138c3cd036e14ea +size 34833 diff --git a/screenshots/de/features.verifysession.impl.outgoing_VerifySelfSessionView_Day_0_de.png b/screenshots/de/features.verifysession.impl.outgoing_VerifySelfSessionView_Day_0_de.png index cead576dbea..35af29059ec 100644 --- a/screenshots/de/features.verifysession.impl.outgoing_VerifySelfSessionView_Day_0_de.png +++ b/screenshots/de/features.verifysession.impl.outgoing_VerifySelfSessionView_Day_0_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:b90e375bca17e97adc72bdfa95c2d6b98cbe056973ea97751cff3718897d4c51 -size 42541 +oid sha256:23de0727192bb64e3ba28a2cd77685b764279e15eb76d35b166c7d7b2d623b68 +size 45057 diff --git a/screenshots/de/features.verifysession.impl.outgoing_VerifySelfSessionView_Day_10_de.png b/screenshots/de/features.verifysession.impl.outgoing_VerifySelfSessionView_Day_10_de.png index c209bc84bc7..d20c22a8792 100644 --- a/screenshots/de/features.verifysession.impl.outgoing_VerifySelfSessionView_Day_10_de.png +++ b/screenshots/de/features.verifysession.impl.outgoing_VerifySelfSessionView_Day_10_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:34496ff29326e8414625f75dff0f9cfe59cb7d926d32d98abc2c3033342858a9 -size 39538 +oid sha256:cf14c725efbcab351df2fd6b81478c44b0d1f708e8d4c272c54f5d8886ceb0ac +size 41630 diff --git a/screenshots/de/features.verifysession.impl.outgoing_VerifySelfSessionView_Day_13_de.png b/screenshots/de/features.verifysession.impl.outgoing_VerifySelfSessionView_Day_13_de.png index c0db6b7b62e..f4b83605430 100644 --- a/screenshots/de/features.verifysession.impl.outgoing_VerifySelfSessionView_Day_13_de.png +++ b/screenshots/de/features.verifysession.impl.outgoing_VerifySelfSessionView_Day_13_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:2d570026d4981c7cd450ee79d6035eb6f421b3a8ad811f89fb204299d6eb393f -size 31462 +oid sha256:609cdca094e16bdfca58df4b2d5493bc55755afd3ffbb0dbd5687677f6526e8f +size 40087 diff --git a/screenshots/de/features.verifysession.impl.outgoing_VerifySelfSessionView_Day_1_de.png b/screenshots/de/features.verifysession.impl.outgoing_VerifySelfSessionView_Day_1_de.png index 1ddaf40a984..432c5d369e8 100644 --- a/screenshots/de/features.verifysession.impl.outgoing_VerifySelfSessionView_Day_1_de.png +++ b/screenshots/de/features.verifysession.impl.outgoing_VerifySelfSessionView_Day_1_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:fa0fe810e2cbffb69fd9cb46c3e3040869064458f5a9291bf5164fb0cb4ddcd0 -size 30215 +oid sha256:80d2cf2d1558993992d8304d0dc83a04dbed8e6a72653ecbf309819095c13a40 +size 35820 diff --git a/screenshots/de/features.verifysession.impl.outgoing_VerifySelfSessionView_Day_4_de.png b/screenshots/de/features.verifysession.impl.outgoing_VerifySelfSessionView_Day_4_de.png index 5ba09ada53e..edb0cf10f38 100644 --- a/screenshots/de/features.verifysession.impl.outgoing_VerifySelfSessionView_Day_4_de.png +++ b/screenshots/de/features.verifysession.impl.outgoing_VerifySelfSessionView_Day_4_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:9b55f2cb6999543cdd3cdc4f2bba2cb8cb238b94acbd05f889f25da8b43a8580 -size 24580 +oid sha256:8c49b74e9b38e3534d1c1bf9c8652f61f09ec3a1c3995886992c0825e4d6b683 +size 34784 diff --git a/screenshots/de/features.verifysession.impl.outgoing_VerifySelfSessionView_Day_7_de.png b/screenshots/de/features.verifysession.impl.outgoing_VerifySelfSessionView_Day_7_de.png index cead576dbea..35af29059ec 100644 --- a/screenshots/de/features.verifysession.impl.outgoing_VerifySelfSessionView_Day_7_de.png +++ b/screenshots/de/features.verifysession.impl.outgoing_VerifySelfSessionView_Day_7_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:b90e375bca17e97adc72bdfa95c2d6b98cbe056973ea97751cff3718897d4c51 -size 42541 +oid sha256:23de0727192bb64e3ba28a2cd77685b764279e15eb76d35b166c7d7b2d623b68 +size 45057 diff --git a/screenshots/de/features.verifysession.impl.outgoing_VerifySelfSessionView_Day_8_de.png b/screenshots/de/features.verifysession.impl.outgoing_VerifySelfSessionView_Day_8_de.png index f760980179b..9821002f34e 100644 --- a/screenshots/de/features.verifysession.impl.outgoing_VerifySelfSessionView_Day_8_de.png +++ b/screenshots/de/features.verifysession.impl.outgoing_VerifySelfSessionView_Day_8_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:54654071726bec5f34f8ec90c4a9a8f88381feaf3861354488ecb833f032fce9 -size 36414 +oid sha256:b9b3d509178d5cebf46d5c03705d6f6f31cace4b9ff8a6951c594a4b64de5943 +size 38994 diff --git a/screenshots/de/libraries.textcomposer_TextComposerAddCaption_Day_0_de.png b/screenshots/de/libraries.textcomposer_TextComposerAddCaption_Day_0_de.png index 00240213814..eb9d617febb 100644 --- a/screenshots/de/libraries.textcomposer_TextComposerAddCaption_Day_0_de.png +++ b/screenshots/de/libraries.textcomposer_TextComposerAddCaption_Day_0_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:91b0c3b998281662308866cf48d832a9e5bed739c4df52faaf9955d4b9377222 -size 59662 +oid sha256:72d90402ff38639d384be74db19bc8ee5e8dfc15def5e24839c404809e74829c +size 65689 diff --git a/screenshots/de/libraries.textcomposer_TextComposerCaption_Day_0_de.png b/screenshots/de/libraries.textcomposer_TextComposerCaption_Day_0_de.png new file mode 100644 index 00000000000..16aabac42df --- /dev/null +++ b/screenshots/de/libraries.textcomposer_TextComposerCaption_Day_0_de.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:70681c983dd8027ef21a7cf7f1ce21b2aa49608026a2f265d4ea2b452f394cc0 +size 57592 diff --git a/screenshots/de/libraries.textcomposer_TextComposerEditCaption_Day_0_de.png b/screenshots/de/libraries.textcomposer_TextComposerEditCaption_Day_0_de.png index dee50d7f3d0..aaf06e57ab9 100644 --- a/screenshots/de/libraries.textcomposer_TextComposerEditCaption_Day_0_de.png +++ b/screenshots/de/libraries.textcomposer_TextComposerEditCaption_Day_0_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:29ea8960948fd36a82248eca077b3d54804a2c1603989b30c39def7019699666 -size 59055 +oid sha256:ed323016c3aa4c61d248f7f515c4008bea91b5ab07513f1ad85c448b28a8e071 +size 66415 diff --git a/screenshots/html/data.js b/screenshots/html/data.js index 46c6676dbcc..ca26a3463f9 100644 --- a/screenshots/html/data.js +++ b/screenshots/html/data.js @@ -1,59 +1,59 @@ // 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",20049,], +["features.preferences.impl.about_AboutView_Day_0_en","features.preferences.impl.about_AboutView_Night_0_en",20056,], ["features.invite.impl.response_AcceptDeclineInviteView_Day_0_en","features.invite.impl.response_AcceptDeclineInviteView_Night_0_en",0,], -["features.invite.impl.response_AcceptDeclineInviteView_Day_1_en","features.invite.impl.response_AcceptDeclineInviteView_Night_1_en",20049,], -["features.invite.impl.response_AcceptDeclineInviteView_Day_2_en","features.invite.impl.response_AcceptDeclineInviteView_Night_2_en",20049,], -["features.invite.impl.response_AcceptDeclineInviteView_Day_3_en","features.invite.impl.response_AcceptDeclineInviteView_Night_3_en",20049,], -["features.invite.impl.response_AcceptDeclineInviteView_Day_4_en","features.invite.impl.response_AcceptDeclineInviteView_Night_4_en",20049,], -["features.logout.impl_AccountDeactivationView_Day_0_en","features.logout.impl_AccountDeactivationView_Night_0_en",20049,], -["features.logout.impl_AccountDeactivationView_Day_1_en","features.logout.impl_AccountDeactivationView_Night_1_en",0,], -["features.logout.impl_AccountDeactivationView_Day_2_en","features.logout.impl_AccountDeactivationView_Night_2_en",20049,], -["features.logout.impl_AccountDeactivationView_Day_3_en","features.logout.impl_AccountDeactivationView_Night_3_en",20049,], -["features.logout.impl_AccountDeactivationView_Day_4_en","features.logout.impl_AccountDeactivationView_Night_4_en",20049,], +["features.invite.impl.response_AcceptDeclineInviteView_Day_1_en","features.invite.impl.response_AcceptDeclineInviteView_Night_1_en",20056,], +["features.invite.impl.response_AcceptDeclineInviteView_Day_2_en","features.invite.impl.response_AcceptDeclineInviteView_Night_2_en",20056,], +["features.invite.impl.response_AcceptDeclineInviteView_Day_3_en","features.invite.impl.response_AcceptDeclineInviteView_Night_3_en",20056,], +["features.invite.impl.response_AcceptDeclineInviteView_Day_4_en","features.invite.impl.response_AcceptDeclineInviteView_Night_4_en",20056,], +["features.logout.impl_AccountDeactivationView_Day_0_en","features.logout.impl_AccountDeactivationView_Night_0_en",20056,], +["features.logout.impl_AccountDeactivationView_Day_1_en","features.logout.impl_AccountDeactivationView_Night_1_en",20059,], +["features.logout.impl_AccountDeactivationView_Day_2_en","features.logout.impl_AccountDeactivationView_Night_2_en",20056,], +["features.logout.impl_AccountDeactivationView_Day_3_en","features.logout.impl_AccountDeactivationView_Night_3_en",20056,], +["features.logout.impl_AccountDeactivationView_Day_4_en","features.logout.impl_AccountDeactivationView_Night_4_en",20056,], ["features.login.impl.accountprovider_AccountProviderView_Day_0_en","features.login.impl.accountprovider_AccountProviderView_Night_0_en",0,], ["features.login.impl.accountprovider_AccountProviderView_Day_1_en","features.login.impl.accountprovider_AccountProviderView_Night_1_en",0,], ["features.login.impl.accountprovider_AccountProviderView_Day_2_en","features.login.impl.accountprovider_AccountProviderView_Night_2_en",0,], ["features.login.impl.accountprovider_AccountProviderView_Day_3_en","features.login.impl.accountprovider_AccountProviderView_Night_3_en",0,], ["features.messages.impl.actionlist_ActionListViewContent_Day_0_en","features.messages.impl.actionlist_ActionListViewContent_Night_0_en",0,], -["features.messages.impl.actionlist_ActionListViewContent_Day_10_en","features.messages.impl.actionlist_ActionListViewContent_Night_10_en",20049,], -["features.messages.impl.actionlist_ActionListViewContent_Day_11_en","features.messages.impl.actionlist_ActionListViewContent_Night_11_en",20049,], -["features.messages.impl.actionlist_ActionListViewContent_Day_12_en","features.messages.impl.actionlist_ActionListViewContent_Night_12_en",20049,], +["features.messages.impl.actionlist_ActionListViewContent_Day_10_en","features.messages.impl.actionlist_ActionListViewContent_Night_10_en",20056,], +["features.messages.impl.actionlist_ActionListViewContent_Day_11_en","features.messages.impl.actionlist_ActionListViewContent_Night_11_en",20056,], +["features.messages.impl.actionlist_ActionListViewContent_Day_12_en","features.messages.impl.actionlist_ActionListViewContent_Night_12_en",20056,], ["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",20049,], -["features.messages.impl.actionlist_ActionListViewContent_Day_3_en","features.messages.impl.actionlist_ActionListViewContent_Night_3_en",20049,], -["features.messages.impl.actionlist_ActionListViewContent_Day_4_en","features.messages.impl.actionlist_ActionListViewContent_Night_4_en",20049,], -["features.messages.impl.actionlist_ActionListViewContent_Day_5_en","features.messages.impl.actionlist_ActionListViewContent_Night_5_en",20049,], -["features.messages.impl.actionlist_ActionListViewContent_Day_6_en","features.messages.impl.actionlist_ActionListViewContent_Night_6_en",20049,], -["features.messages.impl.actionlist_ActionListViewContent_Day_7_en","features.messages.impl.actionlist_ActionListViewContent_Night_7_en",20049,], -["features.messages.impl.actionlist_ActionListViewContent_Day_8_en","features.messages.impl.actionlist_ActionListViewContent_Night_8_en",20049,], -["features.messages.impl.actionlist_ActionListViewContent_Day_9_en","features.messages.impl.actionlist_ActionListViewContent_Night_9_en",20049,], -["features.createroom.impl.addpeople_AddPeopleView_Day_0_en","features.createroom.impl.addpeople_AddPeopleView_Night_0_en",20049,], -["features.createroom.impl.addpeople_AddPeopleView_Day_1_en","features.createroom.impl.addpeople_AddPeopleView_Night_1_en",20049,], -["features.createroom.impl.addpeople_AddPeopleView_Day_2_en","features.createroom.impl.addpeople_AddPeopleView_Night_2_en",20049,], -["features.createroom.impl.addpeople_AddPeopleView_Day_3_en","features.createroom.impl.addpeople_AddPeopleView_Night_3_en",20049,], -["features.preferences.impl.advanced_AdvancedSettingsView_Day_0_en","features.preferences.impl.advanced_AdvancedSettingsView_Night_0_en",20049,], -["features.preferences.impl.advanced_AdvancedSettingsView_Day_1_en","features.preferences.impl.advanced_AdvancedSettingsView_Night_1_en",20049,], -["features.preferences.impl.advanced_AdvancedSettingsView_Day_2_en","features.preferences.impl.advanced_AdvancedSettingsView_Night_2_en",20049,], -["features.preferences.impl.advanced_AdvancedSettingsView_Day_3_en","features.preferences.impl.advanced_AdvancedSettingsView_Night_3_en",20049,], -["features.preferences.impl.advanced_AdvancedSettingsView_Day_4_en","features.preferences.impl.advanced_AdvancedSettingsView_Night_4_en",20049,], -["libraries.designsystem.components.dialogs_AlertDialogContent_Dialogs_en","",20049,], -["libraries.designsystem.components.dialogs_AlertDialog_Day_0_en","libraries.designsystem.components.dialogs_AlertDialog_Night_0_en",20049,], -["features.analytics.impl_AnalyticsOptInView_Day_0_en","features.analytics.impl_AnalyticsOptInView_Night_0_en",20049,], -["features.analytics.api.preferences_AnalyticsPreferencesView_Day_0_en","features.analytics.api.preferences_AnalyticsPreferencesView_Night_0_en",20049,], -["features.preferences.impl.analytics_AnalyticsSettingsView_Day_0_en","features.preferences.impl.analytics_AnalyticsSettingsView_Night_0_en",20049,], -["services.apperror.impl_AppErrorView_Day_0_en","services.apperror.impl_AppErrorView_Night_0_en",20049,], +["features.messages.impl.actionlist_ActionListViewContent_Day_2_en","features.messages.impl.actionlist_ActionListViewContent_Night_2_en",20056,], +["features.messages.impl.actionlist_ActionListViewContent_Day_3_en","features.messages.impl.actionlist_ActionListViewContent_Night_3_en",20056,], +["features.messages.impl.actionlist_ActionListViewContent_Day_4_en","features.messages.impl.actionlist_ActionListViewContent_Night_4_en",20056,], +["features.messages.impl.actionlist_ActionListViewContent_Day_5_en","features.messages.impl.actionlist_ActionListViewContent_Night_5_en",20056,], +["features.messages.impl.actionlist_ActionListViewContent_Day_6_en","features.messages.impl.actionlist_ActionListViewContent_Night_6_en",20056,], +["features.messages.impl.actionlist_ActionListViewContent_Day_7_en","features.messages.impl.actionlist_ActionListViewContent_Night_7_en",20056,], +["features.messages.impl.actionlist_ActionListViewContent_Day_8_en","features.messages.impl.actionlist_ActionListViewContent_Night_8_en",20056,], +["features.messages.impl.actionlist_ActionListViewContent_Day_9_en","features.messages.impl.actionlist_ActionListViewContent_Night_9_en",20056,], +["features.createroom.impl.addpeople_AddPeopleView_Day_0_en","features.createroom.impl.addpeople_AddPeopleView_Night_0_en",20056,], +["features.createroom.impl.addpeople_AddPeopleView_Day_1_en","features.createroom.impl.addpeople_AddPeopleView_Night_1_en",20056,], +["features.createroom.impl.addpeople_AddPeopleView_Day_2_en","features.createroom.impl.addpeople_AddPeopleView_Night_2_en",20056,], +["features.createroom.impl.addpeople_AddPeopleView_Day_3_en","features.createroom.impl.addpeople_AddPeopleView_Night_3_en",20056,], +["features.preferences.impl.advanced_AdvancedSettingsView_Day_0_en","features.preferences.impl.advanced_AdvancedSettingsView_Night_0_en",20056,], +["features.preferences.impl.advanced_AdvancedSettingsView_Day_1_en","features.preferences.impl.advanced_AdvancedSettingsView_Night_1_en",20056,], +["features.preferences.impl.advanced_AdvancedSettingsView_Day_2_en","features.preferences.impl.advanced_AdvancedSettingsView_Night_2_en",20056,], +["features.preferences.impl.advanced_AdvancedSettingsView_Day_3_en","features.preferences.impl.advanced_AdvancedSettingsView_Night_3_en",20056,], +["features.preferences.impl.advanced_AdvancedSettingsView_Day_4_en","features.preferences.impl.advanced_AdvancedSettingsView_Night_4_en",20056,], +["libraries.designsystem.components.dialogs_AlertDialogContent_Dialogs_en","",20056,], +["libraries.designsystem.components.dialogs_AlertDialog_Day_0_en","libraries.designsystem.components.dialogs_AlertDialog_Night_0_en",20056,], +["features.analytics.impl_AnalyticsOptInView_Day_0_en","features.analytics.impl_AnalyticsOptInView_Night_0_en",20056,], +["features.analytics.api.preferences_AnalyticsPreferencesView_Day_0_en","features.analytics.api.preferences_AnalyticsPreferencesView_Night_0_en",20056,], +["features.preferences.impl.analytics_AnalyticsSettingsView_Day_0_en","features.preferences.impl.analytics_AnalyticsSettingsView_Night_0_en",20056,], +["services.apperror.impl_AppErrorView_Day_0_en","services.apperror.impl_AppErrorView_Night_0_en",20056,], ["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",20049,], +["libraries.designsystem.components.async_AsyncActionView_Day_1_en","libraries.designsystem.components.async_AsyncActionView_Night_1_en",20056,], ["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",20049,], +["libraries.designsystem.components.async_AsyncActionView_Day_3_en","libraries.designsystem.components.async_AsyncActionView_Night_3_en",20056,], ["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",20049,], +["libraries.designsystem.components.async_AsyncFailure_Day_0_en","libraries.designsystem.components.async_AsyncFailure_Night_0_en",20056,], ["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",20049,], +["features.messages.impl.messagecomposer_AttachmentSourcePickerMenu_Day_0_en","features.messages.impl.messagecomposer_AttachmentSourcePickerMenu_Night_0_en",20056,], ["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,], @@ -63,13 +63,15 @@ export const screenshots = [ ["libraries.matrix.ui.components_AttachmentThumbnail_Day_6_en","libraries.matrix.ui.components_AttachmentThumbnail_Night_6_en",0,], ["libraries.matrix.ui.components_AttachmentThumbnail_Day_7_en","libraries.matrix.ui.components_AttachmentThumbnail_Night_7_en",0,], ["libraries.matrix.ui.components_AttachmentThumbnail_Day_8_en","libraries.matrix.ui.components_AttachmentThumbnail_Night_8_en",0,], -["features.messages.impl.attachments.preview_AttachmentsView_0_en","",0,], -["features.messages.impl.attachments.preview_AttachmentsView_1_en","",0,], -["features.messages.impl.attachments.preview_AttachmentsView_2_en","",0,], -["features.messages.impl.attachments.preview_AttachmentsView_3_en","",0,], -["features.messages.impl.attachments.preview_AttachmentsView_4_en","",20049,], -["features.messages.impl.attachments.preview_AttachmentsView_5_en","",20049,], -["libraries.matrix.ui.components_AvatarActionBottomSheet_Day_0_en","libraries.matrix.ui.components_AvatarActionBottomSheet_Night_0_en",20049,], +["features.messages.impl.attachments.preview_AttachmentsView_0_en","",20059,], +["features.messages.impl.attachments.preview_AttachmentsView_1_en","",20059,], +["features.messages.impl.attachments.preview_AttachmentsView_2_en","",20059,], +["features.messages.impl.attachments.preview_AttachmentsView_3_en","",20059,], +["features.messages.impl.attachments.preview_AttachmentsView_4_en","",20056,], +["features.messages.impl.attachments.preview_AttachmentsView_5_en","",20056,], +["features.messages.impl.attachments.preview_AttachmentsView_6_en","",20059,], +["features.messages.impl.attachments.preview_AttachmentsView_7_en","",0,], +["libraries.matrix.ui.components_AvatarActionBottomSheet_Day_0_en","libraries.matrix.ui.components_AvatarActionBottomSheet_Night_0_en",20056,], ["libraries.designsystem.components.avatar_Avatar_Avatars_0_en","",0,], ["libraries.designsystem.components.avatar_Avatar_Avatars_10_en","",0,], ["libraries.designsystem.components.avatar_Avatar_Avatars_11_en","",0,], @@ -152,13 +154,13 @@ export const screenshots = [ ["libraries.designsystem.components_Badge_Day_0_en","libraries.designsystem.components_Badge_Night_0_en",0,], ["libraries.designsystem.components_BigCheckmark_Day_0_en","libraries.designsystem.components_BigCheckmark_Night_0_en",0,], ["libraries.designsystem.components_BigIcon_Day_0_en","libraries.designsystem.components_BigIcon_Night_0_en",0,], -["features.preferences.impl.blockedusers_BlockedUsersView_Day_0_en","features.preferences.impl.blockedusers_BlockedUsersView_Night_0_en",20049,], -["features.preferences.impl.blockedusers_BlockedUsersView_Day_1_en","features.preferences.impl.blockedusers_BlockedUsersView_Night_1_en",20049,], -["features.preferences.impl.blockedusers_BlockedUsersView_Day_2_en","features.preferences.impl.blockedusers_BlockedUsersView_Night_2_en",20049,], -["features.preferences.impl.blockedusers_BlockedUsersView_Day_3_en","features.preferences.impl.blockedusers_BlockedUsersView_Night_3_en",20049,], -["features.preferences.impl.blockedusers_BlockedUsersView_Day_4_en","features.preferences.impl.blockedusers_BlockedUsersView_Night_4_en",20049,], -["features.preferences.impl.blockedusers_BlockedUsersView_Day_5_en","features.preferences.impl.blockedusers_BlockedUsersView_Night_5_en",20049,], -["features.preferences.impl.blockedusers_BlockedUsersView_Day_6_en","features.preferences.impl.blockedusers_BlockedUsersView_Night_6_en",20049,], +["features.preferences.impl.blockedusers_BlockedUsersView_Day_0_en","features.preferences.impl.blockedusers_BlockedUsersView_Night_0_en",20056,], +["features.preferences.impl.blockedusers_BlockedUsersView_Day_1_en","features.preferences.impl.blockedusers_BlockedUsersView_Night_1_en",20056,], +["features.preferences.impl.blockedusers_BlockedUsersView_Day_2_en","features.preferences.impl.blockedusers_BlockedUsersView_Night_2_en",20056,], +["features.preferences.impl.blockedusers_BlockedUsersView_Day_3_en","features.preferences.impl.blockedusers_BlockedUsersView_Night_3_en",20056,], +["features.preferences.impl.blockedusers_BlockedUsersView_Day_4_en","features.preferences.impl.blockedusers_BlockedUsersView_Night_4_en",20056,], +["features.preferences.impl.blockedusers_BlockedUsersView_Day_5_en","features.preferences.impl.blockedusers_BlockedUsersView_Night_5_en",20056,], +["features.preferences.impl.blockedusers_BlockedUsersView_Day_6_en","features.preferences.impl.blockedusers_BlockedUsersView_Night_6_en",20056,], ["libraries.designsystem.components_BloomInitials_Day_0_en","libraries.designsystem.components_BloomInitials_Night_0_en",0,], ["libraries.designsystem.components_BloomInitials_Day_1_en","libraries.designsystem.components_BloomInitials_Night_1_en",0,], ["libraries.designsystem.components_BloomInitials_Day_2_en","libraries.designsystem.components_BloomInitials_Night_2_en",0,], @@ -169,115 +171,115 @@ export const screenshots = [ ["libraries.designsystem.components_BloomInitials_Day_7_en","libraries.designsystem.components_BloomInitials_Night_7_en",0,], ["libraries.designsystem.components_Bloom_Day_0_en","libraries.designsystem.components_Bloom_Night_0_en",0,], ["libraries.designsystem.theme.components_BottomSheetDragHandle_Day_0_en","libraries.designsystem.theme.components_BottomSheetDragHandle_Night_0_en",0,], -["features.rageshake.impl.bugreport_BugReportView_Day_0_en","features.rageshake.impl.bugreport_BugReportView_Night_0_en",20049,], -["features.rageshake.impl.bugreport_BugReportView_Day_1_en","features.rageshake.impl.bugreport_BugReportView_Night_1_en",20049,], -["features.rageshake.impl.bugreport_BugReportView_Day_2_en","features.rageshake.impl.bugreport_BugReportView_Night_2_en",20049,], -["features.rageshake.impl.bugreport_BugReportView_Day_3_en","features.rageshake.impl.bugreport_BugReportView_Night_3_en",20049,], -["features.rageshake.impl.bugreport_BugReportView_Day_4_en","features.rageshake.impl.bugreport_BugReportView_Night_4_en",20049,], +["features.rageshake.impl.bugreport_BugReportView_Day_0_en","features.rageshake.impl.bugreport_BugReportView_Night_0_en",20056,], +["features.rageshake.impl.bugreport_BugReportView_Day_1_en","features.rageshake.impl.bugreport_BugReportView_Night_1_en",20056,], +["features.rageshake.impl.bugreport_BugReportView_Day_2_en","features.rageshake.impl.bugreport_BugReportView_Night_2_en",20056,], +["features.rageshake.impl.bugreport_BugReportView_Day_3_en","features.rageshake.impl.bugreport_BugReportView_Night_3_en",20056,], +["features.rageshake.impl.bugreport_BugReportView_Day_4_en","features.rageshake.impl.bugreport_BugReportView_Night_4_en",20056,], ["libraries.designsystem.atomic.molecules_ButtonColumnMolecule_Day_0_en","libraries.designsystem.atomic.molecules_ButtonColumnMolecule_Night_0_en",0,], ["libraries.designsystem.atomic.molecules_ButtonRowMolecule_Day_0_en","libraries.designsystem.atomic.molecules_ButtonRowMolecule_Night_0_en",0,], ["features.messages.impl.timeline.components_CallMenuItem_Day_0_en","features.messages.impl.timeline.components_CallMenuItem_Night_0_en",0,], ["features.messages.impl.timeline.components_CallMenuItem_Day_1_en","features.messages.impl.timeline.components_CallMenuItem_Night_1_en",0,], -["features.messages.impl.timeline.components_CallMenuItem_Day_2_en","features.messages.impl.timeline.components_CallMenuItem_Night_2_en",20049,], -["features.messages.impl.timeline.components_CallMenuItem_Day_3_en","features.messages.impl.timeline.components_CallMenuItem_Night_3_en",20049,], +["features.messages.impl.timeline.components_CallMenuItem_Day_2_en","features.messages.impl.timeline.components_CallMenuItem_Night_2_en",20056,], +["features.messages.impl.timeline.components_CallMenuItem_Day_3_en","features.messages.impl.timeline.components_CallMenuItem_Night_3_en",20056,], ["features.messages.impl.timeline.components_CallMenuItem_Day_4_en","features.messages.impl.timeline.components_CallMenuItem_Night_4_en",0,], ["features.call.impl.ui_CallScreenPipView_Day_0_en","features.call.impl.ui_CallScreenPipView_Night_0_en",0,], ["features.call.impl.ui_CallScreenPipView_Day_1_en","features.call.impl.ui_CallScreenPipView_Night_1_en",0,], ["features.call.impl.ui_CallScreenView_Day_0_en","features.call.impl.ui_CallScreenView_Night_0_en",0,], -["features.call.impl.ui_CallScreenView_Day_1_en","features.call.impl.ui_CallScreenView_Night_1_en",20049,], -["features.call.impl.ui_CallScreenView_Day_2_en","features.call.impl.ui_CallScreenView_Night_2_en",20049,], -["features.call.impl.ui_CallScreenView_Day_3_en","features.call.impl.ui_CallScreenView_Night_3_en",20049,], -["features.login.impl.screens.changeaccountprovider_ChangeAccountProviderView_Day_0_en","features.login.impl.screens.changeaccountprovider_ChangeAccountProviderView_Night_0_en",20049,], -["features.roomdetails.impl.rolesandpermissions.changeroles_ChangeRolesView_Day_0_en","features.roomdetails.impl.rolesandpermissions.changeroles_ChangeRolesView_Night_0_en",20049,], -["features.roomdetails.impl.rolesandpermissions.changeroles_ChangeRolesView_Day_10_en","features.roomdetails.impl.rolesandpermissions.changeroles_ChangeRolesView_Night_10_en",20049,], -["features.roomdetails.impl.rolesandpermissions.changeroles_ChangeRolesView_Day_1_en","features.roomdetails.impl.rolesandpermissions.changeroles_ChangeRolesView_Night_1_en",20049,], -["features.roomdetails.impl.rolesandpermissions.changeroles_ChangeRolesView_Day_2_en","features.roomdetails.impl.rolesandpermissions.changeroles_ChangeRolesView_Night_2_en",20049,], -["features.roomdetails.impl.rolesandpermissions.changeroles_ChangeRolesView_Day_3_en","features.roomdetails.impl.rolesandpermissions.changeroles_ChangeRolesView_Night_3_en",20049,], -["features.roomdetails.impl.rolesandpermissions.changeroles_ChangeRolesView_Day_4_en","features.roomdetails.impl.rolesandpermissions.changeroles_ChangeRolesView_Night_4_en",20049,], -["features.roomdetails.impl.rolesandpermissions.changeroles_ChangeRolesView_Day_5_en","features.roomdetails.impl.rolesandpermissions.changeroles_ChangeRolesView_Night_5_en",20049,], -["features.roomdetails.impl.rolesandpermissions.changeroles_ChangeRolesView_Day_6_en","features.roomdetails.impl.rolesandpermissions.changeroles_ChangeRolesView_Night_6_en",20049,], -["features.roomdetails.impl.rolesandpermissions.changeroles_ChangeRolesView_Day_7_en","features.roomdetails.impl.rolesandpermissions.changeroles_ChangeRolesView_Night_7_en",20049,], -["features.roomdetails.impl.rolesandpermissions.changeroles_ChangeRolesView_Day_8_en","features.roomdetails.impl.rolesandpermissions.changeroles_ChangeRolesView_Night_8_en",20049,], -["features.roomdetails.impl.rolesandpermissions.changeroles_ChangeRolesView_Day_9_en","features.roomdetails.impl.rolesandpermissions.changeroles_ChangeRolesView_Night_9_en",20049,], -["features.roomdetails.impl.rolesandpermissions.permissions_ChangeRoomPermissionsView_Day_0_en","features.roomdetails.impl.rolesandpermissions.permissions_ChangeRoomPermissionsView_Night_0_en",20049,], -["features.roomdetails.impl.rolesandpermissions.permissions_ChangeRoomPermissionsView_Day_1_en","features.roomdetails.impl.rolesandpermissions.permissions_ChangeRoomPermissionsView_Night_1_en",20049,], -["features.roomdetails.impl.rolesandpermissions.permissions_ChangeRoomPermissionsView_Day_2_en","features.roomdetails.impl.rolesandpermissions.permissions_ChangeRoomPermissionsView_Night_2_en",20049,], -["features.roomdetails.impl.rolesandpermissions.permissions_ChangeRoomPermissionsView_Day_3_en","features.roomdetails.impl.rolesandpermissions.permissions_ChangeRoomPermissionsView_Night_3_en",20049,], -["features.roomdetails.impl.rolesandpermissions.permissions_ChangeRoomPermissionsView_Day_4_en","features.roomdetails.impl.rolesandpermissions.permissions_ChangeRoomPermissionsView_Night_4_en",20049,], -["features.roomdetails.impl.rolesandpermissions.permissions_ChangeRoomPermissionsView_Day_5_en","features.roomdetails.impl.rolesandpermissions.permissions_ChangeRoomPermissionsView_Night_5_en",20049,], -["features.roomdetails.impl.rolesandpermissions.permissions_ChangeRoomPermissionsView_Day_6_en","features.roomdetails.impl.rolesandpermissions.permissions_ChangeRoomPermissionsView_Night_6_en",20049,], +["features.call.impl.ui_CallScreenView_Day_1_en","features.call.impl.ui_CallScreenView_Night_1_en",20056,], +["features.call.impl.ui_CallScreenView_Day_2_en","features.call.impl.ui_CallScreenView_Night_2_en",20056,], +["features.call.impl.ui_CallScreenView_Day_3_en","features.call.impl.ui_CallScreenView_Night_3_en",20056,], +["features.login.impl.screens.changeaccountprovider_ChangeAccountProviderView_Day_0_en","features.login.impl.screens.changeaccountprovider_ChangeAccountProviderView_Night_0_en",20056,], +["features.roomdetails.impl.rolesandpermissions.changeroles_ChangeRolesView_Day_0_en","features.roomdetails.impl.rolesandpermissions.changeroles_ChangeRolesView_Night_0_en",20056,], +["features.roomdetails.impl.rolesandpermissions.changeroles_ChangeRolesView_Day_10_en","features.roomdetails.impl.rolesandpermissions.changeroles_ChangeRolesView_Night_10_en",20056,], +["features.roomdetails.impl.rolesandpermissions.changeroles_ChangeRolesView_Day_1_en","features.roomdetails.impl.rolesandpermissions.changeroles_ChangeRolesView_Night_1_en",20056,], +["features.roomdetails.impl.rolesandpermissions.changeroles_ChangeRolesView_Day_2_en","features.roomdetails.impl.rolesandpermissions.changeroles_ChangeRolesView_Night_2_en",20056,], +["features.roomdetails.impl.rolesandpermissions.changeroles_ChangeRolesView_Day_3_en","features.roomdetails.impl.rolesandpermissions.changeroles_ChangeRolesView_Night_3_en",20056,], +["features.roomdetails.impl.rolesandpermissions.changeroles_ChangeRolesView_Day_4_en","features.roomdetails.impl.rolesandpermissions.changeroles_ChangeRolesView_Night_4_en",20056,], +["features.roomdetails.impl.rolesandpermissions.changeroles_ChangeRolesView_Day_5_en","features.roomdetails.impl.rolesandpermissions.changeroles_ChangeRolesView_Night_5_en",20056,], +["features.roomdetails.impl.rolesandpermissions.changeroles_ChangeRolesView_Day_6_en","features.roomdetails.impl.rolesandpermissions.changeroles_ChangeRolesView_Night_6_en",20056,], +["features.roomdetails.impl.rolesandpermissions.changeroles_ChangeRolesView_Day_7_en","features.roomdetails.impl.rolesandpermissions.changeroles_ChangeRolesView_Night_7_en",20056,], +["features.roomdetails.impl.rolesandpermissions.changeroles_ChangeRolesView_Day_8_en","features.roomdetails.impl.rolesandpermissions.changeroles_ChangeRolesView_Night_8_en",20056,], +["features.roomdetails.impl.rolesandpermissions.changeroles_ChangeRolesView_Day_9_en","features.roomdetails.impl.rolesandpermissions.changeroles_ChangeRolesView_Night_9_en",20056,], +["features.roomdetails.impl.rolesandpermissions.permissions_ChangeRoomPermissionsView_Day_0_en","features.roomdetails.impl.rolesandpermissions.permissions_ChangeRoomPermissionsView_Night_0_en",20056,], +["features.roomdetails.impl.rolesandpermissions.permissions_ChangeRoomPermissionsView_Day_1_en","features.roomdetails.impl.rolesandpermissions.permissions_ChangeRoomPermissionsView_Night_1_en",20056,], +["features.roomdetails.impl.rolesandpermissions.permissions_ChangeRoomPermissionsView_Day_2_en","features.roomdetails.impl.rolesandpermissions.permissions_ChangeRoomPermissionsView_Night_2_en",20056,], +["features.roomdetails.impl.rolesandpermissions.permissions_ChangeRoomPermissionsView_Day_3_en","features.roomdetails.impl.rolesandpermissions.permissions_ChangeRoomPermissionsView_Night_3_en",20056,], +["features.roomdetails.impl.rolesandpermissions.permissions_ChangeRoomPermissionsView_Day_4_en","features.roomdetails.impl.rolesandpermissions.permissions_ChangeRoomPermissionsView_Night_4_en",20056,], +["features.roomdetails.impl.rolesandpermissions.permissions_ChangeRoomPermissionsView_Day_5_en","features.roomdetails.impl.rolesandpermissions.permissions_ChangeRoomPermissionsView_Night_5_en",20056,], +["features.roomdetails.impl.rolesandpermissions.permissions_ChangeRoomPermissionsView_Day_6_en","features.roomdetails.impl.rolesandpermissions.permissions_ChangeRoomPermissionsView_Night_6_en",20056,], ["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",20049,], -["features.login.impl.changeserver_ChangeServerView_Day_2_en","features.login.impl.changeserver_ChangeServerView_Night_2_en",20049,], +["features.login.impl.changeserver_ChangeServerView_Day_1_en","features.login.impl.changeserver_ChangeServerView_Night_1_en",20056,], +["features.login.impl.changeserver_ChangeServerView_Day_2_en","features.login.impl.changeserver_ChangeServerView_Night_2_en",20056,], ["libraries.matrix.ui.components_CheckableResolvedUserRow_en","",0,], -["libraries.matrix.ui.components_CheckableUnresolvedUserRow_en","",20049,], +["libraries.matrix.ui.components_CheckableUnresolvedUserRow_en","",20056,], ["libraries.designsystem.theme.components_Checkboxes_Toggles_en","",0,], ["libraries.designsystem.theme.components_CircularProgressIndicator_Progress_Indicators_en","",0,], ["libraries.designsystem.components_ClickableLinkText_Text_en","",0,], ["libraries.designsystem.theme_ColorAliases_Day_0_en","libraries.designsystem.theme_ColorAliases_Night_0_en",0,], -["libraries.designsystem.atomic.molecules_ComposerAlertMolecule_Day_0_en","libraries.designsystem.atomic.molecules_ComposerAlertMolecule_Night_0_en",20049,], -["libraries.designsystem.atomic.molecules_ComposerAlertMolecule_Day_1_en","libraries.designsystem.atomic.molecules_ComposerAlertMolecule_Night_1_en",20049,], -["libraries.textcomposer_ComposerModeView_Day_0_en","libraries.textcomposer_ComposerModeView_Night_0_en",20049,], +["libraries.designsystem.atomic.molecules_ComposerAlertMolecule_Day_0_en","libraries.designsystem.atomic.molecules_ComposerAlertMolecule_Night_0_en",20056,], +["libraries.designsystem.atomic.molecules_ComposerAlertMolecule_Day_1_en","libraries.designsystem.atomic.molecules_ComposerAlertMolecule_Night_1_en",20056,], +["libraries.textcomposer_ComposerModeView_Day_0_en","libraries.textcomposer_ComposerModeView_Night_0_en",20056,], ["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,], ["libraries.textcomposer.components_ComposerOptionsButton_Day_0_en","libraries.textcomposer.components_ComposerOptionsButton_Night_0_en",0,], ["libraries.designsystem.components.avatar_CompositeAvatar_Avatars_en","",0,], -["features.createroom.impl.configureroom_ConfigureRoomViewDark_0_en","",20049,], -["features.createroom.impl.configureroom_ConfigureRoomViewDark_1_en","",20049,], -["features.createroom.impl.configureroom_ConfigureRoomViewDark_2_en","",20049,], -["features.createroom.impl.configureroom_ConfigureRoomViewDark_3_en","",20049,], -["features.createroom.impl.configureroom_ConfigureRoomViewDark_4_en","",20049,], -["features.createroom.impl.configureroom_ConfigureRoomViewDark_5_en","",20049,], -["features.createroom.impl.configureroom_ConfigureRoomViewLight_0_en","",20049,], -["features.createroom.impl.configureroom_ConfigureRoomViewLight_1_en","",20049,], -["features.createroom.impl.configureroom_ConfigureRoomViewLight_2_en","",20049,], -["features.createroom.impl.configureroom_ConfigureRoomViewLight_3_en","",20049,], -["features.createroom.impl.configureroom_ConfigureRoomViewLight_4_en","",20049,], -["features.createroom.impl.configureroom_ConfigureRoomViewLight_5_en","",20049,], +["features.createroom.impl.configureroom_ConfigureRoomViewDark_0_en","",20056,], +["features.createroom.impl.configureroom_ConfigureRoomViewDark_1_en","",20056,], +["features.createroom.impl.configureroom_ConfigureRoomViewDark_2_en","",20056,], +["features.createroom.impl.configureroom_ConfigureRoomViewDark_3_en","",20056,], +["features.createroom.impl.configureroom_ConfigureRoomViewDark_4_en","",20056,], +["features.createroom.impl.configureroom_ConfigureRoomViewDark_5_en","",20056,], +["features.createroom.impl.configureroom_ConfigureRoomViewLight_0_en","",20056,], +["features.createroom.impl.configureroom_ConfigureRoomViewLight_1_en","",20056,], +["features.createroom.impl.configureroom_ConfigureRoomViewLight_2_en","",20056,], +["features.createroom.impl.configureroom_ConfigureRoomViewLight_3_en","",20056,], +["features.createroom.impl.configureroom_ConfigureRoomViewLight_4_en","",20056,], +["features.createroom.impl.configureroom_ConfigureRoomViewLight_5_en","",20056,], ["features.preferences.impl.developer.tracing_ConfigureTracingView_Day_0_en","features.preferences.impl.developer.tracing_ConfigureTracingView_Night_0_en",0,], -["features.login.impl.screens.confirmaccountprovider_ConfirmAccountProviderView_Day_0_en","features.login.impl.screens.confirmaccountprovider_ConfirmAccountProviderView_Night_0_en",20049,], -["features.login.impl.screens.confirmaccountprovider_ConfirmAccountProviderView_Day_1_en","features.login.impl.screens.confirmaccountprovider_ConfirmAccountProviderView_Night_1_en",20049,], -["features.login.impl.screens.confirmaccountprovider_ConfirmAccountProviderView_Day_2_en","features.login.impl.screens.confirmaccountprovider_ConfirmAccountProviderView_Night_2_en",20049,], -["features.roomlist.impl.components_ConfirmRecoveryKeyBanner_Day_0_en","features.roomlist.impl.components_ConfirmRecoveryKeyBanner_Night_0_en",20049,], +["features.login.impl.screens.confirmaccountprovider_ConfirmAccountProviderView_Day_0_en","features.login.impl.screens.confirmaccountprovider_ConfirmAccountProviderView_Night_0_en",20056,], +["features.login.impl.screens.confirmaccountprovider_ConfirmAccountProviderView_Day_1_en","features.login.impl.screens.confirmaccountprovider_ConfirmAccountProviderView_Night_1_en",20056,], +["features.login.impl.screens.confirmaccountprovider_ConfirmAccountProviderView_Day_2_en","features.login.impl.screens.confirmaccountprovider_ConfirmAccountProviderView_Night_2_en",20056,], +["features.roomlist.impl.components_ConfirmRecoveryKeyBanner_Day_0_en","features.roomlist.impl.components_ConfirmRecoveryKeyBanner_Night_0_en",20056,], ["libraries.designsystem.components.dialogs_ConfirmationDialogContent_Dialogs_en","",0,], ["libraries.designsystem.components.dialogs_ConfirmationDialog_Day_0_en","libraries.designsystem.components.dialogs_ConfirmationDialog_Night_0_en",0,], ["features.networkmonitor.api.ui_ConnectivityIndicatorView_Day_0_en","features.networkmonitor.api.ui_ConnectivityIndicatorView_Night_0_en",0,], -["features.rageshake.api.crash_CrashDetectionView_Day_0_en","features.rageshake.api.crash_CrashDetectionView_Night_0_en",20049,], -["features.login.impl.screens.createaccount_CreateAccountView_Day_0_en","features.login.impl.screens.createaccount_CreateAccountView_Night_0_en",20049,], -["features.login.impl.screens.createaccount_CreateAccountView_Day_1_en","features.login.impl.screens.createaccount_CreateAccountView_Night_1_en",20049,], -["features.login.impl.screens.createaccount_CreateAccountView_Day_2_en","features.login.impl.screens.createaccount_CreateAccountView_Night_2_en",20049,], -["features.login.impl.screens.createaccount_CreateAccountView_Day_3_en","features.login.impl.screens.createaccount_CreateAccountView_Night_3_en",20049,], -["features.poll.impl.create_CreatePollView_Day_0_en","features.poll.impl.create_CreatePollView_Night_0_en",20049,], -["features.poll.impl.create_CreatePollView_Day_1_en","features.poll.impl.create_CreatePollView_Night_1_en",20049,], -["features.poll.impl.create_CreatePollView_Day_2_en","features.poll.impl.create_CreatePollView_Night_2_en",20049,], -["features.poll.impl.create_CreatePollView_Day_3_en","features.poll.impl.create_CreatePollView_Night_3_en",20049,], -["features.poll.impl.create_CreatePollView_Day_4_en","features.poll.impl.create_CreatePollView_Night_4_en",20049,], -["features.poll.impl.create_CreatePollView_Day_5_en","features.poll.impl.create_CreatePollView_Night_5_en",20049,], -["features.poll.impl.create_CreatePollView_Day_6_en","features.poll.impl.create_CreatePollView_Night_6_en",20049,], -["features.poll.impl.create_CreatePollView_Day_7_en","features.poll.impl.create_CreatePollView_Night_7_en",20049,], -["features.createroom.impl.root_CreateRoomRootView_Day_0_en","features.createroom.impl.root_CreateRoomRootView_Night_0_en",20049,], -["features.createroom.impl.root_CreateRoomRootView_Day_1_en","features.createroom.impl.root_CreateRoomRootView_Night_1_en",20049,], -["features.createroom.impl.root_CreateRoomRootView_Day_2_en","features.createroom.impl.root_CreateRoomRootView_Night_2_en",20049,], -["features.createroom.impl.root_CreateRoomRootView_Day_3_en","features.createroom.impl.root_CreateRoomRootView_Night_3_en",20049,], -["libraries.designsystem.theme.components.previews_DatePickerDark_DateTime_pickers_en","",20049,], -["libraries.designsystem.theme.components.previews_DatePickerLight_DateTime_pickers_en","",20049,], +["features.rageshake.api.crash_CrashDetectionView_Day_0_en","features.rageshake.api.crash_CrashDetectionView_Night_0_en",20056,], +["features.login.impl.screens.createaccount_CreateAccountView_Day_0_en","features.login.impl.screens.createaccount_CreateAccountView_Night_0_en",20056,], +["features.login.impl.screens.createaccount_CreateAccountView_Day_1_en","features.login.impl.screens.createaccount_CreateAccountView_Night_1_en",20056,], +["features.login.impl.screens.createaccount_CreateAccountView_Day_2_en","features.login.impl.screens.createaccount_CreateAccountView_Night_2_en",20056,], +["features.login.impl.screens.createaccount_CreateAccountView_Day_3_en","features.login.impl.screens.createaccount_CreateAccountView_Night_3_en",20056,], +["features.poll.impl.create_CreatePollView_Day_0_en","features.poll.impl.create_CreatePollView_Night_0_en",20056,], +["features.poll.impl.create_CreatePollView_Day_1_en","features.poll.impl.create_CreatePollView_Night_1_en",20056,], +["features.poll.impl.create_CreatePollView_Day_2_en","features.poll.impl.create_CreatePollView_Night_2_en",20056,], +["features.poll.impl.create_CreatePollView_Day_3_en","features.poll.impl.create_CreatePollView_Night_3_en",20056,], +["features.poll.impl.create_CreatePollView_Day_4_en","features.poll.impl.create_CreatePollView_Night_4_en",20056,], +["features.poll.impl.create_CreatePollView_Day_5_en","features.poll.impl.create_CreatePollView_Night_5_en",20056,], +["features.poll.impl.create_CreatePollView_Day_6_en","features.poll.impl.create_CreatePollView_Night_6_en",20056,], +["features.poll.impl.create_CreatePollView_Day_7_en","features.poll.impl.create_CreatePollView_Night_7_en",20056,], +["features.createroom.impl.root_CreateRoomRootView_Day_0_en","features.createroom.impl.root_CreateRoomRootView_Night_0_en",20056,], +["features.createroom.impl.root_CreateRoomRootView_Day_1_en","features.createroom.impl.root_CreateRoomRootView_Night_1_en",20056,], +["features.createroom.impl.root_CreateRoomRootView_Day_2_en","features.createroom.impl.root_CreateRoomRootView_Night_2_en",20056,], +["features.createroom.impl.root_CreateRoomRootView_Day_3_en","features.createroom.impl.root_CreateRoomRootView_Night_3_en",20056,], +["libraries.designsystem.theme.components.previews_DatePickerDark_DateTime_pickers_en","",20056,], +["libraries.designsystem.theme.components.previews_DatePickerLight_DateTime_pickers_en","",20056,], ["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",20049,], -["features.logout.impl.direct_DefaultDirectLogoutView_Day_2_en","features.logout.impl.direct_DefaultDirectLogoutView_Night_2_en",20049,], -["features.logout.impl.direct_DefaultDirectLogoutView_Day_3_en","features.logout.impl.direct_DefaultDirectLogoutView_Night_3_en",20049,], +["features.logout.impl.direct_DefaultDirectLogoutView_Day_1_en","features.logout.impl.direct_DefaultDirectLogoutView_Night_1_en",20056,], +["features.logout.impl.direct_DefaultDirectLogoutView_Day_2_en","features.logout.impl.direct_DefaultDirectLogoutView_Night_2_en",20056,], +["features.logout.impl.direct_DefaultDirectLogoutView_Day_3_en","features.logout.impl.direct_DefaultDirectLogoutView_Night_3_en",20056,], ["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",20049,], -["features.roomlist.impl.components_DefaultRoomListTopBarWithIndicator_Day_0_en","features.roomlist.impl.components_DefaultRoomListTopBarWithIndicator_Night_0_en",20049,], -["features.roomlist.impl.components_DefaultRoomListTopBar_Day_0_en","features.roomlist.impl.components_DefaultRoomListTopBar_Night_0_en",20049,], +["features.preferences.impl.notifications.edit_DefaultNotificationSettingOption_Day_0_en","features.preferences.impl.notifications.edit_DefaultNotificationSettingOption_Night_0_en",20056,], +["features.roomlist.impl.components_DefaultRoomListTopBarWithIndicator_Day_0_en","features.roomlist.impl.components_DefaultRoomListTopBarWithIndicator_Night_0_en",20056,], +["features.roomlist.impl.components_DefaultRoomListTopBar_Day_0_en","features.roomlist.impl.components_DefaultRoomListTopBar_Night_0_en",20056,], ["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",20049,], -["features.licenses.impl.list_DependencyLicensesListView_Day_1_en","features.licenses.impl.list_DependencyLicensesListView_Night_1_en",20049,], -["features.licenses.impl.list_DependencyLicensesListView_Day_2_en","features.licenses.impl.list_DependencyLicensesListView_Night_2_en",20049,], -["features.preferences.impl.developer_DeveloperSettingsView_Day_0_en","features.preferences.impl.developer_DeveloperSettingsView_Night_0_en",20049,], -["features.preferences.impl.developer_DeveloperSettingsView_Day_1_en","features.preferences.impl.developer_DeveloperSettingsView_Night_1_en",20049,], -["features.preferences.impl.developer_DeveloperSettingsView_Day_2_en","features.preferences.impl.developer_DeveloperSettingsView_Night_2_en",20049,], -["libraries.designsystem.atomic.molecules_DialogLikeBannerMolecule_Day_0_en","libraries.designsystem.atomic.molecules_DialogLikeBannerMolecule_Night_0_en",20049,], +["features.licenses.impl.list_DependencyLicensesListView_Day_0_en","features.licenses.impl.list_DependencyLicensesListView_Night_0_en",20056,], +["features.licenses.impl.list_DependencyLicensesListView_Day_1_en","features.licenses.impl.list_DependencyLicensesListView_Night_1_en",20056,], +["features.licenses.impl.list_DependencyLicensesListView_Day_2_en","features.licenses.impl.list_DependencyLicensesListView_Night_2_en",20056,], +["features.preferences.impl.developer_DeveloperSettingsView_Day_0_en","features.preferences.impl.developer_DeveloperSettingsView_Night_0_en",20056,], +["features.preferences.impl.developer_DeveloperSettingsView_Day_1_en","features.preferences.impl.developer_DeveloperSettingsView_Night_1_en",20056,], +["features.preferences.impl.developer_DeveloperSettingsView_Day_2_en","features.preferences.impl.developer_DeveloperSettingsView_Night_2_en",20056,], +["libraries.designsystem.atomic.molecules_DialogLikeBannerMolecule_Day_0_en","libraries.designsystem.atomic.molecules_DialogLikeBannerMolecule_Night_0_en",20056,], ["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,], @@ -289,12 +291,12 @@ export const screenshots = [ ["libraries.designsystem.text_DpScale_1_0f__en","",0,], ["libraries.designsystem.text_DpScale_1_5f__en","",0,], ["libraries.designsystem.theme.components_DropdownMenuItem_Menus_en","",0,], -["features.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_Day_0_en","features.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_Night_0_en",20049,], -["features.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_Day_1_en","features.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_Night_1_en",20049,], -["features.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_Day_2_en","features.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_Night_2_en",20049,], -["features.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_Day_3_en","features.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_Night_3_en",20049,], -["features.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_Day_4_en","features.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_Night_4_en",20049,], -["features.preferences.impl.user.editprofile_EditUserProfileView_Day_0_en","features.preferences.impl.user.editprofile_EditUserProfileView_Night_0_en",20049,], +["features.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_Day_0_en","features.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_Night_0_en",20056,], +["features.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_Day_1_en","features.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_Night_1_en",20056,], +["features.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_Day_2_en","features.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_Night_2_en",20056,], +["features.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_Day_3_en","features.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_Night_3_en",20056,], +["features.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_Day_4_en","features.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_Night_4_en",20056,], +["features.preferences.impl.user.editprofile_EditUserProfileView_Day_0_en","features.preferences.impl.user.editprofile_EditUserProfileView_Night_0_en",20056,], ["libraries.matrix.ui.components_EditableAvatarView_Day_0_en","libraries.matrix.ui.components_EditableAvatarView_Night_0_en",0,], ["libraries.matrix.ui.components_EditableAvatarView_Day_1_en","libraries.matrix.ui.components_EditableAvatarView_Night_1_en",0,], ["libraries.matrix.ui.components_EditableAvatarView_Day_2_en","libraries.matrix.ui.components_EditableAvatarView_Night_2_en",0,], @@ -304,9 +306,9 @@ export const screenshots = [ ["libraries.designsystem.atomic.atoms_ElementLogoAtomMedium_Day_0_en","libraries.designsystem.atomic.atoms_ElementLogoAtomMedium_Night_0_en",0,], ["features.messages.impl.timeline.components.customreaction_EmojiItem_Day_0_en","features.messages.impl.timeline.components.customreaction_EmojiItem_Night_0_en",0,], ["features.messages.impl.timeline.components.customreaction_EmojiPicker_Day_0_en","features.messages.impl.timeline.components.customreaction_EmojiPicker_Night_0_en",0,], -["libraries.designsystem.components.dialogs_ErrorDialogContent_Dialogs_en","",20049,], -["libraries.designsystem.components.dialogs_ErrorDialogWithDoNotShowAgain_Day_0_en","libraries.designsystem.components.dialogs_ErrorDialogWithDoNotShowAgain_Night_0_en",20049,], -["libraries.designsystem.components.dialogs_ErrorDialog_Day_0_en","libraries.designsystem.components.dialogs_ErrorDialog_Night_0_en",20049,], +["libraries.designsystem.components.dialogs_ErrorDialogContent_Dialogs_en","",20056,], +["libraries.designsystem.components.dialogs_ErrorDialogWithDoNotShowAgain_Day_0_en","libraries.designsystem.components.dialogs_ErrorDialogWithDoNotShowAgain_Night_0_en",20056,], +["libraries.designsystem.components.dialogs_ErrorDialog_Day_0_en","libraries.designsystem.components.dialogs_ErrorDialog_Night_0_en",20056,], ["features.messages.impl.timeline.debug_EventDebugInfoView_Day_0_en","features.messages.impl.timeline.debug_EventDebugInfoView_Night_0_en",0,], ["libraries.featureflag.ui_FeatureListView_Day_0_en","libraries.featureflag.ui_FeatureListView_Night_0_en",0,], ["libraries.designsystem.theme.components_FilledButtonLargeLowPadding_Buttons_en","",0,], @@ -321,15 +323,15 @@ export const screenshots = [ ["libraries.designsystem.theme.components_FloatingActionButton_Floating_Action_Buttons_en","",0,], ["libraries.designsystem.atomic.pages_FlowStepPage_Day_0_en","libraries.designsystem.atomic.pages_FlowStepPage_Night_0_en",0,], ["features.messages.impl.timeline.focus_FocusRequestStateView_Day_0_en","features.messages.impl.timeline.focus_FocusRequestStateView_Night_0_en",0,], -["features.messages.impl.timeline.focus_FocusRequestStateView_Day_1_en","features.messages.impl.timeline.focus_FocusRequestStateView_Night_1_en",20049,], -["features.messages.impl.timeline.focus_FocusRequestStateView_Day_2_en","features.messages.impl.timeline.focus_FocusRequestStateView_Night_2_en",20049,], -["features.messages.impl.timeline.focus_FocusRequestStateView_Day_3_en","features.messages.impl.timeline.focus_FocusRequestStateView_Night_3_en",20049,], +["features.messages.impl.timeline.focus_FocusRequestStateView_Day_1_en","features.messages.impl.timeline.focus_FocusRequestStateView_Night_1_en",20056,], +["features.messages.impl.timeline.focus_FocusRequestStateView_Day_2_en","features.messages.impl.timeline.focus_FocusRequestStateView_Night_2_en",20056,], +["features.messages.impl.timeline.focus_FocusRequestStateView_Day_3_en","features.messages.impl.timeline.focus_FocusRequestStateView_Night_3_en",20056,], ["libraries.textcomposer.components_FormattingOption_Day_0_en","libraries.textcomposer.components_FormattingOption_Night_0_en",0,], ["features.messages.impl.forward_ForwardMessagesView_Day_0_en","features.messages.impl.forward_ForwardMessagesView_Night_0_en",0,], ["features.messages.impl.forward_ForwardMessagesView_Day_1_en","features.messages.impl.forward_ForwardMessagesView_Night_1_en",0,], ["features.messages.impl.forward_ForwardMessagesView_Day_2_en","features.messages.impl.forward_ForwardMessagesView_Night_2_en",0,], -["features.messages.impl.forward_ForwardMessagesView_Day_3_en","features.messages.impl.forward_ForwardMessagesView_Night_3_en",20049,], -["features.roomlist.impl.components_FullScreenIntentPermissionBanner_Day_0_en","features.roomlist.impl.components_FullScreenIntentPermissionBanner_Night_0_en",20049,], +["features.messages.impl.forward_ForwardMessagesView_Day_3_en","features.messages.impl.forward_ForwardMessagesView_Night_3_en",20056,], +["features.roomlist.impl.components_FullScreenIntentPermissionBanner_Day_0_en","features.roomlist.impl.components_FullScreenIntentPermissionBanner_Night_0_en",20056,], ["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,], @@ -351,52 +353,53 @@ export const screenshots = [ ["libraries.designsystem.icons_IconsCompound_Day_5_en","libraries.designsystem.icons_IconsCompound_Night_5_en",0,], ["libraries.designsystem.icons_IconsOther_Day_0_en","libraries.designsystem.icons_IconsOther_Night_0_en",0,], ["features.messages.impl.crypto.identity_IdentityChangeStateView_Day_0_en","features.messages.impl.crypto.identity_IdentityChangeStateView_Night_0_en",0,], -["features.messages.impl.crypto.identity_IdentityChangeStateView_Day_1_en","features.messages.impl.crypto.identity_IdentityChangeStateView_Night_1_en",20049,], -["features.messages.impl.crypto.identity_IdentityChangeStateView_Day_2_en","features.messages.impl.crypto.identity_IdentityChangeStateView_Night_2_en",20049,], +["features.messages.impl.crypto.identity_IdentityChangeStateView_Day_1_en","features.messages.impl.crypto.identity_IdentityChangeStateView_Night_1_en",20056,], +["features.messages.impl.crypto.identity_IdentityChangeStateView_Day_2_en","features.messages.impl.crypto.identity_IdentityChangeStateView_Night_2_en",20056,], ["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,], ["libraries.matrix.ui.messages.reply_InReplyToView_Day_11_en","libraries.matrix.ui.messages.reply_InReplyToView_Night_11_en",0,], ["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",20049,], +["libraries.matrix.ui.messages.reply_InReplyToView_Day_4_en","libraries.matrix.ui.messages.reply_InReplyToView_Night_4_en",20056,], ["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",20049,], +["libraries.matrix.ui.messages.reply_InReplyToView_Day_8_en","libraries.matrix.ui.messages.reply_InReplyToView_Night_8_en",20056,], ["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",20049,], -["features.verifysession.impl.incoming_IncomingVerificationView_Day_0_en","features.verifysession.impl.incoming_IncomingVerificationView_Night_0_en",0,], -["features.verifysession.impl.incoming_IncomingVerificationView_Day_1_en","features.verifysession.impl.incoming_IncomingVerificationView_Night_1_en",20049,], -["features.verifysession.impl.incoming_IncomingVerificationView_Day_2_en","features.verifysession.impl.incoming_IncomingVerificationView_Night_2_en",20049,], -["features.verifysession.impl.incoming_IncomingVerificationView_Day_3_en","features.verifysession.impl.incoming_IncomingVerificationView_Night_3_en",20049,], -["features.verifysession.impl.incoming_IncomingVerificationView_Day_4_en","features.verifysession.impl.incoming_IncomingVerificationView_Night_4_en",20049,], -["features.verifysession.impl.incoming_IncomingVerificationView_Day_5_en","features.verifysession.impl.incoming_IncomingVerificationView_Night_5_en",20049,], -["features.verifysession.impl.incoming_IncomingVerificationView_Day_6_en","features.verifysession.impl.incoming_IncomingVerificationView_Night_6_en",20049,], -["features.verifysession.impl.incoming_IncomingVerificationView_Day_7_en","features.verifysession.impl.incoming_IncomingVerificationView_Night_7_en",20049,], +["features.call.impl.ui_IncomingCallScreen_Day_0_en","features.call.impl.ui_IncomingCallScreen_Night_0_en",20056,], +["features.verifysession.impl.incoming_IncomingVerificationView_Day_0_en","features.verifysession.impl.incoming_IncomingVerificationView_Night_0_en",20059,], +["features.verifysession.impl.incoming_IncomingVerificationView_Day_1_en","features.verifysession.impl.incoming_IncomingVerificationView_Night_1_en",20056,], +["features.verifysession.impl.incoming_IncomingVerificationView_Day_2_en","features.verifysession.impl.incoming_IncomingVerificationView_Night_2_en",20056,], +["features.verifysession.impl.incoming_IncomingVerificationView_Day_3_en","features.verifysession.impl.incoming_IncomingVerificationView_Night_3_en",20056,], +["features.verifysession.impl.incoming_IncomingVerificationView_Day_4_en","features.verifysession.impl.incoming_IncomingVerificationView_Night_4_en",20056,], +["features.verifysession.impl.incoming_IncomingVerificationView_Day_5_en","features.verifysession.impl.incoming_IncomingVerificationView_Night_5_en",20056,], +["features.verifysession.impl.incoming_IncomingVerificationView_Day_6_en","features.verifysession.impl.incoming_IncomingVerificationView_Night_6_en",20056,], +["features.verifysession.impl.incoming_IncomingVerificationView_Day_7_en","features.verifysession.impl.incoming_IncomingVerificationView_Night_7_en",20056,], ["libraries.designsystem.atomic.molecules_InfoListItemMolecule_Day_0_en","libraries.designsystem.atomic.molecules_InfoListItemMolecule_Night_0_en",0,], ["libraries.designsystem.atomic.organisms_InfoListOrganism_Day_0_en","libraries.designsystem.atomic.organisms_InfoListOrganism_Night_0_en",0,], -["libraries.matrix.ui.components_InviteSenderView_Day_0_en","libraries.matrix.ui.components_InviteSenderView_Night_0_en",20049,], +["libraries.matrix.ui.components_InviteSenderView_Day_0_en","libraries.matrix.ui.components_InviteSenderView_Night_0_en",20056,], ["features.joinroom.impl_JoinRoomView_Day_0_en","features.joinroom.impl_JoinRoomView_Night_0_en",0,], -["features.joinroom.impl_JoinRoomView_Day_10_en","features.joinroom.impl_JoinRoomView_Night_10_en",0,], -["features.joinroom.impl_JoinRoomView_Day_11_en","features.joinroom.impl_JoinRoomView_Night_11_en",0,], -["features.joinroom.impl_JoinRoomView_Day_1_en","features.joinroom.impl_JoinRoomView_Night_1_en",20049,], -["features.joinroom.impl_JoinRoomView_Day_2_en","features.joinroom.impl_JoinRoomView_Night_2_en",20049,], -["features.joinroom.impl_JoinRoomView_Day_3_en","features.joinroom.impl_JoinRoomView_Night_3_en",20049,], -["features.joinroom.impl_JoinRoomView_Day_4_en","features.joinroom.impl_JoinRoomView_Night_4_en",20049,], -["features.joinroom.impl_JoinRoomView_Day_5_en","features.joinroom.impl_JoinRoomView_Night_5_en",20049,], -["features.joinroom.impl_JoinRoomView_Day_6_en","features.joinroom.impl_JoinRoomView_Night_6_en",20049,], -["features.joinroom.impl_JoinRoomView_Day_7_en","features.joinroom.impl_JoinRoomView_Night_7_en",20049,], -["features.joinroom.impl_JoinRoomView_Day_8_en","features.joinroom.impl_JoinRoomView_Night_8_en",20049,], -["features.joinroom.impl_JoinRoomView_Day_9_en","features.joinroom.impl_JoinRoomView_Night_9_en",20049,], +["features.joinroom.impl_JoinRoomView_Day_10_en","features.joinroom.impl_JoinRoomView_Night_10_en",20059,], +["features.joinroom.impl_JoinRoomView_Day_11_en","features.joinroom.impl_JoinRoomView_Night_11_en",20059,], +["features.joinroom.impl_JoinRoomView_Day_12_en","features.joinroom.impl_JoinRoomView_Night_12_en",20059,], +["features.joinroom.impl_JoinRoomView_Day_1_en","features.joinroom.impl_JoinRoomView_Night_1_en",20056,], +["features.joinroom.impl_JoinRoomView_Day_2_en","features.joinroom.impl_JoinRoomView_Night_2_en",20056,], +["features.joinroom.impl_JoinRoomView_Day_3_en","features.joinroom.impl_JoinRoomView_Night_3_en",20056,], +["features.joinroom.impl_JoinRoomView_Day_4_en","features.joinroom.impl_JoinRoomView_Night_4_en",20056,], +["features.joinroom.impl_JoinRoomView_Day_5_en","features.joinroom.impl_JoinRoomView_Night_5_en",20056,], +["features.joinroom.impl_JoinRoomView_Day_6_en","features.joinroom.impl_JoinRoomView_Night_6_en",20056,], +["features.joinroom.impl_JoinRoomView_Day_7_en","features.joinroom.impl_JoinRoomView_Night_7_en",20056,], +["features.joinroom.impl_JoinRoomView_Day_8_en","features.joinroom.impl_JoinRoomView_Night_8_en",20056,], +["features.joinroom.impl_JoinRoomView_Day_9_en","features.joinroom.impl_JoinRoomView_Night_9_en",0,], ["libraries.designsystem.components_LabelledCheckbox_Toggles_en","",0,], ["features.leaveroom.api_LeaveRoomView_Day_0_en","features.leaveroom.api_LeaveRoomView_Night_0_en",0,], -["features.leaveroom.api_LeaveRoomView_Day_1_en","features.leaveroom.api_LeaveRoomView_Night_1_en",20049,], -["features.leaveroom.api_LeaveRoomView_Day_2_en","features.leaveroom.api_LeaveRoomView_Night_2_en",20049,], -["features.leaveroom.api_LeaveRoomView_Day_3_en","features.leaveroom.api_LeaveRoomView_Night_3_en",20049,], -["features.leaveroom.api_LeaveRoomView_Day_4_en","features.leaveroom.api_LeaveRoomView_Night_4_en",20049,], -["features.leaveroom.api_LeaveRoomView_Day_5_en","features.leaveroom.api_LeaveRoomView_Night_5_en",20049,], -["features.leaveroom.api_LeaveRoomView_Day_6_en","features.leaveroom.api_LeaveRoomView_Night_6_en",20049,], +["features.leaveroom.api_LeaveRoomView_Day_1_en","features.leaveroom.api_LeaveRoomView_Night_1_en",20056,], +["features.leaveroom.api_LeaveRoomView_Day_2_en","features.leaveroom.api_LeaveRoomView_Night_2_en",20056,], +["features.leaveroom.api_LeaveRoomView_Day_3_en","features.leaveroom.api_LeaveRoomView_Night_3_en",20056,], +["features.leaveroom.api_LeaveRoomView_Day_4_en","features.leaveroom.api_LeaveRoomView_Night_4_en",20056,], +["features.leaveroom.api_LeaveRoomView_Day_5_en","features.leaveroom.api_LeaveRoomView_Night_5_en",20056,], +["features.leaveroom.api_LeaveRoomView_Day_6_en","features.leaveroom.api_LeaveRoomView_Night_6_en",20056,], ["libraries.designsystem.background_LightGradientBackground_Day_0_en","libraries.designsystem.background_LightGradientBackground_Night_0_en",0,], ["libraries.designsystem.theme.components_LinearProgressIndicator_Progress_Indicators_en","",0,], ["libraries.designsystem.components.dialogs_ListDialogContent_Dialogs_en","",0,], @@ -453,29 +456,29 @@ 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",20049,], -["features.lockscreen.impl.settings_LockScreenSettingsView_Day_0_en","features.lockscreen.impl.settings_LockScreenSettingsView_Night_0_en",20049,], -["features.lockscreen.impl.settings_LockScreenSettingsView_Day_1_en","features.lockscreen.impl.settings_LockScreenSettingsView_Night_1_en",20049,], -["features.lockscreen.impl.settings_LockScreenSettingsView_Day_2_en","features.lockscreen.impl.settings_LockScreenSettingsView_Night_2_en",20049,], +["appnav.room.joined_LoadingRoomNodeView_Day_1_en","appnav.room.joined_LoadingRoomNodeView_Night_1_en",20056,], +["features.lockscreen.impl.settings_LockScreenSettingsView_Day_0_en","features.lockscreen.impl.settings_LockScreenSettingsView_Night_0_en",20056,], +["features.lockscreen.impl.settings_LockScreenSettingsView_Day_1_en","features.lockscreen.impl.settings_LockScreenSettingsView_Night_1_en",20056,], +["features.lockscreen.impl.settings_LockScreenSettingsView_Day_2_en","features.lockscreen.impl.settings_LockScreenSettingsView_Night_2_en",20056,], ["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",20049,], -["appnav.loggedin_LoggedInView_Day_2_en","appnav.loggedin_LoggedInView_Night_2_en",20049,], -["appnav.loggedin_LoggedInView_Day_3_en","appnav.loggedin_LoggedInView_Night_3_en",20049,], -["features.login.impl.screens.loginpassword_LoginPasswordView_Day_0_en","features.login.impl.screens.loginpassword_LoginPasswordView_Night_0_en",20049,], -["features.login.impl.screens.loginpassword_LoginPasswordView_Day_1_en","features.login.impl.screens.loginpassword_LoginPasswordView_Night_1_en",20049,], -["features.login.impl.screens.loginpassword_LoginPasswordView_Day_2_en","features.login.impl.screens.loginpassword_LoginPasswordView_Night_2_en",20049,], -["features.logout.impl_LogoutView_Day_0_en","features.logout.impl_LogoutView_Night_0_en",20049,], -["features.logout.impl_LogoutView_Day_1_en","features.logout.impl_LogoutView_Night_1_en",20049,], -["features.logout.impl_LogoutView_Day_2_en","features.logout.impl_LogoutView_Night_2_en",20049,], -["features.logout.impl_LogoutView_Day_3_en","features.logout.impl_LogoutView_Night_3_en",20049,], -["features.logout.impl_LogoutView_Day_4_en","features.logout.impl_LogoutView_Night_4_en",20049,], -["features.logout.impl_LogoutView_Day_5_en","features.logout.impl_LogoutView_Night_5_en",20049,], -["features.logout.impl_LogoutView_Day_6_en","features.logout.impl_LogoutView_Night_6_en",20049,], -["features.logout.impl_LogoutView_Day_7_en","features.logout.impl_LogoutView_Night_7_en",20049,], -["features.logout.impl_LogoutView_Day_8_en","features.logout.impl_LogoutView_Night_8_en",20049,], -["features.logout.impl_LogoutView_Day_9_en","features.logout.impl_LogoutView_Night_9_en",20049,], +["appnav.loggedin_LoggedInView_Day_1_en","appnav.loggedin_LoggedInView_Night_1_en",20056,], +["appnav.loggedin_LoggedInView_Day_2_en","appnav.loggedin_LoggedInView_Night_2_en",20056,], +["appnav.loggedin_LoggedInView_Day_3_en","appnav.loggedin_LoggedInView_Night_3_en",20056,], +["features.login.impl.screens.loginpassword_LoginPasswordView_Day_0_en","features.login.impl.screens.loginpassword_LoginPasswordView_Night_0_en",20056,], +["features.login.impl.screens.loginpassword_LoginPasswordView_Day_1_en","features.login.impl.screens.loginpassword_LoginPasswordView_Night_1_en",20056,], +["features.login.impl.screens.loginpassword_LoginPasswordView_Day_2_en","features.login.impl.screens.loginpassword_LoginPasswordView_Night_2_en",20056,], +["features.logout.impl_LogoutView_Day_0_en","features.logout.impl_LogoutView_Night_0_en",20056,], +["features.logout.impl_LogoutView_Day_1_en","features.logout.impl_LogoutView_Night_1_en",20056,], +["features.logout.impl_LogoutView_Day_2_en","features.logout.impl_LogoutView_Night_2_en",20056,], +["features.logout.impl_LogoutView_Day_3_en","features.logout.impl_LogoutView_Night_3_en",20056,], +["features.logout.impl_LogoutView_Day_4_en","features.logout.impl_LogoutView_Night_4_en",20056,], +["features.logout.impl_LogoutView_Day_5_en","features.logout.impl_LogoutView_Night_5_en",20056,], +["features.logout.impl_LogoutView_Day_6_en","features.logout.impl_LogoutView_Night_6_en",20056,], +["features.logout.impl_LogoutView_Day_7_en","features.logout.impl_LogoutView_Night_7_en",20056,], +["features.logout.impl_LogoutView_Day_8_en","features.logout.impl_LogoutView_Night_8_en",20056,], +["features.logout.impl_LogoutView_Day_9_en","features.logout.impl_LogoutView_Night_9_en",20056,], ["libraries.designsystem.components.button_MainActionButton_Buttons_en","",0,], -["libraries.textcomposer_MarkdownTextComposerEdit_Day_0_en","libraries.textcomposer_MarkdownTextComposerEdit_Night_0_en",20049,], +["libraries.textcomposer_MarkdownTextComposerEdit_Day_0_en","libraries.textcomposer_MarkdownTextComposerEdit_Night_0_en",20056,], ["libraries.textcomposer.components.markdown_MarkdownTextInput_Day_0_en","libraries.textcomposer.components.markdown_MarkdownTextInput_Night_0_en",0,], ["libraries.designsystem.atomic.atoms_MatrixBadgeAtomNegative_Day_0_en","libraries.designsystem.atomic.atoms_MatrixBadgeAtomNegative_Night_0_en",0,], ["libraries.designsystem.atomic.atoms_MatrixBadgeAtomNeutral_Day_0_en","libraries.designsystem.atomic.atoms_MatrixBadgeAtomNeutral_Night_0_en",0,], @@ -485,10 +488,12 @@ export const screenshots = [ ["libraries.matrix.ui.components_MatrixUserHeader_Day_1_en","libraries.matrix.ui.components_MatrixUserHeader_Night_1_en",0,], ["libraries.matrix.ui.components_MatrixUserRow_Day_0_en","libraries.matrix.ui.components_MatrixUserRow_Night_0_en",0,], ["libraries.matrix.ui.components_MatrixUserRow_Day_1_en","libraries.matrix.ui.components_MatrixUserRow_Night_1_en",0,], +["libraries.mediaviewer.api.player_MediaPlayerControllerView_Day_0_en","libraries.mediaviewer.api.player_MediaPlayerControllerView_Night_0_en",0,], +["libraries.mediaviewer.api.player_MediaPlayerControllerView_Day_1_en","libraries.mediaviewer.api.player_MediaPlayerControllerView_Night_1_en",0,], ["libraries.mediaviewer.api.viewer_MediaViewerView_0_en","",0,], ["libraries.mediaviewer.api.viewer_MediaViewerView_10_en","",0,], ["libraries.mediaviewer.api.viewer_MediaViewerView_1_en","",0,], -["libraries.mediaviewer.api.viewer_MediaViewerView_2_en","",20049,], +["libraries.mediaviewer.api.viewer_MediaViewerView_2_en","",20056,], ["libraries.mediaviewer.api.viewer_MediaViewerView_3_en","",0,], ["libraries.mediaviewer.api.viewer_MediaViewerView_4_en","",0,], ["libraries.mediaviewer.api.viewer_MediaViewerView_5_en","",0,], @@ -500,7 +505,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",20049,], +["features.messages.impl.messagecomposer_MessageComposerView_Day_0_en","features.messages.impl.messagecomposer_MessageComposerView_Night_0_en",20056,], ["features.messages.impl.timeline.components_MessageEventBubble_Day_0_en","features.messages.impl.timeline.components_MessageEventBubble_Night_0_en",0,], ["features.messages.impl.timeline.components_MessageEventBubble_Day_10_en","features.messages.impl.timeline.components_MessageEventBubble_Night_10_en",0,], ["features.messages.impl.timeline.components_MessageEventBubble_Day_11_en","features.messages.impl.timeline.components_MessageEventBubble_Night_11_en",0,], @@ -517,7 +522,7 @@ export const screenshots = [ ["features.messages.impl.timeline.components_MessageEventBubble_Day_7_en","features.messages.impl.timeline.components_MessageEventBubble_Night_7_en",0,], ["features.messages.impl.timeline.components_MessageEventBubble_Day_8_en","features.messages.impl.timeline.components_MessageEventBubble_Night_8_en",0,], ["features.messages.impl.timeline.components_MessageEventBubble_Day_9_en","features.messages.impl.timeline.components_MessageEventBubble_Night_9_en",0,], -["features.messages.impl.timeline.components_MessageShieldView_Day_0_en","features.messages.impl.timeline.components_MessageShieldView_Night_0_en",20049,], +["features.messages.impl.timeline.components_MessageShieldView_Day_0_en","features.messages.impl.timeline.components_MessageShieldView_Night_0_en",20056,], ["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,], @@ -525,23 +530,23 @@ export const screenshots = [ ["features.messages.impl.timeline.components_MessagesReactionButton_Day_1_en","features.messages.impl.timeline.components_MessagesReactionButton_Night_1_en",0,], ["features.messages.impl.timeline.components_MessagesReactionButton_Day_2_en","features.messages.impl.timeline.components_MessagesReactionButton_Night_2_en",0,], ["features.messages.impl.timeline.components_MessagesReactionButton_Day_3_en","features.messages.impl.timeline.components_MessagesReactionButton_Night_3_en",0,], -["features.messages.impl.crypto.identity_MessagesViewWithIdentityChange_Day_0_en","features.messages.impl.crypto.identity_MessagesViewWithIdentityChange_Night_0_en",20049,], -["features.messages.impl.crypto.identity_MessagesViewWithIdentityChange_Day_1_en","features.messages.impl.crypto.identity_MessagesViewWithIdentityChange_Night_1_en",20049,], -["features.messages.impl.crypto.identity_MessagesViewWithIdentityChange_Day_2_en","features.messages.impl.crypto.identity_MessagesViewWithIdentityChange_Night_2_en",20049,], -["features.messages.impl_MessagesView_Day_0_en","features.messages.impl_MessagesView_Night_0_en",20049,], -["features.messages.impl_MessagesView_Day_10_en","features.messages.impl_MessagesView_Night_10_en",20049,], -["features.messages.impl_MessagesView_Day_11_en","features.messages.impl_MessagesView_Night_11_en",20049,], -["features.messages.impl_MessagesView_Day_1_en","features.messages.impl_MessagesView_Night_1_en",20049,], -["features.messages.impl_MessagesView_Day_2_en","features.messages.impl_MessagesView_Night_2_en",20049,], -["features.messages.impl_MessagesView_Day_3_en","features.messages.impl_MessagesView_Night_3_en",20049,], -["features.messages.impl_MessagesView_Day_4_en","features.messages.impl_MessagesView_Night_4_en",20049,], -["features.messages.impl_MessagesView_Day_5_en","features.messages.impl_MessagesView_Night_5_en",20049,], -["features.messages.impl_MessagesView_Day_6_en","features.messages.impl_MessagesView_Night_6_en",20049,], -["features.messages.impl_MessagesView_Day_7_en","features.messages.impl_MessagesView_Night_7_en",20049,], -["features.messages.impl_MessagesView_Day_8_en","features.messages.impl_MessagesView_Night_8_en",20049,], -["features.messages.impl_MessagesView_Day_9_en","features.messages.impl_MessagesView_Night_9_en",20049,], +["features.messages.impl.crypto.identity_MessagesViewWithIdentityChange_Day_0_en","features.messages.impl.crypto.identity_MessagesViewWithIdentityChange_Night_0_en",20056,], +["features.messages.impl.crypto.identity_MessagesViewWithIdentityChange_Day_1_en","features.messages.impl.crypto.identity_MessagesViewWithIdentityChange_Night_1_en",20056,], +["features.messages.impl.crypto.identity_MessagesViewWithIdentityChange_Day_2_en","features.messages.impl.crypto.identity_MessagesViewWithIdentityChange_Night_2_en",20056,], +["features.messages.impl_MessagesView_Day_0_en","features.messages.impl_MessagesView_Night_0_en",20056,], +["features.messages.impl_MessagesView_Day_10_en","features.messages.impl_MessagesView_Night_10_en",20056,], +["features.messages.impl_MessagesView_Day_11_en","features.messages.impl_MessagesView_Night_11_en",20056,], +["features.messages.impl_MessagesView_Day_1_en","features.messages.impl_MessagesView_Night_1_en",20056,], +["features.messages.impl_MessagesView_Day_2_en","features.messages.impl_MessagesView_Night_2_en",20056,], +["features.messages.impl_MessagesView_Day_3_en","features.messages.impl_MessagesView_Night_3_en",20056,], +["features.messages.impl_MessagesView_Day_4_en","features.messages.impl_MessagesView_Night_4_en",20056,], +["features.messages.impl_MessagesView_Day_5_en","features.messages.impl_MessagesView_Night_5_en",20056,], +["features.messages.impl_MessagesView_Day_6_en","features.messages.impl_MessagesView_Night_6_en",20056,], +["features.messages.impl_MessagesView_Day_7_en","features.messages.impl_MessagesView_Night_7_en",20056,], +["features.messages.impl_MessagesView_Day_8_en","features.messages.impl_MessagesView_Night_8_en",20056,], +["features.messages.impl_MessagesView_Day_9_en","features.messages.impl_MessagesView_Night_9_en",20056,], ["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",20049,], +["features.migration.impl_MigrationView_Day_1_en","features.migration.impl_MigrationView_Night_1_en",20056,], ["libraries.designsystem.theme.components_ModalBottomSheetDark_Bottom_Sheets_en","",0,], ["libraries.designsystem.theme.components_ModalBottomSheetLight_Bottom_Sheets_en","",0,], ["appicon.element_MonochromeIcon_en","",0,], @@ -550,29 +555,29 @@ export const screenshots = [ ["libraries.designsystem.components.list_MutipleSelectionListItemSelectedTrailingContent_Multiple_selection_List_item_-_selection_in_trailing_content_List_items_en","",0,], ["libraries.designsystem.components.list_MutipleSelectionListItemSelected_Multiple_selection_List_item_-_selection_in_supporting_text_List_items_en","",0,], ["libraries.designsystem.components.list_MutipleSelectionListItem_Multiple_selection_List_item_-_no_selection_List_items_en","",0,], -["features.roomlist.impl.components_NativeSlidingSyncMigrationBanner_Day_0_en","features.roomlist.impl.components_NativeSlidingSyncMigrationBanner_Night_0_en",20049,], -["features.preferences.impl.notifications_NotificationSettingsView_Day_0_en","features.preferences.impl.notifications_NotificationSettingsView_Night_0_en",20049,], -["features.preferences.impl.notifications_NotificationSettingsView_Day_10_en","features.preferences.impl.notifications_NotificationSettingsView_Night_10_en",20049,], -["features.preferences.impl.notifications_NotificationSettingsView_Day_11_en","features.preferences.impl.notifications_NotificationSettingsView_Night_11_en",20049,], -["features.preferences.impl.notifications_NotificationSettingsView_Day_12_en","features.preferences.impl.notifications_NotificationSettingsView_Night_12_en",20049,], -["features.preferences.impl.notifications_NotificationSettingsView_Day_1_en","features.preferences.impl.notifications_NotificationSettingsView_Night_1_en",20049,], -["features.preferences.impl.notifications_NotificationSettingsView_Day_2_en","features.preferences.impl.notifications_NotificationSettingsView_Night_2_en",20049,], -["features.preferences.impl.notifications_NotificationSettingsView_Day_3_en","features.preferences.impl.notifications_NotificationSettingsView_Night_3_en",20049,], -["features.preferences.impl.notifications_NotificationSettingsView_Day_4_en","features.preferences.impl.notifications_NotificationSettingsView_Night_4_en",20049,], -["features.preferences.impl.notifications_NotificationSettingsView_Day_5_en","features.preferences.impl.notifications_NotificationSettingsView_Night_5_en",20049,], -["features.preferences.impl.notifications_NotificationSettingsView_Day_6_en","features.preferences.impl.notifications_NotificationSettingsView_Night_6_en",20049,], -["features.preferences.impl.notifications_NotificationSettingsView_Day_7_en","features.preferences.impl.notifications_NotificationSettingsView_Night_7_en",20049,], -["features.preferences.impl.notifications_NotificationSettingsView_Day_8_en","features.preferences.impl.notifications_NotificationSettingsView_Night_8_en",20049,], -["features.preferences.impl.notifications_NotificationSettingsView_Day_9_en","features.preferences.impl.notifications_NotificationSettingsView_Night_9_en",20049,], -["features.ftue.impl.notifications_NotificationsOptInView_Day_0_en","features.ftue.impl.notifications_NotificationsOptInView_Night_0_en",20049,], +["features.roomlist.impl.components_NativeSlidingSyncMigrationBanner_Day_0_en","features.roomlist.impl.components_NativeSlidingSyncMigrationBanner_Night_0_en",20056,], +["features.preferences.impl.notifications_NotificationSettingsView_Day_0_en","features.preferences.impl.notifications_NotificationSettingsView_Night_0_en",20056,], +["features.preferences.impl.notifications_NotificationSettingsView_Day_10_en","features.preferences.impl.notifications_NotificationSettingsView_Night_10_en",20056,], +["features.preferences.impl.notifications_NotificationSettingsView_Day_11_en","features.preferences.impl.notifications_NotificationSettingsView_Night_11_en",20056,], +["features.preferences.impl.notifications_NotificationSettingsView_Day_12_en","features.preferences.impl.notifications_NotificationSettingsView_Night_12_en",20056,], +["features.preferences.impl.notifications_NotificationSettingsView_Day_1_en","features.preferences.impl.notifications_NotificationSettingsView_Night_1_en",20056,], +["features.preferences.impl.notifications_NotificationSettingsView_Day_2_en","features.preferences.impl.notifications_NotificationSettingsView_Night_2_en",20056,], +["features.preferences.impl.notifications_NotificationSettingsView_Day_3_en","features.preferences.impl.notifications_NotificationSettingsView_Night_3_en",20056,], +["features.preferences.impl.notifications_NotificationSettingsView_Day_4_en","features.preferences.impl.notifications_NotificationSettingsView_Night_4_en",20056,], +["features.preferences.impl.notifications_NotificationSettingsView_Day_5_en","features.preferences.impl.notifications_NotificationSettingsView_Night_5_en",20056,], +["features.preferences.impl.notifications_NotificationSettingsView_Day_6_en","features.preferences.impl.notifications_NotificationSettingsView_Night_6_en",20056,], +["features.preferences.impl.notifications_NotificationSettingsView_Day_7_en","features.preferences.impl.notifications_NotificationSettingsView_Night_7_en",20056,], +["features.preferences.impl.notifications_NotificationSettingsView_Day_8_en","features.preferences.impl.notifications_NotificationSettingsView_Night_8_en",20056,], +["features.preferences.impl.notifications_NotificationSettingsView_Day_9_en","features.preferences.impl.notifications_NotificationSettingsView_Night_9_en",20056,], +["features.ftue.impl.notifications_NotificationsOptInView_Day_0_en","features.ftue.impl.notifications_NotificationsOptInView_Night_0_en",20056,], ["libraries.oidc.impl.webview_OidcView_Day_0_en","libraries.oidc.impl.webview_OidcView_Night_0_en",0,], ["libraries.oidc.impl.webview_OidcView_Day_1_en","libraries.oidc.impl.webview_OidcView_Night_1_en",0,], ["libraries.designsystem.atomic.pages_OnBoardingPage_Day_0_en","libraries.designsystem.atomic.pages_OnBoardingPage_Night_0_en",0,], -["features.onboarding.impl_OnBoardingView_Day_0_en","features.onboarding.impl_OnBoardingView_Night_0_en",20049,], -["features.onboarding.impl_OnBoardingView_Day_1_en","features.onboarding.impl_OnBoardingView_Night_1_en",20049,], -["features.onboarding.impl_OnBoardingView_Day_2_en","features.onboarding.impl_OnBoardingView_Night_2_en",20049,], -["features.onboarding.impl_OnBoardingView_Day_3_en","features.onboarding.impl_OnBoardingView_Night_3_en",20049,], -["features.onboarding.impl_OnBoardingView_Day_4_en","features.onboarding.impl_OnBoardingView_Night_4_en",20049,], +["features.onboarding.impl_OnBoardingView_Day_0_en","features.onboarding.impl_OnBoardingView_Night_0_en",20056,], +["features.onboarding.impl_OnBoardingView_Day_1_en","features.onboarding.impl_OnBoardingView_Night_1_en",20056,], +["features.onboarding.impl_OnBoardingView_Day_2_en","features.onboarding.impl_OnBoardingView_Night_2_en",20056,], +["features.onboarding.impl_OnBoardingView_Day_3_en","features.onboarding.impl_OnBoardingView_Night_3_en",20056,], +["features.onboarding.impl_OnBoardingView_Day_4_en","features.onboarding.impl_OnBoardingView_Night_4_en",20056,], ["libraries.designsystem.background_OnboardingBackground_Day_0_en","libraries.designsystem.background_OnboardingBackground_Night_0_en",0,], ["libraries.designsystem.theme.components_OutlinedButtonLargeLowPadding_Buttons_en","",0,], ["libraries.designsystem.theme.components_OutlinedButtonLarge_Buttons_en","",0,], @@ -585,65 +590,65 @@ export const screenshots = [ ["libraries.designsystem.components_PageTitleWithIconFull_Day_3_en","libraries.designsystem.components_PageTitleWithIconFull_Night_3_en",0,], ["libraries.designsystem.components_PageTitleWithIconFull_Day_4_en","libraries.designsystem.components_PageTitleWithIconFull_Night_4_en",0,], ["libraries.designsystem.components_PageTitleWithIconMinimal_Day_0_en","libraries.designsystem.components_PageTitleWithIconMinimal_Night_0_en",0,], -["libraries.mediaviewer.api.local.pdf_PdfPagesErrorView_Day_0_en","libraries.mediaviewer.api.local.pdf_PdfPagesErrorView_Night_0_en",20049,], -["features.roomdetails.impl.rolesandpermissions.changeroles_PendingMemberRowWithLongName_Day_0_en","features.roomdetails.impl.rolesandpermissions.changeroles_PendingMemberRowWithLongName_Night_0_en",20049,], -["libraries.permissions.api_PermissionsView_Day_0_en","libraries.permissions.api_PermissionsView_Night_0_en",20049,], -["libraries.permissions.api_PermissionsView_Day_1_en","libraries.permissions.api_PermissionsView_Night_1_en",20049,], -["libraries.permissions.api_PermissionsView_Day_2_en","libraries.permissions.api_PermissionsView_Night_2_en",20049,], -["libraries.permissions.api_PermissionsView_Day_3_en","libraries.permissions.api_PermissionsView_Night_3_en",20049,], +["libraries.mediaviewer.api.local.pdf_PdfPagesErrorView_Day_0_en","libraries.mediaviewer.api.local.pdf_PdfPagesErrorView_Night_0_en",20056,], +["features.roomdetails.impl.rolesandpermissions.changeroles_PendingMemberRowWithLongName_Day_0_en","features.roomdetails.impl.rolesandpermissions.changeroles_PendingMemberRowWithLongName_Night_0_en",20056,], +["libraries.permissions.api_PermissionsView_Day_0_en","libraries.permissions.api_PermissionsView_Night_0_en",20056,], +["libraries.permissions.api_PermissionsView_Day_1_en","libraries.permissions.api_PermissionsView_Night_1_en",20056,], +["libraries.permissions.api_PermissionsView_Day_2_en","libraries.permissions.api_PermissionsView_Night_2_en",20056,], +["libraries.permissions.api_PermissionsView_Day_3_en","libraries.permissions.api_PermissionsView_Night_3_en",20056,], ["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",20049,], -["features.lockscreen.impl.unlock_PinUnlockViewInApp_Day_1_en","features.lockscreen.impl.unlock_PinUnlockViewInApp_Night_1_en",20049,], -["features.lockscreen.impl.unlock_PinUnlockViewInApp_Day_2_en","features.lockscreen.impl.unlock_PinUnlockViewInApp_Night_2_en",20049,], -["features.lockscreen.impl.unlock_PinUnlockViewInApp_Day_3_en","features.lockscreen.impl.unlock_PinUnlockViewInApp_Night_3_en",20049,], -["features.lockscreen.impl.unlock_PinUnlockViewInApp_Day_4_en","features.lockscreen.impl.unlock_PinUnlockViewInApp_Night_4_en",20049,], -["features.lockscreen.impl.unlock_PinUnlockViewInApp_Day_5_en","features.lockscreen.impl.unlock_PinUnlockViewInApp_Night_5_en",20049,], -["features.lockscreen.impl.unlock_PinUnlockViewInApp_Day_6_en","features.lockscreen.impl.unlock_PinUnlockViewInApp_Night_6_en",20049,], -["features.lockscreen.impl.unlock_PinUnlockViewInApp_Day_7_en","features.lockscreen.impl.unlock_PinUnlockViewInApp_Night_7_en",20049,], -["features.lockscreen.impl.unlock_PinUnlockView_Day_0_en","features.lockscreen.impl.unlock_PinUnlockView_Night_0_en",20049,], -["features.lockscreen.impl.unlock_PinUnlockView_Day_1_en","features.lockscreen.impl.unlock_PinUnlockView_Night_1_en",20049,], -["features.lockscreen.impl.unlock_PinUnlockView_Day_2_en","features.lockscreen.impl.unlock_PinUnlockView_Night_2_en",20049,], -["features.lockscreen.impl.unlock_PinUnlockView_Day_3_en","features.lockscreen.impl.unlock_PinUnlockView_Night_3_en",20049,], -["features.lockscreen.impl.unlock_PinUnlockView_Day_4_en","features.lockscreen.impl.unlock_PinUnlockView_Night_4_en",20049,], -["features.lockscreen.impl.unlock_PinUnlockView_Day_5_en","features.lockscreen.impl.unlock_PinUnlockView_Night_5_en",20049,], -["features.lockscreen.impl.unlock_PinUnlockView_Day_6_en","features.lockscreen.impl.unlock_PinUnlockView_Night_6_en",20049,], -["features.lockscreen.impl.unlock_PinUnlockView_Day_7_en","features.lockscreen.impl.unlock_PinUnlockView_Night_7_en",20049,], +["features.lockscreen.impl.unlock_PinUnlockViewInApp_Day_0_en","features.lockscreen.impl.unlock_PinUnlockViewInApp_Night_0_en",20056,], +["features.lockscreen.impl.unlock_PinUnlockViewInApp_Day_1_en","features.lockscreen.impl.unlock_PinUnlockViewInApp_Night_1_en",20056,], +["features.lockscreen.impl.unlock_PinUnlockViewInApp_Day_2_en","features.lockscreen.impl.unlock_PinUnlockViewInApp_Night_2_en",20056,], +["features.lockscreen.impl.unlock_PinUnlockViewInApp_Day_3_en","features.lockscreen.impl.unlock_PinUnlockViewInApp_Night_3_en",20056,], +["features.lockscreen.impl.unlock_PinUnlockViewInApp_Day_4_en","features.lockscreen.impl.unlock_PinUnlockViewInApp_Night_4_en",20056,], +["features.lockscreen.impl.unlock_PinUnlockViewInApp_Day_5_en","features.lockscreen.impl.unlock_PinUnlockViewInApp_Night_5_en",20056,], +["features.lockscreen.impl.unlock_PinUnlockViewInApp_Day_6_en","features.lockscreen.impl.unlock_PinUnlockViewInApp_Night_6_en",20056,], +["features.lockscreen.impl.unlock_PinUnlockViewInApp_Day_7_en","features.lockscreen.impl.unlock_PinUnlockViewInApp_Night_7_en",20056,], +["features.lockscreen.impl.unlock_PinUnlockView_Day_0_en","features.lockscreen.impl.unlock_PinUnlockView_Night_0_en",20056,], +["features.lockscreen.impl.unlock_PinUnlockView_Day_1_en","features.lockscreen.impl.unlock_PinUnlockView_Night_1_en",20056,], +["features.lockscreen.impl.unlock_PinUnlockView_Day_2_en","features.lockscreen.impl.unlock_PinUnlockView_Night_2_en",20056,], +["features.lockscreen.impl.unlock_PinUnlockView_Day_3_en","features.lockscreen.impl.unlock_PinUnlockView_Night_3_en",20056,], +["features.lockscreen.impl.unlock_PinUnlockView_Day_4_en","features.lockscreen.impl.unlock_PinUnlockView_Night_4_en",20056,], +["features.lockscreen.impl.unlock_PinUnlockView_Day_5_en","features.lockscreen.impl.unlock_PinUnlockView_Night_5_en",20056,], +["features.lockscreen.impl.unlock_PinUnlockView_Day_6_en","features.lockscreen.impl.unlock_PinUnlockView_Night_6_en",20056,], +["features.lockscreen.impl.unlock_PinUnlockView_Day_7_en","features.lockscreen.impl.unlock_PinUnlockView_Night_7_en",20056,], ["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",20049,], -["features.messages.impl.pinned.banner_PinnedMessagesBannerView_Day_1_en","features.messages.impl.pinned.banner_PinnedMessagesBannerView_Night_1_en",20049,], -["features.messages.impl.pinned.banner_PinnedMessagesBannerView_Day_2_en","features.messages.impl.pinned.banner_PinnedMessagesBannerView_Night_2_en",20049,], -["features.messages.impl.pinned.banner_PinnedMessagesBannerView_Day_3_en","features.messages.impl.pinned.banner_PinnedMessagesBannerView_Night_3_en",20049,], -["features.messages.impl.pinned.banner_PinnedMessagesBannerView_Day_4_en","features.messages.impl.pinned.banner_PinnedMessagesBannerView_Night_4_en",20049,], -["features.messages.impl.pinned.banner_PinnedMessagesBannerView_Day_5_en","features.messages.impl.pinned.banner_PinnedMessagesBannerView_Night_5_en",20049,], -["features.messages.impl.pinned.banner_PinnedMessagesBannerView_Day_6_en","features.messages.impl.pinned.banner_PinnedMessagesBannerView_Night_6_en",20049,], -["features.messages.impl.pinned.banner_PinnedMessagesBannerView_Day_7_en","features.messages.impl.pinned.banner_PinnedMessagesBannerView_Night_7_en",20049,], -["features.messages.impl.pinned.banner_PinnedMessagesBannerView_Day_8_en","features.messages.impl.pinned.banner_PinnedMessagesBannerView_Night_8_en",20049,], -["features.messages.impl.pinned.banner_PinnedMessagesBannerView_Day_9_en","features.messages.impl.pinned.banner_PinnedMessagesBannerView_Night_9_en",20049,], -["features.messages.impl.pinned.list_PinnedMessagesListView_Day_0_en","features.messages.impl.pinned.list_PinnedMessagesListView_Night_0_en",20049,], -["features.messages.impl.pinned.list_PinnedMessagesListView_Day_1_en","features.messages.impl.pinned.list_PinnedMessagesListView_Night_1_en",20049,], -["features.messages.impl.pinned.list_PinnedMessagesListView_Day_2_en","features.messages.impl.pinned.list_PinnedMessagesListView_Night_2_en",20049,], -["features.messages.impl.pinned.list_PinnedMessagesListView_Day_3_en","features.messages.impl.pinned.list_PinnedMessagesListView_Night_3_en",20049,], +["features.messages.impl.pinned.banner_PinnedMessagesBannerView_Day_10_en","features.messages.impl.pinned.banner_PinnedMessagesBannerView_Night_10_en",20056,], +["features.messages.impl.pinned.banner_PinnedMessagesBannerView_Day_1_en","features.messages.impl.pinned.banner_PinnedMessagesBannerView_Night_1_en",20056,], +["features.messages.impl.pinned.banner_PinnedMessagesBannerView_Day_2_en","features.messages.impl.pinned.banner_PinnedMessagesBannerView_Night_2_en",20056,], +["features.messages.impl.pinned.banner_PinnedMessagesBannerView_Day_3_en","features.messages.impl.pinned.banner_PinnedMessagesBannerView_Night_3_en",20056,], +["features.messages.impl.pinned.banner_PinnedMessagesBannerView_Day_4_en","features.messages.impl.pinned.banner_PinnedMessagesBannerView_Night_4_en",20056,], +["features.messages.impl.pinned.banner_PinnedMessagesBannerView_Day_5_en","features.messages.impl.pinned.banner_PinnedMessagesBannerView_Night_5_en",20056,], +["features.messages.impl.pinned.banner_PinnedMessagesBannerView_Day_6_en","features.messages.impl.pinned.banner_PinnedMessagesBannerView_Night_6_en",20056,], +["features.messages.impl.pinned.banner_PinnedMessagesBannerView_Day_7_en","features.messages.impl.pinned.banner_PinnedMessagesBannerView_Night_7_en",20056,], +["features.messages.impl.pinned.banner_PinnedMessagesBannerView_Day_8_en","features.messages.impl.pinned.banner_PinnedMessagesBannerView_Night_8_en",20056,], +["features.messages.impl.pinned.banner_PinnedMessagesBannerView_Day_9_en","features.messages.impl.pinned.banner_PinnedMessagesBannerView_Night_9_en",20056,], +["features.messages.impl.pinned.list_PinnedMessagesListView_Day_0_en","features.messages.impl.pinned.list_PinnedMessagesListView_Night_0_en",20056,], +["features.messages.impl.pinned.list_PinnedMessagesListView_Day_1_en","features.messages.impl.pinned.list_PinnedMessagesListView_Night_1_en",20056,], +["features.messages.impl.pinned.list_PinnedMessagesListView_Day_2_en","features.messages.impl.pinned.list_PinnedMessagesListView_Night_2_en",20056,], +["features.messages.impl.pinned.list_PinnedMessagesListView_Day_3_en","features.messages.impl.pinned.list_PinnedMessagesListView_Night_3_en",20056,], ["libraries.designsystem.atomic.atoms_PlaceholderAtom_Day_0_en","libraries.designsystem.atomic.atoms_PlaceholderAtom_Night_0_en",0,], -["features.poll.api.pollcontent_PollAnswerViewDisclosedNotSelected_Day_0_en","features.poll.api.pollcontent_PollAnswerViewDisclosedNotSelected_Night_0_en",20049,], -["features.poll.api.pollcontent_PollAnswerViewDisclosedSelected_Day_0_en","features.poll.api.pollcontent_PollAnswerViewDisclosedSelected_Night_0_en",20049,], -["features.poll.api.pollcontent_PollAnswerViewEndedSelected_Day_0_en","features.poll.api.pollcontent_PollAnswerViewEndedSelected_Night_0_en",20049,], -["features.poll.api.pollcontent_PollAnswerViewEndedWinnerNotSelected_Day_0_en","features.poll.api.pollcontent_PollAnswerViewEndedWinnerNotSelected_Night_0_en",20049,], -["features.poll.api.pollcontent_PollAnswerViewEndedWinnerSelected_Day_0_en","features.poll.api.pollcontent_PollAnswerViewEndedWinnerSelected_Night_0_en",20049,], +["features.poll.api.pollcontent_PollAnswerViewDisclosedNotSelected_Day_0_en","features.poll.api.pollcontent_PollAnswerViewDisclosedNotSelected_Night_0_en",20056,], +["features.poll.api.pollcontent_PollAnswerViewDisclosedSelected_Day_0_en","features.poll.api.pollcontent_PollAnswerViewDisclosedSelected_Night_0_en",20056,], +["features.poll.api.pollcontent_PollAnswerViewEndedSelected_Day_0_en","features.poll.api.pollcontent_PollAnswerViewEndedSelected_Night_0_en",20056,], +["features.poll.api.pollcontent_PollAnswerViewEndedWinnerNotSelected_Day_0_en","features.poll.api.pollcontent_PollAnswerViewEndedWinnerNotSelected_Night_0_en",20056,], +["features.poll.api.pollcontent_PollAnswerViewEndedWinnerSelected_Day_0_en","features.poll.api.pollcontent_PollAnswerViewEndedWinnerSelected_Night_0_en",20056,], ["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",20049,], -["features.poll.api.pollcontent_PollContentViewCreatorEnded_Day_0_en","features.poll.api.pollcontent_PollContentViewCreatorEnded_Night_0_en",20049,], -["features.poll.api.pollcontent_PollContentViewCreator_Day_0_en","features.poll.api.pollcontent_PollContentViewCreator_Night_0_en",20049,], -["features.poll.api.pollcontent_PollContentViewDisclosed_Day_0_en","features.poll.api.pollcontent_PollContentViewDisclosed_Night_0_en",20049,], -["features.poll.api.pollcontent_PollContentViewEnded_Day_0_en","features.poll.api.pollcontent_PollContentViewEnded_Night_0_en",20049,], -["features.poll.api.pollcontent_PollContentViewUndisclosed_Day_0_en","features.poll.api.pollcontent_PollContentViewUndisclosed_Night_0_en",20049,], -["features.poll.impl.history_PollHistoryView_Day_0_en","features.poll.impl.history_PollHistoryView_Night_0_en",20049,], -["features.poll.impl.history_PollHistoryView_Day_1_en","features.poll.impl.history_PollHistoryView_Night_1_en",20049,], -["features.poll.impl.history_PollHistoryView_Day_2_en","features.poll.impl.history_PollHistoryView_Night_2_en",20049,], -["features.poll.impl.history_PollHistoryView_Day_3_en","features.poll.impl.history_PollHistoryView_Night_3_en",20049,], -["features.poll.impl.history_PollHistoryView_Day_4_en","features.poll.impl.history_PollHistoryView_Night_4_en",20049,], +["features.poll.api.pollcontent_PollContentViewCreatorEditable_Day_0_en","features.poll.api.pollcontent_PollContentViewCreatorEditable_Night_0_en",20056,], +["features.poll.api.pollcontent_PollContentViewCreatorEnded_Day_0_en","features.poll.api.pollcontent_PollContentViewCreatorEnded_Night_0_en",20056,], +["features.poll.api.pollcontent_PollContentViewCreator_Day_0_en","features.poll.api.pollcontent_PollContentViewCreator_Night_0_en",20056,], +["features.poll.api.pollcontent_PollContentViewDisclosed_Day_0_en","features.poll.api.pollcontent_PollContentViewDisclosed_Night_0_en",20056,], +["features.poll.api.pollcontent_PollContentViewEnded_Day_0_en","features.poll.api.pollcontent_PollContentViewEnded_Night_0_en",20056,], +["features.poll.api.pollcontent_PollContentViewUndisclosed_Day_0_en","features.poll.api.pollcontent_PollContentViewUndisclosed_Night_0_en",20056,], +["features.poll.impl.history_PollHistoryView_Day_0_en","features.poll.impl.history_PollHistoryView_Night_0_en",20056,], +["features.poll.impl.history_PollHistoryView_Day_1_en","features.poll.impl.history_PollHistoryView_Night_1_en",20056,], +["features.poll.impl.history_PollHistoryView_Day_2_en","features.poll.impl.history_PollHistoryView_Night_2_en",20056,], +["features.poll.impl.history_PollHistoryView_Day_3_en","features.poll.impl.history_PollHistoryView_Night_3_en",20056,], +["features.poll.impl.history_PollHistoryView_Day_4_en","features.poll.impl.history_PollHistoryView_Night_4_en",20056,], ["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,], @@ -660,197 +665,197 @@ export const screenshots = [ ["libraries.designsystem.components.preferences_PreferenceTextLight_Preferences_en","",0,], ["libraries.designsystem.components.preferences_PreferenceTextWithEndBadgeDark_Preferences_en","",0,], ["libraries.designsystem.components.preferences_PreferenceTextWithEndBadgeLight_Preferences_en","",0,], -["features.preferences.impl.root_PreferencesRootViewDark_0_en","",20049,], -["features.preferences.impl.root_PreferencesRootViewDark_1_en","",20049,], -["features.preferences.impl.root_PreferencesRootViewLight_0_en","",20049,], -["features.preferences.impl.root_PreferencesRootViewLight_1_en","",20049,], +["features.preferences.impl.root_PreferencesRootViewDark_0_en","",20056,], +["features.preferences.impl.root_PreferencesRootViewDark_1_en","",20056,], +["features.preferences.impl.root_PreferencesRootViewLight_0_en","",20056,], +["features.preferences.impl.root_PreferencesRootViewLight_1_en","",20056,], ["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","",20049,], -["libraries.designsystem.components_ProgressDialog_Day_0_en","libraries.designsystem.components_ProgressDialog_Night_0_en",20049,], -["features.messages.impl.timeline.protection_ProtectedView_Day_0_en","features.messages.impl.timeline.protection_ProtectedView_Night_0_en",0,], -["features.messages.impl.timeline.protection_ProtectedView_Day_1_en","features.messages.impl.timeline.protection_ProtectedView_Night_1_en",0,], -["features.messages.impl.timeline.protection_ProtectedView_Day_2_en","features.messages.impl.timeline.protection_ProtectedView_Night_2_en",0,], -["features.messages.impl.timeline.protection_ProtectedView_Day_3_en","features.messages.impl.timeline.protection_ProtectedView_Night_3_en",0,], -["features.login.impl.screens.qrcode.confirmation_QrCodeConfirmationView_Day_0_en","features.login.impl.screens.qrcode.confirmation_QrCodeConfirmationView_Night_0_en",20049,], -["features.login.impl.screens.qrcode.confirmation_QrCodeConfirmationView_Day_1_en","features.login.impl.screens.qrcode.confirmation_QrCodeConfirmationView_Night_1_en",20049,], -["features.login.impl.screens.qrcode.confirmation_QrCodeConfirmationView_Day_2_en","features.login.impl.screens.qrcode.confirmation_QrCodeConfirmationView_Night_2_en",20049,], -["features.login.impl.screens.qrcode.error_QrCodeErrorView_Day_0_en","features.login.impl.screens.qrcode.error_QrCodeErrorView_Night_0_en",20049,], -["features.login.impl.screens.qrcode.error_QrCodeErrorView_Day_1_en","features.login.impl.screens.qrcode.error_QrCodeErrorView_Night_1_en",20049,], -["features.login.impl.screens.qrcode.error_QrCodeErrorView_Day_2_en","features.login.impl.screens.qrcode.error_QrCodeErrorView_Night_2_en",20049,], -["features.login.impl.screens.qrcode.error_QrCodeErrorView_Day_3_en","features.login.impl.screens.qrcode.error_QrCodeErrorView_Night_3_en",20049,], -["features.login.impl.screens.qrcode.error_QrCodeErrorView_Day_4_en","features.login.impl.screens.qrcode.error_QrCodeErrorView_Night_4_en",20049,], -["features.login.impl.screens.qrcode.error_QrCodeErrorView_Day_5_en","features.login.impl.screens.qrcode.error_QrCodeErrorView_Night_5_en",20049,], -["features.login.impl.screens.qrcode.error_QrCodeErrorView_Day_6_en","features.login.impl.screens.qrcode.error_QrCodeErrorView_Night_6_en",20049,], -["features.login.impl.screens.qrcode.intro_QrCodeIntroView_Day_0_en","features.login.impl.screens.qrcode.intro_QrCodeIntroView_Night_0_en",20049,], -["features.login.impl.screens.qrcode.intro_QrCodeIntroView_Day_1_en","features.login.impl.screens.qrcode.intro_QrCodeIntroView_Night_1_en",20049,], -["features.login.impl.screens.qrcode.scan_QrCodeScanView_Day_0_en","features.login.impl.screens.qrcode.scan_QrCodeScanView_Night_0_en",20049,], -["features.login.impl.screens.qrcode.scan_QrCodeScanView_Day_1_en","features.login.impl.screens.qrcode.scan_QrCodeScanView_Night_1_en",20049,], -["features.login.impl.screens.qrcode.scan_QrCodeScanView_Day_2_en","features.login.impl.screens.qrcode.scan_QrCodeScanView_Night_2_en",20049,], -["features.login.impl.screens.qrcode.scan_QrCodeScanView_Day_3_en","features.login.impl.screens.qrcode.scan_QrCodeScanView_Night_3_en",20049,], +["libraries.designsystem.components_ProgressDialogContent_Dialogs_en","",20056,], +["libraries.designsystem.components_ProgressDialog_Day_0_en","libraries.designsystem.components_ProgressDialog_Night_0_en",20056,], +["features.messages.impl.timeline.protection_ProtectedView_Day_0_en","features.messages.impl.timeline.protection_ProtectedView_Night_0_en",20059,], +["features.messages.impl.timeline.protection_ProtectedView_Day_1_en","features.messages.impl.timeline.protection_ProtectedView_Night_1_en",20059,], +["features.messages.impl.timeline.protection_ProtectedView_Day_2_en","features.messages.impl.timeline.protection_ProtectedView_Night_2_en",20059,], +["features.messages.impl.timeline.protection_ProtectedView_Day_3_en","features.messages.impl.timeline.protection_ProtectedView_Night_3_en",20059,], +["features.login.impl.screens.qrcode.confirmation_QrCodeConfirmationView_Day_0_en","features.login.impl.screens.qrcode.confirmation_QrCodeConfirmationView_Night_0_en",20056,], +["features.login.impl.screens.qrcode.confirmation_QrCodeConfirmationView_Day_1_en","features.login.impl.screens.qrcode.confirmation_QrCodeConfirmationView_Night_1_en",20056,], +["features.login.impl.screens.qrcode.confirmation_QrCodeConfirmationView_Day_2_en","features.login.impl.screens.qrcode.confirmation_QrCodeConfirmationView_Night_2_en",20056,], +["features.login.impl.screens.qrcode.error_QrCodeErrorView_Day_0_en","features.login.impl.screens.qrcode.error_QrCodeErrorView_Night_0_en",20056,], +["features.login.impl.screens.qrcode.error_QrCodeErrorView_Day_1_en","features.login.impl.screens.qrcode.error_QrCodeErrorView_Night_1_en",20056,], +["features.login.impl.screens.qrcode.error_QrCodeErrorView_Day_2_en","features.login.impl.screens.qrcode.error_QrCodeErrorView_Night_2_en",20056,], +["features.login.impl.screens.qrcode.error_QrCodeErrorView_Day_3_en","features.login.impl.screens.qrcode.error_QrCodeErrorView_Night_3_en",20056,], +["features.login.impl.screens.qrcode.error_QrCodeErrorView_Day_4_en","features.login.impl.screens.qrcode.error_QrCodeErrorView_Night_4_en",20056,], +["features.login.impl.screens.qrcode.error_QrCodeErrorView_Day_5_en","features.login.impl.screens.qrcode.error_QrCodeErrorView_Night_5_en",20056,], +["features.login.impl.screens.qrcode.error_QrCodeErrorView_Day_6_en","features.login.impl.screens.qrcode.error_QrCodeErrorView_Night_6_en",20056,], +["features.login.impl.screens.qrcode.intro_QrCodeIntroView_Day_0_en","features.login.impl.screens.qrcode.intro_QrCodeIntroView_Night_0_en",20056,], +["features.login.impl.screens.qrcode.intro_QrCodeIntroView_Day_1_en","features.login.impl.screens.qrcode.intro_QrCodeIntroView_Night_1_en",20056,], +["features.login.impl.screens.qrcode.scan_QrCodeScanView_Day_0_en","features.login.impl.screens.qrcode.scan_QrCodeScanView_Night_0_en",20056,], +["features.login.impl.screens.qrcode.scan_QrCodeScanView_Day_1_en","features.login.impl.screens.qrcode.scan_QrCodeScanView_Night_1_en",20056,], +["features.login.impl.screens.qrcode.scan_QrCodeScanView_Day_2_en","features.login.impl.screens.qrcode.scan_QrCodeScanView_Night_2_en",20056,], +["features.login.impl.screens.qrcode.scan_QrCodeScanView_Day_3_en","features.login.impl.screens.qrcode.scan_QrCodeScanView_Night_3_en",20056,], ["libraries.designsystem.theme.components_RadioButton_Toggles_en","",0,], -["features.rageshake.api.detection_RageshakeDialogContent_Day_0_en","features.rageshake.api.detection_RageshakeDialogContent_Night_0_en",20049,], -["features.rageshake.api.preferences_RageshakePreferencesView_Day_0_en","features.rageshake.api.preferences_RageshakePreferencesView_Night_0_en",20049,], +["features.rageshake.api.detection_RageshakeDialogContent_Day_0_en","features.rageshake.api.detection_RageshakeDialogContent_Night_0_en",20056,], +["features.rageshake.api.preferences_RageshakePreferencesView_Day_0_en","features.rageshake.api.preferences_RageshakePreferencesView_Night_0_en",20056,], ["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",20049,], -["features.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_Day_1_en","features.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_Night_1_en",20049,], -["features.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_Day_2_en","features.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_Night_2_en",20049,], -["features.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_Day_3_en","features.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_Night_3_en",20049,], -["features.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_Day_4_en","features.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_Night_4_en",20049,], -["features.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_Day_5_en","features.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_Night_5_en",20049,], -["features.securebackup.impl.setup.views_RecoveryKeyView_Day_0_en","features.securebackup.impl.setup.views_RecoveryKeyView_Night_0_en",20049,], -["features.securebackup.impl.setup.views_RecoveryKeyView_Day_10_en","features.securebackup.impl.setup.views_RecoveryKeyView_Night_10_en",20049,], -["features.securebackup.impl.setup.views_RecoveryKeyView_Day_11_en","features.securebackup.impl.setup.views_RecoveryKeyView_Night_11_en",20049,], -["features.securebackup.impl.setup.views_RecoveryKeyView_Day_12_en","features.securebackup.impl.setup.views_RecoveryKeyView_Night_12_en",20049,], -["features.securebackup.impl.setup.views_RecoveryKeyView_Day_13_en","features.securebackup.impl.setup.views_RecoveryKeyView_Night_13_en",20049,], -["features.securebackup.impl.setup.views_RecoveryKeyView_Day_1_en","features.securebackup.impl.setup.views_RecoveryKeyView_Night_1_en",20049,], -["features.securebackup.impl.setup.views_RecoveryKeyView_Day_2_en","features.securebackup.impl.setup.views_RecoveryKeyView_Night_2_en",20049,], -["features.securebackup.impl.setup.views_RecoveryKeyView_Day_3_en","features.securebackup.impl.setup.views_RecoveryKeyView_Night_3_en",20049,], -["features.securebackup.impl.setup.views_RecoveryKeyView_Day_4_en","features.securebackup.impl.setup.views_RecoveryKeyView_Night_4_en",20049,], -["features.securebackup.impl.setup.views_RecoveryKeyView_Day_5_en","features.securebackup.impl.setup.views_RecoveryKeyView_Night_5_en",20049,], -["features.securebackup.impl.setup.views_RecoveryKeyView_Day_6_en","features.securebackup.impl.setup.views_RecoveryKeyView_Night_6_en",20049,], -["features.securebackup.impl.setup.views_RecoveryKeyView_Day_7_en","features.securebackup.impl.setup.views_RecoveryKeyView_Night_7_en",20049,], -["features.securebackup.impl.setup.views_RecoveryKeyView_Day_8_en","features.securebackup.impl.setup.views_RecoveryKeyView_Night_8_en",20049,], -["features.securebackup.impl.setup.views_RecoveryKeyView_Day_9_en","features.securebackup.impl.setup.views_RecoveryKeyView_Night_9_en",20049,], +["features.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_Day_0_en","features.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_Night_0_en",20056,], +["features.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_Day_1_en","features.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_Night_1_en",20056,], +["features.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_Day_2_en","features.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_Night_2_en",20056,], +["features.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_Day_3_en","features.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_Night_3_en",20056,], +["features.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_Day_4_en","features.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_Night_4_en",20056,], +["features.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_Day_5_en","features.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_Night_5_en",20056,], +["features.securebackup.impl.setup.views_RecoveryKeyView_Day_0_en","features.securebackup.impl.setup.views_RecoveryKeyView_Night_0_en",20056,], +["features.securebackup.impl.setup.views_RecoveryKeyView_Day_10_en","features.securebackup.impl.setup.views_RecoveryKeyView_Night_10_en",20056,], +["features.securebackup.impl.setup.views_RecoveryKeyView_Day_11_en","features.securebackup.impl.setup.views_RecoveryKeyView_Night_11_en",20056,], +["features.securebackup.impl.setup.views_RecoveryKeyView_Day_12_en","features.securebackup.impl.setup.views_RecoveryKeyView_Night_12_en",20056,], +["features.securebackup.impl.setup.views_RecoveryKeyView_Day_13_en","features.securebackup.impl.setup.views_RecoveryKeyView_Night_13_en",20056,], +["features.securebackup.impl.setup.views_RecoveryKeyView_Day_1_en","features.securebackup.impl.setup.views_RecoveryKeyView_Night_1_en",20056,], +["features.securebackup.impl.setup.views_RecoveryKeyView_Day_2_en","features.securebackup.impl.setup.views_RecoveryKeyView_Night_2_en",20056,], +["features.securebackup.impl.setup.views_RecoveryKeyView_Day_3_en","features.securebackup.impl.setup.views_RecoveryKeyView_Night_3_en",20056,], +["features.securebackup.impl.setup.views_RecoveryKeyView_Day_4_en","features.securebackup.impl.setup.views_RecoveryKeyView_Night_4_en",20056,], +["features.securebackup.impl.setup.views_RecoveryKeyView_Day_5_en","features.securebackup.impl.setup.views_RecoveryKeyView_Night_5_en",20056,], +["features.securebackup.impl.setup.views_RecoveryKeyView_Day_6_en","features.securebackup.impl.setup.views_RecoveryKeyView_Night_6_en",20056,], +["features.securebackup.impl.setup.views_RecoveryKeyView_Day_7_en","features.securebackup.impl.setup.views_RecoveryKeyView_Night_7_en",20056,], +["features.securebackup.impl.setup.views_RecoveryKeyView_Day_8_en","features.securebackup.impl.setup.views_RecoveryKeyView_Night_8_en",20056,], +["features.securebackup.impl.setup.views_RecoveryKeyView_Day_9_en","features.securebackup.impl.setup.views_RecoveryKeyView_Night_9_en",20056,], ["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",20049,], -["features.messages.impl.report_ReportMessageView_Day_1_en","features.messages.impl.report_ReportMessageView_Night_1_en",20049,], -["features.messages.impl.report_ReportMessageView_Day_2_en","features.messages.impl.report_ReportMessageView_Night_2_en",20049,], -["features.messages.impl.report_ReportMessageView_Day_3_en","features.messages.impl.report_ReportMessageView_Night_3_en",20049,], -["features.messages.impl.report_ReportMessageView_Day_4_en","features.messages.impl.report_ReportMessageView_Night_4_en",20049,], -["features.messages.impl.report_ReportMessageView_Day_5_en","features.messages.impl.report_ReportMessageView_Night_5_en",20049,], -["features.securebackup.impl.reset.password_ResetIdentityPasswordView_Day_0_en","features.securebackup.impl.reset.password_ResetIdentityPasswordView_Night_0_en",20049,], -["features.securebackup.impl.reset.password_ResetIdentityPasswordView_Day_1_en","features.securebackup.impl.reset.password_ResetIdentityPasswordView_Night_1_en",20049,], -["features.securebackup.impl.reset.password_ResetIdentityPasswordView_Day_2_en","features.securebackup.impl.reset.password_ResetIdentityPasswordView_Night_2_en",20049,], -["features.securebackup.impl.reset.password_ResetIdentityPasswordView_Day_3_en","features.securebackup.impl.reset.password_ResetIdentityPasswordView_Night_3_en",20049,], -["features.securebackup.impl.reset.root_ResetIdentityRootView_Day_0_en","features.securebackup.impl.reset.root_ResetIdentityRootView_Night_0_en",20049,], -["features.securebackup.impl.reset.root_ResetIdentityRootView_Day_1_en","features.securebackup.impl.reset.root_ResetIdentityRootView_Night_1_en",20049,], +["features.messages.impl.report_ReportMessageView_Day_0_en","features.messages.impl.report_ReportMessageView_Night_0_en",20056,], +["features.messages.impl.report_ReportMessageView_Day_1_en","features.messages.impl.report_ReportMessageView_Night_1_en",20056,], +["features.messages.impl.report_ReportMessageView_Day_2_en","features.messages.impl.report_ReportMessageView_Night_2_en",20056,], +["features.messages.impl.report_ReportMessageView_Day_3_en","features.messages.impl.report_ReportMessageView_Night_3_en",20056,], +["features.messages.impl.report_ReportMessageView_Day_4_en","features.messages.impl.report_ReportMessageView_Night_4_en",20056,], +["features.messages.impl.report_ReportMessageView_Day_5_en","features.messages.impl.report_ReportMessageView_Night_5_en",20056,], +["features.securebackup.impl.reset.password_ResetIdentityPasswordView_Day_0_en","features.securebackup.impl.reset.password_ResetIdentityPasswordView_Night_0_en",20056,], +["features.securebackup.impl.reset.password_ResetIdentityPasswordView_Day_1_en","features.securebackup.impl.reset.password_ResetIdentityPasswordView_Night_1_en",20056,], +["features.securebackup.impl.reset.password_ResetIdentityPasswordView_Day_2_en","features.securebackup.impl.reset.password_ResetIdentityPasswordView_Night_2_en",20056,], +["features.securebackup.impl.reset.password_ResetIdentityPasswordView_Day_3_en","features.securebackup.impl.reset.password_ResetIdentityPasswordView_Night_3_en",20056,], +["features.securebackup.impl.reset.root_ResetIdentityRootView_Day_0_en","features.securebackup.impl.reset.root_ResetIdentityRootView_Night_0_en",20056,], +["features.securebackup.impl.reset.root_ResetIdentityRootView_Day_1_en","features.securebackup.impl.reset.root_ResetIdentityRootView_Night_1_en",20056,], ["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",20049,], -["features.messages.impl.crypto.sendfailure.resolve_ResolveVerifiedUserSendFailureView_Day_2_en","features.messages.impl.crypto.sendfailure.resolve_ResolveVerifiedUserSendFailureView_Night_2_en",20049,], -["libraries.designsystem.components.dialogs_RetryDialogContent_Dialogs_en","",20049,], -["libraries.designsystem.components.dialogs_RetryDialog_Day_0_en","libraries.designsystem.components.dialogs_RetryDialog_Night_0_en",20049,], -["features.roomdetails.impl.rolesandpermissions_RolesAndPermissionsView_Day_0_en","features.roomdetails.impl.rolesandpermissions_RolesAndPermissionsView_Night_0_en",20049,], -["features.roomdetails.impl.rolesandpermissions_RolesAndPermissionsView_Day_1_en","features.roomdetails.impl.rolesandpermissions_RolesAndPermissionsView_Night_1_en",20049,], -["features.roomdetails.impl.rolesandpermissions_RolesAndPermissionsView_Day_2_en","features.roomdetails.impl.rolesandpermissions_RolesAndPermissionsView_Night_2_en",20049,], -["features.roomdetails.impl.rolesandpermissions_RolesAndPermissionsView_Day_3_en","features.roomdetails.impl.rolesandpermissions_RolesAndPermissionsView_Night_3_en",20049,], -["features.roomdetails.impl.rolesandpermissions_RolesAndPermissionsView_Day_4_en","features.roomdetails.impl.rolesandpermissions_RolesAndPermissionsView_Night_4_en",20049,], -["features.roomdetails.impl.rolesandpermissions_RolesAndPermissionsView_Day_5_en","features.roomdetails.impl.rolesandpermissions_RolesAndPermissionsView_Night_5_en",20049,], -["features.roomdetails.impl.rolesandpermissions_RolesAndPermissionsView_Day_6_en","features.roomdetails.impl.rolesandpermissions_RolesAndPermissionsView_Night_6_en",20049,], -["features.roomdetails.impl.rolesandpermissions_RolesAndPermissionsView_Day_7_en","features.roomdetails.impl.rolesandpermissions_RolesAndPermissionsView_Night_7_en",20049,], +["features.messages.impl.crypto.sendfailure.resolve_ResolveVerifiedUserSendFailureView_Day_1_en","features.messages.impl.crypto.sendfailure.resolve_ResolveVerifiedUserSendFailureView_Night_1_en",20056,], +["features.messages.impl.crypto.sendfailure.resolve_ResolveVerifiedUserSendFailureView_Day_2_en","features.messages.impl.crypto.sendfailure.resolve_ResolveVerifiedUserSendFailureView_Night_2_en",20056,], +["libraries.designsystem.components.dialogs_RetryDialogContent_Dialogs_en","",20056,], +["libraries.designsystem.components.dialogs_RetryDialog_Day_0_en","libraries.designsystem.components.dialogs_RetryDialog_Night_0_en",20056,], +["features.roomdetails.impl.rolesandpermissions_RolesAndPermissionsView_Day_0_en","features.roomdetails.impl.rolesandpermissions_RolesAndPermissionsView_Night_0_en",20056,], +["features.roomdetails.impl.rolesandpermissions_RolesAndPermissionsView_Day_1_en","features.roomdetails.impl.rolesandpermissions_RolesAndPermissionsView_Night_1_en",20056,], +["features.roomdetails.impl.rolesandpermissions_RolesAndPermissionsView_Day_2_en","features.roomdetails.impl.rolesandpermissions_RolesAndPermissionsView_Night_2_en",20056,], +["features.roomdetails.impl.rolesandpermissions_RolesAndPermissionsView_Day_3_en","features.roomdetails.impl.rolesandpermissions_RolesAndPermissionsView_Night_3_en",20056,], +["features.roomdetails.impl.rolesandpermissions_RolesAndPermissionsView_Day_4_en","features.roomdetails.impl.rolesandpermissions_RolesAndPermissionsView_Night_4_en",20056,], +["features.roomdetails.impl.rolesandpermissions_RolesAndPermissionsView_Day_5_en","features.roomdetails.impl.rolesandpermissions_RolesAndPermissionsView_Night_5_en",20056,], +["features.roomdetails.impl.rolesandpermissions_RolesAndPermissionsView_Day_6_en","features.roomdetails.impl.rolesandpermissions_RolesAndPermissionsView_Night_6_en",20056,], +["features.roomdetails.impl.rolesandpermissions_RolesAndPermissionsView_Day_7_en","features.roomdetails.impl.rolesandpermissions_RolesAndPermissionsView_Night_7_en",20056,], ["features.roomaliasresolver.impl_RoomAliasResolverView_Day_0_en","features.roomaliasresolver.impl_RoomAliasResolverView_Night_0_en",0,], ["features.roomaliasresolver.impl_RoomAliasResolverView_Day_1_en","features.roomaliasresolver.impl_RoomAliasResolverView_Night_1_en",0,], -["features.roomaliasresolver.impl_RoomAliasResolverView_Day_2_en","features.roomaliasresolver.impl_RoomAliasResolverView_Night_2_en",20049,], -["features.roomdetails.impl_RoomDetailsDark_0_en","",20049,], -["features.roomdetails.impl_RoomDetailsDark_10_en","",20049,], -["features.roomdetails.impl_RoomDetailsDark_11_en","",20049,], -["features.roomdetails.impl_RoomDetailsDark_12_en","",20049,], -["features.roomdetails.impl_RoomDetailsDark_13_en","",20049,], -["features.roomdetails.impl_RoomDetailsDark_1_en","",20049,], -["features.roomdetails.impl_RoomDetailsDark_2_en","",20049,], -["features.roomdetails.impl_RoomDetailsDark_3_en","",20049,], -["features.roomdetails.impl_RoomDetailsDark_4_en","",20049,], -["features.roomdetails.impl_RoomDetailsDark_5_en","",20049,], -["features.roomdetails.impl_RoomDetailsDark_6_en","",20049,], -["features.roomdetails.impl_RoomDetailsDark_7_en","",20049,], -["features.roomdetails.impl_RoomDetailsDark_8_en","",20049,], -["features.roomdetails.impl_RoomDetailsDark_9_en","",20049,], -["features.roomdetails.impl.edit_RoomDetailsEditView_Day_0_en","features.roomdetails.impl.edit_RoomDetailsEditView_Night_0_en",20049,], -["features.roomdetails.impl.edit_RoomDetailsEditView_Day_1_en","features.roomdetails.impl.edit_RoomDetailsEditView_Night_1_en",20049,], -["features.roomdetails.impl.edit_RoomDetailsEditView_Day_2_en","features.roomdetails.impl.edit_RoomDetailsEditView_Night_2_en",20049,], -["features.roomdetails.impl.edit_RoomDetailsEditView_Day_3_en","features.roomdetails.impl.edit_RoomDetailsEditView_Night_3_en",20049,], -["features.roomdetails.impl.edit_RoomDetailsEditView_Day_4_en","features.roomdetails.impl.edit_RoomDetailsEditView_Night_4_en",20049,], -["features.roomdetails.impl.edit_RoomDetailsEditView_Day_5_en","features.roomdetails.impl.edit_RoomDetailsEditView_Night_5_en",20049,], -["features.roomdetails.impl.edit_RoomDetailsEditView_Day_6_en","features.roomdetails.impl.edit_RoomDetailsEditView_Night_6_en",20049,], -["features.roomdetails.impl.edit_RoomDetailsEditView_Day_7_en","features.roomdetails.impl.edit_RoomDetailsEditView_Night_7_en",20049,], -["features.roomdetails.impl_RoomDetails_0_en","",20049,], -["features.roomdetails.impl_RoomDetails_10_en","",20049,], -["features.roomdetails.impl_RoomDetails_11_en","",20049,], -["features.roomdetails.impl_RoomDetails_12_en","",20049,], -["features.roomdetails.impl_RoomDetails_13_en","",20049,], -["features.roomdetails.impl_RoomDetails_1_en","",20049,], -["features.roomdetails.impl_RoomDetails_2_en","",20049,], -["features.roomdetails.impl_RoomDetails_3_en","",20049,], -["features.roomdetails.impl_RoomDetails_4_en","",20049,], -["features.roomdetails.impl_RoomDetails_5_en","",20049,], -["features.roomdetails.impl_RoomDetails_6_en","",20049,], -["features.roomdetails.impl_RoomDetails_7_en","",20049,], -["features.roomdetails.impl_RoomDetails_8_en","",20049,], -["features.roomdetails.impl_RoomDetails_9_en","",20049,], -["features.roomdirectory.impl.root_RoomDirectoryView_Day_0_en","features.roomdirectory.impl.root_RoomDirectoryView_Night_0_en",20049,], -["features.roomdirectory.impl.root_RoomDirectoryView_Day_1_en","features.roomdirectory.impl.root_RoomDirectoryView_Night_1_en",20049,], -["features.roomdirectory.impl.root_RoomDirectoryView_Day_2_en","features.roomdirectory.impl.root_RoomDirectoryView_Night_2_en",20049,], -["features.roomdetails.impl.invite_RoomInviteMembersView_Day_0_en","features.roomdetails.impl.invite_RoomInviteMembersView_Night_0_en",20049,], -["features.roomdetails.impl.invite_RoomInviteMembersView_Day_1_en","features.roomdetails.impl.invite_RoomInviteMembersView_Night_1_en",20049,], -["features.roomdetails.impl.invite_RoomInviteMembersView_Day_2_en","features.roomdetails.impl.invite_RoomInviteMembersView_Night_2_en",20049,], -["features.roomdetails.impl.invite_RoomInviteMembersView_Day_3_en","features.roomdetails.impl.invite_RoomInviteMembersView_Night_3_en",20049,], -["features.roomdetails.impl.invite_RoomInviteMembersView_Day_4_en","features.roomdetails.impl.invite_RoomInviteMembersView_Night_4_en",20049,], -["features.roomdetails.impl.invite_RoomInviteMembersView_Day_5_en","features.roomdetails.impl.invite_RoomInviteMembersView_Night_5_en",20049,], -["features.roomdetails.impl.invite_RoomInviteMembersView_Day_6_en","features.roomdetails.impl.invite_RoomInviteMembersView_Night_6_en",20049,], -["features.roomdetails.impl.invite_RoomInviteMembersView_Day_7_en","features.roomdetails.impl.invite_RoomInviteMembersView_Night_7_en",20049,], -["features.roomlist.impl.components_RoomListContentView_Day_0_en","features.roomlist.impl.components_RoomListContentView_Night_0_en",20049,], -["features.roomlist.impl.components_RoomListContentView_Day_1_en","features.roomlist.impl.components_RoomListContentView_Night_1_en",20049,], +["features.roomaliasresolver.impl_RoomAliasResolverView_Day_2_en","features.roomaliasresolver.impl_RoomAliasResolverView_Night_2_en",20056,], +["features.roomdetails.impl_RoomDetailsDark_0_en","",20056,], +["features.roomdetails.impl_RoomDetailsDark_10_en","",20056,], +["features.roomdetails.impl_RoomDetailsDark_11_en","",20056,], +["features.roomdetails.impl_RoomDetailsDark_12_en","",20056,], +["features.roomdetails.impl_RoomDetailsDark_13_en","",20056,], +["features.roomdetails.impl_RoomDetailsDark_1_en","",20056,], +["features.roomdetails.impl_RoomDetailsDark_2_en","",20056,], +["features.roomdetails.impl_RoomDetailsDark_3_en","",20056,], +["features.roomdetails.impl_RoomDetailsDark_4_en","",20056,], +["features.roomdetails.impl_RoomDetailsDark_5_en","",20056,], +["features.roomdetails.impl_RoomDetailsDark_6_en","",20056,], +["features.roomdetails.impl_RoomDetailsDark_7_en","",20056,], +["features.roomdetails.impl_RoomDetailsDark_8_en","",20056,], +["features.roomdetails.impl_RoomDetailsDark_9_en","",20056,], +["features.roomdetails.impl.edit_RoomDetailsEditView_Day_0_en","features.roomdetails.impl.edit_RoomDetailsEditView_Night_0_en",20056,], +["features.roomdetails.impl.edit_RoomDetailsEditView_Day_1_en","features.roomdetails.impl.edit_RoomDetailsEditView_Night_1_en",20056,], +["features.roomdetails.impl.edit_RoomDetailsEditView_Day_2_en","features.roomdetails.impl.edit_RoomDetailsEditView_Night_2_en",20056,], +["features.roomdetails.impl.edit_RoomDetailsEditView_Day_3_en","features.roomdetails.impl.edit_RoomDetailsEditView_Night_3_en",20056,], +["features.roomdetails.impl.edit_RoomDetailsEditView_Day_4_en","features.roomdetails.impl.edit_RoomDetailsEditView_Night_4_en",20056,], +["features.roomdetails.impl.edit_RoomDetailsEditView_Day_5_en","features.roomdetails.impl.edit_RoomDetailsEditView_Night_5_en",20056,], +["features.roomdetails.impl.edit_RoomDetailsEditView_Day_6_en","features.roomdetails.impl.edit_RoomDetailsEditView_Night_6_en",20056,], +["features.roomdetails.impl.edit_RoomDetailsEditView_Day_7_en","features.roomdetails.impl.edit_RoomDetailsEditView_Night_7_en",20056,], +["features.roomdetails.impl_RoomDetails_0_en","",20056,], +["features.roomdetails.impl_RoomDetails_10_en","",20056,], +["features.roomdetails.impl_RoomDetails_11_en","",20056,], +["features.roomdetails.impl_RoomDetails_12_en","",20056,], +["features.roomdetails.impl_RoomDetails_13_en","",20056,], +["features.roomdetails.impl_RoomDetails_1_en","",20056,], +["features.roomdetails.impl_RoomDetails_2_en","",20056,], +["features.roomdetails.impl_RoomDetails_3_en","",20056,], +["features.roomdetails.impl_RoomDetails_4_en","",20056,], +["features.roomdetails.impl_RoomDetails_5_en","",20056,], +["features.roomdetails.impl_RoomDetails_6_en","",20056,], +["features.roomdetails.impl_RoomDetails_7_en","",20056,], +["features.roomdetails.impl_RoomDetails_8_en","",20056,], +["features.roomdetails.impl_RoomDetails_9_en","",20056,], +["features.roomdirectory.impl.root_RoomDirectoryView_Day_0_en","features.roomdirectory.impl.root_RoomDirectoryView_Night_0_en",20056,], +["features.roomdirectory.impl.root_RoomDirectoryView_Day_1_en","features.roomdirectory.impl.root_RoomDirectoryView_Night_1_en",20056,], +["features.roomdirectory.impl.root_RoomDirectoryView_Day_2_en","features.roomdirectory.impl.root_RoomDirectoryView_Night_2_en",20056,], +["features.roomdetails.impl.invite_RoomInviteMembersView_Day_0_en","features.roomdetails.impl.invite_RoomInviteMembersView_Night_0_en",20056,], +["features.roomdetails.impl.invite_RoomInviteMembersView_Day_1_en","features.roomdetails.impl.invite_RoomInviteMembersView_Night_1_en",20056,], +["features.roomdetails.impl.invite_RoomInviteMembersView_Day_2_en","features.roomdetails.impl.invite_RoomInviteMembersView_Night_2_en",20056,], +["features.roomdetails.impl.invite_RoomInviteMembersView_Day_3_en","features.roomdetails.impl.invite_RoomInviteMembersView_Night_3_en",20056,], +["features.roomdetails.impl.invite_RoomInviteMembersView_Day_4_en","features.roomdetails.impl.invite_RoomInviteMembersView_Night_4_en",20056,], +["features.roomdetails.impl.invite_RoomInviteMembersView_Day_5_en","features.roomdetails.impl.invite_RoomInviteMembersView_Night_5_en",20056,], +["features.roomdetails.impl.invite_RoomInviteMembersView_Day_6_en","features.roomdetails.impl.invite_RoomInviteMembersView_Night_6_en",20056,], +["features.roomdetails.impl.invite_RoomInviteMembersView_Day_7_en","features.roomdetails.impl.invite_RoomInviteMembersView_Night_7_en",20056,], +["features.roomlist.impl.components_RoomListContentView_Day_0_en","features.roomlist.impl.components_RoomListContentView_Night_0_en",20056,], +["features.roomlist.impl.components_RoomListContentView_Day_1_en","features.roomlist.impl.components_RoomListContentView_Night_1_en",20056,], ["features.roomlist.impl.components_RoomListContentView_Day_2_en","features.roomlist.impl.components_RoomListContentView_Night_2_en",0,], -["features.roomlist.impl.components_RoomListContentView_Day_3_en","features.roomlist.impl.components_RoomListContentView_Night_3_en",20049,], -["features.roomlist.impl.components_RoomListContentView_Day_4_en","features.roomlist.impl.components_RoomListContentView_Night_4_en",20049,], -["features.roomlist.impl.components_RoomListContentView_Day_5_en","features.roomlist.impl.components_RoomListContentView_Night_5_en",20052,], -["features.roomlist.impl.filters_RoomListFiltersView_Day_0_en","features.roomlist.impl.filters_RoomListFiltersView_Night_0_en",20049,], -["features.roomlist.impl.filters_RoomListFiltersView_Day_1_en","features.roomlist.impl.filters_RoomListFiltersView_Night_1_en",20049,], -["features.roomlist.impl_RoomListModalBottomSheetContent_Day_0_en","features.roomlist.impl_RoomListModalBottomSheetContent_Night_0_en",20049,], -["features.roomlist.impl_RoomListModalBottomSheetContent_Day_1_en","features.roomlist.impl_RoomListModalBottomSheetContent_Night_1_en",20049,], -["features.roomlist.impl_RoomListModalBottomSheetContent_Day_2_en","features.roomlist.impl_RoomListModalBottomSheetContent_Night_2_en",20049,], +["features.roomlist.impl.components_RoomListContentView_Day_3_en","features.roomlist.impl.components_RoomListContentView_Night_3_en",20056,], +["features.roomlist.impl.components_RoomListContentView_Day_4_en","features.roomlist.impl.components_RoomListContentView_Night_4_en",20056,], +["features.roomlist.impl.components_RoomListContentView_Day_5_en","features.roomlist.impl.components_RoomListContentView_Night_5_en",20056,], +["features.roomlist.impl.filters_RoomListFiltersView_Day_0_en","features.roomlist.impl.filters_RoomListFiltersView_Night_0_en",20056,], +["features.roomlist.impl.filters_RoomListFiltersView_Day_1_en","features.roomlist.impl.filters_RoomListFiltersView_Night_1_en",20056,], +["features.roomlist.impl_RoomListModalBottomSheetContent_Day_0_en","features.roomlist.impl_RoomListModalBottomSheetContent_Night_0_en",20056,], +["features.roomlist.impl_RoomListModalBottomSheetContent_Day_1_en","features.roomlist.impl_RoomListModalBottomSheetContent_Night_1_en",20056,], +["features.roomlist.impl_RoomListModalBottomSheetContent_Day_2_en","features.roomlist.impl_RoomListModalBottomSheetContent_Night_2_en",20056,], ["features.roomlist.impl.search_RoomListSearchContent_Day_0_en","features.roomlist.impl.search_RoomListSearchContent_Night_0_en",0,], -["features.roomlist.impl.search_RoomListSearchContent_Day_1_en","features.roomlist.impl.search_RoomListSearchContent_Night_1_en",20049,], -["features.roomlist.impl.search_RoomListSearchContent_Day_2_en","features.roomlist.impl.search_RoomListSearchContent_Night_2_en",20049,], -["features.roomlist.impl_RoomListView_Day_0_en","features.roomlist.impl_RoomListView_Night_0_en",20049,], -["features.roomlist.impl_RoomListView_Day_10_en","features.roomlist.impl_RoomListView_Night_10_en",20049,], -["features.roomlist.impl_RoomListView_Day_1_en","features.roomlist.impl_RoomListView_Night_1_en",20049,], -["features.roomlist.impl_RoomListView_Day_2_en","features.roomlist.impl_RoomListView_Night_2_en",20049,], -["features.roomlist.impl_RoomListView_Day_3_en","features.roomlist.impl_RoomListView_Night_3_en",20049,], -["features.roomlist.impl_RoomListView_Day_4_en","features.roomlist.impl_RoomListView_Night_4_en",20049,], -["features.roomlist.impl_RoomListView_Day_5_en","features.roomlist.impl_RoomListView_Night_5_en",20049,], -["features.roomlist.impl_RoomListView_Day_6_en","features.roomlist.impl_RoomListView_Night_6_en",20049,], -["features.roomlist.impl_RoomListView_Day_7_en","features.roomlist.impl_RoomListView_Night_7_en",20049,], +["features.roomlist.impl.search_RoomListSearchContent_Day_1_en","features.roomlist.impl.search_RoomListSearchContent_Night_1_en",20056,], +["features.roomlist.impl.search_RoomListSearchContent_Day_2_en","features.roomlist.impl.search_RoomListSearchContent_Night_2_en",20056,], +["features.roomlist.impl_RoomListView_Day_0_en","features.roomlist.impl_RoomListView_Night_0_en",20056,], +["features.roomlist.impl_RoomListView_Day_10_en","features.roomlist.impl_RoomListView_Night_10_en",20056,], +["features.roomlist.impl_RoomListView_Day_1_en","features.roomlist.impl_RoomListView_Night_1_en",20056,], +["features.roomlist.impl_RoomListView_Day_2_en","features.roomlist.impl_RoomListView_Night_2_en",20056,], +["features.roomlist.impl_RoomListView_Day_3_en","features.roomlist.impl_RoomListView_Night_3_en",20056,], +["features.roomlist.impl_RoomListView_Day_4_en","features.roomlist.impl_RoomListView_Night_4_en",20056,], +["features.roomlist.impl_RoomListView_Day_5_en","features.roomlist.impl_RoomListView_Night_5_en",20056,], +["features.roomlist.impl_RoomListView_Day_6_en","features.roomlist.impl_RoomListView_Night_6_en",20056,], +["features.roomlist.impl_RoomListView_Day_7_en","features.roomlist.impl_RoomListView_Night_7_en",20056,], ["features.roomlist.impl_RoomListView_Day_8_en","features.roomlist.impl_RoomListView_Night_8_en",0,], ["features.roomlist.impl_RoomListView_Day_9_en","features.roomlist.impl_RoomListView_Night_9_en",0,], -["features.roomdetails.impl.members_RoomMemberListViewBanned_Day_0_en","features.roomdetails.impl.members_RoomMemberListViewBanned_Night_0_en",20049,], -["features.roomdetails.impl.members_RoomMemberListViewBanned_Day_1_en","features.roomdetails.impl.members_RoomMemberListViewBanned_Night_1_en",20049,], -["features.roomdetails.impl.members_RoomMemberListViewBanned_Day_2_en","features.roomdetails.impl.members_RoomMemberListViewBanned_Night_2_en",20049,], -["features.roomdetails.impl.members_RoomMemberListView_Day_0_en","features.roomdetails.impl.members_RoomMemberListView_Night_0_en",20049,], -["features.roomdetails.impl.members_RoomMemberListView_Day_1_en","features.roomdetails.impl.members_RoomMemberListView_Night_1_en",20049,], -["features.roomdetails.impl.members_RoomMemberListView_Day_2_en","features.roomdetails.impl.members_RoomMemberListView_Night_2_en",20049,], -["features.roomdetails.impl.members_RoomMemberListView_Day_3_en","features.roomdetails.impl.members_RoomMemberListView_Night_3_en",20049,], -["features.roomdetails.impl.members_RoomMemberListView_Day_4_en","features.roomdetails.impl.members_RoomMemberListView_Night_4_en",20049,], +["features.roomdetails.impl.members_RoomMemberListViewBanned_Day_0_en","features.roomdetails.impl.members_RoomMemberListViewBanned_Night_0_en",20056,], +["features.roomdetails.impl.members_RoomMemberListViewBanned_Day_1_en","features.roomdetails.impl.members_RoomMemberListViewBanned_Night_1_en",20056,], +["features.roomdetails.impl.members_RoomMemberListViewBanned_Day_2_en","features.roomdetails.impl.members_RoomMemberListViewBanned_Night_2_en",20056,], +["features.roomdetails.impl.members_RoomMemberListView_Day_0_en","features.roomdetails.impl.members_RoomMemberListView_Night_0_en",20056,], +["features.roomdetails.impl.members_RoomMemberListView_Day_1_en","features.roomdetails.impl.members_RoomMemberListView_Night_1_en",20056,], +["features.roomdetails.impl.members_RoomMemberListView_Day_2_en","features.roomdetails.impl.members_RoomMemberListView_Night_2_en",20056,], +["features.roomdetails.impl.members_RoomMemberListView_Day_3_en","features.roomdetails.impl.members_RoomMemberListView_Night_3_en",20056,], +["features.roomdetails.impl.members_RoomMemberListView_Day_4_en","features.roomdetails.impl.members_RoomMemberListView_Night_4_en",20056,], ["features.roomdetails.impl.members_RoomMemberListView_Day_5_en","features.roomdetails.impl.members_RoomMemberListView_Night_5_en",0,], -["features.roomdetails.impl.members_RoomMemberListView_Day_6_en","features.roomdetails.impl.members_RoomMemberListView_Night_6_en",20049,], -["features.roomdetails.impl.members_RoomMemberListView_Day_7_en","features.roomdetails.impl.members_RoomMemberListView_Night_7_en",20049,], -["features.roomdetails.impl.members_RoomMemberListView_Day_8_en","features.roomdetails.impl.members_RoomMemberListView_Night_8_en",20049,], +["features.roomdetails.impl.members_RoomMemberListView_Day_6_en","features.roomdetails.impl.members_RoomMemberListView_Night_6_en",20056,], +["features.roomdetails.impl.members_RoomMemberListView_Day_7_en","features.roomdetails.impl.members_RoomMemberListView_Night_7_en",20056,], +["features.roomdetails.impl.members_RoomMemberListView_Day_8_en","features.roomdetails.impl.members_RoomMemberListView_Night_8_en",20056,], ["libraries.designsystem.atomic.molecules_RoomMembersCountMolecule_Day_0_en","libraries.designsystem.atomic.molecules_RoomMembersCountMolecule_Night_0_en",0,], -["features.roomdetails.impl.members.moderation_RoomMembersModerationView_Day_0_en","features.roomdetails.impl.members.moderation_RoomMembersModerationView_Night_0_en",20049,], -["features.roomdetails.impl.members.moderation_RoomMembersModerationView_Day_1_en","features.roomdetails.impl.members.moderation_RoomMembersModerationView_Night_1_en",20049,], -["features.roomdetails.impl.members.moderation_RoomMembersModerationView_Day_2_en","features.roomdetails.impl.members.moderation_RoomMembersModerationView_Night_2_en",20049,], -["features.roomdetails.impl.members.moderation_RoomMembersModerationView_Day_3_en","features.roomdetails.impl.members.moderation_RoomMembersModerationView_Night_3_en",20049,], -["features.roomdetails.impl.members.moderation_RoomMembersModerationView_Day_4_en","features.roomdetails.impl.members.moderation_RoomMembersModerationView_Night_4_en",20049,], +["features.roomdetails.impl.members.moderation_RoomMembersModerationView_Day_0_en","features.roomdetails.impl.members.moderation_RoomMembersModerationView_Night_0_en",20056,], +["features.roomdetails.impl.members.moderation_RoomMembersModerationView_Day_1_en","features.roomdetails.impl.members.moderation_RoomMembersModerationView_Night_1_en",20056,], +["features.roomdetails.impl.members.moderation_RoomMembersModerationView_Day_2_en","features.roomdetails.impl.members.moderation_RoomMembersModerationView_Night_2_en",20056,], +["features.roomdetails.impl.members.moderation_RoomMembersModerationView_Day_3_en","features.roomdetails.impl.members.moderation_RoomMembersModerationView_Night_3_en",20056,], +["features.roomdetails.impl.members.moderation_RoomMembersModerationView_Day_4_en","features.roomdetails.impl.members.moderation_RoomMembersModerationView_Night_4_en",20056,], ["features.roomdetails.impl.members.moderation_RoomMembersModerationView_Day_5_en","features.roomdetails.impl.members.moderation_RoomMembersModerationView_Night_5_en",0,], -["features.roomdetails.impl.members.moderation_RoomMembersModerationView_Day_6_en","features.roomdetails.impl.members.moderation_RoomMembersModerationView_Night_6_en",20049,], -["features.roomdetails.impl.members.moderation_RoomMembersModerationView_Day_7_en","features.roomdetails.impl.members.moderation_RoomMembersModerationView_Night_7_en",20049,], -["features.roomdetails.impl.members.moderation_RoomMembersModerationView_Day_8_en","features.roomdetails.impl.members.moderation_RoomMembersModerationView_Night_8_en",20049,], +["features.roomdetails.impl.members.moderation_RoomMembersModerationView_Day_6_en","features.roomdetails.impl.members.moderation_RoomMembersModerationView_Night_6_en",20056,], +["features.roomdetails.impl.members.moderation_RoomMembersModerationView_Day_7_en","features.roomdetails.impl.members.moderation_RoomMembersModerationView_Night_7_en",20056,], +["features.roomdetails.impl.members.moderation_RoomMembersModerationView_Day_8_en","features.roomdetails.impl.members.moderation_RoomMembersModerationView_Night_8_en",20056,], ["features.roomdetails.impl.members.moderation_RoomMembersModerationView_Day_9_en","features.roomdetails.impl.members.moderation_RoomMembersModerationView_Night_9_en",0,], -["features.roomdetails.impl.notificationsettings_RoomNotificationSettingsOption_Day_0_en","features.roomdetails.impl.notificationsettings_RoomNotificationSettingsOption_Night_0_en",20049,], -["features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Day_0_en","features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Night_0_en",20049,], -["features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Day_1_en","features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Night_1_en",20049,], -["features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Day_2_en","features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Night_2_en",20049,], -["features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Day_3_en","features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Night_3_en",20049,], -["features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Day_4_en","features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Night_4_en",20049,], -["features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Day_5_en","features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Night_5_en",20049,], -["features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Day_6_en","features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Night_6_en",20049,], -["libraries.roomselect.impl_RoomSelectView_Day_0_en","libraries.roomselect.impl_RoomSelectView_Night_0_en",20049,], -["libraries.roomselect.impl_RoomSelectView_Day_1_en","libraries.roomselect.impl_RoomSelectView_Night_1_en",20049,], -["libraries.roomselect.impl_RoomSelectView_Day_2_en","libraries.roomselect.impl_RoomSelectView_Night_2_en",20049,], -["libraries.roomselect.impl_RoomSelectView_Day_3_en","libraries.roomselect.impl_RoomSelectView_Night_3_en",20049,], -["libraries.roomselect.impl_RoomSelectView_Day_4_en","libraries.roomselect.impl_RoomSelectView_Night_4_en",20049,], -["libraries.roomselect.impl_RoomSelectView_Day_5_en","libraries.roomselect.impl_RoomSelectView_Night_5_en",20049,], +["features.roomdetails.impl.notificationsettings_RoomNotificationSettingsOption_Day_0_en","features.roomdetails.impl.notificationsettings_RoomNotificationSettingsOption_Night_0_en",20056,], +["features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Day_0_en","features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Night_0_en",20056,], +["features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Day_1_en","features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Night_1_en",20056,], +["features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Day_2_en","features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Night_2_en",20056,], +["features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Day_3_en","features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Night_3_en",20056,], +["features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Day_4_en","features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Night_4_en",20056,], +["features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Day_5_en","features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Night_5_en",20056,], +["features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Day_6_en","features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Night_6_en",20056,], +["libraries.roomselect.impl_RoomSelectView_Day_0_en","libraries.roomselect.impl_RoomSelectView_Night_0_en",20056,], +["libraries.roomselect.impl_RoomSelectView_Day_1_en","libraries.roomselect.impl_RoomSelectView_Night_1_en",20056,], +["libraries.roomselect.impl_RoomSelectView_Day_2_en","libraries.roomselect.impl_RoomSelectView_Night_2_en",20056,], +["libraries.roomselect.impl_RoomSelectView_Day_3_en","libraries.roomselect.impl_RoomSelectView_Night_3_en",20056,], +["libraries.roomselect.impl_RoomSelectView_Day_4_en","libraries.roomselect.impl_RoomSelectView_Night_4_en",20056,], +["libraries.roomselect.impl_RoomSelectView_Day_5_en","libraries.roomselect.impl_RoomSelectView_Night_5_en",20056,], ["features.roomlist.impl.components_RoomSummaryPlaceholderRow_Day_0_en","features.roomlist.impl.components_RoomSummaryPlaceholderRow_Night_0_en",0,], ["features.roomlist.impl.components_RoomSummaryRow_Day_0_en","features.roomlist.impl.components_RoomSummaryRow_Night_0_en",0,], ["features.roomlist.impl.components_RoomSummaryRow_Day_10_en","features.roomlist.impl.components_RoomSummaryRow_Night_10_en",0,], @@ -873,12 +878,12 @@ export const screenshots = [ ["features.roomlist.impl.components_RoomSummaryRow_Day_26_en","features.roomlist.impl.components_RoomSummaryRow_Night_26_en",0,], ["features.roomlist.impl.components_RoomSummaryRow_Day_27_en","features.roomlist.impl.components_RoomSummaryRow_Night_27_en",0,], ["features.roomlist.impl.components_RoomSummaryRow_Day_28_en","features.roomlist.impl.components_RoomSummaryRow_Night_28_en",0,], -["features.roomlist.impl.components_RoomSummaryRow_Day_29_en","features.roomlist.impl.components_RoomSummaryRow_Night_29_en",20049,], -["features.roomlist.impl.components_RoomSummaryRow_Day_2_en","features.roomlist.impl.components_RoomSummaryRow_Night_2_en",20049,], -["features.roomlist.impl.components_RoomSummaryRow_Day_30_en","features.roomlist.impl.components_RoomSummaryRow_Night_30_en",20049,], -["features.roomlist.impl.components_RoomSummaryRow_Day_31_en","features.roomlist.impl.components_RoomSummaryRow_Night_31_en",20049,], -["features.roomlist.impl.components_RoomSummaryRow_Day_32_en","features.roomlist.impl.components_RoomSummaryRow_Night_32_en",0,], -["features.roomlist.impl.components_RoomSummaryRow_Day_33_en","features.roomlist.impl.components_RoomSummaryRow_Night_33_en",0,], +["features.roomlist.impl.components_RoomSummaryRow_Day_29_en","features.roomlist.impl.components_RoomSummaryRow_Night_29_en",20056,], +["features.roomlist.impl.components_RoomSummaryRow_Day_2_en","features.roomlist.impl.components_RoomSummaryRow_Night_2_en",20056,], +["features.roomlist.impl.components_RoomSummaryRow_Day_30_en","features.roomlist.impl.components_RoomSummaryRow_Night_30_en",20056,], +["features.roomlist.impl.components_RoomSummaryRow_Day_31_en","features.roomlist.impl.components_RoomSummaryRow_Night_31_en",20056,], +["features.roomlist.impl.components_RoomSummaryRow_Day_32_en","features.roomlist.impl.components_RoomSummaryRow_Night_32_en",20059,], +["features.roomlist.impl.components_RoomSummaryRow_Day_33_en","features.roomlist.impl.components_RoomSummaryRow_Night_33_en",20059,], ["features.roomlist.impl.components_RoomSummaryRow_Day_3_en","features.roomlist.impl.components_RoomSummaryRow_Night_3_en",0,], ["features.roomlist.impl.components_RoomSummaryRow_Day_4_en","features.roomlist.impl.components_RoomSummaryRow_Night_4_en",0,], ["features.roomlist.impl.components_RoomSummaryRow_Day_5_en","features.roomlist.impl.components_RoomSummaryRow_Night_5_en",0,], @@ -886,59 +891,59 @@ export const screenshots = [ ["features.roomlist.impl.components_RoomSummaryRow_Day_7_en","features.roomlist.impl.components_RoomSummaryRow_Night_7_en",0,], ["features.roomlist.impl.components_RoomSummaryRow_Day_8_en","features.roomlist.impl.components_RoomSummaryRow_Night_8_en",0,], ["features.roomlist.impl.components_RoomSummaryRow_Day_9_en","features.roomlist.impl.components_RoomSummaryRow_Night_9_en",0,], -["appnav.root_RootView_Day_0_en","appnav.root_RootView_Night_0_en",20049,], -["appnav.root_RootView_Day_1_en","appnav.root_RootView_Night_1_en",20049,], -["appnav.root_RootView_Day_2_en","appnav.root_RootView_Night_2_en",20049,], +["appnav.root_RootView_Day_0_en","appnav.root_RootView_Night_0_en",20056,], +["appnav.root_RootView_Day_1_en","appnav.root_RootView_Night_1_en",20056,], +["appnav.root_RootView_Day_2_en","appnav.root_RootView_Night_2_en",20056,], ["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",20049,], -["features.login.impl.screens.searchaccountprovider_SearchAccountProviderView_Day_0_en","features.login.impl.screens.searchaccountprovider_SearchAccountProviderView_Night_0_en",20049,], -["features.login.impl.screens.searchaccountprovider_SearchAccountProviderView_Day_1_en","features.login.impl.screens.searchaccountprovider_SearchAccountProviderView_Night_1_en",20049,], +["features.verifysession.impl.emoji_SasEmojis_Day_0_en","features.verifysession.impl.emoji_SasEmojis_Night_0_en",20056,], +["features.login.impl.screens.searchaccountprovider_SearchAccountProviderView_Day_0_en","features.login.impl.screens.searchaccountprovider_SearchAccountProviderView_Night_0_en",20056,], +["features.login.impl.screens.searchaccountprovider_SearchAccountProviderView_Day_1_en","features.login.impl.screens.searchaccountprovider_SearchAccountProviderView_Night_1_en",20056,], ["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","",20049,], +["libraries.designsystem.theme.components_SearchBarActiveWithNoResults_Search_views_en","",20056,], ["libraries.designsystem.theme.components_SearchBarActiveWithQueryNoBackButton_Search_views_en","",0,], ["libraries.designsystem.theme.components_SearchBarActiveWithQuery_Search_views_en","",0,], ["libraries.designsystem.theme.components_SearchBarInactive_Search_views_en","",0,], -["features.createroom.impl.components_SearchMultipleUsersResultItem_en","",20049,], -["features.createroom.impl.components_SearchSingleUserResultItem_en","",20049,], -["features.securebackup.impl.disable_SecureBackupDisableView_Day_0_en","features.securebackup.impl.disable_SecureBackupDisableView_Night_0_en",20049,], -["features.securebackup.impl.disable_SecureBackupDisableView_Day_1_en","features.securebackup.impl.disable_SecureBackupDisableView_Night_1_en",20049,], -["features.securebackup.impl.disable_SecureBackupDisableView_Day_2_en","features.securebackup.impl.disable_SecureBackupDisableView_Night_2_en",20049,], -["features.securebackup.impl.disable_SecureBackupDisableView_Day_3_en","features.securebackup.impl.disable_SecureBackupDisableView_Night_3_en",20049,], -["features.securebackup.impl.enter_SecureBackupEnterRecoveryKeyView_Day_0_en","features.securebackup.impl.enter_SecureBackupEnterRecoveryKeyView_Night_0_en",20049,], -["features.securebackup.impl.enter_SecureBackupEnterRecoveryKeyView_Day_1_en","features.securebackup.impl.enter_SecureBackupEnterRecoveryKeyView_Night_1_en",20049,], -["features.securebackup.impl.enter_SecureBackupEnterRecoveryKeyView_Day_2_en","features.securebackup.impl.enter_SecureBackupEnterRecoveryKeyView_Night_2_en",20049,], -["features.securebackup.impl.enter_SecureBackupEnterRecoveryKeyView_Day_3_en","features.securebackup.impl.enter_SecureBackupEnterRecoveryKeyView_Night_3_en",20049,], -["features.securebackup.impl.root_SecureBackupRootView_Day_0_en","features.securebackup.impl.root_SecureBackupRootView_Night_0_en",20049,], -["features.securebackup.impl.root_SecureBackupRootView_Day_10_en","features.securebackup.impl.root_SecureBackupRootView_Night_10_en",20049,], -["features.securebackup.impl.root_SecureBackupRootView_Day_11_en","features.securebackup.impl.root_SecureBackupRootView_Night_11_en",20049,], -["features.securebackup.impl.root_SecureBackupRootView_Day_12_en","features.securebackup.impl.root_SecureBackupRootView_Night_12_en",20049,], -["features.securebackup.impl.root_SecureBackupRootView_Day_13_en","features.securebackup.impl.root_SecureBackupRootView_Night_13_en",20049,], -["features.securebackup.impl.root_SecureBackupRootView_Day_14_en","features.securebackup.impl.root_SecureBackupRootView_Night_14_en",20049,], -["features.securebackup.impl.root_SecureBackupRootView_Day_15_en","features.securebackup.impl.root_SecureBackupRootView_Night_15_en",20049,], -["features.securebackup.impl.root_SecureBackupRootView_Day_16_en","features.securebackup.impl.root_SecureBackupRootView_Night_16_en",20049,], -["features.securebackup.impl.root_SecureBackupRootView_Day_17_en","features.securebackup.impl.root_SecureBackupRootView_Night_17_en",20049,], -["features.securebackup.impl.root_SecureBackupRootView_Day_1_en","features.securebackup.impl.root_SecureBackupRootView_Night_1_en",20049,], -["features.securebackup.impl.root_SecureBackupRootView_Day_2_en","features.securebackup.impl.root_SecureBackupRootView_Night_2_en",20049,], -["features.securebackup.impl.root_SecureBackupRootView_Day_3_en","features.securebackup.impl.root_SecureBackupRootView_Night_3_en",20049,], -["features.securebackup.impl.root_SecureBackupRootView_Day_4_en","features.securebackup.impl.root_SecureBackupRootView_Night_4_en",20049,], -["features.securebackup.impl.root_SecureBackupRootView_Day_5_en","features.securebackup.impl.root_SecureBackupRootView_Night_5_en",20049,], -["features.securebackup.impl.root_SecureBackupRootView_Day_6_en","features.securebackup.impl.root_SecureBackupRootView_Night_6_en",20049,], -["features.securebackup.impl.root_SecureBackupRootView_Day_7_en","features.securebackup.impl.root_SecureBackupRootView_Night_7_en",20049,], -["features.securebackup.impl.root_SecureBackupRootView_Day_8_en","features.securebackup.impl.root_SecureBackupRootView_Night_8_en",20049,], -["features.securebackup.impl.root_SecureBackupRootView_Day_9_en","features.securebackup.impl.root_SecureBackupRootView_Night_9_en",20049,], -["features.securebackup.impl.setup_SecureBackupSetupViewChange_Day_0_en","features.securebackup.impl.setup_SecureBackupSetupViewChange_Night_0_en",20049,], -["features.securebackup.impl.setup_SecureBackupSetupViewChange_Day_1_en","features.securebackup.impl.setup_SecureBackupSetupViewChange_Night_1_en",20049,], -["features.securebackup.impl.setup_SecureBackupSetupViewChange_Day_2_en","features.securebackup.impl.setup_SecureBackupSetupViewChange_Night_2_en",20049,], -["features.securebackup.impl.setup_SecureBackupSetupViewChange_Day_3_en","features.securebackup.impl.setup_SecureBackupSetupViewChange_Night_3_en",20049,], -["features.securebackup.impl.setup_SecureBackupSetupViewChange_Day_4_en","features.securebackup.impl.setup_SecureBackupSetupViewChange_Night_4_en",20049,], -["features.securebackup.impl.setup_SecureBackupSetupView_Day_0_en","features.securebackup.impl.setup_SecureBackupSetupView_Night_0_en",20049,], -["features.securebackup.impl.setup_SecureBackupSetupView_Day_1_en","features.securebackup.impl.setup_SecureBackupSetupView_Night_1_en",20049,], -["features.securebackup.impl.setup_SecureBackupSetupView_Day_2_en","features.securebackup.impl.setup_SecureBackupSetupView_Night_2_en",20049,], -["features.securebackup.impl.setup_SecureBackupSetupView_Day_3_en","features.securebackup.impl.setup_SecureBackupSetupView_Night_3_en",20049,], -["features.securebackup.impl.setup_SecureBackupSetupView_Day_4_en","features.securebackup.impl.setup_SecureBackupSetupView_Night_4_en",20049,], +["features.createroom.impl.components_SearchMultipleUsersResultItem_en","",20056,], +["features.createroom.impl.components_SearchSingleUserResultItem_en","",20056,], +["features.securebackup.impl.disable_SecureBackupDisableView_Day_0_en","features.securebackup.impl.disable_SecureBackupDisableView_Night_0_en",20056,], +["features.securebackup.impl.disable_SecureBackupDisableView_Day_1_en","features.securebackup.impl.disable_SecureBackupDisableView_Night_1_en",20056,], +["features.securebackup.impl.disable_SecureBackupDisableView_Day_2_en","features.securebackup.impl.disable_SecureBackupDisableView_Night_2_en",20056,], +["features.securebackup.impl.disable_SecureBackupDisableView_Day_3_en","features.securebackup.impl.disable_SecureBackupDisableView_Night_3_en",20056,], +["features.securebackup.impl.enter_SecureBackupEnterRecoveryKeyView_Day_0_en","features.securebackup.impl.enter_SecureBackupEnterRecoveryKeyView_Night_0_en",20056,], +["features.securebackup.impl.enter_SecureBackupEnterRecoveryKeyView_Day_1_en","features.securebackup.impl.enter_SecureBackupEnterRecoveryKeyView_Night_1_en",20056,], +["features.securebackup.impl.enter_SecureBackupEnterRecoveryKeyView_Day_2_en","features.securebackup.impl.enter_SecureBackupEnterRecoveryKeyView_Night_2_en",20056,], +["features.securebackup.impl.enter_SecureBackupEnterRecoveryKeyView_Day_3_en","features.securebackup.impl.enter_SecureBackupEnterRecoveryKeyView_Night_3_en",20056,], +["features.securebackup.impl.root_SecureBackupRootView_Day_0_en","features.securebackup.impl.root_SecureBackupRootView_Night_0_en",20056,], +["features.securebackup.impl.root_SecureBackupRootView_Day_10_en","features.securebackup.impl.root_SecureBackupRootView_Night_10_en",20056,], +["features.securebackup.impl.root_SecureBackupRootView_Day_11_en","features.securebackup.impl.root_SecureBackupRootView_Night_11_en",20056,], +["features.securebackup.impl.root_SecureBackupRootView_Day_12_en","features.securebackup.impl.root_SecureBackupRootView_Night_12_en",20056,], +["features.securebackup.impl.root_SecureBackupRootView_Day_13_en","features.securebackup.impl.root_SecureBackupRootView_Night_13_en",20056,], +["features.securebackup.impl.root_SecureBackupRootView_Day_14_en","features.securebackup.impl.root_SecureBackupRootView_Night_14_en",20056,], +["features.securebackup.impl.root_SecureBackupRootView_Day_15_en","features.securebackup.impl.root_SecureBackupRootView_Night_15_en",20056,], +["features.securebackup.impl.root_SecureBackupRootView_Day_16_en","features.securebackup.impl.root_SecureBackupRootView_Night_16_en",20056,], +["features.securebackup.impl.root_SecureBackupRootView_Day_17_en","features.securebackup.impl.root_SecureBackupRootView_Night_17_en",20056,], +["features.securebackup.impl.root_SecureBackupRootView_Day_1_en","features.securebackup.impl.root_SecureBackupRootView_Night_1_en",20056,], +["features.securebackup.impl.root_SecureBackupRootView_Day_2_en","features.securebackup.impl.root_SecureBackupRootView_Night_2_en",20056,], +["features.securebackup.impl.root_SecureBackupRootView_Day_3_en","features.securebackup.impl.root_SecureBackupRootView_Night_3_en",20056,], +["features.securebackup.impl.root_SecureBackupRootView_Day_4_en","features.securebackup.impl.root_SecureBackupRootView_Night_4_en",20056,], +["features.securebackup.impl.root_SecureBackupRootView_Day_5_en","features.securebackup.impl.root_SecureBackupRootView_Night_5_en",20056,], +["features.securebackup.impl.root_SecureBackupRootView_Day_6_en","features.securebackup.impl.root_SecureBackupRootView_Night_6_en",20056,], +["features.securebackup.impl.root_SecureBackupRootView_Day_7_en","features.securebackup.impl.root_SecureBackupRootView_Night_7_en",20056,], +["features.securebackup.impl.root_SecureBackupRootView_Day_8_en","features.securebackup.impl.root_SecureBackupRootView_Night_8_en",20056,], +["features.securebackup.impl.root_SecureBackupRootView_Day_9_en","features.securebackup.impl.root_SecureBackupRootView_Night_9_en",20056,], +["features.securebackup.impl.setup_SecureBackupSetupViewChange_Day_0_en","features.securebackup.impl.setup_SecureBackupSetupViewChange_Night_0_en",20056,], +["features.securebackup.impl.setup_SecureBackupSetupViewChange_Day_1_en","features.securebackup.impl.setup_SecureBackupSetupViewChange_Night_1_en",20056,], +["features.securebackup.impl.setup_SecureBackupSetupViewChange_Day_2_en","features.securebackup.impl.setup_SecureBackupSetupViewChange_Night_2_en",20056,], +["features.securebackup.impl.setup_SecureBackupSetupViewChange_Day_3_en","features.securebackup.impl.setup_SecureBackupSetupViewChange_Night_3_en",20056,], +["features.securebackup.impl.setup_SecureBackupSetupViewChange_Day_4_en","features.securebackup.impl.setup_SecureBackupSetupViewChange_Night_4_en",20056,], +["features.securebackup.impl.setup_SecureBackupSetupView_Day_0_en","features.securebackup.impl.setup_SecureBackupSetupView_Night_0_en",20056,], +["features.securebackup.impl.setup_SecureBackupSetupView_Day_1_en","features.securebackup.impl.setup_SecureBackupSetupView_Night_1_en",20056,], +["features.securebackup.impl.setup_SecureBackupSetupView_Day_2_en","features.securebackup.impl.setup_SecureBackupSetupView_Night_2_en",20056,], +["features.securebackup.impl.setup_SecureBackupSetupView_Day_3_en","features.securebackup.impl.setup_SecureBackupSetupView_Night_3_en",20056,], +["features.securebackup.impl.setup_SecureBackupSetupView_Day_4_en","features.securebackup.impl.setup_SecureBackupSetupView_Night_4_en",20056,], ["libraries.matrix.ui.components_SelectedRoom_Day_0_en","libraries.matrix.ui.components_SelectedRoom_Night_0_en",0,], ["libraries.matrix.ui.components_SelectedRoom_Day_1_en","libraries.matrix.ui.components_SelectedRoom_Night_1_en",0,], ["libraries.matrix.ui.components_SelectedRoom_Day_2_en","libraries.matrix.ui.components_SelectedRoom_Night_2_en",0,], @@ -946,11 +951,11 @@ export const screenshots = [ ["libraries.matrix.ui.components_SelectedUser_Day_0_en","libraries.matrix.ui.components_SelectedUser_Night_0_en",0,], ["libraries.matrix.ui.components_SelectedUsersRowList_Day_0_en","libraries.matrix.ui.components_SelectedUsersRowList_Night_0_en",0,], ["libraries.textcomposer.components_SendButton_Day_0_en","libraries.textcomposer.components_SendButton_Night_0_en",0,], -["features.location.impl.send_SendLocationView_Day_0_en","features.location.impl.send_SendLocationView_Night_0_en",20049,], -["features.location.impl.send_SendLocationView_Day_1_en","features.location.impl.send_SendLocationView_Night_1_en",20049,], -["features.location.impl.send_SendLocationView_Day_2_en","features.location.impl.send_SendLocationView_Night_2_en",20049,], -["features.location.impl.send_SendLocationView_Day_3_en","features.location.impl.send_SendLocationView_Night_3_en",20049,], -["features.location.impl.send_SendLocationView_Day_4_en","features.location.impl.send_SendLocationView_Night_4_en",20049,], +["features.location.impl.send_SendLocationView_Day_0_en","features.location.impl.send_SendLocationView_Night_0_en",20056,], +["features.location.impl.send_SendLocationView_Day_1_en","features.location.impl.send_SendLocationView_Night_1_en",20056,], +["features.location.impl.send_SendLocationView_Day_2_en","features.location.impl.send_SendLocationView_Night_2_en",20056,], +["features.location.impl.send_SendLocationView_Day_3_en","features.location.impl.send_SendLocationView_Night_3_en",20056,], +["features.location.impl.send_SendLocationView_Day_4_en","features.location.impl.send_SendLocationView_Night_4_en",20056,], ["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,], @@ -960,27 +965,27 @@ export const screenshots = [ ["libraries.matrix.ui.messages.sender_SenderName_Day_6_en","libraries.matrix.ui.messages.sender_SenderName_Night_6_en",0,], ["libraries.matrix.ui.messages.sender_SenderName_Day_7_en","libraries.matrix.ui.messages.sender_SenderName_Night_7_en",0,], ["libraries.matrix.ui.messages.sender_SenderName_Day_8_en","libraries.matrix.ui.messages.sender_SenderName_Night_8_en",0,], -["features.verifysession.impl.incoming.ui_SessionDetailsView_Day_0_en","features.verifysession.impl.incoming.ui_SessionDetailsView_Night_0_en",0,], -["features.roomlist.impl.components_SetUpRecoveryKeyBanner_Day_0_en","features.roomlist.impl.components_SetUpRecoveryKeyBanner_Night_0_en",20049,], -["features.lockscreen.impl.setup.biometric_SetupBiometricView_Day_0_en","features.lockscreen.impl.setup.biometric_SetupBiometricView_Night_0_en",20049,], -["features.lockscreen.impl.setup.pin_SetupPinView_Day_0_en","features.lockscreen.impl.setup.pin_SetupPinView_Night_0_en",20049,], -["features.lockscreen.impl.setup.pin_SetupPinView_Day_1_en","features.lockscreen.impl.setup.pin_SetupPinView_Night_1_en",20049,], -["features.lockscreen.impl.setup.pin_SetupPinView_Day_2_en","features.lockscreen.impl.setup.pin_SetupPinView_Night_2_en",20049,], -["features.lockscreen.impl.setup.pin_SetupPinView_Day_3_en","features.lockscreen.impl.setup.pin_SetupPinView_Night_3_en",20049,], -["features.lockscreen.impl.setup.pin_SetupPinView_Day_4_en","features.lockscreen.impl.setup.pin_SetupPinView_Night_4_en",20049,], +["features.verifysession.impl.incoming.ui_SessionDetailsView_Day_0_en","features.verifysession.impl.incoming.ui_SessionDetailsView_Night_0_en",20059,], +["features.roomlist.impl.components_SetUpRecoveryKeyBanner_Day_0_en","features.roomlist.impl.components_SetUpRecoveryKeyBanner_Night_0_en",20056,], +["features.lockscreen.impl.setup.biometric_SetupBiometricView_Day_0_en","features.lockscreen.impl.setup.biometric_SetupBiometricView_Night_0_en",20056,], +["features.lockscreen.impl.setup.pin_SetupPinView_Day_0_en","features.lockscreen.impl.setup.pin_SetupPinView_Night_0_en",20056,], +["features.lockscreen.impl.setup.pin_SetupPinView_Day_1_en","features.lockscreen.impl.setup.pin_SetupPinView_Night_1_en",20056,], +["features.lockscreen.impl.setup.pin_SetupPinView_Day_2_en","features.lockscreen.impl.setup.pin_SetupPinView_Night_2_en",20056,], +["features.lockscreen.impl.setup.pin_SetupPinView_Day_3_en","features.lockscreen.impl.setup.pin_SetupPinView_Night_3_en",20056,], +["features.lockscreen.impl.setup.pin_SetupPinView_Day_4_en","features.lockscreen.impl.setup.pin_SetupPinView_Night_4_en",20056,], ["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",20049,], -["features.location.impl.show_ShowLocationView_Day_0_en","features.location.impl.show_ShowLocationView_Night_0_en",20049,], -["features.location.impl.show_ShowLocationView_Day_1_en","features.location.impl.show_ShowLocationView_Night_1_en",20049,], -["features.location.impl.show_ShowLocationView_Day_2_en","features.location.impl.show_ShowLocationView_Night_2_en",20049,], -["features.location.impl.show_ShowLocationView_Day_3_en","features.location.impl.show_ShowLocationView_Night_3_en",20049,], -["features.location.impl.show_ShowLocationView_Day_4_en","features.location.impl.show_ShowLocationView_Night_4_en",20049,], -["features.location.impl.show_ShowLocationView_Day_5_en","features.location.impl.show_ShowLocationView_Night_5_en",20049,], -["features.location.impl.show_ShowLocationView_Day_6_en","features.location.impl.show_ShowLocationView_Night_6_en",20049,], -["features.location.impl.show_ShowLocationView_Day_7_en","features.location.impl.show_ShowLocationView_Night_7_en",20049,], -["features.signedout.impl_SignedOutView_Day_0_en","features.signedout.impl_SignedOutView_Night_0_en",20049,], +["features.share.impl_ShareView_Day_3_en","features.share.impl_ShareView_Night_3_en",20056,], +["features.location.impl.show_ShowLocationView_Day_0_en","features.location.impl.show_ShowLocationView_Night_0_en",20056,], +["features.location.impl.show_ShowLocationView_Day_1_en","features.location.impl.show_ShowLocationView_Night_1_en",20056,], +["features.location.impl.show_ShowLocationView_Day_2_en","features.location.impl.show_ShowLocationView_Night_2_en",20056,], +["features.location.impl.show_ShowLocationView_Day_3_en","features.location.impl.show_ShowLocationView_Night_3_en",20056,], +["features.location.impl.show_ShowLocationView_Day_4_en","features.location.impl.show_ShowLocationView_Night_4_en",20056,], +["features.location.impl.show_ShowLocationView_Day_5_en","features.location.impl.show_ShowLocationView_Night_5_en",20056,], +["features.location.impl.show_ShowLocationView_Day_6_en","features.location.impl.show_ShowLocationView_Night_6_en",20056,], +["features.location.impl.show_ShowLocationView_Day_7_en","features.location.impl.show_ShowLocationView_Night_7_en",20056,], +["features.signedout.impl_SignedOutView_Day_0_en","features.signedout.impl_SignedOutView_Night_0_en",20056,], ["libraries.designsystem.components.dialogs_SingleSelectionDialogContent_Dialogs_en","",0,], ["libraries.designsystem.components.dialogs_SingleSelectionDialog_Day_0_en","libraries.designsystem.components.dialogs_SingleSelectionDialog_Night_0_en",0,], ["libraries.designsystem.components.list_SingleSelectionListItemCustomFormattert_Single_selection_List_item_-_custom_formatter_List_items_en","",0,], @@ -989,7 +994,7 @@ export const screenshots = [ ["libraries.designsystem.components.list_SingleSelectionListItemUnselectedWithSupportingText_Single_selection_List_item_-_no_selection,_supporting_text_List_items_en","",0,], ["libraries.designsystem.components.list_SingleSelectionListItem_Single_selection_List_item_-_no_selection_List_items_en","",0,], ["libraries.designsystem.theme.components_Sliders_Sliders_en","",0,], -["features.login.impl.dialogs_SlidingSyncNotSupportedDialog_Day_0_en","features.login.impl.dialogs_SlidingSyncNotSupportedDialog_Night_0_en",20049,], +["features.login.impl.dialogs_SlidingSyncNotSupportedDialog_Day_0_en","features.login.impl.dialogs_SlidingSyncNotSupportedDialog_Night_0_en",20056,], ["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,], @@ -999,40 +1004,40 @@ export const screenshots = [ ["libraries.designsystem.modifiers_SquareSizeModifierLargeHeight_en","",0,], ["libraries.designsystem.modifiers_SquareSizeModifierLargeWidth_en","",0,], ["features.location.api.internal_StaticMapPlaceholder_Day_0_en","features.location.api.internal_StaticMapPlaceholder_Night_0_en",0,], -["features.location.api.internal_StaticMapPlaceholder_Day_1_en","features.location.api.internal_StaticMapPlaceholder_Night_1_en",20049,], +["features.location.api.internal_StaticMapPlaceholder_Day_1_en","features.location.api.internal_StaticMapPlaceholder_Night_1_en",20056,], ["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",20049,], +["features.messages.impl.messagecomposer.suggestions_SuggestionsPickerView_Day_0_en","features.messages.impl.messagecomposer.suggestions_SuggestionsPickerView_Night_0_en",20056,], ["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",20049,], +["appnav.loggedin_SyncStateView_Day_0_en","appnav.loggedin_SyncStateView_Night_0_en",20056,], ["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",20052,], -["libraries.textcomposer_TextComposerCaption_Day_0_en","libraries.textcomposer_TextComposerCaption_Night_0_en",0,], -["libraries.textcomposer_TextComposerEditCaption_Day_0_en","libraries.textcomposer_TextComposerEditCaption_Night_0_en",20052,], -["libraries.textcomposer_TextComposerEdit_Day_0_en","libraries.textcomposer_TextComposerEdit_Night_0_en",20049,], -["libraries.textcomposer_TextComposerFormatting_Day_0_en","libraries.textcomposer_TextComposerFormatting_Night_0_en",20049,], -["libraries.textcomposer_TextComposerLinkDialogCreateLinkWithoutText_Day_0_en","libraries.textcomposer_TextComposerLinkDialogCreateLinkWithoutText_Night_0_en",20049,], -["libraries.textcomposer_TextComposerLinkDialogCreateLink_Day_0_en","libraries.textcomposer_TextComposerLinkDialogCreateLink_Night_0_en",20049,], -["libraries.textcomposer_TextComposerLinkDialogEditLink_Day_0_en","libraries.textcomposer_TextComposerLinkDialogEditLink_Night_0_en",20049,], -["libraries.textcomposer_TextComposerReply_Day_0_en","libraries.textcomposer_TextComposerReply_Night_0_en",20049,], -["libraries.textcomposer_TextComposerReply_Day_10_en","libraries.textcomposer_TextComposerReply_Night_10_en",20049,], -["libraries.textcomposer_TextComposerReply_Day_11_en","libraries.textcomposer_TextComposerReply_Night_11_en",20049,], -["libraries.textcomposer_TextComposerReply_Day_1_en","libraries.textcomposer_TextComposerReply_Night_1_en",20049,], -["libraries.textcomposer_TextComposerReply_Day_2_en","libraries.textcomposer_TextComposerReply_Night_2_en",20049,], -["libraries.textcomposer_TextComposerReply_Day_3_en","libraries.textcomposer_TextComposerReply_Night_3_en",20049,], -["libraries.textcomposer_TextComposerReply_Day_4_en","libraries.textcomposer_TextComposerReply_Night_4_en",20049,], -["libraries.textcomposer_TextComposerReply_Day_5_en","libraries.textcomposer_TextComposerReply_Night_5_en",20049,], -["libraries.textcomposer_TextComposerReply_Day_6_en","libraries.textcomposer_TextComposerReply_Night_6_en",20049,], -["libraries.textcomposer_TextComposerReply_Day_7_en","libraries.textcomposer_TextComposerReply_Night_7_en",20049,], -["libraries.textcomposer_TextComposerReply_Day_8_en","libraries.textcomposer_TextComposerReply_Night_8_en",20049,], -["libraries.textcomposer_TextComposerReply_Day_9_en","libraries.textcomposer_TextComposerReply_Night_9_en",20049,], -["libraries.textcomposer_TextComposerSimple_Day_0_en","libraries.textcomposer_TextComposerSimple_Night_0_en",20049,], +["libraries.textcomposer_TextComposerAddCaption_Day_0_en","libraries.textcomposer_TextComposerAddCaption_Night_0_en",20056,], +["libraries.textcomposer_TextComposerCaption_Day_0_en","libraries.textcomposer_TextComposerCaption_Night_0_en",20059,], +["libraries.textcomposer_TextComposerEditCaption_Day_0_en","libraries.textcomposer_TextComposerEditCaption_Night_0_en",20056,], +["libraries.textcomposer_TextComposerEdit_Day_0_en","libraries.textcomposer_TextComposerEdit_Night_0_en",20056,], +["libraries.textcomposer_TextComposerFormatting_Day_0_en","libraries.textcomposer_TextComposerFormatting_Night_0_en",20056,], +["libraries.textcomposer_TextComposerLinkDialogCreateLinkWithoutText_Day_0_en","libraries.textcomposer_TextComposerLinkDialogCreateLinkWithoutText_Night_0_en",20056,], +["libraries.textcomposer_TextComposerLinkDialogCreateLink_Day_0_en","libraries.textcomposer_TextComposerLinkDialogCreateLink_Night_0_en",20056,], +["libraries.textcomposer_TextComposerLinkDialogEditLink_Day_0_en","libraries.textcomposer_TextComposerLinkDialogEditLink_Night_0_en",20056,], +["libraries.textcomposer_TextComposerReply_Day_0_en","libraries.textcomposer_TextComposerReply_Night_0_en",20056,], +["libraries.textcomposer_TextComposerReply_Day_10_en","libraries.textcomposer_TextComposerReply_Night_10_en",20056,], +["libraries.textcomposer_TextComposerReply_Day_11_en","libraries.textcomposer_TextComposerReply_Night_11_en",20056,], +["libraries.textcomposer_TextComposerReply_Day_1_en","libraries.textcomposer_TextComposerReply_Night_1_en",20056,], +["libraries.textcomposer_TextComposerReply_Day_2_en","libraries.textcomposer_TextComposerReply_Night_2_en",20056,], +["libraries.textcomposer_TextComposerReply_Day_3_en","libraries.textcomposer_TextComposerReply_Night_3_en",20056,], +["libraries.textcomposer_TextComposerReply_Day_4_en","libraries.textcomposer_TextComposerReply_Night_4_en",20056,], +["libraries.textcomposer_TextComposerReply_Day_5_en","libraries.textcomposer_TextComposerReply_Night_5_en",20056,], +["libraries.textcomposer_TextComposerReply_Day_6_en","libraries.textcomposer_TextComposerReply_Night_6_en",20056,], +["libraries.textcomposer_TextComposerReply_Day_7_en","libraries.textcomposer_TextComposerReply_Night_7_en",20056,], +["libraries.textcomposer_TextComposerReply_Day_8_en","libraries.textcomposer_TextComposerReply_Night_8_en",20056,], +["libraries.textcomposer_TextComposerReply_Day_9_en","libraries.textcomposer_TextComposerReply_Night_9_en",20056,], +["libraries.textcomposer_TextComposerSimple_Day_0_en","libraries.textcomposer_TextComposerSimple_Night_0_en",20056,], ["libraries.textcomposer_TextComposerVoice_Day_0_en","libraries.textcomposer_TextComposerVoice_Night_0_en",0,], ["libraries.designsystem.theme.components_TextDark_Text_en","",0,], ["libraries.designsystem.components.list_TextFieldListItemEmpty_Text_field_List_item_-_empty_List_items_en","",0,], @@ -1042,14 +1047,14 @@ export const screenshots = [ ["libraries.designsystem.theme.components_TextFieldsLight_TextFields_en","",0,], ["libraries.textcomposer.components_TextFormatting_Day_0_en","libraries.textcomposer.components_TextFormatting_Night_0_en",0,], ["libraries.designsystem.theme.components_TextLight_Text_en","",0,], -["libraries.designsystem.theme.components.previews_TimePickerHorizontal_DateTime_pickers_en","",20049,], -["libraries.designsystem.theme.components.previews_TimePickerVerticalDark_DateTime_pickers_en","",20049,], -["libraries.designsystem.theme.components.previews_TimePickerVerticalLight_DateTime_pickers_en","",20049,], +["libraries.designsystem.theme.components.previews_TimePickerHorizontal_DateTime_pickers_en","",20056,], +["libraries.designsystem.theme.components.previews_TimePickerVerticalDark_DateTime_pickers_en","",20056,], +["libraries.designsystem.theme.components.previews_TimePickerVerticalLight_DateTime_pickers_en","",20056,], ["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",20049,], -["features.messages.impl.timeline.components_TimelineEventTimestampView_Day_4_en","features.messages.impl.timeline.components_TimelineEventTimestampView_Night_4_en",20049,], +["features.messages.impl.timeline.components_TimelineEventTimestampView_Day_3_en","features.messages.impl.timeline.components_TimelineEventTimestampView_Night_3_en",20056,], +["features.messages.impl.timeline.components_TimelineEventTimestampView_Day_4_en","features.messages.impl.timeline.components_TimelineEventTimestampView_Night_4_en",20056,], ["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.event_TimelineImageWithCaptionRow_Day_0_en","features.messages.impl.timeline.components.event_TimelineImageWithCaptionRow_Night_0_en",0,], @@ -1058,14 +1063,14 @@ 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",20049,], +["features.messages.impl.timeline.components_TimelineItemCallNotifyView_Day_0_en","features.messages.impl.timeline.components_TimelineItemCallNotifyView_Night_0_en",20056,], ["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",20049,], -["features.messages.impl.timeline.components.event_TimelineItemEncryptedView_Day_1_en","features.messages.impl.timeline.components.event_TimelineItemEncryptedView_Night_1_en",20049,], -["features.messages.impl.timeline.components.event_TimelineItemEncryptedView_Day_2_en","features.messages.impl.timeline.components.event_TimelineItemEncryptedView_Night_2_en",0,], -["features.messages.impl.timeline.components.event_TimelineItemEncryptedView_Day_3_en","features.messages.impl.timeline.components.event_TimelineItemEncryptedView_Night_3_en",0,], -["features.messages.impl.timeline.components.event_TimelineItemEncryptedView_Day_4_en","features.messages.impl.timeline.components.event_TimelineItemEncryptedView_Night_4_en",20049,], +["features.messages.impl.timeline.components.event_TimelineItemEncryptedView_Day_0_en","features.messages.impl.timeline.components.event_TimelineItemEncryptedView_Night_0_en",20056,], +["features.messages.impl.timeline.components.event_TimelineItemEncryptedView_Day_1_en","features.messages.impl.timeline.components.event_TimelineItemEncryptedView_Night_1_en",20056,], +["features.messages.impl.timeline.components.event_TimelineItemEncryptedView_Day_2_en","features.messages.impl.timeline.components.event_TimelineItemEncryptedView_Night_2_en",20059,], +["features.messages.impl.timeline.components.event_TimelineItemEncryptedView_Day_3_en","features.messages.impl.timeline.components.event_TimelineItemEncryptedView_Night_3_en",20059,], +["features.messages.impl.timeline.components.event_TimelineItemEncryptedView_Day_4_en","features.messages.impl.timeline.components.event_TimelineItemEncryptedView_Night_4_en",20056,], ["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,], @@ -1073,17 +1078,17 @@ 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",20049,], -["features.messages.impl.timeline.components_TimelineItemEventRowTimestamp_Day_4_en","features.messages.impl.timeline.components_TimelineItemEventRowTimestamp_Night_4_en",20049,], +["features.messages.impl.timeline.components_TimelineItemEventRowTimestamp_Day_3_en","features.messages.impl.timeline.components_TimelineItemEventRowTimestamp_Night_3_en",20056,], +["features.messages.impl.timeline.components_TimelineItemEventRowTimestamp_Day_4_en","features.messages.impl.timeline.components_TimelineItemEventRowTimestamp_Night_4_en",20056,], ["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_TimelineItemEventRowUtd_Day_0_en","features.messages.impl.timeline.components_TimelineItemEventRowUtd_Night_0_en",20049,], -["features.messages.impl.timeline.components_TimelineItemEventRowWithManyReactions_Day_0_en","features.messages.impl.timeline.components_TimelineItemEventRowWithManyReactions_Night_0_en",20049,], +["features.messages.impl.timeline.components_TimelineItemEventRowUtd_Day_0_en","features.messages.impl.timeline.components_TimelineItemEventRowUtd_Night_0_en",20056,], +["features.messages.impl.timeline.components_TimelineItemEventRowWithManyReactions_Day_0_en","features.messages.impl.timeline.components_TimelineItemEventRowWithManyReactions_Night_0_en",20056,], ["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",20049,], -["features.messages.impl.timeline.components_TimelineItemEventRowWithReplyInformative_Day_1_en","features.messages.impl.timeline.components_TimelineItemEventRowWithReplyInformative_Night_1_en",20049,], +["features.messages.impl.timeline.components_TimelineItemEventRowWithReplyInformative_Day_0_en","features.messages.impl.timeline.components_TimelineItemEventRowWithReplyInformative_Night_0_en",20056,], +["features.messages.impl.timeline.components_TimelineItemEventRowWithReplyInformative_Day_1_en","features.messages.impl.timeline.components_TimelineItemEventRowWithReplyInformative_Night_1_en",20056,], ["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,], @@ -1092,40 +1097,40 @@ 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",20049,], +["features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Day_4_en","features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Night_4_en",20056,], ["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",20049,], +["features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Day_8_en","features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Night_8_en",20056,], ["features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Day_9_en","features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Night_9_en",0,], ["features.messages.impl.timeline.components_TimelineItemEventRow_Day_0_en","features.messages.impl.timeline.components_TimelineItemEventRow_Night_0_en",0,], -["features.messages.impl.timeline.components_TimelineItemEventTimestampBelow_en","",20049,], +["features.messages.impl.timeline.components_TimelineItemEventTimestampBelow_en","",20056,], ["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",20049,], -["features.messages.impl.timeline.components_TimelineItemGroupedEventsRowContentExpanded_Day_0_en","features.messages.impl.timeline.components_TimelineItemGroupedEventsRowContentExpanded_Night_0_en",20049,], -["features.messages.impl.timeline.components.event_TimelineItemImageViewHideMediaContent_Day_0_en","features.messages.impl.timeline.components.event_TimelineItemImageViewHideMediaContent_Night_0_en",0,], +["features.messages.impl.timeline.components_TimelineItemGroupedEventsRowContentCollapse_Day_0_en","features.messages.impl.timeline.components_TimelineItemGroupedEventsRowContentCollapse_Night_0_en",20056,], +["features.messages.impl.timeline.components_TimelineItemGroupedEventsRowContentExpanded_Day_0_en","features.messages.impl.timeline.components_TimelineItemGroupedEventsRowContentExpanded_Night_0_en",20056,], +["features.messages.impl.timeline.components.event_TimelineItemImageViewHideMediaContent_Day_0_en","features.messages.impl.timeline.components.event_TimelineItemImageViewHideMediaContent_Night_0_en",20059,], ["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",0,], +["features.messages.impl.timeline.components.event_TimelineItemLegacyCallInviteView_Day_0_en","features.messages.impl.timeline.components.event_TimelineItemLegacyCallInviteView_Night_0_en",20059,], ["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",20049,], -["features.messages.impl.timeline.components.event_TimelineItemPollView_Day_1_en","features.messages.impl.timeline.components.event_TimelineItemPollView_Night_1_en",20049,], -["features.messages.impl.timeline.components.event_TimelineItemPollView_Day_2_en","features.messages.impl.timeline.components.event_TimelineItemPollView_Night_2_en",20049,], -["features.messages.impl.timeline.components.event_TimelineItemPollView_Day_3_en","features.messages.impl.timeline.components.event_TimelineItemPollView_Night_3_en",20049,], -["features.messages.impl.timeline.components_TimelineItemReactionsLayout_Day_0_en","features.messages.impl.timeline.components_TimelineItemReactionsLayout_Night_0_en",20049,], +["features.messages.impl.timeline.components.event_TimelineItemPollView_Day_0_en","features.messages.impl.timeline.components.event_TimelineItemPollView_Night_0_en",20056,], +["features.messages.impl.timeline.components.event_TimelineItemPollView_Day_1_en","features.messages.impl.timeline.components.event_TimelineItemPollView_Night_1_en",20056,], +["features.messages.impl.timeline.components.event_TimelineItemPollView_Day_2_en","features.messages.impl.timeline.components.event_TimelineItemPollView_Night_2_en",20056,], +["features.messages.impl.timeline.components.event_TimelineItemPollView_Day_3_en","features.messages.impl.timeline.components.event_TimelineItemPollView_Night_3_en",20056,], +["features.messages.impl.timeline.components_TimelineItemReactionsLayout_Day_0_en","features.messages.impl.timeline.components_TimelineItemReactionsLayout_Night_0_en",20056,], ["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",20049,], -["features.messages.impl.timeline.components_TimelineItemReactionsViewOutgoing_Day_0_en","features.messages.impl.timeline.components_TimelineItemReactionsViewOutgoing_Night_0_en",20049,], +["features.messages.impl.timeline.components_TimelineItemReactionsViewIncoming_Day_0_en","features.messages.impl.timeline.components_TimelineItemReactionsViewIncoming_Night_0_en",20056,], +["features.messages.impl.timeline.components_TimelineItemReactionsViewOutgoing_Day_0_en","features.messages.impl.timeline.components_TimelineItemReactionsViewOutgoing_Night_0_en",20056,], ["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",20049,], +["features.messages.impl.timeline.components.virtual_TimelineItemReadMarkerView_Day_0_en","features.messages.impl.timeline.components.virtual_TimelineItemReadMarkerView_Night_0_en",20056,], ["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,], @@ -1134,8 +1139,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",20049,], -["features.messages.impl.timeline.components.virtual_TimelineItemRoomBeginningView_Day_0_en","features.messages.impl.timeline.components.virtual_TimelineItemRoomBeginningView_Night_0_en",20049,], +["features.messages.impl.timeline.components.event_TimelineItemRedactedView_Day_0_en","features.messages.impl.timeline.components.event_TimelineItemRedactedView_Night_0_en",20056,], +["features.messages.impl.timeline.components.virtual_TimelineItemRoomBeginningView_Day_0_en","features.messages.impl.timeline.components.virtual_TimelineItemRoomBeginningView_Night_0_en",20056,], ["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,], @@ -1148,8 +1153,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",20049,], -["features.messages.impl.timeline.components.event_TimelineItemVideoViewHideMediaContent_Day_0_en","features.messages.impl.timeline.components.event_TimelineItemVideoViewHideMediaContent_Night_0_en",0,], +["features.messages.impl.timeline.components.event_TimelineItemUnknownView_Day_0_en","features.messages.impl.timeline.components.event_TimelineItemUnknownView_Night_0_en",20056,], +["features.messages.impl.timeline.components.event_TimelineItemVideoViewHideMediaContent_Day_0_en","features.messages.impl.timeline.components.event_TimelineItemVideoViewHideMediaContent_Night_0_en",20059,], ["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,], @@ -1172,84 +1177,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",20049,], -["features.messages.impl.timeline_TimelineView_Day_0_en","features.messages.impl.timeline_TimelineView_Night_0_en",20049,], +["features.messages.impl.timeline_TimelineViewMessageShield_Day_0_en","features.messages.impl.timeline_TimelineViewMessageShield_Night_0_en",20056,], +["features.messages.impl.timeline_TimelineView_Day_0_en","features.messages.impl.timeline_TimelineView_Night_0_en",20056,], ["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",20049,], -["features.messages.impl.timeline_TimelineView_Day_12_en","features.messages.impl.timeline_TimelineView_Night_12_en",20049,], -["features.messages.impl.timeline_TimelineView_Day_13_en","features.messages.impl.timeline_TimelineView_Night_13_en",20049,], -["features.messages.impl.timeline_TimelineView_Day_14_en","features.messages.impl.timeline_TimelineView_Night_14_en",20049,], -["features.messages.impl.timeline_TimelineView_Day_15_en","features.messages.impl.timeline_TimelineView_Night_15_en",20049,], -["features.messages.impl.timeline_TimelineView_Day_16_en","features.messages.impl.timeline_TimelineView_Night_16_en",20049,], -["features.messages.impl.timeline_TimelineView_Day_17_en","features.messages.impl.timeline_TimelineView_Night_17_en",20049,], -["features.messages.impl.timeline_TimelineView_Day_1_en","features.messages.impl.timeline_TimelineView_Night_1_en",20049,], +["features.messages.impl.timeline_TimelineView_Day_11_en","features.messages.impl.timeline_TimelineView_Night_11_en",20056,], +["features.messages.impl.timeline_TimelineView_Day_12_en","features.messages.impl.timeline_TimelineView_Night_12_en",20056,], +["features.messages.impl.timeline_TimelineView_Day_13_en","features.messages.impl.timeline_TimelineView_Night_13_en",20056,], +["features.messages.impl.timeline_TimelineView_Day_14_en","features.messages.impl.timeline_TimelineView_Night_14_en",20056,], +["features.messages.impl.timeline_TimelineView_Day_15_en","features.messages.impl.timeline_TimelineView_Night_15_en",20056,], +["features.messages.impl.timeline_TimelineView_Day_16_en","features.messages.impl.timeline_TimelineView_Night_16_en",20056,], +["features.messages.impl.timeline_TimelineView_Day_17_en","features.messages.impl.timeline_TimelineView_Night_17_en",20056,], +["features.messages.impl.timeline_TimelineView_Day_1_en","features.messages.impl.timeline_TimelineView_Night_1_en",20056,], ["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",20049,], +["features.messages.impl.timeline_TimelineView_Day_4_en","features.messages.impl.timeline_TimelineView_Night_4_en",20056,], ["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",20049,], +["features.messages.impl.timeline_TimelineView_Day_6_en","features.messages.impl.timeline_TimelineView_Night_6_en",20056,], ["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",20049,], +["features.messages.impl.timeline_TimelineView_Day_8_en","features.messages.impl.timeline_TimelineView_Night_8_en",20056,], ["features.messages.impl.timeline_TimelineView_Day_9_en","features.messages.impl.timeline_TimelineView_Night_9_en",0,], ["libraries.designsystem.theme.components_TopAppBar_App_Bars_en","",0,], -["libraries.troubleshoot.impl_TroubleshootNotificationsView_Day_0_en","libraries.troubleshoot.impl_TroubleshootNotificationsView_Night_0_en",20049,], -["libraries.troubleshoot.impl_TroubleshootNotificationsView_Day_1_en","libraries.troubleshoot.impl_TroubleshootNotificationsView_Night_1_en",20049,], -["libraries.troubleshoot.impl_TroubleshootNotificationsView_Day_2_en","libraries.troubleshoot.impl_TroubleshootNotificationsView_Night_2_en",20049,], -["libraries.troubleshoot.impl_TroubleshootNotificationsView_Day_3_en","libraries.troubleshoot.impl_TroubleshootNotificationsView_Night_3_en",20049,], -["libraries.troubleshoot.impl_TroubleshootNotificationsView_Day_4_en","libraries.troubleshoot.impl_TroubleshootNotificationsView_Night_4_en",20049,], -["libraries.troubleshoot.impl_TroubleshootNotificationsView_Day_5_en","libraries.troubleshoot.impl_TroubleshootNotificationsView_Night_5_en",20049,], -["libraries.troubleshoot.impl_TroubleshootNotificationsView_Day_6_en","libraries.troubleshoot.impl_TroubleshootNotificationsView_Night_6_en",20049,], -["libraries.troubleshoot.impl_TroubleshootNotificationsView_Day_7_en","libraries.troubleshoot.impl_TroubleshootNotificationsView_Night_7_en",20049,], +["libraries.troubleshoot.impl_TroubleshootNotificationsView_Day_0_en","libraries.troubleshoot.impl_TroubleshootNotificationsView_Night_0_en",20056,], +["libraries.troubleshoot.impl_TroubleshootNotificationsView_Day_1_en","libraries.troubleshoot.impl_TroubleshootNotificationsView_Night_1_en",20056,], +["libraries.troubleshoot.impl_TroubleshootNotificationsView_Day_2_en","libraries.troubleshoot.impl_TroubleshootNotificationsView_Night_2_en",20056,], +["libraries.troubleshoot.impl_TroubleshootNotificationsView_Day_3_en","libraries.troubleshoot.impl_TroubleshootNotificationsView_Night_3_en",20056,], +["libraries.troubleshoot.impl_TroubleshootNotificationsView_Day_4_en","libraries.troubleshoot.impl_TroubleshootNotificationsView_Night_4_en",20056,], +["libraries.troubleshoot.impl_TroubleshootNotificationsView_Day_5_en","libraries.troubleshoot.impl_TroubleshootNotificationsView_Night_5_en",20056,], +["libraries.troubleshoot.impl_TroubleshootNotificationsView_Day_6_en","libraries.troubleshoot.impl_TroubleshootNotificationsView_Night_6_en",20056,], +["libraries.troubleshoot.impl_TroubleshootNotificationsView_Day_7_en","libraries.troubleshoot.impl_TroubleshootNotificationsView_Night_7_en",20056,], ["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",20049,], -["features.messages.impl.typing_TypingNotificationView_Day_2_en","features.messages.impl.typing_TypingNotificationView_Night_2_en",20049,], -["features.messages.impl.typing_TypingNotificationView_Day_3_en","features.messages.impl.typing_TypingNotificationView_Night_3_en",20049,], -["features.messages.impl.typing_TypingNotificationView_Day_4_en","features.messages.impl.typing_TypingNotificationView_Night_4_en",20049,], -["features.messages.impl.typing_TypingNotificationView_Day_5_en","features.messages.impl.typing_TypingNotificationView_Night_5_en",20049,], -["features.messages.impl.typing_TypingNotificationView_Day_6_en","features.messages.impl.typing_TypingNotificationView_Night_6_en",20049,], +["features.messages.impl.typing_TypingNotificationView_Day_1_en","features.messages.impl.typing_TypingNotificationView_Night_1_en",20056,], +["features.messages.impl.typing_TypingNotificationView_Day_2_en","features.messages.impl.typing_TypingNotificationView_Night_2_en",20056,], +["features.messages.impl.typing_TypingNotificationView_Day_3_en","features.messages.impl.typing_TypingNotificationView_Night_3_en",20056,], +["features.messages.impl.typing_TypingNotificationView_Day_4_en","features.messages.impl.typing_TypingNotificationView_Night_4_en",20056,], +["features.messages.impl.typing_TypingNotificationView_Day_5_en","features.messages.impl.typing_TypingNotificationView_Night_5_en",20056,], +["features.messages.impl.typing_TypingNotificationView_Day_6_en","features.messages.impl.typing_TypingNotificationView_Night_6_en",20056,], ["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","",20049,], +["libraries.matrix.ui.components_UnresolvedUserRow_en","",20056,], ["libraries.matrix.ui.components_UnsavedAvatar_Day_0_en","libraries.matrix.ui.components_UnsavedAvatar_Night_0_en",0,], ["libraries.designsystem.components.avatar_UserAvatarColors_Day_0_en","libraries.designsystem.components.avatar_UserAvatarColors_Night_0_en",0,], -["features.roomdetails.impl.notificationsettings_UserDefinedRoomNotificationSettingsView_Day_0_en","features.roomdetails.impl.notificationsettings_UserDefinedRoomNotificationSettingsView_Night_0_en",20049,], -["features.createroom.impl.components_UserListView_Day_0_en","features.createroom.impl.components_UserListView_Night_0_en",20049,], -["features.createroom.impl.components_UserListView_Day_1_en","features.createroom.impl.components_UserListView_Night_1_en",20049,], -["features.createroom.impl.components_UserListView_Day_2_en","features.createroom.impl.components_UserListView_Night_2_en",20049,], +["features.roomdetails.impl.notificationsettings_UserDefinedRoomNotificationSettingsView_Day_0_en","features.roomdetails.impl.notificationsettings_UserDefinedRoomNotificationSettingsView_Night_0_en",20056,], +["features.createroom.impl.components_UserListView_Day_0_en","features.createroom.impl.components_UserListView_Night_0_en",20056,], +["features.createroom.impl.components_UserListView_Day_1_en","features.createroom.impl.components_UserListView_Night_1_en",20056,], +["features.createroom.impl.components_UserListView_Day_2_en","features.createroom.impl.components_UserListView_Night_2_en",20056,], ["features.createroom.impl.components_UserListView_Day_3_en","features.createroom.impl.components_UserListView_Night_3_en",0,], ["features.createroom.impl.components_UserListView_Day_4_en","features.createroom.impl.components_UserListView_Night_4_en",0,], ["features.createroom.impl.components_UserListView_Day_5_en","features.createroom.impl.components_UserListView_Night_5_en",0,], ["features.createroom.impl.components_UserListView_Day_6_en","features.createroom.impl.components_UserListView_Night_6_en",0,], -["features.createroom.impl.components_UserListView_Day_7_en","features.createroom.impl.components_UserListView_Night_7_en",20049,], +["features.createroom.impl.components_UserListView_Day_7_en","features.createroom.impl.components_UserListView_Night_7_en",20056,], ["features.createroom.impl.components_UserListView_Day_8_en","features.createroom.impl.components_UserListView_Night_8_en",0,], -["features.createroom.impl.components_UserListView_Day_9_en","features.createroom.impl.components_UserListView_Night_9_en",20049,], +["features.createroom.impl.components_UserListView_Day_9_en","features.createroom.impl.components_UserListView_Night_9_en",20056,], ["features.preferences.impl.user_UserPreferences_Day_0_en","features.preferences.impl.user_UserPreferences_Night_0_en",0,], ["features.preferences.impl.user_UserPreferences_Day_1_en","features.preferences.impl.user_UserPreferences_Night_1_en",0,], ["features.preferences.impl.user_UserPreferences_Day_2_en","features.preferences.impl.user_UserPreferences_Night_2_en",0,], -["features.userprofile.shared_UserProfileHeaderSection_Day_0_en","features.userprofile.shared_UserProfileHeaderSection_Night_0_en",0,], -["features.userprofile.shared_UserProfileView_Day_0_en","features.userprofile.shared_UserProfileView_Night_0_en",20049,], -["features.userprofile.shared_UserProfileView_Day_1_en","features.userprofile.shared_UserProfileView_Night_1_en",20049,], -["features.userprofile.shared_UserProfileView_Day_2_en","features.userprofile.shared_UserProfileView_Night_2_en",20049,], -["features.userprofile.shared_UserProfileView_Day_3_en","features.userprofile.shared_UserProfileView_Night_3_en",20049,], -["features.userprofile.shared_UserProfileView_Day_4_en","features.userprofile.shared_UserProfileView_Night_4_en",20049,], -["features.userprofile.shared_UserProfileView_Day_5_en","features.userprofile.shared_UserProfileView_Night_5_en",20049,], -["features.userprofile.shared_UserProfileView_Day_6_en","features.userprofile.shared_UserProfileView_Night_6_en",20049,], -["features.userprofile.shared_UserProfileView_Day_7_en","features.userprofile.shared_UserProfileView_Night_7_en",20049,], -["features.verifysession.impl.outgoing_VerifySelfSessionView_Day_0_en","features.verifysession.impl.outgoing_VerifySelfSessionView_Night_0_en",20049,], -["features.verifysession.impl.outgoing_VerifySelfSessionView_Day_10_en","features.verifysession.impl.outgoing_VerifySelfSessionView_Night_10_en",20049,], +["features.userprofile.shared_UserProfileHeaderSection_Day_0_en","features.userprofile.shared_UserProfileHeaderSection_Night_0_en",20059,], +["features.userprofile.shared_UserProfileView_Day_0_en","features.userprofile.shared_UserProfileView_Night_0_en",20056,], +["features.userprofile.shared_UserProfileView_Day_1_en","features.userprofile.shared_UserProfileView_Night_1_en",20056,], +["features.userprofile.shared_UserProfileView_Day_2_en","features.userprofile.shared_UserProfileView_Night_2_en",20056,], +["features.userprofile.shared_UserProfileView_Day_3_en","features.userprofile.shared_UserProfileView_Night_3_en",20056,], +["features.userprofile.shared_UserProfileView_Day_4_en","features.userprofile.shared_UserProfileView_Night_4_en",20056,], +["features.userprofile.shared_UserProfileView_Day_5_en","features.userprofile.shared_UserProfileView_Night_5_en",20056,], +["features.userprofile.shared_UserProfileView_Day_6_en","features.userprofile.shared_UserProfileView_Night_6_en",20056,], +["features.userprofile.shared_UserProfileView_Day_7_en","features.userprofile.shared_UserProfileView_Night_7_en",20056,], +["features.verifysession.impl.outgoing_VerifySelfSessionView_Day_0_en","features.verifysession.impl.outgoing_VerifySelfSessionView_Night_0_en",20056,], +["features.verifysession.impl.outgoing_VerifySelfSessionView_Day_10_en","features.verifysession.impl.outgoing_VerifySelfSessionView_Night_10_en",20056,], ["features.verifysession.impl.outgoing_VerifySelfSessionView_Day_11_en","features.verifysession.impl.outgoing_VerifySelfSessionView_Night_11_en",0,], ["features.verifysession.impl.outgoing_VerifySelfSessionView_Day_12_en","features.verifysession.impl.outgoing_VerifySelfSessionView_Night_12_en",0,], -["features.verifysession.impl.outgoing_VerifySelfSessionView_Day_13_en","features.verifysession.impl.outgoing_VerifySelfSessionView_Night_13_en",20049,], -["features.verifysession.impl.outgoing_VerifySelfSessionView_Day_1_en","features.verifysession.impl.outgoing_VerifySelfSessionView_Night_1_en",20049,], -["features.verifysession.impl.outgoing_VerifySelfSessionView_Day_2_en","features.verifysession.impl.outgoing_VerifySelfSessionView_Night_2_en",20049,], -["features.verifysession.impl.outgoing_VerifySelfSessionView_Day_3_en","features.verifysession.impl.outgoing_VerifySelfSessionView_Night_3_en",20049,], -["features.verifysession.impl.outgoing_VerifySelfSessionView_Day_4_en","features.verifysession.impl.outgoing_VerifySelfSessionView_Night_4_en",20049,], -["features.verifysession.impl.outgoing_VerifySelfSessionView_Day_5_en","features.verifysession.impl.outgoing_VerifySelfSessionView_Night_5_en",20049,], -["features.verifysession.impl.outgoing_VerifySelfSessionView_Day_6_en","features.verifysession.impl.outgoing_VerifySelfSessionView_Night_6_en",20049,], -["features.verifysession.impl.outgoing_VerifySelfSessionView_Day_7_en","features.verifysession.impl.outgoing_VerifySelfSessionView_Night_7_en",20049,], -["features.verifysession.impl.outgoing_VerifySelfSessionView_Day_8_en","features.verifysession.impl.outgoing_VerifySelfSessionView_Night_8_en",20049,], -["features.verifysession.impl.outgoing_VerifySelfSessionView_Day_9_en","features.verifysession.impl.outgoing_VerifySelfSessionView_Night_9_en",20049,], +["features.verifysession.impl.outgoing_VerifySelfSessionView_Day_13_en","features.verifysession.impl.outgoing_VerifySelfSessionView_Night_13_en",20056,], +["features.verifysession.impl.outgoing_VerifySelfSessionView_Day_1_en","features.verifysession.impl.outgoing_VerifySelfSessionView_Night_1_en",20056,], +["features.verifysession.impl.outgoing_VerifySelfSessionView_Day_2_en","features.verifysession.impl.outgoing_VerifySelfSessionView_Night_2_en",20056,], +["features.verifysession.impl.outgoing_VerifySelfSessionView_Day_3_en","features.verifysession.impl.outgoing_VerifySelfSessionView_Night_3_en",20056,], +["features.verifysession.impl.outgoing_VerifySelfSessionView_Day_4_en","features.verifysession.impl.outgoing_VerifySelfSessionView_Night_4_en",20056,], +["features.verifysession.impl.outgoing_VerifySelfSessionView_Day_5_en","features.verifysession.impl.outgoing_VerifySelfSessionView_Night_5_en",20056,], +["features.verifysession.impl.outgoing_VerifySelfSessionView_Day_6_en","features.verifysession.impl.outgoing_VerifySelfSessionView_Night_6_en",20056,], +["features.verifysession.impl.outgoing_VerifySelfSessionView_Day_7_en","features.verifysession.impl.outgoing_VerifySelfSessionView_Night_7_en",20056,], +["features.verifysession.impl.outgoing_VerifySelfSessionView_Day_8_en","features.verifysession.impl.outgoing_VerifySelfSessionView_Night_8_en",20056,], +["features.verifysession.impl.outgoing_VerifySelfSessionView_Day_9_en","features.verifysession.impl.outgoing_VerifySelfSessionView_Night_9_en",20056,], ["libraries.designsystem.ruler_VerticalRuler_Day_0_en","libraries.designsystem.ruler_VerticalRuler_Night_0_en",0,], ["features.viewfolder.impl.file_ViewFileView_Day_0_en","features.viewfolder.impl.file_ViewFileView_Night_0_en",0,], ["features.viewfolder.impl.file_ViewFileView_Day_1_en","features.viewfolder.impl.file_ViewFileView_Night_1_en",0,], @@ -1264,6 +1269,6 @@ export const screenshots = [ ["libraries.textcomposer.components_VoiceMessageRecording_Day_0_en","libraries.textcomposer.components_VoiceMessageRecording_Night_0_en",0,], ["libraries.textcomposer.components_VoiceMessage_Day_0_en","libraries.textcomposer.components_VoiceMessage_Night_0_en",0,], ["libraries.designsystem.components.media_WaveformPlaybackView_Day_0_en","libraries.designsystem.components.media_WaveformPlaybackView_Night_0_en",0,], -["features.ftue.impl.welcome_WelcomeView_Day_0_en","features.ftue.impl.welcome_WelcomeView_Night_0_en",20049,], +["features.ftue.impl.welcome_WelcomeView_Day_0_en","features.ftue.impl.welcome_WelcomeView_Night_0_en",20056,], ["libraries.designsystem.ruler_WithRulers_Day_0_en","libraries.designsystem.ruler_WithRulers_Night_0_en",0,], ]; diff --git a/tests/uitests/src/test/snapshots/images/features.createroom.impl.configureroom_ConfigureRoomViewDark_3_en.png b/tests/uitests/src/test/snapshots/images/features.createroom.impl.configureroom_ConfigureRoomViewDark_3_en.png index 80352e80836..9c82b817856 100644 --- a/tests/uitests/src/test/snapshots/images/features.createroom.impl.configureroom_ConfigureRoomViewDark_3_en.png +++ b/tests/uitests/src/test/snapshots/images/features.createroom.impl.configureroom_ConfigureRoomViewDark_3_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:564e7609bc44d06e095e01113333793a85b1ffa5f5ad2eb0523ad073661a941a -size 56894 +oid sha256:d99e10bf3d0322ed25d883aa80376b0f1bd92d8174a6623e099272b4002fbfc4 +size 56880 diff --git a/tests/uitests/src/test/snapshots/images/features.createroom.impl.configureroom_ConfigureRoomViewLight_3_en.png b/tests/uitests/src/test/snapshots/images/features.createroom.impl.configureroom_ConfigureRoomViewLight_3_en.png index 800d6888075..0f5a5043b97 100644 --- a/tests/uitests/src/test/snapshots/images/features.createroom.impl.configureroom_ConfigureRoomViewLight_3_en.png +++ b/tests/uitests/src/test/snapshots/images/features.createroom.impl.configureroom_ConfigureRoomViewLight_3_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f3dfce838e3fb0ba5cc3063f5057926872b85a213ad8852f98ff609386ca18f5 -size 58705 +oid sha256:9426c57dc59d8341087b3800a40847e63b8e6ee3c4e65cfe1712b3f5fa884618 +size 58696 From 1b10aa4f8f03f5f01545208ae253dd1d7a9908ea Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Mon, 2 Dec 2024 09:07:08 +0100 Subject: [PATCH 66/96] Exclude ExoPlayerForPreview from coverage metrics. --- .../mediaviewer/impl/local/video/ExoPlayerForPreview.kt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/video/ExoPlayerForPreview.kt b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/video/ExoPlayerForPreview.kt index 21f107ec959..c5176375767 100644 --- a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/video/ExoPlayerForPreview.kt +++ b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/video/ExoPlayerForPreview.kt @@ -53,8 +53,10 @@ import androidx.media3.exoplayer.trackselection.TrackSelectionArray import androidx.media3.exoplayer.trackselection.TrackSelector import androidx.media3.exoplayer.video.VideoFrameMetadataListener import androidx.media3.exoplayer.video.spherical.CameraMotionListener +import io.element.android.libraries.architecture.coverage.ExcludeFromCoverage @SuppressLint("UnsafeOptInUsageError") +@ExcludeFromCoverage class ExoPlayerForPreview( private val isPlaying: Boolean = false, ) : ExoPlayer { From 181cf56791078da1d3179bd580d1e0582d40b90c Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 2 Dec 2024 08:19:42 +0000 Subject: [PATCH 67/96] fix(deps): update dependency com.sigpwned:emoji4j-core to v16 --- 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 1bcab24c19f..00c4e1ce71a 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -201,7 +201,7 @@ matrix_analytics_events = "com.github.matrix-org:matrix-analytics-events:0.28.0" # Emojibase matrix_emojibase_bindings = "io.element.android:emojibase-bindings:1.3.3" -sigpwned_emoji4j = "com.sigpwned:emoji4j-core:15.1.2" +sigpwned_emoji4j = "com.sigpwned:emoji4j-core:16.0.0" # Di inject = "javax.inject:javax.inject:1" From 1ee8676b19093c485cda211a01cab411fd06791d Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Fri, 29 Nov 2024 11:33:24 +0100 Subject: [PATCH 68/96] Do not auto-play videos. --- .../impl/local/video/MediaVideoView.kt | 20 +++++++++---------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/video/MediaVideoView.kt b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/video/MediaVideoView.kt index d9785491924..bb4e47d9720 100644 --- a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/video/MediaVideoView.kt +++ b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/video/MediaVideoView.kt @@ -80,11 +80,10 @@ private fun ExoPlayerMediaVideoView( localMedia: LocalMedia?, modifier: Modifier = Modifier, ) { - val isControllerVisibleByDefault = LocalInspectionMode.current var mediaPlayerControllerState: MediaPlayerControllerState by remember { mutableStateOf( MediaPlayerControllerState( - isVisible = isControllerVisibleByDefault, + isVisible = true, isPlaying = false, progressInMillis = 0, durationInMillis = 0, @@ -122,18 +121,16 @@ private fun ExoPlayerMediaVideoView( override fun onTimelineChanged(timeline: Timeline, reason: Int) { if (reason == Player.TIMELINE_CHANGE_REASON_SOURCE_UPDATE) { - mediaPlayerControllerState = mediaPlayerControllerState.copy( - durationInMillis = exoPlayer.duration, - ) + exoPlayer.duration.takeIf { it >= 0 } + ?.let { + mediaPlayerControllerState = mediaPlayerControllerState.copy( + durationInMillis = it, + ) + } } } } - LaunchedEffect(Unit) { - exoPlayer.addListener(playerListener) - exoPlayer.prepare() - } - var autoHideController by remember { mutableIntStateOf(0) } LaunchedEffect(autoHideController) { @@ -238,7 +235,8 @@ private fun ExoPlayerMediaVideoView( OnLifecycleEvent { _, event -> when (event) { - Lifecycle.Event.ON_RESUME -> exoPlayer.play() + Lifecycle.Event.ON_CREATE -> exoPlayer.addListener(playerListener) + Lifecycle.Event.ON_RESUME -> exoPlayer.prepare() Lifecycle.Event.ON_PAUSE -> exoPlayer.pause() Lifecycle.Event.ON_DESTROY -> { exoPlayer.release() From bcac193b12b909c17b0b49f5fda5167c8cc08bad Mon Sep 17 00:00:00 2001 From: Valere Date: Mon, 2 Dec 2024 14:50:10 +0100 Subject: [PATCH 69/96] feat(crypto): Support new expected UTD causes UX + Analytics --- .../event/TimelineItemEncryptedView.kt | 9 +++++++++ .../TimelineItemEncryptedContentProvider.kt | 18 ++++++++++++++++++ .../api/timeline/item/event/UtdCause.kt | 19 ++++++++++++++++++- .../matrix/impl/analytics/UtdTracker.kt | 3 +++ .../item/event/TimelineEventContentMapper.kt | 3 +++ .../src/main/res/values/localazy.xml | 3 +++ 6 files changed, 54 insertions(+), 1 deletion(-) diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/event/TimelineItemEncryptedView.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/event/TimelineItemEncryptedView.kt index e84f7ccbc22..b91b4ccc172 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/event/TimelineItemEncryptedView.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/event/TimelineItemEncryptedView.kt @@ -40,6 +40,15 @@ fun TimelineItemEncryptedView( UtdCause.UnknownDevice -> { CommonStrings.common_unable_to_decrypt_insecure_device to CompoundDrawables.ic_compound_block } + UtdCause.HistoricalMessage -> { + CommonStrings.timeline_decryption_failure_historical_event_no_key_backup to CompoundDrawables.ic_compound_block + } + UtdCause.WithheldUnverifiedOrInsecureDevice -> { + CommonStrings.timeline_decryption_failure_withheld_unverified to CompoundDrawables.ic_compound_block + } + UtdCause.WithheldBySender -> { + CommonStrings.timeline_decryption_failure_unable_to_decrypt to CompoundDrawables.ic_compound_error + } else -> { CommonStrings.common_waiting_for_decryption_key to CompoundDrawables.ic_compound_time } diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/model/event/TimelineItemEncryptedContentProvider.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/model/event/TimelineItemEncryptedContentProvider.kt index 7aa44e03f0f..b312024ebb7 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/model/event/TimelineItemEncryptedContentProvider.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/model/event/TimelineItemEncryptedContentProvider.kt @@ -33,6 +33,24 @@ open class TimelineItemEncryptedContentProvider : PreviewParameterProvider { Error.Name.ExpectedSentByInsecureDevice } + UtdCause.HISTORICAL_MESSAGE -> Error.Name.HistoricalMessage + UtdCause.WITHHELD_FOR_UNVERIFIED_OR_INSECURE_DEVICE -> Error.Name.RoomKeysWithheldForUnverifiedDevice + UtdCause.WITHHELD_BY_SENDER -> Error.Name.OlmKeysNotSentError } val event = Error( context = null, diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/item/event/TimelineEventContentMapper.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/item/event/TimelineEventContentMapper.kt index f85dc5acc1c..6e079ffe3f5 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/item/event/TimelineEventContentMapper.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/item/event/TimelineEventContentMapper.kt @@ -145,6 +145,9 @@ private fun RustUtdCause.map(): UtdCause { RustUtdCause.VERIFICATION_VIOLATION -> UtdCause.VerificationViolation RustUtdCause.UNSIGNED_DEVICE -> UtdCause.UnsignedDevice RustUtdCause.UNKNOWN_DEVICE -> UtdCause.UnknownDevice + RustUtdCause.HISTORICAL_MESSAGE -> UtdCause.HistoricalMessage + RustUtdCause.WITHHELD_FOR_UNVERIFIED_OR_INSECURE_DEVICE -> UtdCause.WithheldUnverifiedOrInsecureDevice + RustUtdCause.WITHHELD_BY_SENDER -> UtdCause.WithheldBySender } } diff --git a/libraries/ui-strings/src/main/res/values/localazy.xml b/libraries/ui-strings/src/main/res/values/localazy.xml index 9d6e87db99a..02c85887ae8 100644 --- a/libraries/ui-strings/src/main/res/values/localazy.xml +++ b/libraries/ui-strings/src/main/res/values/localazy.xml @@ -365,4 +365,7 @@ Reason: %1$s." "Version: %1$s (%2$s)" "en" "en" + "Historical messages are not available on this device" + "Unable to decrypt message" + "This message was blocked either because your device is unverified or because the sender needs to verify your identity." From 94ebac7e74c476c84e2154d0ed421136abce5874 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Mon, 2 Dec 2024 15:53:40 +0100 Subject: [PATCH 70/96] Add warning when adding a caption. --- .../messages/impl/MessagesPresenter.kt | 6 +- .../preview/AttachmentsPreviewPresenter.kt | 2 + .../preview/AttachmentsPreviewState.kt | 1 + .../AttachmentsPreviewStateProvider.kt | 3 + .../preview/AttachmentsPreviewView.kt | 5 +- .../messages/impl/MessagesPresenterTest.kt | 66 ++++++++++++- .../AttachmentsPreviewPresenterTest.kt | 16 ++- .../MessageComposerPresenterTest.kt | 7 +- .../libraries/featureflag/api/FeatureFlags.kt | 9 +- .../textcomposer/CaptionWarningBottomSheet.kt | 73 ++++++++++++++ .../libraries/textcomposer/TextComposer.kt | 97 ++++++++++++------- .../textcomposer/model/MessageComposerMode.kt | 16 ++- .../impl/src/main/res/values/localazy.xml | 2 +- 13 files changed, 260 insertions(+), 43 deletions(-) create mode 100644 libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/CaptionWarningBottomSheet.kt diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesPresenter.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesPresenter.kt index 5a68b5cc9ee..4895390ab87 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesPresenter.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesPresenter.kt @@ -402,26 +402,28 @@ class MessagesPresenter @AssistedInject constructor( } } - private fun handleActionAddCaption( + private suspend fun handleActionAddCaption( targetEvent: TimelineItem.Event, composerState: MessageComposerState, ) { val composerMode = MessageComposerMode.EditCaption( eventOrTransactionId = targetEvent.eventOrTransactionId, content = "", + showCaptionCompatibilityWarning = featureFlagsService.isFeatureEnabled(FeatureFlags.MediaCaptionWarning), ) composerState.eventSink( MessageComposerEvents.SetMode(composerMode) ) } - private fun handleActionEditCaption( + private suspend fun handleActionEditCaption( targetEvent: TimelineItem.Event, composerState: MessageComposerState, ) { val composerMode = MessageComposerMode.EditCaption( eventOrTransactionId = targetEvent.eventOrTransactionId, content = (targetEvent.content as? TimelineItemEventContentWithAttachment)?.caption.orEmpty(), + showCaptionCompatibilityWarning = featureFlagsService.isFeatureEnabled(FeatureFlags.MediaCaptionWarning), ) composerState.eventSink( MessageComposerEvents.SetMode(composerMode) diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/attachments/preview/AttachmentsPreviewPresenter.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/attachments/preview/AttachmentsPreviewPresenter.kt index 606e91863d3..cda414934a3 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/attachments/preview/AttachmentsPreviewPresenter.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/attachments/preview/AttachmentsPreviewPresenter.kt @@ -74,6 +74,7 @@ class AttachmentsPreviewPresenter @AssistedInject constructor( val userSentAttachment = remember { mutableStateOf(false) } val allowCaption by featureFlagService.isFeatureEnabledFlow(FeatureFlags.MediaCaptionCreation).collectAsState(initial = false) + val showCaptionCompatibilityWarning by featureFlagService.isFeatureEnabledFlow(FeatureFlags.MediaCaptionWarning).collectAsState(initial = false) val mediaUploadInfoState = remember { mutableStateOf>(AsyncData.Uninitialized) } LaunchedEffect(Unit) { @@ -145,6 +146,7 @@ class AttachmentsPreviewPresenter @AssistedInject constructor( sendActionState = sendActionState.value, textEditorState = textEditorState, allowCaption = allowCaption, + showCaptionCompatibilityWarning = showCaptionCompatibilityWarning, eventSink = ::handleEvents ) } diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/attachments/preview/AttachmentsPreviewState.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/attachments/preview/AttachmentsPreviewState.kt index 0878b52f803..739efa8d24f 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/attachments/preview/AttachmentsPreviewState.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/attachments/preview/AttachmentsPreviewState.kt @@ -16,6 +16,7 @@ data class AttachmentsPreviewState( val sendActionState: SendActionState, val textEditorState: TextEditorState, val allowCaption: Boolean, + val showCaptionCompatibilityWarning: Boolean, val eventSink: (AttachmentsPreviewEvents) -> Unit ) diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/attachments/preview/AttachmentsPreviewStateProvider.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/attachments/preview/AttachmentsPreviewStateProvider.kt index 1a52316735c..b718936a1cf 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/attachments/preview/AttachmentsPreviewStateProvider.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/attachments/preview/AttachmentsPreviewStateProvider.kt @@ -24,6 +24,7 @@ open class AttachmentsPreviewStateProvider : PreviewParameterProvider() + val presenter = createMessagesPresenter( + messageComposerPresenter = { aMessageComposerState(eventSink = composerRecorder) }, + featureFlagService = FakeFeatureFlagService( + initialState = mapOf(FeatureFlags.MediaCaptionWarning.key to false) + ) + ) + presenter.test { + val initialState = awaitItem() + initialState.eventSink(MessagesEvents.HandleAction(TimelineItemAction.EditCaption, messageEvent)) + awaitItem() + composerRecorder.assertSingle( + MessageComposerEvents.SetMode( + composerMode = MessageComposerMode.EditCaption( + eventOrTransactionId = AN_EVENT_ID.toEventOrTransactionId(), + content = A_CAPTION, + showCaptionCompatibilityWarning = false, ) ) ) @@ -1033,6 +1066,37 @@ class MessagesPresenterTest { composerMode = MessageComposerMode.EditCaption( eventOrTransactionId = AN_EVENT_ID.toEventOrTransactionId(), content = "", + showCaptionCompatibilityWarning = true, + ) + ) + ) + } + } + + @Test + fun `present - handle action add caption without warning`() = runTest { + val composerRecorder = EventsRecorder() + val presenter = createMessagesPresenter( + messageComposerPresenter = { aMessageComposerState(eventSink = composerRecorder) }, + featureFlagService = FakeFeatureFlagService( + initialState = mapOf(FeatureFlags.MediaCaptionWarning.key to false) + ) + ) + val messageEvent = aMessageEvent( + content = aTimelineItemImageContent( + caption = null, + ) + ) + presenter.test { + val initialState = awaitItem() + initialState.eventSink(MessagesEvents.HandleAction(TimelineItemAction.AddCaption, messageEvent)) + awaitItem() + composerRecorder.assertSingle( + MessageComposerEvents.SetMode( + composerMode = MessageComposerMode.EditCaption( + eventOrTransactionId = AN_EVENT_ID.toEventOrTransactionId(), + content = "", + showCaptionCompatibilityWarning = false, ) ) ) @@ -1097,6 +1161,7 @@ class MessagesPresenterTest { givenRoomInfo(aRoomInfo(id = roomId, name = "")) }, navigator: FakeMessagesNavigator = FakeMessagesNavigator(), + featureFlagService: FeatureFlagService = FakeFeatureFlagService(), clipboardHelper: FakeClipboardHelper = FakeClipboardHelper(), analyticsService: FakeAnalyticsService = FakeAnalyticsService(), timelineEventSink: (TimelineEvents) -> Unit = {}, @@ -1109,7 +1174,6 @@ class MessagesPresenterTest { }, actionListEventSink: (ActionListEvents) -> Unit = {}, ): MessagesPresenter { - val featureFlagService = FakeFeatureFlagService() return MessagesPresenter( room = matrixRoom, composerPresenter = messageComposerPresenter, diff --git a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/attachments/AttachmentsPreviewPresenterTest.kt b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/attachments/AttachmentsPreviewPresenterTest.kt index 095b770f082..92e43aa03a7 100644 --- a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/attachments/AttachmentsPreviewPresenterTest.kt +++ b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/attachments/AttachmentsPreviewPresenterTest.kt @@ -67,10 +67,22 @@ class AttachmentsPreviewPresenterTest { @Test fun `present - initial state`() = runTest { createAttachmentsPreviewPresenter().test { - skipItems(1) + skipItems(1) val initialState = awaitItem() assertThat(initialState.sendActionState).isEqualTo(SendActionState.Idle) assertThat(initialState.allowCaption).isTrue() + assertThat(initialState.showCaptionCompatibilityWarning).isTrue() + } + } + + @Test + fun `present - initial state no caption warning`() = runTest { + createAttachmentsPreviewPresenter( + showCaptionCompatibilityWarning = false, + ).test { + skipItems(1) + val initialState = awaitItem() + assertThat(initialState.showCaptionCompatibilityWarning).isFalse() } } @@ -443,6 +455,7 @@ class AttachmentsPreviewPresenterTest { onDoneListener: OnDoneListener = OnDoneListener { lambdaError() }, mediaUploadOnSendQueueEnabled: Boolean = true, allowCaption: Boolean = true, + showCaptionCompatibilityWarning: Boolean = true, ): AttachmentsPreviewPresenter { return AttachmentsPreviewPresenter( attachment = aMediaAttachment(localMedia), @@ -454,6 +467,7 @@ class AttachmentsPreviewPresenterTest { initialState = mapOf( FeatureFlags.MediaUploadOnSendQueue.key to mediaUploadOnSendQueueEnabled, FeatureFlags.MediaCaptionCreation.key to allowCaption, + FeatureFlags.MediaCaptionWarning.key to showCaptionCompatibilityWarning, ), ) ) diff --git a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/messagecomposer/MessageComposerPresenterTest.kt b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/messagecomposer/MessageComposerPresenterTest.kt index d0b41bbb1ee..a56da055aac 100644 --- a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/messagecomposer/MessageComposerPresenterTest.kt +++ b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/messagecomposer/MessageComposerPresenterTest.kt @@ -1586,7 +1586,12 @@ fun anEditMode( fun anEditCaptionMode( eventOrTransactionId: EventOrTransactionId = AN_EVENT_ID.toEventOrTransactionId(), caption: String = A_CAPTION, -) = MessageComposerMode.EditCaption(eventOrTransactionId, caption) + showCaptionCompatibilityWarning: Boolean = false, +) = MessageComposerMode.EditCaption( + eventOrTransactionId = eventOrTransactionId, + content = caption, + showCaptionCompatibilityWarning = showCaptionCompatibilityWarning, +) fun aReplyMode() = MessageComposerMode.Reply( replyToDetails = InReplyToDetails.Loading(AN_EVENT_ID), diff --git a/libraries/featureflag/api/src/main/kotlin/io/element/android/libraries/featureflag/api/FeatureFlags.kt b/libraries/featureflag/api/src/main/kotlin/io/element/android/libraries/featureflag/api/FeatureFlags.kt index 42d9f309207..7d21ed11389 100644 --- a/libraries/featureflag/api/src/main/kotlin/io/element/android/libraries/featureflag/api/FeatureFlags.kt +++ b/libraries/featureflag/api/src/main/kotlin/io/element/android/libraries/featureflag/api/FeatureFlags.kt @@ -144,7 +144,14 @@ enum class FeatureFlags( key = "feature.media_caption_creation", title = "Allow creation of media captions", description = null, - defaultValue = { buildMeta -> buildMeta.buildType != BuildType.RELEASE }, + defaultValue = { true }, + isFinished = false, + ), + MediaCaptionWarning( + key = "feature.media_caption_creation_warning", + title = "Show a compatibility warning on media captions creation", + description = null, + defaultValue = { true }, isFinished = false, ), } diff --git a/libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/CaptionWarningBottomSheet.kt b/libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/CaptionWarningBottomSheet.kt new file mode 100644 index 00000000000..832d95ef145 --- /dev/null +++ b/libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/CaptionWarningBottomSheet.kt @@ -0,0 +1,73 @@ +/* + * Copyright 2024 New Vector Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only + * Please see LICENSE in the repository root for full details. + */ + +package io.element.android.libraries.textcomposer + +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.unit.dp +import io.element.android.compound.theme.ElementTheme +import io.element.android.libraries.designsystem.components.BigIcon +import io.element.android.libraries.designsystem.preview.ElementPreview +import io.element.android.libraries.designsystem.preview.PreviewsDayNight +import io.element.android.libraries.designsystem.theme.components.ModalBottomSheet +import io.element.android.libraries.designsystem.theme.components.OutlinedButton +import io.element.android.libraries.ui.strings.CommonStrings + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun CaptionWarningBottomSheet( + onDismiss: () -> Unit, + modifier: Modifier = Modifier, +) { + ModalBottomSheet( + modifier = modifier, + onDismissRequest = onDismiss, + ) { + Column( + modifier = Modifier + .fillMaxWidth() + .padding(horizontal = 16.dp), + horizontalAlignment = Alignment.CenterHorizontally, + verticalArrangement = Arrangement.spacedBy(16.dp), + ) { + BigIcon( + style = BigIcon.Style.AlertSolid, + ) + Text( + text = stringResource(CommonStrings.screen_media_upload_preview_caption_warning), + style = ElementTheme.typography.fontBodyMdRegular, + color = ElementTheme.colors.textPrimary, + textAlign = TextAlign.Center, + ) + OutlinedButton( + modifier = Modifier + .fillMaxWidth() + .padding(vertical = 16.dp), + onClick = onDismiss, + text = stringResource(CommonStrings.action_ok), + ) + } + } +} + +@PreviewsDayNight +@Composable +internal fun CaptionWarningBottomSheetPreview() = ElementPreview { + CaptionWarningBottomSheet( + onDismiss = {}, + ) +} diff --git a/libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/TextComposer.kt b/libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/TextComposer.kt index fe6034b8b60..9ebb5a7c228 100644 --- a/libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/TextComposer.kt +++ b/libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/TextComposer.kt @@ -10,8 +10,10 @@ package io.element.android.libraries.textcomposer import android.net.Uri import androidx.compose.foundation.background import androidx.compose.foundation.border +import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.BoxScope import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.IntrinsicSize import androidx.compose.foundation.layout.Row @@ -26,8 +28,10 @@ import androidx.compose.foundation.layout.width import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.rememberUpdatedState +import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip @@ -36,10 +40,12 @@ import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.tooling.preview.PreviewParameter import androidx.compose.ui.unit.dp import io.element.android.compound.theme.ElementTheme +import io.element.android.compound.tokens.generated.CompoundIcons import io.element.android.libraries.designsystem.components.media.createFakeWaveform import io.element.android.libraries.designsystem.preview.ElementPreview import io.element.android.libraries.designsystem.preview.PreviewsDayNight import io.element.android.libraries.designsystem.theme.components.CircularProgressIndicator +import io.element.android.libraries.designsystem.theme.components.Icon import io.element.android.libraries.designsystem.theme.components.Text import io.element.android.libraries.matrix.api.core.EventId import io.element.android.libraries.matrix.api.timeline.item.event.EventOrTransactionId @@ -66,6 +72,7 @@ import io.element.android.libraries.textcomposer.model.VoiceMessageRecorderEvent import io.element.android.libraries.textcomposer.model.VoiceMessageState import io.element.android.libraries.textcomposer.model.aTextEditorStateMarkdown import io.element.android.libraries.textcomposer.model.aTextEditorStateRich +import io.element.android.libraries.textcomposer.model.showCaptionCompatibilityWarning import io.element.android.libraries.ui.strings.CommonStrings import io.element.android.wysiwyg.compose.RichTextEditor import io.element.android.wysiwyg.compose.RichTextEditorState @@ -121,8 +128,8 @@ fun TextComposer( } val layoutModifier = modifier - .fillMaxSize() - .height(IntrinsicSize.Min) + .fillMaxSize() + .height(IntrinsicSize.Min) val composerOptionsButton: @Composable () -> Unit = remember(composerMode) { @Composable { @@ -146,7 +153,7 @@ fun TextComposer( val placeholder = if (composerMode.inThread) { stringResource(id = CommonStrings.action_reply_in_thread) - } else if (composerMode is MessageComposerMode.Attachment) { + } else if (composerMode is MessageComposerMode.Attachment || composerMode is MessageComposerMode.EditCaption) { stringResource(id = R.string.rich_text_editor_composer_caption_placeholder) } else { stringResource(id = R.string.rich_text_editor_composer_placeholder) @@ -182,7 +189,7 @@ fun TextComposer( composerMode = composerMode, onResetComposerMode = onResetComposerMode, placeholder = placeholder, - showPlaceholder = { state.state.text.value().isEmpty() }, + showPlaceholder = state.state.text.value().isEmpty(), subcomposing = subcomposing, ) { MarkdownTextInput( @@ -337,8 +344,8 @@ private fun StandardLayout( if (voiceMessageState is VoiceMessageState.Preview || voiceMessageState is VoiceMessageState.Recording) { Box( modifier = Modifier - .padding(bottom = 5.dp, top = 5.dp, end = 3.dp, start = 3.dp) - .size(48.dp), + .padding(bottom = 5.dp, top = 5.dp, end = 3.dp, start = 3.dp) + .size(48.dp), contentAlignment = Alignment.Center, ) { voiceDeleteButton() @@ -348,8 +355,8 @@ private fun StandardLayout( } Box( modifier = Modifier - .padding(bottom = 8.dp, top = 8.dp) - .weight(1f) + .padding(bottom = 8.dp, top = 8.dp) + .weight(1f) ) { voiceRecording() } @@ -362,16 +369,16 @@ private fun StandardLayout( } Box( modifier = Modifier - .padding(bottom = 8.dp, top = 8.dp) - .weight(1f) + .padding(bottom = 8.dp, top = 8.dp) + .weight(1f) ) { textInput() } } Box( - Modifier - .padding(bottom = 5.dp, top = 5.dp, end = 6.dp, start = 6.dp) - .size(48.dp), + Modifier + .padding(bottom = 5.dp, top = 5.dp, end = 6.dp, start = 6.dp) + .size(48.dp), contentAlignment = Alignment.Center, ) { endButton() @@ -393,8 +400,8 @@ private fun TextFormattingLayout( ) { Box( modifier = Modifier - .weight(1f) - .padding(horizontal = 12.dp) + .weight(1f) + .padding(horizontal = 12.dp) ) { textInput() } @@ -428,9 +435,9 @@ private fun TextInputBox( composerMode: MessageComposerMode, onResetComposerMode: () -> Unit, placeholder: String, - showPlaceholder: () -> Boolean, + showPlaceholder: Boolean, subcomposing: Boolean, - textInput: @Composable () -> Unit, + textInput: @Composable BoxScope.() -> Unit, ) { val bgColor = ElementTheme.colors.bgSubtleSecondary val borderColor = ElementTheme.colors.borderDisabled @@ -438,11 +445,11 @@ private fun TextInputBox( Column( modifier = Modifier - .clip(roundedCorners) - .border(0.5.dp, borderColor, roundedCorners) - .background(color = bgColor) - .requiredHeightIn(min = 42.dp) - .fillMaxSize(), + .clip(roundedCorners) + .border(0.5.dp, borderColor, roundedCorners) + .background(color = bgColor) + .requiredHeightIn(min = 42.dp) + .fillMaxSize(), ) { if (composerMode is MessageComposerMode.Special) { ComposerModeView( @@ -453,15 +460,15 @@ private fun TextInputBox( val defaultTypography = ElementTheme.typography.fontBodyLgRegular Box( modifier = Modifier - .padding(top = 4.dp, bottom = 4.dp, start = 12.dp, end = 12.dp) - // Apply test tag only once, otherwise 2 nodes will have it (both the normal and subcomposing one) and tests will fail - .then(if (!subcomposing) Modifier.testTag(TestTags.textEditor) else Modifier), + .padding(top = 4.dp, bottom = 4.dp, start = 12.dp, end = 12.dp) + // Apply test tag only once, otherwise 2 nodes will have it (both the normal and subcomposing one) and tests will fail + .then(if (!subcomposing) Modifier.testTag(TestTags.textEditor) else Modifier), contentAlignment = Alignment.CenterStart, ) { // Placeholder - if (showPlaceholder()) { + if (showPlaceholder) { Text( - placeholder, + text = placeholder, style = defaultTypography.copy( color = ElementTheme.colors.textSecondary, ), @@ -471,6 +478,24 @@ private fun TextInputBox( } textInput() + + if (showPlaceholder && composerMode.showCaptionCompatibilityWarning()) { + var showBottomSheet by remember { mutableStateOf(false) } + Icon( + modifier = Modifier + .clickable { showBottomSheet = true } + .padding(horizontal = 8.dp, vertical = 4.dp) + .align(Alignment.CenterEnd), + imageVector = CompoundIcons.InfoSolid(), + tint = ElementTheme.colors.iconCriticalPrimary, + contentDescription = null, + ) + if (showBottomSheet) { + CaptionWarningBottomSheet( + onDismiss = { showBottomSheet = false }, + ) + } + } } } } @@ -492,7 +517,7 @@ private fun TextInput( composerMode = composerMode, onResetComposerMode = onResetComposerMode, placeholder = placeholder, - showPlaceholder = { state.messageHtml.isEmpty() }, + showPlaceholder = state.messageHtml.isEmpty(), subcomposing = subcomposing, ) { RichTextEditor( @@ -501,8 +526,8 @@ private fun TextInput( // This prevents it gaining focus and mutating the state. registerStateUpdates = !subcomposing, modifier = Modifier - .padding(top = 6.dp, bottom = 6.dp) - .fillMaxWidth(), + .padding(top = 6.dp, bottom = 6.dp) + .fillMaxWidth(), style = ElementRichTextEditorStyle.composerStyle(hasFocus = state.hasFocus), resolveMentionDisplay = resolveMentionDisplay, resolveRoomMentionDisplay = resolveRoomMentionDisplay, @@ -602,13 +627,14 @@ internal fun TextComposerEditCaptionPreview() = ElementPreview { internal fun TextComposerAddCaptionPreview() = ElementPreview { PreviewColumn( items = aTextEditorStateRichList() - ) { _, textEditorState -> + ) { index, textEditorState -> ATextComposer( state = textEditorState, voiceMessageState = VoiceMessageState.Idle, composerMode = aMessageComposerModeEditCaption( // No caption so that the UI will be in add caption mode content = "", + showCompatibilityWarning = index == 0, ), enableVoiceMessages = false, ) @@ -657,7 +683,10 @@ internal fun TextComposerCaptionPreview() = ElementPreview { ATextComposer( state = textEditorState, voiceMessageState = VoiceMessageState.Idle, - composerMode = MessageComposerMode.Attachment(allowCaption = index < list.size), + composerMode = MessageComposerMode.Attachment( + allowCaption = index < list.size, + showCaptionCompatibilityWarning = index == 0, + ), enableVoiceMessages = false, ) } @@ -762,9 +791,11 @@ fun aMessageComposerModeEdit( fun aMessageComposerModeEditCaption( eventOrTransactionId: EventOrTransactionId = EventId("$1234").toEventOrTransactionId(), content: String, + showCompatibilityWarning: Boolean = false, ) = MessageComposerMode.EditCaption( eventOrTransactionId = eventOrTransactionId, - content = content + content = content, + showCaptionCompatibilityWarning = showCompatibilityWarning, ) fun aMessageComposerModeReply( diff --git a/libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/model/MessageComposerMode.kt b/libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/model/MessageComposerMode.kt index 4ef6cfc019c..f698f7ffe99 100644 --- a/libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/model/MessageComposerMode.kt +++ b/libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/model/MessageComposerMode.kt @@ -18,7 +18,10 @@ import io.element.android.libraries.matrix.ui.messages.reply.eventId sealed interface MessageComposerMode { data object Normal : MessageComposerMode - data class Attachment(val allowCaption: Boolean) : MessageComposerMode + data class Attachment( + val allowCaption: Boolean, + val showCaptionCompatibilityWarning: Boolean, + ) : MessageComposerMode sealed interface Special : MessageComposerMode @@ -29,7 +32,8 @@ sealed interface MessageComposerMode { data class EditCaption( val eventOrTransactionId: EventOrTransactionId, - val content: String + val content: String, + val showCaptionCompatibilityWarning: Boolean, ) : Special data class Reply( @@ -51,3 +55,11 @@ sealed interface MessageComposerMode { replyToDetails.eventContent is MessageContent && (replyToDetails.eventContent as MessageContent).isThreaded } + +fun MessageComposerMode.showCaptionCompatibilityWarning(): Boolean { + return when (this) { + is MessageComposerMode.Attachment -> showCaptionCompatibilityWarning + is MessageComposerMode.EditCaption -> showCaptionCompatibilityWarning && content.isEmpty() + else -> false + } +} diff --git a/libraries/textcomposer/impl/src/main/res/values/localazy.xml b/libraries/textcomposer/impl/src/main/res/values/localazy.xml index e7cbb5da9ac..fcc763db308 100644 --- a/libraries/textcomposer/impl/src/main/res/values/localazy.xml +++ b/libraries/textcomposer/impl/src/main/res/values/localazy.xml @@ -4,7 +4,7 @@ "Toggle bullet list" "Close formatting options" "Toggle code block" - "Optional caption…" + "Add a caption" "Message…" "Create a link" "Edit link" From c926697b38c3676d22c3fae001b3cc8f6cc308d4 Mon Sep 17 00:00:00 2001 From: ElementBot Date: Mon, 2 Dec 2024 15:33:17 +0000 Subject: [PATCH 71/96] Update screenshots --- ...messages.impl.attachments.preview_AttachmentsView_0_en.png | 4 ++-- ...messages.impl.attachments.preview_AttachmentsView_1_en.png | 4 ++-- ...messages.impl.attachments.preview_AttachmentsView_2_en.png | 4 ++-- ...messages.impl.attachments.preview_AttachmentsView_3_en.png | 4 ++-- ...messages.impl.attachments.preview_AttachmentsView_5_en.png | 3 +++ ...raries.textcomposer_CaptionWarningBottomSheet_Day_0_en.png | 3 +++ ...ries.textcomposer_CaptionWarningBottomSheet_Night_0_en.png | 3 +++ ...libraries.textcomposer_TextComposerAddCaption_Day_0_en.png | 4 ++-- ...braries.textcomposer_TextComposerAddCaption_Night_0_en.png | 4 ++-- .../libraries.textcomposer_TextComposerCaption_Day_0_en.png | 4 ++-- .../libraries.textcomposer_TextComposerCaption_Night_0_en.png | 4 ++-- ...ibraries.textcomposer_TextComposerEditCaption_Day_0_en.png | 4 ++-- ...raries.textcomposer_TextComposerEditCaption_Night_0_en.png | 4 ++-- 13 files changed, 29 insertions(+), 20 deletions(-) create mode 100644 tests/uitests/src/test/snapshots/images/features.messages.impl.attachments.preview_AttachmentsView_5_en.png create mode 100644 tests/uitests/src/test/snapshots/images/libraries.textcomposer_CaptionWarningBottomSheet_Day_0_en.png create mode 100644 tests/uitests/src/test/snapshots/images/libraries.textcomposer_CaptionWarningBottomSheet_Night_0_en.png diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.attachments.preview_AttachmentsView_0_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.attachments.preview_AttachmentsView_0_en.png index 1a48fb35cfe..d56a5de7d30 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.attachments.preview_AttachmentsView_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.attachments.preview_AttachmentsView_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:2399ee4cd37cbafec07e87bfab90e66ee3df5b6aba602d5cd9bd1114c7365642 -size 397379 +oid sha256:7839db8763b29e38ad67380e09101e48fd3a650080967fb5e51a8bf6411d0427 +size 397423 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.attachments.preview_AttachmentsView_1_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.attachments.preview_AttachmentsView_1_en.png index 8510d977be9..fb0ca03ea36 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.attachments.preview_AttachmentsView_1_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.attachments.preview_AttachmentsView_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:3a92cb782d97553f364fab3df3fe159557a26aad8b7e5c176b40616c2f05abdd -size 51410 +oid sha256:2c40163401ccd77a79d314bd373bb09d9b9bd0bd8d0afe281792c19d6fd593d3 +size 51465 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.attachments.preview_AttachmentsView_2_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.attachments.preview_AttachmentsView_2_en.png index e799726c52b..8c6edbaa980 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.attachments.preview_AttachmentsView_2_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.attachments.preview_AttachmentsView_2_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:361ff23fd2ff99aecfdffd10b45e9235d86183d4856cb2a3e99f85b9e04c2d59 -size 51376 +oid sha256:1cba25287c6d2beee594937c3139b3800630379e1b5a552c5cca886f8646bbfe +size 51429 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.attachments.preview_AttachmentsView_3_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.attachments.preview_AttachmentsView_3_en.png index df965394aa5..350eb731783 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.attachments.preview_AttachmentsView_3_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.attachments.preview_AttachmentsView_3_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:efbfed755b29293009f45fca33f58863b612772de9a1d55593c979dbb04ff6f2 -size 88981 +oid sha256:b4f33aa3545c29c25b3c40e6de90772e4e1f0685095429bdbcc4216e9020161c +size 89038 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.attachments.preview_AttachmentsView_5_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.attachments.preview_AttachmentsView_5_en.png new file mode 100644 index 00000000000..d56a5de7d30 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.attachments.preview_AttachmentsView_5_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7839db8763b29e38ad67380e09101e48fd3a650080967fb5e51a8bf6411d0427 +size 397423 diff --git a/tests/uitests/src/test/snapshots/images/libraries.textcomposer_CaptionWarningBottomSheet_Day_0_en.png b/tests/uitests/src/test/snapshots/images/libraries.textcomposer_CaptionWarningBottomSheet_Day_0_en.png new file mode 100644 index 00000000000..c8aedb734a9 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/libraries.textcomposer_CaptionWarningBottomSheet_Day_0_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:9bcb98d543eba3d43a58b9d17f753c65ccbae2df6f6ebf444c2eccae482a7466 +size 18474 diff --git a/tests/uitests/src/test/snapshots/images/libraries.textcomposer_CaptionWarningBottomSheet_Night_0_en.png b/tests/uitests/src/test/snapshots/images/libraries.textcomposer_CaptionWarningBottomSheet_Night_0_en.png new file mode 100644 index 00000000000..2053e6fa752 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/libraries.textcomposer_CaptionWarningBottomSheet_Night_0_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:e77770bc5d582ad53fc1ad7d3d86b8df85e2c0f8fb997145a1c695ca14cf1e93 +size 17258 diff --git a/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerAddCaption_Day_0_en.png b/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerAddCaption_Day_0_en.png index fadf6629650..5f3d66edeae 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerAddCaption_Day_0_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerAddCaption_Day_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:97d9c333fdc5684971e22593b246ca2751657691dad90ec89d891379e7a0b47f -size 60161 +oid sha256:8c4220a5d9401d42a905dcf204bd273e8039d77a889209d4eb35de7c384ed05c +size 61113 diff --git a/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerAddCaption_Night_0_en.png b/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerAddCaption_Night_0_en.png index 068ccea0fdf..80e866f801a 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerAddCaption_Night_0_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerAddCaption_Night_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c08a7e954c11ff61a9130c54c0b273a5b8996c9095a4dae07cb4b5bc357fc15f -size 58458 +oid sha256:009a1fc06c9a2e2bc112c4483002b43e9710c5ced3b2668c40c91b7c54d43b30 +size 59382 diff --git a/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerCaption_Day_0_en.png b/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerCaption_Day_0_en.png index b5330db5c97..d2843698935 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerCaption_Day_0_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerCaption_Day_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:1b9b24eafbcaa2143c199a0522fa1aae98d9c7bddb80364602f0662567a2f1a1 -size 56485 +oid sha256:2eb0eaa26e48d182bd3dc78671cb43f02c24ef5f15fb4e6e8b47da2f3d37ce7b +size 56567 diff --git a/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerCaption_Night_0_en.png b/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerCaption_Night_0_en.png index dea84aaa40a..101c090e864 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerCaption_Night_0_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerCaption_Night_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:fc7a5491acff69b64ea73c1a62b7ae9e148ce57768697de2ec280327cd72298d -size 55402 +oid sha256:fcfa2769e764b164375e6f6ef5194ce9ef686b6f76e16848270380a88beb175a +size 55518 diff --git a/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerEditCaption_Day_0_en.png b/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerEditCaption_Day_0_en.png index 82475e58db8..17daeade89c 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerEditCaption_Day_0_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerEditCaption_Day_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:1967fa34ef6bd37c373f68badaed4e41b04efbbf929187e6ded4cfb903715325 -size 59539 +oid sha256:4f6f448d800b741e7e59a44b0f660f4702603e394df6223b1d968c862266083e +size 59832 diff --git a/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerEditCaption_Night_0_en.png b/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerEditCaption_Night_0_en.png index db2e4e318d7..270f2ab1d10 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerEditCaption_Night_0_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerEditCaption_Night_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:430b30b65f5908fce562be613afa41131c4fbe8849db3d3f5a3fa424417469a4 -size 57827 +oid sha256:81bfbaf9030bc40ca6744dd6bf8170243243ebcd98fbc3de71fed85798d60412 +size 58150 From 3b5b443cbbababbf416eec80972d057d59bbc05e Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Fri, 29 Nov 2024 13:50:19 +0100 Subject: [PATCH 72/96] MediaViewer: iterate on design --- .../messages/impl/MessagesFlowNode.kt | 20 ++- .../libraries/mediaviewer/api/MediaInfo.kt | 43 ++++- .../impl/DefaultMediaViewerEntryPoint.kt | 4 +- .../impl/local/AndroidLocalMediaFactory.kt | 12 +- .../impl/local/DefaultLocalMediaRenderer.kt | 1 + .../mediaviewer/impl/local/LocalMediaView.kt | 2 + .../impl/local/video/MediaVideoView.kt | 9 +- .../impl/viewer/MediaViewerStateProvider.kt | 96 ++++++----- .../impl/viewer/MediaViewerView.kt | 151 ++++++++++++++---- .../local/AndroidLocalMediaFactoryTest.kt | 8 +- .../mediaviewer/test/FakeLocalMediaFactory.kt | 4 +- 11 files changed, 264 insertions(+), 86 deletions(-) diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesFlowNode.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesFlowNode.kt index 9d5ed6ff8c1..e80f99a67cb 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesFlowNode.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesFlowNode.kt @@ -337,7 +337,9 @@ class MessagesFlowNode @AssistedInject constructor( caption = event.content.caption, mimeType = event.content.mimeType, formattedFileSize = event.content.formattedFileSize, - fileExtension = event.content.fileExtension + fileExtension = event.content.fileExtension, + senderName = event.safeSenderName, + dateSent = event.sentTime, ), mediaSource = event.content.mediaSource, thumbnailSource = event.content.thumbnailSource, @@ -355,7 +357,9 @@ class MessagesFlowNode @AssistedInject constructor( caption = event.content.caption, mimeType = event.content.mimeType, formattedFileSize = event.content.formattedFileSize, - fileExtension = event.content.fileExtension + fileExtension = event.content.fileExtension, + senderName = event.safeSenderName, + dateSent = event.sentTime, ), mediaSource = event.content.preferredMediaSource, thumbnailSource = event.content.thumbnailSource, @@ -373,7 +377,9 @@ class MessagesFlowNode @AssistedInject constructor( caption = event.content.caption, mimeType = event.content.mimeType, formattedFileSize = event.content.formattedFileSize, - fileExtension = event.content.fileExtension + fileExtension = event.content.fileExtension, + senderName = event.safeSenderName, + dateSent = event.sentTime, ), mediaSource = event.content.videoSource, thumbnailSource = event.content.thumbnailSource, @@ -388,7 +394,9 @@ class MessagesFlowNode @AssistedInject constructor( caption = event.content.caption, mimeType = event.content.mimeType, formattedFileSize = event.content.formattedFileSize, - fileExtension = event.content.fileExtension + fileExtension = event.content.fileExtension, + senderName = event.safeSenderName, + dateSent = event.sentTime, ), mediaSource = event.content.fileSource, thumbnailSource = event.content.thumbnailSource, @@ -403,7 +411,9 @@ class MessagesFlowNode @AssistedInject constructor( caption = event.content.caption, mimeType = event.content.mimeType, formattedFileSize = event.content.formattedFileSize, - fileExtension = event.content.fileExtension + fileExtension = event.content.fileExtension, + senderName = event.safeSenderName, + dateSent = event.sentTime, ), mediaSource = event.content.mediaSource, thumbnailSource = null, diff --git a/libraries/mediaviewer/api/src/main/kotlin/io/element/android/libraries/mediaviewer/api/MediaInfo.kt b/libraries/mediaviewer/api/src/main/kotlin/io/element/android/libraries/mediaviewer/api/MediaInfo.kt index 93cd2f9378f..5c317b1d6a4 100644 --- a/libraries/mediaviewer/api/src/main/kotlin/io/element/android/libraries/mediaviewer/api/MediaInfo.kt +++ b/libraries/mediaviewer/api/src/main/kotlin/io/element/android/libraries/mediaviewer/api/MediaInfo.kt @@ -18,44 +18,73 @@ data class MediaInfo( val mimeType: String, val formattedFileSize: String, val fileExtension: String, + val senderName: String?, + val dateSent: String?, ) : Parcelable -fun anImageMediaInfo(): MediaInfo = MediaInfo( +fun anImageMediaInfo( + caption: String? = null, + senderName: String? = null, + dateSent: String? = null, +): MediaInfo = MediaInfo( filename = "an image file.jpg", - caption = null, + caption = caption, mimeType = MimeTypes.Jpeg, formattedFileSize = "4MB", fileExtension = "jpg", + senderName = senderName, + dateSent = dateSent, ) -fun aVideoMediaInfo(): MediaInfo = MediaInfo( +fun aVideoMediaInfo( + caption: String? = null, + senderName: String? = null, + dateSent: String? = null, +): MediaInfo = MediaInfo( filename = "a video file.mp4", - caption = null, + caption = caption, mimeType = MimeTypes.Mp4, formattedFileSize = "14MB", fileExtension = "mp4", + senderName = senderName, + dateSent = dateSent, ) -fun aPdfMediaInfo(): MediaInfo = MediaInfo( +fun aPdfMediaInfo( + senderName: String? = null, + dateSent: String? = null, +): MediaInfo = MediaInfo( filename = "a pdf file.pdf", caption = null, mimeType = MimeTypes.Pdf, formattedFileSize = "23MB", fileExtension = "pdf", + senderName = senderName, + dateSent = dateSent, ) -fun anApkMediaInfo(): MediaInfo = MediaInfo( +fun anApkMediaInfo( + senderName: String? = null, + dateSent: String? = null, +): MediaInfo = MediaInfo( filename = "an apk file.apk", caption = null, mimeType = MimeTypes.Apk, formattedFileSize = "50MB", fileExtension = "apk", + senderName = senderName, + dateSent = dateSent, ) -fun anAudioMediaInfo(): MediaInfo = MediaInfo( +fun anAudioMediaInfo( + senderName: String? = null, + dateSent: String? = null, +): MediaInfo = MediaInfo( filename = "an audio file.mp3", caption = null, mimeType = MimeTypes.Mp3, formattedFileSize = "7MB", fileExtension = "mp3", + senderName = senderName, + dateSent = dateSent, ) diff --git a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/DefaultMediaViewerEntryPoint.kt b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/DefaultMediaViewerEntryPoint.kt index 5bd16c840b7..86d7bca722b 100644 --- a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/DefaultMediaViewerEntryPoint.kt +++ b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/DefaultMediaViewerEntryPoint.kt @@ -46,7 +46,9 @@ class DefaultMediaViewerEntryPoint @Inject constructor() : MediaViewerEntryPoint caption = null, mimeType = mimeType, formattedFileSize = "", - fileExtension = "" + fileExtension = "", + senderName = null, + dateSent = null, ), mediaSource = MediaSource(url = avatarUrl), thumbnailSource = null, diff --git a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/AndroidLocalMediaFactory.kt b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/AndroidLocalMediaFactory.kt index 461563f4653..8b5163cf6c1 100644 --- a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/AndroidLocalMediaFactory.kt +++ b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/AndroidLocalMediaFactory.kt @@ -41,6 +41,8 @@ class AndroidLocalMediaFactory @Inject constructor( name = mediaInfo.filename, caption = mediaInfo.caption, formattedFileSize = mediaInfo.formattedFileSize, + senderName = mediaInfo.senderName, + dateSent = mediaInfo.dateSent, ) override fun createFromUri( @@ -54,6 +56,8 @@ class AndroidLocalMediaFactory @Inject constructor( name = name, caption = null, formattedFileSize = formattedFileSize, + senderName = null, + dateSent = null, ) private fun createFromUri( @@ -61,7 +65,9 @@ class AndroidLocalMediaFactory @Inject constructor( mimeType: String?, name: String?, caption: String?, - formattedFileSize: String? + formattedFileSize: String?, + senderName: String?, + dateSent: String?, ): LocalMedia { val resolvedMimeType = mimeType ?: context.getMimeType(uri) ?: MimeTypes.OctetStream val fileName = name ?: context.getFileName(uri) ?: "" @@ -74,7 +80,9 @@ class AndroidLocalMediaFactory @Inject constructor( filename = fileName, caption = caption, formattedFileSize = fileSize, - fileExtension = fileExtension + fileExtension = fileExtension, + senderName = senderName, + dateSent = dateSent, ) ) } diff --git a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/DefaultLocalMediaRenderer.kt b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/DefaultLocalMediaRenderer.kt index 6b1005dccf7..b801ebe00f1 100644 --- a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/DefaultLocalMediaRenderer.kt +++ b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/DefaultLocalMediaRenderer.kt @@ -29,6 +29,7 @@ class DefaultLocalMediaRenderer @Inject constructor() : LocalMediaRenderer { ) LocalMediaView( modifier = Modifier.fillMaxSize(), + bottomPaddingInPixels = 0, localMedia = localMedia, localMediaViewState = localMediaViewState, onClick = {} diff --git a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/LocalMediaView.kt b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/LocalMediaView.kt index 44392e27b9a..5d0a2993df2 100644 --- a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/LocalMediaView.kt +++ b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/LocalMediaView.kt @@ -22,6 +22,7 @@ import io.element.android.libraries.mediaviewer.impl.local.video.MediaVideoView @Composable fun LocalMediaView( localMedia: LocalMedia?, + bottomPaddingInPixels: Int, onClick: () -> Unit, modifier: Modifier = Modifier, localMediaViewState: LocalMediaViewState = rememberLocalMediaViewState(), @@ -37,6 +38,7 @@ fun LocalMediaView( ) mimeType.isMimeTypeVideo() -> MediaVideoView( localMediaViewState = localMediaViewState, + bottomPaddingInPixels = bottomPaddingInPixels, localMedia = localMedia, modifier = modifier, ) diff --git a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/video/MediaVideoView.kt b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/video/MediaVideoView.kt index d9785491924..6d172823e75 100644 --- a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/video/MediaVideoView.kt +++ b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/video/MediaVideoView.kt @@ -14,6 +14,7 @@ import androidx.compose.foundation.background import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.derivedStateOf @@ -37,6 +38,7 @@ import androidx.media3.ui.PlayerView import io.element.android.compound.theme.ElementTheme import io.element.android.libraries.designsystem.preview.ElementPreview import io.element.android.libraries.designsystem.preview.PreviewsDayNight +import io.element.android.libraries.designsystem.text.toDp import io.element.android.libraries.designsystem.theme.components.Text import io.element.android.libraries.designsystem.utils.KeepScreenOn import io.element.android.libraries.designsystem.utils.OnLifecycleEvent @@ -51,6 +53,7 @@ import kotlin.time.Duration.Companion.seconds @Composable fun MediaVideoView( localMediaViewState: LocalMediaViewState, + bottomPaddingInPixels: Int, localMedia: LocalMedia?, modifier: Modifier = Modifier, ) { @@ -66,6 +69,7 @@ fun MediaVideoView( } ExoPlayerMediaVideoView( localMediaViewState = localMediaViewState, + bottomPaddingInPixels = bottomPaddingInPixels, exoPlayer = exoPlayer, localMedia = localMedia, modifier = modifier, @@ -76,6 +80,7 @@ fun MediaVideoView( @Composable private fun ExoPlayerMediaVideoView( localMediaViewState: LocalMediaViewState, + bottomPaddingInPixels: Int, exoPlayer: ExoPlayer, localMedia: LocalMedia?, modifier: Modifier = Modifier, @@ -232,7 +237,8 @@ private fun ExoPlayerMediaVideoView( }, modifier = Modifier .fillMaxWidth() - .align(Alignment.BottomCenter), + .align(Alignment.BottomCenter) + .padding(bottom = bottomPaddingInPixels.toDp()), ) } @@ -254,6 +260,7 @@ private fun ExoPlayerMediaVideoView( internal fun MediaVideoViewPreview() = ElementPreview { MediaVideoView( modifier = Modifier.fillMaxSize(), + bottomPaddingInPixels = 0, localMediaViewState = rememberLocalMediaViewState(), localMedia = null, ) diff --git a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerStateProvider.kt b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerStateProvider.kt index 4ffcb75b075..6c7a9fb704f 100644 --- a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerStateProvider.kt +++ b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerStateProvider.kt @@ -24,52 +24,72 @@ open class MediaViewerStateProvider : PreviewParameterProvider aMediaViewerState(), aMediaViewerState(AsyncData.Loading()), aMediaViewerState(AsyncData.Failure(IllegalStateException("error"))), - aMediaViewerState( - AsyncData.Success( - LocalMedia(Uri.EMPTY, anImageMediaInfo()) - ), - anImageMediaInfo(), - ), - aMediaViewerState( - AsyncData.Success( - LocalMedia(Uri.EMPTY, aVideoMediaInfo()) - ), - aVideoMediaInfo(), - ), - aMediaViewerState( - AsyncData.Success( - LocalMedia(Uri.EMPTY, aPdfMediaInfo()) - ), - aPdfMediaInfo(), - ), + anImageMediaInfo( + senderName = "Sally Sanderson", + dateSent = "21 NOV, 2024", + caption = "A caption", + ).let { + aMediaViewerState( + AsyncData.Success( + LocalMedia(Uri.EMPTY, it) + ), + it, + ) + }, + aVideoMediaInfo( + senderName = "Sally Sanderson", + dateSent = "21 NOV, 2024", + caption = "A caption", + ).let { + aMediaViewerState( + AsyncData.Success( + LocalMedia(Uri.EMPTY, it) + ), + it, + ) + }, + aPdfMediaInfo().let { + aMediaViewerState( + AsyncData.Success( + LocalMedia(Uri.EMPTY, it) + ), + it, + ) + }, aMediaViewerState( AsyncData.Loading(), anApkMediaInfo(), ), - aMediaViewerState( - AsyncData.Success( - LocalMedia(Uri.EMPTY, anApkMediaInfo()) - ), - anApkMediaInfo(), - ), + anApkMediaInfo().let { + aMediaViewerState( + AsyncData.Success( + LocalMedia(Uri.EMPTY, it) + ), + it, + ) + }, aMediaViewerState( AsyncData.Loading(), anAudioMediaInfo(), ), - aMediaViewerState( - AsyncData.Success( - LocalMedia(Uri.EMPTY, anAudioMediaInfo()) - ), - anAudioMediaInfo(), - ), - aMediaViewerState( - AsyncData.Success( - LocalMedia(Uri.EMPTY, anImageMediaInfo()) - ), - anImageMediaInfo(), - canDownload = false, - canShare = false, - ), + anAudioMediaInfo().let { + aMediaViewerState( + AsyncData.Success( + LocalMedia(Uri.EMPTY, it) + ), + it, + ) + }, + anImageMediaInfo().let { + aMediaViewerState( + AsyncData.Success( + LocalMedia(Uri.EMPTY, it) + ), + it, + canDownload = false, + canShare = false, + ) + }, ) } diff --git a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerView.kt b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerView.kt index ae5e9401cb9..1e3c264d146 100644 --- a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerView.kt +++ b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerView.kt @@ -16,10 +16,14 @@ import androidx.compose.animation.fadeIn import androidx.compose.animation.fadeOut import androidx.compose.foundation.background import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.navigationBarsPadding +import androidx.compose.foundation.layout.padding import androidx.compose.material.icons.Icons import androidx.compose.material.icons.automirrored.filled.OpenInNew import androidx.compose.material3.ExperimentalMaterial3Api @@ -28,6 +32,7 @@ import androidx.compose.material3.TopAppBarDefaults import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableIntStateOf import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.rememberUpdatedState @@ -36,12 +41,15 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.layout.ContentScale +import androidx.compose.ui.layout.onSizeChanged import androidx.compose.ui.platform.LocalInspectionMode import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.PreviewParameter import androidx.compose.ui.unit.dp import coil.compose.AsyncImage +import io.element.android.compound.theme.ElementTheme import io.element.android.compound.tokens.generated.CompoundIcons import io.element.android.libraries.architecture.AsyncData import io.element.android.libraries.core.mimetype.MimeTypes @@ -51,6 +59,7 @@ import io.element.android.libraries.designsystem.preview.ElementPreviewDark import io.element.android.libraries.designsystem.theme.components.Icon import io.element.android.libraries.designsystem.theme.components.IconButton import io.element.android.libraries.designsystem.theme.components.Scaffold +import io.element.android.libraries.designsystem.theme.components.Text import io.element.android.libraries.designsystem.theme.components.TopAppBar import io.element.android.libraries.designsystem.utils.snackbar.SnackbarHost import io.element.android.libraries.designsystem.utils.snackbar.rememberSnackbarHostState @@ -80,6 +89,7 @@ fun MediaViewerView( val snackbarHostState = rememberSnackbarHostState(snackbarMessage = state.snackbarMessage) var showOverlay by remember { mutableStateOf(true) } + var bottomPaddingInPixels by remember { mutableIntStateOf(0) } BackHandler { onBackClick() } Scaffold( modifier, @@ -88,6 +98,7 @@ fun MediaViewerView( ) { MediaViewerPage( showOverlay = showOverlay, + bottomPaddingInPixels = bottomPaddingInPixels, state = state, onDismiss = { onBackClick() @@ -97,14 +108,29 @@ fun MediaViewerView( } ) AnimatedVisibility(visible = showOverlay, enter = fadeIn(), exit = fadeOut()) { - MediaViewerTopBar( - actionsEnabled = state.downloadedMedia is AsyncData.Success, - mimeType = state.mediaInfo.mimeType, - onBackClick = onBackClick, - canDownload = state.canDownload, - canShare = state.canShare, - eventSink = state.eventSink - ) + Box( + modifier = Modifier + .fillMaxSize() + .navigationBarsPadding() + ) { + MediaViewerTopBar( + actionsEnabled = state.downloadedMedia is AsyncData.Success, + senderName = state.mediaInfo.senderName, + dateSent = state.mediaInfo.dateSent, + onBackClick = onBackClick, + eventSink = state.eventSink + ) + MediaViewerBottomBar( + modifier = Modifier.align(Alignment.BottomCenter), + actionsEnabled = state.downloadedMedia is AsyncData.Success, + canDownload = state.canDownload, + canShare = state.canShare, + mimeType = state.mediaInfo.mimeType, + caption = state.mediaInfo.caption, + onHeightChanged = { bottomPaddingInPixels = it }, + eventSink = state.eventSink + ) + } } } } @@ -112,6 +138,7 @@ fun MediaViewerView( @Composable private fun MediaViewerPage( showOverlay: Boolean, + bottomPaddingInPixels: Int, state: MediaViewerState, onDismiss: () -> Unit, onShowOverlayChange: (Boolean) -> Unit, @@ -148,8 +175,8 @@ private fun MediaViewerPage( Box( modifier = Modifier - .fillMaxSize() - .navigationBarsPadding() + .fillMaxSize() + .navigationBarsPadding() ) { Box(contentAlignment = Alignment.Center) { val zoomableState = rememberZoomableState( @@ -168,6 +195,7 @@ private fun MediaViewerPage( LocalMediaView( modifier = Modifier.fillMaxSize(), + bottomPaddingInPixels = bottomPaddingInPixels, localMediaViewState = localMediaViewState, localMedia = state.downloadedMedia.dataOrNull(), mediaInfo = state.mediaInfo, @@ -193,8 +221,8 @@ private fun MediaViewerPage( if (showProgress) { LinearProgressIndicator( modifier = Modifier - .fillMaxWidth() - .height(2.dp) + .fillMaxWidth() + .height(2.dp) ) } } @@ -246,23 +274,99 @@ private fun rememberShowProgress(downloadedMedia: AsyncData): Boolea return showProgress } +@Suppress("UNUSED_PARAMETER") @OptIn(ExperimentalMaterial3Api::class) @Composable private fun MediaViewerTopBar( actionsEnabled: Boolean, - canDownload: Boolean, - canShare: Boolean, - mimeType: String, + senderName: String?, + dateSent: String?, onBackClick: () -> Unit, eventSink: (MediaViewerEvents) -> Unit, ) { TopAppBar( - title = {}, + title = { + if (senderName != null && dateSent != null) { + Column( + modifier = Modifier + .fillMaxWidth() + .padding(end = 48.dp), + horizontalAlignment = Alignment.CenterHorizontally, + ) { + Text( + text = senderName, + style = ElementTheme.typography.fontBodyMdMedium, + color = ElementTheme.colors.textPrimary, + ) + Text( + text = dateSent, + style = ElementTheme.typography.fontBodySmRegular, + color = ElementTheme.colors.textPrimary, + ) + } + } + }, colors = TopAppBarDefaults.topAppBarColors( containerColor = Color.Transparent.copy(0.6f), ), navigationIcon = { BackButton(onClick = onBackClick) }, actions = { + // TODO Add action to open infos. + } + ) +} + +@Composable +private fun MediaViewerBottomBar( + actionsEnabled: Boolean, + canDownload: Boolean, + canShare: Boolean, + mimeType: String, + caption: String?, + onHeightChanged: (Int) -> Unit, + eventSink: (MediaViewerEvents) -> Unit, + modifier: Modifier = Modifier, +) { + Column( + modifier = modifier + .fillMaxWidth() + .background(Color(0x99101317)) + .onSizeChanged { + onHeightChanged(it.height) + }, + ) { + if (caption != null) { + Text( + modifier = Modifier + .fillMaxWidth() + .padding(16.dp), + text = caption, + maxLines = 5, + overflow = TextOverflow.Ellipsis, + style = ElementTheme.typography.fontBodyLgRegular, + ) + } + Row( + modifier = modifier + .fillMaxWidth() + .padding(start = 8.dp, end = 8.dp, bottom = 8.dp), + verticalAlignment = Alignment.CenterVertically, + ) { + if (canShare) { + IconButton( + enabled = actionsEnabled, + onClick = { + eventSink(MediaViewerEvents.Share) + }, + modifier = Modifier.align(Alignment.CenterVertically) + ) { + Icon( + imageVector = CompoundIcons.ShareAndroid(), + contentDescription = stringResource(id = CommonStrings.action_share) + ) + } + } + Spacer(modifier = Modifier.weight(1f)) IconButton( enabled = actionsEnabled, onClick = { @@ -293,21 +397,8 @@ private fun MediaViewerTopBar( ) } } - if (canShare) { - IconButton( - enabled = actionsEnabled, - onClick = { - eventSink(MediaViewerEvents.Share) - }, - ) { - Icon( - imageVector = CompoundIcons.ShareAndroid(), - contentDescription = stringResource(id = CommonStrings.action_share) - ) - } - } } - ) + } } @Composable diff --git a/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/local/AndroidLocalMediaFactoryTest.kt b/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/local/AndroidLocalMediaFactoryTest.kt index 5729c5310da..c341f6e7515 100644 --- a/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/local/AndroidLocalMediaFactoryTest.kt +++ b/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/local/AndroidLocalMediaFactoryTest.kt @@ -11,6 +11,7 @@ import com.google.common.truth.Truth.assertThat import io.element.android.libraries.androidutils.filesize.FakeFileSizeFormatter import io.element.android.libraries.core.mimetype.MimeTypes import io.element.android.libraries.matrix.api.media.MediaFile +import io.element.android.libraries.matrix.test.A_USER_NAME import io.element.android.libraries.matrix.test.media.FakeMediaFile import io.element.android.libraries.mediaviewer.api.MediaInfo import io.element.android.libraries.mediaviewer.api.anImageMediaInfo @@ -25,7 +26,10 @@ class AndroidLocalMediaFactoryTest { @Test fun `test AndroidLocalMediaFactory`() { val sut = createAndroidLocalMediaFactory() - val result = sut.createFromMediaFile(aMediaFile(), anImageMediaInfo()) + val result = sut.createFromMediaFile(aMediaFile(), anImageMediaInfo( + senderName = A_USER_NAME, + dateSent = "12:34", + )) assertThat(result.uri.toString()).endsWith("aPath") assertThat(result.info).isEqualTo( MediaInfo( @@ -34,6 +38,8 @@ class AndroidLocalMediaFactoryTest { mimeType = MimeTypes.Jpeg, formattedFileSize = "4MB", fileExtension = "jpg", + senderName = A_USER_NAME, + dateSent = "12:34" ) ) } diff --git a/libraries/mediaviewer/test/src/main/kotlin/io/element/android/libraries/mediaviewer/test/FakeLocalMediaFactory.kt b/libraries/mediaviewer/test/src/main/kotlin/io/element/android/libraries/mediaviewer/test/FakeLocalMediaFactory.kt index df85f2d53d7..a0f36c6f0fb 100644 --- a/libraries/mediaviewer/test/src/main/kotlin/io/element/android/libraries/mediaviewer/test/FakeLocalMediaFactory.kt +++ b/libraries/mediaviewer/test/src/main/kotlin/io/element/android/libraries/mediaviewer/test/FakeLocalMediaFactory.kt @@ -36,7 +36,9 @@ class FakeLocalMediaFactory( caption = null, mimeType = mimeType ?: fallbackMimeType, formattedFileSize = formattedFileSize ?: fallbackFileSize, - fileExtension = fileExtensionExtractor.extractFromName(safeName) + fileExtension = fileExtensionExtractor.extractFromName(safeName), + senderName = null, + dateSent = null ) return aLocalMedia(uri, mediaInfo) } From 1f61be8f86ddad71bd99755b8304f1f0a46e37c2 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Mon, 2 Dec 2024 17:12:18 +0100 Subject: [PATCH 73/96] Improve preview. --- .../libraries/mediaviewer/impl/viewer/MediaViewerView.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerView.kt b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerView.kt index 1e3c264d146..0099ffe700d 100644 --- a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerView.kt +++ b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerView.kt @@ -89,7 +89,8 @@ fun MediaViewerView( val snackbarHostState = rememberSnackbarHostState(snackbarMessage = state.snackbarMessage) var showOverlay by remember { mutableStateOf(true) } - var bottomPaddingInPixels by remember { mutableIntStateOf(0) } + val defaultBottomPaddingInPixels = if (LocalInspectionMode.current) 303 else 0 + var bottomPaddingInPixels by remember { mutableIntStateOf(defaultBottomPaddingInPixels) } BackHandler { onBackClick() } Scaffold( modifier, From 3f9621e4af0e2912cd587c0f74b208cd3f9c8a1e Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Mon, 2 Dec 2024 15:47:54 +0100 Subject: [PATCH 74/96] Video player: Iterate on Play/Pause button --- .../local/video/MediaPlayerControllerView.kt | 22 ++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/video/MediaPlayerControllerView.kt b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/video/MediaPlayerControllerView.kt index 9cee07728f1..f0c6040412e 100644 --- a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/video/MediaPlayerControllerView.kt +++ b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/video/MediaPlayerControllerView.kt @@ -11,10 +11,13 @@ import androidx.compose.animation.AnimatedVisibility import androidx.compose.animation.fadeIn import androidx.compose.animation.fadeOut import androidx.compose.foundation.background +import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.widthIn +import androidx.compose.foundation.shape.CircleShape import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableFloatStateOf @@ -63,8 +66,21 @@ fun MediaPlayerControllerView( .widthIn(max = 480.dp), verticalAlignment = Alignment.CenterVertically, ) { - IconButton( - onClick = onTogglePlay, + val bgColor = if (state.isPlaying) { + ElementTheme.colors.bgCanvasDefault + } else { + ElementTheme.colors.textPrimary + } + Box( + modifier = Modifier + .clickable { onTogglePlay() } + .size(36.dp) + .background( + color = bgColor, + shape = CircleShape, + ) + .padding(8.dp), + contentAlignment = Alignment.Center, ) { if (state.isPlaying) { Icon( @@ -75,7 +91,7 @@ fun MediaPlayerControllerView( } else { Icon( imageVector = CompoundIcons.PlaySolid(), - tint = ElementTheme.colors.iconPrimary, + tint = ElementTheme.colors.iconOnSolidPrimary, contentDescription = stringResource(CommonStrings.a11y_play) ) } From 3c5454f0b7ad99bd543055eef8e818f282a3ca2b Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Mon, 2 Dec 2024 17:18:10 +0100 Subject: [PATCH 75/96] Add Divider --- .../libraries/mediaviewer/impl/viewer/MediaViewerView.kt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerView.kt b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerView.kt index 0099ffe700d..a9b43843f53 100644 --- a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerView.kt +++ b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerView.kt @@ -56,6 +56,7 @@ import io.element.android.libraries.core.mimetype.MimeTypes import io.element.android.libraries.designsystem.components.button.BackButton import io.element.android.libraries.designsystem.components.dialogs.RetryDialog import io.element.android.libraries.designsystem.preview.ElementPreviewDark +import io.element.android.libraries.designsystem.theme.components.HorizontalDivider import io.element.android.libraries.designsystem.theme.components.Icon import io.element.android.libraries.designsystem.theme.components.IconButton import io.element.android.libraries.designsystem.theme.components.Scaffold @@ -336,6 +337,7 @@ private fun MediaViewerBottomBar( onHeightChanged(it.height) }, ) { + HorizontalDivider() if (caption != null) { Text( modifier = Modifier From 89aee0446af28b0d4b6474cabe46af0e1d993634 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Mon, 2 Dec 2024 17:38:47 +0100 Subject: [PATCH 76/96] Fix player controls not showing on attachment preview. --- .../attachments/preview/AttachmentsPreviewView.kt | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/attachments/preview/AttachmentsPreviewView.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/attachments/preview/AttachmentsPreviewView.kt index d0a980658d5..a91baaad8c0 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/attachments/preview/AttachmentsPreviewView.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/attachments/preview/AttachmentsPreviewView.kt @@ -11,12 +11,14 @@ import androidx.activity.compose.BackHandler import androidx.compose.foundation.Image import androidx.compose.foundation.background import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.IntrinsicSize import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.imePadding import androidx.compose.foundation.layout.navigationBarsPadding +import androidx.compose.foundation.layout.padding import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment @@ -81,8 +83,9 @@ fun AttachmentsPreviewView( title = {}, ) } - ) { + ) { paddingValues -> AttachmentPreviewContent( + modifier = Modifier.padding(paddingValues), state = state, localMediaRenderer = localMediaRenderer, onSendClick = ::postSendAttachment, @@ -134,14 +137,16 @@ private fun AttachmentPreviewContent( state: AttachmentsPreviewState, localMediaRenderer: LocalMediaRenderer, onSendClick: () -> Unit, + modifier: Modifier = Modifier, ) { - Box( - modifier = Modifier + Column( + modifier = modifier .fillMaxSize() .navigationBarsPadding(), ) { Box( - modifier = Modifier.fillMaxSize(), + modifier = Modifier + .weight(1f), contentAlignment = Alignment.Center ) { when (val attachment = state.attachment) { @@ -157,7 +162,6 @@ private fun AttachmentPreviewContent( .fillMaxWidth() .background(ElementTheme.colors.bgCanvasDefault) .height(IntrinsicSize.Min) - .align(Alignment.BottomCenter) .imePadding(), ) } From dc34a861b41455a3116ae41178a0877349b07325 Mon Sep 17 00:00:00 2001 From: ElementBot Date: Mon, 2 Dec 2024 16:51:17 +0000 Subject: [PATCH 77/96] Update screenshots --- ...messages.impl.attachments.preview_AttachmentsView_0_en.png | 4 ++-- ...messages.impl.attachments.preview_AttachmentsView_1_en.png | 4 ++-- ...messages.impl.attachments.preview_AttachmentsView_2_en.png | 4 ++-- ...messages.impl.attachments.preview_AttachmentsView_3_en.png | 4 ++-- ...messages.impl.attachments.preview_AttachmentsView_4_en.png | 4 ++-- ...messages.impl.attachments.preview_AttachmentsView_5_en.png | 4 ++-- ...er.impl.local.video_MediaPlayerControllerView_Day_0_en.png | 4 ++-- ...er.impl.local.video_MediaPlayerControllerView_Day_1_en.png | 4 ++-- ....impl.local.video_MediaPlayerControllerView_Night_0_en.png | 4 ++-- ....impl.local.video_MediaPlayerControllerView_Night_1_en.png | 4 ++-- ...s.mediaviewer.impl.local.video_MediaVideoView_Day_0_en.png | 4 ++-- ...mediaviewer.impl.local.video_MediaVideoView_Night_0_en.png | 4 ++-- ...libraries.mediaviewer.impl.viewer_MediaViewerView_0_en.png | 4 ++-- ...ibraries.mediaviewer.impl.viewer_MediaViewerView_10_en.png | 4 ++-- ...libraries.mediaviewer.impl.viewer_MediaViewerView_1_en.png | 4 ++-- ...libraries.mediaviewer.impl.viewer_MediaViewerView_2_en.png | 4 ++-- ...libraries.mediaviewer.impl.viewer_MediaViewerView_3_en.png | 4 ++-- ...libraries.mediaviewer.impl.viewer_MediaViewerView_4_en.png | 4 ++-- ...libraries.mediaviewer.impl.viewer_MediaViewerView_5_en.png | 4 ++-- ...libraries.mediaviewer.impl.viewer_MediaViewerView_6_en.png | 4 ++-- ...libraries.mediaviewer.impl.viewer_MediaViewerView_7_en.png | 4 ++-- ...libraries.mediaviewer.impl.viewer_MediaViewerView_8_en.png | 4 ++-- ...libraries.mediaviewer.impl.viewer_MediaViewerView_9_en.png | 4 ++-- 23 files changed, 46 insertions(+), 46 deletions(-) diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.attachments.preview_AttachmentsView_0_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.attachments.preview_AttachmentsView_0_en.png index d56a5de7d30..71d0679471d 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.attachments.preview_AttachmentsView_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.attachments.preview_AttachmentsView_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:7839db8763b29e38ad67380e09101e48fd3a650080967fb5e51a8bf6411d0427 -size 397423 +oid sha256:17aa655ef22beec5cef50f5d44cb2ecd8ad3a1979bc072a33079a49a8c4495c5 +size 397284 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.attachments.preview_AttachmentsView_1_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.attachments.preview_AttachmentsView_1_en.png index fb0ca03ea36..9df61f791ef 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.attachments.preview_AttachmentsView_1_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.attachments.preview_AttachmentsView_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:2c40163401ccd77a79d314bd373bb09d9b9bd0bd8d0afe281792c19d6fd593d3 -size 51465 +oid sha256:8a0e722772be6b9d38c5f0ef3198502ca6e6ebb2599e3a4ebb4cc95cde907095 +size 52012 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.attachments.preview_AttachmentsView_2_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.attachments.preview_AttachmentsView_2_en.png index 8c6edbaa980..40926d90b9e 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.attachments.preview_AttachmentsView_2_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.attachments.preview_AttachmentsView_2_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:1cba25287c6d2beee594937c3139b3800630379e1b5a552c5cca886f8646bbfe -size 51429 +oid sha256:aa4cae0da657162117538b6839032ebf467542a043f18e308eeaf5ae28ca14e8 +size 51984 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.attachments.preview_AttachmentsView_3_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.attachments.preview_AttachmentsView_3_en.png index 350eb731783..63c68481974 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.attachments.preview_AttachmentsView_3_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.attachments.preview_AttachmentsView_3_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:b4f33aa3545c29c25b3c40e6de90772e4e1f0685095429bdbcc4216e9020161c -size 89038 +oid sha256:df6fc9bcb3636549fdfeacb4c9e19cc3c699b7519558bd14f409e7b0c6a84d80 +size 89846 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.attachments.preview_AttachmentsView_4_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.attachments.preview_AttachmentsView_4_en.png index 6920a089ef4..a31bc036b59 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.attachments.preview_AttachmentsView_4_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.attachments.preview_AttachmentsView_4_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:507c7dffae1aabfa687174f1f964e2c40b004183b6bc3a70b56d764e0d308b47 -size 392923 +oid sha256:aedd5d3a01457b8ed06b16cd63d08f24ae34568e2b912b82fb892b154c94e6df +size 392780 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.attachments.preview_AttachmentsView_5_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.attachments.preview_AttachmentsView_5_en.png index d56a5de7d30..71d0679471d 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.attachments.preview_AttachmentsView_5_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.attachments.preview_AttachmentsView_5_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:7839db8763b29e38ad67380e09101e48fd3a650080967fb5e51a8bf6411d0427 -size 397423 +oid sha256:17aa655ef22beec5cef50f5d44cb2ecd8ad3a1979bc072a33079a49a8c4495c5 +size 397284 diff --git a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.local.video_MediaPlayerControllerView_Day_0_en.png b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.local.video_MediaPlayerControllerView_Day_0_en.png index 5a9251549c9..93d2782dbbe 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.local.video_MediaPlayerControllerView_Day_0_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.local.video_MediaPlayerControllerView_Day_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:e7a7ea1da7e7602cc53cc162c4a685516a7a46ca148eafca6e19a5748630bda5 -size 7036 +oid sha256:333a21a41a7d5f8d47946648a7381dadeccf213a1176696b3512c08ae929d4d6 +size 7819 diff --git a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.local.video_MediaPlayerControllerView_Day_1_en.png b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.local.video_MediaPlayerControllerView_Day_1_en.png index 3a2eb1a1032..a40e83dc489 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.local.video_MediaPlayerControllerView_Day_1_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.local.video_MediaPlayerControllerView_Day_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:bc35254c6962b5b113a2c25c4c9dd0c94449521152ffd73f41a0c36429fabbb0 -size 7258 +oid sha256:cba8f49caf65856569266a561206437840a43da2d41ed5f08321ecda99204329 +size 8236 diff --git a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.local.video_MediaPlayerControllerView_Night_0_en.png b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.local.video_MediaPlayerControllerView_Night_0_en.png index 08774369135..d6bb46d5c23 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.local.video_MediaPlayerControllerView_Night_0_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.local.video_MediaPlayerControllerView_Night_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:9f69e358ddd7e00f7301598f5dd235a2f5b9077f8926c2bfa3a4bca1168900f0 -size 7173 +oid sha256:773785bb234c0719c0f27ee91a970c63d7f971518dc0c83298a4b6adb9acc4cf +size 8066 diff --git a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.local.video_MediaPlayerControllerView_Night_1_en.png b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.local.video_MediaPlayerControllerView_Night_1_en.png index bc5633f7b6f..64ec4ae5d4f 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.local.video_MediaPlayerControllerView_Night_1_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.local.video_MediaPlayerControllerView_Night_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:b096093e04eb187fce0a85496c8a5b251afe0d0bccd977abcfb4d1e3dbe32a20 -size 7436 +oid sha256:5424e7ce4a5259aab297a7911741352f0fba01e5fdac972768441db9edf41171 +size 7675 diff --git a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.local.video_MediaVideoView_Day_0_en.png b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.local.video_MediaVideoView_Day_0_en.png index ec685d363a2..6ab81fd4de1 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.local.video_MediaVideoView_Day_0_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.local.video_MediaVideoView_Day_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:3b7160dc01dd4704bb07a8c91858bef0d4e99c0f55ca1d7dbdc3e22546a25125 -size 12210 +oid sha256:267d4be8b727a0ecb5af1e5f1e69adfd68f50f32f1de78f4f9fde60f635244b5 +size 13045 diff --git a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.local.video_MediaVideoView_Night_0_en.png b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.local.video_MediaVideoView_Night_0_en.png index df1ea796c15..48a87ab6aee 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.local.video_MediaVideoView_Night_0_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.local.video_MediaVideoView_Night_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:2591b742c64d3d058d4638e5014080f8b3eb13eba3a73951d71dfdc60e7676d9 -size 12455 +oid sha256:412476e819f688b5314651fd3d59439fc0e4f53ee777e3a070b82fd19d51700e +size 13272 diff --git a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.viewer_MediaViewerView_0_en.png b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.viewer_MediaViewerView_0_en.png index c6d641ba08b..ae44f16e97f 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.viewer_MediaViewerView_0_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.viewer_MediaViewerView_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a6fe771fa6492768239d0caf7a9c10613efb95ff9c2c1b786ee0a6974392af9f -size 389635 +oid sha256:9df1a0ff2b3aaab2d1a346cb134b560d65c462286575ffc6124099529562eac1 +size 389594 diff --git a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.viewer_MediaViewerView_10_en.png b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.viewer_MediaViewerView_10_en.png index 6a81f3f1294..347f2dd6c29 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.viewer_MediaViewerView_10_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.viewer_MediaViewerView_10_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:2b286342ff4d46637beac1f980294f77b3e2eb6824d56448cdbdce7b41c911ab -size 388612 +oid sha256:4fde3cef34d23c894ae480a1b4c961065f244d845584f8607c4bb21e0a7e5f10 +size 388615 diff --git a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.viewer_MediaViewerView_1_en.png b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.viewer_MediaViewerView_1_en.png index 909f84c0814..a9ae9d7999e 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.viewer_MediaViewerView_1_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.viewer_MediaViewerView_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:7b023a77242de9cab647e87b18edcd86a48a7843aa8fa51c84b443e3e8b41bcb -size 389669 +oid sha256:cf07ed00618c0552205b1e726050382369041bb7f2d9742b754a5652eca48265 +size 389631 diff --git a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.viewer_MediaViewerView_2_en.png b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.viewer_MediaViewerView_2_en.png index fb24aa81f39..173f440a849 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.viewer_MediaViewerView_2_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.viewer_MediaViewerView_2_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:75ff0cd0cfe594a217d2b58b48c2bb4aedad692a270c2cee8aa3d4bdf6758e1e -size 94797 +oid sha256:143285221dd5a1e714a9897293f13c45ca567635e60350738033b315f44f742a +size 94735 diff --git a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.viewer_MediaViewerView_3_en.png b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.viewer_MediaViewerView_3_en.png index 3b71589b75c..a63c5a2230d 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.viewer_MediaViewerView_3_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.viewer_MediaViewerView_3_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:0dc5fdbd7d0b3980ad19bf74640067e8bb294def913e3d13d7bc4ad9c822382d -size 389921 +oid sha256:a4e1b6a7a3dcc1627aec1767ac8edac95bec483ebdc98d71d65342084e08a4dc +size 396792 diff --git a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.viewer_MediaViewerView_4_en.png b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.viewer_MediaViewerView_4_en.png index d5d6d31f124..585ab58d5e4 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.viewer_MediaViewerView_4_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.viewer_MediaViewerView_4_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:05794effa4c47e3d2b68892e613f18a55c96789a4e65a182dd0bf2ca0c812d44 -size 14474 +oid sha256:6c3c2b7b1d64387ec1109ab21304df50de5bd4fac0317c27a2799e7405da3843 +size 22219 diff --git a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.viewer_MediaViewerView_5_en.png b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.viewer_MediaViewerView_5_en.png index b56bd6454a1..94ba7bede2a 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.viewer_MediaViewerView_5_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.viewer_MediaViewerView_5_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:e6113747e1677c2f28c2a109bc2c7075a753917068c1bbc3a46d5bdef4db4e23 -size 5756 +oid sha256:364fce9e921a21dcaae9ef1d7c98efe47c4c9118d23958550ee9eafaf202e2fa +size 5751 diff --git a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.viewer_MediaViewerView_6_en.png b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.viewer_MediaViewerView_6_en.png index 4cf13a8381f..72bdd87b183 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.viewer_MediaViewerView_6_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.viewer_MediaViewerView_6_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f5a6ec7984ceab5acf44431a9bff89c29c9ac27c95804d29b800124addd6e910 -size 14800 +oid sha256:769a00d9e84cb2da43d790158f35e66bc5ed6538fdcb7f5e316f5de13d9bd9ad +size 14768 diff --git a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.viewer_MediaViewerView_7_en.png b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.viewer_MediaViewerView_7_en.png index 27b6fb0c1b4..7658ec53754 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.viewer_MediaViewerView_7_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.viewer_MediaViewerView_7_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:d03b94e2b502b9857b9b4c2527df86d1aa0a194abed794cbe601ec4172422dcc -size 14987 +oid sha256:bf1804b21f3d383c94e28714746ac61987643c8ec0480d2850b19eb01991aa4e +size 15043 diff --git a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.viewer_MediaViewerView_8_en.png b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.viewer_MediaViewerView_8_en.png index f4d2b37db67..f9276290071 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.viewer_MediaViewerView_8_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.viewer_MediaViewerView_8_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:56b9d11058f06732364668a5833f52fa4e62541fa8ee48f13996ae0a11e11100 -size 13609 +oid sha256:ec58fa08f3c160e1b7d462b580f79b1c05a5644b9f807a79cfeebbeea417ed10 +size 13502 diff --git a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.viewer_MediaViewerView_9_en.png b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.viewer_MediaViewerView_9_en.png index b0693b38c5c..4394560d46d 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.viewer_MediaViewerView_9_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.viewer_MediaViewerView_9_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:25c1e3cb51b13bb65b281180862ac8fb6faa1e8bd0ce26d8d0e07321c03c116c -size 13742 +oid sha256:689081427ece8bc009266a50b9d2a80def581f51f00bf65b35d295b0ea7dcab3 +size 13736 From 70faf229cb9fa97bfb3679f730619e931dbe9629 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Mon, 2 Dec 2024 18:09:29 +0100 Subject: [PATCH 78/96] Fix modifier issue. --- .../libraries/mediaviewer/impl/viewer/MediaViewerView.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerView.kt b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerView.kt index a9b43843f53..96d513458df 100644 --- a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerView.kt +++ b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerView.kt @@ -350,7 +350,7 @@ private fun MediaViewerBottomBar( ) } Row( - modifier = modifier + modifier = Modifier .fillMaxWidth() .padding(start = 8.dp, end = 8.dp, bottom = 8.dp), verticalAlignment = Alignment.CenterVertically, From ad9f3d544d4247cc48e785b822bd75f89ceb2d94 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 2 Dec 2024 20:30:18 +0000 Subject: [PATCH 79/96] Update dependency com.lemonappdev:konsist to v0.17.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 1bcab24c19f..b11ef3fc76f 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -150,7 +150,7 @@ test_arch_core = "androidx.arch.core:core-testing:2.2.0" test_junit = "junit:junit:4.13.2" test_runner = "androidx.test:runner:1.6.2" test_mockk = "io.mockk:mockk:1.13.13" -test_konsist = "com.lemonappdev:konsist:0.17.0" +test_konsist = "com.lemonappdev:konsist:0.17.1" test_turbine = "app.cash.turbine:turbine:1.2.0" test_truth = "com.google.truth:truth:1.4.4" test_parameter_injector = "com.google.testparameterinjector:test-parameter-injector:1.18" From 5ea8d575d261650ebab8b49d1e29cee8a0c8c25b Mon Sep 17 00:00:00 2001 From: ganfra Date: Mon, 2 Dec 2024 16:19:57 +0100 Subject: [PATCH 80/96] navigation : clear backstack when opening room from outer node --- .../android/appnav/LoggedInFlowNode.kt | 55 ++++++++++++++++--- .../io/element/android/appnav/RootFlowNode.kt | 3 +- 2 files changed, 48 insertions(+), 10 deletions(-) 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 fa161554cdf..940e576a303 100644 --- a/appnav/src/main/kotlin/io/element/android/appnav/LoggedInFlowNode.kt +++ b/appnav/src/main/kotlin/io/element/android/appnav/LoggedInFlowNode.kt @@ -20,11 +20,20 @@ import androidx.lifecycle.repeatOnLifecycle import com.bumble.appyx.core.composable.PermanentChild import com.bumble.appyx.core.lifecycle.subscribe import com.bumble.appyx.core.modality.BuildContext +import com.bumble.appyx.core.navigation.NavElements +import com.bumble.appyx.core.navigation.NavKey import com.bumble.appyx.core.navigation.model.permanent.PermanentNavModel import com.bumble.appyx.core.node.Node import com.bumble.appyx.core.plugin.Plugin import com.bumble.appyx.core.plugin.plugins import com.bumble.appyx.navmodel.backstack.BackStack +import com.bumble.appyx.navmodel.backstack.BackStack.State.ACTIVE +import com.bumble.appyx.navmodel.backstack.BackStack.State.CREATED +import com.bumble.appyx.navmodel.backstack.BackStack.State.STASHED +import com.bumble.appyx.navmodel.backstack.BackStackElement +import com.bumble.appyx.navmodel.backstack.BackStackElements +import com.bumble.appyx.navmodel.backstack.operation.BackStackOperation +import com.bumble.appyx.navmodel.backstack.operation.Push import com.bumble.appyx.navmodel.backstack.operation.pop import com.bumble.appyx.navmodel.backstack.operation.push import com.bumble.appyx.navmodel.backstack.operation.replace @@ -312,7 +321,7 @@ class LoggedInFlowNode @AssistedInject constructor( } override fun onForwardedToSingleRoom(roomId: RoomId) { - coroutineScope.launch { attachRoom(roomId.toRoomIdOrAlias()) } + coroutineScope.launch { attachRoom(roomId.toRoomIdOrAlias(), clearBackstack = false) } } override fun onPermalinkClick(data: PermalinkData, pushToBackstack: Boolean) { @@ -472,21 +481,21 @@ class LoggedInFlowNode @AssistedInject constructor( serverNames: List = emptyList(), trigger: JoinedRoom.Trigger? = null, eventId: EventId? = null, + clearBackstack: Boolean, ) { waitForNavTargetAttached { navTarget -> navTarget is NavTarget.RoomList } attachChild { - backstack.push( - NavTarget.Room( - roomIdOrAlias = roomIdOrAlias, - serverNames = serverNames, - trigger = trigger, - initialElement = RoomNavigationTarget.Messages( - focusedEventId = eventId - ) + val roomNavTarget = NavTarget.Room( + roomIdOrAlias = roomIdOrAlias, + serverNames = serverNames, + trigger = trigger, + initialElement = RoomNavigationTarget.Messages( + focusedEventId = eventId ) ) + backstack.accept(AttachRoomOperation(roomNavTarget, clearBackstack)) } } @@ -531,3 +540,31 @@ class LoggedInFlowNode @AssistedInject constructor( @Assisted plugins: List, ) : Node(buildContext, plugins = plugins) } + +@Parcelize +private class AttachRoomOperation( + val roomTarget: LoggedInFlowNode.NavTarget.Room, + val clearBackstack: Boolean, +) : BackStackOperation { + override fun isApplicable(elements: NavElements) = true + + override fun invoke(elements: BackStackElements): BackStackElements { + return if (clearBackstack) { + // Makes sure the room list target is alone in the backstack and stashed + elements.mapNotNull { element -> + if (element.key.navTarget == LoggedInFlowNode.NavTarget.RoomList) { + element.transitionTo(STASHED, this) + } else { + null + } + } + BackStackElement( + key = NavKey(roomTarget), + fromState = CREATED, + targetState = ACTIVE, + operation = this + ) + } else { + Push(roomTarget).invoke(elements) + } + } +} 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 53f6de60324..143595d934c 100644 --- a/appnav/src/main/kotlin/io/element/android/appnav/RootFlowNode.kt +++ b/appnav/src/main/kotlin/io/element/android/appnav/RootFlowNode.kt @@ -303,6 +303,7 @@ class RootFlowNode @AssistedInject constructor( trigger = JoinedRoom.Trigger.MobilePermalink, serverNames = permalinkData.viaParameters, eventId = permalinkData.eventId, + clearBackstack = true ) } is PermalinkData.UserLink -> { @@ -318,7 +319,7 @@ class RootFlowNode @AssistedInject constructor( .apply { when (deeplinkData) { is DeeplinkData.Root -> Unit // The room list will always be shown, observing FtueState - is DeeplinkData.Room -> attachRoom(deeplinkData.roomId.toRoomIdOrAlias()) + is DeeplinkData.Room -> attachRoom(deeplinkData.roomId.toRoomIdOrAlias(), clearBackstack = true) } } } From 647fea6d34ae017888b84d293759d42f2f163a44 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 3 Dec 2024 00:11:06 +0000 Subject: [PATCH 81/96] Update dagger to v2.53 --- 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 1bcab24c19f..5294c273136 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -53,7 +53,7 @@ telephoto = "0.14.0" dependencyAnalysis = "2.5.0" # DI -dagger = "2.52" +dagger = "2.53" anvil = "0.4.0" # Auto service From 92975e83b650f52b921d2731301ab28f29a8d9d0 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Tue, 3 Dec 2024 09:26:03 +0100 Subject: [PATCH 82/96] Fix detekt issues. --- .../impl/local/video/MediaPlayerControllerView.kt | 4 +++- .../libraries/mediaviewer/impl/viewer/MediaViewerView.kt | 6 +++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/video/MediaPlayerControllerView.kt b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/video/MediaPlayerControllerView.kt index f0c6040412e..2a5757aa943 100644 --- a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/video/MediaPlayerControllerView.kt +++ b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/video/MediaPlayerControllerView.kt @@ -25,6 +25,7 @@ import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip import androidx.compose.ui.graphics.Color import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.style.TextAlign @@ -73,12 +74,13 @@ fun MediaPlayerControllerView( } Box( modifier = Modifier - .clickable { onTogglePlay() } .size(36.dp) .background( color = bgColor, shape = CircleShape, ) + .clip(CircleShape) + .clickable { onTogglePlay() } .padding(8.dp), contentAlignment = Alignment.Center, ) { diff --git a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerView.kt b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerView.kt index 96d513458df..cdcc6f9fb2f 100644 --- a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerView.kt +++ b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerView.kt @@ -129,7 +129,7 @@ fun MediaViewerView( canShare = state.canShare, mimeType = state.mediaInfo.mimeType, caption = state.mediaInfo.caption, - onHeightChanged = { bottomPaddingInPixels = it }, + onHeightChange = { bottomPaddingInPixels = it }, eventSink = state.eventSink ) } @@ -325,7 +325,7 @@ private fun MediaViewerBottomBar( canShare: Boolean, mimeType: String, caption: String?, - onHeightChanged: (Int) -> Unit, + onHeightChange: (Int) -> Unit, eventSink: (MediaViewerEvents) -> Unit, modifier: Modifier = Modifier, ) { @@ -334,7 +334,7 @@ private fun MediaViewerBottomBar( .fillMaxWidth() .background(Color(0x99101317)) .onSizeChanged { - onHeightChanged(it.height) + onHeightChange(it.height) }, ) { HorizontalDivider() From a21bd16af605fcef8118db7994dbb1b7f6108837 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Tue, 3 Dec 2024 09:42:13 +0100 Subject: [PATCH 83/96] Move more fields to TimelineItemEventContentWithAttachment --- .../features/messages/impl/MessagesFlowNode.kt | 4 ++-- .../event/TimelineItemContentMessageFactory.kt | 6 ++++-- .../model/event/TimelineItemAudioContent.kt | 8 ++++---- .../model/event/TimelineItemEventContent.kt | 5 +++++ .../model/event/TimelineItemFileContent.kt | 8 ++++---- .../event/TimelineItemFileContentProvider.kt | 2 +- .../model/event/TimelineItemImageContent.kt | 8 ++++---- .../model/event/TimelineItemStickerContent.kt | 8 ++++---- .../model/event/TimelineItemVideoContent.kt | 8 ++++---- .../event/TimelineItemVideoContentProvider.kt | 2 +- .../model/event/TimelineItemVoiceContent.kt | 6 ++++-- .../event/TimelineItemVoiceContentProvider.kt | 2 ++ .../messages/impl/MessagesPresenterTest.kt | 4 ++-- .../TimelineItemContentMessageFactoryTest.kt | 16 ++++++++++------ 14 files changed, 51 insertions(+), 36 deletions(-) diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesFlowNode.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesFlowNode.kt index e80f99a67cb..53500cfd351 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesFlowNode.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesFlowNode.kt @@ -381,7 +381,7 @@ class MessagesFlowNode @AssistedInject constructor( senderName = event.safeSenderName, dateSent = event.sentTime, ), - mediaSource = event.content.videoSource, + mediaSource = event.content.mediaSource, thumbnailSource = event.content.thumbnailSource, ) overlay.show(navTarget) @@ -398,7 +398,7 @@ class MessagesFlowNode @AssistedInject constructor( senderName = event.safeSenderName, dateSent = event.sentTime, ), - mediaSource = event.content.fileSource, + mediaSource = event.content.mediaSource, thumbnailSource = event.content.thumbnailSource, ) overlay.show(navTarget) diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/factories/event/TimelineItemContentMessageFactory.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/factories/event/TimelineItemContentMessageFactory.kt index 867cb694db1..c2515560f53 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/factories/event/TimelineItemContentMessageFactory.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/factories/event/TimelineItemContentMessageFactory.kt @@ -147,7 +147,7 @@ class TimelineItemContentMessageFactory @Inject constructor( formattedCaption = parseHtml(messageType.formattedCaption) ?: messageType.caption?.withLinks(), isEdited = content.isEdited, thumbnailSource = messageType.info?.thumbnailSource, - videoSource = messageType.source, + mediaSource = messageType.source, mimeType = messageType.info?.mimetype ?: MimeTypes.OctetStream, width = messageType.info?.width?.toInt(), height = messageType.info?.height?.toInt(), @@ -186,6 +186,8 @@ class TimelineItemContentMessageFactory @Inject constructor( duration = messageType.info?.duration ?: Duration.ZERO, mimeType = messageType.info?.mimetype ?: MimeTypes.OctetStream, waveform = messageType.details?.waveform?.toImmutableList() ?: persistentListOf(), + formattedFileSize = fileSizeFormatter.format(messageType.info?.size ?: 0), + fileExtension = fileExtensionExtractor.extractFromName(messageType.filename) ) } false -> { @@ -211,7 +213,7 @@ class TimelineItemContentMessageFactory @Inject constructor( formattedCaption = parseHtml(messageType.formattedCaption) ?: messageType.caption?.withLinks(), isEdited = content.isEdited, thumbnailSource = messageType.info?.thumbnailSource, - fileSource = messageType.source, + mediaSource = messageType.source, mimeType = messageType.info?.mimetype ?: MimeTypes.fromFileExtension(fileExtension), formattedFileSize = fileSizeFormatter.format(messageType.info?.size ?: 0), fileExtension = fileExtension diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/model/event/TimelineItemAudioContent.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/model/event/TimelineItemAudioContent.kt index 46176cc4744..a3b2061b920 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/model/event/TimelineItemAudioContent.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/model/event/TimelineItemAudioContent.kt @@ -17,10 +17,10 @@ data class TimelineItemAudioContent( override val formattedCaption: CharSequence?, override val isEdited: Boolean, val duration: Duration, - val mediaSource: MediaSource, - val mimeType: String, - val formattedFileSize: String, - val fileExtension: String, + override val mediaSource: MediaSource, + override val mimeType: String, + override val formattedFileSize: String, + override val fileExtension: String, ) : TimelineItemEventContentWithAttachment { val fileExtensionAndSize = formatFileExtensionAndSize( diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/model/event/TimelineItemEventContent.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/model/event/TimelineItemEventContent.kt index 62c55c22eff..6c823462bf4 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/model/event/TimelineItemEventContent.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/model/event/TimelineItemEventContent.kt @@ -8,6 +8,7 @@ package io.element.android.features.messages.impl.timeline.model.event import androidx.compose.runtime.Immutable +import io.element.android.libraries.matrix.api.media.MediaSource @Immutable sealed interface TimelineItemEventContent { @@ -26,6 +27,10 @@ sealed interface TimelineItemEventContentWithAttachment : val filename: String val caption: String? val formattedCaption: CharSequence? + val mediaSource: MediaSource + val mimeType: String + val formattedFileSize: String + val fileExtension: String val bestDescription: String get() = caption ?: filename diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/model/event/TimelineItemFileContent.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/model/event/TimelineItemFileContent.kt index 3f1d8fe0412..286411c5111 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/model/event/TimelineItemFileContent.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/model/event/TimelineItemFileContent.kt @@ -15,11 +15,11 @@ data class TimelineItemFileContent( override val caption: String?, override val formattedCaption: CharSequence?, override val isEdited: Boolean, - val fileSource: MediaSource, + override val mediaSource: MediaSource, val thumbnailSource: MediaSource?, - val formattedFileSize: String, - val fileExtension: String, - val mimeType: String, + override val formattedFileSize: String, + override val fileExtension: String, + override val mimeType: String, ) : TimelineItemEventContentWithAttachment { override val type: String = "TimelineItemFileContent" diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/model/event/TimelineItemFileContentProvider.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/model/event/TimelineItemFileContentProvider.kt index 409e26079e1..b8f28c741a6 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/model/event/TimelineItemFileContentProvider.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/model/event/TimelineItemFileContentProvider.kt @@ -31,7 +31,7 @@ fun aTimelineItemFileContent( formattedCaption = null, isEdited = false, thumbnailSource = null, - fileSource = MediaSource(url = ""), + mediaSource = MediaSource(url = ""), mimeType = MimeTypes.Pdf, formattedFileSize = "100kB", fileExtension = "pdf" diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/model/event/TimelineItemImageContent.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/model/event/TimelineItemImageContent.kt index 78323166b4f..80b055a5a6d 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/model/event/TimelineItemImageContent.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/model/event/TimelineItemImageContent.kt @@ -18,11 +18,11 @@ data class TimelineItemImageContent( override val caption: String?, override val formattedCaption: CharSequence?, override val isEdited: Boolean, - val mediaSource: MediaSource, + override val mediaSource: MediaSource, val thumbnailSource: MediaSource?, - val formattedFileSize: String, - val fileExtension: String, - val mimeType: String, + override val formattedFileSize: String, + override val fileExtension: String, + override val mimeType: String, val blurhash: String?, val width: Int?, val height: Int?, 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 ebaeb53b4b9..ebf25d7e959 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 @@ -14,11 +14,11 @@ data class TimelineItemStickerContent( override val caption: String?, override val formattedCaption: CharSequence?, override val isEdited: Boolean, - val mediaSource: MediaSource, + override val mediaSource: MediaSource, val thumbnailSource: MediaSource?, - val formattedFileSize: String, - val fileExtension: String, - val mimeType: String, + override val formattedFileSize: String, + override val fileExtension: String, + override val mimeType: String, val blurhash: String?, val width: Int?, val height: Int?, diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/model/event/TimelineItemVideoContent.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/model/event/TimelineItemVideoContent.kt index caee06ef64c..74406aaf373 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/model/event/TimelineItemVideoContent.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/model/event/TimelineItemVideoContent.kt @@ -16,7 +16,7 @@ data class TimelineItemVideoContent( override val formattedCaption: CharSequence?, override val isEdited: Boolean, val duration: Duration, - val videoSource: MediaSource, + override val mediaSource: MediaSource, val thumbnailSource: MediaSource?, val aspectRatio: Float?, val blurHash: String?, @@ -24,9 +24,9 @@ data class TimelineItemVideoContent( val width: Int?, val thumbnailWidth: Int?, val thumbnailHeight: Int?, - val mimeType: String, - val formattedFileSize: String, - val fileExtension: String, + override val mimeType: String, + override val formattedFileSize: String, + override val fileExtension: String, ) : TimelineItemEventContentWithAttachment { override val type: String = "TimelineItemImageContent" diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/model/event/TimelineItemVideoContentProvider.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/model/event/TimelineItemVideoContentProvider.kt index 1ed05fa6066..477c00d808f 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/model/event/TimelineItemVideoContentProvider.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/model/event/TimelineItemVideoContentProvider.kt @@ -35,7 +35,7 @@ fun aTimelineItemVideoContent( blurHash = blurhash, aspectRatio = aspectRatio, duration = 100.milliseconds, - videoSource = MediaSource(""), + mediaSource = MediaSource(""), width = 150, height = 300, thumbnailWidth = 150, diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/model/event/TimelineItemVoiceContent.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/model/event/TimelineItemVoiceContent.kt index 21b6696ffe2..ad3908166a5 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/model/event/TimelineItemVoiceContent.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/model/event/TimelineItemVoiceContent.kt @@ -19,8 +19,10 @@ data class TimelineItemVoiceContent( override val formattedCaption: CharSequence?, override val isEdited: Boolean, val duration: Duration, - val mediaSource: MediaSource, - val mimeType: String, + override val mediaSource: MediaSource, + override val formattedFileSize: String, + override val fileExtension: String, + override val mimeType: String, val waveform: ImmutableList, ) : TimelineItemEventContentWithAttachment { override val type: String = "TimelineItemAudioContent" diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/model/event/TimelineItemVoiceContentProvider.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/model/event/TimelineItemVoiceContentProvider.kt index bd7308d9704..0c3fd246ca1 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/model/event/TimelineItemVoiceContentProvider.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/model/event/TimelineItemVoiceContentProvider.kt @@ -53,4 +53,6 @@ fun aTimelineItemVoiceContent( mediaSource = mediaSource, mimeType = mimeType, waveform = waveform.toPersistentList(), + formattedFileSize = "1.0 MB", + fileExtension = "ogg", ) diff --git a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/MessagesPresenterTest.kt b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/MessagesPresenterTest.kt index 541034bc573..8cb7464a9ad 100644 --- a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/MessagesPresenterTest.kt +++ b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/MessagesPresenterTest.kt @@ -371,7 +371,7 @@ class MessagesPresenterTest { formattedCaption = null, isEdited = false, duration = 10.milliseconds, - videoSource = MediaSource(AN_AVATAR_URL), + mediaSource = MediaSource(AN_AVATAR_URL), thumbnailSource = MediaSource(AN_AVATAR_URL), mimeType = MimeTypes.Mp4, blurHash = null, @@ -413,7 +413,7 @@ class MessagesPresenterTest { caption = null, isEdited = false, formattedCaption = null, - fileSource = MediaSource(AN_AVATAR_URL), + mediaSource = MediaSource(AN_AVATAR_URL), thumbnailSource = MediaSource(AN_AVATAR_URL), formattedFileSize = "10 MB", mimeType = MimeTypes.Pdf, diff --git a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/timeline/factories/event/TimelineItemContentMessageFactoryTest.kt b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/timeline/factories/event/TimelineItemContentMessageFactoryTest.kt index b771141ce33..751186554ca 100644 --- a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/timeline/factories/event/TimelineItemContentMessageFactoryTest.kt +++ b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/timeline/factories/event/TimelineItemContentMessageFactoryTest.kt @@ -239,7 +239,7 @@ class TimelineItemContentMessageFactoryTest { formattedCaption = null, isEdited = false, duration = Duration.ZERO, - videoSource = MediaSource(url = "url", json = null), + mediaSource = MediaSource(url = "url", json = null), thumbnailSource = null, aspectRatio = null, blurHash = null, @@ -291,7 +291,7 @@ class TimelineItemContentMessageFactoryTest { formattedCaption = SpannedString("formatted"), isEdited = true, duration = 1.minutes, - videoSource = MediaSource(url = "url", json = null), + mediaSource = MediaSource(url = "url", json = null), thumbnailSource = MediaSource("url_thumbnail"), aspectRatio = 3f, blurHash = A_BLUR_HASH, @@ -380,7 +380,9 @@ class TimelineItemContentMessageFactoryTest { duration = Duration.ZERO, mediaSource = MediaSource(url = "url", json = null), mimeType = MimeTypes.OctetStream, - waveform = emptyList().toImmutableList() + waveform = emptyList().toImmutableList(), + fileExtension = "", + formattedFileSize = "", ) assertThat(result).isEqualTo(expected) } @@ -419,7 +421,9 @@ class TimelineItemContentMessageFactoryTest { duration = 1.minutes, mediaSource = MediaSource(url = "url", json = null), mimeType = MimeTypes.Ogg, - waveform = persistentListOf(1f, 2f) + waveform = persistentListOf(1f, 2f), + fileExtension = "", + formattedFileSize = "", ) assertThat(result).isEqualTo(expected) } @@ -571,7 +575,7 @@ class TimelineItemContentMessageFactoryTest { caption = null, formattedCaption = null, isEdited = false, - fileSource = MediaSource(url = "url", json = null), + mediaSource = MediaSource(url = "url", json = null), thumbnailSource = null, formattedFileSize = "0 Bytes", fileExtension = "", @@ -612,7 +616,7 @@ class TimelineItemContentMessageFactoryTest { caption = null, formattedCaption = null, isEdited = true, - fileSource = MediaSource(url = "url", json = null), + mediaSource = MediaSource(url = "url", json = null), thumbnailSource = MediaSource("url_thumbnail"), formattedFileSize = "123 Bytes", fileExtension = "pdf", From dbb062f230db3499c8f70e6a90b45559e2de1815 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Tue, 3 Dec 2024 09:59:18 +0100 Subject: [PATCH 84/96] Create method buildMediaViewerNavTarget --- .../messages/impl/MessagesFlowNode.kt | 87 ++++++++----------- 1 file changed, 37 insertions(+), 50 deletions(-) diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesFlowNode.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesFlowNode.kt index 53500cfd351..f6400f579b8 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesFlowNode.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesFlowNode.kt @@ -40,6 +40,7 @@ import io.element.android.features.messages.impl.timeline.TimelineController import io.element.android.features.messages.impl.timeline.debug.EventDebugInfoNode import io.element.android.features.messages.impl.timeline.model.TimelineItem import io.element.android.features.messages.impl.timeline.model.event.TimelineItemAudioContent +import io.element.android.features.messages.impl.timeline.model.event.TimelineItemEventContentWithAttachment import io.element.android.features.messages.impl.timeline.model.event.TimelineItemFileContent import io.element.android.features.messages.impl.timeline.model.event.TimelineItemImageContent import io.element.android.features.messages.impl.timeline.model.event.TimelineItemLocationContent @@ -331,16 +332,9 @@ class MessagesFlowNode @AssistedInject constructor( private fun processEventClick(event: TimelineItem.Event): Boolean { return when (event.content) { is TimelineItemImageContent -> { - val navTarget = NavTarget.MediaViewer( - mediaInfo = MediaInfo( - filename = event.content.filename, - caption = event.content.caption, - mimeType = event.content.mimeType, - formattedFileSize = event.content.formattedFileSize, - fileExtension = event.content.fileExtension, - senderName = event.safeSenderName, - dateSent = event.sentTime, - ), + val navTarget = buildMediaViewerNavTarget( + event = event, + content = event.content, mediaSource = event.content.mediaSource, thumbnailSource = event.content.thumbnailSource, ) @@ -351,16 +345,9 @@ class MessagesFlowNode @AssistedInject constructor( /* Sticker may have an empty url and no thumbnail if encrypted on certain bridges */ if (event.content.preferredMediaSource != null) { - val navTarget = NavTarget.MediaViewer( - mediaInfo = MediaInfo( - filename = event.content.filename, - caption = event.content.caption, - mimeType = event.content.mimeType, - formattedFileSize = event.content.formattedFileSize, - fileExtension = event.content.fileExtension, - senderName = event.safeSenderName, - dateSent = event.sentTime, - ), + val navTarget = buildMediaViewerNavTarget( + event = event, + content = event.content, mediaSource = event.content.preferredMediaSource, thumbnailSource = event.content.thumbnailSource, ) @@ -371,16 +358,9 @@ class MessagesFlowNode @AssistedInject constructor( } } is TimelineItemVideoContent -> { - val navTarget = NavTarget.MediaViewer( - mediaInfo = MediaInfo( - filename = event.content.filename, - caption = event.content.caption, - mimeType = event.content.mimeType, - formattedFileSize = event.content.formattedFileSize, - fileExtension = event.content.fileExtension, - senderName = event.safeSenderName, - dateSent = event.sentTime, - ), + val navTarget = buildMediaViewerNavTarget( + event = event, + content = event.content, mediaSource = event.content.mediaSource, thumbnailSource = event.content.thumbnailSource, ) @@ -388,16 +368,9 @@ class MessagesFlowNode @AssistedInject constructor( true } is TimelineItemFileContent -> { - val navTarget = NavTarget.MediaViewer( - mediaInfo = MediaInfo( - filename = event.content.filename, - caption = event.content.caption, - mimeType = event.content.mimeType, - formattedFileSize = event.content.formattedFileSize, - fileExtension = event.content.fileExtension, - senderName = event.safeSenderName, - dateSent = event.sentTime, - ), + val navTarget = buildMediaViewerNavTarget( + event = event, + content = event.content, mediaSource = event.content.mediaSource, thumbnailSource = event.content.thumbnailSource, ) @@ -405,16 +378,9 @@ class MessagesFlowNode @AssistedInject constructor( true } is TimelineItemAudioContent -> { - val navTarget = NavTarget.MediaViewer( - mediaInfo = MediaInfo( - filename = event.content.filename, - caption = event.content.caption, - mimeType = event.content.mimeType, - formattedFileSize = event.content.formattedFileSize, - fileExtension = event.content.fileExtension, - senderName = event.safeSenderName, - dateSent = event.sentTime, - ), + val navTarget = buildMediaViewerNavTarget( + event = event, + content = event.content, mediaSource = event.content.mediaSource, thumbnailSource = null, ) @@ -433,6 +399,27 @@ class MessagesFlowNode @AssistedInject constructor( } } + private fun buildMediaViewerNavTarget( + event: TimelineItem.Event, + content: TimelineItemEventContentWithAttachment, + mediaSource: MediaSource, + thumbnailSource: MediaSource?, + ): NavTarget { + return NavTarget.MediaViewer( + mediaInfo = MediaInfo( + filename = content.filename, + caption = content.caption, + mimeType = content.mimeType, + formattedFileSize = content.formattedFileSize, + fileExtension = content.fileExtension, + senderName = event.safeSenderName, + dateSent = event.sentTime, + ), + mediaSource = mediaSource, + thumbnailSource = thumbnailSource, + ) + } + @Composable override fun View(modifier: Modifier) { mentionSpanTheme.updateStyles(currentUserId = room.sessionId) From 04edf84783c0399c1f91ff1be80a0cd154a8192c Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Tue, 3 Dec 2024 10:17:28 +0100 Subject: [PATCH 85/96] Fix navigation issue. LocationViewer should not use the Appyx overlay. --- .../element/android/features/messages/impl/MessagesFlowNode.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesFlowNode.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesFlowNode.kt index f6400f579b8..3d014fd0242 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesFlowNode.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesFlowNode.kt @@ -392,7 +392,7 @@ class MessagesFlowNode @AssistedInject constructor( location = event.content.location, description = event.content.description, ) - overlay.show(navTarget) + backstack.push(navTarget) true } else -> false From 0574c14421a58314eb227ce0bb01455678c7f72f Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Tue, 3 Dec 2024 10:21:06 +0100 Subject: [PATCH 86/96] Simplify code. --- .../messages/impl/MessagesFlowNode.kt | 39 +++++++++---------- 1 file changed, 18 insertions(+), 21 deletions(-) diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesFlowNode.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesFlowNode.kt index 3d014fd0242..8cbb7b6d748 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesFlowNode.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesFlowNode.kt @@ -330,68 +330,65 @@ class MessagesFlowNode @AssistedInject constructor( } private fun processEventClick(event: TimelineItem.Event): Boolean { - return when (event.content) { + val navTarget = when (event.content) { is TimelineItemImageContent -> { - val navTarget = buildMediaViewerNavTarget( + buildMediaViewerNavTarget( event = event, content = event.content, mediaSource = event.content.mediaSource, thumbnailSource = event.content.thumbnailSource, ) - overlay.show(navTarget) - true } is TimelineItemStickerContent -> { /* Sticker may have an empty url and no thumbnail if encrypted on certain bridges */ - if (event.content.preferredMediaSource != null) { - val navTarget = buildMediaViewerNavTarget( + event.content.preferredMediaSource?.let { preferredMediaSource -> + buildMediaViewerNavTarget( event = event, content = event.content, - mediaSource = event.content.preferredMediaSource, + mediaSource = preferredMediaSource, thumbnailSource = event.content.thumbnailSource, ) - overlay.show(navTarget) - true - } else { - false } } is TimelineItemVideoContent -> { - val navTarget = buildMediaViewerNavTarget( + buildMediaViewerNavTarget( event = event, content = event.content, mediaSource = event.content.mediaSource, thumbnailSource = event.content.thumbnailSource, ) - overlay.show(navTarget) - true } is TimelineItemFileContent -> { - val navTarget = buildMediaViewerNavTarget( + buildMediaViewerNavTarget( event = event, content = event.content, mediaSource = event.content.mediaSource, thumbnailSource = event.content.thumbnailSource, ) - overlay.show(navTarget) - true } is TimelineItemAudioContent -> { - val navTarget = buildMediaViewerNavTarget( + buildMediaViewerNavTarget( event = event, content = event.content, mediaSource = event.content.mediaSource, thumbnailSource = null, ) - overlay.show(navTarget) - true } is TimelineItemLocationContent -> { - val navTarget = NavTarget.LocationViewer( + NavTarget.LocationViewer( location = event.content.location, description = event.content.description, ) + } + else -> null + } + return when (navTarget) { + is NavTarget.MediaViewer -> { + overlay.show(navTarget) + true + } + is NavTarget.LocationViewer -> { backstack.push(navTarget) true } From bf7e978e7423f1f21461fad9243b8fcab6ec8a5d Mon Sep 17 00:00:00 2001 From: Valere Date: Tue, 3 Dec 2024 11:20:55 +0100 Subject: [PATCH 87/96] Update withheld unverified string --- libraries/ui-strings/src/main/res/values/localazy.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/ui-strings/src/main/res/values/localazy.xml b/libraries/ui-strings/src/main/res/values/localazy.xml index 02c85887ae8..8f4aa8b20c2 100644 --- a/libraries/ui-strings/src/main/res/values/localazy.xml +++ b/libraries/ui-strings/src/main/res/values/localazy.xml @@ -367,5 +367,5 @@ Reason: %1$s." "en" "Historical messages are not available on this device" "Unable to decrypt message" - "This message was blocked either because your device is unverified or because the sender needs to verify your identity." + "This message was blocked either because you did not verify your device or because the sender needs to verify your identity." From 5e927398b143ba519482735070f77491909ba1f2 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Tue, 3 Dec 2024 11:37:19 +0100 Subject: [PATCH 88/96] Fix tests. --- .../event/TimelineItemContentMessageFactoryTest.kt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/timeline/factories/event/TimelineItemContentMessageFactoryTest.kt b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/timeline/factories/event/TimelineItemContentMessageFactoryTest.kt index 751186554ca..fb853f44727 100644 --- a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/timeline/factories/event/TimelineItemContentMessageFactoryTest.kt +++ b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/timeline/factories/event/TimelineItemContentMessageFactoryTest.kt @@ -382,7 +382,7 @@ class TimelineItemContentMessageFactoryTest { mimeType = MimeTypes.OctetStream, waveform = emptyList().toImmutableList(), fileExtension = "", - formattedFileSize = "", + formattedFileSize = "0 Bytes", ) assertThat(result).isEqualTo(expected) } @@ -422,8 +422,8 @@ class TimelineItemContentMessageFactoryTest { mediaSource = MediaSource(url = "url", json = null), mimeType = MimeTypes.Ogg, waveform = persistentListOf(1f, 2f), - fileExtension = "", - formattedFileSize = "", + fileExtension = "ogg", + formattedFileSize = "123 Bytes", ) assertThat(result).isEqualTo(expected) } From a475cb856841f4a6db4e2816501fdd519275d807 Mon Sep 17 00:00:00 2001 From: ganfra Date: Mon, 2 Dec 2024 21:57:20 +0100 Subject: [PATCH 89/96] fix : hide keyboard when TextComposer is removed from composition --- .../utils/HideKeyboardWhenDisposed.kt | 22 +++++++++++++++++++ .../libraries/textcomposer/TextComposer.kt | 2 ++ 2 files changed, 24 insertions(+) create mode 100644 libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/utils/HideKeyboardWhenDisposed.kt diff --git a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/utils/HideKeyboardWhenDisposed.kt b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/utils/HideKeyboardWhenDisposed.kt new file mode 100644 index 00000000000..0e18528605c --- /dev/null +++ b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/utils/HideKeyboardWhenDisposed.kt @@ -0,0 +1,22 @@ +/* + * Copyright 2024 New Vector Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only + * Please see LICENSE in the repository root for full details. + */ + +package io.element.android.libraries.designsystem.utils + +import androidx.compose.runtime.Composable +import androidx.compose.runtime.DisposableEffect +import androidx.compose.ui.platform.LocalSoftwareKeyboardController + +@Composable +fun HideKeyboardWhenDisposed() { + val keyboardController = LocalSoftwareKeyboardController.current + DisposableEffect(Unit) { + onDispose { + keyboardController?.hide() + } + } +} diff --git a/libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/TextComposer.kt b/libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/TextComposer.kt index 9ebb5a7c228..274453533b1 100644 --- a/libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/TextComposer.kt +++ b/libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/TextComposer.kt @@ -47,6 +47,7 @@ import io.element.android.libraries.designsystem.preview.PreviewsDayNight import io.element.android.libraries.designsystem.theme.components.CircularProgressIndicator import io.element.android.libraries.designsystem.theme.components.Icon import io.element.android.libraries.designsystem.theme.components.Text +import io.element.android.libraries.designsystem.utils.HideKeyboardWhenDisposed import io.element.android.libraries.matrix.api.core.EventId import io.element.android.libraries.matrix.api.timeline.item.event.EventOrTransactionId import io.element.android.libraries.matrix.api.timeline.item.event.toEventOrTransactionId @@ -323,6 +324,7 @@ fun TextComposer( } } } + HideKeyboardWhenDisposed() } @Composable From 54b4d0237140a033a49aedae965e7b944225a7b4 Mon Sep 17 00:00:00 2001 From: ganfra Date: Tue, 3 Dec 2024 12:51:21 +0100 Subject: [PATCH 90/96] room preview : catch all exception --- .../android/libraries/matrix/impl/room/RustRoomFactory.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/RustRoomFactory.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/RustRoomFactory.kt index 84f34ae9bfd..d39d45c067e 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/RustRoomFactory.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/RustRoomFactory.kt @@ -141,7 +141,7 @@ class RustRoomFactory( } val innerRoom = try { roomListItem.previewRoom(via = emptyList()) - } catch (e: RoomListException) { + } catch (e: Exception) { Timber.e(e, "Failed to get pending room for $roomId") return@withContext null } From 73c9ab869641a91ee135ed4a1fb1ddde40e820e3 Mon Sep 17 00:00:00 2001 From: ElementBot Date: Tue, 3 Dec 2024 13:41:36 +0000 Subject: [PATCH 91/96] Update screenshots --- ...ne.components.event_TimelineItemEncryptedView_Day_4_en.png | 4 ++-- ...ne.components.event_TimelineItemEncryptedView_Day_5_en.png | 3 +++ ...ne.components.event_TimelineItemEncryptedView_Day_6_en.png | 3 +++ ...ne.components.event_TimelineItemEncryptedView_Day_7_en.png | 3 +++ ....components.event_TimelineItemEncryptedView_Night_4_en.png | 4 ++-- ....components.event_TimelineItemEncryptedView_Night_5_en.png | 3 +++ ....components.event_TimelineItemEncryptedView_Night_6_en.png | 3 +++ ....components.event_TimelineItemEncryptedView_Night_7_en.png | 3 +++ 8 files changed, 22 insertions(+), 4 deletions(-) create mode 100644 tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemEncryptedView_Day_5_en.png create mode 100644 tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemEncryptedView_Day_6_en.png create mode 100644 tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemEncryptedView_Day_7_en.png create mode 100644 tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemEncryptedView_Night_5_en.png create mode 100644 tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemEncryptedView_Night_6_en.png create mode 100644 tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemEncryptedView_Night_7_en.png diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemEncryptedView_Day_4_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemEncryptedView_Day_4_en.png index afa1dd9b61b..ffb879e7704 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemEncryptedView_Day_4_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemEncryptedView_Day_4_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:fee2af8462597d58274b7168c5cfe1f6d6b0909b048adc0f4fc5b3c12a90b859 -size 8861 +oid sha256:397d76d3fe47c61d112b09355097f103ef3ab38caaa99d838d44498a85969289 +size 12419 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemEncryptedView_Day_5_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemEncryptedView_Day_5_en.png new file mode 100644 index 00000000000..ee6bed15eb7 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemEncryptedView_Day_5_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:21dcb76e1f9712325c1d47603e121849298aba995d493380ccc3a174296f0dd5 +size 23794 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemEncryptedView_Day_6_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemEncryptedView_Day_6_en.png new file mode 100644 index 00000000000..cff8f7e35f8 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemEncryptedView_Day_6_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d5c8494ebb4ceaf3a31b661aec47f8a33afeb7aab1457483b7009099a6b56f86 +size 8960 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemEncryptedView_Day_7_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemEncryptedView_Day_7_en.png new file mode 100644 index 00000000000..afa1dd9b61b --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemEncryptedView_Day_7_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:fee2af8462597d58274b7168c5cfe1f6d6b0909b048adc0f4fc5b3c12a90b859 +size 8861 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemEncryptedView_Night_4_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemEncryptedView_Night_4_en.png index 212726df377..3809d0c0d53 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemEncryptedView_Night_4_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemEncryptedView_Night_4_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:d4f48cd7dc7e2bbf7363d1127e46721c25bb8dd887927dbcffe525f5bb5bae01 -size 8781 +oid sha256:252efa710f80f4ea57c909cfd5cfee2beef982a209367138f10972dd5aa49db2 +size 12264 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemEncryptedView_Night_5_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemEncryptedView_Night_5_en.png new file mode 100644 index 00000000000..78b8059fe51 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemEncryptedView_Night_5_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:12ba26807e062ad5146847438ad82b9c24805c3edbc3c949f5ba3ac20c768af0 +size 23430 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemEncryptedView_Night_6_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemEncryptedView_Night_6_en.png new file mode 100644 index 00000000000..a851ce84e55 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemEncryptedView_Night_6_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:dda55a19381d9f51a270afa644894f909d8c479be0a5e57b977393c9f1253683 +size 8960 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemEncryptedView_Night_7_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemEncryptedView_Night_7_en.png new file mode 100644 index 00000000000..212726df377 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemEncryptedView_Night_7_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d4f48cd7dc7e2bbf7363d1127e46721c25bb8dd887927dbcffe525f5bb5bae01 +size 8781 From 3e9fb94b9de0e9fdc5d36eb5c4c6a39f24cf02f7 Mon Sep 17 00:00:00 2001 From: ganfra Date: Tue, 3 Dec 2024 15:55:31 +0100 Subject: [PATCH 92/96] fix(ui) : update timeline informative view --- .../event/TimelineItemInformativeView.kt | 20 ++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/event/TimelineItemInformativeView.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/event/TimelineItemInformativeView.kt index 58f2f257127..304527e8061 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/event/TimelineItemInformativeView.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/event/TimelineItemInformativeView.kt @@ -8,8 +8,10 @@ package io.element.android.features.messages.impl.timeline.components.event import androidx.annotation.DrawableRes +import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width import androidx.compose.material3.MaterialTheme @@ -44,14 +46,18 @@ fun TimelineItemInformativeView( ) ) }, - verticalAlignment = Alignment.CenterVertically, ) { - Icon( - resourceId = iconResourceId, - tint = MaterialTheme.colorScheme.secondary, - contentDescription = iconDescription, - modifier = Modifier.size(16.dp) - ) + Box( + contentAlignment = Alignment.Center, + modifier = Modifier.height(20.dp) + ) { + Icon( + resourceId = iconResourceId, + tint = MaterialTheme.colorScheme.secondary, + contentDescription = iconDescription, + modifier = Modifier.size(16.dp) + ) + } Spacer(modifier = Modifier.width(4.dp)) Text( fontStyle = FontStyle.Italic, From d83bd5bceee4c6879eda6a5ba2ce7ccbb45cb4d5 Mon Sep 17 00:00:00 2001 From: ElementBot Date: Tue, 3 Dec 2024 15:07:54 +0000 Subject: [PATCH 93/96] Update screenshots --- ...ne.components.event_TimelineItemEncryptedView_Day_5_en.png | 4 ++-- ....components.event_TimelineItemEncryptedView_Night_5_en.png | 4 ++-- ...l.timeline.components_TimelineItemEventRowUtd_Day_0_en.png | 4 ++-- ...timeline.components_TimelineItemEventRowUtd_Night_0_en.png | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemEncryptedView_Day_5_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemEncryptedView_Day_5_en.png index ee6bed15eb7..8f51f4d170e 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemEncryptedView_Day_5_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemEncryptedView_Day_5_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:21dcb76e1f9712325c1d47603e121849298aba995d493380ccc3a174296f0dd5 -size 23794 +oid sha256:aba63b0f223f8480d40e6c9c48ce44a1ae1a8bdcc3d101030b9a0bd5f1e9ebee +size 23773 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemEncryptedView_Night_5_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemEncryptedView_Night_5_en.png index 78b8059fe51..8561e181513 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemEncryptedView_Night_5_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemEncryptedView_Night_5_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:12ba26807e062ad5146847438ad82b9c24805c3edbc3c949f5ba3ac20c768af0 -size 23430 +oid sha256:5d0a687a259fafe830560b762a915e478d680dd7c34a295d72e82fc7c427a815 +size 23403 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowUtd_Day_0_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowUtd_Day_0_en.png index 78776020315..e847cd3292d 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowUtd_Day_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowUtd_Day_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:b1f04171ef894f299b58cc15158daf9655cc04f9ab2418973e7e6e78e22884e8 -size 31693 +oid sha256:f1c226a36c42d4aa725a941ed58036dc5e75c9547720e00b75c64c7fe33491af +size 31647 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowUtd_Night_0_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowUtd_Night_0_en.png index 57f18ac15c9..562bcf09f20 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowUtd_Night_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowUtd_Night_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:8ce15bbbb3bc562f92a7d07a0f2f907d4e351e0b7133a61b7ef49540ef622c15 -size 30613 +oid sha256:47afdecd896bef06623b81ca53e0b60a0deeb01014903906fbd3fbf15ea4a5f6 +size 30592 From be24cdd1a0c7c79ad7a45dbf0177ad412e9b8ebc Mon Sep 17 00:00:00 2001 From: fkwp Date: Wed, 4 Dec 2024 10:04:38 +0100 Subject: [PATCH 94/96] increase ringing timeout from 15 seconds to 90 seconds --- .../kotlin/io/element/android/appconfig/ElementCallConfig.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/appconfig/src/main/kotlin/io/element/android/appconfig/ElementCallConfig.kt b/appconfig/src/main/kotlin/io/element/android/appconfig/ElementCallConfig.kt index d7cad2f9e16..390ba5a5320 100644 --- a/appconfig/src/main/kotlin/io/element/android/appconfig/ElementCallConfig.kt +++ b/appconfig/src/main/kotlin/io/element/android/appconfig/ElementCallConfig.kt @@ -16,5 +16,5 @@ object ElementCallConfig { /** * The default duration of a ringing call in seconds before it's automatically dismissed. */ - const val RINGING_CALL_DURATION_SECONDS = 15 + const val RINGING_CALL_DURATION_SECONDS = 90 } From a064c88f8f7c6dc0c5bbad4efa53e3724897c069 Mon Sep 17 00:00:00 2001 From: ganfra Date: Wed, 4 Dec 2024 11:03:24 +0100 Subject: [PATCH 95/96] fix(room_detail) : hide room avatar preview --- .../android/features/roomdetails/impl/RoomDetailsFlowNode.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsFlowNode.kt b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsFlowNode.kt index 166a22d694e..12cdbdcadf7 100644 --- a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsFlowNode.kt +++ b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsFlowNode.kt @@ -15,7 +15,6 @@ import com.bumble.appyx.core.node.Node import com.bumble.appyx.core.plugin.Plugin import com.bumble.appyx.core.plugin.plugins import com.bumble.appyx.navmodel.backstack.BackStack -import com.bumble.appyx.navmodel.backstack.operation.pop import com.bumble.appyx.navmodel.backstack.operation.push import dagger.assisted.Assisted import dagger.assisted.AssistedInject @@ -36,6 +35,7 @@ import io.element.android.features.userprofile.shared.UserProfileNodeHelper import io.element.android.libraries.architecture.BackstackWithOverlayBox import io.element.android.libraries.architecture.BaseFlowNode import io.element.android.libraries.architecture.createNode +import io.element.android.libraries.architecture.overlay.operation.hide import io.element.android.libraries.architecture.overlay.operation.show import io.element.android.libraries.di.RoomScope import io.element.android.libraries.matrix.api.core.RoomId @@ -202,7 +202,7 @@ class RoomDetailsFlowNode @AssistedInject constructor( is NavTarget.AvatarPreview -> { val callback = object : MediaViewerEntryPoint.Callback { override fun onDone() { - backstack.pop() + overlay.hide() } } mediaViewerEntryPoint.nodeBuilder(this, buildContext) From a81392d8acae584dce491c66942c70f1a4b6db73 Mon Sep 17 00:00:00 2001 From: ganfra Date: Wed, 4 Dec 2024 11:31:33 +0100 Subject: [PATCH 96/96] fix(composer) : use HideKeyboardWhenDisposed only in MessagesView --- .../io/element/android/features/messages/impl/MessagesView.kt | 3 +++ .../io/element/android/libraries/textcomposer/TextComposer.kt | 2 -- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesView.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesView.kt index fa66e463bbc..47e4721f7fc 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesView.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesView.kt @@ -90,6 +90,7 @@ import io.element.android.libraries.designsystem.theme.components.BottomSheetDra import io.element.android.libraries.designsystem.theme.components.Scaffold import io.element.android.libraries.designsystem.theme.components.Text import io.element.android.libraries.designsystem.theme.components.TopAppBar +import io.element.android.libraries.designsystem.utils.HideKeyboardWhenDisposed import io.element.android.libraries.designsystem.utils.KeepScreenOn import io.element.android.libraries.designsystem.utils.OnLifecycleEvent import io.element.android.libraries.designsystem.utils.snackbar.SnackbarHost @@ -124,6 +125,8 @@ fun MessagesView( KeepScreenOn(state.voiceMessageComposerState.keepScreenOn) + HideKeyboardWhenDisposed() + val snackbarHostState = rememberSnackbarHostState(snackbarMessage = state.snackbarMessage) // This is needed because the composer is inside an AndroidView that can't be affected by the FocusManager in Compose diff --git a/libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/TextComposer.kt b/libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/TextComposer.kt index 274453533b1..9ebb5a7c228 100644 --- a/libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/TextComposer.kt +++ b/libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/TextComposer.kt @@ -47,7 +47,6 @@ import io.element.android.libraries.designsystem.preview.PreviewsDayNight import io.element.android.libraries.designsystem.theme.components.CircularProgressIndicator import io.element.android.libraries.designsystem.theme.components.Icon import io.element.android.libraries.designsystem.theme.components.Text -import io.element.android.libraries.designsystem.utils.HideKeyboardWhenDisposed import io.element.android.libraries.matrix.api.core.EventId import io.element.android.libraries.matrix.api.timeline.item.event.EventOrTransactionId import io.element.android.libraries.matrix.api.timeline.item.event.toEventOrTransactionId @@ -324,7 +323,6 @@ fun TextComposer( } } } - HideKeyboardWhenDisposed() } @Composable