Add missing screenshot and improve UX when user enter wrong pin then correct pin.

This commit is contained in:
Benoit Marty 2026-05-06 14:48:55 +02:00 committed by Benoit Marty
parent d18b529285
commit ae044607c7
2 changed files with 42 additions and 23 deletions

View file

@ -20,7 +20,7 @@ open class PinUnlockStateProvider : PreviewParameterProvider<PinUnlockState> {
override val values: Sequence<PinUnlockState>
get() = sequenceOf(
aPinUnlockState(),
aPinUnlockState(pinEntry = PinEntry.createEmpty(4).fillWith("12")),
aPinUnlockState(pinEntry = AsyncData.Success(PinEntry.createEmpty(4).fillWith("12"))),
aPinUnlockState(showWrongPinTitle = true),
aPinUnlockState(showSignOutPrompt = true),
aPinUnlockState(showBiometricUnlock = false),
@ -31,11 +31,18 @@ open class PinUnlockStateProvider : PreviewParameterProvider<PinUnlockState> {
BiometricUnlockError(BiometricPrompt.ERROR_LOCKOUT, "Biometric auth disabled")
)
),
aPinUnlockState(showSignOutPrompt = true, pinEntry = AsyncData.Failure(Exception("An error occurred"))),
// User enter wrong pin once, and then correct PIN. In this case, the error (with counter reset to 3) should not be displayed.
aPinUnlockState(
remainingAttempts = AsyncData.Success(2),
showWrongPinTitle = true,
isUnlocked = true,
),
)
}
fun aPinUnlockState(
pinEntry: PinEntry = PinEntry.createEmpty(4),
pinEntry: AsyncData<PinEntry> = AsyncData.Success(PinEntry.createEmpty(4)),
remainingAttempts: AsyncData<Int> = AsyncData.Success(3),
showWrongPinTitle: Boolean = false,
showSignOutPrompt: Boolean = false,
@ -44,7 +51,7 @@ fun aPinUnlockState(
isUnlocked: Boolean = false,
signOutAction: AsyncAction<Unit> = AsyncAction.Uninitialized,
) = PinUnlockState(
pinEntry = AsyncData.Success(pinEntry),
pinEntry = pinEntry,
showWrongPinTitle = showWrongPinTitle,
remainingAttempts = remainingAttempts,
showSignOutPrompt = showSignOutPrompt,

View file

@ -108,10 +108,10 @@ private fun PinUnlockPage(
) {
BoxWithConstraints {
val commonModifier = Modifier
.fillMaxSize()
.systemBarsPadding()
.imePadding()
.padding(all = 20.dp)
.fillMaxSize()
.systemBarsPadding()
.imePadding()
.padding(all = 20.dp)
val header = @Composable {
PinUnlockHeader(
@ -147,8 +147,8 @@ private fun PinUnlockPage(
state.eventSink(PinUnlockEvent.OnPinEntryChanged(it))
},
modifier = Modifier
.focusRequester(focusRequester)
.fillMaxWidth()
.focusRequester(focusRequester)
.fillMaxWidth()
)
}
} else {
@ -217,8 +217,8 @@ private fun PinUnlockCompactView(
}
BoxWithConstraints(
modifier = Modifier
.weight(1f)
.fillMaxHeight(),
.weight(1f)
.fillMaxHeight(),
contentAlignment = Alignment.Center,
) {
content()
@ -239,9 +239,9 @@ private fun PinUnlockExpandedView(
header()
BoxWithConstraints(
modifier = Modifier
.weight(1f)
.fillMaxWidth()
.padding(top = 40.dp),
.weight(1f)
.fillMaxWidth()
.padding(top = 40.dp),
) {
content()
}
@ -274,8 +274,8 @@ private fun PinDot(
}
Box(
modifier = Modifier
.size(14.dp)
.background(backgroundColor, CircleShape)
.size(14.dp)
.background(backgroundColor, CircleShape)
)
}
@ -311,14 +311,26 @@ private fun PinUnlockHeader(
)
Spacer(Modifier.height(8.dp))
val remainingAttempts = state.remainingAttempts.dataOrNull()
val subtitle = if (remainingAttempts != null) {
if (state.showWrongPinTitle) {
pluralStringResource(id = R.plurals.screen_app_lock_subtitle_wrong_pin, count = remainingAttempts, remainingAttempts)
} else {
pluralStringResource(id = R.plurals.screen_app_lock_subtitle, count = remainingAttempts, remainingAttempts)
val subtitle = when {
state.isUnlocked -> {
// Hide any previous error
""
}
} else {
""
remainingAttempts != null ->
if (state.showWrongPinTitle) {
pluralStringResource(
id = R.plurals.screen_app_lock_subtitle_wrong_pin,
count = remainingAttempts,
remainingAttempts,
)
} else {
pluralStringResource(
id = R.plurals.screen_app_lock_subtitle,
count = remainingAttempts,
remainingAttempts,
)
}
else -> ""
}
val subtitleColor = if (state.showWrongPinTitle) {
ElementTheme.colors.textCriticalPrimary