From 784415f6986ac3c0823aee8658c93e8d05d45464 Mon Sep 17 00:00:00 2001 From: ganfra Date: Thu, 19 Oct 2023 21:58:12 +0200 Subject: [PATCH 01/22] Pin auth : simple first iteration on ui --- .../impl/auth/PinAuthenticationView.kt | 115 +++++++++-- .../lockscreen/impl/auth/numpad/PinKeypad.kt | 182 ++++++++++++++++++ .../impl/auth/numpad/PinKeypadModel.kt | 26 +++ 3 files changed, 304 insertions(+), 19 deletions(-) create mode 100644 features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/auth/numpad/PinKeypad.kt create mode 100644 features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/auth/numpad/PinKeypadModel.kt diff --git a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/auth/PinAuthenticationView.kt b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/auth/PinAuthenticationView.kt index 2b62e46800..740d85adec 100644 --- a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/auth/PinAuthenticationView.kt +++ b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/auth/PinAuthenticationView.kt @@ -16,22 +16,40 @@ package io.element.android.features.lockscreen.impl.auth -import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.background +import androidx.compose.foundation.gestures.Orientation +import androidx.compose.foundation.gestures.scrollable +import androidx.compose.foundation.layout.Arrangement.spacedBy +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.BoxWithConstraints +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.heightIn import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.systemBarsPadding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.shape.CircleShape import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Lock +import androidx.compose.material3.MaterialTheme import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.tooling.preview.PreviewParameter import androidx.compose.ui.unit.dp -import io.element.android.libraries.designsystem.atomic.molecules.IconTitleSubtitleMolecule +import io.element.android.features.lockscreen.impl.auth.numpad.PinKeypad import io.element.android.libraries.designsystem.atomic.pages.HeaderFooterPage import io.element.android.libraries.designsystem.preview.ElementPreview import io.element.android.libraries.designsystem.preview.PreviewsDayNight import io.element.android.libraries.designsystem.theme.components.Button +import io.element.android.libraries.designsystem.theme.components.Icon import io.element.android.libraries.designsystem.theme.components.Surface +import io.element.android.libraries.designsystem.theme.components.Text +import io.element.android.libraries.theme.ElementTheme @Composable fun PinAuthenticationView( @@ -40,27 +58,23 @@ fun PinAuthenticationView( ) { Surface(modifier) { HeaderFooterPage( - modifier = Modifier - .systemBarsPadding() - .fillMaxSize(), header = { PinAuthenticationHeader(modifier = Modifier.padding(top = 60.dp, bottom = 12.dp)) }, - footer = { PinAuthenticationFooter(state) }, + content = { + Box( + modifier = Modifier + .padding(top = 40.dp) + .fillMaxWidth(), + contentAlignment = Alignment.Center, + ) { + PinKeypad( + onClick = {} + ) + } + } ) } } -@Composable -private fun PinAuthenticationHeader( - modifier: Modifier = Modifier, -) { - IconTitleSubtitleMolecule( - modifier = modifier, - title = "Element X is locked", - subTitle = null, - iconImageVector = Icons.Default.Lock, - ) -} - @Composable private fun PinAuthenticationFooter(state: PinAuthenticationState) { Button( @@ -72,6 +86,69 @@ private fun PinAuthenticationFooter(state: PinAuthenticationState) { ) } +@Composable +private fun PinDotsRow( + modifier: Modifier = Modifier, +) { + Row(modifier, horizontalArrangement = spacedBy(8.dp), verticalAlignment = Alignment.CenterVertically) { + PinDot(isFilled = true) + PinDot(isFilled = true) + PinDot(isFilled = false) + PinDot(isFilled = false) + } +} + +@Composable +private fun PinDot( + isFilled: Boolean, + modifier: Modifier = Modifier, +) { + val backgroundColor = if (isFilled) { + ElementTheme.colors.iconPrimary + } else { + ElementTheme.colors.bgSubtlePrimary + } + Box( + modifier = modifier + .size(14.dp) + .background(backgroundColor, CircleShape) + ) +} + +@Composable +private fun PinAuthenticationHeader( + modifier: Modifier = Modifier, +) { + Column(modifier, horizontalAlignment = Alignment.CenterHorizontally) { + Icon( + modifier = Modifier + .size(32.dp), + tint = ElementTheme.colors.iconPrimary, + imageVector = Icons.Filled.Lock, + contentDescription = "", + ) + Spacer(modifier = Modifier.height(16.dp)) + Text( + text = "Enter your PIN", + modifier = Modifier + .fillMaxWidth(), + textAlign = TextAlign.Center, + style = ElementTheme.typography.fontHeadingMdBold, + color = MaterialTheme.colorScheme.primary, + ) + Spacer(Modifier.height(8.dp)) + Text( + text = "You have 3 attempts to unlock", + modifier = Modifier.fillMaxWidth(), + textAlign = TextAlign.Center, + style = ElementTheme.typography.fontBodyMdRegular, + color = MaterialTheme.colorScheme.secondary, + ) + Spacer(Modifier.height(24.dp)) + PinDotsRow() + } +} + @Composable @PreviewsDayNight internal fun PinAuthenticationViewPreview(@PreviewParameter(PinAuthenticationStateProvider::class) state: PinAuthenticationState) { diff --git a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/auth/numpad/PinKeypad.kt b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/auth/numpad/PinKeypad.kt new file mode 100644 index 0000000000..43abc24002 --- /dev/null +++ b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/auth/numpad/PinKeypad.kt @@ -0,0 +1,182 @@ +/* + * Copyright (c) 2023 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.element.android.features.lockscreen.impl.auth.numpad + +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.PaddingValues +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.shape.CircleShape +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.automirrored.filled.Backspace +import androidx.compose.material3.Button +import androidx.compose.material3.ButtonDefaults +import androidx.compose.material3.IconButton +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.unit.Dp +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import io.element.android.libraries.designsystem.preview.ElementPreview +import io.element.android.libraries.designsystem.preview.PreviewsDayNight +import io.element.android.libraries.designsystem.text.toSp +import io.element.android.libraries.designsystem.theme.components.Icon +import io.element.android.libraries.theme.ElementTheme + +@Composable +fun PinKeypad( + onClick: (PinKeypadModel) -> Unit, + modifier: Modifier = Modifier, + verticalArrangement: Arrangement.Vertical = Arrangement.Top, + verticalAlignment: Alignment.Vertical = Alignment.Top, + horizontalArrangement: Arrangement.Horizontal = Arrangement.Start, + horizontalAlignment: Alignment.Horizontal = Alignment.Start, +) { + Column( + modifier = modifier, + verticalArrangement = verticalArrangement, + horizontalAlignment = horizontalAlignment, + ) { + PinKeypadRow( + verticalAlignment = verticalAlignment, + horizontalArrangement = horizontalArrangement, + models = listOf(PinKeypadModel.Number("1"), PinKeypadModel.Number("2"), PinKeypadModel.Number("3")), + onClick = onClick, + ) + PinKeypadRow( + verticalAlignment = verticalAlignment, + horizontalArrangement = horizontalArrangement, + models = listOf(PinKeypadModel.Number("4"), PinKeypadModel.Number("5"), PinKeypadModel.Number("6")), + onClick = onClick, + ) + PinKeypadRow( + verticalAlignment = verticalAlignment, + horizontalArrangement = horizontalArrangement, + models = listOf(PinKeypadModel.Number("7"), PinKeypadModel.Number("8"), PinKeypadModel.Number("9")), + onClick = onClick, + ) + PinKeypadRow( + verticalAlignment = verticalAlignment, + horizontalArrangement = horizontalArrangement, + models = listOf(PinKeypadModel.Empty, PinKeypadModel.Number("0"), PinKeypadModel.Back), + onClick = onClick, + ) + } +} + +@Composable +private fun PinKeypadRow( + models: List, + onClick: (PinKeypadModel) -> Unit, + modifier: Modifier = Modifier, + horizontalArrangement: Arrangement.Horizontal = Arrangement.Start, + verticalAlignment: Alignment.Vertical = Alignment.Top, +) { + Row( + horizontalArrangement = horizontalArrangement, + verticalAlignment = verticalAlignment, + modifier = modifier, + ) { + val commonModifier = Modifier.size(80.dp) + for (model in models) { + when (model) { + is PinKeypadModel.Empty -> { + Spacer(modifier = commonModifier) + } + is PinKeypadModel.Back -> { + PinKeypadBackButton( + modifier = commonModifier, + onClick = { onClick(model) }, + ) + } + is PinKeypadModel.Number -> { + PinKeyBadDigitButton( + size = 80.dp, + modifier = commonModifier, + digit = model.number, + onClick = { onClick(model) }, + ) + } + } + } + } +} + +@Composable +private fun PinKeyBadDigitButton( + digit: String, + size: Dp, + onClick: (String) -> Unit, + modifier: Modifier = Modifier, +) { + Button( + colors = ButtonDefaults.buttonColors( + containerColor = ElementTheme.colors.bgSubtlePrimary, + contentColor = Color.Transparent, + ), + shape = CircleShape, + contentPadding = PaddingValues(0.dp), + modifier = modifier + .clip(CircleShape), + onClick = { onClick(digit) } + ) { + val fontSize = 80.dp.toSp() / 2 + val originalFont = ElementTheme.typography.fontHeadingXlBold + val ratio = fontSize.value / originalFont.fontSize.value + val lineHeight = originalFont.lineHeight * ratio + Text( + text = digit, + color = ElementTheme.colors.textPrimary, + style = originalFont.copy(fontSize = fontSize, lineHeight = lineHeight, letterSpacing = 0.sp), + ) + } +} + +@Composable +private fun PinKeypadBackButton( + onClick: () -> Unit, + modifier: Modifier = Modifier, +) { + IconButton( + modifier = modifier + .clip(CircleShape) + .background(color = Color.Transparent, shape = CircleShape), + onClick = onClick, + ) { + Icon( + imageVector = Icons.AutoMirrored.Filled.Backspace, + contentDescription = null, + ) + } +} + +@Composable +@PreviewsDayNight +fun PinKeypad() { + ElementPreview { + PinKeypad(onClick = {}) + } +} + + diff --git a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/auth/numpad/PinKeypadModel.kt b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/auth/numpad/PinKeypadModel.kt new file mode 100644 index 0000000000..108486e400 --- /dev/null +++ b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/auth/numpad/PinKeypadModel.kt @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2023 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.element.android.features.lockscreen.impl.auth.numpad + +import androidx.compose.runtime.Immutable + +@Immutable +sealed interface PinKeypadModel { + data object Empty : PinKeypadModel + data object Back : PinKeypadModel + data class Number(val number: String) : PinKeypadModel +} From 5b611ed01782b918dad9cc2f9aefc4b8362d0a57 Mon Sep 17 00:00:00 2001 From: ganfra Date: Fri, 20 Oct 2023 15:15:19 +0200 Subject: [PATCH 02/22] Lockscreen: renaming --- build.gradle.kts | 3 +- .../lockscreen/impl/LockScreenFlowNode.kt | 18 +++---- .../impl/pin/DefaultPinCodeManager.kt | 2 +- .../lockscreen/impl/pin/PinCodeManager.kt | 2 +- .../SetupPinEvents.kt} | 8 ++-- .../SetupPinNode.kt} | 8 ++-- .../SetupPinPresenter.kt} | 40 ++++++++-------- .../SetupPinState.kt} | 12 ++--- .../SetupPinStateProvider.kt} | 32 ++++++------- .../SetupPinView.kt} | 48 +++++++++---------- .../impl/{create => setup}/model/PinDigit.kt | 2 +- .../impl/{create => setup}/model/PinEntry.kt | 2 +- .../validation/CreatePinFailure.kt | 8 ++-- .../validation/PinValidator.kt | 8 ++-- .../PinUnlockEvents.kt} | 6 +-- .../PinUnlockNode.kt} | 8 ++-- .../PinUnlockPresenter.kt} | 14 +++--- .../PinUnlockState.kt} | 6 +-- .../PinUnlockStateProvider.kt} | 10 ++-- .../PinUnlockView.kt} | 25 ++++------ .../impl/{auth => unlock}/numpad/PinKeypad.kt | 2 +- .../{auth => unlock}/numpad/PinKeypadModel.kt | 2 +- .../CreatePinPresenterTest.kt | 10 ++-- 23 files changed, 135 insertions(+), 141 deletions(-) rename features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/{create/CreatePinEvents.kt => setup/SetupPinEvents.kt} (73%) rename features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/{create/CreatePinNode.kt => setup/SetupPinNode.kt} (88%) rename features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/{create/CreatePinPresenter.kt => setup/SetupPinPresenter.kt} (73%) rename features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/{create/CreatePinState.kt => setup/SetupPinState.kt} (72%) rename features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/{create/CreatePinStateProvider.kt => setup/SetupPinStateProvider.kt} (66%) rename features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/{create/CreatePinView.kt => setup/SetupPinView.kt} (80%) rename features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/{create => setup}/model/PinDigit.kt (92%) rename features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/{create => setup}/model/PinEntry.kt (96%) rename features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/{create => setup}/validation/CreatePinFailure.kt (74%) rename features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/{create => setup}/validation/PinValidator.kt (80%) rename features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/{auth/PinAuthenticationEvents.kt => unlock/PinUnlockEvents.kt} (80%) rename features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/{auth/PinAuthenticationNode.kt => unlock/PinUnlockNode.kt} (86%) rename features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/{auth/PinAuthenticationPresenter.kt => unlock/PinUnlockPresenter.kt} (73%) rename features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/{auth/PinAuthenticationState.kt => unlock/PinUnlockState.kt} (80%) rename features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/{auth/PinAuthenticationStateProvider.kt => unlock/PinUnlockStateProvider.kt} (70%) rename features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/{auth/PinAuthenticationView.kt => unlock/PinUnlockView.kt} (83%) rename features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/{auth => unlock}/numpad/PinKeypad.kt (98%) rename features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/{auth => unlock}/numpad/PinKeypadModel.kt (92%) rename features/lockscreen/impl/src/test/kotlin/io/element/android/features/lockscreen/impl/{create => setup}/CreatePinPresenterTest.kt (92%) diff --git a/build.gradle.kts b/build.gradle.kts index e14ad71981..391313fe2d 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -251,8 +251,7 @@ koverMerged { // Some options can't be tested at the moment excludes += "io.element.android.features.preferences.impl.developer.DeveloperSettingsPresenter$*" // Temporary until we have actually something to test. - excludes += "io.element.android.features.lockscreen.impl.auth.PinAuthenticationPresenter" - excludes += "io.element.android.features.lockscreen.impl.auth.PinAuthenticationPresenter$*" + excludes += "io.element.android.features.lockscreen.impl.unlock.PinUnlockPresenter$*" } bound { minValue = 85 diff --git a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/LockScreenFlowNode.kt b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/LockScreenFlowNode.kt index d2989d53cc..fa3b88e18a 100644 --- a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/LockScreenFlowNode.kt +++ b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/LockScreenFlowNode.kt @@ -27,8 +27,8 @@ import com.bumble.appyx.navmodel.backstack.BackStack import dagger.assisted.Assisted import dagger.assisted.AssistedInject import io.element.android.anvilannotations.ContributesNode -import io.element.android.features.lockscreen.impl.auth.PinAuthenticationNode -import io.element.android.features.lockscreen.impl.create.CreatePinNode +import io.element.android.features.lockscreen.impl.setup.SetupPinNode +import io.element.android.features.lockscreen.impl.unlock.PinUnlockNode import io.element.android.libraries.architecture.BackstackNode import io.element.android.libraries.architecture.animation.rememberDefaultTransitionHandler import io.element.android.libraries.architecture.createNode @@ -41,7 +41,7 @@ class LockScreenFlowNode @AssistedInject constructor( @Assisted plugins: List, ) : BackstackNode( backstack = BackStack( - initialElement = NavTarget.Auth, + initialElement = NavTarget.Unlock, savedStateMap = buildContext.savedStateMap, ), buildContext = buildContext, @@ -50,19 +50,19 @@ class LockScreenFlowNode @AssistedInject constructor( sealed interface NavTarget : Parcelable { @Parcelize - data object Auth : NavTarget + data object Unlock : NavTarget @Parcelize - data object Create : NavTarget + data object Setup : NavTarget } override fun resolve(navTarget: NavTarget, buildContext: BuildContext): Node { return when (navTarget) { - NavTarget.Auth -> { - createNode(buildContext) + NavTarget.Unlock -> { + createNode(buildContext) } - NavTarget.Create -> { - createNode(buildContext) + NavTarget.Setup -> { + createNode(buildContext) } } } diff --git a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/pin/DefaultPinCodeManager.kt b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/pin/DefaultPinCodeManager.kt index e7529e9280..1f7439301c 100644 --- a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/pin/DefaultPinCodeManager.kt +++ b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/pin/DefaultPinCodeManager.kt @@ -37,7 +37,7 @@ class DefaultPinCodeManager @Inject constructor( return pinCodeStore.hasPinCode() } - override suspend fun createPinCode(pinCode: String) { + override suspend fun SetupPinCode(pinCode: String) { val secretKey = secretKeyProvider.getOrCreateKey(SECRET_KEY_ALIAS) val encryptedPinCode = encryptionDecryptionService.encrypt(secretKey, pinCode.toByteArray()).toBase64() pinCodeStore.saveEncryptedPinCode(encryptedPinCode) diff --git a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/pin/PinCodeManager.kt b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/pin/PinCodeManager.kt index 5f84f5296d..49b6141665 100644 --- a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/pin/PinCodeManager.kt +++ b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/pin/PinCodeManager.kt @@ -30,7 +30,7 @@ interface PinCodeManager { * Creates a new encrypted pin code. * @param pinCode the clear pin code to create */ - suspend fun createPinCode(pinCode: String) + suspend fun SetupPinCode(pinCode: String) /** * @return true if the pin code is correct. diff --git a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/create/CreatePinEvents.kt b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/setup/SetupPinEvents.kt similarity index 73% rename from features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/create/CreatePinEvents.kt rename to features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/setup/SetupPinEvents.kt index 78ce529325..45c5b034b0 100644 --- a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/create/CreatePinEvents.kt +++ b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/setup/SetupPinEvents.kt @@ -14,9 +14,9 @@ * limitations under the License. */ -package io.element.android.features.lockscreen.impl.create +package io.element.android.features.lockscreen.impl.setup -sealed interface CreatePinEvents { - data class OnPinEntryChanged(val entryAsText: String) : CreatePinEvents - data object ClearFailure : CreatePinEvents +sealed interface SetupPinEvents { + data class OnPinEntryChanged(val entryAsText: String) : SetupPinEvents + data object ClearFailure : SetupPinEvents } diff --git a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/create/CreatePinNode.kt b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/setup/SetupPinNode.kt similarity index 88% rename from features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/create/CreatePinNode.kt rename to features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/setup/SetupPinNode.kt index 331d6ada84..7474289f1e 100644 --- a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/create/CreatePinNode.kt +++ b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/setup/SetupPinNode.kt @@ -14,7 +14,7 @@ * limitations under the License. */ -package io.element.android.features.lockscreen.impl.create +package io.element.android.features.lockscreen.impl.setup import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier @@ -27,16 +27,16 @@ import io.element.android.anvilannotations.ContributesNode import io.element.android.libraries.di.AppScope @ContributesNode(AppScope::class) -class CreatePinNode @AssistedInject constructor( +class SetupPinNode @AssistedInject constructor( @Assisted buildContext: BuildContext, @Assisted plugins: List, - private val presenter: CreatePinPresenter, + private val presenter: SetupPinPresenter, ) : Node(buildContext, plugins = plugins) { @Composable override fun View(modifier: Modifier) { val state = presenter.present() - CreatePinView( + SetupPinView( state = state, onBackClicked = { }, modifier = modifier diff --git a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/create/CreatePinPresenter.kt b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/setup/SetupPinPresenter.kt similarity index 73% rename from features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/create/CreatePinPresenter.kt rename to features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/setup/SetupPinPresenter.kt index 957594c0f7..747af1bfd4 100644 --- a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/create/CreatePinPresenter.kt +++ b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/setup/SetupPinPresenter.kt @@ -14,29 +14,29 @@ * limitations under the License. */ -package io.element.android.features.lockscreen.impl.create +package io.element.android.features.lockscreen.impl.setup import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue -import io.element.android.features.lockscreen.impl.create.model.PinEntry -import io.element.android.features.lockscreen.impl.create.validation.CreatePinFailure -import io.element.android.features.lockscreen.impl.create.validation.PinValidator +import io.element.android.features.lockscreen.impl.setup.model.PinEntry +import io.element.android.features.lockscreen.impl.setup.validation.SetupPinFailure +import io.element.android.features.lockscreen.impl.setup.validation.PinValidator import io.element.android.libraries.architecture.Presenter import io.element.android.libraries.core.meta.BuildMeta import javax.inject.Inject private const val PIN_SIZE = 4 -class CreatePinPresenter @Inject constructor( +class SetupPinPresenter @Inject constructor( private val pinValidator: PinValidator, private val buildMeta: BuildMeta, -) : Presenter { +) : Presenter { @Composable - override fun present(): CreatePinState { + override fun present(): SetupPinState { var choosePinEntry by remember { mutableStateOf(PinEntry.empty(PIN_SIZE)) } @@ -46,20 +46,20 @@ class CreatePinPresenter @Inject constructor( var isConfirmationStep by remember { mutableStateOf(false) } - var createPinFailure by remember { - mutableStateOf(null) + var setupPinFailure by remember { + mutableStateOf(null) } - fun handleEvents(event: CreatePinEvents) { + fun handleEvents(event: SetupPinEvents) { when (event) { - is CreatePinEvents.OnPinEntryChanged -> { + is SetupPinEvents.OnPinEntryChanged -> { if (isConfirmationStep) { confirmPinEntry = confirmPinEntry.fillWith(event.entryAsText) if (confirmPinEntry.isPinComplete()) { if (confirmPinEntry == choosePinEntry) { //TODO save in db and navigate to next screen } else { - createPinFailure = CreatePinFailure.PinsDontMatch + setupPinFailure = SetupPinFailure.PinsDontMatch } } } else { @@ -67,35 +67,35 @@ class CreatePinPresenter @Inject constructor( if (choosePinEntry.isPinComplete()) { when (val pinValidationResult = pinValidator.isPinValid(choosePinEntry)) { is PinValidator.Result.Invalid -> { - createPinFailure = pinValidationResult.failure + setupPinFailure = pinValidationResult.failure } PinValidator.Result.Valid -> isConfirmationStep = true } } } } - CreatePinEvents.ClearFailure -> { - when (createPinFailure) { - is CreatePinFailure.PinsDontMatch -> { + SetupPinEvents.ClearFailure -> { + when (setupPinFailure) { + is SetupPinFailure.PinsDontMatch -> { choosePinEntry = PinEntry.empty(PIN_SIZE) confirmPinEntry = PinEntry.empty(PIN_SIZE) } - is CreatePinFailure.PinBlacklisted -> { + is SetupPinFailure.PinBlacklisted -> { choosePinEntry = PinEntry.empty(PIN_SIZE) } null -> Unit } isConfirmationStep = false - createPinFailure = null + setupPinFailure = null } } } - return CreatePinState( + return SetupPinState( choosePinEntry = choosePinEntry, confirmPinEntry = confirmPinEntry, isConfirmationStep = isConfirmationStep, - createPinFailure = createPinFailure, + SetupPinFailure = setupPinFailure, appName = buildMeta.applicationName, eventSink = ::handleEvents ) diff --git a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/create/CreatePinState.kt b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/setup/SetupPinState.kt similarity index 72% rename from features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/create/CreatePinState.kt rename to features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/setup/SetupPinState.kt index 020076a2ab..f2b1f50e5c 100644 --- a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/create/CreatePinState.kt +++ b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/setup/SetupPinState.kt @@ -14,18 +14,18 @@ * limitations under the License. */ -package io.element.android.features.lockscreen.impl.create +package io.element.android.features.lockscreen.impl.setup -import io.element.android.features.lockscreen.impl.create.model.PinEntry -import io.element.android.features.lockscreen.impl.create.validation.CreatePinFailure +import io.element.android.features.lockscreen.impl.setup.model.PinEntry +import io.element.android.features.lockscreen.impl.setup.validation.SetupPinFailure -data class CreatePinState( +data class SetupPinState( val choosePinEntry: PinEntry, val confirmPinEntry: PinEntry, val isConfirmationStep: Boolean, - val createPinFailure: CreatePinFailure?, + val SetupPinFailure: SetupPinFailure?, val appName: String, - val eventSink: (CreatePinEvents) -> Unit + val eventSink: (SetupPinEvents) -> Unit ) { val pinSize = choosePinEntry.size val activePinEntry = if (isConfirmationStep) { diff --git a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/create/CreatePinStateProvider.kt b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/setup/SetupPinStateProvider.kt similarity index 66% rename from features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/create/CreatePinStateProvider.kt rename to features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/setup/SetupPinStateProvider.kt index c9dcce018d..05df16f591 100644 --- a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/create/CreatePinStateProvider.kt +++ b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/setup/SetupPinStateProvider.kt @@ -14,47 +14,47 @@ * limitations under the License. */ -package io.element.android.features.lockscreen.impl.create +package io.element.android.features.lockscreen.impl.setup import androidx.compose.ui.tooling.preview.PreviewParameterProvider -import io.element.android.features.lockscreen.impl.create.model.PinEntry -import io.element.android.features.lockscreen.impl.create.validation.CreatePinFailure +import io.element.android.features.lockscreen.impl.setup.model.PinEntry +import io.element.android.features.lockscreen.impl.setup.validation.SetupPinFailure -open class CreatePinStateProvider : PreviewParameterProvider { - override val values: Sequence +open class SetupPinStateProvider : PreviewParameterProvider { + override val values: Sequence get() = sequenceOf( - aCreatePinState(), - aCreatePinState( + aSetupPinState(), + aSetupPinState( choosePinEntry = PinEntry.empty(4).fillWith("12") ), - aCreatePinState( + aSetupPinState( choosePinEntry = PinEntry.empty(4).fillWith("1789"), isConfirmationStep = true, ), - aCreatePinState( + aSetupPinState( choosePinEntry = PinEntry.empty(4).fillWith("1789"), confirmPinEntry = PinEntry.empty(4).fillWith("1788"), isConfirmationStep = true, - creationFailure = CreatePinFailure.PinsDontMatch + creationFailure = SetupPinFailure.PinsDontMatch ), - aCreatePinState( + aSetupPinState( choosePinEntry = PinEntry.empty(4).fillWith("1111"), - creationFailure = CreatePinFailure.PinBlacklisted + creationFailure = SetupPinFailure.PinBlacklisted ), ) } -fun aCreatePinState( +fun aSetupPinState( choosePinEntry: PinEntry = PinEntry.empty(4), confirmPinEntry: PinEntry = PinEntry.empty(4), isConfirmationStep: Boolean = false, - creationFailure: CreatePinFailure? = null, -) = CreatePinState( + creationFailure: SetupPinFailure? = null, +) = SetupPinState( choosePinEntry = choosePinEntry, confirmPinEntry = confirmPinEntry, isConfirmationStep = isConfirmationStep, - createPinFailure = creationFailure, + SetupPinFailure = creationFailure, appName = "Element", eventSink = {} ) diff --git a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/create/CreatePinView.kt b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/setup/SetupPinView.kt similarity index 80% rename from features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/create/CreatePinView.kt rename to features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/setup/SetupPinView.kt index 063d65f41f..3b84e1d889 100644 --- a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/create/CreatePinView.kt +++ b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/setup/SetupPinView.kt @@ -16,7 +16,7 @@ @file:OptIn(ExperimentalMaterial3Api::class) -package io.element.android.features.lockscreen.impl.create +package io.element.android.features.lockscreen.impl.setup import androidx.compose.foundation.background import androidx.compose.foundation.border @@ -46,9 +46,9 @@ import androidx.compose.ui.text.input.TextFieldValue import androidx.compose.ui.tooling.preview.PreviewParameter import androidx.compose.ui.unit.dp import io.element.android.features.lockscreen.impl.R -import io.element.android.features.lockscreen.impl.create.model.PinDigit -import io.element.android.features.lockscreen.impl.create.model.PinEntry -import io.element.android.features.lockscreen.impl.create.validation.CreatePinFailure +import io.element.android.features.lockscreen.impl.setup.model.PinDigit +import io.element.android.features.lockscreen.impl.setup.model.PinEntry +import io.element.android.features.lockscreen.impl.setup.validation.SetupPinFailure import io.element.android.libraries.designsystem.atomic.molecules.IconTitleSubtitleMolecule import io.element.android.libraries.designsystem.components.button.BackButton import io.element.android.libraries.designsystem.components.dialogs.ErrorDialog @@ -61,8 +61,8 @@ import io.element.android.libraries.designsystem.theme.pinDigitBg import io.element.android.libraries.theme.ElementTheme @Composable -fun CreatePinView( - state: CreatePinState, +fun SetupPinView( + state: SetupPinState, onBackClicked: () -> Unit, modifier: Modifier = Modifier, ) { @@ -86,15 +86,15 @@ fun CreatePinView( .verticalScroll(state = scrollState) .padding(vertical = 16.dp, horizontal = 20.dp), ) { - CreatePinHeader(state.isConfirmationStep, state.appName) - CreatePinContent(state) + SetupPinHeader(state.isConfirmationStep, state.appName) + SetupPinContent(state) } } ) } @Composable -private fun CreatePinHeader( +private fun SetupPinHeader( isValidationStep: Boolean, appName: String, modifier: Modifier = Modifier, @@ -116,44 +116,44 @@ private fun CreatePinHeader( } @Composable -private fun CreatePinContent( - state: CreatePinState, +private fun SetupPinContent( + state: SetupPinState, modifier: Modifier = Modifier, ) { PinEntryTextField( state.activePinEntry, onValueChange = { - state.eventSink(CreatePinEvents.OnPinEntryChanged(it)) + state.eventSink(SetupPinEvents.OnPinEntryChanged(it)) }, modifier = modifier .padding(top = 36.dp) .fillMaxWidth() ) - if (state.createPinFailure != null) { + if (state.SetupPinFailure != null) { ErrorDialog( modifier = modifier, - title = state.createPinFailure.title(), - content = state.createPinFailure.content(), + title = state.SetupPinFailure.title(), + content = state.SetupPinFailure.content(), onDismiss = { - state.eventSink(CreatePinEvents.ClearFailure) + state.eventSink(SetupPinEvents.ClearFailure) } ) } } @Composable -private fun CreatePinFailure.content(): String { +private fun SetupPinFailure.content(): String { return when (this) { - CreatePinFailure.PinBlacklisted -> stringResource(id = R.string.screen_app_lock_setup_pin_blacklisted_dialog_content) - CreatePinFailure.PinsDontMatch -> stringResource(id = R.string.screen_app_lock_setup_pin_mismatch_dialog_content) + SetupPinFailure.PinBlacklisted -> stringResource(id = R.string.screen_app_lock_setup_pin_blacklisted_dialog_content) + SetupPinFailure.PinsDontMatch -> stringResource(id = R.string.screen_app_lock_setup_pin_mismatch_dialog_content) } } @Composable -private fun CreatePinFailure.title(): String { +private fun SetupPinFailure.title(): String { return when (this) { - CreatePinFailure.PinBlacklisted -> stringResource(id = R.string.screen_app_lock_setup_pin_blacklisted_dialog_title) - CreatePinFailure.PinsDontMatch -> stringResource(id = R.string.screen_app_lock_setup_pin_mismatch_dialog_title) + SetupPinFailure.PinBlacklisted -> stringResource(id = R.string.screen_app_lock_setup_pin_blacklisted_dialog_title) + SetupPinFailure.PinsDontMatch -> stringResource(id = R.string.screen_app_lock_setup_pin_mismatch_dialog_title) } } @@ -225,9 +225,9 @@ private fun PinDigitView( @Composable @PreviewsDayNight -internal fun CreatePinViewPreview(@PreviewParameter(CreatePinStateProvider::class) state: CreatePinState) { +internal fun SetupPinViewPreview(@PreviewParameter(SetupPinStateProvider::class) state: SetupPinState) { ElementPreview { - CreatePinView( + SetupPinView( state = state, onBackClicked = {}, ) diff --git a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/create/model/PinDigit.kt b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/setup/model/PinDigit.kt similarity index 92% rename from features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/create/model/PinDigit.kt rename to features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/setup/model/PinDigit.kt index 741a61cafe..10a4832866 100644 --- a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/create/model/PinDigit.kt +++ b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/setup/model/PinDigit.kt @@ -14,7 +14,7 @@ * limitations under the License. */ -package io.element.android.features.lockscreen.impl.create.model +package io.element.android.features.lockscreen.impl.setup.model sealed interface PinDigit { data object Empty : PinDigit diff --git a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/create/model/PinEntry.kt b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/setup/model/PinEntry.kt similarity index 96% rename from features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/create/model/PinEntry.kt rename to features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/setup/model/PinEntry.kt index a97315f2e8..9f802a989c 100644 --- a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/create/model/PinEntry.kt +++ b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/setup/model/PinEntry.kt @@ -14,7 +14,7 @@ * limitations under the License. */ -package io.element.android.features.lockscreen.impl.create.model +package io.element.android.features.lockscreen.impl.setup.model import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.toPersistentList diff --git a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/create/validation/CreatePinFailure.kt b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/setup/validation/CreatePinFailure.kt similarity index 74% rename from features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/create/validation/CreatePinFailure.kt rename to features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/setup/validation/CreatePinFailure.kt index 8c0cb78921..3bb21cb9e6 100644 --- a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/create/validation/CreatePinFailure.kt +++ b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/setup/validation/CreatePinFailure.kt @@ -14,9 +14,9 @@ * limitations under the License. */ -package io.element.android.features.lockscreen.impl.create.validation +package io.element.android.features.lockscreen.impl.setup.validation -sealed interface CreatePinFailure { - data object PinBlacklisted : CreatePinFailure - data object PinsDontMatch : CreatePinFailure +sealed interface SetupPinFailure { + data object PinBlacklisted : SetupPinFailure + data object PinsDontMatch : SetupPinFailure } diff --git a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/create/validation/PinValidator.kt b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/setup/validation/PinValidator.kt similarity index 80% rename from features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/create/validation/PinValidator.kt rename to features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/setup/validation/PinValidator.kt index 7353ec47d0..0ddf86d887 100644 --- a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/create/validation/PinValidator.kt +++ b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/setup/validation/PinValidator.kt @@ -14,10 +14,10 @@ * limitations under the License. */ -package io.element.android.features.lockscreen.impl.create.validation +package io.element.android.features.lockscreen.impl.setup.validation import androidx.annotation.VisibleForTesting -import io.element.android.features.lockscreen.impl.create.model.PinEntry +import io.element.android.features.lockscreen.impl.setup.model.PinEntry import javax.inject.Inject class PinValidator @Inject constructor() { @@ -29,14 +29,14 @@ class PinValidator @Inject constructor() { sealed interface Result { data object Valid : Result - data class Invalid(val failure: CreatePinFailure) : Result + data class Invalid(val failure: SetupPinFailure) : Result } fun isPinValid(pinEntry: PinEntry): Result { val pinAsText = pinEntry.toText() val isBlacklisted = BLACKLIST.any { it == pinAsText } return if (isBlacklisted) { - Result.Invalid(CreatePinFailure.PinBlacklisted) + Result.Invalid(SetupPinFailure.PinBlacklisted) } else { Result.Valid } diff --git a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/auth/PinAuthenticationEvents.kt b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/unlock/PinUnlockEvents.kt similarity index 80% rename from features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/auth/PinAuthenticationEvents.kt rename to features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/unlock/PinUnlockEvents.kt index f9f46c430a..ba35f3045c 100644 --- a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/auth/PinAuthenticationEvents.kt +++ b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/unlock/PinUnlockEvents.kt @@ -14,8 +14,8 @@ * limitations under the License. */ -package io.element.android.features.lockscreen.impl.auth +package io.element.android.features.lockscreen.impl.unlock -sealed interface PinAuthenticationEvents { - data object Unlock : PinAuthenticationEvents +sealed interface PinUnlockEvents { + data object Unlock : PinUnlockEvents } diff --git a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/auth/PinAuthenticationNode.kt b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/unlock/PinUnlockNode.kt similarity index 86% rename from features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/auth/PinAuthenticationNode.kt rename to features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/unlock/PinUnlockNode.kt index d236d40cf1..0fba55c17b 100644 --- a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/auth/PinAuthenticationNode.kt +++ b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/unlock/PinUnlockNode.kt @@ -14,7 +14,7 @@ * limitations under the License. */ -package io.element.android.features.lockscreen.impl.auth +package io.element.android.features.lockscreen.impl.unlock import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier @@ -27,16 +27,16 @@ import io.element.android.anvilannotations.ContributesNode import io.element.android.libraries.di.AppScope @ContributesNode(AppScope::class) -class PinAuthenticationNode @AssistedInject constructor( +class PinUnlockNode @AssistedInject constructor( @Assisted buildContext: BuildContext, @Assisted plugins: List, - private val presenter: PinAuthenticationPresenter, + private val presenter: PinUnlockPresenter, ) : Node(buildContext, plugins = plugins) { @Composable override fun View(modifier: Modifier) { val state = presenter.present() - PinAuthenticationView( + PinUnlockView( state = state, modifier = modifier ) diff --git a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/auth/PinAuthenticationPresenter.kt b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/unlock/PinUnlockPresenter.kt similarity index 73% rename from features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/auth/PinAuthenticationPresenter.kt rename to features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/unlock/PinUnlockPresenter.kt index ecc82f421c..24cba574af 100644 --- a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/auth/PinAuthenticationPresenter.kt +++ b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/unlock/PinUnlockPresenter.kt @@ -14,7 +14,7 @@ * limitations under the License. */ -package io.element.android.features.lockscreen.impl.auth +package io.element.android.features.lockscreen.impl.unlock import androidx.compose.runtime.Composable import io.element.android.features.lockscreen.api.LockScreenStateService @@ -23,20 +23,20 @@ import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.launch import javax.inject.Inject -class PinAuthenticationPresenter @Inject constructor( +class PinUnlockPresenter @Inject constructor( private val pinStateService: LockScreenStateService, private val coroutineScope: CoroutineScope, -) : Presenter { +) : Presenter { @Composable - override fun present(): PinAuthenticationState { + override fun present(): PinUnlockState { - fun handleEvents(event: PinAuthenticationEvents) { + fun handleEvents(event: PinUnlockEvents) { when (event) { - PinAuthenticationEvents.Unlock -> coroutineScope.launch { pinStateService.unlock() } + PinUnlockEvents.Unlock -> coroutineScope.launch { pinStateService.unlock() } } } - return PinAuthenticationState( + return PinUnlockState( eventSink = ::handleEvents ) } diff --git a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/auth/PinAuthenticationState.kt b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/unlock/PinUnlockState.kt similarity index 80% rename from features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/auth/PinAuthenticationState.kt rename to features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/unlock/PinUnlockState.kt index 387467534f..dec731c040 100644 --- a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/auth/PinAuthenticationState.kt +++ b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/unlock/PinUnlockState.kt @@ -14,8 +14,8 @@ * limitations under the License. */ -package io.element.android.features.lockscreen.impl.auth +package io.element.android.features.lockscreen.impl.unlock -data class PinAuthenticationState( - val eventSink: (PinAuthenticationEvents) -> Unit +data class PinUnlockState( + val eventSink: (PinUnlockEvents) -> Unit ) diff --git a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/auth/PinAuthenticationStateProvider.kt b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/unlock/PinUnlockStateProvider.kt similarity index 70% rename from features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/auth/PinAuthenticationStateProvider.kt rename to features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/unlock/PinUnlockStateProvider.kt index a2612ed858..f5afb44fa9 100644 --- a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/auth/PinAuthenticationStateProvider.kt +++ b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/unlock/PinUnlockStateProvider.kt @@ -14,17 +14,17 @@ * limitations under the License. */ -package io.element.android.features.lockscreen.impl.auth +package io.element.android.features.lockscreen.impl.unlock import androidx.compose.ui.tooling.preview.PreviewParameterProvider -open class PinAuthenticationStateProvider : PreviewParameterProvider { - override val values: Sequence +open class PinUnlockStateProvider : PreviewParameterProvider { + override val values: Sequence get() = sequenceOf( - aPinAuthenticationState(), + aPinUnlockState(), ) } -fun aPinAuthenticationState() = PinAuthenticationState( +fun aPinUnlockState() = PinUnlockState( eventSink = {} ) diff --git a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/auth/PinAuthenticationView.kt b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/unlock/PinUnlockView.kt similarity index 83% rename from features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/auth/PinAuthenticationView.kt rename to features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/unlock/PinUnlockView.kt index 740d85adec..47027853b4 100644 --- a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/auth/PinAuthenticationView.kt +++ b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/unlock/PinUnlockView.kt @@ -14,23 +14,18 @@ * limitations under the License. */ -package io.element.android.features.lockscreen.impl.auth +package io.element.android.features.lockscreen.impl.unlock import androidx.compose.foundation.background -import androidx.compose.foundation.gestures.Orientation -import androidx.compose.foundation.gestures.scrollable import androidx.compose.foundation.layout.Arrangement.spacedBy import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.BoxWithConstraints import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height -import androidx.compose.foundation.layout.heightIn import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size -import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.shape.CircleShape import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Lock @@ -41,7 +36,7 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.tooling.preview.PreviewParameter import androidx.compose.ui.unit.dp -import io.element.android.features.lockscreen.impl.auth.numpad.PinKeypad +import io.element.android.features.lockscreen.impl.unlock.numpad.PinKeypad import io.element.android.libraries.designsystem.atomic.pages.HeaderFooterPage import io.element.android.libraries.designsystem.preview.ElementPreview import io.element.android.libraries.designsystem.preview.PreviewsDayNight @@ -52,13 +47,13 @@ import io.element.android.libraries.designsystem.theme.components.Text import io.element.android.libraries.theme.ElementTheme @Composable -fun PinAuthenticationView( - state: PinAuthenticationState, +fun PinUnlockView( + state: PinUnlockState, modifier: Modifier = Modifier, ) { Surface(modifier) { HeaderFooterPage( - header = { PinAuthenticationHeader(modifier = Modifier.padding(top = 60.dp, bottom = 12.dp)) }, + header = { PinUnlockHeader(modifier = Modifier.padding(top = 60.dp, bottom = 12.dp)) }, content = { Box( modifier = Modifier @@ -76,12 +71,12 @@ fun PinAuthenticationView( } @Composable -private fun PinAuthenticationFooter(state: PinAuthenticationState) { +private fun PinUnlockFooter(state: PinUnlockState) { Button( modifier = Modifier.fillMaxWidth(), text = "Unlock", onClick = { - state.eventSink(PinAuthenticationEvents.Unlock) + state.eventSink(PinUnlockEvents.Unlock) } ) } @@ -116,7 +111,7 @@ private fun PinDot( } @Composable -private fun PinAuthenticationHeader( +private fun PinUnlockHeader( modifier: Modifier = Modifier, ) { Column(modifier, horizontalAlignment = Alignment.CenterHorizontally) { @@ -151,9 +146,9 @@ private fun PinAuthenticationHeader( @Composable @PreviewsDayNight -internal fun PinAuthenticationViewPreview(@PreviewParameter(PinAuthenticationStateProvider::class) state: PinAuthenticationState) { +internal fun PinUnlockViewPreview(@PreviewParameter(PinUnlockStateProvider::class) state: PinUnlockState) { ElementPreview { - PinAuthenticationView( + PinUnlockView( state = state, ) } diff --git a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/auth/numpad/PinKeypad.kt b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/unlock/numpad/PinKeypad.kt similarity index 98% rename from features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/auth/numpad/PinKeypad.kt rename to features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/unlock/numpad/PinKeypad.kt index 43abc24002..44a09ed08f 100644 --- a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/auth/numpad/PinKeypad.kt +++ b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/unlock/numpad/PinKeypad.kt @@ -14,7 +14,7 @@ * limitations under the License. */ -package io.element.android.features.lockscreen.impl.auth.numpad +package io.element.android.features.lockscreen.impl.unlock.numpad import androidx.compose.foundation.background import androidx.compose.foundation.layout.Arrangement diff --git a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/auth/numpad/PinKeypadModel.kt b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/unlock/numpad/PinKeypadModel.kt similarity index 92% rename from features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/auth/numpad/PinKeypadModel.kt rename to features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/unlock/numpad/PinKeypadModel.kt index 108486e400..4ea42e7f42 100644 --- a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/auth/numpad/PinKeypadModel.kt +++ b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/unlock/numpad/PinKeypadModel.kt @@ -14,7 +14,7 @@ * limitations under the License. */ -package io.element.android.features.lockscreen.impl.auth.numpad +package io.element.android.features.lockscreen.impl.unlock.numpad import androidx.compose.runtime.Immutable diff --git a/features/lockscreen/impl/src/test/kotlin/io/element/android/features/lockscreen/impl/create/CreatePinPresenterTest.kt b/features/lockscreen/impl/src/test/kotlin/io/element/android/features/lockscreen/impl/setup/CreatePinPresenterTest.kt similarity index 92% rename from features/lockscreen/impl/src/test/kotlin/io/element/android/features/lockscreen/impl/create/CreatePinPresenterTest.kt rename to features/lockscreen/impl/src/test/kotlin/io/element/android/features/lockscreen/impl/setup/CreatePinPresenterTest.kt index 78536bb693..85f54fd149 100644 --- a/features/lockscreen/impl/src/test/kotlin/io/element/android/features/lockscreen/impl/create/CreatePinPresenterTest.kt +++ b/features/lockscreen/impl/src/test/kotlin/io/element/android/features/lockscreen/impl/setup/CreatePinPresenterTest.kt @@ -14,16 +14,16 @@ * limitations under the License. */ -package io.element.android.features.lockscreen.impl.create +package io.element.android.features.lockscreen.impl.setup import app.cash.molecule.RecompositionMode import app.cash.molecule.moleculeFlow import app.cash.turbine.test import com.google.common.truth.Truth.assertThat -import io.element.android.features.lockscreen.impl.create.model.PinDigit -import io.element.android.features.lockscreen.impl.create.model.PinEntry -import io.element.android.features.lockscreen.impl.create.validation.CreatePinFailure -import io.element.android.features.lockscreen.impl.create.validation.PinValidator +import io.element.android.features.lockscreen.impl.setup.model.PinDigit +import io.element.android.features.lockscreen.impl.setup.model.PinEntry +import io.element.android.features.lockscreen.impl.setup.validation.CreatePinFailure +import io.element.android.features.lockscreen.impl.setup.validation.PinValidator import io.element.android.libraries.matrix.test.core.aBuildMeta import io.element.android.tests.testutils.awaitLastSequentialItem import kotlinx.coroutines.test.runTest From 1d3a75fbd42554e7cd58d8f7b7f1348230e335e6 Mon Sep 17 00:00:00 2001 From: ganfra Date: Fri, 20 Oct 2023 15:23:10 +0200 Subject: [PATCH 03/22] Pin : move some classes around --- .../impl/components/PinEntryTextField.kt | 116 ++++++++++++++++++ .../impl/{setup => pin}/model/PinDigit.kt | 2 +- .../impl/{setup => pin}/model/PinEntry.kt | 2 +- .../impl/setup/SetupPinPresenter.kt | 2 +- .../lockscreen/impl/setup/SetupPinState.kt | 2 +- .../impl/setup/SetupPinStateProvider.kt | 2 +- .../lockscreen/impl/setup/SetupPinView.kt | 83 +------------ .../impl/setup/validation/PinValidator.kt | 2 +- .../impl/setup/CreatePinPresenterTest.kt | 4 +- 9 files changed, 125 insertions(+), 90 deletions(-) create mode 100644 features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/components/PinEntryTextField.kt rename features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/{setup => pin}/model/PinDigit.kt (93%) rename features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/{setup => pin}/model/PinEntry.kt (96%) diff --git a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/components/PinEntryTextField.kt b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/components/PinEntryTextField.kt new file mode 100644 index 0000000000..5682e594fe --- /dev/null +++ b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/components/PinEntryTextField.kt @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2023 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.element.android.features.lockscreen.impl.components + +import androidx.compose.foundation.background +import androidx.compose.foundation.border +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.foundation.text.BasicTextField +import androidx.compose.foundation.text.KeyboardOptions +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.text.input.KeyboardType +import androidx.compose.ui.text.input.TextFieldValue +import androidx.compose.ui.unit.dp +import io.element.android.features.lockscreen.impl.pin.model.PinDigit +import io.element.android.features.lockscreen.impl.pin.model.PinEntry +import io.element.android.libraries.designsystem.preview.PreviewsDayNight +import io.element.android.libraries.designsystem.theme.pinDigitBg +import io.element.android.libraries.theme.ElementTheme + +@Composable +fun PinEntryTextField( + pinEntry: PinEntry, + onValueChange: (String) -> Unit, + modifier: Modifier = Modifier, +) { + BasicTextField( + modifier = modifier, + value = TextFieldValue(pinEntry.toText()), + onValueChange = { + onValueChange(it.text) + }, + keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number), + decorationBox = { + PinEntryRow(pinEntry = pinEntry) + } + ) +} + +@Composable +private fun PinEntryRow( + pinEntry: PinEntry, + modifier: Modifier = Modifier, +) { + Row( + modifier = modifier, + horizontalArrangement = Arrangement.spacedBy(8.dp, alignment = Alignment.CenterHorizontally), + verticalAlignment = Alignment.CenterVertically, + ) { + for (digit in pinEntry.digits) { + PinDigitView(digit = digit) + } + } +} + +@Composable +private fun PinDigitView( + digit: PinDigit, + modifier: Modifier = Modifier, +) { + val shape = RoundedCornerShape(8.dp) + val appearanceModifier = when (digit) { + PinDigit.Empty -> { + Modifier.border(1.dp, ElementTheme.colors.iconPrimary, shape) + } + is PinDigit.Filled -> { + Modifier.background(ElementTheme.colors.pinDigitBg, shape) + } + } + Box( + modifier = modifier + .size(48.dp) + .then(appearanceModifier), + contentAlignment = Alignment.Center, + + ) { + if (digit is PinDigit.Filled) { + Text( + text = digit.toText(), + style = ElementTheme.typography.fontHeadingMdBold + ) + } + + } +} + +@PreviewsDayNight +@Composable +fun PinEntryTextFieldPreview() { + ElementTheme { + PinEntryTextField( + pinEntry = PinEntry.empty(4).fillWith("12"), + onValueChange = {}, + ) + } +} diff --git a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/setup/model/PinDigit.kt b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/pin/model/PinDigit.kt similarity index 93% rename from features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/setup/model/PinDigit.kt rename to features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/pin/model/PinDigit.kt index 10a4832866..aa3c45e02e 100644 --- a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/setup/model/PinDigit.kt +++ b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/pin/model/PinDigit.kt @@ -14,7 +14,7 @@ * limitations under the License. */ -package io.element.android.features.lockscreen.impl.setup.model +package io.element.android.features.lockscreen.impl.pin.model sealed interface PinDigit { data object Empty : PinDigit diff --git a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/setup/model/PinEntry.kt b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/pin/model/PinEntry.kt similarity index 96% rename from features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/setup/model/PinEntry.kt rename to features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/pin/model/PinEntry.kt index 9f802a989c..d14b71ffe2 100644 --- a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/setup/model/PinEntry.kt +++ b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/pin/model/PinEntry.kt @@ -14,7 +14,7 @@ * limitations under the License. */ -package io.element.android.features.lockscreen.impl.setup.model +package io.element.android.features.lockscreen.impl.pin.model import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.toPersistentList diff --git a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/setup/SetupPinPresenter.kt b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/setup/SetupPinPresenter.kt index 747af1bfd4..af34c387d2 100644 --- a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/setup/SetupPinPresenter.kt +++ b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/setup/SetupPinPresenter.kt @@ -21,7 +21,7 @@ import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue -import io.element.android.features.lockscreen.impl.setup.model.PinEntry +import io.element.android.features.lockscreen.impl.pin.model.PinEntry import io.element.android.features.lockscreen.impl.setup.validation.SetupPinFailure import io.element.android.features.lockscreen.impl.setup.validation.PinValidator import io.element.android.libraries.architecture.Presenter diff --git a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/setup/SetupPinState.kt b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/setup/SetupPinState.kt index f2b1f50e5c..7823b1e39f 100644 --- a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/setup/SetupPinState.kt +++ b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/setup/SetupPinState.kt @@ -16,7 +16,7 @@ package io.element.android.features.lockscreen.impl.setup -import io.element.android.features.lockscreen.impl.setup.model.PinEntry +import io.element.android.features.lockscreen.impl.pin.model.PinEntry import io.element.android.features.lockscreen.impl.setup.validation.SetupPinFailure data class SetupPinState( diff --git a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/setup/SetupPinStateProvider.kt b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/setup/SetupPinStateProvider.kt index 05df16f591..37a232dc11 100644 --- a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/setup/SetupPinStateProvider.kt +++ b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/setup/SetupPinStateProvider.kt @@ -17,7 +17,7 @@ package io.element.android.features.lockscreen.impl.setup import androidx.compose.ui.tooling.preview.PreviewParameterProvider -import io.element.android.features.lockscreen.impl.setup.model.PinEntry +import io.element.android.features.lockscreen.impl.pin.model.PinEntry import io.element.android.features.lockscreen.impl.setup.validation.SetupPinFailure open class SetupPinStateProvider : PreviewParameterProvider { diff --git a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/setup/SetupPinView.kt b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/setup/SetupPinView.kt index 3b84e1d889..18be5e14b4 100644 --- a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/setup/SetupPinView.kt +++ b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/setup/SetupPinView.kt @@ -18,21 +18,12 @@ package io.element.android.features.lockscreen.impl.setup -import androidx.compose.foundation.background -import androidx.compose.foundation.border -import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.consumeWindowInsets import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.imePadding import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.size import androidx.compose.foundation.rememberScrollState -import androidx.compose.foundation.shape.RoundedCornerShape -import androidx.compose.foundation.text.BasicTextField -import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.foundation.verticalScroll import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Lock @@ -41,13 +32,10 @@ import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource -import androidx.compose.ui.text.input.KeyboardType -import androidx.compose.ui.text.input.TextFieldValue import androidx.compose.ui.tooling.preview.PreviewParameter import androidx.compose.ui.unit.dp import io.element.android.features.lockscreen.impl.R -import io.element.android.features.lockscreen.impl.setup.model.PinDigit -import io.element.android.features.lockscreen.impl.setup.model.PinEntry +import io.element.android.features.lockscreen.impl.components.PinEntryTextField import io.element.android.features.lockscreen.impl.setup.validation.SetupPinFailure import io.element.android.libraries.designsystem.atomic.molecules.IconTitleSubtitleMolecule import io.element.android.libraries.designsystem.components.button.BackButton @@ -55,10 +43,7 @@ import io.element.android.libraries.designsystem.components.dialogs.ErrorDialog import io.element.android.libraries.designsystem.preview.ElementPreview import io.element.android.libraries.designsystem.preview.PreviewsDayNight import io.element.android.libraries.designsystem.theme.components.Scaffold -import io.element.android.libraries.designsystem.theme.components.Text import io.element.android.libraries.designsystem.theme.components.TopAppBar -import io.element.android.libraries.designsystem.theme.pinDigitBg -import io.element.android.libraries.theme.ElementTheme @Composable fun SetupPinView( @@ -157,72 +142,6 @@ private fun SetupPinFailure.title(): String { } } -@Composable -private fun PinEntryTextField( - pinEntry: PinEntry, - onValueChange: (String) -> Unit, - modifier: Modifier = Modifier, -) { - BasicTextField( - modifier = modifier, - value = TextFieldValue(pinEntry.toText()), - onValueChange = { - onValueChange(it.text) - }, - keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number), - decorationBox = { - PinEntryRow(pinEntry = pinEntry) - } - ) -} - -@Composable -private fun PinEntryRow( - pinEntry: PinEntry, - modifier: Modifier = Modifier, -) { - Row( - modifier = modifier, - horizontalArrangement = Arrangement.spacedBy(8.dp, alignment = Alignment.CenterHorizontally), - verticalAlignment = Alignment.CenterVertically, - ) { - for (digit in pinEntry.digits) { - PinDigitView(digit = digit) - } - } -} - -@Composable -private fun PinDigitView( - digit: PinDigit, - modifier: Modifier = Modifier, -) { - val shape = RoundedCornerShape(8.dp) - val appearanceModifier = when (digit) { - PinDigit.Empty -> { - Modifier.border(1.dp, ElementTheme.colors.iconPrimary, shape) - } - is PinDigit.Filled -> { - Modifier.background(ElementTheme.colors.pinDigitBg, shape) - } - } - Box( - modifier = modifier - .size(48.dp) - .then(appearanceModifier), - contentAlignment = Alignment.Center, - - ) { - if (digit is PinDigit.Filled) { - Text( - text = digit.toText(), - style = ElementTheme.typography.fontHeadingMdBold - ) - } - - } -} - @Composable @PreviewsDayNight internal fun SetupPinViewPreview(@PreviewParameter(SetupPinStateProvider::class) state: SetupPinState) { diff --git a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/setup/validation/PinValidator.kt b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/setup/validation/PinValidator.kt index 0ddf86d887..c7435120aa 100644 --- a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/setup/validation/PinValidator.kt +++ b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/setup/validation/PinValidator.kt @@ -17,7 +17,7 @@ package io.element.android.features.lockscreen.impl.setup.validation import androidx.annotation.VisibleForTesting -import io.element.android.features.lockscreen.impl.setup.model.PinEntry +import io.element.android.features.lockscreen.impl.pin.model.PinEntry import javax.inject.Inject class PinValidator @Inject constructor() { diff --git a/features/lockscreen/impl/src/test/kotlin/io/element/android/features/lockscreen/impl/setup/CreatePinPresenterTest.kt b/features/lockscreen/impl/src/test/kotlin/io/element/android/features/lockscreen/impl/setup/CreatePinPresenterTest.kt index 85f54fd149..723b8e8e6b 100644 --- a/features/lockscreen/impl/src/test/kotlin/io/element/android/features/lockscreen/impl/setup/CreatePinPresenterTest.kt +++ b/features/lockscreen/impl/src/test/kotlin/io/element/android/features/lockscreen/impl/setup/CreatePinPresenterTest.kt @@ -20,8 +20,8 @@ import app.cash.molecule.RecompositionMode import app.cash.molecule.moleculeFlow import app.cash.turbine.test import com.google.common.truth.Truth.assertThat -import io.element.android.features.lockscreen.impl.setup.model.PinDigit -import io.element.android.features.lockscreen.impl.setup.model.PinEntry +import io.element.android.features.lockscreen.impl.pin.model.PinDigit +import io.element.android.features.lockscreen.impl.pin.model.PinEntry import io.element.android.features.lockscreen.impl.setup.validation.CreatePinFailure import io.element.android.features.lockscreen.impl.setup.validation.PinValidator import io.element.android.libraries.matrix.test.core.aBuildMeta From 55a272d8b7eb03d8e7f651e57f94b00be33f02de Mon Sep 17 00:00:00 2001 From: ganfra Date: Fri, 20 Oct 2023 15:43:55 +0200 Subject: [PATCH 04/22] Pin unlock : start branching logic --- .../lockscreen/impl/pin/model/PinEntry.kt | 24 ++++++++++++- .../impl/setup/SetupPinPresenter.kt | 4 +-- .../state/DefaultLockScreenStateService.kt | 3 +- .../lockscreen/impl/unlock/PinUnlockEvents.kt | 3 ++ .../impl/unlock/PinUnlockPresenter.kt | 25 +++++++++++++ .../lockscreen/impl/unlock/PinUnlockState.kt | 3 ++ .../impl/unlock/PinUnlockStateProvider.kt | 6 +++- .../lockscreen/impl/unlock/PinUnlockView.kt | 36 +++++++++---------- .../impl/unlock/numpad/PinKeypad.kt | 10 +++--- .../impl/unlock/numpad/PinKeypadModel.kt | 2 +- 10 files changed, 85 insertions(+), 31 deletions(-) diff --git a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/pin/model/PinEntry.kt b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/pin/model/PinEntry.kt index d14b71ffe2..92dda869a6 100644 --- a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/pin/model/PinEntry.kt +++ b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/pin/model/PinEntry.kt @@ -50,14 +50,36 @@ data class PinEntry( return copy(digits = newDigits.toPersistentList()) } + fun deleteLast(): PinEntry { + if (isEmpty()) return this + val newDigits = digits.toMutableList() + newDigits.indexOfLast { it is PinDigit.Filled }.also { lastFilled -> + newDigits[lastFilled] = PinDigit.Empty + } + return copy(digits = newDigits.toPersistentList()) + } + + fun addDigit(digit: Char): PinEntry { + if (isComplete()) return this + val newDigits = digits.toMutableList() + newDigits.indexOfFirst { it is PinDigit.Empty }.also { firstEmpty -> + newDigits[firstEmpty] = PinDigit.Filled(digit) + } + return copy(digits = newDigits.toPersistentList()) + } + fun clear(): PinEntry { return fillWith("") } - fun isPinComplete(): Boolean { + fun isComplete(): Boolean { return digits.all { it is PinDigit.Filled } } + fun isEmpty(): Boolean { + return digits.all { it is PinDigit.Empty } + } + fun toText(): String { return digits.joinToString("") { it.toText() diff --git a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/setup/SetupPinPresenter.kt b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/setup/SetupPinPresenter.kt index af34c387d2..8561e5333c 100644 --- a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/setup/SetupPinPresenter.kt +++ b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/setup/SetupPinPresenter.kt @@ -55,7 +55,7 @@ class SetupPinPresenter @Inject constructor( is SetupPinEvents.OnPinEntryChanged -> { if (isConfirmationStep) { confirmPinEntry = confirmPinEntry.fillWith(event.entryAsText) - if (confirmPinEntry.isPinComplete()) { + if (confirmPinEntry.isComplete()) { if (confirmPinEntry == choosePinEntry) { //TODO save in db and navigate to next screen } else { @@ -64,7 +64,7 @@ class SetupPinPresenter @Inject constructor( } } else { choosePinEntry = choosePinEntry.fillWith(event.entryAsText) - if (choosePinEntry.isPinComplete()) { + if (choosePinEntry.isComplete()) { when (val pinValidationResult = pinValidator.isPinValid(choosePinEntry)) { is PinValidator.Result.Invalid -> { setupPinFailure = pinValidationResult.failure diff --git a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/state/DefaultLockScreenStateService.kt b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/state/DefaultLockScreenStateService.kt index dbfeca2c6a..a071de06e9 100644 --- a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/state/DefaultLockScreenStateService.kt +++ b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/state/DefaultLockScreenStateService.kt @@ -25,7 +25,6 @@ import io.element.android.libraries.featureflag.api.FeatureFlagService import io.element.android.libraries.featureflag.api.FeatureFlags import kotlinx.coroutines.Job import kotlinx.coroutines.coroutineScope -import kotlinx.coroutines.delay import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.launch @@ -57,7 +56,7 @@ class DefaultLockScreenStateService @Inject constructor( override suspend fun entersBackground() = coroutineScope { lockJob = launch { if (featureFlagService.isFeatureEnabled(FeatureFlags.PinUnlock)) { - delay(GRACE_PERIOD_IN_MILLIS) + //delay(GRACE_PERIOD_IN_MILLIS) _lockScreenState.value = LockScreenState.Locked } } diff --git a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/unlock/PinUnlockEvents.kt b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/unlock/PinUnlockEvents.kt index ba35f3045c..8dddd40e8a 100644 --- a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/unlock/PinUnlockEvents.kt +++ b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/unlock/PinUnlockEvents.kt @@ -16,6 +16,9 @@ package io.element.android.features.lockscreen.impl.unlock +import io.element.android.features.lockscreen.impl.unlock.numpad.PinKeypadModel + sealed interface PinUnlockEvents { + data class OnPinKeypadPressed(val pinKeypadModel: PinKeypadModel) : PinUnlockEvents data object Unlock : PinUnlockEvents } 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 24cba574af..d673ad7966 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 @@ -17,7 +17,13 @@ package io.element.android.features.lockscreen.impl.unlock import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue import io.element.android.features.lockscreen.api.LockScreenStateService +import io.element.android.features.lockscreen.impl.pin.model.PinEntry +import io.element.android.features.lockscreen.impl.unlock.numpad.PinKeypadModel import io.element.android.libraries.architecture.Presenter import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.launch @@ -31,13 +37,32 @@ class PinUnlockPresenter @Inject constructor( @Composable override fun present(): PinUnlockState { + var pinEntry by remember { + mutableStateOf(PinEntry.empty(4)) + } + fun handleEvents(event: PinUnlockEvents) { when (event) { PinUnlockEvents.Unlock -> coroutineScope.launch { pinStateService.unlock() } + is PinUnlockEvents.OnPinKeypadPressed -> { + pinEntry = pinEntry.process(event.pinKeypadModel) + if (pinEntry.isComplete()) { + coroutineScope.launch { pinStateService.unlock() } + } + } } } return PinUnlockState( + pinEntry = pinEntry, eventSink = ::handleEvents ) } + + private fun PinEntry.process(pinKeypadModel: PinKeypadModel): PinEntry { + return when (pinKeypadModel) { + PinKeypadModel.Back -> deleteLast() + is PinKeypadModel.Number -> addDigit(pinKeypadModel.number) + PinKeypadModel.Empty -> this + } + } } 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 dec731c040..69d3213c7e 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 @@ -16,6 +16,9 @@ package io.element.android.features.lockscreen.impl.unlock +import io.element.android.features.lockscreen.impl.pin.model.PinEntry + data class PinUnlockState( + val pinEntry: PinEntry, val eventSink: (PinUnlockEvents) -> Unit ) 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 f5afb44fa9..5120818316 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 @@ -17,6 +17,7 @@ package io.element.android.features.lockscreen.impl.unlock import androidx.compose.ui.tooling.preview.PreviewParameterProvider +import io.element.android.features.lockscreen.impl.pin.model.PinEntry open class PinUnlockStateProvider : PreviewParameterProvider { override val values: Sequence @@ -25,6 +26,9 @@ open class PinUnlockStateProvider : PreviewParameterProvider { ) } -fun aPinUnlockState() = PinUnlockState( +fun aPinUnlockState( + pinEntry: PinEntry = PinEntry.empty(4), +) = PinUnlockState( + pinEntry = pinEntry, eventSink = {} ) 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 47027853b4..5631f33e32 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,11 +36,12 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.tooling.preview.PreviewParameter import androidx.compose.ui.unit.dp +import io.element.android.features.lockscreen.impl.pin.model.PinDigit +import io.element.android.features.lockscreen.impl.pin.model.PinEntry import io.element.android.features.lockscreen.impl.unlock.numpad.PinKeypad import io.element.android.libraries.designsystem.atomic.pages.HeaderFooterPage import io.element.android.libraries.designsystem.preview.ElementPreview import io.element.android.libraries.designsystem.preview.PreviewsDayNight -import io.element.android.libraries.designsystem.theme.components.Button import io.element.android.libraries.designsystem.theme.components.Icon import io.element.android.libraries.designsystem.theme.components.Surface import io.element.android.libraries.designsystem.theme.components.Text @@ -53,7 +54,12 @@ fun PinUnlockView( ) { Surface(modifier) { HeaderFooterPage( - header = { PinUnlockHeader(modifier = Modifier.padding(top = 60.dp, bottom = 12.dp)) }, + header = { + PinUnlockHeader( + state = state, + modifier = Modifier.padding(top = 60.dp, bottom = 12.dp) + ) + }, content = { Box( modifier = Modifier @@ -62,7 +68,9 @@ fun PinUnlockView( contentAlignment = Alignment.Center, ) { PinKeypad( - onClick = {} + onClick = { + state.eventSink(PinUnlockEvents.OnPinKeypadPressed(it)) + } ) } } @@ -70,26 +78,15 @@ fun PinUnlockView( } } -@Composable -private fun PinUnlockFooter(state: PinUnlockState) { - Button( - modifier = Modifier.fillMaxWidth(), - text = "Unlock", - onClick = { - state.eventSink(PinUnlockEvents.Unlock) - } - ) -} - @Composable private fun PinDotsRow( + pinEntry: PinEntry, modifier: Modifier = Modifier, ) { Row(modifier, horizontalArrangement = spacedBy(8.dp), verticalAlignment = Alignment.CenterVertically) { - PinDot(isFilled = true) - PinDot(isFilled = true) - PinDot(isFilled = false) - PinDot(isFilled = false) + for (digit in pinEntry.digits) { + PinDot(isFilled = digit is PinDigit.Filled) + } } } @@ -112,6 +109,7 @@ private fun PinDot( @Composable private fun PinUnlockHeader( + state: PinUnlockState, modifier: Modifier = Modifier, ) { Column(modifier, horizontalAlignment = Alignment.CenterHorizontally) { @@ -140,7 +138,7 @@ private fun PinUnlockHeader( color = MaterialTheme.colorScheme.secondary, ) Spacer(Modifier.height(24.dp)) - PinDotsRow() + PinDotsRow(state.pinEntry) } } diff --git a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/unlock/numpad/PinKeypad.kt b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/unlock/numpad/PinKeypad.kt index 44a09ed08f..d22a34b732 100644 --- a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/unlock/numpad/PinKeypad.kt +++ b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/unlock/numpad/PinKeypad.kt @@ -61,25 +61,25 @@ fun PinKeypad( PinKeypadRow( verticalAlignment = verticalAlignment, horizontalArrangement = horizontalArrangement, - models = listOf(PinKeypadModel.Number("1"), PinKeypadModel.Number("2"), PinKeypadModel.Number("3")), + models = listOf(PinKeypadModel.Number('1'), PinKeypadModel.Number('2'), PinKeypadModel.Number('3')), onClick = onClick, ) PinKeypadRow( verticalAlignment = verticalAlignment, horizontalArrangement = horizontalArrangement, - models = listOf(PinKeypadModel.Number("4"), PinKeypadModel.Number("5"), PinKeypadModel.Number("6")), + models = listOf(PinKeypadModel.Number('4'), PinKeypadModel.Number('5'), PinKeypadModel.Number('6')), onClick = onClick, ) PinKeypadRow( verticalAlignment = verticalAlignment, horizontalArrangement = horizontalArrangement, - models = listOf(PinKeypadModel.Number("7"), PinKeypadModel.Number("8"), PinKeypadModel.Number("9")), + models = listOf(PinKeypadModel.Number('7'), PinKeypadModel.Number('8'), PinKeypadModel.Number('9')), onClick = onClick, ) PinKeypadRow( verticalAlignment = verticalAlignment, horizontalArrangement = horizontalArrangement, - models = listOf(PinKeypadModel.Empty, PinKeypadModel.Number("0"), PinKeypadModel.Back), + models = listOf(PinKeypadModel.Empty, PinKeypadModel.Number('0'), PinKeypadModel.Back), onClick = onClick, ) } @@ -114,7 +114,7 @@ private fun PinKeypadRow( PinKeyBadDigitButton( size = 80.dp, modifier = commonModifier, - digit = model.number, + digit = model.number.toString(), onClick = { onClick(model) }, ) } diff --git a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/unlock/numpad/PinKeypadModel.kt b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/unlock/numpad/PinKeypadModel.kt index 4ea42e7f42..f1430dcaa5 100644 --- a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/unlock/numpad/PinKeypadModel.kt +++ b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/unlock/numpad/PinKeypadModel.kt @@ -22,5 +22,5 @@ import androidx.compose.runtime.Immutable sealed interface PinKeypadModel { data object Empty : PinKeypadModel data object Back : PinKeypadModel - data class Number(val number: String) : PinKeypadModel + data class Number(val number: Char) : PinKeypadModel } From a6060ab4ab345a29e170caf60be14e603561ac68 Mon Sep 17 00:00:00 2001 From: ganfra Date: Fri, 20 Oct 2023 16:35:54 +0200 Subject: [PATCH 05/22] Pin unlock : fix some ui --- .../lockscreen/impl/unlock/PinUnlockView.kt | 8 +++- .../impl/unlock/numpad/PinKeypad.kt | 40 ++++++++++++------- 2 files changed, 31 insertions(+), 17 deletions(-) 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 5631f33e32..686790afcb 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 @@ -22,6 +22,7 @@ import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding @@ -65,12 +66,15 @@ fun PinUnlockView( modifier = Modifier .padding(top = 40.dp) .fillMaxWidth(), - contentAlignment = Alignment.Center, ) { PinKeypad( onClick = { state.eventSink(PinUnlockEvents.OnPinKeypadPressed(it)) - } + }, + horizontalArrangement = spacedBy(24.dp, Alignment.CenterHorizontally), + verticalArrangement = spacedBy(16.dp, Alignment.CenterVertically), + horizontalAlignment = Alignment.CenterHorizontally, + verticalAlignment = Alignment.CenterVertically, ) } } diff --git a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/unlock/numpad/PinKeypad.kt b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/unlock/numpad/PinKeypad.kt index d22a34b732..39656a8d56 100644 --- a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/unlock/numpad/PinKeypad.kt +++ b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/unlock/numpad/PinKeypad.kt @@ -17,18 +17,21 @@ package io.element.android.features.lockscreen.impl.unlock.numpad import androidx.compose.foundation.background +import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.BoxScope import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.size import androidx.compose.foundation.shape.CircleShape import androidx.compose.material.icons.Icons import androidx.compose.material.icons.automirrored.filled.Backspace import androidx.compose.material3.Button import androidx.compose.material3.ButtonDefaults -import androidx.compose.material3.IconButton import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment @@ -96,7 +99,7 @@ private fun PinKeypadRow( Row( horizontalArrangement = horizontalArrangement, verticalAlignment = verticalAlignment, - modifier = modifier, + modifier = modifier.fillMaxWidth(), ) { val commonModifier = Modifier.size(80.dp) for (model in models) { @@ -123,6 +126,22 @@ private fun PinKeypadRow( } } +@Composable +private fun PinKeypadButton( + onClick: () -> Unit, + modifier: Modifier = Modifier, + content: @Composable BoxScope.() -> Unit, +) { + Box( + contentAlignment = Alignment.Center, + modifier = modifier + .clip(CircleShape) + .background(color = ElementTheme.colors.bgSubtlePrimary) + .clickable(onClick = onClick), + content = content + ) +} + @Composable private fun PinKeyBadDigitButton( digit: String, @@ -130,15 +149,8 @@ private fun PinKeyBadDigitButton( onClick: (String) -> Unit, modifier: Modifier = Modifier, ) { - Button( - colors = ButtonDefaults.buttonColors( - containerColor = ElementTheme.colors.bgSubtlePrimary, - contentColor = Color.Transparent, - ), - shape = CircleShape, - contentPadding = PaddingValues(0.dp), - modifier = modifier - .clip(CircleShape), + PinKeypadButton( + modifier = modifier, onClick = { onClick(digit) } ) { val fontSize = 80.dp.toSp() / 2 @@ -158,10 +170,8 @@ private fun PinKeypadBackButton( onClick: () -> Unit, modifier: Modifier = Modifier, ) { - IconButton( - modifier = modifier - .clip(CircleShape) - .background(color = Color.Transparent, shape = CircleShape), + PinKeypadButton( + modifier = modifier, onClick = onClick, ) { Icon( From f12de0ce1d57c650f4f526897639b8e6af1f5db5 Mon Sep 17 00:00:00 2001 From: ganfra Date: Fri, 20 Oct 2023 17:57:29 +0200 Subject: [PATCH 06/22] Pin unlock : best effort for small height --- .../lockscreen/impl/unlock/PinUnlockView.kt | 122 +++++++++++++++--- 1 file changed, 101 insertions(+), 21 deletions(-) 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 686790afcb..4f4f9be2df 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 @@ -17,16 +17,20 @@ package io.element.android.features.lockscreen.impl.unlock import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Arrangement.spacedBy import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.BoxWithConstraints import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxHeight import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.systemBarsPadding import androidx.compose.foundation.shape.CircleShape import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Lock @@ -34,18 +38,20 @@ import androidx.compose.material3.MaterialTheme import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.tooling.preview.PreviewParameter import androidx.compose.ui.unit.dp +import io.element.android.features.lockscreen.impl.R import io.element.android.features.lockscreen.impl.pin.model.PinDigit import io.element.android.features.lockscreen.impl.pin.model.PinEntry import io.element.android.features.lockscreen.impl.unlock.numpad.PinKeypad -import io.element.android.libraries.designsystem.atomic.pages.HeaderFooterPage import io.element.android.libraries.designsystem.preview.ElementPreview import io.element.android.libraries.designsystem.preview.PreviewsDayNight import io.element.android.libraries.designsystem.theme.components.Icon import io.element.android.libraries.designsystem.theme.components.Surface import io.element.android.libraries.designsystem.theme.components.Text +import io.element.android.libraries.designsystem.theme.components.TextButton import io.element.android.libraries.theme.ElementTheme @Composable @@ -54,31 +60,95 @@ fun PinUnlockView( modifier: Modifier = Modifier, ) { Surface(modifier) { - HeaderFooterPage( - header = { + BoxWithConstraints { + val commonModifier = Modifier + .fillMaxSize() + .systemBarsPadding() + .padding(all = 20.dp) + + val header = @Composable { PinUnlockHeader( state = state, modifier = Modifier.padding(top = 60.dp, bottom = 12.dp) ) - }, - content = { - Box( - modifier = Modifier - .padding(top = 40.dp) - .fillMaxWidth(), - ) { - PinKeypad( - onClick = { - state.eventSink(PinUnlockEvents.OnPinKeypadPressed(it)) - }, - horizontalArrangement = spacedBy(24.dp, Alignment.CenterHorizontally), - verticalArrangement = spacedBy(16.dp, Alignment.CenterVertically), - horizontalAlignment = Alignment.CenterHorizontally, - verticalAlignment = Alignment.CenterVertically, - ) - } } - ) + val footer = @Composable { + PinUnlockFooter() + } + val content = @Composable { + PinKeypad( + onClick = { + state.eventSink(PinUnlockEvents.OnPinKeypadPressed(it)) + }, + horizontalArrangement = spacedBy(24.dp, Alignment.CenterHorizontally), + verticalArrangement = spacedBy(16.dp, Alignment.CenterVertically), + horizontalAlignment = Alignment.CenterHorizontally, + verticalAlignment = Alignment.CenterVertically, + ) + } + if (maxHeight < 600.dp) { + PinUnlockCompactView( + header = header, + footer = footer, + content = content, + modifier = commonModifier, + ) + } else { + PinUnlockExpandedView( + header = header, + footer = footer, + content = content, + modifier = commonModifier, + ) + } + } + } +} + +@Composable +fun PinUnlockCompactView( + modifier: Modifier = Modifier, + header: @Composable () -> Unit, + footer: @Composable () -> Unit, + content: @Composable () -> Unit, +) { + Row(modifier = modifier) { + Column(Modifier.weight(1f)) { + header() + Spacer(modifier = Modifier.height(24.dp)) + footer() + } + Box( + modifier = Modifier + .weight(1f) + .fillMaxHeight(), + contentAlignment = Alignment.Center, + ) { + content() + } + } +} + +@Composable +fun PinUnlockExpandedView( + modifier: Modifier = Modifier, + header: @Composable () -> Unit, + footer: @Composable () -> Unit, + content: @Composable () -> Unit, +) { + Column( + modifier = modifier, + ) { + header() + Box( + modifier = Modifier + .weight(1f) + .fillMaxWidth() + .padding(top = 40.dp), + ) { + content() + } + footer() } } @@ -146,6 +216,16 @@ private fun PinUnlockHeader( } } +@Composable +private fun PinUnlockFooter( + modifier: Modifier = Modifier, +) { + Row(modifier.fillMaxWidth(), horizontalArrangement = Arrangement.SpaceAround) { + TextButton(text = "Use biometric", onClick = { }) + TextButton(text = stringResource(id = R.string.screen_app_lock_forgot_pin), onClick = { }) + } +} + @Composable @PreviewsDayNight internal fun PinUnlockViewPreview(@PreviewParameter(PinUnlockStateProvider::class) state: PinUnlockState) { From 67d4271f4d81e701517de1b61ac4399d88c571de Mon Sep 17 00:00:00 2001 From: ganfra Date: Fri, 20 Oct 2023 18:52:56 +0200 Subject: [PATCH 07/22] Pin unlock : add signout prompt --- features/lockscreen/impl/build.gradle.kts | 1 + .../impl/pin/DefaultPinCodeManager.kt | 2 +- .../lockscreen/impl/pin/PinCodeManager.kt | 2 +- .../lockscreen/impl/pin/model/PinEntry.kt | 3 +- .../lockscreen/impl/unlock/PinUnlockEvents.kt | 1 + .../impl/unlock/PinUnlockPresenter.kt | 19 ++++++++-- .../lockscreen/impl/unlock/PinUnlockState.kt | 7 +++- .../impl/unlock/PinUnlockStateProvider.kt | 10 ++++++ .../lockscreen/impl/unlock/PinUnlockView.kt | 36 +++++++++++++++++-- .../impl/PreferencesFeatureFlagProvider.kt | 5 +-- 10 files changed, 74 insertions(+), 12 deletions(-) diff --git a/features/lockscreen/impl/build.gradle.kts b/features/lockscreen/impl/build.gradle.kts index 028d8bee3c..8daeb2178c 100644 --- a/features/lockscreen/impl/build.gradle.kts +++ b/features/lockscreen/impl/build.gradle.kts @@ -40,6 +40,7 @@ dependencies { implementation(projects.libraries.designsystem) implementation(projects.libraries.featureflag.api) implementation(projects.libraries.cryptography.api) + implementation(projects.libraries.uiStrings) testImplementation(libs.test.junit) testImplementation(libs.coroutines.test) diff --git a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/pin/DefaultPinCodeManager.kt b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/pin/DefaultPinCodeManager.kt index 1f7439301c..f5848a9d40 100644 --- a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/pin/DefaultPinCodeManager.kt +++ b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/pin/DefaultPinCodeManager.kt @@ -37,7 +37,7 @@ class DefaultPinCodeManager @Inject constructor( return pinCodeStore.hasPinCode() } - override suspend fun SetupPinCode(pinCode: String) { + override suspend fun setupPinCode(pinCode: String) { val secretKey = secretKeyProvider.getOrCreateKey(SECRET_KEY_ALIAS) val encryptedPinCode = encryptionDecryptionService.encrypt(secretKey, pinCode.toByteArray()).toBase64() pinCodeStore.saveEncryptedPinCode(encryptedPinCode) diff --git a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/pin/PinCodeManager.kt b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/pin/PinCodeManager.kt index 49b6141665..09197c3eb1 100644 --- a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/pin/PinCodeManager.kt +++ b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/pin/PinCodeManager.kt @@ -30,7 +30,7 @@ interface PinCodeManager { * Creates a new encrypted pin code. * @param pinCode the clear pin code to create */ - suspend fun SetupPinCode(pinCode: String) + suspend fun setupPinCode(pinCode: String) /** * @return true if the pin code is correct. diff --git a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/pin/model/PinEntry.kt b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/pin/model/PinEntry.kt index 92dda869a6..76331bd38f 100644 --- a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/pin/model/PinEntry.kt +++ b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/pin/model/PinEntry.kt @@ -18,10 +18,11 @@ package io.element.android.features.lockscreen.impl.pin.model import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.toPersistentList +import java.io.Serializable data class PinEntry( val digits: ImmutableList, -) { +): Serializable { companion object { fun empty(size: Int): PinEntry { diff --git a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/unlock/PinUnlockEvents.kt b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/unlock/PinUnlockEvents.kt index 8dddd40e8a..a90b6cb702 100644 --- a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/unlock/PinUnlockEvents.kt +++ b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/unlock/PinUnlockEvents.kt @@ -21,4 +21,5 @@ import io.element.android.features.lockscreen.impl.unlock.numpad.PinKeypadModel sealed interface PinUnlockEvents { data class OnPinKeypadPressed(val pinKeypadModel: PinKeypadModel) : PinUnlockEvents data object Unlock : PinUnlockEvents + data object OnForgetPin : PinUnlockEvents } 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 d673ad7966..d6b77f799c 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 @@ -18,8 +18,9 @@ package io.element.android.features.lockscreen.impl.unlock import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableIntStateOf import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember +import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.runtime.setValue import io.element.android.features.lockscreen.api.LockScreenStateService import io.element.android.features.lockscreen.impl.pin.model.PinEntry @@ -36,10 +37,18 @@ class PinUnlockPresenter @Inject constructor( @Composable override fun present(): PinUnlockState { - - var pinEntry by remember { + var pinEntry by rememberSaveable { mutableStateOf(PinEntry.empty(4)) } + var remainingAttempts by rememberSaveable { + mutableIntStateOf(3) + } + var showWrongPinTitle by rememberSaveable { + mutableStateOf(false) + } + var showSignOutPrompt by rememberSaveable { + mutableStateOf(false) + } fun handleEvents(event: PinUnlockEvents) { when (event) { @@ -50,10 +59,14 @@ class PinUnlockPresenter @Inject constructor( coroutineScope.launch { pinStateService.unlock() } } } + PinUnlockEvents.OnForgetPin -> showSignOutPrompt = true } } return PinUnlockState( pinEntry = pinEntry, + showWrongPinTitle = showWrongPinTitle, + remainingAttempts = remainingAttempts, + showSignOutPrompt = showSignOutPrompt, eventSink = ::handleEvents ) } 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 69d3213c7e..1787fb8e8b 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 @@ -20,5 +20,10 @@ import io.element.android.features.lockscreen.impl.pin.model.PinEntry data class PinUnlockState( val pinEntry: PinEntry, + val showWrongPinTitle: Boolean, + val remainingAttempts: Int, + val showSignOutPrompt: Boolean, val eventSink: (PinUnlockEvents) -> Unit -) +) { + val isSignOutPromptCancellable = remainingAttempts > 0 +} 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 5120818316..4f269d2f5a 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 @@ -23,12 +23,22 @@ open class PinUnlockStateProvider : PreviewParameterProvider { override val values: Sequence get() = sequenceOf( aPinUnlockState(), + aPinUnlockState(pinEntry = PinEntry.empty(4).fillWith("12")), + aPinUnlockState(showWrongPinTitle = true), + aPinUnlockState(showSignOutPrompt = true), + aPinUnlockState(showSignOutPrompt = true, remainingAttempts = 0), ) } fun aPinUnlockState( pinEntry: PinEntry = PinEntry.empty(4), + remainingAttempts: Int = 3, + showWrongPinTitle: Boolean = false, + showSignOutPrompt: Boolean = false, ) = PinUnlockState( pinEntry = pinEntry, + showWrongPinTitle = showWrongPinTitle, + remainingAttempts = remainingAttempts, + showSignOutPrompt = showSignOutPrompt, eventSink = {} ) 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 4f4f9be2df..19cb866a5c 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 @@ -38,6 +38,7 @@ import androidx.compose.material3.MaterialTheme import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +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.PreviewParameter @@ -46,6 +47,8 @@ import io.element.android.features.lockscreen.impl.R import io.element.android.features.lockscreen.impl.pin.model.PinDigit import io.element.android.features.lockscreen.impl.pin.model.PinEntry import io.element.android.features.lockscreen.impl.unlock.numpad.PinKeypad +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 import io.element.android.libraries.designsystem.preview.PreviewsDayNight import io.element.android.libraries.designsystem.theme.components.Icon @@ -53,6 +56,7 @@ import io.element.android.libraries.designsystem.theme.components.Surface import io.element.android.libraries.designsystem.theme.components.Text import io.element.android.libraries.designsystem.theme.components.TextButton import io.element.android.libraries.theme.ElementTheme +import io.element.android.libraries.ui.strings.CommonStrings @Composable fun PinUnlockView( @@ -101,6 +105,22 @@ fun PinUnlockView( modifier = commonModifier, ) } + if (state.showSignOutPrompt) { + if (state.isSignOutPromptCancellable) { + ConfirmationDialog( + title = stringResource(id = R.string.screen_app_lock_signout_alert_title), + content = stringResource(id = R.string.screen_app_lock_signout_alert_message), + onSubmitClicked = {}, + onDismiss = {}, + ) + } else { + ErrorDialog( + title = stringResource(id = R.string.screen_app_lock_signout_alert_title), + content = stringResource(id = R.string.screen_app_lock_signout_alert_message), + onDismiss = {}, + ) + } + } } } } @@ -196,7 +216,7 @@ private fun PinUnlockHeader( ) Spacer(modifier = Modifier.height(16.dp)) Text( - text = "Enter your PIN", + text = stringResource(id = CommonStrings.common_enter_your_pin), modifier = Modifier .fillMaxWidth(), textAlign = TextAlign.Center, @@ -204,12 +224,22 @@ private fun PinUnlockHeader( color = MaterialTheme.colorScheme.primary, ) Spacer(Modifier.height(8.dp)) + val subtitle = if (state.showWrongPinTitle) { + pluralStringResource(id = R.plurals.screen_app_lock_subtitle_wrong_pin, count = state.remainingAttempts, state.remainingAttempts) + } else { + stringResource(id = R.string.screen_app_lock_subtitle) + } + val subtitleColor = if (state.showWrongPinTitle) { + MaterialTheme.colorScheme.error + } else { + MaterialTheme.colorScheme.secondary + } Text( - text = "You have 3 attempts to unlock", + text = subtitle, modifier = Modifier.fillMaxWidth(), textAlign = TextAlign.Center, style = ElementTheme.typography.fontBodyMdRegular, - color = MaterialTheme.colorScheme.secondary, + color = subtitleColor, ) Spacer(Modifier.height(24.dp)) PinDotsRow(state.pinEntry) diff --git a/libraries/featureflag/impl/src/main/kotlin/io/element/android/libraries/featureflag/impl/PreferencesFeatureFlagProvider.kt b/libraries/featureflag/impl/src/main/kotlin/io/element/android/libraries/featureflag/impl/PreferencesFeatureFlagProvider.kt index ddffdebd34..23ff977da2 100644 --- a/libraries/featureflag/impl/src/main/kotlin/io/element/android/libraries/featureflag/impl/PreferencesFeatureFlagProvider.kt +++ b/libraries/featureflag/impl/src/main/kotlin/io/element/android/libraries/featureflag/impl/PreferencesFeatureFlagProvider.kt @@ -24,6 +24,7 @@ import androidx.datastore.preferences.core.edit import androidx.datastore.preferences.preferencesDataStore import io.element.android.libraries.di.ApplicationContext import io.element.android.libraries.featureflag.api.Feature +import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.first import kotlinx.coroutines.flow.map import javax.inject.Inject @@ -44,10 +45,10 @@ class PreferencesFeatureFlagProvider @Inject constructor(@ApplicationContext con } } - override suspend fun isFeatureEnabled(feature: Feature): Boolean { + override fun isFeatureEnabled(feature: Feature): Flow { return store.data.map { prefs -> prefs[booleanPreferencesKey(feature.key)] ?: feature.defaultValue - }.first() + } } override fun hasFeature(feature: Feature): Boolean { From 4a24e1cd7e2fc2988eee9a7e22ff288edef8385b Mon Sep 17 00:00:00 2001 From: ganfra Date: Fri, 20 Oct 2023 20:25:54 +0200 Subject: [PATCH 08/22] Pin unlock : better PinKeypad management --- .../lockscreen/impl/unlock/PinUnlockView.kt | 16 +++---- .../impl/unlock/numpad/PinKeypad.kt | 42 ++++++++++++++----- 2 files changed, 39 insertions(+), 19 deletions(-) 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 19cb866a5c..2fff711131 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 @@ -21,6 +21,7 @@ import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Arrangement.spacedBy import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.BoxWithConstraints +import androidx.compose.foundation.layout.BoxWithConstraintsScope import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer @@ -79,15 +80,14 @@ fun PinUnlockView( val footer = @Composable { PinUnlockFooter() } - val content = @Composable { + val content = @Composable { constraints: BoxWithConstraintsScope -> PinKeypad( onClick = { state.eventSink(PinUnlockEvents.OnPinKeypadPressed(it)) }, - horizontalArrangement = spacedBy(24.dp, Alignment.CenterHorizontally), - verticalArrangement = spacedBy(16.dp, Alignment.CenterVertically), + maxWidth = constraints.maxWidth, + maxHeight = constraints.maxHeight, horizontalAlignment = Alignment.CenterHorizontally, - verticalAlignment = Alignment.CenterVertically, ) } if (maxHeight < 600.dp) { @@ -130,7 +130,7 @@ fun PinUnlockCompactView( modifier: Modifier = Modifier, header: @Composable () -> Unit, footer: @Composable () -> Unit, - content: @Composable () -> Unit, + content: @Composable BoxWithConstraintsScope.() -> Unit, ) { Row(modifier = modifier) { Column(Modifier.weight(1f)) { @@ -138,7 +138,7 @@ fun PinUnlockCompactView( Spacer(modifier = Modifier.height(24.dp)) footer() } - Box( + BoxWithConstraints( modifier = Modifier .weight(1f) .fillMaxHeight(), @@ -154,13 +154,13 @@ fun PinUnlockExpandedView( modifier: Modifier = Modifier, header: @Composable () -> Unit, footer: @Composable () -> Unit, - content: @Composable () -> Unit, + content: @Composable BoxWithConstraintsScope.() -> Unit, ) { Column( modifier = modifier, ) { header() - Box( + BoxWithConstraints( modifier = Modifier .weight(1f) .fillMaxWidth() diff --git a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/unlock/numpad/PinKeypad.kt b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/unlock/numpad/PinKeypad.kt index 39656a8d56..ee8adb19b2 100644 --- a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/unlock/numpad/PinKeypad.kt +++ b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/unlock/numpad/PinKeypad.kt @@ -19,10 +19,11 @@ package io.element.android.features.lockscreen.impl.unlock.numpad import androidx.compose.foundation.background import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Arrangement.spacedBy import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.BoxScope +import androidx.compose.foundation.layout.BoxWithConstraints import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxWidth @@ -30,56 +31,68 @@ import androidx.compose.foundation.layout.size import androidx.compose.foundation.shape.CircleShape import androidx.compose.material.icons.Icons import androidx.compose.material.icons.automirrored.filled.Backspace -import androidx.compose.material3.Button -import androidx.compose.material3.ButtonDefaults import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip -import androidx.compose.ui.graphics.Color import androidx.compose.ui.unit.Dp +import androidx.compose.ui.unit.coerceAtMost import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp +import androidx.compose.ui.unit.times import io.element.android.libraries.designsystem.preview.ElementPreview import io.element.android.libraries.designsystem.preview.PreviewsDayNight import io.element.android.libraries.designsystem.text.toSp import io.element.android.libraries.designsystem.theme.components.Icon import io.element.android.libraries.theme.ElementTheme +private val spaceBetweenPinKey = 8.dp +private val maxSizePinKey = 80.dp + @Composable fun PinKeypad( onClick: (PinKeypadModel) -> Unit, + maxWidth: Dp, + maxHeight: Dp, modifier: Modifier = Modifier, - verticalArrangement: Arrangement.Vertical = Arrangement.Top, verticalAlignment: Alignment.Vertical = Alignment.Top, - horizontalArrangement: Arrangement.Horizontal = Arrangement.Start, horizontalAlignment: Alignment.Horizontal = Alignment.Start, ) { + val pinKeyMaxWidth = ((maxWidth - 2 * spaceBetweenPinKey) / 3).coerceAtMost(maxSizePinKey) + val pinKeyMaxHeight = ((maxHeight - 3 * spaceBetweenPinKey) / 4).coerceAtMost(maxSizePinKey) + val pinKeySize = if (pinKeyMaxWidth < pinKeyMaxHeight) pinKeyMaxWidth else pinKeyMaxHeight + + val horizontalArrangement = spacedBy(spaceBetweenPinKey, Alignment.CenterHorizontally) + val verticalArrangement = spacedBy(spaceBetweenPinKey, Alignment.CenterVertically) Column( modifier = modifier, verticalArrangement = verticalArrangement, horizontalAlignment = horizontalAlignment, ) { PinKeypadRow( + pinKeySize = pinKeySize, verticalAlignment = verticalAlignment, horizontalArrangement = horizontalArrangement, models = listOf(PinKeypadModel.Number('1'), PinKeypadModel.Number('2'), PinKeypadModel.Number('3')), onClick = onClick, ) PinKeypadRow( + pinKeySize = pinKeySize, verticalAlignment = verticalAlignment, horizontalArrangement = horizontalArrangement, models = listOf(PinKeypadModel.Number('4'), PinKeypadModel.Number('5'), PinKeypadModel.Number('6')), onClick = onClick, ) PinKeypadRow( + pinKeySize = pinKeySize, verticalAlignment = verticalAlignment, horizontalArrangement = horizontalArrangement, models = listOf(PinKeypadModel.Number('7'), PinKeypadModel.Number('8'), PinKeypadModel.Number('9')), onClick = onClick, ) PinKeypadRow( + pinKeySize = pinKeySize, verticalAlignment = verticalAlignment, horizontalArrangement = horizontalArrangement, models = listOf(PinKeypadModel.Empty, PinKeypadModel.Number('0'), PinKeypadModel.Back), @@ -92,6 +105,7 @@ fun PinKeypad( private fun PinKeypadRow( models: List, onClick: (PinKeypadModel) -> Unit, + pinKeySize: Dp, modifier: Modifier = Modifier, horizontalArrangement: Arrangement.Horizontal = Arrangement.Start, verticalAlignment: Alignment.Vertical = Alignment.Top, @@ -101,7 +115,7 @@ private fun PinKeypadRow( verticalAlignment = verticalAlignment, modifier = modifier.fillMaxWidth(), ) { - val commonModifier = Modifier.size(80.dp) + val commonModifier = Modifier.size(pinKeySize) for (model in models) { when (model) { is PinKeypadModel.Empty -> { @@ -115,7 +129,7 @@ private fun PinKeypadRow( } is PinKeypadModel.Number -> { PinKeyBadDigitButton( - size = 80.dp, + size = pinKeySize, modifier = commonModifier, digit = model.number.toString(), onClick = { onClick(model) }, @@ -153,7 +167,7 @@ private fun PinKeyBadDigitButton( modifier = modifier, onClick = { onClick(digit) } ) { - val fontSize = 80.dp.toSp() / 2 + val fontSize = size.toSp() / 2 val originalFont = ElementTheme.typography.fontHeadingXlBold val ratio = fontSize.value / originalFont.fontSize.value val lineHeight = originalFont.lineHeight * ratio @@ -183,9 +197,15 @@ private fun PinKeypadBackButton( @Composable @PreviewsDayNight -fun PinKeypad() { +fun PinKeypadPreview() { ElementPreview { - PinKeypad(onClick = {}) + BoxWithConstraints { + PinKeypad( + maxWidth = maxWidth, + maxHeight = maxHeight, + onClick = {} + ) + } } } From fd63220ee08abdd73da1578d87da5ed0d5d68259 Mon Sep 17 00:00:00 2001 From: ganfra Date: Fri, 20 Oct 2023 20:26:04 +0200 Subject: [PATCH 09/22] Fix compilation --- .../android/features/lockscreen/impl/pin/model/PinEntry.kt | 3 +-- .../features/lockscreen/impl/unlock/PinUnlockPresenter.kt | 3 ++- .../featureflag/impl/PreferencesFeatureFlagProvider.kt | 5 ++--- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/pin/model/PinEntry.kt b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/pin/model/PinEntry.kt index 76331bd38f..92dda869a6 100644 --- a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/pin/model/PinEntry.kt +++ b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/pin/model/PinEntry.kt @@ -18,11 +18,10 @@ package io.element.android.features.lockscreen.impl.pin.model import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.toPersistentList -import java.io.Serializable data class PinEntry( val digits: ImmutableList, -): Serializable { +) { companion object { fun empty(size: Int): PinEntry { 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 d6b77f799c..a6f06158d4 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 @@ -20,6 +20,7 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableIntStateOf import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.runtime.setValue import io.element.android.features.lockscreen.api.LockScreenStateService @@ -37,7 +38,7 @@ class PinUnlockPresenter @Inject constructor( @Composable override fun present(): PinUnlockState { - var pinEntry by rememberSaveable { + var pinEntry by remember { mutableStateOf(PinEntry.empty(4)) } var remainingAttempts by rememberSaveable { diff --git a/libraries/featureflag/impl/src/main/kotlin/io/element/android/libraries/featureflag/impl/PreferencesFeatureFlagProvider.kt b/libraries/featureflag/impl/src/main/kotlin/io/element/android/libraries/featureflag/impl/PreferencesFeatureFlagProvider.kt index 23ff977da2..ddffdebd34 100644 --- a/libraries/featureflag/impl/src/main/kotlin/io/element/android/libraries/featureflag/impl/PreferencesFeatureFlagProvider.kt +++ b/libraries/featureflag/impl/src/main/kotlin/io/element/android/libraries/featureflag/impl/PreferencesFeatureFlagProvider.kt @@ -24,7 +24,6 @@ import androidx.datastore.preferences.core.edit import androidx.datastore.preferences.preferencesDataStore import io.element.android.libraries.di.ApplicationContext import io.element.android.libraries.featureflag.api.Feature -import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.first import kotlinx.coroutines.flow.map import javax.inject.Inject @@ -45,10 +44,10 @@ class PreferencesFeatureFlagProvider @Inject constructor(@ApplicationContext con } } - override fun isFeatureEnabled(feature: Feature): Flow { + override suspend fun isFeatureEnabled(feature: Feature): Boolean { return store.data.map { prefs -> prefs[booleanPreferencesKey(feature.key)] ?: feature.defaultValue - } + }.first() } override fun hasFeature(feature: Feature): Boolean { From ab13c5d696c6aef5b414148d3e8c0979bb3b9fd8 Mon Sep 17 00:00:00 2001 From: ganfra Date: Fri, 20 Oct 2023 20:38:27 +0200 Subject: [PATCH 10/22] Fix some warnings --- .../lockscreen/impl/setup/SetupPinPresenter.kt | 2 +- .../features/lockscreen/impl/setup/SetupPinState.kt | 3 +-- .../lockscreen/impl/setup/SetupPinStateProvider.kt | 2 +- .../features/lockscreen/impl/setup/SetupPinView.kt | 6 +++--- .../{CreatePinFailure.kt => SetupPinFailure.kt} | 0 .../impl/state/DefaultLockScreenStateService.kt | 2 +- .../features/lockscreen/impl/unlock/PinUnlockView.kt | 4 ++-- .../lockscreen/impl/unlock/numpad/PinKeypad.kt | 12 +++++++----- 8 files changed, 16 insertions(+), 15 deletions(-) rename features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/setup/validation/{CreatePinFailure.kt => SetupPinFailure.kt} (100%) diff --git a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/setup/SetupPinPresenter.kt b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/setup/SetupPinPresenter.kt index 8561e5333c..6a880a6967 100644 --- a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/setup/SetupPinPresenter.kt +++ b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/setup/SetupPinPresenter.kt @@ -95,7 +95,7 @@ class SetupPinPresenter @Inject constructor( choosePinEntry = choosePinEntry, confirmPinEntry = confirmPinEntry, isConfirmationStep = isConfirmationStep, - SetupPinFailure = setupPinFailure, + setupPinFailure = setupPinFailure, appName = buildMeta.applicationName, eventSink = ::handleEvents ) diff --git a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/setup/SetupPinState.kt b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/setup/SetupPinState.kt index 7823b1e39f..3ae4a2c85b 100644 --- a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/setup/SetupPinState.kt +++ b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/setup/SetupPinState.kt @@ -23,11 +23,10 @@ data class SetupPinState( val choosePinEntry: PinEntry, val confirmPinEntry: PinEntry, val isConfirmationStep: Boolean, - val SetupPinFailure: SetupPinFailure?, + val setupPinFailure: SetupPinFailure?, val appName: String, val eventSink: (SetupPinEvents) -> Unit ) { - val pinSize = choosePinEntry.size val activePinEntry = if (isConfirmationStep) { confirmPinEntry } else { diff --git a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/setup/SetupPinStateProvider.kt b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/setup/SetupPinStateProvider.kt index 37a232dc11..1a177b4a83 100644 --- a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/setup/SetupPinStateProvider.kt +++ b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/setup/SetupPinStateProvider.kt @@ -54,7 +54,7 @@ fun aSetupPinState( choosePinEntry = choosePinEntry, confirmPinEntry = confirmPinEntry, isConfirmationStep = isConfirmationStep, - SetupPinFailure = creationFailure, + setupPinFailure = creationFailure, appName = "Element", eventSink = {} ) diff --git a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/setup/SetupPinView.kt b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/setup/SetupPinView.kt index 18be5e14b4..b8f40b06d0 100644 --- a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/setup/SetupPinView.kt +++ b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/setup/SetupPinView.kt @@ -114,11 +114,11 @@ private fun SetupPinContent( .padding(top = 36.dp) .fillMaxWidth() ) - if (state.SetupPinFailure != null) { + if (state.setupPinFailure != null) { ErrorDialog( modifier = modifier, - title = state.SetupPinFailure.title(), - content = state.SetupPinFailure.content(), + title = state.setupPinFailure.title(), + content = state.setupPinFailure.content(), onDismiss = { state.eventSink(SetupPinEvents.ClearFailure) } diff --git a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/setup/validation/CreatePinFailure.kt b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/setup/validation/SetupPinFailure.kt similarity index 100% rename from features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/setup/validation/CreatePinFailure.kt rename to features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/setup/validation/SetupPinFailure.kt diff --git a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/state/DefaultLockScreenStateService.kt b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/state/DefaultLockScreenStateService.kt index a071de06e9..f2e037b111 100644 --- a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/state/DefaultLockScreenStateService.kt +++ b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/state/DefaultLockScreenStateService.kt @@ -30,7 +30,7 @@ import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.launch import javax.inject.Inject -private const val GRACE_PERIOD_IN_MILLIS = 90 * 1000L +//private const val GRACE_PERIOD_IN_MILLIS = 90 * 1000L @SingleIn(AppScope::class) @ContributesBinding(AppScope::class) 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 2fff711131..be43d6cf32 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 @@ -127,9 +127,9 @@ fun PinUnlockView( @Composable fun PinUnlockCompactView( - modifier: Modifier = Modifier, header: @Composable () -> Unit, footer: @Composable () -> Unit, + modifier: Modifier = Modifier, content: @Composable BoxWithConstraintsScope.() -> Unit, ) { Row(modifier = modifier) { @@ -151,9 +151,9 @@ fun PinUnlockCompactView( @Composable fun PinUnlockExpandedView( - modifier: Modifier = Modifier, header: @Composable () -> Unit, footer: @Composable () -> Unit, + modifier: Modifier = Modifier, content: @Composable BoxWithConstraintsScope.() -> Unit, ) { Column( diff --git a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/unlock/numpad/PinKeypad.kt b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/unlock/numpad/PinKeypad.kt index ee8adb19b2..8a6230c725 100644 --- a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/unlock/numpad/PinKeypad.kt +++ b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/unlock/numpad/PinKeypad.kt @@ -46,6 +46,8 @@ import io.element.android.libraries.designsystem.preview.PreviewsDayNight import io.element.android.libraries.designsystem.text.toSp import io.element.android.libraries.designsystem.theme.components.Icon import io.element.android.libraries.theme.ElementTheme +import kotlinx.collections.immutable.ImmutableList +import kotlinx.collections.immutable.persistentListOf private val spaceBetweenPinKey = 8.dp private val maxSizePinKey = 80.dp @@ -74,28 +76,28 @@ fun PinKeypad( pinKeySize = pinKeySize, verticalAlignment = verticalAlignment, horizontalArrangement = horizontalArrangement, - models = listOf(PinKeypadModel.Number('1'), PinKeypadModel.Number('2'), PinKeypadModel.Number('3')), + models = persistentListOf(PinKeypadModel.Number('1'), PinKeypadModel.Number('2'), PinKeypadModel.Number('3')), onClick = onClick, ) PinKeypadRow( pinKeySize = pinKeySize, verticalAlignment = verticalAlignment, horizontalArrangement = horizontalArrangement, - models = listOf(PinKeypadModel.Number('4'), PinKeypadModel.Number('5'), PinKeypadModel.Number('6')), + models = persistentListOf(PinKeypadModel.Number('4'), PinKeypadModel.Number('5'), PinKeypadModel.Number('6')), onClick = onClick, ) PinKeypadRow( pinKeySize = pinKeySize, verticalAlignment = verticalAlignment, horizontalArrangement = horizontalArrangement, - models = listOf(PinKeypadModel.Number('7'), PinKeypadModel.Number('8'), PinKeypadModel.Number('9')), + models = persistentListOf(PinKeypadModel.Number('7'), PinKeypadModel.Number('8'), PinKeypadModel.Number('9')), onClick = onClick, ) PinKeypadRow( pinKeySize = pinKeySize, verticalAlignment = verticalAlignment, horizontalArrangement = horizontalArrangement, - models = listOf(PinKeypadModel.Empty, PinKeypadModel.Number('0'), PinKeypadModel.Back), + models = persistentListOf(PinKeypadModel.Empty, PinKeypadModel.Number('0'), PinKeypadModel.Back), onClick = onClick, ) } @@ -103,7 +105,7 @@ fun PinKeypad( @Composable private fun PinKeypadRow( - models: List, + models: ImmutableList, onClick: (PinKeypadModel) -> Unit, pinKeySize: Dp, modifier: Modifier = Modifier, From 0e00797e67c08ad486279680c2d185953c01315a Mon Sep 17 00:00:00 2001 From: ElementBot Date: Mon, 23 Oct 2023 08:15:26 +0000 Subject: [PATCH 11/22] Update screenshots --- ...null_PinAuthenticationView-D-0_0_null_0,NEXUS_5,1.0,en].png | 3 --- ...null_PinAuthenticationView-N-0_1_null_0,NEXUS_5,1.0,en].png | 3 --- ...nents_null_PinEntryTextField-D-0_0_null,NEXUS_5,1.0,en].png | 3 +++ ...nents_null_PinEntryTextField-N-0_1_null,NEXUS_5,1.0,en].png | 3 +++ ...l.setup_null_SetupPinView-D-1_1_null_0,NEXUS_5,1.0,en].png} | 0 ...l.setup_null_SetupPinView-D-1_1_null_1,NEXUS_5,1.0,en].png} | 0 ...l.setup_null_SetupPinView-D-1_1_null_2,NEXUS_5,1.0,en].png} | 0 ...l.setup_null_SetupPinView-D-1_1_null_3,NEXUS_5,1.0,en].png} | 0 ...l.setup_null_SetupPinView-D-1_1_null_4,NEXUS_5,1.0,en].png} | 0 ...l.setup_null_SetupPinView-N-1_2_null_0,NEXUS_5,1.0,en].png} | 0 ...l.setup_null_SetupPinView-N-1_2_null_1,NEXUS_5,1.0,en].png} | 0 ...l.setup_null_SetupPinView-N-1_2_null_2,NEXUS_5,1.0,en].png} | 0 ...l.setup_null_SetupPinView-N-1_2_null_3,NEXUS_5,1.0,en].png} | 0 ...l.setup_null_SetupPinView-N-1_2_null_4,NEXUS_5,1.0,en].png} | 0 ...unlock.numpad_null_PinKeypad-D-3_3_null,NEXUS_5,1.0,en].png | 3 +++ ...unlock.numpad_null_PinKeypad-N-3_4_null,NEXUS_5,1.0,en].png | 3 +++ ....unlock_null_PinUnlockView-D-2_2_null_0,NEXUS_5,1.0,en].png | 3 +++ ....unlock_null_PinUnlockView-D-2_2_null_1,NEXUS_5,1.0,en].png | 3 +++ ....unlock_null_PinUnlockView-D-2_2_null_2,NEXUS_5,1.0,en].png | 3 +++ ....unlock_null_PinUnlockView-D-2_2_null_3,NEXUS_5,1.0,en].png | 3 +++ ....unlock_null_PinUnlockView-D-2_2_null_4,NEXUS_5,1.0,en].png | 3 +++ ....unlock_null_PinUnlockView-N-2_3_null_0,NEXUS_5,1.0,en].png | 3 +++ ....unlock_null_PinUnlockView-N-2_3_null_1,NEXUS_5,1.0,en].png | 3 +++ ....unlock_null_PinUnlockView-N-2_3_null_2,NEXUS_5,1.0,en].png | 3 +++ ....unlock_null_PinUnlockView-N-2_3_null_3,NEXUS_5,1.0,en].png | 3 +++ ....unlock_null_PinUnlockView-N-2_3_null_4,NEXUS_5,1.0,en].png | 3 +++ 26 files changed, 42 insertions(+), 6 deletions(-) delete mode 100644 tests/uitests/src/test/snapshots/images/ui_S_t[f.lockscreen.impl.auth_null_PinAuthenticationView-D-0_0_null_0,NEXUS_5,1.0,en].png delete mode 100644 tests/uitests/src/test/snapshots/images/ui_S_t[f.lockscreen.impl.auth_null_PinAuthenticationView-N-0_1_null_0,NEXUS_5,1.0,en].png create mode 100644 tests/uitests/src/test/snapshots/images/ui_S_t[f.lockscreen.impl.components_null_PinEntryTextField-D-0_0_null,NEXUS_5,1.0,en].png create mode 100644 tests/uitests/src/test/snapshots/images/ui_S_t[f.lockscreen.impl.components_null_PinEntryTextField-N-0_1_null,NEXUS_5,1.0,en].png rename tests/uitests/src/test/snapshots/images/{ui_S_t[f.lockscreen.impl.create_null_CreatePinView-D-1_1_null_0,NEXUS_5,1.0,en].png => ui_S_t[f.lockscreen.impl.setup_null_SetupPinView-D-1_1_null_0,NEXUS_5,1.0,en].png} (100%) rename tests/uitests/src/test/snapshots/images/{ui_S_t[f.lockscreen.impl.create_null_CreatePinView-D-1_1_null_1,NEXUS_5,1.0,en].png => ui_S_t[f.lockscreen.impl.setup_null_SetupPinView-D-1_1_null_1,NEXUS_5,1.0,en].png} (100%) rename tests/uitests/src/test/snapshots/images/{ui_S_t[f.lockscreen.impl.create_null_CreatePinView-D-1_1_null_2,NEXUS_5,1.0,en].png => ui_S_t[f.lockscreen.impl.setup_null_SetupPinView-D-1_1_null_2,NEXUS_5,1.0,en].png} (100%) rename tests/uitests/src/test/snapshots/images/{ui_S_t[f.lockscreen.impl.create_null_CreatePinView-D-1_1_null_3,NEXUS_5,1.0,en].png => ui_S_t[f.lockscreen.impl.setup_null_SetupPinView-D-1_1_null_3,NEXUS_5,1.0,en].png} (100%) rename tests/uitests/src/test/snapshots/images/{ui_S_t[f.lockscreen.impl.create_null_CreatePinView-D-1_1_null_4,NEXUS_5,1.0,en].png => ui_S_t[f.lockscreen.impl.setup_null_SetupPinView-D-1_1_null_4,NEXUS_5,1.0,en].png} (100%) rename tests/uitests/src/test/snapshots/images/{ui_S_t[f.lockscreen.impl.create_null_CreatePinView-N-1_2_null_0,NEXUS_5,1.0,en].png => ui_S_t[f.lockscreen.impl.setup_null_SetupPinView-N-1_2_null_0,NEXUS_5,1.0,en].png} (100%) rename tests/uitests/src/test/snapshots/images/{ui_S_t[f.lockscreen.impl.create_null_CreatePinView-N-1_2_null_1,NEXUS_5,1.0,en].png => ui_S_t[f.lockscreen.impl.setup_null_SetupPinView-N-1_2_null_1,NEXUS_5,1.0,en].png} (100%) rename tests/uitests/src/test/snapshots/images/{ui_S_t[f.lockscreen.impl.create_null_CreatePinView-N-1_2_null_2,NEXUS_5,1.0,en].png => ui_S_t[f.lockscreen.impl.setup_null_SetupPinView-N-1_2_null_2,NEXUS_5,1.0,en].png} (100%) rename tests/uitests/src/test/snapshots/images/{ui_S_t[f.lockscreen.impl.create_null_CreatePinView-N-1_2_null_3,NEXUS_5,1.0,en].png => ui_S_t[f.lockscreen.impl.setup_null_SetupPinView-N-1_2_null_3,NEXUS_5,1.0,en].png} (100%) rename tests/uitests/src/test/snapshots/images/{ui_S_t[f.lockscreen.impl.create_null_CreatePinView-N-1_2_null_4,NEXUS_5,1.0,en].png => ui_S_t[f.lockscreen.impl.setup_null_SetupPinView-N-1_2_null_4,NEXUS_5,1.0,en].png} (100%) create mode 100644 tests/uitests/src/test/snapshots/images/ui_S_t[f.lockscreen.impl.unlock.numpad_null_PinKeypad-D-3_3_null,NEXUS_5,1.0,en].png create mode 100644 tests/uitests/src/test/snapshots/images/ui_S_t[f.lockscreen.impl.unlock.numpad_null_PinKeypad-N-3_4_null,NEXUS_5,1.0,en].png create mode 100644 tests/uitests/src/test/snapshots/images/ui_S_t[f.lockscreen.impl.unlock_null_PinUnlockView-D-2_2_null_0,NEXUS_5,1.0,en].png create mode 100644 tests/uitests/src/test/snapshots/images/ui_S_t[f.lockscreen.impl.unlock_null_PinUnlockView-D-2_2_null_1,NEXUS_5,1.0,en].png create mode 100644 tests/uitests/src/test/snapshots/images/ui_S_t[f.lockscreen.impl.unlock_null_PinUnlockView-D-2_2_null_2,NEXUS_5,1.0,en].png create mode 100644 tests/uitests/src/test/snapshots/images/ui_S_t[f.lockscreen.impl.unlock_null_PinUnlockView-D-2_2_null_3,NEXUS_5,1.0,en].png create mode 100644 tests/uitests/src/test/snapshots/images/ui_S_t[f.lockscreen.impl.unlock_null_PinUnlockView-D-2_2_null_4,NEXUS_5,1.0,en].png create mode 100644 tests/uitests/src/test/snapshots/images/ui_S_t[f.lockscreen.impl.unlock_null_PinUnlockView-N-2_3_null_0,NEXUS_5,1.0,en].png create mode 100644 tests/uitests/src/test/snapshots/images/ui_S_t[f.lockscreen.impl.unlock_null_PinUnlockView-N-2_3_null_1,NEXUS_5,1.0,en].png create mode 100644 tests/uitests/src/test/snapshots/images/ui_S_t[f.lockscreen.impl.unlock_null_PinUnlockView-N-2_3_null_2,NEXUS_5,1.0,en].png create mode 100644 tests/uitests/src/test/snapshots/images/ui_S_t[f.lockscreen.impl.unlock_null_PinUnlockView-N-2_3_null_3,NEXUS_5,1.0,en].png create mode 100644 tests/uitests/src/test/snapshots/images/ui_S_t[f.lockscreen.impl.unlock_null_PinUnlockView-N-2_3_null_4,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.lockscreen.impl.auth_null_PinAuthenticationView-D-0_0_null_0,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.lockscreen.impl.auth_null_PinAuthenticationView-D-0_0_null_0,NEXUS_5,1.0,en].png deleted file mode 100644 index f1992899f6..0000000000 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.lockscreen.impl.auth_null_PinAuthenticationView-D-0_0_null_0,NEXUS_5,1.0,en].png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:f19d53c688e3f862894775756f00040adb5cbba99de71c053ed503c1b8af9518 -size 15239 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.lockscreen.impl.auth_null_PinAuthenticationView-N-0_1_null_0,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.lockscreen.impl.auth_null_PinAuthenticationView-N-0_1_null_0,NEXUS_5,1.0,en].png deleted file mode 100644 index f7a21c8025..0000000000 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.lockscreen.impl.auth_null_PinAuthenticationView-N-0_1_null_0,NEXUS_5,1.0,en].png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:11c145595f7713bc7b66f9d07e917bca82d6e06a1b55367801eb4d2cbfef89b0 -size 14353 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.lockscreen.impl.components_null_PinEntryTextField-D-0_0_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.lockscreen.impl.components_null_PinEntryTextField-D-0_0_null,NEXUS_5,1.0,en].png new file mode 100644 index 0000000000..b2f7ce4747 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.lockscreen.impl.components_null_PinEntryTextField-D-0_0_null,NEXUS_5,1.0,en].png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:de1d44f62edd3f2d30421e49ad435971b165711b8bfe6d4a9475c5fb2f9f83ed +size 8506 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.lockscreen.impl.components_null_PinEntryTextField-N-0_1_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.lockscreen.impl.components_null_PinEntryTextField-N-0_1_null,NEXUS_5,1.0,en].png new file mode 100644 index 0000000000..a4c7739624 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.lockscreen.impl.components_null_PinEntryTextField-N-0_1_null,NEXUS_5,1.0,en].png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d58d2d25d8f2c07c976bcda0eea7ec101f993ad1ef733fae4c713a67650e33e2 +size 8498 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.lockscreen.impl.create_null_CreatePinView-D-1_1_null_0,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.lockscreen.impl.setup_null_SetupPinView-D-1_1_null_0,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.lockscreen.impl.create_null_CreatePinView-D-1_1_null_0,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.lockscreen.impl.setup_null_SetupPinView-D-1_1_null_0,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.lockscreen.impl.create_null_CreatePinView-D-1_1_null_1,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.lockscreen.impl.setup_null_SetupPinView-D-1_1_null_1,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.lockscreen.impl.create_null_CreatePinView-D-1_1_null_1,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.lockscreen.impl.setup_null_SetupPinView-D-1_1_null_1,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.lockscreen.impl.create_null_CreatePinView-D-1_1_null_2,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.lockscreen.impl.setup_null_SetupPinView-D-1_1_null_2,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.lockscreen.impl.create_null_CreatePinView-D-1_1_null_2,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.lockscreen.impl.setup_null_SetupPinView-D-1_1_null_2,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.lockscreen.impl.create_null_CreatePinView-D-1_1_null_3,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.lockscreen.impl.setup_null_SetupPinView-D-1_1_null_3,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.lockscreen.impl.create_null_CreatePinView-D-1_1_null_3,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.lockscreen.impl.setup_null_SetupPinView-D-1_1_null_3,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.lockscreen.impl.create_null_CreatePinView-D-1_1_null_4,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.lockscreen.impl.setup_null_SetupPinView-D-1_1_null_4,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.lockscreen.impl.create_null_CreatePinView-D-1_1_null_4,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.lockscreen.impl.setup_null_SetupPinView-D-1_1_null_4,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.lockscreen.impl.create_null_CreatePinView-N-1_2_null_0,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.lockscreen.impl.setup_null_SetupPinView-N-1_2_null_0,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.lockscreen.impl.create_null_CreatePinView-N-1_2_null_0,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.lockscreen.impl.setup_null_SetupPinView-N-1_2_null_0,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.lockscreen.impl.create_null_CreatePinView-N-1_2_null_1,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.lockscreen.impl.setup_null_SetupPinView-N-1_2_null_1,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.lockscreen.impl.create_null_CreatePinView-N-1_2_null_1,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.lockscreen.impl.setup_null_SetupPinView-N-1_2_null_1,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.lockscreen.impl.create_null_CreatePinView-N-1_2_null_2,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.lockscreen.impl.setup_null_SetupPinView-N-1_2_null_2,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.lockscreen.impl.create_null_CreatePinView-N-1_2_null_2,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.lockscreen.impl.setup_null_SetupPinView-N-1_2_null_2,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.lockscreen.impl.create_null_CreatePinView-N-1_2_null_3,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.lockscreen.impl.setup_null_SetupPinView-N-1_2_null_3,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.lockscreen.impl.create_null_CreatePinView-N-1_2_null_3,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.lockscreen.impl.setup_null_SetupPinView-N-1_2_null_3,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.lockscreen.impl.create_null_CreatePinView-N-1_2_null_4,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.lockscreen.impl.setup_null_SetupPinView-N-1_2_null_4,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.lockscreen.impl.create_null_CreatePinView-N-1_2_null_4,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.lockscreen.impl.setup_null_SetupPinView-N-1_2_null_4,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.lockscreen.impl.unlock.numpad_null_PinKeypad-D-3_3_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.lockscreen.impl.unlock.numpad_null_PinKeypad-D-3_3_null,NEXUS_5,1.0,en].png new file mode 100644 index 0000000000..fc54ab5f7e --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.lockscreen.impl.unlock.numpad_null_PinKeypad-D-3_3_null,NEXUS_5,1.0,en].png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:b14ff41b74e36809f359a7b3b73ffdb9c0c2cd97ec786333bcce9412f05825e6 +size 30608 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.lockscreen.impl.unlock.numpad_null_PinKeypad-N-3_4_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.lockscreen.impl.unlock.numpad_null_PinKeypad-N-3_4_null,NEXUS_5,1.0,en].png new file mode 100644 index 0000000000..62b7c73a26 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.lockscreen.impl.unlock.numpad_null_PinKeypad-N-3_4_null,NEXUS_5,1.0,en].png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1521d9fecaaadcfc7ed4670d997b36a20bd2a84f564794a06cb10bfe7d1ad64e +size 28812 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.lockscreen.impl.unlock_null_PinUnlockView-D-2_2_null_0,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.lockscreen.impl.unlock_null_PinUnlockView-D-2_2_null_0,NEXUS_5,1.0,en].png new file mode 100644 index 0000000000..e81bbf1c1d --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.lockscreen.impl.unlock_null_PinUnlockView-D-2_2_null_0,NEXUS_5,1.0,en].png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c369763c4be676d6727a6b0f5cd74d56a9de09b9c3780e1806874d19ba7ffd3f +size 42705 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.lockscreen.impl.unlock_null_PinUnlockView-D-2_2_null_1,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.lockscreen.impl.unlock_null_PinUnlockView-D-2_2_null_1,NEXUS_5,1.0,en].png new file mode 100644 index 0000000000..bcb90d6b4a --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.lockscreen.impl.unlock_null_PinUnlockView-D-2_2_null_1,NEXUS_5,1.0,en].png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a63439f320a1b6ad124cb943f95651f85d2e9cfc34597cb450c803b6dafaefa7 +size 43149 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.lockscreen.impl.unlock_null_PinUnlockView-D-2_2_null_2,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.lockscreen.impl.unlock_null_PinUnlockView-D-2_2_null_2,NEXUS_5,1.0,en].png new file mode 100644 index 0000000000..bf2823f6a4 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.lockscreen.impl.unlock_null_PinUnlockView-D-2_2_null_2,NEXUS_5,1.0,en].png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:165e37ef78a7b09bbd49e8d692ccb27836e35d8535b182d9837a5c3daa5cf3a6 +size 43978 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.lockscreen.impl.unlock_null_PinUnlockView-D-2_2_null_3,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.lockscreen.impl.unlock_null_PinUnlockView-D-2_2_null_3,NEXUS_5,1.0,en].png new file mode 100644 index 0000000000..b3ca08978d --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.lockscreen.impl.unlock_null_PinUnlockView-D-2_2_null_3,NEXUS_5,1.0,en].png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ecaba43c72a890d85f9894eb987f291967c8ea15bdc09db88d6a72384098d827 +size 48308 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.lockscreen.impl.unlock_null_PinUnlockView-D-2_2_null_4,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.lockscreen.impl.unlock_null_PinUnlockView-D-2_2_null_4,NEXUS_5,1.0,en].png new file mode 100644 index 0000000000..5b8c62dcbf --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.lockscreen.impl.unlock_null_PinUnlockView-D-2_2_null_4,NEXUS_5,1.0,en].png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:25175242be4133a74541f0bb2d05db95484a65da952031fb8f68a2fdef88a995 +size 45880 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.lockscreen.impl.unlock_null_PinUnlockView-N-2_3_null_0,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.lockscreen.impl.unlock_null_PinUnlockView-N-2_3_null_0,NEXUS_5,1.0,en].png new file mode 100644 index 0000000000..fc34314f30 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.lockscreen.impl.unlock_null_PinUnlockView-N-2_3_null_0,NEXUS_5,1.0,en].png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:699c96cc0d06c85eeda3a3b408877d37445bebf1873a86d6255ba8626ba410b0 +size 39654 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.lockscreen.impl.unlock_null_PinUnlockView-N-2_3_null_1,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.lockscreen.impl.unlock_null_PinUnlockView-N-2_3_null_1,NEXUS_5,1.0,en].png new file mode 100644 index 0000000000..6d029a3034 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.lockscreen.impl.unlock_null_PinUnlockView-N-2_3_null_1,NEXUS_5,1.0,en].png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:233bb8cb261f752ac868c492d075fea9e5af656fcc8ad0d12fbf05b2dd690788 +size 40113 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.lockscreen.impl.unlock_null_PinUnlockView-N-2_3_null_2,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.lockscreen.impl.unlock_null_PinUnlockView-N-2_3_null_2,NEXUS_5,1.0,en].png new file mode 100644 index 0000000000..af181f44e5 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.lockscreen.impl.unlock_null_PinUnlockView-N-2_3_null_2,NEXUS_5,1.0,en].png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:920b9f28c3d2f5e726ad4beeb668e75c285b0e731e6d7eaaf87ca3b2a8b9980b +size 40652 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.lockscreen.impl.unlock_null_PinUnlockView-N-2_3_null_3,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.lockscreen.impl.unlock_null_PinUnlockView-N-2_3_null_3,NEXUS_5,1.0,en].png new file mode 100644 index 0000000000..2616989dcd --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.lockscreen.impl.unlock_null_PinUnlockView-N-2_3_null_3,NEXUS_5,1.0,en].png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:28197831dacc61f25d6b3a0080db331ef317283e8032fa5cc4ed457709da0f89 +size 42980 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.lockscreen.impl.unlock_null_PinUnlockView-N-2_3_null_4,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.lockscreen.impl.unlock_null_PinUnlockView-N-2_3_null_4,NEXUS_5,1.0,en].png new file mode 100644 index 0000000000..ce7df11d83 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.lockscreen.impl.unlock_null_PinUnlockView-N-2_3_null_4,NEXUS_5,1.0,en].png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:652154d82c5f43f91cface3f2e5650ee5a98cf1faed08a80589ab42225bd8120 +size 40557 From 0bc992c1ba5407730b666eec2183db92b0194dba Mon Sep 17 00:00:00 2001 From: ganfra Date: Mon, 23 Oct 2023 10:32:43 +0200 Subject: [PATCH 12/22] Pin : fix tests after rename --- .../impl/pin/DefaultPinCodeManager.kt | 2 +- .../lockscreen/impl/pin/PinCodeManager.kt | 2 +- ...senterTest.kt => SetupPinPresenterTest.kt} | 38 +++++++++---------- 3 files changed, 21 insertions(+), 21 deletions(-) rename features/lockscreen/impl/src/test/kotlin/io/element/android/features/lockscreen/impl/setup/{CreatePinPresenterTest.kt => SetupPinPresenterTest.kt} (74%) diff --git a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/pin/DefaultPinCodeManager.kt b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/pin/DefaultPinCodeManager.kt index f5848a9d40..e7529e9280 100644 --- a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/pin/DefaultPinCodeManager.kt +++ b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/pin/DefaultPinCodeManager.kt @@ -37,7 +37,7 @@ class DefaultPinCodeManager @Inject constructor( return pinCodeStore.hasPinCode() } - override suspend fun setupPinCode(pinCode: String) { + override suspend fun createPinCode(pinCode: String) { val secretKey = secretKeyProvider.getOrCreateKey(SECRET_KEY_ALIAS) val encryptedPinCode = encryptionDecryptionService.encrypt(secretKey, pinCode.toByteArray()).toBase64() pinCodeStore.saveEncryptedPinCode(encryptedPinCode) diff --git a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/pin/PinCodeManager.kt b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/pin/PinCodeManager.kt index 09197c3eb1..5f84f5296d 100644 --- a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/pin/PinCodeManager.kt +++ b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/pin/PinCodeManager.kt @@ -30,7 +30,7 @@ interface PinCodeManager { * Creates a new encrypted pin code. * @param pinCode the clear pin code to create */ - suspend fun setupPinCode(pinCode: String) + suspend fun createPinCode(pinCode: String) /** * @return true if the pin code is correct. diff --git a/features/lockscreen/impl/src/test/kotlin/io/element/android/features/lockscreen/impl/setup/CreatePinPresenterTest.kt b/features/lockscreen/impl/src/test/kotlin/io/element/android/features/lockscreen/impl/setup/SetupPinPresenterTest.kt similarity index 74% rename from features/lockscreen/impl/src/test/kotlin/io/element/android/features/lockscreen/impl/setup/CreatePinPresenterTest.kt rename to features/lockscreen/impl/src/test/kotlin/io/element/android/features/lockscreen/impl/setup/SetupPinPresenterTest.kt index 723b8e8e6b..d7529be243 100644 --- a/features/lockscreen/impl/src/test/kotlin/io/element/android/features/lockscreen/impl/setup/CreatePinPresenterTest.kt +++ b/features/lockscreen/impl/src/test/kotlin/io/element/android/features/lockscreen/impl/setup/SetupPinPresenterTest.kt @@ -22,14 +22,14 @@ import app.cash.turbine.test import com.google.common.truth.Truth.assertThat import io.element.android.features.lockscreen.impl.pin.model.PinDigit import io.element.android.features.lockscreen.impl.pin.model.PinEntry -import io.element.android.features.lockscreen.impl.setup.validation.CreatePinFailure import io.element.android.features.lockscreen.impl.setup.validation.PinValidator +import io.element.android.features.lockscreen.impl.setup.validation.SetupPinFailure import io.element.android.libraries.matrix.test.core.aBuildMeta import io.element.android.tests.testutils.awaitLastSequentialItem import kotlinx.coroutines.test.runTest import org.junit.Test -class CreatePinPresenterTest { +class SetupPinPresenterTest { private val blacklistedPin = PinValidator.BLACKLIST.first() private val halfCompletePin = "12" @@ -39,58 +39,58 @@ class CreatePinPresenterTest { @Test fun `present - complete flow`() = runTest { - val presenter = createCreatePinPresenter() + val presenter = createSetupPinPresenter() moleculeFlow(RecompositionMode.Immediate) { presenter.present() }.test { awaitItem().also { state -> state.choosePinEntry.assertEmpty() state.confirmPinEntry.assertEmpty() - assertThat(state.createPinFailure).isNull() + assertThat(state.setupPinFailure).isNull() assertThat(state.isConfirmationStep).isFalse() - state.eventSink(CreatePinEvents.OnPinEntryChanged(halfCompletePin)) + state.eventSink(SetupPinEvents.OnPinEntryChanged(halfCompletePin)) } awaitItem().also { state -> state.choosePinEntry.assertText(halfCompletePin) state.confirmPinEntry.assertEmpty() - assertThat(state.createPinFailure).isNull() + assertThat(state.setupPinFailure).isNull() assertThat(state.isConfirmationStep).isFalse() - state.eventSink(CreatePinEvents.OnPinEntryChanged(blacklistedPin)) + state.eventSink(SetupPinEvents.OnPinEntryChanged(blacklistedPin)) } awaitLastSequentialItem().also { state -> state.choosePinEntry.assertText(blacklistedPin) - assertThat(state.createPinFailure).isEqualTo(CreatePinFailure.PinBlacklisted) - state.eventSink(CreatePinEvents.ClearFailure) + assertThat(state.setupPinFailure).isEqualTo(SetupPinFailure.PinBlacklisted) + state.eventSink(SetupPinEvents.ClearFailure) } awaitLastSequentialItem().also { state -> state.choosePinEntry.assertEmpty() - assertThat(state.createPinFailure).isNull() - state.eventSink(CreatePinEvents.OnPinEntryChanged(completePin)) + assertThat(state.setupPinFailure).isNull() + state.eventSink(SetupPinEvents.OnPinEntryChanged(completePin)) } awaitLastSequentialItem().also { state -> state.choosePinEntry.assertText(completePin) state.confirmPinEntry.assertEmpty() assertThat(state.isConfirmationStep).isTrue() - state.eventSink(CreatePinEvents.OnPinEntryChanged(mismatchedPin)) + state.eventSink(SetupPinEvents.OnPinEntryChanged(mismatchedPin)) } awaitLastSequentialItem().also { state -> state.choosePinEntry.assertText(completePin) state.confirmPinEntry.assertText(mismatchedPin) - assertThat(state.createPinFailure).isEqualTo(CreatePinFailure.PinsDontMatch) - state.eventSink(CreatePinEvents.ClearFailure) + assertThat(state.setupPinFailure).isEqualTo(SetupPinFailure.PinsDontMatch) + state.eventSink(SetupPinEvents.ClearFailure) } awaitLastSequentialItem().also { state -> state.choosePinEntry.assertEmpty() state.confirmPinEntry.assertEmpty() assertThat(state.isConfirmationStep).isFalse() - assertThat(state.createPinFailure).isNull() - state.eventSink(CreatePinEvents.OnPinEntryChanged(completePin)) + assertThat(state.setupPinFailure).isNull() + state.eventSink(SetupPinEvents.OnPinEntryChanged(completePin)) } awaitLastSequentialItem().also { state -> state.choosePinEntry.assertText(completePin) state.confirmPinEntry.assertEmpty() assertThat(state.isConfirmationStep).isTrue() - state.eventSink(CreatePinEvents.OnPinEntryChanged(completePin)) + state.eventSink(SetupPinEvents.OnPinEntryChanged(completePin)) } awaitItem().also { state -> state.choosePinEntry.assertText(completePin) @@ -108,7 +108,7 @@ class CreatePinPresenterTest { assertThat(isEmpty).isTrue() } - private fun createCreatePinPresenter(): CreatePinPresenter { - return CreatePinPresenter(PinValidator(), aBuildMeta()) + private fun createSetupPinPresenter(): SetupPinPresenter { + return SetupPinPresenter(PinValidator(), aBuildMeta()) } } From 35dce75fd1b2bad6eeba00edcedecaae234ea21b Mon Sep 17 00:00:00 2001 From: ganfra Date: Mon, 23 Oct 2023 10:34:49 +0200 Subject: [PATCH 13/22] PIN : fix warning --- .../features/lockscreen/impl/components/PinEntryTextField.kt | 2 +- .../android/features/lockscreen/impl/unlock/numpad/PinKeypad.kt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/components/PinEntryTextField.kt b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/components/PinEntryTextField.kt index 5682e594fe..e4b6e6ac47 100644 --- a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/components/PinEntryTextField.kt +++ b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/components/PinEntryTextField.kt @@ -106,7 +106,7 @@ private fun PinDigitView( @PreviewsDayNight @Composable -fun PinEntryTextFieldPreview() { +internal fun PinEntryTextFieldPreview() { ElementTheme { PinEntryTextField( pinEntry = PinEntry.empty(4).fillWith("12"), diff --git a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/unlock/numpad/PinKeypad.kt b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/unlock/numpad/PinKeypad.kt index 8a6230c725..46b9ca1b82 100644 --- a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/unlock/numpad/PinKeypad.kt +++ b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/unlock/numpad/PinKeypad.kt @@ -199,7 +199,7 @@ private fun PinKeypadBackButton( @Composable @PreviewsDayNight -fun PinKeypadPreview() { +internal fun PinKeypadPreview() { ElementPreview { BoxWithConstraints { PinKeypad( From 4fbe32a6daaf9419c95d98687ad9cca164ba075a Mon Sep 17 00:00:00 2001 From: ganfra Date: Mon, 23 Oct 2023 11:00:47 +0200 Subject: [PATCH 14/22] PIN: fix konsist --- .../android/features/lockscreen/impl/unlock/PinUnlockView.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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 be43d6cf32..e2cf522a07 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 @@ -126,7 +126,7 @@ fun PinUnlockView( } @Composable -fun PinUnlockCompactView( +private fun PinUnlockCompactView( header: @Composable () -> Unit, footer: @Composable () -> Unit, modifier: Modifier = Modifier, @@ -150,7 +150,7 @@ fun PinUnlockCompactView( } @Composable -fun PinUnlockExpandedView( +private fun PinUnlockExpandedView( header: @Composable () -> Unit, footer: @Composable () -> Unit, modifier: Modifier = Modifier, From 6230d9d48b8c1638e5c46addb56bf5d1d108c1a8 Mon Sep 17 00:00:00 2001 From: ganfra Date: Mon, 23 Oct 2023 11:41:08 +0200 Subject: [PATCH 15/22] PIN : add test for SetupPinPresenter --- build.gradle.kts | 2 - features/lockscreen/impl/build.gradle.kts | 2 + .../lockscreen/impl/unlock/PinUnlockEvents.kt | 2 +- .../impl/unlock/PinUnlockPresenter.kt | 2 +- .../impl/pin/model/PinEntryAssertions.kt | 28 ++++++ .../impl/setup/SetupPinPresenterTest.kt | 11 +-- .../impl/unlock/PinUnlockPresenterTest.kt | 89 +++++++++++++++++++ 7 files changed, 123 insertions(+), 13 deletions(-) create mode 100644 features/lockscreen/impl/src/test/kotlin/io/element/android/features/lockscreen/impl/pin/model/PinEntryAssertions.kt create mode 100644 features/lockscreen/impl/src/test/kotlin/io/element/android/features/lockscreen/impl/unlock/PinUnlockPresenterTest.kt diff --git a/build.gradle.kts b/build.gradle.kts index 391313fe2d..f08c023b1d 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -250,8 +250,6 @@ koverMerged { excludes += "io.element.android.appnav.loggedin.LoggedInPresenter$*" // Some options can't be tested at the moment excludes += "io.element.android.features.preferences.impl.developer.DeveloperSettingsPresenter$*" - // Temporary until we have actually something to test. - excludes += "io.element.android.features.lockscreen.impl.unlock.PinUnlockPresenter$*" } bound { minValue = 85 diff --git a/features/lockscreen/impl/build.gradle.kts b/features/lockscreen/impl/build.gradle.kts index 8daeb2178c..a3f5b27949 100644 --- a/features/lockscreen/impl/build.gradle.kts +++ b/features/lockscreen/impl/build.gradle.kts @@ -51,6 +51,8 @@ dependencies { testImplementation(projects.tests.testutils) testImplementation(projects.libraries.cryptography.test) testImplementation(projects.libraries.cryptography.impl) + testImplementation(projects.libraries.featureflag.test) + ksp(libs.showkase.processor) } diff --git a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/unlock/PinUnlockEvents.kt b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/unlock/PinUnlockEvents.kt index a90b6cb702..5560dedd24 100644 --- a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/unlock/PinUnlockEvents.kt +++ b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/unlock/PinUnlockEvents.kt @@ -20,6 +20,6 @@ import io.element.android.features.lockscreen.impl.unlock.numpad.PinKeypadModel sealed interface PinUnlockEvents { data class OnPinKeypadPressed(val pinKeypadModel: PinKeypadModel) : PinUnlockEvents - data object Unlock : PinUnlockEvents data object OnForgetPin : PinUnlockEvents + data object ClearSignOutPrompt : PinUnlockEvents } 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 a6f06158d4..783e03c92a 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 @@ -53,7 +53,6 @@ class PinUnlockPresenter @Inject constructor( fun handleEvents(event: PinUnlockEvents) { when (event) { - PinUnlockEvents.Unlock -> coroutineScope.launch { pinStateService.unlock() } is PinUnlockEvents.OnPinKeypadPressed -> { pinEntry = pinEntry.process(event.pinKeypadModel) if (pinEntry.isComplete()) { @@ -61,6 +60,7 @@ class PinUnlockPresenter @Inject constructor( } } PinUnlockEvents.OnForgetPin -> showSignOutPrompt = true + PinUnlockEvents.ClearSignOutPrompt -> showSignOutPrompt = false } } return PinUnlockState( diff --git a/features/lockscreen/impl/src/test/kotlin/io/element/android/features/lockscreen/impl/pin/model/PinEntryAssertions.kt b/features/lockscreen/impl/src/test/kotlin/io/element/android/features/lockscreen/impl/pin/model/PinEntryAssertions.kt new file mode 100644 index 0000000000..37d54677a1 --- /dev/null +++ b/features/lockscreen/impl/src/test/kotlin/io/element/android/features/lockscreen/impl/pin/model/PinEntryAssertions.kt @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2023 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.element.android.features.lockscreen.impl.pin.model + +import com.google.common.truth.Truth.assertThat + +fun PinEntry.assertText(text: String) { + assertThat(toText()).isEqualTo(text) +} + +fun PinEntry.assertEmpty() { + val isEmpty = digits.all { it is PinDigit.Empty } + assertThat(isEmpty).isTrue() +} diff --git a/features/lockscreen/impl/src/test/kotlin/io/element/android/features/lockscreen/impl/setup/SetupPinPresenterTest.kt b/features/lockscreen/impl/src/test/kotlin/io/element/android/features/lockscreen/impl/setup/SetupPinPresenterTest.kt index d7529be243..5d9901a9f1 100644 --- a/features/lockscreen/impl/src/test/kotlin/io/element/android/features/lockscreen/impl/setup/SetupPinPresenterTest.kt +++ b/features/lockscreen/impl/src/test/kotlin/io/element/android/features/lockscreen/impl/setup/SetupPinPresenterTest.kt @@ -22,6 +22,8 @@ import app.cash.turbine.test import com.google.common.truth.Truth.assertThat import io.element.android.features.lockscreen.impl.pin.model.PinDigit import io.element.android.features.lockscreen.impl.pin.model.PinEntry +import io.element.android.features.lockscreen.impl.pin.model.assertEmpty +import io.element.android.features.lockscreen.impl.pin.model.assertText import io.element.android.features.lockscreen.impl.setup.validation.PinValidator import io.element.android.features.lockscreen.impl.setup.validation.SetupPinFailure import io.element.android.libraries.matrix.test.core.aBuildMeta @@ -99,15 +101,6 @@ class SetupPinPresenterTest { } } - private fun PinEntry.assertText(text: String) { - assertThat(toText()).isEqualTo(text) - } - - private fun PinEntry.assertEmpty() { - val isEmpty = digits.all { it is PinDigit.Empty } - assertThat(isEmpty).isTrue() - } - private fun createSetupPinPresenter(): SetupPinPresenter { return SetupPinPresenter(PinValidator(), aBuildMeta()) } 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 new file mode 100644 index 0000000000..6839fe65c7 --- /dev/null +++ b/features/lockscreen/impl/src/test/kotlin/io/element/android/features/lockscreen/impl/unlock/PinUnlockPresenterTest.kt @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2023 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.element.android.features.lockscreen.impl.unlock + +import app.cash.molecule.RecompositionMode +import app.cash.molecule.moleculeFlow +import app.cash.turbine.test +import com.google.common.truth.Truth.assertThat +import io.element.android.features.lockscreen.impl.pin.model.assertEmpty +import io.element.android.features.lockscreen.impl.pin.model.assertText +import io.element.android.features.lockscreen.impl.state.DefaultLockScreenStateService +import io.element.android.features.lockscreen.impl.unlock.numpad.PinKeypadModel +import io.element.android.libraries.featureflag.api.FeatureFlags +import io.element.android.libraries.featureflag.test.FakeFeatureFlagService +import io.element.android.tests.testutils.awaitLastSequentialItem +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.test.runTest +import org.junit.Test + +class PinUnlockPresenterTest { + + private val halfCompletePin = "12" + private val completePin = "1235" + + @Test + fun `present - complete flow`() = runTest { + val presenter = createPinUnlockPresenter(this) + moleculeFlow(RecompositionMode.Immediate) { + presenter.present() + }.test { + awaitItem().also { state -> + state.pinEntry.assertEmpty() + assertThat(state.showWrongPinTitle).isFalse() + assertThat(state.showSignOutPrompt).isFalse() + assertThat(state.remainingAttempts).isEqualTo(3) + state.eventSink(PinUnlockEvents.OnPinKeypadPressed(PinKeypadModel.Number('1'))) + state.eventSink(PinUnlockEvents.OnPinKeypadPressed(PinKeypadModel.Number('2'))) + } + awaitLastSequentialItem().also { state -> + state.pinEntry.assertText(halfCompletePin) + state.eventSink(PinUnlockEvents.OnPinKeypadPressed(PinKeypadModel.Number('3'))) + state.eventSink(PinUnlockEvents.OnPinKeypadPressed(PinKeypadModel.Back)) + state.eventSink(PinUnlockEvents.OnPinKeypadPressed(PinKeypadModel.Empty)) + } + awaitLastSequentialItem().also { state -> + state.pinEntry.assertText(halfCompletePin) + state.eventSink(PinUnlockEvents.OnForgetPin) + } + awaitLastSequentialItem().also { state -> + assertThat(state.showSignOutPrompt).isEqualTo(true) + assertThat(state.isSignOutPromptCancellable).isEqualTo(true) + state.eventSink(PinUnlockEvents.ClearSignOutPrompt) + } + awaitLastSequentialItem().also { state -> + assertThat(state.showSignOutPrompt).isEqualTo(false) + state.eventSink(PinUnlockEvents.OnPinKeypadPressed(PinKeypadModel.Number('3'))) + state.eventSink(PinUnlockEvents.OnPinKeypadPressed(PinKeypadModel.Number('5'))) + } + awaitLastSequentialItem().also { state -> + state.pinEntry.assertText(completePin) + } + } + } + + private suspend fun createPinUnlockPresenter(scope: CoroutineScope): PinUnlockPresenter { + val featureFlagService = FakeFeatureFlagService().apply { + setFeatureEnabled(FeatureFlags.PinUnlock, true) + } + val lockScreenStateService = DefaultLockScreenStateService(featureFlagService) + return PinUnlockPresenter( + lockScreenStateService, + scope, + ) + } +} From 8ca42d4cfcff383690e47e7911a2d8af06727f0a Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Mon, 23 Oct 2023 11:57:04 +0200 Subject: [PATCH 16/22] Konsist: add test to ensure that functions with `@PreviewsDayNight` contain `ElementTheme` composable, and fix existing issues. --- .../lockscreen/impl/components/PinEntryTextField.kt | 3 ++- .../virtual/TimelineEncryptedHistoryBannerView.kt | 3 ++- .../libraries/textcomposer/TextComposerLinkDialog.kt | 7 ++++--- .../textcomposer/components/RecordingProgress.kt | 7 +++---- .../android/tests/konsist/KonsistPreviewTest.kt | 11 +++++++++++ 5 files changed, 22 insertions(+), 9 deletions(-) diff --git a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/components/PinEntryTextField.kt b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/components/PinEntryTextField.kt index e4b6e6ac47..fceaf59f2a 100644 --- a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/components/PinEntryTextField.kt +++ b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/components/PinEntryTextField.kt @@ -34,6 +34,7 @@ import androidx.compose.ui.text.input.TextFieldValue import androidx.compose.ui.unit.dp import io.element.android.features.lockscreen.impl.pin.model.PinDigit import io.element.android.features.lockscreen.impl.pin.model.PinEntry +import io.element.android.libraries.designsystem.preview.ElementPreview import io.element.android.libraries.designsystem.preview.PreviewsDayNight import io.element.android.libraries.designsystem.theme.pinDigitBg import io.element.android.libraries.theme.ElementTheme @@ -107,7 +108,7 @@ private fun PinDigitView( @PreviewsDayNight @Composable internal fun PinEntryTextFieldPreview() { - ElementTheme { + ElementPreview { PinEntryTextField( pinEntry = PinEntry.empty(4).fillWith("12"), onValueChange = {}, diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/virtual/TimelineEncryptedHistoryBannerView.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/virtual/TimelineEncryptedHistoryBannerView.kt index 0317a68a00..2ef6c6580c 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/virtual/TimelineEncryptedHistoryBannerView.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/virtual/TimelineEncryptedHistoryBannerView.kt @@ -29,6 +29,7 @@ import androidx.compose.ui.draw.clip import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp import io.element.android.features.messages.impl.R +import io.element.android.libraries.designsystem.preview.ElementPreview import io.element.android.libraries.designsystem.preview.PreviewsDayNight import io.element.android.libraries.designsystem.theme.components.Icon import io.element.android.libraries.designsystem.utils.CommonDrawables @@ -61,7 +62,7 @@ fun TimelineEncryptedHistoryBannerView(modifier: Modifier = Modifier) { @PreviewsDayNight @Composable internal fun TimelineEncryptedHistoryBannerViewPreview() { - ElementTheme { + ElementPreview { TimelineEncryptedHistoryBannerView() } } diff --git a/libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/TextComposerLinkDialog.kt b/libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/TextComposerLinkDialog.kt index f36e2ca11c..232e9ab0c1 100644 --- a/libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/TextComposerLinkDialog.kt +++ b/libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/TextComposerLinkDialog.kt @@ -26,6 +26,7 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource import io.element.android.libraries.designsystem.components.dialogs.ListDialog import io.element.android.libraries.designsystem.components.list.TextFieldListItem +import io.element.android.libraries.designsystem.preview.ElementPreview import io.element.android.libraries.designsystem.preview.PreviewsDayNight import io.element.android.libraries.designsystem.theme.components.ListItem import io.element.android.libraries.designsystem.theme.components.Text @@ -200,7 +201,7 @@ private fun EditLinkDialog( @PreviewsDayNight @Composable -internal fun TextComposerLinkDialogCreateLinkPreview() { +internal fun TextComposerLinkDialogCreateLinkPreview() = ElementPreview { TextComposerLinkDialog( onDismissRequest = {}, linkAction = LinkAction.InsertLink, @@ -212,7 +213,7 @@ internal fun TextComposerLinkDialogCreateLinkPreview() { @PreviewsDayNight @Composable -internal fun TextComposerLinkDialogCreateLinkWithoutTextPreview() { +internal fun TextComposerLinkDialogCreateLinkWithoutTextPreview() = ElementPreview { TextComposerLinkDialog( onDismissRequest = {}, linkAction = LinkAction.SetLink(null), @@ -224,7 +225,7 @@ internal fun TextComposerLinkDialogCreateLinkWithoutTextPreview() { @PreviewsDayNight @Composable -internal fun TextComposerLinkDialogEditLinkPreview() { +internal fun TextComposerLinkDialogEditLinkPreview() = ElementPreview { TextComposerLinkDialog( onDismissRequest = {}, linkAction = LinkAction.SetLink("https://element.io"), diff --git a/libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/components/RecordingProgress.kt b/libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/components/RecordingProgress.kt index db4f59342c..2fc0420e05 100644 --- a/libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/components/RecordingProgress.kt +++ b/libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/components/RecordingProgress.kt @@ -30,6 +30,7 @@ import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp +import io.element.android.libraries.designsystem.preview.ElementPreview import io.element.android.libraries.designsystem.preview.PreviewsDayNight import io.element.android.libraries.designsystem.theme.components.Text import io.element.android.libraries.theme.ElementTheme @@ -46,9 +47,7 @@ internal fun RecordingProgress( shape = MaterialTheme.shapes.medium, ) .padding(start = 12.dp, end = 20.dp, top = 8.dp, bottom = 8.dp) - .heightIn(26.dp) - - , + .heightIn(26.dp), verticalAlignment = Alignment.CenterVertically, ) { Box( @@ -69,6 +68,6 @@ internal fun RecordingProgress( @PreviewsDayNight @Composable -internal fun RecordingProgressPreview() { +internal fun RecordingProgressPreview() = ElementPreview { RecordingProgress() } diff --git a/tests/konsist/src/test/kotlin/io/element/android/tests/konsist/KonsistPreviewTest.kt b/tests/konsist/src/test/kotlin/io/element/android/tests/konsist/KonsistPreviewTest.kt index 40c73c8eaa..7061d4ba55 100644 --- a/tests/konsist/src/test/kotlin/io/element/android/tests/konsist/KonsistPreviewTest.kt +++ b/tests/konsist/src/test/kotlin/io/element/android/tests/konsist/KonsistPreviewTest.kt @@ -35,4 +35,15 @@ class KonsistPreviewTest { it.hasNameEndingWith("DarkPreview").not() } } + + @Test + fun `Functions with '@PreviewsDayNight' annotation should contain 'ElementPreview' composable`() { + Konsist + .scopeFromProject() + .functions() + .withAllAnnotationsOf(PreviewsDayNight::class) + .assertTrue { + it.text.contains("ElementPreview") + } + } } From 6a3c42f189acf7a9695f34404587e13920914ea2 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Mon, 23 Oct 2023 12:00:01 +0200 Subject: [PATCH 17/22] Konsist: add test to ensure that functions with `@PreviewsDayNight` are internal, and fix existing issues. --- .../android/tests/konsist/KonsistPreviewTest.kt | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/tests/konsist/src/test/kotlin/io/element/android/tests/konsist/KonsistPreviewTest.kt b/tests/konsist/src/test/kotlin/io/element/android/tests/konsist/KonsistPreviewTest.kt index 7061d4ba55..f82f4dac7c 100644 --- a/tests/konsist/src/test/kotlin/io/element/android/tests/konsist/KonsistPreviewTest.kt +++ b/tests/konsist/src/test/kotlin/io/element/android/tests/konsist/KonsistPreviewTest.kt @@ -46,4 +46,15 @@ class KonsistPreviewTest { it.text.contains("ElementPreview") } } + + @Test + fun `Functions with '@PreviewsDayNight' are internal`() { + Konsist + .scopeFromProject() + .functions() + .withAllAnnotationsOf(PreviewsDayNight::class) + .assertTrue { + it.hasInternalModifier + } + } } From f8512d3964bb89c8d94e78c9469f5c921b90ed6c Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Mon, 23 Oct 2023 14:01:23 +0200 Subject: [PATCH 18/22] Remove unused import --- .../features/lockscreen/impl/setup/SetupPinPresenterTest.kt | 2 -- 1 file changed, 2 deletions(-) diff --git a/features/lockscreen/impl/src/test/kotlin/io/element/android/features/lockscreen/impl/setup/SetupPinPresenterTest.kt b/features/lockscreen/impl/src/test/kotlin/io/element/android/features/lockscreen/impl/setup/SetupPinPresenterTest.kt index 5d9901a9f1..94877fbff5 100644 --- a/features/lockscreen/impl/src/test/kotlin/io/element/android/features/lockscreen/impl/setup/SetupPinPresenterTest.kt +++ b/features/lockscreen/impl/src/test/kotlin/io/element/android/features/lockscreen/impl/setup/SetupPinPresenterTest.kt @@ -20,8 +20,6 @@ import app.cash.molecule.RecompositionMode import app.cash.molecule.moleculeFlow import app.cash.turbine.test import com.google.common.truth.Truth.assertThat -import io.element.android.features.lockscreen.impl.pin.model.PinDigit -import io.element.android.features.lockscreen.impl.pin.model.PinEntry import io.element.android.features.lockscreen.impl.pin.model.assertEmpty import io.element.android.features.lockscreen.impl.pin.model.assertText import io.element.android.features.lockscreen.impl.setup.validation.PinValidator From 05a999acd4832c3cb1d62a852b49c483f595abb7 Mon Sep 17 00:00:00 2001 From: ganfra Date: Mon, 23 Oct 2023 15:30:17 +0200 Subject: [PATCH 19/22] Pin: add LockScreenConfig and address PR reviews --- .../android/appconfig/LockScreenConfig.kt | 35 +++++++++++++++++++ features/lockscreen/impl/build.gradle.kts | 5 ++- .../impl/components/PinEntryTextField.kt | 2 +- .../lockscreen/impl/pin/model/PinEntry.kt | 4 +-- .../impl/setup/SetupPinPresenter.kt | 15 ++++---- .../impl/setup/SetupPinStateProvider.kt | 14 ++++---- .../impl/setup/validation/PinValidator.kt | 9 ++--- .../lockscreen/impl/unlock/PinUnlockEvents.kt | 2 +- .../impl/unlock/PinUnlockPresenter.kt | 8 +++-- .../impl/unlock/PinUnlockStateProvider.kt | 4 +-- .../lockscreen/impl/unlock/PinUnlockView.kt | 2 +- .../unlock/{numpad => keypad}/PinKeypad.kt | 2 +- .../{numpad => keypad}/PinKeypadModel.kt | 2 +- .../impl/setup/SetupPinPresenterTest.kt | 3 +- .../impl/unlock/PinUnlockPresenterTest.kt | 2 +- 15 files changed, 71 insertions(+), 38 deletions(-) create mode 100644 appconfig/src/main/kotlin/io/element/android/appconfig/LockScreenConfig.kt rename features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/unlock/{numpad => keypad}/PinKeypad.kt (99%) rename features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/unlock/{numpad => keypad}/PinKeypadModel.kt (92%) diff --git a/appconfig/src/main/kotlin/io/element/android/appconfig/LockScreenConfig.kt b/appconfig/src/main/kotlin/io/element/android/appconfig/LockScreenConfig.kt new file mode 100644 index 0000000000..5930f53428 --- /dev/null +++ b/appconfig/src/main/kotlin/io/element/android/appconfig/LockScreenConfig.kt @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2023 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.element.android.appconfig + +object LockScreenConfig { + + /** + * Whether the LockScreen is mandatory or not. + */ + const val IS_MANDATORY: Boolean = false + + /** + * Some PINs are blacklisted. + */ + val PIN_BLACKLIST = listOf("0000", "1234") + + /** + * The size of the PIN. + */ + const val PIN_SIZE = 4 +} diff --git a/features/lockscreen/impl/build.gradle.kts b/features/lockscreen/impl/build.gradle.kts index a3f5b27949..a3657ccff3 100644 --- a/features/lockscreen/impl/build.gradle.kts +++ b/features/lockscreen/impl/build.gradle.kts @@ -30,9 +30,11 @@ anvil { } dependencies { + ksp(libs.showkase.processor) implementation(projects.anvilannotations) anvil(projects.anvilcodegen) api(projects.features.lockscreen.api) + implementation(projects.appconfig) implementation(projects.libraries.core) implementation(projects.libraries.architecture) implementation(projects.libraries.matrix.api) @@ -52,7 +54,4 @@ dependencies { testImplementation(projects.libraries.cryptography.test) testImplementation(projects.libraries.cryptography.impl) testImplementation(projects.libraries.featureflag.test) - - - ksp(libs.showkase.processor) } diff --git a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/components/PinEntryTextField.kt b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/components/PinEntryTextField.kt index fceaf59f2a..91f6d435c5 100644 --- a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/components/PinEntryTextField.kt +++ b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/components/PinEntryTextField.kt @@ -110,7 +110,7 @@ private fun PinDigitView( internal fun PinEntryTextFieldPreview() { ElementPreview { PinEntryTextField( - pinEntry = PinEntry.empty(4).fillWith("12"), + pinEntry = PinEntry.createEmpty(4).fillWith("12"), onValueChange = {}, ) } diff --git a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/pin/model/PinEntry.kt b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/pin/model/PinEntry.kt index 92dda869a6..eaca592de9 100644 --- a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/pin/model/PinEntry.kt +++ b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/pin/model/PinEntry.kt @@ -24,7 +24,7 @@ data class PinEntry( ) { companion object { - fun empty(size: Int): PinEntry { + fun createEmpty(size: Int): PinEntry { val digits = List(size) { PinDigit.Empty } return PinEntry( digits = digits.toPersistentList() @@ -69,7 +69,7 @@ data class PinEntry( } fun clear(): PinEntry { - return fillWith("") + return createEmpty(size) } fun isComplete(): Boolean { diff --git a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/setup/SetupPinPresenter.kt b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/setup/SetupPinPresenter.kt index 6a880a6967..3c380e6be7 100644 --- a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/setup/SetupPinPresenter.kt +++ b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/setup/SetupPinPresenter.kt @@ -21,15 +21,14 @@ import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue +import io.element.android.appconfig.LockScreenConfig import io.element.android.features.lockscreen.impl.pin.model.PinEntry -import io.element.android.features.lockscreen.impl.setup.validation.SetupPinFailure import io.element.android.features.lockscreen.impl.setup.validation.PinValidator +import io.element.android.features.lockscreen.impl.setup.validation.SetupPinFailure import io.element.android.libraries.architecture.Presenter import io.element.android.libraries.core.meta.BuildMeta import javax.inject.Inject -private const val PIN_SIZE = 4 - class SetupPinPresenter @Inject constructor( private val pinValidator: PinValidator, private val buildMeta: BuildMeta, @@ -38,10 +37,10 @@ class SetupPinPresenter @Inject constructor( @Composable override fun present(): SetupPinState { var choosePinEntry by remember { - mutableStateOf(PinEntry.empty(PIN_SIZE)) + mutableStateOf(PinEntry.createEmpty(LockScreenConfig.PIN_SIZE)) } var confirmPinEntry by remember { - mutableStateOf(PinEntry.empty(PIN_SIZE)) + mutableStateOf(PinEntry.createEmpty(LockScreenConfig.PIN_SIZE)) } var isConfirmationStep by remember { mutableStateOf(false) @@ -77,11 +76,11 @@ class SetupPinPresenter @Inject constructor( SetupPinEvents.ClearFailure -> { when (setupPinFailure) { is SetupPinFailure.PinsDontMatch -> { - choosePinEntry = PinEntry.empty(PIN_SIZE) - confirmPinEntry = PinEntry.empty(PIN_SIZE) + choosePinEntry = choosePinEntry.clear() + confirmPinEntry = confirmPinEntry.clear() } is SetupPinFailure.PinBlacklisted -> { - choosePinEntry = PinEntry.empty(PIN_SIZE) + choosePinEntry = choosePinEntry.clear() } null -> Unit } diff --git a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/setup/SetupPinStateProvider.kt b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/setup/SetupPinStateProvider.kt index 1a177b4a83..bb0a46d10c 100644 --- a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/setup/SetupPinStateProvider.kt +++ b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/setup/SetupPinStateProvider.kt @@ -25,20 +25,20 @@ open class SetupPinStateProvider : PreviewParameterProvider { get() = sequenceOf( aSetupPinState(), aSetupPinState( - choosePinEntry = PinEntry.empty(4).fillWith("12") + choosePinEntry = PinEntry.createEmpty(4).fillWith("12") ), aSetupPinState( - choosePinEntry = PinEntry.empty(4).fillWith("1789"), + choosePinEntry = PinEntry.createEmpty(4).fillWith("1789"), isConfirmationStep = true, ), aSetupPinState( - choosePinEntry = PinEntry.empty(4).fillWith("1789"), - confirmPinEntry = PinEntry.empty(4).fillWith("1788"), + choosePinEntry = PinEntry.createEmpty(4).fillWith("1789"), + confirmPinEntry = PinEntry.createEmpty(4).fillWith("1788"), isConfirmationStep = true, creationFailure = SetupPinFailure.PinsDontMatch ), aSetupPinState( - choosePinEntry = PinEntry.empty(4).fillWith("1111"), + choosePinEntry = PinEntry.createEmpty(4).fillWith("1111"), creationFailure = SetupPinFailure.PinBlacklisted ), @@ -46,8 +46,8 @@ open class SetupPinStateProvider : PreviewParameterProvider { } fun aSetupPinState( - choosePinEntry: PinEntry = PinEntry.empty(4), - confirmPinEntry: PinEntry = PinEntry.empty(4), + choosePinEntry: PinEntry = PinEntry.createEmpty(4), + confirmPinEntry: PinEntry = PinEntry.createEmpty(4), isConfirmationStep: Boolean = false, creationFailure: SetupPinFailure? = null, ) = SetupPinState( diff --git a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/setup/validation/PinValidator.kt b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/setup/validation/PinValidator.kt index c7435120aa..20ad023b1c 100644 --- a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/setup/validation/PinValidator.kt +++ b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/setup/validation/PinValidator.kt @@ -16,17 +16,12 @@ package io.element.android.features.lockscreen.impl.setup.validation -import androidx.annotation.VisibleForTesting +import io.element.android.appconfig.LockScreenConfig import io.element.android.features.lockscreen.impl.pin.model.PinEntry import javax.inject.Inject class PinValidator @Inject constructor() { - companion object { - @VisibleForTesting - val BLACKLIST = listOf("0000", "1234") - } - sealed interface Result { data object Valid : Result data class Invalid(val failure: SetupPinFailure) : Result @@ -34,7 +29,7 @@ class PinValidator @Inject constructor() { fun isPinValid(pinEntry: PinEntry): Result { val pinAsText = pinEntry.toText() - val isBlacklisted = BLACKLIST.any { it == pinAsText } + val isBlacklisted = LockScreenConfig.PIN_BLACKLIST.any { it == pinAsText } return if (isBlacklisted) { Result.Invalid(SetupPinFailure.PinBlacklisted) } else { diff --git a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/unlock/PinUnlockEvents.kt b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/unlock/PinUnlockEvents.kt index 5560dedd24..30ee16df02 100644 --- a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/unlock/PinUnlockEvents.kt +++ b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/unlock/PinUnlockEvents.kt @@ -16,7 +16,7 @@ package io.element.android.features.lockscreen.impl.unlock -import io.element.android.features.lockscreen.impl.unlock.numpad.PinKeypadModel +import io.element.android.features.lockscreen.impl.unlock.keypad.PinKeypadModel sealed interface PinUnlockEvents { data class OnPinKeypadPressed(val pinKeypadModel: PinKeypadModel) : PinUnlockEvents 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 783e03c92a..e189a2ab39 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 @@ -23,9 +23,10 @@ import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.runtime.setValue +import io.element.android.appconfig.LockScreenConfig import io.element.android.features.lockscreen.api.LockScreenStateService import io.element.android.features.lockscreen.impl.pin.model.PinEntry -import io.element.android.features.lockscreen.impl.unlock.numpad.PinKeypadModel +import io.element.android.features.lockscreen.impl.unlock.keypad.PinKeypadModel import io.element.android.libraries.architecture.Presenter import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.launch @@ -39,9 +40,11 @@ class PinUnlockPresenter @Inject constructor( @Composable override fun present(): PinUnlockState { var pinEntry by remember { - mutableStateOf(PinEntry.empty(4)) + //TODO fetch size from db + mutableStateOf(PinEntry.createEmpty(LockScreenConfig.PIN_SIZE)) } var remainingAttempts by rememberSaveable { + //TODO fetch from db mutableIntStateOf(3) } var showWrongPinTitle by rememberSaveable { @@ -56,6 +59,7 @@ class PinUnlockPresenter @Inject constructor( is PinUnlockEvents.OnPinKeypadPressed -> { pinEntry = pinEntry.process(event.pinKeypadModel) if (pinEntry.isComplete()) { + //TODO check pin with PinCodeManager coroutineScope.launch { pinStateService.unlock() } } } 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 4f269d2f5a..8ddc942e25 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 @@ -23,7 +23,7 @@ open class PinUnlockStateProvider : PreviewParameterProvider { override val values: Sequence get() = sequenceOf( aPinUnlockState(), - aPinUnlockState(pinEntry = PinEntry.empty(4).fillWith("12")), + aPinUnlockState(pinEntry = PinEntry.createEmpty(4).fillWith("12")), aPinUnlockState(showWrongPinTitle = true), aPinUnlockState(showSignOutPrompt = true), aPinUnlockState(showSignOutPrompt = true, remainingAttempts = 0), @@ -31,7 +31,7 @@ open class PinUnlockStateProvider : PreviewParameterProvider { } fun aPinUnlockState( - pinEntry: PinEntry = PinEntry.empty(4), + pinEntry: PinEntry = PinEntry.createEmpty(4), remainingAttempts: Int = 3, showWrongPinTitle: Boolean = false, showSignOutPrompt: Boolean = false, 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 e2cf522a07..37cb591007 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 @@ -47,7 +47,7 @@ import androidx.compose.ui.unit.dp import io.element.android.features.lockscreen.impl.R import io.element.android.features.lockscreen.impl.pin.model.PinDigit import io.element.android.features.lockscreen.impl.pin.model.PinEntry -import io.element.android.features.lockscreen.impl.unlock.numpad.PinKeypad +import io.element.android.features.lockscreen.impl.unlock.keypad.PinKeypad 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 diff --git a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/unlock/numpad/PinKeypad.kt b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/unlock/keypad/PinKeypad.kt similarity index 99% rename from features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/unlock/numpad/PinKeypad.kt rename to features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/unlock/keypad/PinKeypad.kt index 46b9ca1b82..1056718dd0 100644 --- a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/unlock/numpad/PinKeypad.kt +++ b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/unlock/keypad/PinKeypad.kt @@ -14,7 +14,7 @@ * limitations under the License. */ -package io.element.android.features.lockscreen.impl.unlock.numpad +package io.element.android.features.lockscreen.impl.unlock.keypad import androidx.compose.foundation.background import androidx.compose.foundation.clickable diff --git a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/unlock/numpad/PinKeypadModel.kt b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/unlock/keypad/PinKeypadModel.kt similarity index 92% rename from features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/unlock/numpad/PinKeypadModel.kt rename to features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/unlock/keypad/PinKeypadModel.kt index f1430dcaa5..8d232cb21b 100644 --- a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/unlock/numpad/PinKeypadModel.kt +++ b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/unlock/keypad/PinKeypadModel.kt @@ -14,7 +14,7 @@ * limitations under the License. */ -package io.element.android.features.lockscreen.impl.unlock.numpad +package io.element.android.features.lockscreen.impl.unlock.keypad import androidx.compose.runtime.Immutable diff --git a/features/lockscreen/impl/src/test/kotlin/io/element/android/features/lockscreen/impl/setup/SetupPinPresenterTest.kt b/features/lockscreen/impl/src/test/kotlin/io/element/android/features/lockscreen/impl/setup/SetupPinPresenterTest.kt index 94877fbff5..21005cc722 100644 --- a/features/lockscreen/impl/src/test/kotlin/io/element/android/features/lockscreen/impl/setup/SetupPinPresenterTest.kt +++ b/features/lockscreen/impl/src/test/kotlin/io/element/android/features/lockscreen/impl/setup/SetupPinPresenterTest.kt @@ -20,6 +20,7 @@ import app.cash.molecule.RecompositionMode import app.cash.molecule.moleculeFlow import app.cash.turbine.test import com.google.common.truth.Truth.assertThat +import io.element.android.appconfig.LockScreenConfig import io.element.android.features.lockscreen.impl.pin.model.assertEmpty import io.element.android.features.lockscreen.impl.pin.model.assertText import io.element.android.features.lockscreen.impl.setup.validation.PinValidator @@ -31,7 +32,7 @@ import org.junit.Test class SetupPinPresenterTest { - private val blacklistedPin = PinValidator.BLACKLIST.first() + private val blacklistedPin = LockScreenConfig.PIN_BLACKLIST private val halfCompletePin = "12" private val completePin = "1235" private val mismatchedPin = "1236" 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 6839fe65c7..02919edce0 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 @@ -23,7 +23,7 @@ import com.google.common.truth.Truth.assertThat import io.element.android.features.lockscreen.impl.pin.model.assertEmpty import io.element.android.features.lockscreen.impl.pin.model.assertText import io.element.android.features.lockscreen.impl.state.DefaultLockScreenStateService -import io.element.android.features.lockscreen.impl.unlock.numpad.PinKeypadModel +import io.element.android.features.lockscreen.impl.unlock.keypad.PinKeypadModel import io.element.android.libraries.featureflag.api.FeatureFlags import io.element.android.libraries.featureflag.test.FakeFeatureFlagService import io.element.android.tests.testutils.awaitLastSequentialItem From da4dd44654c0209d8635be4d6d5a7f2687de1b36 Mon Sep 17 00:00:00 2001 From: ganfra Date: Mon, 23 Oct 2023 15:38:24 +0200 Subject: [PATCH 20/22] PIN unlock : adjust ui a bit --- .../android/features/lockscreen/impl/unlock/PinUnlockView.kt | 4 +++- .../features/lockscreen/impl/unlock/keypad/PinKeypad.kt | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) 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 37cb591007..5769f42b35 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 @@ -78,7 +78,9 @@ fun PinUnlockView( ) } val footer = @Composable { - PinUnlockFooter() + PinUnlockFooter( + modifier = Modifier.padding(top = 24.dp) + ) } val content = @Composable { constraints: BoxWithConstraintsScope -> PinKeypad( diff --git a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/unlock/keypad/PinKeypad.kt b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/unlock/keypad/PinKeypad.kt index 1056718dd0..9db5cfe11a 100644 --- a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/unlock/keypad/PinKeypad.kt +++ b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/unlock/keypad/PinKeypad.kt @@ -49,7 +49,7 @@ import io.element.android.libraries.theme.ElementTheme import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.persistentListOf -private val spaceBetweenPinKey = 8.dp +private val spaceBetweenPinKey = 16.dp private val maxSizePinKey = 80.dp @Composable From 4bcb17f09f46b5e6d34267443cf15e0bc0fe4006 Mon Sep 17 00:00:00 2001 From: ElementBot Date: Mon, 23 Oct 2023 13:49:14 +0000 Subject: [PATCH 21/22] Update screenshots --- ...nlock.keypad_null_PinKeypad-D-3_3_null,NEXUS_5,1.0,en].png | 3 +++ ...nlock.keypad_null_PinKeypad-N-3_4_null,NEXUS_5,1.0,en].png | 3 +++ ...nlock.numpad_null_PinKeypad-D-3_3_null,NEXUS_5,1.0,en].png | 3 --- ...nlock.numpad_null_PinKeypad-N-3_4_null,NEXUS_5,1.0,en].png | 3 --- ...unlock_null_PinUnlockView-D-2_2_null_0,NEXUS_5,1.0,en].png | 4 ++-- ...unlock_null_PinUnlockView-D-2_2_null_1,NEXUS_5,1.0,en].png | 4 ++-- ...unlock_null_PinUnlockView-D-2_2_null_2,NEXUS_5,1.0,en].png | 4 ++-- ...unlock_null_PinUnlockView-D-2_2_null_3,NEXUS_5,1.0,en].png | 4 ++-- ...unlock_null_PinUnlockView-D-2_2_null_4,NEXUS_5,1.0,en].png | 4 ++-- ...unlock_null_PinUnlockView-N-2_3_null_0,NEXUS_5,1.0,en].png | 4 ++-- ...unlock_null_PinUnlockView-N-2_3_null_1,NEXUS_5,1.0,en].png | 4 ++-- ...unlock_null_PinUnlockView-N-2_3_null_2,NEXUS_5,1.0,en].png | 4 ++-- ...unlock_null_PinUnlockView-N-2_3_null_3,NEXUS_5,1.0,en].png | 4 ++-- ...unlock_null_PinUnlockView-N-2_3_null_4,NEXUS_5,1.0,en].png | 4 ++-- 14 files changed, 26 insertions(+), 26 deletions(-) create mode 100644 tests/uitests/src/test/snapshots/images/ui_S_t[f.lockscreen.impl.unlock.keypad_null_PinKeypad-D-3_3_null,NEXUS_5,1.0,en].png create mode 100644 tests/uitests/src/test/snapshots/images/ui_S_t[f.lockscreen.impl.unlock.keypad_null_PinKeypad-N-3_4_null,NEXUS_5,1.0,en].png delete mode 100644 tests/uitests/src/test/snapshots/images/ui_S_t[f.lockscreen.impl.unlock.numpad_null_PinKeypad-D-3_3_null,NEXUS_5,1.0,en].png delete mode 100644 tests/uitests/src/test/snapshots/images/ui_S_t[f.lockscreen.impl.unlock.numpad_null_PinKeypad-N-3_4_null,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.lockscreen.impl.unlock.keypad_null_PinKeypad-D-3_3_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.lockscreen.impl.unlock.keypad_null_PinKeypad-D-3_3_null,NEXUS_5,1.0,en].png new file mode 100644 index 0000000000..dbb5213ce6 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.lockscreen.impl.unlock.keypad_null_PinKeypad-D-3_3_null,NEXUS_5,1.0,en].png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:cbb48906ee7f1f18034cd7c64766790689f95f4ea4c0310a98430921b3792aee +size 30854 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.lockscreen.impl.unlock.keypad_null_PinKeypad-N-3_4_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.lockscreen.impl.unlock.keypad_null_PinKeypad-N-3_4_null,NEXUS_5,1.0,en].png new file mode 100644 index 0000000000..4a018f0927 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.lockscreen.impl.unlock.keypad_null_PinKeypad-N-3_4_null,NEXUS_5,1.0,en].png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4ec32849337493132ab88ebc7270728e3c568896e40b0f451b633c924591cbaa +size 28579 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.lockscreen.impl.unlock.numpad_null_PinKeypad-D-3_3_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.lockscreen.impl.unlock.numpad_null_PinKeypad-D-3_3_null,NEXUS_5,1.0,en].png deleted file mode 100644 index fc54ab5f7e..0000000000 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.lockscreen.impl.unlock.numpad_null_PinKeypad-D-3_3_null,NEXUS_5,1.0,en].png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:b14ff41b74e36809f359a7b3b73ffdb9c0c2cd97ec786333bcce9412f05825e6 -size 30608 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.lockscreen.impl.unlock.numpad_null_PinKeypad-N-3_4_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.lockscreen.impl.unlock.numpad_null_PinKeypad-N-3_4_null,NEXUS_5,1.0,en].png deleted file mode 100644 index 62b7c73a26..0000000000 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.lockscreen.impl.unlock.numpad_null_PinKeypad-N-3_4_null,NEXUS_5,1.0,en].png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:1521d9fecaaadcfc7ed4670d997b36a20bd2a84f564794a06cb10bfe7d1ad64e -size 28812 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.lockscreen.impl.unlock_null_PinUnlockView-D-2_2_null_0,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.lockscreen.impl.unlock_null_PinUnlockView-D-2_2_null_0,NEXUS_5,1.0,en].png index e81bbf1c1d..c508164493 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.lockscreen.impl.unlock_null_PinUnlockView-D-2_2_null_0,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.lockscreen.impl.unlock_null_PinUnlockView-D-2_2_null_0,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c369763c4be676d6727a6b0f5cd74d56a9de09b9c3780e1806874d19ba7ffd3f -size 42705 +oid sha256:c94f10441359bdb901ee1f8be9c307312586d6ca54495e88ec231c1e931eb36b +size 38994 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.lockscreen.impl.unlock_null_PinUnlockView-D-2_2_null_1,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.lockscreen.impl.unlock_null_PinUnlockView-D-2_2_null_1,NEXUS_5,1.0,en].png index bcb90d6b4a..07c06a033c 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.lockscreen.impl.unlock_null_PinUnlockView-D-2_2_null_1,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.lockscreen.impl.unlock_null_PinUnlockView-D-2_2_null_1,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a63439f320a1b6ad124cb943f95651f85d2e9cfc34597cb450c803b6dafaefa7 -size 43149 +oid sha256:38456a511fbc72e3d544c8f88138be4f24b6adb3a10629989c037141213a9e19 +size 39441 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.lockscreen.impl.unlock_null_PinUnlockView-D-2_2_null_2,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.lockscreen.impl.unlock_null_PinUnlockView-D-2_2_null_2,NEXUS_5,1.0,en].png index bf2823f6a4..4a8df974cd 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.lockscreen.impl.unlock_null_PinUnlockView-D-2_2_null_2,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.lockscreen.impl.unlock_null_PinUnlockView-D-2_2_null_2,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:165e37ef78a7b09bbd49e8d692ccb27836e35d8535b182d9837a5c3daa5cf3a6 -size 43978 +oid sha256:083c3972e5d019ce1d8565a655bd6f6fb6689e17792ddf7ed282d5eee529a7b6 +size 40292 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.lockscreen.impl.unlock_null_PinUnlockView-D-2_2_null_3,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.lockscreen.impl.unlock_null_PinUnlockView-D-2_2_null_3,NEXUS_5,1.0,en].png index b3ca08978d..02570ec381 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.lockscreen.impl.unlock_null_PinUnlockView-D-2_2_null_3,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.lockscreen.impl.unlock_null_PinUnlockView-D-2_2_null_3,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ecaba43c72a890d85f9894eb987f291967c8ea15bdc09db88d6a72384098d827 -size 48308 +oid sha256:bda49a721fbd19b4cbe0f4dc1b4013154a55e17f78e099f411d1caaef82cfa6c +size 46711 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.lockscreen.impl.unlock_null_PinUnlockView-D-2_2_null_4,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.lockscreen.impl.unlock_null_PinUnlockView-D-2_2_null_4,NEXUS_5,1.0,en].png index 5b8c62dcbf..ee9f61a453 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.lockscreen.impl.unlock_null_PinUnlockView-D-2_2_null_4,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.lockscreen.impl.unlock_null_PinUnlockView-D-2_2_null_4,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:25175242be4133a74541f0bb2d05db95484a65da952031fb8f68a2fdef88a995 -size 45880 +oid sha256:28d2e1634cc0bbf01f6efc2b260625abb26f2105bf1e858f2bd196830d70854c +size 44278 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.lockscreen.impl.unlock_null_PinUnlockView-N-2_3_null_0,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.lockscreen.impl.unlock_null_PinUnlockView-N-2_3_null_0,NEXUS_5,1.0,en].png index fc34314f30..c7864da5cc 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.lockscreen.impl.unlock_null_PinUnlockView-N-2_3_null_0,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.lockscreen.impl.unlock_null_PinUnlockView-N-2_3_null_0,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:699c96cc0d06c85eeda3a3b408877d37445bebf1873a86d6255ba8626ba410b0 -size 39654 +oid sha256:ab8c04689414b5183fa6ab5a479063b478b3d02dfb6bf2df72b1b606c77392ad +size 36278 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.lockscreen.impl.unlock_null_PinUnlockView-N-2_3_null_1,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.lockscreen.impl.unlock_null_PinUnlockView-N-2_3_null_1,NEXUS_5,1.0,en].png index 6d029a3034..5d49a0e78a 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.lockscreen.impl.unlock_null_PinUnlockView-N-2_3_null_1,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.lockscreen.impl.unlock_null_PinUnlockView-N-2_3_null_1,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:233bb8cb261f752ac868c492d075fea9e5af656fcc8ad0d12fbf05b2dd690788 -size 40113 +oid sha256:fda961a2240c1458ad561c8f4e7fa265bbe6c70cf9b0fbfcd1ae0879036a3343 +size 36714 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.lockscreen.impl.unlock_null_PinUnlockView-N-2_3_null_2,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.lockscreen.impl.unlock_null_PinUnlockView-N-2_3_null_2,NEXUS_5,1.0,en].png index af181f44e5..b386f26669 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.lockscreen.impl.unlock_null_PinUnlockView-N-2_3_null_2,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.lockscreen.impl.unlock_null_PinUnlockView-N-2_3_null_2,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:920b9f28c3d2f5e726ad4beeb668e75c285b0e731e6d7eaaf87ca3b2a8b9980b -size 40652 +oid sha256:0cb889338b21dd8e1a913348ff02cd217f48840c4d54b99ed4d89b67dff771bb +size 37254 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.lockscreen.impl.unlock_null_PinUnlockView-N-2_3_null_3,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.lockscreen.impl.unlock_null_PinUnlockView-N-2_3_null_3,NEXUS_5,1.0,en].png index 2616989dcd..39854067a2 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.lockscreen.impl.unlock_null_PinUnlockView-N-2_3_null_3,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.lockscreen.impl.unlock_null_PinUnlockView-N-2_3_null_3,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:28197831dacc61f25d6b3a0080db331ef317283e8032fa5cc4ed457709da0f89 -size 42980 +oid sha256:7b0011f773767d2806b2269281415f910b4770bc0e95dff2a2a29a2c46f9e458 +size 41488 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.lockscreen.impl.unlock_null_PinUnlockView-N-2_3_null_4,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.lockscreen.impl.unlock_null_PinUnlockView-N-2_3_null_4,NEXUS_5,1.0,en].png index ce7df11d83..bb647daed5 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.lockscreen.impl.unlock_null_PinUnlockView-N-2_3_null_4,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.lockscreen.impl.unlock_null_PinUnlockView-N-2_3_null_4,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:652154d82c5f43f91cface3f2e5650ee5a98cf1faed08a80589ab42225bd8120 -size 40557 +oid sha256:d50c34cdf50881d8176d90617c717f7214faeaa4fdce22ec4b93b0e5669b9869 +size 39073 From 20eed4f7d7c7dcd83d92f5e87dba3311e6310919 Mon Sep 17 00:00:00 2001 From: ganfra Date: Mon, 23 Oct 2023 16:03:11 +0200 Subject: [PATCH 22/22] PIN : fix tests with new LockScreenConfig --- .../io/element/android/appconfig/LockScreenConfig.kt | 6 +++--- .../lockscreen/impl/setup/validation/PinValidator.kt | 7 +++++-- .../lockscreen/impl/setup/SetupPinPresenterTest.kt | 5 ++--- 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/appconfig/src/main/kotlin/io/element/android/appconfig/LockScreenConfig.kt b/appconfig/src/main/kotlin/io/element/android/appconfig/LockScreenConfig.kt index 5930f53428..9427a1f9c7 100644 --- a/appconfig/src/main/kotlin/io/element/android/appconfig/LockScreenConfig.kt +++ b/appconfig/src/main/kotlin/io/element/android/appconfig/LockScreenConfig.kt @@ -19,14 +19,14 @@ package io.element.android.appconfig object LockScreenConfig { /** - * Whether the LockScreen is mandatory or not. + * Whether the PIN is mandatory or not. */ - const val IS_MANDATORY: Boolean = false + const val IS_PIN_MANDATORY: Boolean = false /** * Some PINs are blacklisted. */ - val PIN_BLACKLIST = listOf("0000", "1234") + val PIN_BLACKLIST = setOf("0000", "1234") /** * The size of the PIN. diff --git a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/setup/validation/PinValidator.kt b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/setup/validation/PinValidator.kt index 20ad023b1c..b164ee8c88 100644 --- a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/setup/validation/PinValidator.kt +++ b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/setup/validation/PinValidator.kt @@ -20,7 +20,10 @@ import io.element.android.appconfig.LockScreenConfig import io.element.android.features.lockscreen.impl.pin.model.PinEntry import javax.inject.Inject -class PinValidator @Inject constructor() { +class PinValidator internal constructor(private val pinBlacklist: Set) { + + @Inject + constructor() : this(LockScreenConfig.PIN_BLACKLIST) sealed interface Result { data object Valid : Result @@ -29,7 +32,7 @@ class PinValidator @Inject constructor() { fun isPinValid(pinEntry: PinEntry): Result { val pinAsText = pinEntry.toText() - val isBlacklisted = LockScreenConfig.PIN_BLACKLIST.any { it == pinAsText } + val isBlacklisted = pinBlacklist.any { it == pinAsText } return if (isBlacklisted) { Result.Invalid(SetupPinFailure.PinBlacklisted) } else { diff --git a/features/lockscreen/impl/src/test/kotlin/io/element/android/features/lockscreen/impl/setup/SetupPinPresenterTest.kt b/features/lockscreen/impl/src/test/kotlin/io/element/android/features/lockscreen/impl/setup/SetupPinPresenterTest.kt index 21005cc722..ff797b52f4 100644 --- a/features/lockscreen/impl/src/test/kotlin/io/element/android/features/lockscreen/impl/setup/SetupPinPresenterTest.kt +++ b/features/lockscreen/impl/src/test/kotlin/io/element/android/features/lockscreen/impl/setup/SetupPinPresenterTest.kt @@ -20,7 +20,6 @@ import app.cash.molecule.RecompositionMode import app.cash.molecule.moleculeFlow import app.cash.turbine.test import com.google.common.truth.Truth.assertThat -import io.element.android.appconfig.LockScreenConfig import io.element.android.features.lockscreen.impl.pin.model.assertEmpty import io.element.android.features.lockscreen.impl.pin.model.assertText import io.element.android.features.lockscreen.impl.setup.validation.PinValidator @@ -32,7 +31,7 @@ import org.junit.Test class SetupPinPresenterTest { - private val blacklistedPin = LockScreenConfig.PIN_BLACKLIST + private val blacklistedPin = "1234" private val halfCompletePin = "12" private val completePin = "1235" private val mismatchedPin = "1236" @@ -101,6 +100,6 @@ class SetupPinPresenterTest { } private fun createSetupPinPresenter(): SetupPinPresenter { - return SetupPinPresenter(PinValidator(), aBuildMeta()) + return SetupPinPresenter(PinValidator(setOf(blacklistedPin)), aBuildMeta()) } }