mirror of
https://github.com/bitwarden/android.git
synced 2025-12-10 00:06:22 -06:00
PM-28522: Update the Login With Device Screen (#6184)
This commit is contained in:
parent
f02b374e98
commit
ca7a65fc95
@ -1,16 +1,11 @@
|
||||
package com.x8bit.bitwarden.ui.auth.feature.loginwithdevice
|
||||
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.PaddingValues
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.defaultMinSize
|
||||
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.verticalScroll
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
@ -20,7 +15,6 @@ 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.input.nestedscroll.nestedScroll
|
||||
import androidx.compose.ui.platform.testTag
|
||||
@ -30,13 +24,17 @@ import androidx.compose.ui.unit.dp
|
||||
import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import com.bitwarden.ui.platform.base.util.EventsEffect
|
||||
import com.bitwarden.ui.platform.base.util.standardHorizontalMargin
|
||||
import com.bitwarden.ui.platform.components.appbar.BitwardenTopAppBar
|
||||
import com.bitwarden.ui.platform.components.button.BitwardenOutlinedButton
|
||||
import com.bitwarden.ui.platform.components.content.BitwardenLoadingContent
|
||||
import com.bitwarden.ui.platform.components.dialog.BitwardenBasicDialog
|
||||
import com.bitwarden.ui.platform.components.dialog.BitwardenLoadingDialog
|
||||
import com.bitwarden.ui.platform.components.indicator.BitwardenCircularProgressIndicator
|
||||
import com.bitwarden.ui.platform.components.field.BitwardenTextField
|
||||
import com.bitwarden.ui.platform.components.field.model.TextToolbarType
|
||||
import com.bitwarden.ui.platform.components.model.CardStyle
|
||||
import com.bitwarden.ui.platform.components.scaffold.BitwardenScaffold
|
||||
import com.bitwarden.ui.platform.components.text.BitwardenClickableText
|
||||
import com.bitwarden.ui.platform.components.text.BitwardenHyperTextLink
|
||||
import com.bitwarden.ui.platform.components.util.rememberVectorPainter
|
||||
import com.bitwarden.ui.platform.resource.BitwardenDrawable
|
||||
import com.bitwarden.ui.platform.resource.BitwardenString
|
||||
@ -120,111 +118,99 @@ private fun LoginWithDeviceScreenContent(
|
||||
modifier = modifier
|
||||
.verticalScroll(rememberScrollState()),
|
||||
) {
|
||||
Spacer(modifier = Modifier.height(height = 24.dp))
|
||||
|
||||
Text(
|
||||
text = state.title(),
|
||||
textAlign = TextAlign.Start,
|
||||
style = BitwardenTheme.typography.headlineMedium,
|
||||
textAlign = TextAlign.Center,
|
||||
style = BitwardenTheme.typography.titleMedium,
|
||||
color = BitwardenTheme.colorScheme.text.primary,
|
||||
modifier = Modifier
|
||||
.padding(horizontal = 16.dp)
|
||||
.standardHorizontalMargin()
|
||||
.fillMaxWidth(),
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.height(24.dp))
|
||||
Spacer(modifier = Modifier.height(height = 12.dp))
|
||||
|
||||
Text(
|
||||
text = state.subtitle(),
|
||||
textAlign = TextAlign.Start,
|
||||
textAlign = TextAlign.Center,
|
||||
style = BitwardenTheme.typography.bodyMedium,
|
||||
color = BitwardenTheme.colorScheme.text.primary,
|
||||
modifier = Modifier
|
||||
.padding(horizontal = 16.dp)
|
||||
.standardHorizontalMargin()
|
||||
.fillMaxWidth(),
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.height(16.dp))
|
||||
Spacer(modifier = Modifier.height(height = 12.dp))
|
||||
|
||||
Text(
|
||||
text = state.description(),
|
||||
textAlign = TextAlign.Start,
|
||||
textAlign = TextAlign.Center,
|
||||
style = BitwardenTheme.typography.bodyMedium,
|
||||
color = BitwardenTheme.colorScheme.text.primary,
|
||||
modifier = Modifier
|
||||
.padding(horizontal = 16.dp)
|
||||
.standardHorizontalMargin()
|
||||
.fillMaxWidth(),
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.height(24.dp))
|
||||
|
||||
Text(
|
||||
text = stringResource(id = BitwardenString.fingerprint_phrase),
|
||||
textAlign = TextAlign.Start,
|
||||
style = BitwardenTheme.typography.titleLarge,
|
||||
color = BitwardenTheme.colorScheme.text.primary,
|
||||
BitwardenTextField(
|
||||
label = stringResource(id = BitwardenString.fingerprint_phrase),
|
||||
value = state.fingerprintPhrase,
|
||||
textFieldTestTag = "FingerprintPhraseValue",
|
||||
onValueChange = { },
|
||||
readOnly = true,
|
||||
singleLine = false,
|
||||
textToolbarType = TextToolbarType.NONE,
|
||||
textStyle = BitwardenTheme.typography.sensitiveInfoSmall,
|
||||
textColor = BitwardenTheme.colorScheme.text.codePink,
|
||||
cardStyle = CardStyle.Full,
|
||||
modifier = Modifier
|
||||
.padding(horizontal = 16.dp)
|
||||
.fillMaxWidth(),
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.height(12.dp))
|
||||
|
||||
Text(
|
||||
text = state.fingerprintPhrase,
|
||||
textAlign = TextAlign.Start,
|
||||
color = BitwardenTheme.colorScheme.text.codePink,
|
||||
style = BitwardenTheme.typography.sensitiveInfoSmall,
|
||||
minLines = 2,
|
||||
modifier = Modifier
|
||||
.testTag("FingerprintPhraseValue")
|
||||
.padding(horizontal = 16.dp)
|
||||
.standardHorizontalMargin()
|
||||
.fillMaxWidth(),
|
||||
)
|
||||
|
||||
if (state.allowsResend) {
|
||||
Column(
|
||||
verticalArrangement = Arrangement.Center,
|
||||
Spacer(modifier = Modifier.height(height = 24.dp))
|
||||
BitwardenOutlinedButton(
|
||||
label = stringResource(id = BitwardenString.resend_notification),
|
||||
onClick = onResendNotificationClick,
|
||||
modifier = Modifier
|
||||
.defaultMinSize(minHeight = 40.dp)
|
||||
.align(Alignment.Start),
|
||||
) {
|
||||
if (state.isResendNotificationLoading) {
|
||||
BitwardenCircularProgressIndicator(
|
||||
modifier = Modifier
|
||||
.padding(horizontal = 64.dp)
|
||||
.size(size = 16.dp),
|
||||
)
|
||||
} else {
|
||||
BitwardenClickableText(
|
||||
modifier = Modifier.testTag("ResendNotificationButton"),
|
||||
label = stringResource(id = BitwardenString.resend_notification),
|
||||
style = BitwardenTheme.typography.labelLarge,
|
||||
innerPadding = PaddingValues(vertical = 8.dp, horizontal = 16.dp),
|
||||
onClick = onResendNotificationClick,
|
||||
)
|
||||
}
|
||||
}
|
||||
.testTag(tag = "ResendNotificationButton")
|
||||
.standardHorizontalMargin()
|
||||
.fillMaxWidth(),
|
||||
)
|
||||
}
|
||||
|
||||
Spacer(modifier = Modifier.height(28.dp))
|
||||
Spacer(modifier = Modifier.height(height = 24.dp))
|
||||
|
||||
Text(
|
||||
text = state.otherOptions(),
|
||||
textAlign = TextAlign.Start,
|
||||
style = BitwardenTheme.typography.bodyMedium,
|
||||
color = BitwardenTheme.colorScheme.text.primary,
|
||||
textAlign = TextAlign.Center,
|
||||
style = BitwardenTheme.typography.bodySmall,
|
||||
color = BitwardenTheme.colorScheme.text.secondary,
|
||||
modifier = Modifier
|
||||
.padding(horizontal = 16.dp)
|
||||
.standardHorizontalMargin()
|
||||
.fillMaxWidth(),
|
||||
)
|
||||
|
||||
BitwardenClickableText(
|
||||
modifier = Modifier.testTag("ViewAllLoginOptionsButton"),
|
||||
label = stringResource(id = BitwardenString.view_all_login_options),
|
||||
innerPadding = PaddingValues(vertical = 8.dp, horizontal = 16.dp),
|
||||
style = BitwardenTheme.typography.labelLarge,
|
||||
Spacer(modifier = Modifier.height(height = 12.dp))
|
||||
|
||||
BitwardenHyperTextLink(
|
||||
annotatedResId = BitwardenString.need_another_option_view_all_login_options,
|
||||
annotationKey = "viewAll",
|
||||
accessibilityString = stringResource(id = BitwardenString.view_all_login_options),
|
||||
onClick = onViewAllLogInOptionsClick,
|
||||
style = BitwardenTheme.typography.bodySmall,
|
||||
modifier = Modifier
|
||||
.testTag(tag = "ViewAllLoginOptionsButton")
|
||||
.standardHorizontalMargin()
|
||||
.fillMaxWidth(),
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.height(height = 12.dp))
|
||||
Spacer(modifier = Modifier.navigationBarsPadding())
|
||||
}
|
||||
}
|
||||
|
||||
@ -52,7 +52,7 @@ class LoginWithDeviceViewModel @Inject constructor(
|
||||
private var authJob: Job = Job().apply { complete() }
|
||||
|
||||
init {
|
||||
sendNewAuthRequest(isResend = false)
|
||||
sendNewAuthRequest()
|
||||
}
|
||||
|
||||
override fun handleAction(action: LoginWithDeviceAction) {
|
||||
@ -74,7 +74,14 @@ class LoginWithDeviceViewModel @Inject constructor(
|
||||
}
|
||||
|
||||
private fun handleResendNotificationClicked() {
|
||||
sendNewAuthRequest(isResend = true)
|
||||
mutableStateFlow.update {
|
||||
it.copy(
|
||||
dialogState = LoginWithDeviceState.DialogState.Loading(
|
||||
message = BitwardenString.resending.asText(),
|
||||
),
|
||||
)
|
||||
}
|
||||
sendNewAuthRequest()
|
||||
}
|
||||
|
||||
private fun handleViewAllLogInOptionsClicked() {
|
||||
@ -99,9 +106,6 @@ class LoginWithDeviceViewModel @Inject constructor(
|
||||
) {
|
||||
when (val result = action.result) {
|
||||
is CreateAuthRequestResult.Success -> {
|
||||
updateContent { content ->
|
||||
content.copy(isResendNotificationLoading = false)
|
||||
}
|
||||
mutableStateFlow.update {
|
||||
it.copy(
|
||||
dialogState = null,
|
||||
@ -123,7 +127,6 @@ class LoginWithDeviceViewModel @Inject constructor(
|
||||
viewState = LoginWithDeviceState.ViewState.Content(
|
||||
loginWithDeviceType = it.loginWithDeviceType,
|
||||
fingerprintPhrase = result.authRequest.fingerprint,
|
||||
isResendNotificationLoading = false,
|
||||
),
|
||||
dialogState = null,
|
||||
)
|
||||
@ -131,9 +134,6 @@ class LoginWithDeviceViewModel @Inject constructor(
|
||||
}
|
||||
|
||||
is CreateAuthRequestResult.Error -> {
|
||||
updateContent { content ->
|
||||
content.copy(isResendNotificationLoading = false)
|
||||
}
|
||||
mutableStateFlow.update {
|
||||
it.copy(
|
||||
dialogState = LoginWithDeviceState.DialogState.Error(
|
||||
@ -149,9 +149,6 @@ class LoginWithDeviceViewModel @Inject constructor(
|
||||
CreateAuthRequestResult.Declined -> Unit
|
||||
|
||||
CreateAuthRequestResult.Expired -> {
|
||||
updateContent { content ->
|
||||
content.copy(isResendNotificationLoading = false)
|
||||
}
|
||||
mutableStateFlow.update {
|
||||
it.copy(
|
||||
dialogState = LoginWithDeviceState.DialogState.Error(
|
||||
@ -279,8 +276,7 @@ class LoginWithDeviceViewModel @Inject constructor(
|
||||
}
|
||||
}
|
||||
|
||||
private fun sendNewAuthRequest(isResend: Boolean) {
|
||||
setIsResendNotificationLoading(isResend)
|
||||
private fun sendNewAuthRequest() {
|
||||
authJob.cancel()
|
||||
authJob = authRepository
|
||||
.createAuthRequestWithUpdates(
|
||||
@ -291,22 +287,6 @@ class LoginWithDeviceViewModel @Inject constructor(
|
||||
.onEach(::sendAction)
|
||||
.launchIn(viewModelScope)
|
||||
}
|
||||
|
||||
private fun setIsResendNotificationLoading(isResend: Boolean) {
|
||||
updateContent { it.copy(isResendNotificationLoading = isResend) }
|
||||
}
|
||||
|
||||
private inline fun updateContent(
|
||||
crossinline block: (
|
||||
LoginWithDeviceState.ViewState.Content,
|
||||
) -> LoginWithDeviceState.ViewState.Content?,
|
||||
) {
|
||||
val currentViewState = state.viewState
|
||||
val updatedContent = (currentViewState as? LoginWithDeviceState.ViewState.Content)
|
||||
?.let(block)
|
||||
?: return
|
||||
mutableStateFlow.update { it.copy(viewState = updatedContent) }
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -349,13 +329,10 @@ data class LoginWithDeviceState(
|
||||
* Content state for the [LoginWithDeviceScreen] showing the actual content or items.
|
||||
*
|
||||
* @property fingerprintPhrase The fingerprint phrase to present to the user.
|
||||
* @property isResendNotificationLoading Indicates if the resend loading spinner should be
|
||||
* displayed.
|
||||
*/
|
||||
@Parcelize
|
||||
data class Content(
|
||||
val fingerprintPhrase: String,
|
||||
val isResendNotificationLoading: Boolean,
|
||||
private val loginWithDeviceType: LoginWithDeviceType,
|
||||
) : ViewState() {
|
||||
/**
|
||||
@ -401,14 +378,19 @@ data class LoginWithDeviceState(
|
||||
/**
|
||||
* The text to display indicating that there are other option for logging in.
|
||||
*/
|
||||
@Suppress("MaxLineLength")
|
||||
val otherOptions: Text
|
||||
get() = when (loginWithDeviceType) {
|
||||
LoginWithDeviceType.OTHER_DEVICE,
|
||||
LoginWithDeviceType.SSO_OTHER_DEVICE,
|
||||
-> BitwardenString.log_in_with_device_must_be_set_up_in_the_settings_of_the_bitwarden_app_need_another_option.asText()
|
||||
-> {
|
||||
BitwardenString
|
||||
.log_in_with_device_must_be_set_up_in_the_settings_of_the_bitwarden_app
|
||||
.asText()
|
||||
}
|
||||
|
||||
LoginWithDeviceType.SSO_ADMIN_APPROVAL -> BitwardenString.trouble_logging_in.asText()
|
||||
LoginWithDeviceType.SSO_ADMIN_APPROVAL -> {
|
||||
BitwardenString.trouble_logging_in.asText()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -7,6 +7,7 @@ import androidx.compose.ui.test.isDialog
|
||||
import androidx.compose.ui.test.onNodeWithContentDescription
|
||||
import androidx.compose.ui.test.onNodeWithText
|
||||
import androidx.compose.ui.test.performClick
|
||||
import androidx.compose.ui.test.performFirstLinkClick
|
||||
import androidx.compose.ui.test.performScrollTo
|
||||
import com.bitwarden.core.data.repository.util.bufferedMutableSharedFlow
|
||||
import com.bitwarden.ui.platform.manager.IntentManager
|
||||
@ -92,7 +93,10 @@ class LoginWithDeviceScreenTest : BitwardenComposeTest() {
|
||||
|
||||
@Test
|
||||
fun `view all log in options click should send ViewAllLogInOptionsClick action`() {
|
||||
composeTestRule.onNodeWithText("View all log in options").performScrollTo().performClick()
|
||||
composeTestRule
|
||||
.onNodeWithText(text = "Need another option? View all login options")
|
||||
.performScrollTo()
|
||||
.performFirstLinkClick()
|
||||
verify {
|
||||
viewModel.trySendAction(LoginWithDeviceAction.ViewAllLogInOptionsClick)
|
||||
}
|
||||
@ -168,7 +172,6 @@ private val DEFAULT_STATE = LoginWithDeviceState(
|
||||
emailAddress = EMAIL,
|
||||
viewState = LoginWithDeviceState.ViewState.Content(
|
||||
fingerprintPhrase = "alabster-drinkable-mystified-rapping-irrigate",
|
||||
isResendNotificationLoading = false,
|
||||
loginWithDeviceType = LoginWithDeviceType.OTHER_DEVICE,
|
||||
),
|
||||
dialogState = null,
|
||||
|
||||
@ -121,8 +121,8 @@ class LoginWithDeviceViewModelTest : BaseViewModelTest() {
|
||||
viewModel.trySendAction(LoginWithDeviceAction.ResendNotificationClick)
|
||||
assertEquals(
|
||||
DEFAULT_STATE.copy(
|
||||
viewState = DEFAULT_CONTENT_VIEW_STATE.copy(
|
||||
isResendNotificationLoading = true,
|
||||
dialogState = LoginWithDeviceState.DialogState.Loading(
|
||||
message = BitwardenString.resending.asText(),
|
||||
),
|
||||
),
|
||||
viewModel.stateFlow.value,
|
||||
@ -610,7 +610,6 @@ class LoginWithDeviceViewModelTest : BaseViewModelTest() {
|
||||
DEFAULT_STATE.copy(
|
||||
viewState = DEFAULT_CONTENT_VIEW_STATE.copy(
|
||||
fingerprintPhrase = FINGERPRINT,
|
||||
isResendNotificationLoading = false,
|
||||
),
|
||||
dialogState = LoginWithDeviceState.DialogState.Error(
|
||||
title = BitwardenString.an_error_has_occurred.asText(),
|
||||
@ -661,7 +660,6 @@ class LoginWithDeviceViewModelTest : BaseViewModelTest() {
|
||||
DEFAULT_STATE.copy(
|
||||
viewState = DEFAULT_CONTENT_VIEW_STATE.copy(
|
||||
fingerprintPhrase = FINGERPRINT,
|
||||
isResendNotificationLoading = false,
|
||||
),
|
||||
dialogState = LoginWithDeviceState.DialogState.Error(
|
||||
title = null,
|
||||
@ -693,7 +691,6 @@ private const val FINGERPRINT = "fingerprint"
|
||||
|
||||
private val DEFAULT_CONTENT_VIEW_STATE = LoginWithDeviceState.ViewState.Content(
|
||||
fingerprintPhrase = FINGERPRINT,
|
||||
isResendNotificationLoading = false,
|
||||
loginWithDeviceType = LoginWithDeviceType.OTHER_DEVICE,
|
||||
)
|
||||
|
||||
|
||||
@ -37,6 +37,7 @@ import androidx.compose.ui.focus.FocusRequester
|
||||
import androidx.compose.ui.focus.focusRequester
|
||||
import androidx.compose.ui.focus.onFocusChanged
|
||||
import androidx.compose.ui.focus.onFocusEvent
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.layout.onGloballyPositioned
|
||||
import androidx.compose.ui.platform.LocalClipboard
|
||||
import androidx.compose.ui.platform.LocalFocusManager
|
||||
@ -94,6 +95,7 @@ import kotlinx.collections.immutable.toImmutableList
|
||||
* @param readOnly `true` if the input should be read-only and not accept user interactions.
|
||||
* @param enabled Whether or not the text field is enabled.
|
||||
* @param textStyle An optional style that may be used to override the default used.
|
||||
* @param textColor An optional color that may be used to override the text color.
|
||||
* @param shouldAddCustomLineBreaks If `true`, line breaks will be inserted to allow for filling
|
||||
* an entire line before breaking. `false` by default.
|
||||
* @param visualTransformation Transforms the visual representation of the input [value].
|
||||
@ -123,6 +125,7 @@ fun BitwardenTextField(
|
||||
readOnly: Boolean = false,
|
||||
enabled: Boolean = true,
|
||||
textStyle: TextStyle = BitwardenTheme.typography.bodyLarge,
|
||||
textColor: Color = BitwardenTheme.colorScheme.text.primary,
|
||||
shouldAddCustomLineBreaks: Boolean = false,
|
||||
keyboardType: KeyboardType = KeyboardType.Text,
|
||||
keyboardActions: KeyboardActions = KeyboardActions.Default,
|
||||
@ -158,6 +161,7 @@ fun BitwardenTextField(
|
||||
readOnly = readOnly,
|
||||
enabled = enabled,
|
||||
textStyle = textStyle,
|
||||
textColor = textColor,
|
||||
shouldAddCustomLineBreaks = shouldAddCustomLineBreaks,
|
||||
keyboardType = keyboardType,
|
||||
keyboardActions = keyboardActions,
|
||||
@ -194,6 +198,7 @@ fun BitwardenTextField(
|
||||
* @param readOnly `true` if the input should be read-only and not accept user interactions.
|
||||
* @param enabled Whether or not the text field is enabled.
|
||||
* @param textStyle An optional style that may be used to override the default used.
|
||||
* @param textColor An optional color that may be used to override the text color.
|
||||
* @param shouldAddCustomLineBreaks If `true`, line breaks will be inserted to allow for filling
|
||||
* an entire line before breaking. `false` by default.
|
||||
* @param visualTransformation Transforms the visual representation of the input [value].
|
||||
@ -226,6 +231,7 @@ fun BitwardenTextField(
|
||||
readOnly: Boolean = false,
|
||||
enabled: Boolean = true,
|
||||
textStyle: TextStyle = BitwardenTheme.typography.bodyLarge,
|
||||
textColor: Color = BitwardenTheme.colorScheme.text.primary,
|
||||
shouldAddCustomLineBreaks: Boolean = false,
|
||||
keyboardType: KeyboardType = KeyboardType.Text,
|
||||
keyboardActions: KeyboardActions = KeyboardActions.Default,
|
||||
@ -312,7 +318,7 @@ fun BitwardenTextField(
|
||||
var focused by remember { mutableStateOf(false) }
|
||||
|
||||
TextField(
|
||||
colors = bitwardenTextFieldColors(),
|
||||
colors = bitwardenTextFieldColors(textColor = textColor),
|
||||
enabled = enabled,
|
||||
label = label?.let {
|
||||
{
|
||||
|
||||
@ -24,6 +24,7 @@ fun bitwardenTextFieldButtonColors(): TextFieldColors = bitwardenTextFieldColors
|
||||
*/
|
||||
@Composable
|
||||
fun bitwardenTextFieldColors(
|
||||
textColor: Color = BitwardenTheme.colorScheme.text.primary,
|
||||
disabledTextColor: Color = BitwardenTheme.colorScheme.filledButton.foregroundDisabled,
|
||||
disabledLeadingIconColor: Color = BitwardenTheme.colorScheme.filledButton.foregroundDisabled,
|
||||
disabledTrailingIconColor: Color = BitwardenTheme.colorScheme.filledButton.foregroundDisabled,
|
||||
@ -31,8 +32,8 @@ fun bitwardenTextFieldColors(
|
||||
disabledPlaceholderColor: Color = BitwardenTheme.colorScheme.text.secondary,
|
||||
disabledSupportingTextColor: Color = BitwardenTheme.colorScheme.filledButton.foregroundDisabled,
|
||||
): TextFieldColors = TextFieldColors(
|
||||
focusedTextColor = BitwardenTheme.colorScheme.text.primary,
|
||||
unfocusedTextColor = BitwardenTheme.colorScheme.text.primary,
|
||||
focusedTextColor = textColor,
|
||||
unfocusedTextColor = textColor,
|
||||
disabledTextColor = disabledTextColor,
|
||||
errorTextColor = BitwardenTheme.colorScheme.text.primary,
|
||||
focusedContainerColor = Color.Transparent,
|
||||
|
||||
@ -653,7 +653,8 @@ Do you want to switch to this account?</string>
|
||||
<string name="invalid_uri">Invalid URI</string>
|
||||
<string name="the_urix_is_already_blocked">The URI %1$s is already blocked</string>
|
||||
<string name="login_approved">Login approved</string>
|
||||
<string name="log_in_with_device_must_be_set_up_in_the_settings_of_the_bitwarden_app_need_another_option">Log in with device must be set up in the settings of the Bitwarden app. Need another option?</string>
|
||||
<string name="log_in_with_device_must_be_set_up_in_the_settings_of_the_bitwarden_app">Log in with device must be set up in the settings of the Bitwarden app.</string>
|
||||
<string name="need_another_option_view_all_login_options">Need another option? <annotation link="viewAll">View all login options</annotation></string>
|
||||
<string name="log_in_with_device">Log in with device</string>
|
||||
<string name="logging_in_on">Logging in on</string>
|
||||
<string name="logging_in_on_with_colon">Logging in on:</string>
|
||||
@ -1156,4 +1157,5 @@ Do you want to switch to this account?</string>
|
||||
<string name="lock_app">Lock app</string>
|
||||
<string name="use_your_devices_lock_method_to_unlock_the_app">Use your device’s lock method to unlock the app</string>
|
||||
<string name="loading_vault_data">Loading vault data…</string>
|
||||
<string name="resending">Resending</string>
|
||||
</resources>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user