diff --git a/app/src/main/java/com/x8bit/bitwarden/ui/platform/feature/settings/accountsecurity/PinInputDialog.kt b/app/src/main/java/com/x8bit/bitwarden/ui/platform/feature/settings/accountsecurity/PinInputDialog.kt
index dd4e09c69a..0794e5d253 100644
--- a/app/src/main/java/com/x8bit/bitwarden/ui/platform/feature/settings/accountsecurity/PinInputDialog.kt
+++ b/app/src/main/java/com/x8bit/bitwarden/ui/platform/feature/settings/accountsecurity/PinInputDialog.kt
@@ -38,6 +38,8 @@ import com.x8bit.bitwarden.ui.platform.components.model.CardStyle
import com.x8bit.bitwarden.ui.platform.components.util.maxDialogHeight
import com.x8bit.bitwarden.ui.platform.theme.BitwardenTheme
+private const val MINIMUM_PIN_LENGTH: Int = 4
+
/**
* A dialog for setting a user's PIN.
*
@@ -138,6 +140,7 @@ fun PinInputDialog(
BitwardenFilledButton(
label = stringResource(id = R.string.submit),
+ isEnabled = !isPinCreation || pin.length >= MINIMUM_PIN_LENGTH,
onClick = { onSubmitClick(pin) },
modifier = Modifier.testTag(tag = "AcceptAlertButton"),
)
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 09eb9d7b6e..82204babf1 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -480,7 +480,7 @@ Scanning will happen automatically.
Unlock
Unlock vault
30 minutes
- Set your PIN code for unlocking Bitwarden. Your PIN settings will be reset if you ever fully log out of the application.
+ Your PIN must be at least 4 characters. Your PIN settings will be reset if you ever fully log out of the application.
Logged in as %1$s on %2$s.
Your vault is locked. Verify your master password to continue.
Your vault is locked. Verify your PIN code to continue.
diff --git a/app/src/test/java/com/x8bit/bitwarden/ui/auth/feature/accountsetup/SetupUnlockScreenTest.kt b/app/src/test/java/com/x8bit/bitwarden/ui/auth/feature/accountsetup/SetupUnlockScreenTest.kt
index ed27aa1b14..93e66d730f 100644
--- a/app/src/test/java/com/x8bit/bitwarden/ui/auth/feature/accountsetup/SetupUnlockScreenTest.kt
+++ b/app/src/test/java/com/x8bit/bitwarden/ui/auth/feature/accountsetup/SetupUnlockScreenTest.kt
@@ -2,6 +2,7 @@ package com.x8bit.bitwarden.ui.auth.feature.accountsetup
import androidx.compose.ui.test.assertIsDisplayed
import androidx.compose.ui.test.assertIsEnabled
+import androidx.compose.ui.test.assertIsNotEnabled
import androidx.compose.ui.test.assertIsOff
import androidx.compose.ui.test.assertIsOn
import androidx.compose.ui.test.filterToOne
@@ -257,8 +258,8 @@ class SetupUnlockScreenTest : BaseComposeTest() {
.assertIsDisplayed()
composeTestRule
.onAllNodesWithText(
- text = "Set your PIN code for unlocking Bitwarden. Your PIN settings will be reset if " +
- "you ever fully log out of the application.",
+ text = "Your PIN must be at least 4 characters. Your PIN settings will be reset " +
+ "if you ever fully log out of the application.",
)
.filterToOne(hasAnyAncestor(isDialog()))
.assertIsDisplayed()
@@ -306,9 +307,8 @@ class SetupUnlockScreenTest : BaseComposeTest() {
composeTestRule.assertNoDialogExists()
}
- @Suppress("MaxLineLength")
@Test
- fun `PIN input dialog Submit click with empty pin should clear the dialog and send UnlockWithPinToggle Disabled`() {
+ fun `PIN input dialog with empty pin should disable submit button`() {
mutableStateFlow.update {
it.copy(isUnlockWithPinEnabled = false)
}
@@ -320,14 +320,7 @@ class SetupUnlockScreenTest : BaseComposeTest() {
composeTestRule
.onAllNodesWithText(text = "Submit")
.filterToOne(hasAnyAncestor(isDialog()))
- .performClick()
-
- verify {
- viewModel.trySendAction(
- SetupUnlockAction.UnlockWithPinToggle(UnlockWithPinState.Disabled),
- )
- }
- composeTestRule.assertNoDialogExists()
+ .assertIsNotEnabled()
}
@Suppress("MaxLineLength")
diff --git a/app/src/test/java/com/x8bit/bitwarden/ui/platform/feature/settings/accountsecurity/AccountSecurityScreenTest.kt b/app/src/test/java/com/x8bit/bitwarden/ui/platform/feature/settings/accountsecurity/AccountSecurityScreenTest.kt
index 7eacd87a42..4fca3b62f4 100644
--- a/app/src/test/java/com/x8bit/bitwarden/ui/platform/feature/settings/accountsecurity/AccountSecurityScreenTest.kt
+++ b/app/src/test/java/com/x8bit/bitwarden/ui/platform/feature/settings/accountsecurity/AccountSecurityScreenTest.kt
@@ -3,6 +3,7 @@ package com.x8bit.bitwarden.ui.platform.feature.settings.accountsecurity
import androidx.compose.ui.test.assert
import androidx.compose.ui.test.assertIsDisplayed
import androidx.compose.ui.test.assertIsFocused
+import androidx.compose.ui.test.assertIsNotEnabled
import androidx.compose.ui.test.assertIsOff
import androidx.compose.ui.test.assertIsOn
import androidx.compose.ui.test.filterToOne
@@ -352,8 +353,8 @@ class AccountSecurityScreenTest : BaseComposeTest() {
.assertIsDisplayed()
composeTestRule
.onAllNodesWithText(
- "Set your PIN code for unlocking Bitwarden. Your PIN settings will be reset if " +
- "you ever fully log out of the application.",
+ text = "Your PIN must be at least 4 characters. Your PIN settings will be reset " +
+ "if you ever fully log out of the application.",
)
.filterToOne(hasAnyAncestor(isDialog()))
.assertIsDisplayed()
@@ -402,9 +403,8 @@ class AccountSecurityScreenTest : BaseComposeTest() {
composeTestRule.assertNoDialogExists()
}
- @Suppress("MaxLineLength")
@Test
- fun `PIN input dialog Submit click with empty pin should clear the dialog and send UnlockWithPinToggle Disabled`() {
+ fun `PIN input dialog with empty pin should disable the Submit button`() {
mutableStateFlow.update {
it.copy(isUnlockWithPinEnabled = false)
}
@@ -414,16 +414,9 @@ class AccountSecurityScreenTest : BaseComposeTest() {
.performClick()
composeTestRule
- .onAllNodesWithText("Submit")
+ .onAllNodesWithText(text = "Submit")
.filterToOne(hasAnyAncestor(isDialog()))
- .performClick()
-
- verify {
- viewModel.trySendAction(
- AccountSecurityAction.UnlockWithPinToggle(UnlockWithPinState.Disabled),
- )
- }
- composeTestRule.assertNoDialogExists()
+ .assertIsNotEnabled()
}
@Suppress("MaxLineLength")