From 6a413f8e17f338aec0242672af6233d310ab6001 Mon Sep 17 00:00:00 2001 From: AbronStudio Date: Sat, 26 Jul 2025 13:39:10 +0330 Subject: [PATCH] feat(auth): update platform selection screen and login text - Add "Continue" string resource for navigation - Update login screen heading to "Welcome back!" - Add login subheading "Great to see you again!" - Update registration form heading to "Make it Official!" - Change registration data text to "New Here? Let's Get You Set Up!" - Change platform button text from "Login" to "Confirm" - Set API URL to "https://api.revolt.chat" for both platform options --- .../screens/login/LoginGreetingScreen.kt | 2 +- .../chat/revolt/screens/login/LoginScreen.kt | 155 ++++++++------ .../screens/register/RegisterDetailsScreen.kt | 152 ++++++------- .../res/drawable/login_charachter_img.xml | 201 ++++++++++++++++++ app/src/main/res/values/strings.xml | 8 +- 5 files changed, 372 insertions(+), 146 deletions(-) create mode 100644 app/src/main/res/drawable/login_charachter_img.xml diff --git a/app/src/main/java/chat/revolt/screens/login/LoginGreetingScreen.kt b/app/src/main/java/chat/revolt/screens/login/LoginGreetingScreen.kt index 0fc711fd..1ffa83c0 100644 --- a/app/src/main/java/chat/revolt/screens/login/LoginGreetingScreen.kt +++ b/app/src/main/java/chat/revolt/screens/login/LoginGreetingScreen.kt @@ -138,7 +138,7 @@ fun LoginGreetingScreen(navController: NavController) { Spacer(modifier = Modifier.height(5.dp)) ElevatedButton( - onClick = { navController.navigate("register/greeting") }, + onClick = { navController.navigate("register/details") }, modifier = Modifier .fillMaxWidth() .testTag("view_signup_page_button") diff --git a/app/src/main/java/chat/revolt/screens/login/LoginScreen.kt b/app/src/main/java/chat/revolt/screens/login/LoginScreen.kt index 9b5931f5..ebe969a6 100644 --- a/app/src/main/java/chat/revolt/screens/login/LoginScreen.kt +++ b/app/src/main/java/chat/revolt/screens/login/LoginScreen.kt @@ -1,6 +1,7 @@ package chat.revolt.screens.login import android.util.Log +import androidx.compose.foundation.Image import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row @@ -10,18 +11,20 @@ import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.imePadding import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.safeDrawingPadding -import androidx.compose.foundation.layout.width +import androidx.compose.foundation.layout.size import androidx.compose.foundation.text.input.TextObfuscationMode import androidx.compose.foundation.text.input.rememberTextFieldState import androidx.compose.material3.Button +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.HorizontalDivider import androidx.compose.material3.Icon import androidx.compose.material3.IconButton import androidx.compose.material3.LocalTextStyle import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Scaffold import androidx.compose.material3.SecureTextField import androidx.compose.material3.Text -import androidx.compose.material3.TextButton +import androidx.compose.material3.TopAppBar import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue @@ -31,7 +34,6 @@ import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.autofill.ContentType -import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.testTag import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource @@ -150,6 +152,7 @@ class LoginViewModel @Inject constructor( } } +@OptIn(ExperimentalMaterial3Api::class) @Composable fun LoginScreen(navController: NavController, viewModel: LoginViewModel = hiltViewModel()) { val passwordTextFieldState = rememberTextFieldState() @@ -158,8 +161,6 @@ fun LoginScreen(navController: NavController, viewModel: LoginViewModel = hiltVi } val showPassword = remember { mutableStateOf(false) } - val context = LocalContext.current - LaunchedEffect(viewModel.navigateTo) { when (viewModel.navigateTo) { "mfa" -> { @@ -189,21 +190,53 @@ fun LoginScreen(navController: NavController, viewModel: LoginViewModel = hiltVi } } - Column( - modifier = Modifier - .fillMaxSize() - .padding(20.dp) - .imePadding() - .safeDrawingPadding(), - verticalArrangement = Arrangement.Center, - horizontalAlignment = Alignment.CenterHorizontally - ) { + Scaffold( + topBar = { + Column { + TopAppBar( + modifier = Modifier.fillMaxWidth() + .padding(horizontal = 16.dp), + title = {}, + actions = { + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.SpaceBetween, + verticalAlignment = Alignment.CenterVertically, + ) { + IconButton( + content = { + Icon( + painter = painterResource(R.drawable.icn_arrow_back_24dp), + contentDescription = stringResource(R.string.back) + ) + }, + onClick = { navController.popBackStack() } + ) + Text(text = "Register") + } + }, + ) + HorizontalDivider() + } + } + ) { innerPadding -> Column( modifier = Modifier - .weight(1f), - verticalArrangement = Arrangement.Center, + .padding(innerPadding) + .fillMaxSize() + .padding(vertical = 20.dp, horizontal = 16.dp) + .imePadding(), + verticalArrangement = Arrangement.Top, horizontalAlignment = Alignment.CenterHorizontally ) { + Spacer(modifier = Modifier.height(16.dp)) + Image( + modifier = Modifier + .size(120.dp), + painter = painterResource(R.drawable.login_charachter_img), + contentDescription = "Login character" + ) + Spacer(modifier = Modifier.height(4.dp)) Text( text = stringResource(R.string.login_heading), style = MaterialTheme.typography.displaySmall.copy( @@ -212,15 +245,31 @@ fun LoginScreen(navController: NavController, viewModel: LoginViewModel = hiltVi textAlign = TextAlign.Center ), modifier = Modifier - .padding(horizontal = 20.dp, vertical = 10.dp) + .padding(horizontal = 20.dp, vertical = 4.dp) + .fillMaxWidth() + ) + Text( + text = stringResource(R.string.login_subheading), + color = MaterialTheme.colorScheme.onBackground.copy( + alpha = 0.5f + ), + style = MaterialTheme.typography.titleMedium.copy( + fontSize = 16.sp, + textAlign = TextAlign.Center, + fontWeight = FontWeight.Normal + ), + modifier = Modifier + .padding(horizontal = 20.dp) .fillMaxWidth() ) + Spacer(modifier = Modifier.height(32.dp)) + Column( modifier = Modifier - .width(270.dp), + .fillMaxWidth(), verticalArrangement = Arrangement.Center, - horizontalAlignment = Alignment.CenterHorizontally + horizontalAlignment = Alignment.Start ) { FormTextField( value = viewModel.email, @@ -229,7 +278,8 @@ fun LoginScreen(navController: NavController, viewModel: LoginViewModel = hiltVi action = ImeAction.Next, onChange = viewModel::setEmail, modifier = Modifier - .padding(vertical = 25.dp) + .fillMaxWidth() + .padding(bottom = 16.dp) .semantics { contentType = ContentType.EmailAddress } @@ -250,6 +300,7 @@ fun LoginScreen(navController: NavController, viewModel: LoginViewModel = hiltVi showPassword.value = !showPassword.value }) { when { + showPassword.value -> { Icon( painter = painterResource(R.drawable.icn_visibility_off_24dp), @@ -266,59 +317,27 @@ fun LoginScreen(navController: NavController, viewModel: LoginViewModel = hiltVi } } }, - modifier = Modifier.semantics { - contentType = ContentType.Password - } + modifier = Modifier + .fillMaxWidth() + .semantics { + contentType = ContentType.Password + } ) - Weblink( text = stringResource(R.string.password_forgot), url = "$REVOLT_APP/login/reset", - modifier = Modifier.padding(vertical = 7.dp) + modifier = Modifier.padding(vertical = 12.dp) ) + Spacer(modifier = Modifier.height(32.dp)) - if (viewModel.error != null) { - Text( - text = viewModel.error!!, - color = MaterialTheme.colorScheme.error, - style = MaterialTheme.typography.titleMedium.copy( - textAlign = TextAlign.Center, - fontWeight = FontWeight.Normal, - fontSize = 15.sp - ), - modifier = Modifier.padding(vertical = 7.dp) - ) - } - } - } - - Column( - modifier = Modifier - .fillMaxWidth(), - horizontalAlignment = Alignment.CenterHorizontally - ) { - Weblink( - text = stringResource(R.string.resend_verification), - url = "$REVOLT_APP/login/resend", - modifier = Modifier - .padding(vertical = 7.dp) - .testTag("resend_verification_link") - ) - - Spacer(modifier = Modifier.height(10.dp)) - - Row { - TextButton(onClick = { - navController.popBackStack() - }) { - Text(text = stringResource(R.string.back)) - } - - Spacer(modifier = Modifier.width(10.dp)) - - Button(onClick = { - viewModel.doLogin() - }) { + Button( + onClick = { + viewModel.doLogin() + }, + modifier = Modifier + .fillMaxWidth() + .testTag("confirm_platform_button") + ) { Text(text = stringResource(R.string.login)) } } diff --git a/app/src/main/java/chat/revolt/screens/register/RegisterDetailsScreen.kt b/app/src/main/java/chat/revolt/screens/register/RegisterDetailsScreen.kt index 1355f9c2..bd0ab8d0 100644 --- a/app/src/main/java/chat/revolt/screens/register/RegisterDetailsScreen.kt +++ b/app/src/main/java/chat/revolt/screens/register/RegisterDetailsScreen.kt @@ -1,6 +1,7 @@ package chat.revolt.screens.register import android.content.Context +import androidx.compose.foundation.Image import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row @@ -10,12 +11,16 @@ import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.imePadding import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.safeDrawingPadding -import androidx.compose.foundation.layout.width +import androidx.compose.foundation.layout.size import androidx.compose.material3.Button +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.HorizontalDivider +import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Scaffold import androidx.compose.material3.Text -import androidx.compose.material3.TextButton +import androidx.compose.material3.TopAppBar import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf @@ -24,6 +29,8 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.autofill.ContentType import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.platform.testTag +import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.semantics.contentType import androidx.compose.ui.semantics.semantics @@ -112,28 +119,59 @@ class RegisterDetailsScreenViewModel : ViewModel() { } } +@OptIn(ExperimentalMaterial3Api::class) @Composable fun RegisterDetailsScreen( navController: NavController, viewModel: RegisterDetailsScreenViewModel = viewModel() ) { - val context = LocalContext.current - - Column( - modifier = Modifier - .fillMaxSize() - .padding(20.dp) - .imePadding() - .safeDrawingPadding(), - verticalArrangement = Arrangement.Center, - horizontalAlignment = Alignment.CenterHorizontally - ) { + Scaffold( + topBar = { + Column { + TopAppBar( + modifier = Modifier.fillMaxWidth() + .padding(horizontal = 16.dp), + title = {}, + actions = { + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.SpaceBetween, + verticalAlignment = Alignment.CenterVertically, + ) { + IconButton( + content = { + Icon( + painter = painterResource(R.drawable.icn_arrow_back_24dp), + contentDescription = stringResource(R.string.back) + ) + }, + onClick = { navController.popBackStack() } + ) + Text(text = stringResource(R.string.login)) + } + }, + ) + HorizontalDivider() + } + } + ) { innerPadding -> Column( modifier = Modifier - .weight(1f), - verticalArrangement = Arrangement.Center, + .padding(innerPadding) + .fillMaxSize() + .padding(vertical = 20.dp, horizontal = 16.dp) + .imePadding(), + verticalArrangement = Arrangement.Top, horizontalAlignment = Alignment.CenterHorizontally ) { + Spacer(modifier = Modifier.height(16.dp)) + Image( + modifier = Modifier + .size(120.dp), + painter = painterResource(R.drawable.login_charachter_img), + contentDescription = "Login character" + ) + Spacer(modifier = Modifier.height(4.dp)) Text( text = stringResource(R.string.register_form_heading), style = MaterialTheme.typography.displaySmall.copy( @@ -142,33 +180,31 @@ fun RegisterDetailsScreen( textAlign = TextAlign.Center ), modifier = Modifier - .padding(horizontal = 10.dp) + .padding(horizontal = 20.dp, vertical = 4.dp) .fillMaxWidth() ) - - Spacer(modifier = Modifier.height(10.dp)) - Text( text = stringResource(R.string.register_data), color = MaterialTheme.colorScheme.onBackground.copy( alpha = 0.5f ), style = MaterialTheme.typography.titleMedium.copy( + fontSize = 16.sp, textAlign = TextAlign.Center, fontWeight = FontWeight.Normal ), modifier = Modifier - .padding(horizontal = 10.dp) + .padding(horizontal = 20.dp) .fillMaxWidth() ) - Spacer(modifier = Modifier.height(40.dp)) + Spacer(modifier = Modifier.height(32.dp)) Column( modifier = Modifier .fillMaxWidth(), verticalArrangement = Arrangement.Center, - horizontalAlignment = Alignment.CenterHorizontally + horizontalAlignment = Alignment.Start ) { FormTextField( value = viewModel.email, @@ -176,66 +212,34 @@ fun RegisterDetailsScreen( label = stringResource(R.string.register_email), type = KeyboardType.Email, action = ImeAction.Next, - modifier = Modifier.semantics { contentType = ContentType.EmailAddress } + modifier = Modifier.fillMaxWidth().semantics { contentType = ContentType.EmailAddress } ) - Text( - text = stringResource(R.string.register_email_verification_hint), - color = MaterialTheme.colorScheme.onBackground.copy( - alpha = 0.5f - ), - fontSize = 12.sp, - modifier = Modifier.padding(horizontal = 40.dp, vertical = 10.dp) - ) - - Spacer(modifier = Modifier.height(10.dp)) - + Spacer(modifier = Modifier.height(16.dp)) FormTextField( value = viewModel.password, onChange = { viewModel.password = it }, label = stringResource(R.string.register_password), - type = KeyboardType.Password, - action = ImeAction.Done, - modifier = Modifier.semantics { contentType = ContentType.NewPassword } - ) - Text( - text = stringResource(R.string.register_password_rules), - color = MaterialTheme.colorScheme.onBackground.copy( - alpha = 0.5f - ), - fontSize = 12.sp, - modifier = Modifier.padding(horizontal = 40.dp, vertical = 10.dp) + type = KeyboardType.Email, + action = ImeAction.Next, + modifier = Modifier.fillMaxWidth().semantics { contentType = ContentType.EmailAddress } ) + Spacer(modifier = Modifier.height(32.dp)) - if (!viewModel.error.isNullOrBlank()) { - Text( - text = viewModel.error!!, - color = MaterialTheme.colorScheme.error, - modifier = Modifier.padding(horizontal = 40.dp, vertical = 10.dp), - textAlign = TextAlign.Center - ) + val context = LocalContext.current + + Button( + onClick = { + viewModel.initCaptcha(context) { + viewModel.doRegistration(navController) + } + }, + modifier = Modifier + .fillMaxWidth() + .testTag("setup_continue_button") + ) { + Text(text = stringResource(R.string.continue_)) } } } - - Row { - TextButton(onClick = { - navController.popBackStack() - }) { - Text(text = stringResource(R.string.back)) - } - - Spacer(modifier = Modifier.width(10.dp)) - - Button( - onClick = { - viewModel.initCaptcha(context) { - viewModel.doRegistration(navController) - } - }, - enabled = viewModel.email.isNotBlank() && viewModel.password.isNotBlank() - ) { - Text(text = stringResource(R.string.signup)) - } - } } } diff --git a/app/src/main/res/drawable/login_charachter_img.xml b/app/src/main/res/drawable/login_charachter_img.xml new file mode 100644 index 00000000..c517707b --- /dev/null +++ b/app/src/main/res/drawable/login_charachter_img.xml @@ -0,0 +1,201 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index bccf2571..7febdc6e 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -8,6 +8,7 @@ Share Let\'s go Confirm + Continue Fetching some info, hang in there… Hold your horses! You\'re doing that too often in a short amount of time. @@ -39,7 +40,8 @@ Try again Log out - Let\'s log you in + Welcome back! + Great to see you again! Forgot password? Resend a verification email Using a password manager? @@ -49,8 +51,8 @@ Welcome to Revolt Use Revolt to chat about stuff. It\'s like a place to hang out, get together, and talk about stuff. Best part, it\'s on the internet. - Let\'s get you set up. - Your data is safe with us. We don\'t sell it, and neither do we use it to show you ads. + Make it Official! + New Here? Let’s Get You Set Up! Email We\'ll send you a verification email to confirm your account. Password