PM-27597: Update Yubikey illustration to match the rest of the app (#6087)

This commit is contained in:
David Perez 2025-11-04 16:15:40 -06:00 committed by GitHub
parent 2bb06063c7
commit bfbe47f48f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
10 changed files with 137 additions and 64 deletions

View File

@ -7,24 +7,19 @@ import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.navigationBarsPadding
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.text.KeyboardActions
import androidx.compose.foundation.verticalScroll
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBarDefaults
import androidx.compose.material3.rememberTopAppBarState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.input.nestedscroll.nestedScroll
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.input.ImeAction
@ -58,7 +53,6 @@ import com.bitwarden.ui.platform.manager.IntentManager
import com.bitwarden.ui.platform.resource.BitwardenDrawable
import com.bitwarden.ui.platform.resource.BitwardenString
import com.bitwarden.ui.platform.theme.BitwardenTheme
import com.bitwarden.ui.util.asText
import com.x8bit.bitwarden.ui.auth.feature.twofactorlogin.util.description
import com.x8bit.bitwarden.ui.auth.feature.twofactorlogin.util.title
import com.x8bit.bitwarden.ui.platform.composition.LocalAuthTabLaunchers
@ -126,19 +120,18 @@ fun TwoFactorLoginScreen(
},
)
val scrollBehavior = TopAppBarDefaults.pinnedScrollBehavior(rememberTopAppBarState())
val title = if (state.isNewDeviceVerification) {
BitwardenString.verify_your_identity.asText()
} else {
state.authMethod.title
}
val scrollBehavior = TopAppBarDefaults.pinnedScrollBehavior()
BitwardenScaffold(
modifier = Modifier
.fillMaxSize()
.nestedScroll(scrollBehavior.nestedScrollConnection),
topBar = {
BitwardenTopAppBar(
title = title(),
title = if (state.isNewDeviceVerification) {
stringResource(id = BitwardenString.verify_your_identity)
} else {
state.authMethod.title()
},
scrollBehavior = scrollBehavior,
navigationIcon = rememberVectorPainter(id = BitwardenDrawable.ic_close),
navigationIconContentDescription = stringResource(id = BitwardenString.close),
@ -230,55 +223,45 @@ private fun TwoFactorLoginScreenContent(
modifier = modifier
.verticalScroll(rememberScrollState()),
) {
if (state.authMethod != TwoFactorAuthMethod.YUBI_KEY) {
state.imageRes?.let {
Spacer(modifier = Modifier.height(12.dp))
Image(
painter = painterResource(id = it),
contentDescription = null,
state.imageRes?.let {
Spacer(modifier = Modifier.height(12.dp))
Image(
painter = painterResource(id = it),
contentDescription = null,
modifier = Modifier
.standardHorizontalMargin()
.size(124.dp),
)
Spacer(modifier = Modifier.height(12.dp))
}
if (state.isNewDeviceVerification) {
Spacer(modifier = Modifier.height(height = 12.dp))
Text(
text = stringResource(id = BitwardenString.enter_verification_code_new_device),
textAlign = TextAlign.Center,
style = BitwardenTheme.typography.bodyMedium,
color = BitwardenTheme.colorScheme.text.primary,
modifier = Modifier
.standardHorizontalMargin()
.fillMaxWidth(),
)
} else {
state.authMethod.description(email = state.displayEmail)?.let { text ->
Spacer(modifier = Modifier.height(height = 12.dp))
Text(
text = text(),
textAlign = TextAlign.Center,
style = BitwardenTheme.typography.bodyMedium,
color = BitwardenTheme.colorScheme.text.primary,
modifier = Modifier
.standardHorizontalMargin()
.size(124.dp),
)
Spacer(modifier = Modifier.height(12.dp))
}
}
Spacer(modifier = Modifier.height(height = 12.dp))
Text(
text = if (state.isNewDeviceVerification) {
stringResource(BitwardenString.enter_verification_code_new_device)
} else {
state.authMethod.description(
state.displayEmail,
).invoke()
},
textAlign = TextAlign.Center,
style = BitwardenTheme.typography.bodyMedium,
color = BitwardenTheme.colorScheme.text.primary,
modifier = Modifier
.standardHorizontalMargin()
.fillMaxWidth(),
)
Spacer(modifier = Modifier.height(12.dp))
if (state.authMethod == TwoFactorAuthMethod.YUBI_KEY) {
state.imageRes?.let {
Spacer(modifier = Modifier.height(12.dp))
Image(
painter = painterResource(id = it),
contentDescription = null,
alignment = Alignment.Center,
contentScale = ContentScale.FillWidth,
modifier = Modifier
.padding(horizontal = 24.dp)
.clip(RoundedCornerShape(4.dp))
.fillMaxWidth(),
)
Spacer(modifier = Modifier.height(24.dp))
}
}
Spacer(modifier = Modifier.height(12.dp))
if (state.shouldShowCodeInput) {
BitwardenPasswordField(
value = state.codeInput,

View File

@ -29,11 +29,12 @@ val TwoFactorAuthMethod.title: Text
/**
* Get the description for the given auth method.
*/
fun TwoFactorAuthMethod.description(email: String): Text = when (this) {
fun TwoFactorAuthMethod.description(email: String): Text? = when (this) {
TwoFactorAuthMethod.AUTHENTICATOR_APP -> BitwardenString.enter_verification_code_app.asText()
TwoFactorAuthMethod.DUO -> {
BitwardenString.follow_the_steps_from_duo_to_finish_logging_in.asText()
}
TwoFactorAuthMethod.DUO_ORGANIZATION -> {
BitwardenString.duo_two_step_login_is_required_for_your_account
.asText()
@ -45,8 +46,12 @@ fun TwoFactorAuthMethod.description(email: String): Text = when (this) {
TwoFactorAuthMethod.WEB_AUTH -> {
BitwardenString.continue_to_complete_web_authn_verification.asText()
}
TwoFactorAuthMethod.YUBI_KEY -> BitwardenString.yubi_key_instruction.asText()
else -> "".asText()
TwoFactorAuthMethod.U2F,
TwoFactorAuthMethod.REMEMBER,
TwoFactorAuthMethod.RECOVERY_CODE,
-> null
}
/**
@ -122,7 +127,7 @@ val TwoFactorAuthMethod.shouldUseNfc: Boolean
@get:DrawableRes
val TwoFactorAuthMethod.imageRes: Int?
get() = when (this) {
TwoFactorAuthMethod.YUBI_KEY -> BitwardenDrawable.img_yubi_key
TwoFactorAuthMethod.YUBI_KEY -> BitwardenDrawable.ill_yubi_key
TwoFactorAuthMethod.EMAIL -> BitwardenDrawable.ill_new_device_verification
TwoFactorAuthMethod.AUTHENTICATOR_APP -> BitwardenDrawable.ill_authenticator
else -> null

View File

@ -43,8 +43,8 @@ class TwoFactorAuthMethodExtensionTest {
TwoFactorAuthMethod.DUO to
BitwardenString.follow_the_steps_from_duo_to_finish_logging_in.asText(),
TwoFactorAuthMethod.YUBI_KEY to BitwardenString.yubi_key_instruction.asText(),
TwoFactorAuthMethod.U2F to "".asText(),
TwoFactorAuthMethod.REMEMBER to "".asText(),
TwoFactorAuthMethod.U2F to null,
TwoFactorAuthMethod.REMEMBER to null,
TwoFactorAuthMethod.DUO_ORGANIZATION to
BitwardenString.duo_two_step_login_is_required_for_your_account
.asText()
@ -54,7 +54,7 @@ class TwoFactorAuthMethodExtensionTest {
),
TwoFactorAuthMethod.WEB_AUTH to
BitwardenString.continue_to_complete_web_authn_verification.asText(),
TwoFactorAuthMethod.RECOVERY_CODE to "".asText(),
TwoFactorAuthMethod.RECOVERY_CODE to null,
)
.forEach { (type, title) ->
assertEquals(
@ -142,7 +142,7 @@ class TwoFactorAuthMethodExtensionTest {
TwoFactorAuthMethod.AUTHENTICATOR_APP to BitwardenDrawable.ill_authenticator,
TwoFactorAuthMethod.EMAIL to BitwardenDrawable.ill_new_device_verification,
TwoFactorAuthMethod.DUO to null,
TwoFactorAuthMethod.YUBI_KEY to BitwardenDrawable.img_yubi_key,
TwoFactorAuthMethod.YUBI_KEY to BitwardenDrawable.ill_yubi_key,
TwoFactorAuthMethod.U2F to null,
TwoFactorAuthMethod.REMEMBER to null,
TwoFactorAuthMethod.DUO_ORGANIZATION to null,

Binary file not shown.

Before

Width:  |  Height:  |  Size: 182 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 90 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 300 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 583 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 901 KiB

View File

@ -0,0 +1,85 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="124dp"
android:height="124dp"
android:viewportWidth="124"
android:viewportHeight="124">
<path
android:name="primary"
android:fillColor="#DBE5F6"
android:pathData="M20.67,23.25C20.67,18.97 24.14,15.5 28.42,15.5H116.25C120.53,15.5 124,18.97 124,23.25V85.25C124,89.53 120.53,93 116.25,93H28.42C24.14,93 20.67,89.53 20.67,85.25V23.25Z" />
<path
android:name="outline"
android:fillColor="#020F66"
android:fillType="evenOdd"
android:pathData="M116.25,18.08H28.42C25.56,18.08 23.25,20.4 23.25,23.25V85.25C23.25,88.1 25.56,90.42 28.42,90.42H116.25C119.1,90.42 121.42,88.1 121.42,85.25V23.25C121.42,20.4 119.1,18.08 116.25,18.08ZM28.42,15.5C24.14,15.5 20.67,18.97 20.67,23.25V85.25C20.67,89.53 24.14,93 28.42,93H116.25C120.53,93 124,89.53 124,85.25V23.25C124,18.97 120.53,15.5 116.25,15.5H28.42Z" />
<path
android:name="secondary"
android:fillColor="#AAC3EF"
android:pathData="M94.29,59.42C94.29,71.54 84.46,81.37 72.33,81.37C60.21,81.37 50.38,71.54 50.38,59.42C50.38,47.29 60.21,37.46 72.33,37.46C84.46,37.46 94.29,47.29 94.29,59.42Z" />
<path
android:name="accent"
android:fillColor="#FFBF00"
android:pathData="M59.42,55.54C59.42,53.4 61.15,51.67 63.29,51.67H81.38C83.52,51.67 85.25,53.4 85.25,55.54V68.46C85.25,70.6 83.52,72.33 81.38,72.33H63.29C61.15,72.33 59.42,70.6 59.42,68.46V55.54Z" />
<path
android:name="outline"
android:fillColor="#020F66"
android:fillType="evenOdd"
android:pathData="M81.38,54.25H63.29C62.58,54.25 62,54.83 62,55.54V68.46C62,69.17 62.58,69.75 63.29,69.75H81.38C82.09,69.75 82.67,69.17 82.67,68.46V55.54C82.67,54.83 82.09,54.25 81.38,54.25ZM63.29,51.67C61.15,51.67 59.42,53.4 59.42,55.54V68.46C59.42,70.6 61.15,72.33 63.29,72.33H81.38C83.52,72.33 85.25,70.6 85.25,68.46V55.54C85.25,53.4 83.52,51.67 81.38,51.67H63.29Z" />
<path
android:name="outline"
android:fillColor="#020F66"
android:pathData="M71.04,59.42C71.04,58.7 71.62,58.13 72.33,58.13C73.05,58.13 73.63,58.7 73.63,59.42V64.58C73.63,65.3 73.05,65.88 72.33,65.88C71.62,65.88 71.04,65.3 71.04,64.58V59.42Z" />
<path
android:name="outline"
android:fillColor="#020F66"
android:fillType="evenOdd"
android:pathData="M65.88,50.38C65.88,46.81 68.77,43.92 72.33,43.92C75.9,43.92 78.79,46.81 78.79,50.38V51.67H76.21V50.38C76.21,48.24 74.47,46.5 72.33,46.5C70.19,46.5 68.46,48.24 68.46,50.38V51.67H65.88V50.38Z" />
<path
android:name="outline"
android:fillColor="#020F66"
android:fillType="evenOdd"
android:pathData="M122.71,31L21.96,31L21.96,28.42L122.71,28.42L122.71,31Z" />
<path
android:name="outline"
android:fillColor="#020F66"
android:pathData="M118.83,23.25C118.83,24.68 117.68,25.83 116.25,25.83C114.82,25.83 113.67,24.68 113.67,23.25C113.67,21.82 114.82,20.67 116.25,20.67C117.68,20.67 118.83,21.82 118.83,23.25Z" />
<path
android:name="outline"
android:fillColor="#020F66"
android:pathData="M111.08,23.25C111.08,24.68 109.93,25.83 108.5,25.83C107.07,25.83 105.92,24.68 105.92,23.25C105.92,21.82 107.07,20.67 108.5,20.67C109.93,20.67 111.08,21.82 111.08,23.25Z" />
<path
android:name="outline"
android:fillColor="#020F66"
android:pathData="M103.33,23.25C103.33,24.68 102.18,25.83 100.75,25.83C99.32,25.83 98.17,24.68 98.17,23.25C98.17,21.82 99.32,20.67 100.75,20.67C102.18,20.67 103.33,21.82 103.33,23.25Z" />
<path
android:name="outline"
android:fillColor="#020F66"
android:pathData="M11.63,40.04C11.63,38.61 12.78,37.46 14.21,37.46H33.58C35.01,37.46 36.17,38.61 36.17,40.04V59.42H11.63V40.04Z" />
<path
android:name="accent"
android:fillColor="#FFBF00"
android:pathData="M15.5,41.33H19.38V55.54H15.5V41.33Z" />
<path
android:name="accent"
android:fillColor="#FFBF00"
android:pathData="M21.96,43.92H25.83V55.54H21.96V43.92Z" />
<path
android:name="accent"
android:fillColor="#FFBF00"
android:pathData="M28.42,41.33H32.29V55.54H28.42V41.33Z" />
<path
android:name="secondary"
android:fillColor="#AAC3EF"
android:fillType="evenOdd"
android:pathData="M10.33,56.83C7.48,56.83 5.17,59.15 5.17,62V113.67C5.17,116.52 7.48,118.83 10.33,118.83H37.46C40.31,118.83 42.63,116.52 42.63,113.67V62C42.63,59.15 40.31,56.83 37.46,56.83H10.33ZM23.9,103.33C25.68,103.33 27.13,104.78 27.13,106.56C27.13,108.35 25.68,109.79 23.9,109.79C22.11,109.79 20.67,108.35 20.67,106.56C20.67,104.78 22.11,103.33 23.9,103.33Z" />
<path
android:name="outline"
android:fillColor="#020F66"
android:fillType="evenOdd"
android:pathData="M10.33,59.42C8.91,59.42 7.75,60.57 7.75,62V113.67C7.75,115.09 8.91,116.25 10.33,116.25H37.46C38.89,116.25 40.04,115.09 40.04,113.67V62C40.04,60.57 38.89,59.42 37.46,59.42H10.33ZM23.9,100.75C27.11,100.75 29.71,103.35 29.71,106.56C29.71,109.77 27.11,112.38 23.9,112.38C20.69,112.38 18.08,109.77 18.08,106.56C18.08,103.35 20.69,100.75 23.9,100.75ZM5.17,62C5.17,59.15 7.48,56.83 10.33,56.83H37.46C40.31,56.83 42.63,59.15 42.63,62V113.67C42.63,116.52 40.31,118.83 37.46,118.83H10.33C7.48,118.83 5.17,116.52 5.17,113.67V62ZM27.13,106.56C27.13,104.78 25.68,103.33 23.9,103.33C22.11,103.33 20.67,104.78 20.67,106.56C20.67,108.35 22.11,109.79 23.9,109.79C25.68,109.79 27.13,108.35 27.13,106.56Z" />
<path
android:name="tertiary"
android:fillColor="#ffffff"
android:fillType="evenOdd"
android:pathData="M23.9,93C29.25,93 33.58,88.66 33.58,83.31C33.58,77.96 29.25,73.63 23.9,73.63C18.55,73.63 14.21,77.96 14.21,83.31C14.21,88.66 18.55,93 23.9,93ZM23.9,95.58C30.67,95.58 36.17,90.09 36.17,83.31C36.17,76.54 30.67,71.04 23.9,71.04C17.12,71.04 11.63,76.54 11.63,83.31C11.63,90.09 17.12,95.58 23.9,95.58Z" />
</vector>

View File

@ -179,8 +179,8 @@
<string name="send_verification_code_again">Resend code</string>
<string name="verification_email_not_sent">Could not send verification email. Try again.</string>
<string name="verification_email_sent">Verification email sent</string>
<string name="yubi_key_instruction">To continue, hold your YubiKey NEO against the back of the device or insert your YubiKey into your devices USB port, then touch its button.</string>
<string name="yubi_key_title">YubiKey security key</string>
<string name="yubi_key_instruction">To continue, hold your Yubico security key against the back of the device or insert it into your devices USB port, then touch its button.</string>
<string name="yubi_key_title">Yubico security key</string>
<string name="add_new_attachment">Add new attachment</string>
<string name="attachments">Attachments</string>
<string name="unable_to_download_file">Unable to download file.</string>