From 6af3870547d2b16d4fc678289d86f801bf0e9725 Mon Sep 17 00:00:00 2001 From: ElementBot Date: Tue, 9 Jun 2026 10:21:25 +0000 Subject: [PATCH 1/5] Update screenshots --- ...atures.lockscreen.impl.unlock_PinUnlockViewCompact_0_en.png | 3 +++ ...atures.lockscreen.impl.unlock_PinUnlockViewCompact_1_en.png | 3 +++ ...res.lockscreen.impl.unlock_PinUnlockViewInApp_Day_10_en.png | 3 +++ ...s.lockscreen.impl.unlock_PinUnlockViewInApp_Night_10_en.png | 3 +++ ...features.lockscreen.impl.unlock_PinUnlockView_Day_10_en.png | 3 +++ ...atures.lockscreen.impl.unlock_PinUnlockView_Night_10_en.png | 3 +++ 6 files changed, 18 insertions(+) create mode 100644 tests/uitests/src/test/snapshots/images/features.lockscreen.impl.unlock_PinUnlockViewCompact_0_en.png create mode 100644 tests/uitests/src/test/snapshots/images/features.lockscreen.impl.unlock_PinUnlockViewCompact_1_en.png create mode 100644 tests/uitests/src/test/snapshots/images/features.lockscreen.impl.unlock_PinUnlockViewInApp_Day_10_en.png create mode 100644 tests/uitests/src/test/snapshots/images/features.lockscreen.impl.unlock_PinUnlockViewInApp_Night_10_en.png create mode 100644 tests/uitests/src/test/snapshots/images/features.lockscreen.impl.unlock_PinUnlockView_Day_10_en.png create mode 100644 tests/uitests/src/test/snapshots/images/features.lockscreen.impl.unlock_PinUnlockView_Night_10_en.png diff --git a/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.unlock_PinUnlockViewCompact_0_en.png b/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.unlock_PinUnlockViewCompact_0_en.png new file mode 100644 index 0000000000..10076e1c68 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.unlock_PinUnlockViewCompact_0_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7790ba46051ba39863f057bc53c937f513f91b6094094b2b449794d7de3aa875 +size 32833 diff --git a/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.unlock_PinUnlockViewCompact_1_en.png b/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.unlock_PinUnlockViewCompact_1_en.png new file mode 100644 index 0000000000..eeddc7261f --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.unlock_PinUnlockViewCompact_1_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:bc7032e0d69a44d8ab2d3187183eb77cc28d7a5669fd7e56ee99d4f90ee05d62 +size 33137 diff --git a/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.unlock_PinUnlockViewInApp_Day_10_en.png b/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.unlock_PinUnlockViewInApp_Day_10_en.png new file mode 100644 index 0000000000..0dd66f5feb --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.unlock_PinUnlockViewInApp_Day_10_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:25ca16b3574c5cf850e06099312d4af294561c8c9833742a0b3902bc3b35cb39 +size 20669 diff --git a/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.unlock_PinUnlockViewInApp_Night_10_en.png b/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.unlock_PinUnlockViewInApp_Night_10_en.png new file mode 100644 index 0000000000..e03c2f9cc3 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.unlock_PinUnlockViewInApp_Night_10_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:e58621f378a1abac78c5bdfb6a31675c1f762f53434f28b869ac8c7b6f9ad8ad +size 20109 diff --git a/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.unlock_PinUnlockView_Day_10_en.png b/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.unlock_PinUnlockView_Day_10_en.png new file mode 100644 index 0000000000..0a9a82d9ce --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.unlock_PinUnlockView_Day_10_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:094814ca5366ba623d12c26e8c1ab1cffc8c41c9970c442ddf53c44899c2ac7f +size 36215 diff --git a/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.unlock_PinUnlockView_Night_10_en.png b/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.unlock_PinUnlockView_Night_10_en.png new file mode 100644 index 0000000000..732af3b016 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.unlock_PinUnlockView_Night_10_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:821bd77d0c03044f800bcb5f537bbc52c8f32d86d4fcd68fa0f3838e1e35f960 +size 34972 From 969880e35a86a94f8bb3099e67653ce06e4b6f07 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Fri, 5 Jun 2026 14:07:45 +0200 Subject: [PATCH 2/5] [Link new device] Unlock with device credentials or application PIN code --- features/linknewdevice/impl/build.gradle.kts | 2 + .../impl/LinkNewDeviceFlowNode.kt | 37 ++++- .../impl/LinkNewMobileHandler.kt | 7 +- .../impl/screens/root/LinkDeviceType.kt | 13 ++ .../screens/root/LinkNewDeviceRootEvent.kt | 1 - .../screens/root/LinkNewDeviceRootNode.kt | 4 +- .../root/LinkNewDeviceRootPresenter.kt | 14 +- .../screens/root/LinkNewDeviceRootView.kt | 70 ++++---- .../DefaultLinkNewDeviceEntryPointTest.kt | 2 + .../number/EnterNumberPresenterTest.kt | 7 +- .../root/LinkNewDeviceRootPresenterTest.kt | 35 +++- .../screens/root/LinkNewDeviceRootViewTest.kt | 30 ++-- .../lockscreen/api/DeviceUnlockEntryPoint.kt | 35 ++++ features/lockscreen/impl/build.gradle.kts | 1 + .../impl/DefaultDeviceUnlockEntryPoint.kt | 35 ++++ .../impl/biometric/BiometricAuthenticator.kt | 4 +- .../BiometricAuthenticatorManager.kt | 11 ++ .../DefaultBiometricAuthenticatorManager.kt | 56 ++++++- .../impl/device/DeviceUnlockCallbackHolder.kt | 30 ++++ .../impl/device/DeviceUnlockEvent.kt | 12 ++ .../impl/device/DeviceUnlockNode.kt | 49 ++++++ .../impl/device/DeviceUnlockPresenter.kt | 88 ++++++++++ .../impl/device/DeviceUnlockState.kt | 13 ++ .../settings/LockScreenSettingsFlowNode.kt | 9 +- .../lockscreen/impl/unlock/PinUnlockHelper.kt | 12 +- .../lockscreen/impl/unlock/PinUnlockNode.kt | 15 +- .../impl/unlock/PinUnlockPresenter.kt | 15 +- .../lockscreen/impl/unlock/PinUnlockState.kt | 1 + .../impl/unlock/PinUnlockStateProvider.kt | 11 ++ .../lockscreen/impl/unlock/PinUnlockView.kt | 55 +++++-- .../impl/unlock/activity/PinUnlockActivity.kt | 6 +- .../biometric/FakeBiometricAuthenticator.kt | 14 +- .../FakeBiometricAuthenticatorManager.kt | 14 +- .../impl/device/DeviceUnlockPresenterTest.kt | 152 ++++++++++++++++++ .../impl/unlock/PinUnlockPresenterTest.kt | 27 ++++ .../test/FakeDeviceUnlockCallback.kt | 19 +++ .../test/FakeDeviceUnlockEntryPoint.kt | 22 +++ .../api/linknewdevice/LinkMobileHandler.kt | 3 + 38 files changed, 828 insertions(+), 103 deletions(-) create mode 100644 features/linknewdevice/impl/src/main/kotlin/io/element/android/features/linknewdevice/impl/screens/root/LinkDeviceType.kt create mode 100644 features/lockscreen/api/src/main/kotlin/io/element/android/features/lockscreen/api/DeviceUnlockEntryPoint.kt create mode 100644 features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/DefaultDeviceUnlockEntryPoint.kt create mode 100644 features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/device/DeviceUnlockCallbackHolder.kt create mode 100644 features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/device/DeviceUnlockEvent.kt create mode 100644 features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/device/DeviceUnlockNode.kt create mode 100644 features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/device/DeviceUnlockPresenter.kt create mode 100644 features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/device/DeviceUnlockState.kt create mode 100644 features/lockscreen/impl/src/test/kotlin/io/element/android/features/lockscreen/impl/device/DeviceUnlockPresenterTest.kt create mode 100644 features/lockscreen/test/src/main/kotlin/io/element/android/features/lockscreen/test/FakeDeviceUnlockCallback.kt create mode 100644 features/lockscreen/test/src/main/kotlin/io/element/android/features/lockscreen/test/FakeDeviceUnlockEntryPoint.kt diff --git a/features/linknewdevice/impl/build.gradle.kts b/features/linknewdevice/impl/build.gradle.kts index adbec91e6a..4659a2d2b8 100644 --- a/features/linknewdevice/impl/build.gradle.kts +++ b/features/linknewdevice/impl/build.gradle.kts @@ -30,6 +30,7 @@ dependencies { // TODO Cleanup implementation(projects.appconfig) implementation(projects.features.enterprise.api) + implementation(projects.features.lockscreen.api) implementation(projects.features.rageshake.api) implementation(projects.libraries.core) implementation(projects.libraries.androidutils) @@ -53,6 +54,7 @@ dependencies { testCommonDependencies(libs, true) testImplementation(projects.features.linknewdevice.test) + testImplementation(projects.features.lockscreen.test) testImplementation(projects.features.enterprise.test) testImplementation(projects.libraries.featureflag.test) testImplementation(projects.libraries.matrix.test) diff --git a/features/linknewdevice/impl/src/main/kotlin/io/element/android/features/linknewdevice/impl/LinkNewDeviceFlowNode.kt b/features/linknewdevice/impl/src/main/kotlin/io/element/android/features/linknewdevice/impl/LinkNewDeviceFlowNode.kt index 61645ead9d..8f434384c4 100644 --- a/features/linknewdevice/impl/src/main/kotlin/io/element/android/features/linknewdevice/impl/LinkNewDeviceFlowNode.kt +++ b/features/linknewdevice/impl/src/main/kotlin/io/element/android/features/linknewdevice/impl/LinkNewDeviceFlowNode.kt @@ -13,8 +13,10 @@ import androidx.activity.compose.LocalActivity import androidx.compose.runtime.Composable import androidx.compose.runtime.DisposableEffect import androidx.compose.ui.Modifier +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.model.permanent.PermanentNavModel import com.bumble.appyx.core.node.Node import com.bumble.appyx.core.plugin.Plugin import com.bumble.appyx.navmodel.backstack.BackStack @@ -34,8 +36,10 @@ import io.element.android.features.linknewdevice.impl.screens.error.ErrorNode import io.element.android.features.linknewdevice.impl.screens.error.ErrorScreenType import io.element.android.features.linknewdevice.impl.screens.number.EnterNumberNode import io.element.android.features.linknewdevice.impl.screens.qrcode.ShowQrCodeNode +import io.element.android.features.linknewdevice.impl.screens.root.LinkDeviceType import io.element.android.features.linknewdevice.impl.screens.root.LinkNewDeviceRootNode import io.element.android.features.linknewdevice.impl.screens.scan.ScanQrCodeNode +import io.element.android.features.lockscreen.api.DeviceUnlockEntryPoint import io.element.android.libraries.androidutils.browser.openUrlInChromeCustomTab import io.element.android.libraries.architecture.BackstackView import io.element.android.libraries.architecture.BaseFlowNode @@ -67,11 +71,16 @@ class LinkNewDeviceFlowNode( private val linkNewMobileHandler: LinkNewMobileHandler, private val linkNewDesktopHandler: LinkNewDesktopHandler, private val sessionEnterpriseService: SessionEnterpriseService, + private val deviceUnlockEntryPoint: DeviceUnlockEntryPoint, ) : BaseFlowNode( backstack = BackStack( initialElement = NavTarget.Root, savedStateMap = buildContext.savedStateMap, ), + permanentNavModel = PermanentNavModel( + navTargets = setOf(NavTarget.LockScreen), + savedStateMap = buildContext.savedStateMap, + ), buildContext = buildContext, plugins = plugins, ) { @@ -124,6 +133,9 @@ class LinkNewDeviceFlowNode( @Parcelize data object DesktopScanQrCode : NavTarget + @Parcelize + data object LockScreen : NavTarget + @Parcelize data class Error( val errorScreenType: ErrorScreenType, @@ -137,6 +149,9 @@ class LinkNewDeviceFlowNode( Timber.tag(tag.value).d("step: ${linkMobileStep::class.java.simpleName}") when (linkMobileStep) { LinkMobileStep.Uninitialized -> Unit + LinkMobileStep.CreatingQrCode -> { + // This step is handled in LinkNewDeviceRootPresenter + } LinkMobileStep.Done -> { callback.onDone() } @@ -224,13 +239,28 @@ class LinkNewDeviceFlowNode( callback.onDone() } - override fun linkDesktopDevice() { - linkNewDesktopHandler.reset() - backstack.push(NavTarget.DesktopNotice) + override fun onUnlockDevice(type: LinkDeviceType) { + val callback = object : DeviceUnlockEntryPoint.Callback { + override fun onCancel() = Unit + override fun onUnlocked() = when (type) { + LinkDeviceType.Mobile -> { + linkNewMobileHandler.reset() + linkNewMobileHandler.createAndStartNewHandler() + } + LinkDeviceType.Desktop -> { + linkNewDesktopHandler.reset() + backstack.push(NavTarget.DesktopNotice) + } + } + } + deviceUnlockEntryPoint.requestUnlock(callback) } } createNode(buildContext, listOf(callback)) } + is NavTarget.LockScreen -> { + deviceUnlockEntryPoint.createNode(this, buildContext) + } NavTarget.DesktopNotice -> { val callback = object : DesktopNoticeNode.Callback { override fun navigateBack() { @@ -324,5 +354,6 @@ class LinkNewDeviceFlowNode( } } BackstackView() + PermanentChild(permanentNavModel = permanentNavModel, navTarget = NavTarget.LockScreen) } } diff --git a/features/linknewdevice/impl/src/main/kotlin/io/element/android/features/linknewdevice/impl/LinkNewMobileHandler.kt b/features/linknewdevice/impl/src/main/kotlin/io/element/android/features/linknewdevice/impl/LinkNewMobileHandler.kt index 18d67f577a..39c9c6fef3 100644 --- a/features/linknewdevice/impl/src/main/kotlin/io/element/android/features/linknewdevice/impl/LinkNewMobileHandler.kt +++ b/features/linknewdevice/impl/src/main/kotlin/io/element/android/features/linknewdevice/impl/LinkNewMobileHandler.kt @@ -43,12 +43,15 @@ class LinkNewMobileHandler( val stepFlow: StateFlow get() = linkMobileStepFlow.asStateFlow() - fun createAndStartNewHandler() { + fun createAndStartNewHandler(forRotating: Boolean = false) { Timber.tag(loggerTag.value).d("createAndStartNewHandler()") currentJob?.cancel() handler = matrixClient.createLinkMobileHandler().getOrNull() handler?.let { h -> currentJob = sessionScope.launch { + if (!forRotating) { + linkMobileStepFlow.emit(LinkMobileStep.CreatingQrCode) + } h.linkMobileStep .onEach { linkMobileStepFlow.emit(it) @@ -68,7 +71,7 @@ class LinkNewMobileHandler( } fun rotateQrCode() { - createAndStartNewHandler() + createAndStartNewHandler(forRotating = true) } fun onTooManyRotation() { diff --git a/features/linknewdevice/impl/src/main/kotlin/io/element/android/features/linknewdevice/impl/screens/root/LinkDeviceType.kt b/features/linknewdevice/impl/src/main/kotlin/io/element/android/features/linknewdevice/impl/screens/root/LinkDeviceType.kt new file mode 100644 index 0000000000..6b26fe5e79 --- /dev/null +++ b/features/linknewdevice/impl/src/main/kotlin/io/element/android/features/linknewdevice/impl/screens/root/LinkDeviceType.kt @@ -0,0 +1,13 @@ +/* + * Copyright (c) 2026 Element Creations Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial. + * Please see LICENSE files in the repository root for full details. + */ + +package io.element.android.features.linknewdevice.impl.screens.root + +enum class LinkDeviceType { + Mobile, + Desktop, +} diff --git a/features/linknewdevice/impl/src/main/kotlin/io/element/android/features/linknewdevice/impl/screens/root/LinkNewDeviceRootEvent.kt b/features/linknewdevice/impl/src/main/kotlin/io/element/android/features/linknewdevice/impl/screens/root/LinkNewDeviceRootEvent.kt index 8ce6af90b0..97047fea9d 100644 --- a/features/linknewdevice/impl/src/main/kotlin/io/element/android/features/linknewdevice/impl/screens/root/LinkNewDeviceRootEvent.kt +++ b/features/linknewdevice/impl/src/main/kotlin/io/element/android/features/linknewdevice/impl/screens/root/LinkNewDeviceRootEvent.kt @@ -8,6 +8,5 @@ package io.element.android.features.linknewdevice.impl.screens.root sealed interface LinkNewDeviceRootEvent { - data object LinkMobileDevice : LinkNewDeviceRootEvent data object CloseDialog : LinkNewDeviceRootEvent } diff --git a/features/linknewdevice/impl/src/main/kotlin/io/element/android/features/linknewdevice/impl/screens/root/LinkNewDeviceRootNode.kt b/features/linknewdevice/impl/src/main/kotlin/io/element/android/features/linknewdevice/impl/screens/root/LinkNewDeviceRootNode.kt index f43ffa64df..dc74f1287f 100644 --- a/features/linknewdevice/impl/src/main/kotlin/io/element/android/features/linknewdevice/impl/screens/root/LinkNewDeviceRootNode.kt +++ b/features/linknewdevice/impl/src/main/kotlin/io/element/android/features/linknewdevice/impl/screens/root/LinkNewDeviceRootNode.kt @@ -27,7 +27,7 @@ class LinkNewDeviceRootNode( ) : Node(buildContext, plugins = plugins) { interface Callback : Plugin { fun onDone() - fun linkDesktopDevice() + fun onUnlockDevice(type: LinkDeviceType) } private val callback: Callback = callback() @@ -39,7 +39,7 @@ class LinkNewDeviceRootNode( state = state, modifier = modifier, onBackClick = callback::onDone, - onLinkDesktopDeviceClick = callback::linkDesktopDevice, + onUnlockDevice = callback::onUnlockDevice, ) } } diff --git a/features/linknewdevice/impl/src/main/kotlin/io/element/android/features/linknewdevice/impl/screens/root/LinkNewDeviceRootPresenter.kt b/features/linknewdevice/impl/src/main/kotlin/io/element/android/features/linknewdevice/impl/screens/root/LinkNewDeviceRootPresenter.kt index a17ed88fd3..af3ede0c27 100644 --- a/features/linknewdevice/impl/src/main/kotlin/io/element/android/features/linknewdevice/impl/screens/root/LinkNewDeviceRootPresenter.kt +++ b/features/linknewdevice/impl/src/main/kotlin/io/element/android/features/linknewdevice/impl/screens/root/LinkNewDeviceRootPresenter.kt @@ -50,7 +50,13 @@ class LinkNewDeviceRootPresenter( LaunchedEffect(step) { when (val finalStep = step) { is LinkMobileStep.Uninitialized -> { - qrCodeData = AsyncData.Uninitialized + // Ignore this step when loading QrCode + if (!qrCodeData.isLoading()) { + qrCodeData = AsyncData.Uninitialized + } + } + is LinkMobileStep.CreatingQrCode -> { + qrCodeData = AsyncData.Loading() } is LinkMobileStep.QrReady -> { qrCodeData = AsyncData.Success(Unit) @@ -64,12 +70,6 @@ class LinkNewDeviceRootPresenter( fun handleEvent(event: LinkNewDeviceRootEvent) { when (event) { - LinkNewDeviceRootEvent.LinkMobileDevice -> coroutineScope.launch { - qrCodeData = AsyncData.Loading() - // Wait for the QrCode to be ready - linkNewMobileHandler.reset() - linkNewMobileHandler.createAndStartNewHandler() - } LinkNewDeviceRootEvent.CloseDialog -> coroutineScope.launch { linkNewMobileHandler.reset() } diff --git a/features/linknewdevice/impl/src/main/kotlin/io/element/android/features/linknewdevice/impl/screens/root/LinkNewDeviceRootView.kt b/features/linknewdevice/impl/src/main/kotlin/io/element/android/features/linknewdevice/impl/screens/root/LinkNewDeviceRootView.kt index d9249d3e89..5778abfb2c 100644 --- a/features/linknewdevice/impl/src/main/kotlin/io/element/android/features/linknewdevice/impl/screens/root/LinkNewDeviceRootView.kt +++ b/features/linknewdevice/impl/src/main/kotlin/io/element/android/features/linknewdevice/impl/screens/root/LinkNewDeviceRootView.kt @@ -41,7 +41,7 @@ import io.element.android.libraries.ui.strings.CommonStrings fun LinkNewDeviceRootView( state: LinkNewDeviceRootState, onBackClick: () -> Unit, - onLinkDesktopDeviceClick: () -> Unit, + onUnlockDevice: (type: LinkDeviceType) -> Unit, modifier: Modifier = Modifier, ) { val (title, subtitle, iconStyle) = if (state.isSupported.dataOrNull() == false) { @@ -57,6 +57,7 @@ fun LinkNewDeviceRootView( BigIcon.Style.Default(CompoundIcons.Devices()) ) } + FlowStepPage( onBackClick = onBackClick, title = title, @@ -83,40 +84,37 @@ fun LinkNewDeviceRootView( } is AsyncData.Success -> { if (state.isSupported.data) { - when (state.qrCodeData) { - AsyncData.Uninitialized, - is AsyncData.Failure -> { - Button( - onClick = { state.eventSink(LinkNewDeviceRootEvent.LinkMobileDevice) }, - text = stringResource(id = R.string.screen_link_new_device_root_mobile_device), - modifier = Modifier.fillMaxWidth(), - leadingIcon = IconSource.Vector(CompoundIcons.Mobile()), - ) - Button( - onClick = onLinkDesktopDeviceClick, - text = stringResource(id = R.string.screen_link_new_device_root_desktop_computer), - modifier = Modifier.fillMaxWidth(), - leadingIcon = IconSource.Vector(CompoundIcons.Computer()), - ) - } - is AsyncData.Loading, - is AsyncData.Success -> { - Button( - onClick = { state.eventSink(LinkNewDeviceRootEvent.LinkMobileDevice) }, - text = stringResource(id = R.string.screen_link_new_device_root_loading_qr_code), - showProgress = true, - enabled = false, - modifier = Modifier.fillMaxWidth(), - ) - Button( - onClick = onLinkDesktopDeviceClick, - text = stringResource(id = R.string.screen_link_new_device_root_desktop_computer), - modifier = Modifier.fillMaxWidth(), - enabled = false, - leadingIcon = IconSource.Vector(CompoundIcons.Computer()), - ) - } - } + val canClick = state.qrCodeData is AsyncData.Uninitialized + val isLoading = state.qrCodeData is AsyncData.Loading || state.qrCodeData is AsyncData.Success + Button( + onClick = { + if (canClick) { + onUnlockDevice(LinkDeviceType.Mobile) + } + }, + text = stringResource( + id = if (isLoading) { + R.string.screen_link_new_device_root_loading_qr_code + } else { + R.string.screen_link_new_device_root_mobile_device + } + ), + showProgress = isLoading, + enabled = !isLoading, + modifier = Modifier.fillMaxWidth(), + leadingIcon = IconSource.Vector(CompoundIcons.Mobile()), + ) + Button( + onClick = { + if (canClick) { + onUnlockDevice(LinkDeviceType.Desktop) + } + }, + text = stringResource(id = R.string.screen_link_new_device_root_desktop_computer), + enabled = !isLoading, + modifier = Modifier.fillMaxWidth(), + leadingIcon = IconSource.Vector(CompoundIcons.Computer()), + ) } else { Button( onClick = onBackClick, @@ -147,6 +145,6 @@ internal fun LinkNewDeviceRootViewPreview( LinkNewDeviceRootView( state = state, onBackClick = { }, - onLinkDesktopDeviceClick = { }, + onUnlockDevice = { }, ) } diff --git a/features/linknewdevice/impl/src/test/kotlin/io/element/android/features/linknewdevice/impl/DefaultLinkNewDeviceEntryPointTest.kt b/features/linknewdevice/impl/src/test/kotlin/io/element/android/features/linknewdevice/impl/DefaultLinkNewDeviceEntryPointTest.kt index 1b2af8f4c3..a198bc27d9 100644 --- a/features/linknewdevice/impl/src/test/kotlin/io/element/android/features/linknewdevice/impl/DefaultLinkNewDeviceEntryPointTest.kt +++ b/features/linknewdevice/impl/src/test/kotlin/io/element/android/features/linknewdevice/impl/DefaultLinkNewDeviceEntryPointTest.kt @@ -13,6 +13,7 @@ import com.bumble.appyx.testing.junit4.util.MainDispatcherRule import com.google.common.truth.Truth.assertThat import io.element.android.features.enterprise.test.FakeSessionEnterpriseService import io.element.android.features.linknewdevice.api.LinkNewDeviceEntryPoint +import io.element.android.features.lockscreen.test.FakeDeviceUnlockEntryPoint import io.element.android.libraries.matrix.test.FakeMatrixClient import io.element.android.tests.testutils.lambda.lambdaError import io.element.android.tests.testutils.node.TestParentNode @@ -39,6 +40,7 @@ class DefaultLinkNewDeviceEntryPointTest { linkNewMobileHandler = LinkNewMobileHandler(client), linkNewDesktopHandler = LinkNewDesktopHandler(client), sessionEnterpriseService = FakeSessionEnterpriseService(), + deviceUnlockEntryPoint = FakeDeviceUnlockEntryPoint(), ) } val callback: LinkNewDeviceEntryPoint.Callback = object : LinkNewDeviceEntryPoint.Callback { diff --git a/features/linknewdevice/impl/src/test/kotlin/io/element/android/features/linknewdevice/impl/screens/number/EnterNumberPresenterTest.kt b/features/linknewdevice/impl/src/test/kotlin/io/element/android/features/linknewdevice/impl/screens/number/EnterNumberPresenterTest.kt index fe2e11e95c..b3602c81dc 100644 --- a/features/linknewdevice/impl/src/test/kotlin/io/element/android/features/linknewdevice/impl/screens/number/EnterNumberPresenterTest.kt +++ b/features/linknewdevice/impl/src/test/kotlin/io/element/android/features/linknewdevice/impl/screens/number/EnterNumberPresenterTest.kt @@ -88,6 +88,7 @@ class EnterNumberPresenterTest { navigator = navigator, linkNewMobileHandler = linkNewMobileHandler, ).test { + skipItems(1) val initialState = awaitItem() linkMobileHandler.emitStep( LinkMobileStep.QrScanned(checkCodeSender) @@ -96,7 +97,7 @@ class EnterNumberPresenterTest { initialState.eventSink(EnterNumberEvent.UpdateNumber("88")) skipItems(1) initialState.eventSink(EnterNumberEvent.Continue) - skipItems(1) + skipItems(2) val finalState = awaitItem() assertThat(finalState.sendingCode.isLoading()).isTrue() advanceUntilIdle() @@ -130,6 +131,7 @@ class EnterNumberPresenterTest { LinkMobileStep.QrScanned(checkCodeSender) ) runCurrent() + skipItems(1) initialState.eventSink(EnterNumberEvent.UpdateNumber("88")) skipItems(1) initialState.eventSink(EnterNumberEvent.Continue) @@ -163,6 +165,7 @@ class EnterNumberPresenterTest { createPresenter( linkNewMobileHandler = linkNewMobileHandler, ).test { + skipItems(1) val initialState = awaitItem() linkMobileHandler.emitStep( LinkMobileStep.QrScanned(checkCodeSender) @@ -171,7 +174,7 @@ class EnterNumberPresenterTest { initialState.eventSink(EnterNumberEvent.UpdateNumber("88")) skipItems(1) initialState.eventSink(EnterNumberEvent.Continue) - skipItems(1) + skipItems(2) val loadingState = awaitItem() assertThat(loadingState.sendingCode.isLoading()).isTrue() expectNoEvents() diff --git a/features/linknewdevice/impl/src/test/kotlin/io/element/android/features/linknewdevice/impl/screens/root/LinkNewDeviceRootPresenterTest.kt b/features/linknewdevice/impl/src/test/kotlin/io/element/android/features/linknewdevice/impl/screens/root/LinkNewDeviceRootPresenterTest.kt index 88a68786f3..d2216c2737 100644 --- a/features/linknewdevice/impl/src/test/kotlin/io/element/android/features/linknewdevice/impl/screens/root/LinkNewDeviceRootPresenterTest.kt +++ b/features/linknewdevice/impl/src/test/kotlin/io/element/android/features/linknewdevice/impl/screens/root/LinkNewDeviceRootPresenterTest.kt @@ -75,15 +75,48 @@ class LinkNewDeviceRootPresenterTest { sessionCoroutineScope = backgroundScope, createLinkMobileHandlerResult = { Result.success(linkMobileHandler) } ) + val linkNewMobileHandler = LinkNewMobileHandler(matrixClient) createPresenter( matrixClient = matrixClient, + linkNewMobileHandler = linkNewMobileHandler, ).test { skipItems(1) val initialState = awaitItem() assertThat(initialState.isSupported.dataOrNull()).isTrue() - initialState.eventSink(LinkNewDeviceRootEvent.LinkMobileDevice) + linkNewMobileHandler.createAndStartNewHandler() + skipItems(1) val loadingState = awaitItem() assertThat(loadingState.qrCodeData.isLoading()).isTrue() + skipItems(1) + } + } + + @Test + fun `present - close dialog resets qrCodeData`() = runTest { + val fakeLinkMobileHandler = FakeLinkMobileHandler(startResult = {}) + val matrixClient = FakeMatrixClient( + canLinkNewDeviceResult = { Result.success(true) }, + sessionCoroutineScope = backgroundScope, + createLinkMobileHandlerResult = { Result.success(fakeLinkMobileHandler) } + ) + val linkNewMobileHandler = LinkNewMobileHandler(matrixClient) + createPresenter( + matrixClient = matrixClient, + linkNewMobileHandler = linkNewMobileHandler, + ).test { + skipItems(1) + linkNewMobileHandler.onTooManyRotation() + var errorState = awaitItem() + while (!errorState.qrCodeData.isFailure()) { + errorState = awaitItem() + } + assertThat(errorState.qrCodeData.isFailure()).isTrue() + errorState.eventSink(LinkNewDeviceRootEvent.CloseDialog) + var resetState = awaitItem() + while (!resetState.qrCodeData.isUninitialized()) { + resetState = awaitItem() + } + assertThat(resetState.qrCodeData.isUninitialized()).isTrue() } } diff --git a/features/linknewdevice/impl/src/test/kotlin/io/element/android/features/linknewdevice/impl/screens/root/LinkNewDeviceRootViewTest.kt b/features/linknewdevice/impl/src/test/kotlin/io/element/android/features/linknewdevice/impl/screens/root/LinkNewDeviceRootViewTest.kt index bceb8753b2..11dc9aedf6 100644 --- a/features/linknewdevice/impl/src/test/kotlin/io/element/android/features/linknewdevice/impl/screens/root/LinkNewDeviceRootViewTest.kt +++ b/features/linknewdevice/impl/src/test/kotlin/io/element/android/features/linknewdevice/impl/screens/root/LinkNewDeviceRootViewTest.kt @@ -18,9 +18,11 @@ import io.element.android.features.linknewdevice.impl.R import io.element.android.libraries.architecture.AsyncData import io.element.android.libraries.ui.strings.CommonStrings import io.element.android.tests.testutils.EnsureNeverCalled +import io.element.android.tests.testutils.EnsureNeverCalledWithParam import io.element.android.tests.testutils.EventsRecorder import io.element.android.tests.testutils.clickOn import io.element.android.tests.testutils.ensureCalledOnce +import io.element.android.tests.testutils.ensureCalledOnceWithParam import io.element.android.tests.testutils.pressBackKey import org.junit.Test import org.junit.runner.RunWith @@ -44,29 +46,31 @@ class LinkNewDeviceRootViewTest { @Test fun `link desktop button clicked - calls the expected callback`() = runAndroidComposeUiTest { val eventRecorder = EventsRecorder(expectEvents = false) - ensureCalledOnce { callback -> + ensureCalledOnceWithParam(LinkDeviceType.Desktop) { callback -> setLinkNewDeviceRootView( state = aLinkNewDeviceRootState( isSupported = AsyncData.Success(true), eventSink = eventRecorder, ), - onLinkDesktopDeviceClick = callback, + onUnlockDevice = callback, ) clickOn(R.string.screen_link_new_device_root_desktop_computer) } } @Test - fun `link mobile button clicked - emits the expected event`() = runAndroidComposeUiTest { - val eventRecorder = EventsRecorder() - setLinkNewDeviceRootView( - state = aLinkNewDeviceRootState( - isSupported = AsyncData.Success(true), - eventSink = eventRecorder, + fun `link mobile button clicked - calls the expected callback`() = runAndroidComposeUiTest { + val eventRecorder = EventsRecorder(expectEvents = false) + ensureCalledOnceWithParam(LinkDeviceType.Mobile) { callback -> + setLinkNewDeviceRootView( + state = aLinkNewDeviceRootState( + isSupported = AsyncData.Success(true), + eventSink = eventRecorder, + ), + onUnlockDevice = callback, ) - ) - clickOn(R.string.screen_link_new_device_root_mobile_device) - eventRecorder.assertSingle(LinkNewDeviceRootEvent.LinkMobileDevice) + clickOn(R.string.screen_link_new_device_root_mobile_device) + } } @Test @@ -87,13 +91,13 @@ class LinkNewDeviceRootViewTest { private fun AndroidComposeUiTest.setLinkNewDeviceRootView( state: LinkNewDeviceRootState = aLinkNewDeviceRootState(), onBackClick: () -> Unit = EnsureNeverCalled(), - onLinkDesktopDeviceClick: () -> Unit = EnsureNeverCalled(), + onUnlockDevice: (type: LinkDeviceType) -> Unit = EnsureNeverCalledWithParam(), ) { setContent { LinkNewDeviceRootView( state = state, onBackClick = onBackClick, - onLinkDesktopDeviceClick = onLinkDesktopDeviceClick, + onUnlockDevice = onUnlockDevice, ) } } diff --git a/features/lockscreen/api/src/main/kotlin/io/element/android/features/lockscreen/api/DeviceUnlockEntryPoint.kt b/features/lockscreen/api/src/main/kotlin/io/element/android/features/lockscreen/api/DeviceUnlockEntryPoint.kt new file mode 100644 index 0000000000..2953688a84 --- /dev/null +++ b/features/lockscreen/api/src/main/kotlin/io/element/android/features/lockscreen/api/DeviceUnlockEntryPoint.kt @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2026 Element Creations Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial. + * Please see LICENSE files in the repository root for full details. + */ + +package io.element.android.features.lockscreen.api + +import com.bumble.appyx.core.modality.BuildContext +import com.bumble.appyx.core.node.Node +import io.element.android.libraries.architecture.FeatureEntryPoint + +/** + * An entry point for features that want to lock the screen and require + * the user to unlock it before they can interact with the app. + * - if the system lock is available, it will be used to unlock the screen. + * - if the system lock is not available, but app lock is available, it will be used to unlock the screen. + * - if neither is available, the screen will be unlocked immediately. + * + * The Node provided by [createNode] has to be added as a PermanentChild. + */ +interface DeviceUnlockEntryPoint : FeatureEntryPoint { + fun createNode( + parentNode: Node, + buildContext: BuildContext, + ): Node + + fun requestUnlock(callback: Callback) + + interface Callback { + fun onCancel() + fun onUnlocked() + } +} diff --git a/features/lockscreen/impl/build.gradle.kts b/features/lockscreen/impl/build.gradle.kts index 63aec590de..414b4b5909 100644 --- a/features/lockscreen/impl/build.gradle.kts +++ b/features/lockscreen/impl/build.gradle.kts @@ -48,6 +48,7 @@ dependencies { implementation(libs.androidx.biometric) testCommonDependencies(libs, true) + testImplementation(projects.features.lockscreen.test) testImplementation(projects.libraries.matrix.test) testImplementation(projects.libraries.cryptography.test) testImplementation(projects.libraries.cryptography.impl) diff --git a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/DefaultDeviceUnlockEntryPoint.kt b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/DefaultDeviceUnlockEntryPoint.kt new file mode 100644 index 0000000000..f4b78968f8 --- /dev/null +++ b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/DefaultDeviceUnlockEntryPoint.kt @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2026 Element Creations Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial. + * Please see LICENSE files in the repository root for full details. + */ + +package io.element.android.features.lockscreen.impl + +import com.bumble.appyx.core.modality.BuildContext +import com.bumble.appyx.core.node.Node +import dev.zacsweers.metro.AppScope +import dev.zacsweers.metro.ContributesBinding +import io.element.android.features.lockscreen.api.DeviceUnlockEntryPoint +import io.element.android.features.lockscreen.impl.device.DeviceUnlockCallbackHolder +import io.element.android.features.lockscreen.impl.device.DeviceUnlockNode +import io.element.android.libraries.architecture.createNode + +@ContributesBinding(AppScope::class) +class DefaultDeviceUnlockEntryPoint( + private val deviceUnlockCallbackHolder: DeviceUnlockCallbackHolder, +) : DeviceUnlockEntryPoint { + override fun createNode( + parentNode: Node, + buildContext: BuildContext, + ): Node { + return parentNode.createNode( + buildContext = buildContext, + ) + } + + override fun requestUnlock(callback: DeviceUnlockEntryPoint.Callback) { + deviceUnlockCallbackHolder.requestUnlock(callback) + } +} diff --git a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/biometric/BiometricAuthenticator.kt b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/biometric/BiometricAuthenticator.kt index d18d9b73b7..097049c97a 100644 --- a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/biometric/BiometricAuthenticator.kt +++ b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/biometric/BiometricAuthenticator.kt @@ -109,7 +109,9 @@ private class AuthenticationCallback( override fun onAuthenticationSucceeded(result: BiometricPrompt.AuthenticationResult) { super.onAuthenticationSucceeded(result) - if (result.cryptoObject?.cipher.isValid()) { + if (result.authenticationType == BiometricPrompt.AUTHENTICATION_RESULT_TYPE_BIOMETRIC && + result.cryptoObject?.cipher.isValid() || + result.authenticationType == BiometricPrompt.AUTHENTICATION_RESULT_TYPE_DEVICE_CREDENTIAL) { callbacks.forEach { it.onBiometricAuthenticationSuccess() } deferredAuthenticationResult.complete(BiometricAuthenticator.AuthenticationResult.Success) } else { diff --git a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/biometric/BiometricAuthenticatorManager.kt b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/biometric/BiometricAuthenticatorManager.kt index 2ea0ed7d05..6234e65284 100644 --- a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/biometric/BiometricAuthenticatorManager.kt +++ b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/biometric/BiometricAuthenticatorManager.kt @@ -21,6 +21,11 @@ interface BiometricAuthenticatorManager { */ val hasAvailableAuthenticator: Boolean + /** + * If the device is secured for example with a pin, pattern or password, and the user has enrolled at least one biometric. + */ + val canUseDeviceUnlock: Boolean + fun addCallback(callback: BiometricAuthenticator.Callback) fun removeCallback(callback: BiometricAuthenticator.Callback) @@ -35,6 +40,12 @@ interface BiometricAuthenticatorManager { @Composable fun rememberUnlockBiometricAuthenticator(): BiometricAuthenticator + /** + * Remember a biometric authenticator ready for unlocking the app, using the device settings. + */ + @Composable + fun rememberUnlockDeviceBiometricAuthenticator(): BiometricAuthenticator + /** * Remember a biometric authenticator ready for confirmation. */ diff --git a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/biometric/DefaultBiometricAuthenticatorManager.kt b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/biometric/DefaultBiometricAuthenticatorManager.kt index 117323ec0a..27408c919a 100644 --- a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/biometric/DefaultBiometricAuthenticatorManager.kt +++ b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/biometric/DefaultBiometricAuthenticatorManager.kt @@ -35,6 +35,7 @@ import io.element.android.libraries.di.annotations.AppCoroutineScope import io.element.android.libraries.di.annotations.ApplicationContext import io.element.android.libraries.ui.strings.CommonStrings import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.launch import java.util.concurrent.CopyOnWriteArrayList @@ -69,6 +70,12 @@ class DefaultBiometricAuthenticatorManager( get() = lockScreenConfig.isStrongBiometricsEnabled && biometricManager.canAuthenticate(BiometricManager.Authenticators.BIOMETRIC_STRONG) == BiometricManager.BIOMETRIC_SUCCESS + /** + * Returns true if a strong biometric method (i.e.: fingerprint, some face or iris unlock implementations) can be used. + */ + private val canUseDeviceCredentialAuth: Boolean + get() = biometricManager.canAuthenticate(BiometricManager.Authenticators.DEVICE_CREDENTIAL) == BiometricManager.BIOMETRIC_SUCCESS + /** * Returns true if any biometric method (weak or strong) can be used. */ @@ -78,6 +85,9 @@ class DefaultBiometricAuthenticatorManager( override val isDeviceSecured: Boolean get() = keyguardManager.isDeviceSecure + override val canUseDeviceUnlock: Boolean + get() = isDeviceSecured && (canUseWeakBiometricAuth || canUseStrongBiometricAuth || canUseDeviceCredentialAuth) + private val internalCallback = object : DefaultBiometricUnlockCallback() { override fun onBiometricSetupError() { coroutineScope.launch { disable() } @@ -99,6 +109,28 @@ class DefaultBiometricAuthenticatorManager( isAvailable = isAvailable, promptTitle = promptTitle, promptNegative = promptNegative, + forDeviceUnlock = false, + ) + } + + @Composable + override fun rememberUnlockDeviceBiometricAuthenticator(): BiometricAuthenticator { + val isAvailableTrigger by remember { + // Need to trigger the creation of BiometricAuthenticator twice, else the callback will not be ready. + // (the issue already exists in [rememberUnlockBiometricAuthenticator]) + flowOf(false, true) + }.collectAsState(initial = false) + val lifecycleState by LocalLifecycleOwner.current.lifecycle.currentStateFlow.collectAsState() + val isAvailable by remember(lifecycleState) { + derivedStateOf { isAvailableTrigger && canUseDeviceUnlock } + } + val promptTitle = stringResource(id = R.string.screen_app_lock_biometric_unlock_title_android) + val promptNegative = null + return rememberBiometricAuthenticator( + isAvailable = isAvailable, + promptTitle = promptTitle, + promptNegative = promptNegative, + forDeviceUnlock = true, ) } @@ -114,6 +146,7 @@ class DefaultBiometricAuthenticatorManager( isAvailable = isAvailable, promptTitle = promptTitle, promptNegative = promptNegative, + forDeviceUnlock = false, ) } @@ -126,7 +159,8 @@ class DefaultBiometricAuthenticatorManager( private fun rememberBiometricAuthenticator( isAvailable: Boolean, promptTitle: String, - promptNegative: String, + promptNegative: String?, + forDeviceUnlock: Boolean, ): BiometricAuthenticator { val activity = LocalContext.current.findFragmentActivity() return remember(isAvailable) { @@ -136,11 +170,21 @@ class DefaultBiometricAuthenticatorManager( canUseWeakBiometricAuth -> BiometricManager.Authenticators.BIOMETRIC_WEAK else -> 0 } - val promptInfo = BiometricPrompt.PromptInfo.Builder().apply { - setTitle(promptTitle) - setNegativeButtonText(promptNegative) - setAllowedAuthenticators(authenticators) - }.build() + val promptInfo = BiometricPrompt.PromptInfo.Builder() + .setTitle(promptTitle) + .apply { + if (promptNegative != null) { + setNegativeButtonText(promptNegative) + } + if (forDeviceUnlock) { + setAllowedAuthenticators( + authenticators or if (canUseDeviceCredentialAuth) BiometricManager.Authenticators.DEVICE_CREDENTIAL else 0 + ) + } else { + setAllowedAuthenticators(authenticators) + } + } + .build() DefaultBiometricAuthentication( activity = activity, promptInfo = promptInfo, diff --git a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/device/DeviceUnlockCallbackHolder.kt b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/device/DeviceUnlockCallbackHolder.kt new file mode 100644 index 0000000000..cf8b23d3f6 --- /dev/null +++ b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/device/DeviceUnlockCallbackHolder.kt @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2026 Element Creations Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial. + * Please see LICENSE files in the repository root for full details. + */ + +package io.element.android.features.lockscreen.impl.device + +import dev.zacsweers.metro.AppScope +import dev.zacsweers.metro.Inject +import dev.zacsweers.metro.SingleIn +import io.element.android.features.lockscreen.api.DeviceUnlockEntryPoint +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow + +@Inject +@SingleIn(AppScope::class) +class DeviceUnlockCallbackHolder { + private val _deviceUnlockCallback = MutableStateFlow(null) + val deviceUnlockCallback: StateFlow = _deviceUnlockCallback + + fun requestUnlock(callback: DeviceUnlockEntryPoint.Callback) { + _deviceUnlockCallback.value = callback + } + + fun onDone() { + _deviceUnlockCallback.value = null + } +} diff --git a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/device/DeviceUnlockEvent.kt b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/device/DeviceUnlockEvent.kt new file mode 100644 index 0000000000..8b894875cb --- /dev/null +++ b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/device/DeviceUnlockEvent.kt @@ -0,0 +1,12 @@ +/* + * Copyright (c) 2026 Element Creations Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial. + * Please see LICENSE files in the repository root for full details. + */ + +package io.element.android.features.lockscreen.impl.device + +sealed interface DeviceUnlockEvent { + data object CancelPinCode : DeviceUnlockEvent +} diff --git a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/device/DeviceUnlockNode.kt b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/device/DeviceUnlockNode.kt new file mode 100644 index 0000000000..2df706abe7 --- /dev/null +++ b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/device/DeviceUnlockNode.kt @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2026 Element Creations Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial. + * Please see LICENSE files in the repository root for full details. + */ + +package io.element.android.features.lockscreen.impl.device + +import androidx.compose.runtime.Composable +import androidx.compose.runtime.remember +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 dev.zacsweers.metro.Assisted +import dev.zacsweers.metro.AssistedInject +import io.element.android.annotations.ContributesNode +import io.element.android.features.lockscreen.impl.unlock.PinUnlockPresenter +import io.element.android.features.lockscreen.impl.unlock.PinUnlockView +import io.element.android.libraries.di.SessionScope + +@ContributesNode(SessionScope::class) +@AssistedInject +class DeviceUnlockNode( + @Assisted buildContext: BuildContext, + @Assisted plugins: List, + private val presenter: DeviceUnlockPresenter, + private val presenterFactory: PinUnlockPresenter.Factory, +) : Node(buildContext, plugins = plugins) { + @Composable + override fun View(modifier: Modifier) { + val state = presenter.present() + if (state.showApplicationPinCode) { + val pinUnlockPresenter = remember { + presenterFactory.create(forDeviceUnlock = true) + } + val pinState = pinUnlockPresenter.present() + PinUnlockView( + state = pinState, + isInAppUnlock = true, + onCancel = { + state.eventSink(DeviceUnlockEvent.CancelPinCode) + }, + modifier = modifier, + ) + } + } +} diff --git a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/device/DeviceUnlockPresenter.kt b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/device/DeviceUnlockPresenter.kt new file mode 100644 index 0000000000..4cc2bb8fd1 --- /dev/null +++ b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/device/DeviceUnlockPresenter.kt @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2026 Element Creations Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial. + * Please see LICENSE files in the repository root for full details. + */ + +package io.element.android.features.lockscreen.impl.device + +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.collectAsState +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.rememberCoroutineScope +import androidx.compose.runtime.setValue +import dev.zacsweers.metro.Inject +import io.element.android.features.lockscreen.impl.biometric.BiometricAuthenticatorManager +import io.element.android.features.lockscreen.impl.pin.PinCodeManager +import io.element.android.features.lockscreen.impl.unlock.PinUnlockHelper +import io.element.android.libraries.architecture.Presenter +import kotlinx.coroutines.flow.first +import kotlinx.coroutines.launch + +@Inject +class DeviceUnlockPresenter( + private val pinUnlockHelper: PinUnlockHelper, + private val biometricAuthenticatorManager: BiometricAuthenticatorManager, + private val biometricRequester: DeviceUnlockCallbackHolder, + private val pinCodeManager: PinCodeManager, +) : Presenter { + @Composable + override fun present(): DeviceUnlockState { + val coroutineScope = rememberCoroutineScope() + var showApplicationPinCode by remember { + mutableStateOf(false) + } + + val biometricUnlock = biometricAuthenticatorManager.rememberUnlockDeviceBiometricAuthenticator() + val deviceUnlockCallback by biometricRequester.deviceUnlockCallback.collectAsState() + val canUseDeviceUnlock = biometricAuthenticatorManager.canUseDeviceUnlock + + fun setUnlock(isUnlock: Boolean) = coroutineScope.launch { + deviceUnlockCallback?.let { + if (isUnlock) { + it.onUnlocked() + } else { + it.onCancel() + } + } + showApplicationPinCode = false + biometricRequester.onDone() + } + + LaunchedEffect(biometricUnlock, canUseDeviceUnlock, deviceUnlockCallback) { + if (deviceUnlockCallback != null) { + if (canUseDeviceUnlock) { + biometricUnlock.setup() + biometricUnlock.authenticate() + } else if (pinCodeManager.hasPinCode().first()) { + showApplicationPinCode = true + } else { + // No security, unlock immediately + setUnlock(true) + } + } + } + + pinUnlockHelper.OnUnlockEffect { isUnlock -> + setUnlock(isUnlock) + } + + fun handleEvent(event: DeviceUnlockEvent) { + when (event) { + DeviceUnlockEvent.CancelPinCode -> { + showApplicationPinCode = false + setUnlock(false) + } + } + } + + return DeviceUnlockState( + showApplicationPinCode = showApplicationPinCode, + eventSink = ::handleEvent, + ) + } +} diff --git a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/device/DeviceUnlockState.kt b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/device/DeviceUnlockState.kt new file mode 100644 index 0000000000..48d2181605 --- /dev/null +++ b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/device/DeviceUnlockState.kt @@ -0,0 +1,13 @@ +/* + * Copyright (c) 2026 Element Creations Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial. + * Please see LICENSE files in the repository root for full details. + */ + +package io.element.android.features.lockscreen.impl.device + +data class DeviceUnlockState( + val showApplicationPinCode: Boolean, + val eventSink: (DeviceUnlockEvent) -> Unit, +) diff --git a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/settings/LockScreenSettingsFlowNode.kt b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/settings/LockScreenSettingsFlowNode.kt index 0bd26729d5..a6e2c1265c 100644 --- a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/settings/LockScreenSettingsFlowNode.kt +++ b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/settings/LockScreenSettingsFlowNode.kt @@ -103,8 +103,15 @@ class LockScreenSettingsFlowNode( override fun onUnlock() { backstack.newRoot(NavTarget.Settings) } + + override fun onCancel() { + // Should not happen in this context. + } } - createNode(buildContext, plugins = listOf(callback)) + val inputs = PinUnlockNode.Inputs( + forDeviceUnlock = false, + ) + createNode(buildContext, plugins = listOf(callback, inputs)) } NavTarget.SetupPin -> { createNode(buildContext) diff --git a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/unlock/PinUnlockHelper.kt b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/unlock/PinUnlockHelper.kt index 2a475814c9..10de1f23a5 100644 --- a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/unlock/PinUnlockHelper.kt +++ b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/unlock/PinUnlockHelper.kt @@ -24,17 +24,23 @@ class PinUnlockHelper( private val pinCodeManager: PinCodeManager ) { @Composable - fun OnUnlockEffect(onUnlock: () -> Unit) { + fun OnUnlockEffect(onUnlock: (Boolean) -> Unit) { val latestOnUnlock by rememberUpdatedState(onUnlock) DisposableEffect(Unit) { val biometricUnlockCallback = object : DefaultBiometricUnlockCallback() { override fun onBiometricAuthenticationSuccess() { - latestOnUnlock() + latestOnUnlock(true) + } + + override fun onBiometricAuthenticationFailed(error: Exception?) { + if (error != null) { + latestOnUnlock(false) + } } } val pinCodeVerifiedCallback = object : DefaultPinCodeManagerCallback() { override fun onPinCodeVerified() { - latestOnUnlock() + latestOnUnlock(true) } } biometricAuthenticatorManager.addCallback(biometricUnlockCallback) diff --git a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/unlock/PinUnlockNode.kt b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/unlock/PinUnlockNode.kt index 459e165e00..47e7715ea5 100644 --- a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/unlock/PinUnlockNode.kt +++ b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/unlock/PinUnlockNode.kt @@ -17,7 +17,9 @@ import com.bumble.appyx.core.plugin.Plugin import dev.zacsweers.metro.Assisted import dev.zacsweers.metro.AssistedInject import io.element.android.annotations.ContributesNode +import io.element.android.libraries.architecture.NodeInputs import io.element.android.libraries.architecture.callback +import io.element.android.libraries.architecture.inputs import io.element.android.libraries.di.SessionScope @ContributesNode(SessionScope::class) @@ -25,13 +27,23 @@ import io.element.android.libraries.di.SessionScope class PinUnlockNode( @Assisted buildContext: BuildContext, @Assisted plugins: List, - private val presenter: PinUnlockPresenter, + presenterFactory: PinUnlockPresenter.Factory, ) : Node(buildContext, plugins = plugins) { interface Callback : Plugin { fun onUnlock() + + // For feature unlock + fun onCancel() } + data class Inputs( + val forDeviceUnlock: Boolean, + ) : NodeInputs + private val callback: Callback = callback() + private val inputs: Inputs = inputs() + + private val presenter: PinUnlockPresenter = presenterFactory.create(inputs.forDeviceUnlock) @Composable override fun View(modifier: Modifier) { @@ -46,6 +58,7 @@ class PinUnlockNode( // UnlockNode is only used for in-app unlock, so we can safely set isInAppUnlock to true. // It's set to false in PinUnlockActivity. isInAppUnlock = true, + onCancel = callback::onCancel, modifier = modifier ) } diff --git a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/unlock/PinUnlockPresenter.kt b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/unlock/PinUnlockPresenter.kt index c8dd8916f9..65afba669d 100644 --- a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/unlock/PinUnlockPresenter.kt +++ b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/unlock/PinUnlockPresenter.kt @@ -16,7 +16,9 @@ import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.runtime.setValue -import dev.zacsweers.metro.Inject +import dev.zacsweers.metro.Assisted +import dev.zacsweers.metro.AssistedFactory +import dev.zacsweers.metro.AssistedInject import io.element.android.features.lockscreen.impl.biometric.BiometricAuthenticator import io.element.android.features.lockscreen.impl.biometric.BiometricAuthenticatorManager import io.element.android.features.lockscreen.impl.pin.PinCodeManager @@ -32,8 +34,9 @@ import io.element.android.libraries.di.annotations.AppCoroutineScope import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.launch -@Inject +@AssistedInject class PinUnlockPresenter( + @Assisted private val forDeviceUnlock: Boolean, private val pinCodeManager: PinCodeManager, private val biometricAuthenticatorManager: BiometricAuthenticatorManager, private val logoutUseCase: LogoutUseCase, @@ -41,6 +44,11 @@ class PinUnlockPresenter( private val coroutineScope: CoroutineScope, private val pinUnlockHelper: PinUnlockHelper, ) : Presenter { + @AssistedFactory + interface Factory { + fun create(forDeviceUnlock: Boolean): PinUnlockPresenter + } + @Composable override fun present(): PinUnlockState { val pinEntryState = remember { @@ -98,7 +106,7 @@ class PinUnlockPresenter( } } pinUnlockHelper.OnUnlockEffect { - isUnlocked.value = true + isUnlocked.value = it } fun handleEvent(event: PinUnlockEvent) { @@ -128,6 +136,7 @@ class PinUnlockPresenter( } } return PinUnlockState( + canNavigateBack = forDeviceUnlock, pinEntry = pinEntry, showWrongPinTitle = showWrongPinTitle, remainingAttempts = remainingAttempts, diff --git a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/unlock/PinUnlockState.kt b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/unlock/PinUnlockState.kt index 037aa87dec..1aae6afa51 100644 --- a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/unlock/PinUnlockState.kt +++ b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/unlock/PinUnlockState.kt @@ -15,6 +15,7 @@ import io.element.android.libraries.architecture.AsyncAction import io.element.android.libraries.architecture.AsyncData data class PinUnlockState( + val canNavigateBack: Boolean, val pinEntry: AsyncData, val showWrongPinTitle: Boolean, val remainingAttempts: AsyncData, diff --git a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/unlock/PinUnlockStateProvider.kt b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/unlock/PinUnlockStateProvider.kt index 1b8166a8ac..aef2c057a2 100644 --- a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/unlock/PinUnlockStateProvider.kt +++ b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/unlock/PinUnlockStateProvider.kt @@ -38,10 +38,20 @@ open class PinUnlockStateProvider : PreviewParameterProvider { showWrongPinTitle = true, isUnlocked = true, ), + aPinUnlockState(canNavigateBack = true), + ) +} + +open class PinUnlockStateCompactProvider : PreviewParameterProvider { + override val values: Sequence + get() = sequenceOf( + aPinUnlockState(), + aPinUnlockState(canNavigateBack = true) ) } fun aPinUnlockState( + canNavigateBack: Boolean = false, pinEntry: AsyncData = AsyncData.Success(PinEntry.createEmpty(4)), remainingAttempts: AsyncData = AsyncData.Success(3), showWrongPinTitle: Boolean = false, @@ -51,6 +61,7 @@ fun aPinUnlockState( isUnlocked: Boolean = false, signOutAction: AsyncAction = AsyncAction.Uninitialized, ) = PinUnlockState( + canNavigateBack = canNavigateBack, pinEntry = pinEntry, showWrongPinTitle = showWrongPinTitle, remainingAttempts = remainingAttempts, diff --git a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/unlock/PinUnlockView.kt b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/unlock/PinUnlockView.kt index 6749697b64..0292b29a0f 100644 --- a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/unlock/PinUnlockView.kt +++ b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/unlock/PinUnlockView.kt @@ -36,6 +36,7 @@ import androidx.compose.ui.focus.focusRequester import androidx.compose.ui.res.pluralStringResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.PreviewParameter import androidx.compose.ui.unit.dp import androidx.lifecycle.Lifecycle @@ -50,6 +51,7 @@ import io.element.android.libraries.architecture.AsyncAction import io.element.android.libraries.architecture.AsyncData import io.element.android.libraries.designsystem.components.BigIcon import io.element.android.libraries.designsystem.components.ProgressDialog +import io.element.android.libraries.designsystem.components.button.BackButton import io.element.android.libraries.designsystem.components.dialogs.ConfirmationDialog import io.element.android.libraries.designsystem.components.dialogs.ErrorDialog import io.element.android.libraries.designsystem.preview.ElementPreview @@ -65,6 +67,7 @@ import io.element.android.libraries.ui.strings.CommonStrings fun PinUnlockView( state: PinUnlockState, isInAppUnlock: Boolean, + onCancel: () -> Unit, modifier: Modifier = Modifier, ) { OnLifecycleEvent { _, event -> @@ -74,7 +77,7 @@ fun PinUnlockView( } } Surface(modifier) { - PinUnlockPage(state = state, isInAppUnlock = isInAppUnlock) + PinUnlockPage(state = state, isInAppUnlock = isInAppUnlock, onCancel = onCancel) if (state.showSignOutPrompt) { SignOutPrompt( isCancellable = state.isSignOutPromptCancellable, @@ -105,13 +108,14 @@ fun PinUnlockView( private fun PinUnlockPage( state: PinUnlockState, isInAppUnlock: Boolean, + onCancel: () -> Unit, ) { BoxWithConstraints { val commonModifier = Modifier - .fillMaxSize() - .systemBarsPadding() - .imePadding() - .padding(all = 20.dp) + .fillMaxSize() + .systemBarsPadding() + .imePadding() + .padding(all = 20.dp) val header = @Composable { PinUnlockHeader( @@ -147,8 +151,8 @@ private fun PinUnlockPage( state.eventSink(PinUnlockEvent.OnPinEntryChanged(it)) }, modifier = Modifier - .focusRequester(focusRequester) - .fillMaxWidth() + .focusRequester(focusRequester) + .fillMaxWidth() ) } } else { @@ -177,6 +181,15 @@ private fun PinUnlockPage( modifier = commonModifier, ) } + if (state.canNavigateBack) { + BackButton( + onClick = onCancel, + modifier = Modifier + .align(Alignment.TopStart) + .systemBarsPadding() + .padding(8.dp), + ) + } } } @@ -217,8 +230,8 @@ private fun PinUnlockCompactView( } BoxWithConstraints( modifier = Modifier - .weight(1f) - .fillMaxHeight(), + .weight(1f) + .fillMaxHeight(), contentAlignment = Alignment.Center, ) { content() @@ -239,9 +252,9 @@ private fun PinUnlockExpandedView( header() BoxWithConstraints( modifier = Modifier - .weight(1f) - .fillMaxWidth() - .padding(top = 40.dp), + .weight(1f) + .fillMaxWidth() + .padding(top = 40.dp), ) { content() } @@ -274,8 +287,8 @@ private fun PinDot( } Box( modifier = Modifier - .size(14.dp) - .background(backgroundColor, CircleShape) + .size(14.dp) + .background(backgroundColor, CircleShape) ) } @@ -373,6 +386,7 @@ internal fun PinUnlockViewInAppPreview(@PreviewParameter(PinUnlockStateProvider: PinUnlockView( state = state, isInAppUnlock = true, + onCancel = {}, ) } } @@ -384,6 +398,19 @@ internal fun PinUnlockViewPreview(@PreviewParameter(PinUnlockStateProvider::clas PinUnlockView( state = state, isInAppUnlock = false, + onCancel = {}, + ) + } +} + +@Composable +@Preview(heightDp = 480, widthDp = 800) +internal fun PinUnlockViewCompactPreview(@PreviewParameter(PinUnlockStateCompactProvider::class) state: PinUnlockState) { + ElementPreview { + PinUnlockView( + state = state, + isInAppUnlock = false, + onCancel = {}, ) } } diff --git a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/unlock/activity/PinUnlockActivity.kt b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/unlock/activity/PinUnlockActivity.kt index 34adfeca99..613b1cf79e 100644 --- a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/unlock/activity/PinUnlockActivity.kt +++ b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/unlock/activity/PinUnlockActivity.kt @@ -41,7 +41,7 @@ class PinUnlockActivity : AppCompatActivity() { } } - @Inject lateinit var presenter: PinUnlockPresenter + @Inject lateinit var presenterFactory: PinUnlockPresenter.Factory @Inject lateinit var lockScreenService: LockScreenService @Inject lateinit var appPreferencesStore: AppPreferencesStore @Inject lateinit var featureFlagService: FeatureFlagService @@ -52,6 +52,7 @@ class PinUnlockActivity : AppCompatActivity() { enableEdgeToEdge() super.onCreate(savedInstanceState) bindings().inject(this) + val presenter = presenterFactory.create(forDeviceUnlock = false) setContent { val colors by remember { enterpriseService.semanticColorsFlow(sessionId = null) @@ -67,6 +68,9 @@ class PinUnlockActivity : AppCompatActivity() { PinUnlockView( state = state, isInAppUnlock = false, + onCancel = { + // Should not happen + }, ) } } diff --git a/features/lockscreen/impl/src/test/kotlin/io/element/android/features/lockscreen/impl/biometric/FakeBiometricAuthenticator.kt b/features/lockscreen/impl/src/test/kotlin/io/element/android/features/lockscreen/impl/biometric/FakeBiometricAuthenticator.kt index 63729f941a..0fb2e9df8b 100644 --- a/features/lockscreen/impl/src/test/kotlin/io/element/android/features/lockscreen/impl/biometric/FakeBiometricAuthenticator.kt +++ b/features/lockscreen/impl/src/test/kotlin/io/element/android/features/lockscreen/impl/biometric/FakeBiometricAuthenticator.kt @@ -8,10 +8,18 @@ package io.element.android.features.lockscreen.impl.biometric +import io.element.android.tests.testutils.simulateLongTask + class FakeBiometricAuthenticator( override val isActive: Boolean = false, - private val authenticateLambda: suspend () -> BiometricAuthenticator.AuthenticationResult = { BiometricAuthenticator.AuthenticationResult.Success }, + private val setupLambda: () -> Unit = { }, + private val authenticateLambda: () -> BiometricAuthenticator.AuthenticationResult = { BiometricAuthenticator.AuthenticationResult.Success }, ) : BiometricAuthenticator { - override suspend fun setup() = Unit - override suspend fun authenticate() = authenticateLambda() + override suspend fun setup() = simulateLongTask { + setupLambda() + } + + override suspend fun authenticate() = simulateLongTask { + authenticateLambda() + } } diff --git a/features/lockscreen/impl/src/test/kotlin/io/element/android/features/lockscreen/impl/biometric/FakeBiometricAuthenticatorManager.kt b/features/lockscreen/impl/src/test/kotlin/io/element/android/features/lockscreen/impl/biometric/FakeBiometricAuthenticatorManager.kt index 0ae8552334..1a70f25d30 100644 --- a/features/lockscreen/impl/src/test/kotlin/io/element/android/features/lockscreen/impl/biometric/FakeBiometricAuthenticatorManager.kt +++ b/features/lockscreen/impl/src/test/kotlin/io/element/android/features/lockscreen/impl/biometric/FakeBiometricAuthenticatorManager.kt @@ -12,8 +12,9 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.remember class FakeBiometricAuthenticatorManager( - override var isDeviceSecured: Boolean = true, - override var hasAvailableAuthenticator: Boolean = false, + override val isDeviceSecured: Boolean = true, + override val canUseDeviceUnlock: Boolean = true, + override val hasAvailableAuthenticator: Boolean = false, private val createBiometricAuthenticator: () -> BiometricAuthenticator = { FakeBiometricAuthenticator() }, private val disableLambda: suspend () -> Unit = { }, ) : BiometricAuthenticatorManager { @@ -28,7 +29,14 @@ class FakeBiometricAuthenticatorManager( @Composable override fun rememberUnlockBiometricAuthenticator(): BiometricAuthenticator { return remember { - createBiometricAuthenticator() + createBiometricAuthenticator() + } + } + + @Composable + override fun rememberUnlockDeviceBiometricAuthenticator(): BiometricAuthenticator { + return remember { + createBiometricAuthenticator() } } diff --git a/features/lockscreen/impl/src/test/kotlin/io/element/android/features/lockscreen/impl/device/DeviceUnlockPresenterTest.kt b/features/lockscreen/impl/src/test/kotlin/io/element/android/features/lockscreen/impl/device/DeviceUnlockPresenterTest.kt new file mode 100644 index 0000000000..f94c9b4251 --- /dev/null +++ b/features/lockscreen/impl/src/test/kotlin/io/element/android/features/lockscreen/impl/device/DeviceUnlockPresenterTest.kt @@ -0,0 +1,152 @@ +/* + * Copyright (c) 2026 Element Creations Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial. + * Please see LICENSE files in the repository root for full details. + */ + +@file:OptIn(ExperimentalCoroutinesApi::class) + +package io.element.android.features.lockscreen.impl.device + +import com.google.common.truth.Truth.assertThat +import io.element.android.features.lockscreen.impl.biometric.BiometricAuthenticator +import io.element.android.features.lockscreen.impl.biometric.FakeBiometricAuthenticator +import io.element.android.features.lockscreen.impl.biometric.FakeBiometricAuthenticatorManager +import io.element.android.features.lockscreen.impl.fixtures.aPinCodeManager +import io.element.android.features.lockscreen.impl.pin.PinCodeManager +import io.element.android.features.lockscreen.impl.unlock.PinUnlockHelper +import io.element.android.features.lockscreen.test.FakeDeviceUnlockCallback +import io.element.android.tests.testutils.lambda.lambdaRecorder +import io.element.android.tests.testutils.test +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.test.advanceUntilIdle +import kotlinx.coroutines.test.runTest +import org.junit.Test + +class DeviceUnlockPresenterTest { + @Test + fun `present - when unlock requested and device unlock available, use biometric authenticator`() = runTest { + val setupLambda = lambdaRecorder { } + val authenticateLambda = lambdaRecorder { + BiometricAuthenticator.AuthenticationResult.Success + } + val fakeBiometricAuthenticator = FakeBiometricAuthenticator( + setupLambda = setupLambda, + authenticateLambda = authenticateLambda, + ) + val biometricAuthenticatorManager = FakeBiometricAuthenticatorManager( + canUseDeviceUnlock = true, + createBiometricAuthenticator = { fakeBiometricAuthenticator }, + ) + val callbackHolder = DeviceUnlockCallbackHolder() + val callback = FakeDeviceUnlockCallback() + + createPresenter( + biometricAuthenticatorManager = biometricAuthenticatorManager, + callbackHolder = callbackHolder, + ).test { + awaitItem().also { state -> + assertThat(state.showApplicationPinCode).isFalse() + } + callbackHolder.requestUnlock(callback) + advanceUntilIdle() + setupLambda.assertions().isCalledOnce() + authenticateLambda.assertions().isCalledOnce() + skipItems(1) + } + } + + @Test + fun `present - when unlock requested and device unlock unavailable and app pin is configured, show app pin`() = runTest { + val callbackHolder = DeviceUnlockCallbackHolder() + val callback = FakeDeviceUnlockCallback() + val pinCodeManager = aPinCodeManager().apply { + createPinCode("1234") + } + createPresenter( + biometricAuthenticatorManager = FakeBiometricAuthenticatorManager(canUseDeviceUnlock = false), + callbackHolder = callbackHolder, + pinCodeManager = pinCodeManager, + ).test { + awaitItem().also { state -> + assertThat(state.showApplicationPinCode).isFalse() + } + + callbackHolder.requestUnlock(callback) + skipItems(1) + awaitItem().also { state -> + assertThat(state.showApplicationPinCode).isTrue() + } + } + } + + @Test + fun `present - when unlock requested and no security, unlock immediately`() = runTest { + val callbackHolder = DeviceUnlockCallbackHolder() + val onUnlockedLambda = lambdaRecorder { } + val callback = FakeDeviceUnlockCallback( + onUnlockedLambda = onUnlockedLambda, + ) + createPresenter( + biometricAuthenticatorManager = FakeBiometricAuthenticatorManager(canUseDeviceUnlock = false), + callbackHolder = callbackHolder, + ).test { + awaitItem().also { state -> + assertThat(state.showApplicationPinCode).isFalse() + } + callbackHolder.requestUnlock(callback) + skipItems(2) + assertThat(callbackHolder.deviceUnlockCallback.value).isNull() + onUnlockedLambda.assertions().isCalledOnce() + } + } + + @Test + fun `present - CancelPinCode event cancels unlock request`() = runTest { + val callbackHolder = DeviceUnlockCallbackHolder() + val onCancelLambda = lambdaRecorder { } + val callback = FakeDeviceUnlockCallback( + onCancelLambda = onCancelLambda, + ) + val pinCodeManager = aPinCodeManager().apply { + createPinCode("1234") + } + createPresenter( + biometricAuthenticatorManager = FakeBiometricAuthenticatorManager(canUseDeviceUnlock = false), + callbackHolder = callbackHolder, + pinCodeManager = pinCodeManager, + ).test { + awaitItem() + callbackHolder.requestUnlock(callback) + skipItems(1) + awaitItem().also { state -> + assertThat(state.showApplicationPinCode).isTrue() + state.eventSink(DeviceUnlockEvent.CancelPinCode) + } + awaitItem().also { state -> + assertThat(state.showApplicationPinCode).isFalse() + } + skipItems(1) + onCancelLambda.assertions().isCalledOnce() + assertThat(callbackHolder.deviceUnlockCallback.value).isNull() + } + } + + private fun createPresenter( + biometricAuthenticatorManager: FakeBiometricAuthenticatorManager = FakeBiometricAuthenticatorManager(), + callbackHolder: DeviceUnlockCallbackHolder = DeviceUnlockCallbackHolder(), + pinCodeManager: PinCodeManager = aPinCodeManager(), + ): DeviceUnlockPresenter { + val pinUnlockHelper = PinUnlockHelper( + biometricAuthenticatorManager = biometricAuthenticatorManager, + pinCodeManager = pinCodeManager, + ) + return DeviceUnlockPresenter( + pinUnlockHelper = pinUnlockHelper, + biometricAuthenticatorManager = biometricAuthenticatorManager, + biometricRequester = callbackHolder, + pinCodeManager = pinCodeManager, + ) + } +} diff --git a/features/lockscreen/impl/src/test/kotlin/io/element/android/features/lockscreen/impl/unlock/PinUnlockPresenterTest.kt b/features/lockscreen/impl/src/test/kotlin/io/element/android/features/lockscreen/impl/unlock/PinUnlockPresenterTest.kt index fa7d05b5cb..b20a99d27f 100644 --- a/features/lockscreen/impl/src/test/kotlin/io/element/android/features/lockscreen/impl/unlock/PinUnlockPresenterTest.kt +++ b/features/lockscreen/impl/src/test/kotlin/io/element/android/features/lockscreen/impl/unlock/PinUnlockPresenterTest.kt @@ -147,11 +147,37 @@ class PinUnlockPresenterTest { } } + @Test + fun `present - forDeviceUnlock is exposed in state`() = runTest { + val presenter = createPinUnlockPresenter(forDeviceUnlock = true) + presenter.test { + skipItems(1) + awaitItem().also { state -> + assertThat(state.canNavigateBack).isTrue() + } + } + } + + @Test + fun `present - pin entry changed event updates pin entry`() = runTest { + val presenter = createPinUnlockPresenter() + presenter.test { + skipItems(1) + awaitItem().also { state -> + state.eventSink(PinUnlockEvent.OnPinEntryChanged(halfCompletePin)) + } + awaitItem().also { state -> + state.pinEntry.assertText(halfCompletePin) + } + } + } + private fun AsyncData.assertText(text: String) { dataOrNull()?.assertText(text) } private suspend fun TestScope.createPinUnlockPresenter( + forDeviceUnlock: Boolean = false, biometricAuthenticatorManager: BiometricAuthenticatorManager = FakeBiometricAuthenticatorManager(), callback: PinCodeManager.Callback = DefaultPinCodeManagerCallback(), logoutUseCase: FakeLogoutUseCase = FakeLogoutUseCase(logoutLambda = {}), @@ -162,6 +188,7 @@ class PinUnlockPresenterTest { createPinCode(completePin) } return PinUnlockPresenter( + forDeviceUnlock = forDeviceUnlock, pinCodeManager = pinCodeManager, biometricAuthenticatorManager = biometricAuthenticatorManager, logoutUseCase = logoutUseCase, diff --git a/features/lockscreen/test/src/main/kotlin/io/element/android/features/lockscreen/test/FakeDeviceUnlockCallback.kt b/features/lockscreen/test/src/main/kotlin/io/element/android/features/lockscreen/test/FakeDeviceUnlockCallback.kt new file mode 100644 index 0000000000..f960733902 --- /dev/null +++ b/features/lockscreen/test/src/main/kotlin/io/element/android/features/lockscreen/test/FakeDeviceUnlockCallback.kt @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2026 Element Creations Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial. + * Please see LICENSE files in the repository root for full details. + */ + +package io.element.android.features.lockscreen.test + +import io.element.android.features.lockscreen.api.DeviceUnlockEntryPoint +import io.element.android.tests.testutils.EnsureNeverCalled + +class FakeDeviceUnlockCallback( + private val onCancelLambda: () -> Unit = EnsureNeverCalled(), + private val onUnlockedLambda: () -> Unit = EnsureNeverCalled(), +) : DeviceUnlockEntryPoint.Callback { + override fun onCancel() = onCancelLambda() + override fun onUnlocked() = onUnlockedLambda() +} diff --git a/features/lockscreen/test/src/main/kotlin/io/element/android/features/lockscreen/test/FakeDeviceUnlockEntryPoint.kt b/features/lockscreen/test/src/main/kotlin/io/element/android/features/lockscreen/test/FakeDeviceUnlockEntryPoint.kt new file mode 100644 index 0000000000..8278fc882f --- /dev/null +++ b/features/lockscreen/test/src/main/kotlin/io/element/android/features/lockscreen/test/FakeDeviceUnlockEntryPoint.kt @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2026 Element Creations Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial. + * Please see LICENSE files in the repository root for full details. + */ + +package io.element.android.features.lockscreen.test + +import com.bumble.appyx.core.modality.BuildContext +import com.bumble.appyx.core.node.Node +import io.element.android.features.lockscreen.api.DeviceUnlockEntryPoint +import io.element.android.tests.testutils.lambda.lambdaError + +class FakeDeviceUnlockEntryPoint : DeviceUnlockEntryPoint { + override fun createNode( + parentNode: Node, + buildContext: BuildContext, + ): Node = lambdaError() + + override fun requestUnlock(callback: DeviceUnlockEntryPoint.Callback) = lambdaError() +} diff --git a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/linknewdevice/LinkMobileHandler.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/linknewdevice/LinkMobileHandler.kt index 1947729c7f..eb2d49b5b0 100644 --- a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/linknewdevice/LinkMobileHandler.kt +++ b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/linknewdevice/LinkMobileHandler.kt @@ -16,6 +16,9 @@ interface LinkMobileHandler { sealed interface LinkMobileStep { data object Uninitialized : LinkMobileStep + + // Internal application step, for the UI + data object CreatingQrCode : LinkMobileStep data object Starting : LinkMobileStep data class QrReady(val data: String) : LinkMobileStep data object QrRotating : LinkMobileStep From 8e12acf62c0498d2c5d17f622e36704da160cb86 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Tue, 16 Jun 2026 14:04:46 +0200 Subject: [PATCH 3/5] Fix Konsist tests. --- .../impl/device/DeviceUnlockPresenterTest.kt | 20 +++++++++---------- ... => FakeDeviceUnlockEntryPointCallback.kt} | 2 +- 2 files changed, 11 insertions(+), 11 deletions(-) rename features/lockscreen/test/src/main/kotlin/io/element/android/features/lockscreen/test/{FakeDeviceUnlockCallback.kt => FakeDeviceUnlockEntryPointCallback.kt} (94%) diff --git a/features/lockscreen/impl/src/test/kotlin/io/element/android/features/lockscreen/impl/device/DeviceUnlockPresenterTest.kt b/features/lockscreen/impl/src/test/kotlin/io/element/android/features/lockscreen/impl/device/DeviceUnlockPresenterTest.kt index f94c9b4251..4b1cdf645d 100644 --- a/features/lockscreen/impl/src/test/kotlin/io/element/android/features/lockscreen/impl/device/DeviceUnlockPresenterTest.kt +++ b/features/lockscreen/impl/src/test/kotlin/io/element/android/features/lockscreen/impl/device/DeviceUnlockPresenterTest.kt @@ -16,7 +16,7 @@ import io.element.android.features.lockscreen.impl.biometric.FakeBiometricAuthen import io.element.android.features.lockscreen.impl.fixtures.aPinCodeManager import io.element.android.features.lockscreen.impl.pin.PinCodeManager import io.element.android.features.lockscreen.impl.unlock.PinUnlockHelper -import io.element.android.features.lockscreen.test.FakeDeviceUnlockCallback +import io.element.android.features.lockscreen.test.FakeDeviceUnlockEntryPointCallback import io.element.android.tests.testutils.lambda.lambdaRecorder import io.element.android.tests.testutils.test import kotlinx.coroutines.ExperimentalCoroutinesApi @@ -40,9 +40,9 @@ class DeviceUnlockPresenterTest { createBiometricAuthenticator = { fakeBiometricAuthenticator }, ) val callbackHolder = DeviceUnlockCallbackHolder() - val callback = FakeDeviceUnlockCallback() + val callback = FakeDeviceUnlockEntryPointCallback() - createPresenter( + createDeviceUnlockPresenter( biometricAuthenticatorManager = biometricAuthenticatorManager, callbackHolder = callbackHolder, ).test { @@ -60,11 +60,11 @@ class DeviceUnlockPresenterTest { @Test fun `present - when unlock requested and device unlock unavailable and app pin is configured, show app pin`() = runTest { val callbackHolder = DeviceUnlockCallbackHolder() - val callback = FakeDeviceUnlockCallback() + val callback = FakeDeviceUnlockEntryPointCallback() val pinCodeManager = aPinCodeManager().apply { createPinCode("1234") } - createPresenter( + createDeviceUnlockPresenter( biometricAuthenticatorManager = FakeBiometricAuthenticatorManager(canUseDeviceUnlock = false), callbackHolder = callbackHolder, pinCodeManager = pinCodeManager, @@ -85,10 +85,10 @@ class DeviceUnlockPresenterTest { fun `present - when unlock requested and no security, unlock immediately`() = runTest { val callbackHolder = DeviceUnlockCallbackHolder() val onUnlockedLambda = lambdaRecorder { } - val callback = FakeDeviceUnlockCallback( + val callback = FakeDeviceUnlockEntryPointCallback( onUnlockedLambda = onUnlockedLambda, ) - createPresenter( + createDeviceUnlockPresenter( biometricAuthenticatorManager = FakeBiometricAuthenticatorManager(canUseDeviceUnlock = false), callbackHolder = callbackHolder, ).test { @@ -106,13 +106,13 @@ class DeviceUnlockPresenterTest { fun `present - CancelPinCode event cancels unlock request`() = runTest { val callbackHolder = DeviceUnlockCallbackHolder() val onCancelLambda = lambdaRecorder { } - val callback = FakeDeviceUnlockCallback( + val callback = FakeDeviceUnlockEntryPointCallback( onCancelLambda = onCancelLambda, ) val pinCodeManager = aPinCodeManager().apply { createPinCode("1234") } - createPresenter( + createDeviceUnlockPresenter( biometricAuthenticatorManager = FakeBiometricAuthenticatorManager(canUseDeviceUnlock = false), callbackHolder = callbackHolder, pinCodeManager = pinCodeManager, @@ -133,7 +133,7 @@ class DeviceUnlockPresenterTest { } } - private fun createPresenter( + private fun createDeviceUnlockPresenter( biometricAuthenticatorManager: FakeBiometricAuthenticatorManager = FakeBiometricAuthenticatorManager(), callbackHolder: DeviceUnlockCallbackHolder = DeviceUnlockCallbackHolder(), pinCodeManager: PinCodeManager = aPinCodeManager(), diff --git a/features/lockscreen/test/src/main/kotlin/io/element/android/features/lockscreen/test/FakeDeviceUnlockCallback.kt b/features/lockscreen/test/src/main/kotlin/io/element/android/features/lockscreen/test/FakeDeviceUnlockEntryPointCallback.kt similarity index 94% rename from features/lockscreen/test/src/main/kotlin/io/element/android/features/lockscreen/test/FakeDeviceUnlockCallback.kt rename to features/lockscreen/test/src/main/kotlin/io/element/android/features/lockscreen/test/FakeDeviceUnlockEntryPointCallback.kt index f960733902..9c80caede2 100644 --- a/features/lockscreen/test/src/main/kotlin/io/element/android/features/lockscreen/test/FakeDeviceUnlockCallback.kt +++ b/features/lockscreen/test/src/main/kotlin/io/element/android/features/lockscreen/test/FakeDeviceUnlockEntryPointCallback.kt @@ -10,7 +10,7 @@ package io.element.android.features.lockscreen.test import io.element.android.features.lockscreen.api.DeviceUnlockEntryPoint import io.element.android.tests.testutils.EnsureNeverCalled -class FakeDeviceUnlockCallback( +class FakeDeviceUnlockEntryPointCallback( private val onCancelLambda: () -> Unit = EnsureNeverCalled(), private val onUnlockedLambda: () -> Unit = EnsureNeverCalled(), ) : DeviceUnlockEntryPoint.Callback { From 2836bccfce05ade33587de0694d6d509254cee9c Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 17 Jun 2026 11:11:26 +0200 Subject: [PATCH 4/5] Handle PR reviews. --- .../linknewdevice/impl/LinkNewDeviceFlowNode.kt | 2 +- .../lockscreen/api/DeviceUnlockEntryPoint.kt | 2 +- .../impl/biometric/BiometricAuthenticator.kt | 1 + .../impl/biometric/BiometricAuthenticatorManager.kt | 2 +- .../DefaultBiometricAuthenticatorManager.kt | 2 +- .../lockscreen/impl/device/DeviceUnlockNode.kt | 4 ++-- .../lockscreen/impl/device/DeviceUnlockPresenter.kt | 13 +++++-------- .../impl/device/DeviceUnlockPresenterTest.kt | 2 +- .../test/FakeDeviceUnlockEntryPointCallback.kt | 2 +- 9 files changed, 14 insertions(+), 16 deletions(-) diff --git a/features/linknewdevice/impl/src/main/kotlin/io/element/android/features/linknewdevice/impl/LinkNewDeviceFlowNode.kt b/features/linknewdevice/impl/src/main/kotlin/io/element/android/features/linknewdevice/impl/LinkNewDeviceFlowNode.kt index 8f434384c4..d686b22860 100644 --- a/features/linknewdevice/impl/src/main/kotlin/io/element/android/features/linknewdevice/impl/LinkNewDeviceFlowNode.kt +++ b/features/linknewdevice/impl/src/main/kotlin/io/element/android/features/linknewdevice/impl/LinkNewDeviceFlowNode.kt @@ -242,7 +242,7 @@ class LinkNewDeviceFlowNode( override fun onUnlockDevice(type: LinkDeviceType) { val callback = object : DeviceUnlockEntryPoint.Callback { override fun onCancel() = Unit - override fun onUnlocked() = when (type) { + override fun onUnlock() = when (type) { LinkDeviceType.Mobile -> { linkNewMobileHandler.reset() linkNewMobileHandler.createAndStartNewHandler() diff --git a/features/lockscreen/api/src/main/kotlin/io/element/android/features/lockscreen/api/DeviceUnlockEntryPoint.kt b/features/lockscreen/api/src/main/kotlin/io/element/android/features/lockscreen/api/DeviceUnlockEntryPoint.kt index 2953688a84..d67668caf1 100644 --- a/features/lockscreen/api/src/main/kotlin/io/element/android/features/lockscreen/api/DeviceUnlockEntryPoint.kt +++ b/features/lockscreen/api/src/main/kotlin/io/element/android/features/lockscreen/api/DeviceUnlockEntryPoint.kt @@ -30,6 +30,6 @@ interface DeviceUnlockEntryPoint : FeatureEntryPoint { interface Callback { fun onCancel() - fun onUnlocked() + fun onUnlock() } } diff --git a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/biometric/BiometricAuthenticator.kt b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/biometric/BiometricAuthenticator.kt index 097049c97a..74d36b0834 100644 --- a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/biometric/BiometricAuthenticator.kt +++ b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/biometric/BiometricAuthenticator.kt @@ -59,6 +59,7 @@ class DefaultBiometricAuthentication( private var cryptoObject: CryptoObject? = null override suspend fun setup() { + if (cryptoObject != null) return try { val secretKey = ensureKey() val cipher = encryptionDecryptionService.createEncryptionCipher(secretKey) diff --git a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/biometric/BiometricAuthenticatorManager.kt b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/biometric/BiometricAuthenticatorManager.kt index 6234e65284..cccfa143b9 100644 --- a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/biometric/BiometricAuthenticatorManager.kt +++ b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/biometric/BiometricAuthenticatorManager.kt @@ -22,7 +22,7 @@ interface BiometricAuthenticatorManager { val hasAvailableAuthenticator: Boolean /** - * If the device is secured for example with a pin, pattern or password, and the user has enrolled at least one biometric. + * If the device is secured for example with a pin, a pattern, a password, or biometric. */ val canUseDeviceUnlock: Boolean diff --git a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/biometric/DefaultBiometricAuthenticatorManager.kt b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/biometric/DefaultBiometricAuthenticatorManager.kt index 27408c919a..80ea43b44d 100644 --- a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/biometric/DefaultBiometricAuthenticatorManager.kt +++ b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/biometric/DefaultBiometricAuthenticatorManager.kt @@ -71,7 +71,7 @@ class DefaultBiometricAuthenticatorManager( biometricManager.canAuthenticate(BiometricManager.Authenticators.BIOMETRIC_STRONG) == BiometricManager.BIOMETRIC_SUCCESS /** - * Returns true if a strong biometric method (i.e.: fingerprint, some face or iris unlock implementations) can be used. + * Returns true if a device credential method (i.e.: pattern, pin) can be used. */ private val canUseDeviceCredentialAuth: Boolean get() = biometricManager.canAuthenticate(BiometricManager.Authenticators.DEVICE_CREDENTIAL) == BiometricManager.BIOMETRIC_SUCCESS diff --git a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/device/DeviceUnlockNode.kt b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/device/DeviceUnlockNode.kt index 2df706abe7..9b73239725 100644 --- a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/device/DeviceUnlockNode.kt +++ b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/device/DeviceUnlockNode.kt @@ -26,14 +26,14 @@ class DeviceUnlockNode( @Assisted buildContext: BuildContext, @Assisted plugins: List, private val presenter: DeviceUnlockPresenter, - private val presenterFactory: PinUnlockPresenter.Factory, + private val pinUnlockPresenterFactory: PinUnlockPresenter.Factory, ) : Node(buildContext, plugins = plugins) { @Composable override fun View(modifier: Modifier) { val state = presenter.present() if (state.showApplicationPinCode) { val pinUnlockPresenter = remember { - presenterFactory.create(forDeviceUnlock = true) + pinUnlockPresenterFactory.create(forDeviceUnlock = true) } val pinState = pinUnlockPresenter.present() PinUnlockView( diff --git a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/device/DeviceUnlockPresenter.kt b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/device/DeviceUnlockPresenter.kt index 4cc2bb8fd1..676340764e 100644 --- a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/device/DeviceUnlockPresenter.kt +++ b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/device/DeviceUnlockPresenter.kt @@ -13,7 +13,6 @@ import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember -import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.setValue import dev.zacsweers.metro.Inject import io.element.android.features.lockscreen.impl.biometric.BiometricAuthenticatorManager @@ -21,36 +20,34 @@ import io.element.android.features.lockscreen.impl.pin.PinCodeManager import io.element.android.features.lockscreen.impl.unlock.PinUnlockHelper import io.element.android.libraries.architecture.Presenter import kotlinx.coroutines.flow.first -import kotlinx.coroutines.launch @Inject class DeviceUnlockPresenter( private val pinUnlockHelper: PinUnlockHelper, private val biometricAuthenticatorManager: BiometricAuthenticatorManager, - private val biometricRequester: DeviceUnlockCallbackHolder, + private val deviceUnlockCallbackHolder: DeviceUnlockCallbackHolder, private val pinCodeManager: PinCodeManager, ) : Presenter { @Composable override fun present(): DeviceUnlockState { - val coroutineScope = rememberCoroutineScope() var showApplicationPinCode by remember { mutableStateOf(false) } val biometricUnlock = biometricAuthenticatorManager.rememberUnlockDeviceBiometricAuthenticator() - val deviceUnlockCallback by biometricRequester.deviceUnlockCallback.collectAsState() + val deviceUnlockCallback by deviceUnlockCallbackHolder.deviceUnlockCallback.collectAsState() val canUseDeviceUnlock = biometricAuthenticatorManager.canUseDeviceUnlock - fun setUnlock(isUnlock: Boolean) = coroutineScope.launch { + fun setUnlock(isUnlock: Boolean) { deviceUnlockCallback?.let { if (isUnlock) { - it.onUnlocked() + it.onUnlock() } else { it.onCancel() } } showApplicationPinCode = false - biometricRequester.onDone() + deviceUnlockCallbackHolder.onDone() } LaunchedEffect(biometricUnlock, canUseDeviceUnlock, deviceUnlockCallback) { diff --git a/features/lockscreen/impl/src/test/kotlin/io/element/android/features/lockscreen/impl/device/DeviceUnlockPresenterTest.kt b/features/lockscreen/impl/src/test/kotlin/io/element/android/features/lockscreen/impl/device/DeviceUnlockPresenterTest.kt index 4b1cdf645d..52aeaa04a8 100644 --- a/features/lockscreen/impl/src/test/kotlin/io/element/android/features/lockscreen/impl/device/DeviceUnlockPresenterTest.kt +++ b/features/lockscreen/impl/src/test/kotlin/io/element/android/features/lockscreen/impl/device/DeviceUnlockPresenterTest.kt @@ -145,7 +145,7 @@ class DeviceUnlockPresenterTest { return DeviceUnlockPresenter( pinUnlockHelper = pinUnlockHelper, biometricAuthenticatorManager = biometricAuthenticatorManager, - biometricRequester = callbackHolder, + deviceUnlockCallbackHolder = callbackHolder, pinCodeManager = pinCodeManager, ) } diff --git a/features/lockscreen/test/src/main/kotlin/io/element/android/features/lockscreen/test/FakeDeviceUnlockEntryPointCallback.kt b/features/lockscreen/test/src/main/kotlin/io/element/android/features/lockscreen/test/FakeDeviceUnlockEntryPointCallback.kt index 9c80caede2..3b7394cae0 100644 --- a/features/lockscreen/test/src/main/kotlin/io/element/android/features/lockscreen/test/FakeDeviceUnlockEntryPointCallback.kt +++ b/features/lockscreen/test/src/main/kotlin/io/element/android/features/lockscreen/test/FakeDeviceUnlockEntryPointCallback.kt @@ -15,5 +15,5 @@ class FakeDeviceUnlockEntryPointCallback( private val onUnlockedLambda: () -> Unit = EnsureNeverCalled(), ) : DeviceUnlockEntryPoint.Callback { override fun onCancel() = onCancelLambda() - override fun onUnlocked() = onUnlockedLambda() + override fun onUnlock() = onUnlockedLambda() } From 194fa340a7bda3d583419be629ff23cd0536c32c Mon Sep 17 00:00:00 2001 From: ElementBot Date: Wed, 17 Jun 2026 09:31:36 +0000 Subject: [PATCH 5/5] Update screenshots --- ...eatures.lockscreen.impl.unlock_PinUnlockView_Day_10_en.png | 4 ++-- ...tures.lockscreen.impl.unlock_PinUnlockView_Night_10_en.png | 4 ++-- ...nts.preview.imageeditor_AttachmentImageEditorView_2_en.png | 4 ++-- ...nts.preview.imageeditor_AttachmentImageEditorView_5_en.png | 4 ++-- ...rypto.identity_MessagesViewWithIdentityChange_Day_0_en.png | 4 ++-- ...rypto.identity_MessagesViewWithIdentityChange_Day_1_en.png | 4 ++-- ...rypto.identity_MessagesViewWithIdentityChange_Day_2_en.png | 4 ++-- ...pto.identity_MessagesViewWithIdentityChange_Night_0_en.png | 4 ++-- ...pto.identity_MessagesViewWithIdentityChange_Night_1_en.png | 4 ++-- ...pto.identity_MessagesViewWithIdentityChange_Night_2_en.png | 4 ++-- ...re.resolve_ResolveVerifiedUserSendFailureView_Day_1_en.png | 4 ++-- ...re.resolve_ResolveVerifiedUserSendFailureView_Day_2_en.png | 4 ++-- ....resolve_ResolveVerifiedUserSendFailureView_Night_1_en.png | 4 ++-- ....resolve_ResolveVerifiedUserSendFailureView_Night_2_en.png | 4 ++-- ...meline.components.event_ATimelineItemEventRow_Day_0_en.png | 4 ++-- ...line.components.event_ATimelineItemEventRow_Night_0_en.png | 4 ++-- ....components.event_TimelineImageWithCaptionRow_Day_0_en.png | 4 ++-- ...omponents.event_TimelineImageWithCaptionRow_Night_0_en.png | 4 ++-- ....components.event_TimelineVideoWithCaptionRow_Day_0_en.png | 4 ++-- ...omponents.event_TimelineVideoWithCaptionRow_Night_0_en.png | 4 ++-- ....components_TimelineItemEventRowDisambiguated_Day_0_en.png | 4 ++-- ...omponents_TimelineItemEventRowDisambiguated_Night_0_en.png | 4 ++-- ...ents_TimelineItemEventRowWithReplyInformative_Day_0_en.png | 4 ++-- ...ents_TimelineItemEventRowWithReplyInformative_Day_1_en.png | 4 ++-- ...ts_TimelineItemEventRowWithReplyInformative_Night_0_en.png | 4 ++-- ...ts_TimelineItemEventRowWithReplyInformative_Night_1_en.png | 4 ++-- ...components_TimelineItemEventRowWithReplyOther_Day_0_en.png | 4 ++-- ...components_TimelineItemEventRowWithReplyOther_Day_1_en.png | 4 ++-- ...mponents_TimelineItemEventRowWithReplyOther_Night_0_en.png | 4 ++-- ...mponents_TimelineItemEventRowWithReplyOther_Night_1_en.png | 4 ++-- ...line.components_TimelineItemEventRowWithReply_Day_0_en.png | 4 ++-- ...ine.components_TimelineItemEventRowWithReply_Day_10_en.png | 4 ++-- ...ine.components_TimelineItemEventRowWithReply_Day_11_en.png | 4 ++-- ...line.components_TimelineItemEventRowWithReply_Day_1_en.png | 4 ++-- ...line.components_TimelineItemEventRowWithReply_Day_2_en.png | 4 ++-- ...line.components_TimelineItemEventRowWithReply_Day_3_en.png | 4 ++-- ...line.components_TimelineItemEventRowWithReply_Day_4_en.png | 4 ++-- ...line.components_TimelineItemEventRowWithReply_Day_5_en.png | 4 ++-- ...line.components_TimelineItemEventRowWithReply_Day_6_en.png | 4 ++-- ...line.components_TimelineItemEventRowWithReply_Day_7_en.png | 4 ++-- ...line.components_TimelineItemEventRowWithReply_Day_8_en.png | 4 ++-- ...line.components_TimelineItemEventRowWithReply_Day_9_en.png | 4 ++-- ...ne.components_TimelineItemEventRowWithReply_Night_0_en.png | 4 ++-- ...e.components_TimelineItemEventRowWithReply_Night_10_en.png | 4 ++-- ...e.components_TimelineItemEventRowWithReply_Night_11_en.png | 4 ++-- ...ne.components_TimelineItemEventRowWithReply_Night_1_en.png | 4 ++-- ...ne.components_TimelineItemEventRowWithReply_Night_2_en.png | 4 ++-- ...ne.components_TimelineItemEventRowWithReply_Night_3_en.png | 4 ++-- ...ne.components_TimelineItemEventRowWithReply_Night_4_en.png | 4 ++-- ...ne.components_TimelineItemEventRowWithReply_Night_5_en.png | 4 ++-- ...ne.components_TimelineItemEventRowWithReply_Night_6_en.png | 4 ++-- ...ne.components_TimelineItemEventRowWithReply_Night_7_en.png | 4 ++-- ...ne.components_TimelineItemEventRowWithReply_Night_8_en.png | 4 ++-- ...ne.components_TimelineItemEventRowWithReply_Night_9_en.png | 4 ++-- .../images/features.messages.impl_MessagesView_Day_0_en.png | 4 ++-- .../images/features.messages.impl_MessagesView_Day_10_en.png | 4 ++-- .../images/features.messages.impl_MessagesView_Day_11_en.png | 4 ++-- .../images/features.messages.impl_MessagesView_Day_1_en.png | 4 ++-- .../images/features.messages.impl_MessagesView_Day_2_en.png | 4 ++-- .../images/features.messages.impl_MessagesView_Day_3_en.png | 4 ++-- .../images/features.messages.impl_MessagesView_Day_4_en.png | 4 ++-- .../images/features.messages.impl_MessagesView_Day_5_en.png | 4 ++-- .../images/features.messages.impl_MessagesView_Day_6_en.png | 4 ++-- .../images/features.messages.impl_MessagesView_Day_7_en.png | 4 ++-- .../images/features.messages.impl_MessagesView_Day_8_en.png | 4 ++-- .../images/features.messages.impl_MessagesView_Day_9_en.png | 4 ++-- .../images/features.messages.impl_MessagesView_Night_0_en.png | 4 ++-- .../features.messages.impl_MessagesView_Night_10_en.png | 4 ++-- .../features.messages.impl_MessagesView_Night_11_en.png | 4 ++-- .../images/features.messages.impl_MessagesView_Night_1_en.png | 4 ++-- .../images/features.messages.impl_MessagesView_Night_2_en.png | 4 ++-- .../images/features.messages.impl_MessagesView_Night_3_en.png | 4 ++-- .../images/features.messages.impl_MessagesView_Night_4_en.png | 4 ++-- .../images/features.messages.impl_MessagesView_Night_5_en.png | 4 ++-- .../images/features.messages.impl_MessagesView_Night_6_en.png | 4 ++-- .../images/features.messages.impl_MessagesView_Night_7_en.png | 4 ++-- .../images/features.messages.impl_MessagesView_Night_8_en.png | 4 ++-- .../images/features.messages.impl_MessagesView_Night_9_en.png | 4 ++-- ...references.impl.blockedusers_BlockedUsersView_Day_4_en.png | 4 ++-- ...references.impl.blockedusers_BlockedUsersView_Day_5_en.png | 4 ++-- ...ferences.impl.blockedusers_BlockedUsersView_Night_4_en.png | 4 ++-- ...ferences.impl.blockedusers_BlockedUsersView_Night_5_en.png | 4 ++-- ...embermoderation.impl_RoomMemberModerationView_Day_5_en.png | 4 ++-- ...embermoderation.impl_RoomMemberModerationView_Day_7_en.png | 4 ++-- ...bermoderation.impl_RoomMemberModerationView_Night_5_en.png | 4 ++-- ...bermoderation.impl_RoomMemberModerationView_Night_7_en.png | 4 ++-- ...eme.components_HorizontalFloatingToolbarNoFab_Day_0_en.png | 4 ++-- ...e.components_HorizontalFloatingToolbarNoFab_Night_0_en.png | 4 ++-- ...em.theme.components_HorizontalFloatingToolbar_Day_0_en.png | 4 ++-- ....theme.components_HorizontalFloatingToolbar_Night_0_en.png | 4 ++-- 90 files changed, 180 insertions(+), 180 deletions(-) diff --git a/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.unlock_PinUnlockView_Day_10_en.png b/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.unlock_PinUnlockView_Day_10_en.png index 0a9a82d9ce..adb9484e70 100644 --- a/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.unlock_PinUnlockView_Day_10_en.png +++ b/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.unlock_PinUnlockView_Day_10_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:094814ca5366ba623d12c26e8c1ab1cffc8c41c9970c442ddf53c44899c2ac7f -size 36215 +oid sha256:a60781d3bc38ed6c2ed830464f447d509f88a9767b81dea3acbd29ea21b5c0f6 +size 36212 diff --git a/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.unlock_PinUnlockView_Night_10_en.png b/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.unlock_PinUnlockView_Night_10_en.png index 732af3b016..1831605a28 100644 --- a/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.unlock_PinUnlockView_Night_10_en.png +++ b/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.unlock_PinUnlockView_Night_10_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:821bd77d0c03044f800bcb5f537bbc52c8f32d86d4fcd68fa0f3838e1e35f960 -size 34972 +oid sha256:5d115c0f6d4c705dce1062aa2dbb026980df5efed8d8b2500774e6f75cbe366f +size 34987 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.attachments.preview.imageeditor_AttachmentImageEditorView_2_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.attachments.preview.imageeditor_AttachmentImageEditorView_2_en.png index 8edee63bc1..3192cf2a5e 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.attachments.preview.imageeditor_AttachmentImageEditorView_2_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.attachments.preview.imageeditor_AttachmentImageEditorView_2_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:de82970da241172b94f822f8792e6fc721dcfc7f0f67e3523962e253e9750884 -size 255933 +oid sha256:1885bbe8b0ea497ac20d7bcdd0c6a93ba0533e898378d35e1cafdc8c9924fd56 +size 279984 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.attachments.preview.imageeditor_AttachmentImageEditorView_5_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.attachments.preview.imageeditor_AttachmentImageEditorView_5_en.png index f899ad5d43..ccfdd7d9ed 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.attachments.preview.imageeditor_AttachmentImageEditorView_5_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.attachments.preview.imageeditor_AttachmentImageEditorView_5_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:1ca032575e4ebd75a2ebc5a4cb9f966e48cdfa56f4ff42d6d9309fa3577a1adb -size 310609 +oid sha256:fe6cb72de5079be2ac02ec39f74bac0d20492cd6f5509b71ad9cfc4cc52955d3 +size 326468 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.crypto.identity_MessagesViewWithIdentityChange_Day_0_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.crypto.identity_MessagesViewWithIdentityChange_Day_0_en.png index 5f51b27f5e..693a36b7dd 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.crypto.identity_MessagesViewWithIdentityChange_Day_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.crypto.identity_MessagesViewWithIdentityChange_Day_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:3274314ab9e39c23a6b9d66adf80ac8bb7b364ce60a300f96582374a18bc821f -size 54590 +oid sha256:3dbb8ef39b6a7a0c2f576d8bd101aa97c89da696f23e6d5836846494471c01a1 +size 55799 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.crypto.identity_MessagesViewWithIdentityChange_Day_1_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.crypto.identity_MessagesViewWithIdentityChange_Day_1_en.png index b1850a50a5..e1f6ee6430 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.crypto.identity_MessagesViewWithIdentityChange_Day_1_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.crypto.identity_MessagesViewWithIdentityChange_Day_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f1dd0da147212e13a6c0ad5ad8f85ce55666c444076c238ea27eba5605cfab1f -size 56909 +oid sha256:5e27c7c51fe07cca51b92a601aa9c58deab609bfa5e82f8f6f88eaab6ae59ec3 +size 64307 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.crypto.identity_MessagesViewWithIdentityChange_Day_2_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.crypto.identity_MessagesViewWithIdentityChange_Day_2_en.png index 5289eaca63..4185f46b51 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.crypto.identity_MessagesViewWithIdentityChange_Day_2_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.crypto.identity_MessagesViewWithIdentityChange_Day_2_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:65f9ee083a73669a0d3f9d88141a610ea53f3c39e89d8f706d414b04555b4764 -size 59321 +oid sha256:085963fcb425147d35a9ad947a7a3e4ba4712bd3d2f32e93099ff15cffe83b88 +size 64761 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.crypto.identity_MessagesViewWithIdentityChange_Night_0_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.crypto.identity_MessagesViewWithIdentityChange_Night_0_en.png index 2e70435fa5..d3f7da6320 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.crypto.identity_MessagesViewWithIdentityChange_Night_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.crypto.identity_MessagesViewWithIdentityChange_Night_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:7a3667390d9d88894bbdd5d72b0b714b29c9ff160653e310e97b0da87b6ba8b0 -size 54724 +oid sha256:8a94a4cc176b5d52ef9b21339749324adeef9857b6cdaa2ae973903e2408662a +size 55904 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.crypto.identity_MessagesViewWithIdentityChange_Night_1_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.crypto.identity_MessagesViewWithIdentityChange_Night_1_en.png index bd3b0196d6..0f6de1b844 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.crypto.identity_MessagesViewWithIdentityChange_Night_1_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.crypto.identity_MessagesViewWithIdentityChange_Night_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:6f7f7415abbe51858f938e16ad03c6aab983fb3d5e2a53a028bae3c031446646 -size 67848 +oid sha256:28512b0fda0b71b98eab03cee15c9d3163825b1a3545670cfa277ddd5434c87a +size 58417 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.crypto.identity_MessagesViewWithIdentityChange_Night_2_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.crypto.identity_MessagesViewWithIdentityChange_Night_2_en.png index 6c774d4cec..f4d51ccc61 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.crypto.identity_MessagesViewWithIdentityChange_Night_2_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.crypto.identity_MessagesViewWithIdentityChange_Night_2_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:6ed6a5f1a2055e19a6b8fb0af4738845bd2184f755c323022c52154cdfa07e05 -size 60909 +oid sha256:8a8f5aaaa7ebb0e61b07867590d99a8791c5d04cad1ce0f334d23dce6f26c6e6 +size 67276 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.crypto.sendfailure.resolve_ResolveVerifiedUserSendFailureView_Day_1_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.crypto.sendfailure.resolve_ResolveVerifiedUserSendFailureView_Day_1_en.png index 02d0fc8eeb..bd73e322ab 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.crypto.sendfailure.resolve_ResolveVerifiedUserSendFailureView_Day_1_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.crypto.sendfailure.resolve_ResolveVerifiedUserSendFailureView_Day_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f77d8243c23d3f37dff86dec53671cbde9fafe1314f6e6b445abdfe47d751ad6 -size 56187 +oid sha256:12020ba97720f2374f9ace172693f08be01522e4ca30d3970efa91d802581e81 +size 3657 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.crypto.sendfailure.resolve_ResolveVerifiedUserSendFailureView_Day_2_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.crypto.sendfailure.resolve_ResolveVerifiedUserSendFailureView_Day_2_en.png index 93622cedfe..bd73e322ab 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.crypto.sendfailure.resolve_ResolveVerifiedUserSendFailureView_Day_2_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.crypto.sendfailure.resolve_ResolveVerifiedUserSendFailureView_Day_2_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:87193a7c9eb9d40234970e5f5be02e80f2b3ffe91e2c9ca6afd58b8bccdd5911 -size 55075 +oid sha256:12020ba97720f2374f9ace172693f08be01522e4ca30d3970efa91d802581e81 +size 3657 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.crypto.sendfailure.resolve_ResolveVerifiedUserSendFailureView_Night_1_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.crypto.sendfailure.resolve_ResolveVerifiedUserSendFailureView_Night_1_en.png index bd73e322ab..0cf6c10c4e 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.crypto.sendfailure.resolve_ResolveVerifiedUserSendFailureView_Night_1_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.crypto.sendfailure.resolve_ResolveVerifiedUserSendFailureView_Night_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:12020ba97720f2374f9ace172693f08be01522e4ca30d3970efa91d802581e81 -size 3657 +oid sha256:49f0bb16d3d57b59242e704e3dd4e8885c59721a42129837ff6a4f0d7d02de11 +size 54433 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.crypto.sendfailure.resolve_ResolveVerifiedUserSendFailureView_Night_2_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.crypto.sendfailure.resolve_ResolveVerifiedUserSendFailureView_Night_2_en.png index adec213a8c..bd73e322ab 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.crypto.sendfailure.resolve_ResolveVerifiedUserSendFailureView_Night_2_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.crypto.sendfailure.resolve_ResolveVerifiedUserSendFailureView_Night_2_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:8ebee4aec3dbab6e1bb05fda7c5e423f0e931560743d0f0ccbac6b70fa9ad808 -size 52921 +oid sha256:12020ba97720f2374f9ace172693f08be01522e4ca30d3970efa91d802581e81 +size 3657 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_ATimelineItemEventRow_Day_0_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_ATimelineItemEventRow_Day_0_en.png index 38a81d10b8..08169845d5 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_ATimelineItemEventRow_Day_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_ATimelineItemEventRow_Day_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:4420dfe9f6f95411093eb1c17825a389a31d7a5d5ef146129e5872cdd5d87aff -size 295295 +oid sha256:86eac241e9084cc830ff13d231908da2eb0dff246aa5cac64dddaac68a5d5f13 +size 295298 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_ATimelineItemEventRow_Night_0_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_ATimelineItemEventRow_Night_0_en.png index 06dd93b269..3f12875a5b 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_ATimelineItemEventRow_Night_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_ATimelineItemEventRow_Night_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:578a3707102c7754f607c3a14f94f32cafa30ee570db174386533c484cb4773c -size 295031 +oid sha256:7076c9a44a433cd9eeca536365ae262d39b4ad99a8f854faadec272cb1b82031 +size 294992 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineImageWithCaptionRow_Day_0_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineImageWithCaptionRow_Day_0_en.png index fc985de87d..29e7582971 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineImageWithCaptionRow_Day_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineImageWithCaptionRow_Day_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:3f358da2b9b0521c14e525bcb2bd41c29c96aacaf5f007546e6d362bde2ee3fb -size 612526 +oid sha256:d6441c572f64d99bc119d649e5e6422fe516b9d097f310ccbd99a9ddded9609f +size 612494 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineImageWithCaptionRow_Night_0_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineImageWithCaptionRow_Night_0_en.png index 90bee6c117..176ebfa36b 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineImageWithCaptionRow_Night_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineImageWithCaptionRow_Night_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a709de55bc68cf12064ebdbde92c0a99bef3252958d7966540458d253e8c12c2 -size 611422 +oid sha256:5a867dda82242d2b13bd4bc84a9f1c9b8b7b99c030e19a6cce39b2f828b517f3 +size 611488 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineVideoWithCaptionRow_Day_0_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineVideoWithCaptionRow_Day_0_en.png index 80857358e7..f792a1663a 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineVideoWithCaptionRow_Day_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineVideoWithCaptionRow_Day_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:54e71f45db31e8664c42f8c05feb91ae839589e00cb89d12088c15c85fb9f25f -size 607824 +oid sha256:e3bb005a88e9a4d2bb850478ee8ac2c4f31d32625bd6d2abf455fade461cd399 +size 607806 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineVideoWithCaptionRow_Night_0_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineVideoWithCaptionRow_Night_0_en.png index 8733429e34..18319e718f 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineVideoWithCaptionRow_Night_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineVideoWithCaptionRow_Night_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:8bb505fe6d67669339c9366f8ee5bc75974e223837d95e76e637455a51c18711 -size 606787 +oid sha256:4a2a57f5547f98b9ac2d8bf7195a1e4b49e03834e8866c6cc76660a6a3b16e74 +size 606823 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowDisambiguated_Day_0_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowDisambiguated_Day_0_en.png index 0435f55de6..ab6392a424 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowDisambiguated_Day_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowDisambiguated_Day_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ff839731834d7d0c94fa9a2c412014ddbaeaa053c5af1c8cbd00a3f3a583f364 -size 379511 +oid sha256:94f89a37549a3f198442db467bc7d8539f0b5649d97927bfe731f090d6dfb03d +size 379505 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowDisambiguated_Night_0_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowDisambiguated_Night_0_en.png index 9cbd5c1d95..f0b5506b89 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowDisambiguated_Night_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowDisambiguated_Night_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:d0e170b4bea262de612bf3374d475fcd25470ff91b7554d20809c51857a78cec -size 377963 +oid sha256:04ea6c2947a21d3d4a3d43e9c4750c4f2a49056536a4da3f34c95df8353e9de3 +size 377990 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReplyInformative_Day_0_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReplyInformative_Day_0_en.png index 3ac59caeea..1f0fdabe6d 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReplyInformative_Day_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReplyInformative_Day_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:1a94d5198e27338675c0e15df5874ba3272ee315b8d77291dc7ccc7c754ed1f4 -size 365082 +oid sha256:b8bb5a6de6601da8d7fe59f110a054577e2e25dae4bb449f60c04e7d7a1b9551 +size 365073 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReplyInformative_Day_1_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReplyInformative_Day_1_en.png index 86018764ac..195aa04fe2 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReplyInformative_Day_1_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReplyInformative_Day_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:8344427a0fe87cbf0883ff53a9ee4dcf90976a7011f6618d85961df48b2c53a9 -size 370228 +oid sha256:76e5ae44362792d570cd82f3910c8bd0acde509b8418c5892e0385e7d636f042 +size 370223 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReplyInformative_Night_0_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReplyInformative_Night_0_en.png index 29771235f0..058a3992c3 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReplyInformative_Night_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReplyInformative_Night_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:60b9f2b920cd2a2a414805d1f0f77925232d9ae60bd607fa18d4395cda2dd73d -size 363291 +oid sha256:00fe1e676086766a3eac3e4457eff52c989789fc5d8d0df2624c019ed25ce9af +size 363322 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReplyInformative_Night_1_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReplyInformative_Night_1_en.png index c6d4541184..db4ea8296a 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReplyInformative_Night_1_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReplyInformative_Night_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c00e504593d8eb61b598f05f46ee4d591757975a80c0b4227b240847d2cd4868 -size 368510 +oid sha256:2f0d24b8011564ee7a8b2f8c2e6a24eda668ee42d451d862f884acb7926aa06c +size 368529 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReplyOther_Day_0_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReplyOther_Day_0_en.png index 94428abb56..84d9d4e5c3 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReplyOther_Day_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReplyOther_Day_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:36d7cf2510d546d2b330b1d1b1674ce58df0558c547e443794a1e7b2222add87 -size 347897 +oid sha256:7c609a633ab23eae5729ecb57a17a385bac65e81cbf0180c01e0847f1028039e +size 347890 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReplyOther_Day_1_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReplyOther_Day_1_en.png index 7ddac02717..73b7e674e2 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReplyOther_Day_1_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReplyOther_Day_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a4ac79f3b8fb4e231244bd96b244a4f2526d6ed28d558f9d50734d83bbb74992 -size 363909 +oid sha256:991deacdfb7bc371a2df960a2364ae3b2187e588aa5afe7f39409e367040dd9c +size 363893 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReplyOther_Night_0_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReplyOther_Night_0_en.png index 22ff4965d1..bac23aab98 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReplyOther_Night_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReplyOther_Night_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:787151f8f242a8794a804bf14831f6ca680814d617e85feb3652103e8a0f20cd -size 346565 +oid sha256:e30686c7c037ef102717e0316543faf4d3ed2671c21eca96a667150daab380d6 +size 346614 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReplyOther_Night_1_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReplyOther_Night_1_en.png index 4e17de6908..b6e4650d9d 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReplyOther_Night_1_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReplyOther_Night_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c1e15400fa2c5ee6087316501445c551a3932b65e16de31e68acc5efbd16a559 -size 361603 +oid sha256:2cd357a1fbaa425eca95587bff2f768a45e773f983f75664875653ba1900e534 +size 361625 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Day_0_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Day_0_en.png index 67490ba700..01d4dca84b 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Day_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Day_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f4431e2d9f30123949ea5676ce60f642234adcf9b5a33f2acc3f80ebf6609a66 -size 369730 +oid sha256:ef2bf449671b652cb152b3baab92ab100eab77a54229ab49daeab156f2f484d0 +size 369724 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Day_10_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Day_10_en.png index 1600afff71..f0dfbc3321 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Day_10_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Day_10_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:273351cc9c533b2424859a0de00a8a3786628abc3a88175705c4205dedf7e9aa -size 354737 +oid sha256:f7a6302320bd1e4258e03487539bf46b0b12781dfc8a22b3f9f267017a6146fa +size 354751 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Day_11_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Day_11_en.png index e38cf03ad6..c4943b892c 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Day_11_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Day_11_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:41a0e404dea7f52359b24b3ec3926b1405429b165cfed44c63b3922ea6d3cb46 -size 368114 +oid sha256:4c410e853089cc2c4a2c48a00dd9a8babc8095aed72bb4625057444710559c6c +size 368129 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Day_1_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Day_1_en.png index 68f8148879..b5dac8434c 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Day_1_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Day_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:6ca8cf82aa8ab1bdad56a27584b27789402aeb7ad8fadd038280a376fb75a72c -size 345094 +oid sha256:1a92f8af94682facac66d4aacb6e49f345561c15be2f8b689041b78aeaaae831 +size 345062 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Day_2_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Day_2_en.png index 1b99468924..8aa2cca147 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Day_2_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Day_2_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:3a9509411777f342261cab58b92a022b3c9f8f0f7a9e4d0527120a91976575f0 -size 357733 +oid sha256:02ecb903124273e24151ea2088f6b99144f7dcadba00a582b6210dd23835b5c9 +size 357743 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Day_3_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Day_3_en.png index b5032c29b3..cececc229a 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Day_3_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Day_3_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:dce23463c335d01eb67293cfcede5d85e96ab2ba035cc9a188d42e8e6866bc63 -size 356831 +oid sha256:f0c6dafaa41849af00d5097a85bd88e3a054a0a9e41c0466a08e6ff8dd6102b2 +size 356857 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Day_4_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Day_4_en.png index 14a40a5676..a332744358 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Day_4_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Day_4_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a11044fe90227f1f316a1ade8587e545bb620e11cca76865fc2eb83cdb817fc5 -size 364655 +oid sha256:588967869cbd25ed8b82aff5618175660a8a9e45a5a861b1c7867cf1913f575b +size 364646 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Day_5_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Day_5_en.png index 133fd3903f..d7b969fd5b 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Day_5_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Day_5_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:426d1c844a8c88281c5fa4c61916d93278fdfd38f8cdf2dc54bf1a821f2de3eb -size 397167 +oid sha256:2528df873713755f542f61cd794080929586c1bd5f316c0378ce9e837c21d50b +size 397145 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Day_6_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Day_6_en.png index 63bd9c3f6d..0041a870b9 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Day_6_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Day_6_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a6cd94664f89bdad2a9761ea8b20acb83fed3ed7cb5be41af8fe4852643c0bfc -size 356175 +oid sha256:a2bd77c08be705c66225f16c29fd6826decd92b41922d0f8ffc0d1a63d8c59d2 +size 356193 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Day_7_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Day_7_en.png index f67906a37c..9fcf389708 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Day_7_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Day_7_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ffa68c8398d789444151855496e5df4ffa03218a383db6ea46fd4f979829b823 -size 355831 +oid sha256:9daeee1aaa04247da3c8bb5aaae9947aab1ed2d2057995e53d6ebdb63e5cd356 +size 355848 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Day_8_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Day_8_en.png index d235670def..6e83d6491d 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Day_8_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Day_8_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a00bd766a00b7e7c6615fc53bf469b3ca5056a6c514c096431ae38d99d604306 -size 364845 +oid sha256:34152c742abc486a48234e22101833bc163cf11979890d06aac41e68e3c404d0 +size 364846 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Day_9_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Day_9_en.png index b10f9741b9..0021619c44 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Day_9_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Day_9_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:3ec1b0244dab22414c6719b3309426e13128d0c70fb67dc66cd8a60d42521fd0 -size 355411 +oid sha256:7b23d3a37774283067a8919b8c332b1bb5a79e90dceb7216b484b985491282e5 +size 355389 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Night_0_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Night_0_en.png index 422c324695..77abe20982 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Night_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Night_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a1df8d22766981fc76d6d767dc3f40d98cadc7c51be20417b067b91af604232b -size 367884 +oid sha256:5c3d87862c6d7fc88d0f23cd54c5b9f77028992fdd7c282a195b964dd17e85ac +size 367855 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Night_10_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Night_10_en.png index 448bcec677..1d34761a9b 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Night_10_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Night_10_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:fe0daf9161bc2da194992a2fc9505bf2009c5dbed78cdb35d2eb7ed1380a7df5 -size 353037 +oid sha256:f7d9b5fc0ff5d7828ad6f4dc0c9bd9520b4920553da97ed7b4e030ee844c0208 +size 353054 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Night_11_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Night_11_en.png index 5243218ae3..c081fa16a5 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Night_11_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Night_11_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:9a85db2f5958db867578663533f204b2e803372d470da890fd8056ffed0cf46c -size 366254 +oid sha256:6a92bcf5885322e11a706071969fb674b1f6e60e021af153aaa125baa4a602ae +size 366285 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Night_1_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Night_1_en.png index b6d1f07279..47a9a6b630 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Night_1_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Night_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:4bee12a6bdb18fea5ac6997671bfcb903296da7278cf69b2456330066ca31dfb -size 342870 +oid sha256:54372845e922d047408dd960d048b9b5eae2263d589117d8e7d197741aa34f32 +size 342827 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Night_2_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Night_2_en.png index 5560c21967..ceca184bd7 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Night_2_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Night_2_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:af4a48ee80535f2c0a226c4ffa4344054fb63b7b0a88ea2c030a4eb8dd5e9644 -size 356078 +oid sha256:8e82011a72f36889c53ab61ed2b9947c7fb5f868c9b7010904fc10f4ca587082 +size 356082 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Night_3_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Night_3_en.png index 5cdad1df92..5cc5cfe4fc 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Night_3_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Night_3_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:9e2d8caf5aaae7d3406c703288e491f328552f0acd18e56afd5265b4ceaf1cd1 -size 355272 +oid sha256:6524cc87257cc9d3f135904f4e14594b56df695e71fe576418d2319c472d710b +size 355285 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Night_4_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Night_4_en.png index e9d85990e8..a431a9429a 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Night_4_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Night_4_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:66d4b6ea4a697735bbb0fac936b89cde99c5077973ba828894bf50b5dae233b3 -size 362848 +oid sha256:93c2df04d65f6078ce3f7067fbae8a7317ec42ed0fc013dee962a3953269f3b7 +size 362813 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Night_5_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Night_5_en.png index 0eb106f4a9..b51a89586b 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Night_5_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Night_5_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:217ac95bf476c53d2dc6d3d0143b21312bf38b8ab86c8dfd4f9360582b584f9d -size 395476 +oid sha256:e642229c58169775fe702769a306bbef22698516ae6f7ac75a761213c3f195fa +size 395446 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Night_6_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Night_6_en.png index aa322fc2e4..ae8495618a 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Night_6_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Night_6_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:5fae87094ea13b14e2dc7c16ca96e4f8096ff39e962799468fb4ead4c666620f -size 354381 +oid sha256:08057fdc1e1184720b438ddd2a8753f00791baf2456cc30b45de8e6bdeb57e8e +size 354404 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Night_7_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Night_7_en.png index 9d617f6688..40105c1498 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Night_7_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Night_7_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:dabad9dcd5b8f0d4bb964a0187ad7c94b023b04552dacd29a077daddfd48d550 -size 354052 +oid sha256:5ed24d190f10c079f8cf176404372d40eb25cc78ce595a22febc540315057b86 +size 354075 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Night_8_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Night_8_en.png index 0cfd1dc985..1a8ea3e4e9 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Night_8_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Night_8_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:545c9e8933e420cc3f8fbba0fbd5162c946c65a20721faeb77c568596ca720cd -size 363045 +oid sha256:66aba7b4271a990fac85b0bbc7cbdc371fa1e38a4da5bb4e2f62a80b21cb3a8f +size 363012 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Night_9_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Night_9_en.png index c8306263a0..c9227ebf94 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Night_9_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Night_9_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:756f0cff90ddd61adce2f467c0384d74d430f6d51c091e4980e45bcc9ee6f0fd -size 353705 +oid sha256:e614f4a8657637c584a283d69124236d00fe1251c2b8d739c5688a57a6fd152e +size 353693 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_0_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_0_en.png index 9c5932834e..5f724184b0 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:0dd30568e628750f922a87c2df1fd7751e9d899b9163253c9f2a0c7b03e4a869 -size 56247 +oid sha256:179b30927c3db3963bef12243ae69908ad0b99275906197abd02c110f012213f +size 57267 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_10_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_10_en.png index eb15c6182b..157e74f7f0 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_10_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_10_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a94d9346e04d59f90cfea7ac2ef4d71003fc7e2eef8cf8627257f7cf0aea6457 -size 50445 +oid sha256:dc02a7c7b38753d9509b3cb0fb2eb0e29b6d6c79b8471ba4dc7dd5b81b13d15b +size 50892 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_11_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_11_en.png index a63b53d2c1..35ba5bc8ae 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_11_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_11_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:b7fdd2e68114457368c5d19fe117b2d5a86a02ca475925c9fae0269ff92f5144 -size 66312 +oid sha256:44fd4c046c89628b32d85c7732ef2ed6a50b3e02928bd2409b6bfbb0c6aa3fd9 +size 59064 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_1_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_1_en.png index 875fb85bda..9685e6cbc9 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_1_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f966bd2eade0180013c2c019963ad9f89c04f16cadcc04954bf3a4427c854635 -size 40002 +oid sha256:d1a28720d554bc4698eb52e27e7c6228ac9c14b3703a8c139c3113f8b8fa284e +size 40355 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_2_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_2_en.png index cdf6093729..f00e72d033 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_2_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_2_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:75873117f71dfaed153713aa24ff007ec4a7ec5e779344f20a3e44ac061c6939 -size 54587 +oid sha256:6d1a8746f4dc362d7d1caa424b18c09c3d2e14753e8d6599267d472a61e197df +size 59137 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_3_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_3_en.png index c19f70ee0a..db61d90955 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_3_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_3_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:bc8b338c1a56b1b663171e16815b3c8122dab3ec948f3db4b9e790833b3f89a6 -size 55378 +oid sha256:8093bd975c14cf5da50203a039e0c292dadc68183fdee5076adc217058b555f8 +size 57236 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_4_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_4_en.png index 3cd7dd274c..c891dbf206 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_4_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_4_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:b2a89e79995050e8b24b459172a7c123cc08c64097d5d735cef8c47f913a3bf4 -size 54080 +oid sha256:507ab916afdc3f4d1429ef70c6e19dac8a80713636b064657430c19252494098 +size 55558 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_5_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_5_en.png index a7296ed824..ae8c29241d 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_5_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_5_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:24510c12067dae5a164a91a67ec60723c40e3c7015757ff82098e8c37e60b3cf -size 60437 +oid sha256:616deb9421b09e2fa25d6953263fd70a9f687fdfbdf9503bbc35e7a0660ec440 +size 58459 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_6_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_6_en.png index c9eb1ec497..4c3689dedd 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_6_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_6_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:80ba9d0ce1813b31a4ef8f3fc89381cbaa1468a46744536c815da97adf8acf80 -size 50240 +oid sha256:b14de263a1f2356b3e84b2a633b0ed837bd160d04c1ec8eeb8c55176856e59ce +size 48755 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_7_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_7_en.png index 767be1a188..42c31db4f8 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_7_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_7_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:970396f75edf55841822286155e73e5f4981c347c7c2ff34e69ff9e4bf0aac9f -size 59343 +oid sha256:50ef8852ecea57a766f5b074ab4703d753de424c403c9fa778614d7b863e0e98 +size 60393 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_8_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_8_en.png index e4a14ae551..f654a4403c 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_8_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_8_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:39430896a687266d7a60890fdac5dbca6d36c87fe30d07619c9c50e23c3f77be -size 56972 +oid sha256:e11d2920b56154389cffd1d56b986de2a570bff474d4f4861c710239d27c44e0 +size 58442 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_9_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_9_en.png index c8bbc80737..b8d8a2cf4c 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_9_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_9_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:1c8055e4bc61233e75896ecb2139140ca40cdbd55eedb6108cf3a916f1e32ea4 -size 61377 +oid sha256:1cb21bd5e7d348d1d07ca4b6a360f26a4735cc9760fdd7e3b4b1bcde32da6f08 +size 62655 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_0_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_0_en.png index b3c490ad32..1f5ddc83fd 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:30e13e1b91d681088ceba71f21f668a5d8b8f376cb10832f0289b1b14c1103e4 -size 55569 +oid sha256:3f3b1665b2038873c849362b16a04713ef89d17a9b3e44dc828754110e192e33 +size 56407 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_10_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_10_en.png index 1106928ade..74826e1e9e 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_10_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_10_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:b0d66d79ec03a19a05f765230640fb8b2b1e386f08f55231f7231582daddb131 -size 51195 +oid sha256:805245ffe7f4e99a0f5927b89bcaa6ab8eaf7cc603d352b14b8109e76eecbdf2 +size 51742 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_11_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_11_en.png index d2b5044048..c88cc50675 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_11_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_11_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:52441a5e250b027ddd40ee32754a63c6206762084f47ecfa7e057e2ac77e78a8 -size 69120 +oid sha256:674d24421c80412d52bc3fe4559d0518a37ae2cee8e8a1408e2085a809816248 +size 59731 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_1_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_1_en.png index 5b842a7e61..d7eb027558 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_1_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:529c7a98771dbdef837f3aea963871aca1ec086de9d9f8b86c5f6758d21468a8 -size 38724 +oid sha256:5789d10db607ad77acd5d9391b970b2e0a0f962c205b3bf40db5c78d0dcea48b +size 38821 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_2_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_2_en.png index 4abc38bbad..eb13905340 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_2_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_2_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f9aa8ad754bcf44c3c5f06e1fd89374f72b9be42859a7931de9f10c0b404967b -size 54037 +oid sha256:4f988610da5b4feaa47eb9e5224f9b0d2d47633d9aa8fd45117fff75f5040680 +size 58673 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_3_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_3_en.png index 250279e2f8..063684db1c 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_3_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_3_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:4f9e76f5d50ce3e0fa259f0692184564a8a988c2e0ba047595c34a99c04fb8e2 -size 50510 +oid sha256:7a23be24d65190802b26b4e586c80a5cadc6451ea7d351e19c777947daa688d4 +size 52352 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_4_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_4_en.png index 6b4cb7360c..b2e5208390 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_4_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_4_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:abf3863e6d5ddc747dfea06a006983345937cd85d0e89b60bc625f4ad16b2691 -size 52906 +oid sha256:72460dfd88da9b6ebf586e98a819dcc6d377da3515df35a0a2b7247fa376f7d8 +size 54987 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_5_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_5_en.png index 5fdad34a63..4f903b55b7 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_5_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_5_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:7658b9a628d46392ba93d5831b4d3101f9ddee17e6f964d096506dabeb460676 -size 55134 +oid sha256:2e99ae9731e9c75fd025db8f24649d6219941ff3aaf0bd4a67bc2c8d1f204cb3 +size 53516 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_6_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_6_en.png index 689eba066a..ffae0459fc 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_6_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_6_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f961d41153cc90023abbbc972902d629ce903f3a3bfe8546923a76997fa1c20e -size 45362 +oid sha256:539799354ad5b383c308779b1278e879db4542d9d1c870c13a54a0ae927767fb +size 44098 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_7_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_7_en.png index 5e28ba8938..cc87882600 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_7_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_7_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f5c6ac53f33fb4338a11358a487c2042304691ecf50f61ca0e7cbb75bc227efc -size 58294 +oid sha256:8538de17063819eb6aa0a614a8f108b122b0597769f253b538775d2b90473276 +size 59186 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_8_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_8_en.png index 1ad21c4d64..46c4466773 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_8_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_8_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:289819914863942caad5202131efddd9b880b4af64a36d4b45fb547b5b1ec47f -size 55916 +oid sha256:c7ba8b81a3df9e797ca317a450a7f1bf0a8391aa6b919136827b5ab8e324cdb7 +size 57057 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_9_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_9_en.png index d8ad46e844..6e371532de 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_9_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_9_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:0b511680e8505d812f0a1f7ac47791e36f20b6387f0655fc0f9198939a4b8845 -size 62903 +oid sha256:86273e812cbc6245527c3d1f138111ece99375aec0d68728882b656b01687bff +size 64392 diff --git a/tests/uitests/src/test/snapshots/images/features.preferences.impl.blockedusers_BlockedUsersView_Day_4_en.png b/tests/uitests/src/test/snapshots/images/features.preferences.impl.blockedusers_BlockedUsersView_Day_4_en.png index 074820e157..7cca911c45 100644 --- a/tests/uitests/src/test/snapshots/images/features.preferences.impl.blockedusers_BlockedUsersView_Day_4_en.png +++ b/tests/uitests/src/test/snapshots/images/features.preferences.impl.blockedusers_BlockedUsersView_Day_4_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:7caacb336793b8ae4b83e9a10a82325e25e8b3c036f881898ed28688250eb6e0 -size 55744 +oid sha256:26e14b77fa3c3aeaea58782309e6de8b9047e07945009322990ebf5f4c283309 +size 52770 diff --git a/tests/uitests/src/test/snapshots/images/features.preferences.impl.blockedusers_BlockedUsersView_Day_5_en.png b/tests/uitests/src/test/snapshots/images/features.preferences.impl.blockedusers_BlockedUsersView_Day_5_en.png index 2af459c158..7cca911c45 100644 --- a/tests/uitests/src/test/snapshots/images/features.preferences.impl.blockedusers_BlockedUsersView_Day_5_en.png +++ b/tests/uitests/src/test/snapshots/images/features.preferences.impl.blockedusers_BlockedUsersView_Day_5_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:28a95d4b7ebca92c4e0467f3ecd9acdaf7f6257604d190f5d088a9a25e87d637 -size 55305 +oid sha256:26e14b77fa3c3aeaea58782309e6de8b9047e07945009322990ebf5f4c283309 +size 52770 diff --git a/tests/uitests/src/test/snapshots/images/features.preferences.impl.blockedusers_BlockedUsersView_Night_4_en.png b/tests/uitests/src/test/snapshots/images/features.preferences.impl.blockedusers_BlockedUsersView_Night_4_en.png index 616c06bf46..a68f886f73 100644 --- a/tests/uitests/src/test/snapshots/images/features.preferences.impl.blockedusers_BlockedUsersView_Night_4_en.png +++ b/tests/uitests/src/test/snapshots/images/features.preferences.impl.blockedusers_BlockedUsersView_Night_4_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:0ce2519906f1aaf34700ca9ba4bdeaa72030f1f5aff3f7e24352a1435ac67d98 -size 53966 +oid sha256:e5a2e306087a967849f61872b56a83f194d1a76df5723f0bbae6e6e2f4a98c63 +size 55725 diff --git a/tests/uitests/src/test/snapshots/images/features.preferences.impl.blockedusers_BlockedUsersView_Night_5_en.png b/tests/uitests/src/test/snapshots/images/features.preferences.impl.blockedusers_BlockedUsersView_Night_5_en.png index 36d19c6b72..616c06bf46 100644 --- a/tests/uitests/src/test/snapshots/images/features.preferences.impl.blockedusers_BlockedUsersView_Night_5_en.png +++ b/tests/uitests/src/test/snapshots/images/features.preferences.impl.blockedusers_BlockedUsersView_Night_5_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:7dfa2767c55a81d3f121b8fa55443b7b05f9369e91639b80e0be349863799ad7 -size 55438 +oid sha256:0ce2519906f1aaf34700ca9ba4bdeaa72030f1f5aff3f7e24352a1435ac67d98 +size 53966 diff --git a/tests/uitests/src/test/snapshots/images/features.roommembermoderation.impl_RoomMemberModerationView_Day_5_en.png b/tests/uitests/src/test/snapshots/images/features.roommembermoderation.impl_RoomMemberModerationView_Day_5_en.png index 73b8b8e50c..5c597300e4 100644 --- a/tests/uitests/src/test/snapshots/images/features.roommembermoderation.impl_RoomMemberModerationView_Day_5_en.png +++ b/tests/uitests/src/test/snapshots/images/features.roommembermoderation.impl_RoomMemberModerationView_Day_5_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:e8a3ad99763929d2783147814e44fa9ec7e7efb7b99949e3580f23c38fb5d971 -size 9398 +oid sha256:21aee17ee9a292bb2f0d3d2ec2db565ebb8d5df753454a5a002f033ed5ed39c5 +size 3853 diff --git a/tests/uitests/src/test/snapshots/images/features.roommembermoderation.impl_RoomMemberModerationView_Day_7_en.png b/tests/uitests/src/test/snapshots/images/features.roommembermoderation.impl_RoomMemberModerationView_Day_7_en.png index 5c597300e4..f8a1f24b34 100644 --- a/tests/uitests/src/test/snapshots/images/features.roommembermoderation.impl_RoomMemberModerationView_Day_7_en.png +++ b/tests/uitests/src/test/snapshots/images/features.roommembermoderation.impl_RoomMemberModerationView_Day_7_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:21aee17ee9a292bb2f0d3d2ec2db565ebb8d5df753454a5a002f033ed5ed39c5 -size 3853 +oid sha256:1342b6427f5b2e3075ae3ccee60bf1d3b11afaccf3e152643d6ef2d65c21b54e +size 9108 diff --git a/tests/uitests/src/test/snapshots/images/features.roommembermoderation.impl_RoomMemberModerationView_Night_5_en.png b/tests/uitests/src/test/snapshots/images/features.roommembermoderation.impl_RoomMemberModerationView_Night_5_en.png index d47bf90664..4ae7279fe7 100644 --- a/tests/uitests/src/test/snapshots/images/features.roommembermoderation.impl_RoomMemberModerationView_Night_5_en.png +++ b/tests/uitests/src/test/snapshots/images/features.roommembermoderation.impl_RoomMemberModerationView_Night_5_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:520cae2544153ba45f8fe4b021286c2d22da06aa1b60be7f1b13879723ff994c -size 3664 +oid sha256:410a8596d4c70b9a3856d959d6d71ade8e831e8581ff410c9900957a93b3eb50 +size 8114 diff --git a/tests/uitests/src/test/snapshots/images/features.roommembermoderation.impl_RoomMemberModerationView_Night_7_en.png b/tests/uitests/src/test/snapshots/images/features.roommembermoderation.impl_RoomMemberModerationView_Night_7_en.png index a87d89c701..d47bf90664 100644 --- a/tests/uitests/src/test/snapshots/images/features.roommembermoderation.impl_RoomMemberModerationView_Night_7_en.png +++ b/tests/uitests/src/test/snapshots/images/features.roommembermoderation.impl_RoomMemberModerationView_Night_7_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:0f3a0cb5d9bae6725a1c527f3d9575aabf85d3edf63a28d9faa23f4f0b65e2d0 -size 7624 +oid sha256:520cae2544153ba45f8fe4b021286c2d22da06aa1b60be7f1b13879723ff994c +size 3664 diff --git a/tests/uitests/src/test/snapshots/images/libraries.designsystem.theme.components_HorizontalFloatingToolbarNoFab_Day_0_en.png b/tests/uitests/src/test/snapshots/images/libraries.designsystem.theme.components_HorizontalFloatingToolbarNoFab_Day_0_en.png index ee5c582240..58546b8522 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.designsystem.theme.components_HorizontalFloatingToolbarNoFab_Day_0_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.designsystem.theme.components_HorizontalFloatingToolbarNoFab_Day_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:75de341f705bb22955f9399180519b65ad59c2e1917317d56e50ea4db78f35bc -size 12102 +oid sha256:30357bf18792db5ab20085010251170a724ffe8c00313facd04ee704e806af64 +size 10982 diff --git a/tests/uitests/src/test/snapshots/images/libraries.designsystem.theme.components_HorizontalFloatingToolbarNoFab_Night_0_en.png b/tests/uitests/src/test/snapshots/images/libraries.designsystem.theme.components_HorizontalFloatingToolbarNoFab_Night_0_en.png index fedead0fa8..52fd9b9693 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.designsystem.theme.components_HorizontalFloatingToolbarNoFab_Night_0_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.designsystem.theme.components_HorizontalFloatingToolbarNoFab_Night_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:4811667dec0f32accc5e2c8a5dd5c0b34017fcff8d1e0376ee7a4708426bca0f -size 9838 +oid sha256:58b9491aaa5554b89d86c62a5c9c44975367538c6baa5562f8dc5768f76d8264 +size 8705 diff --git a/tests/uitests/src/test/snapshots/images/libraries.designsystem.theme.components_HorizontalFloatingToolbar_Day_0_en.png b/tests/uitests/src/test/snapshots/images/libraries.designsystem.theme.components_HorizontalFloatingToolbar_Day_0_en.png index 38ad0e4b56..83302d6ba4 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.designsystem.theme.components_HorizontalFloatingToolbar_Day_0_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.designsystem.theme.components_HorizontalFloatingToolbar_Day_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:326d59cf768b2dbd96eb7964d54c8eda509a5cd57c6e62087625e3314da0bb4d -size 13658 +oid sha256:16dee1dfe746cd40dac9fe8f0af3ecb42cd14bab5cc490917b589beed065ed1b +size 14686 diff --git a/tests/uitests/src/test/snapshots/images/libraries.designsystem.theme.components_HorizontalFloatingToolbar_Night_0_en.png b/tests/uitests/src/test/snapshots/images/libraries.designsystem.theme.components_HorizontalFloatingToolbar_Night_0_en.png index 4da2a98aca..687e0d436a 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.designsystem.theme.components_HorizontalFloatingToolbar_Night_0_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.designsystem.theme.components_HorizontalFloatingToolbar_Night_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ef0dc4d53daeb986f378b6e4d85928b4b6729336c89cf21e642c88c53688a3ab -size 10292 +oid sha256:d57df7110371c9224e232b707d6a1b10ce14afcb56c803a78220792f2a0d4cf2 +size 11354