summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorDavid Göransson <david.goransson@mullvad.net>2026-04-22 11:20:35 +0200
committerDavid Göransson <david.goransson@mullvad.net>2026-04-22 11:20:35 +0200
commit042b04909bcf0e20c623bf0208a0a8153331a096 (patch)
treee08d7b87878cd2dd22350a3d2e17d1bb485e1493
parentbfe0141a0a2544a0f692d6729ea86407b2c233d1 (diff)
downloadmullvadvpn-update-login-view-to-new-design-droid-2560.tar.xz
mullvadvpn-update-login-view-to-new-design-droid-2560.zip
-rw-r--r--android/lib/feature/login/impl/src/main/kotlin/net/mullvad/mullvadvpn/feature/login/impl/LoginScreen.kt101
1 files changed, 54 insertions, 47 deletions
diff --git a/android/lib/feature/login/impl/src/main/kotlin/net/mullvad/mullvadvpn/feature/login/impl/LoginScreen.kt b/android/lib/feature/login/impl/src/main/kotlin/net/mullvad/mullvadvpn/feature/login/impl/LoginScreen.kt
index 5b970abdba..0cc87e56e9 100644
--- a/android/lib/feature/login/impl/src/main/kotlin/net/mullvad/mullvadvpn/feature/login/impl/LoginScreen.kt
+++ b/android/lib/feature/login/impl/src/main/kotlin/net/mullvad/mullvadvpn/feature/login/impl/LoginScreen.kt
@@ -10,7 +10,6 @@ import androidx.compose.foundation.layout.ColumnScope
import androidx.compose.foundation.layout.IntrinsicSize
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
-import androidx.compose.foundation.layout.defaultMinSize
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
@@ -21,6 +20,7 @@ import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.shape.CornerSize
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.foundation.text.input.TextFieldLineLimits
+import androidx.compose.foundation.text.input.TextFieldState
import androidx.compose.foundation.text.input.rememberTextFieldState
import androidx.compose.foundation.text.input.setTextAndPlaceCursorAtEnd
import androidx.compose.foundation.verticalScroll
@@ -134,7 +134,7 @@ private fun PreviewLoginScreen(
}
private const val TOP_SPACER_WEIGHT = 1f
-private const val BOTTOM_SPACER_WEIGHT = 3f
+private const val BOTTOM_SPACER_WEIGHT = 1f
@Composable
fun Login(
@@ -267,17 +267,19 @@ private fun LoginScreen(
.padding(bottom = Dimens.smallPadding),
)
- LoginInput(
- state,
- onLoginClick,
- onAccountNumberChange,
- onDeleteHistoryClick,
- onShowApiUnreachableDialog,
- )
+ Column {
+ LoginInput(
+ state,
+ onLoginClick,
+ onAccountNumberChange,
+ onDeleteHistoryClick,
+ onShowApiUnreachableDialog,
+ )
+ }
AnimatedVisibility(state.loginState is LoginState.Idle) {
Column {
- Spacer(modifier = Modifier.size(Dimens.mediumSpacer))
+ Spacer(modifier = Modifier.height(Dimens.mediumSpacer))
VariantButton(
isEnabled = state.loginButtonEnabled,
onClick = { onLoginClick(state.accountNumberInput) },
@@ -286,6 +288,7 @@ private fun LoginScreen(
)
Spacer(modifier = Modifier.height(Dimens.largePadding))
OrDivier()
+ Spacer(modifier = Modifier.height(Dimens.mediumSpacer))
PrimaryTextButton(
modifier = Modifier.align(Alignment.CenterHorizontally),
text = stringResource(id = R.string.create_new_account),
@@ -301,10 +304,7 @@ private fun LoginScreen(
@Composable
fun OrDivier() {
- Row(
- modifier = Modifier.defaultMinSize(minHeight = Dimens.orDivierMinHeight),
- verticalAlignment = Alignment.CenterVertically,
- ) {
+ Row(verticalAlignment = Alignment.CenterVertically) {
HorizontalDivider(
modifier = Modifier.weight(1f),
color = MaterialTheme.colorScheme.onBackground,
@@ -358,7 +358,11 @@ private fun ColumnScope.LoginInput(
it
}
},
- state = accountState,
+ state =
+ if (state.loginState is LoginState.Loading.CreatingAccount) TextFieldState("")
+ else {
+ accountState
+ },
labelPosition = TextFieldLabelPosition.Above(),
label = {
Text(
@@ -368,22 +372,31 @@ private fun ColumnScope.LoginInput(
)
},
lineLimits = TextFieldLineLimits.SingleLine,
- trailingIcon = {
- IconButton(
- modifier = Modifier.testTag(LOGIN_REVEAL_INPUT_BUTTON_TEST_TAG),
- onClick = { showPassword = !showPassword },
- ) {
- Icon(
- imageVector =
- if (showPassword) Icons.Outlined.VisibilityOff
- else Icons.Outlined.Visibility,
- contentDescription =
- if (showPassword) stringResource(id = R.string.hide_account_number)
- else stringResource(id = R.string.show_account_number),
- )
+ trailingIcon =
+ if (state.loginState is LoginState.Idle) {
+ {
+ IconButton(
+ modifier = Modifier.testTag(LOGIN_REVEAL_INPUT_BUTTON_TEST_TAG),
+ onClick = { showPassword = !showPassword },
+ ) {
+ Icon(
+ imageVector =
+ if (showPassword) Icons.Outlined.VisibilityOff
+ else Icons.Outlined.Visibility,
+ contentDescription =
+ if (showPassword) stringResource(id = R.string.hide_account_number)
+ else stringResource(id = R.string.show_account_number),
+ )
+ }
+ }
+ } else null,
+ placeholder = {
+ if (state.loginState == LoginState.Loading.CreatingAccount) {
+ Text("Generating...")
+ } else {
+ Text(stringResource(R.string.login_description))
}
},
- placeholder = { Text(stringResource(R.string.login_description)) },
onKeyboardAction = { onLoginClick(state.accountNumberInput) },
keyboardOptions =
KeyboardOptions(
@@ -421,11 +434,13 @@ private fun ColumnScope.LoginInput(
}
}
- SupportingText(
- Modifier.padding(bottom = Dimens.smallPadding),
- onShowApiUnreachableDialog = onShowApiUnreachableDialog,
- state = state,
- )
+ val text = state.loginState.supportingText(onShowApiUnreachableDialog)
+ AnimatedVisibility(text != null) {
+ SupportingText(
+ Modifier.padding(top = Dimens.tinyPadding),
+ text = text ?: AnnotatedString(""),
+ )
+ }
}
@Composable
@@ -468,21 +483,12 @@ private fun LoginState.title(): String =
)
@Composable
-private fun SupportingText(
- modifier: Modifier = Modifier,
- state: LoginUiState,
- onShowApiUnreachableDialog: (LoginUiStateError) -> Unit,
-) {
+private fun SupportingText(modifier: Modifier = Modifier, text: AnnotatedString) {
Text(
modifier = modifier,
- text = state.loginState.supportingText(onShowApiUnreachableDialog) ?: AnnotatedString(""),
+ text = text,
style = MaterialTheme.typography.labelLarge,
- color =
- if (state.loginState.isError()) {
- MaterialTheme.colorScheme.error
- } else {
- MaterialTheme.colorScheme.onPrimary
- },
+ color = MaterialTheme.colorScheme.error,
)
}
@@ -621,6 +627,7 @@ private fun AccountDropDownItem(
private fun LoginUiStateError.toLoginAction(): LoginAction =
when (this) {
is LoginUiStateError.LoginError.ApiUnreachable -> LoginAction.LOGIN
-// is LoginUiStateError.CreateAccountError.ApiUnreachable -> LoginAction.CREATE_ACCOUNT
+ // is LoginUiStateError.CreateAccountError.ApiUnreachable ->
+ // LoginAction.CREATE_ACCOUNT
else -> throw IllegalArgumentException("Not an API unreachable error")
}