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