重构登录注册页面UI
- 提取ActionButton组件以复用 - 提取TextInputField组件以复用 - 更新Profile页面布局 - 更新ChangePasswordScreen页面布局 - 更新EmailSignup页面布局 - 更新UserAuth页面布局 - 更新Signup页面布局 - 更新Login页面布局
@@ -1,12 +1,30 @@
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.material3.*
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.text.input.PasswordVisualTransformation
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.aiosman.riderpro.LocalNavController
|
||||
import com.aiosman.riderpro.R
|
||||
import com.aiosman.riderpro.data.AccountService
|
||||
import com.aiosman.riderpro.data.AccountServiceImpl
|
||||
import com.aiosman.riderpro.ui.comment.NoticeScreenHeader
|
||||
import com.aiosman.riderpro.ui.composables.ActionButton
|
||||
import com.aiosman.riderpro.ui.composables.StatusBarSpacer
|
||||
import com.aiosman.riderpro.ui.composables.TextInputField
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
/**
|
||||
@@ -37,60 +55,93 @@ fun ChangePasswordScreen() {
|
||||
var errorMessage by remember { mutableStateOf("") }
|
||||
val scope = rememberCoroutineScope()
|
||||
val navController = LocalNavController.current
|
||||
Scaffold { paddingValues ->
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.padding(paddingValues),
|
||||
verticalArrangement = Arrangement.Center
|
||||
var oldPasswordError by remember { mutableStateOf<String?>(null) }
|
||||
var confirmPasswordError by remember { mutableStateOf<String?>(null) }
|
||||
var passwordError by remember { mutableStateOf<String?>(null) }
|
||||
fun validate(): Boolean {
|
||||
oldPasswordError =
|
||||
if (currentPassword.isEmpty()) "Please enter your current password" else null
|
||||
passwordError = when {
|
||||
newPassword.length < 8 -> "Password must be at least 8 characters long"
|
||||
!newPassword.any { it.isDigit() } -> "Password must contain at least one digit"
|
||||
!newPassword.any { it.isUpperCase() } -> "Password must contain at least one uppercase letter"
|
||||
!newPassword.any { it.isLowerCase() } -> "Password must contain at least one lowercase letter"
|
||||
else -> null
|
||||
}
|
||||
confirmPasswordError =
|
||||
if (newPassword != confirmPassword) "Passwords do not match" else null
|
||||
return passwordError == null && confirmPasswordError == null && oldPasswordError == null
|
||||
}
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.background(Color.White),
|
||||
horizontalAlignment = Alignment.CenterHorizontally
|
||||
) {
|
||||
StatusBarSpacer()
|
||||
Box(
|
||||
modifier = Modifier.padding(horizontal = 24.dp, vertical = 16.dp)
|
||||
) {
|
||||
TextField(
|
||||
value = currentPassword,
|
||||
NoticeScreenHeader(
|
||||
title = "Change password",
|
||||
moreIcon = false
|
||||
)
|
||||
|
||||
}
|
||||
Column(
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 24.dp)
|
||||
) {
|
||||
Spacer(modifier = Modifier.height(80.dp))
|
||||
TextInputField(
|
||||
text = currentPassword,
|
||||
onValueChange = { currentPassword = it },
|
||||
label = { Text("Current Password") },
|
||||
visualTransformation = PasswordVisualTransformation(),
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
password = true,
|
||||
label = "Current password",
|
||||
hint = "Enter your current password",
|
||||
error = oldPasswordError
|
||||
)
|
||||
Spacer(modifier = Modifier.height(16.dp))
|
||||
TextField(
|
||||
value = newPassword,
|
||||
Spacer(modifier = Modifier.height(24.dp))
|
||||
TextInputField(
|
||||
text = newPassword,
|
||||
onValueChange = { newPassword = it },
|
||||
label = { Text("New Password") },
|
||||
visualTransformation = PasswordVisualTransformation(),
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
password = true,
|
||||
label = "New password",
|
||||
hint = "Enter your new password",
|
||||
error = passwordError
|
||||
)
|
||||
Spacer(modifier = Modifier.height(16.dp))
|
||||
TextField(
|
||||
value = confirmPassword,
|
||||
Spacer(modifier = Modifier.height(24.dp))
|
||||
TextInputField(
|
||||
text = confirmPassword,
|
||||
onValueChange = { confirmPassword = it },
|
||||
label = { Text("Confirm New Password") },
|
||||
visualTransformation = PasswordVisualTransformation(),
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
password = true,
|
||||
label = "Confirm new password",
|
||||
hint = "Enter your new password again",
|
||||
error = confirmPasswordError
|
||||
)
|
||||
Spacer(modifier = Modifier.height(16.dp))
|
||||
if (errorMessage.isNotEmpty()) {
|
||||
Text(
|
||||
text = errorMessage,
|
||||
color = MaterialTheme.colorScheme.error,
|
||||
modifier = Modifier.padding(bottom = 16.dp)
|
||||
)
|
||||
}
|
||||
Button(
|
||||
onClick = {
|
||||
if (newPassword == confirmPassword) {
|
||||
scope.launch {
|
||||
Spacer(modifier = Modifier.height(80.dp))
|
||||
ActionButton(
|
||||
modifier = Modifier
|
||||
.width(345.dp)
|
||||
.height(48.dp),
|
||||
text = "LET'S RIDE".uppercase(),
|
||||
backgroundImage = R.mipmap.rider_pro_signup_red_bg
|
||||
) {
|
||||
if (validate()) {
|
||||
scope.launch {
|
||||
try {
|
||||
viewModel.changePassword(currentPassword, newPassword)
|
||||
navController.popBackStack()
|
||||
} catch (e: Exception) {
|
||||
errorMessage = e.message ?: "An error occurred"
|
||||
}
|
||||
} else {
|
||||
errorMessage = "Passwords do not match"
|
||||
}
|
||||
},
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
) {
|
||||
Text("Change Password")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
package com.aiosman.riderpro.ui.composables
|
||||
|
||||
import androidx.annotation.DrawableRes
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.layout.ContentScale
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.unit.sp
|
||||
import com.aiosman.riderpro.ui.modifiers.noRippleClickable
|
||||
|
||||
@Composable
|
||||
fun ActionButton(
|
||||
modifier: Modifier,
|
||||
text: String,
|
||||
color: Color = Color.White,
|
||||
@DrawableRes backgroundImage: Int,
|
||||
leading: @Composable (() -> Unit)? = null,
|
||||
click: () -> Unit = {}
|
||||
) {
|
||||
Box(
|
||||
modifier = modifier.noRippleClickable {
|
||||
click()
|
||||
}
|
||||
) {
|
||||
Image(
|
||||
painter = painterResource(id = backgroundImage),
|
||||
contentDescription = "Rider Pro",
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
contentScale = ContentScale.FillBounds
|
||||
)
|
||||
Row(
|
||||
modifier = Modifier.align(Alignment.Center),
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
leading?.invoke()
|
||||
Text(text, fontSize = 16.sp, color = color, fontWeight = FontWeight.W400)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,125 @@
|
||||
package com.aiosman.riderpro.ui.composables
|
||||
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.text.BasicTextField
|
||||
import androidx.compose.foundation.text.KeyboardOptions
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.focus.onFocusChanged
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.ColorFilter
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.text.TextStyle
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.text.input.KeyboardType
|
||||
import androidx.compose.ui.text.input.PasswordVisualTransformation
|
||||
import androidx.compose.ui.text.input.VisualTransformation
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import com.aiosman.riderpro.R
|
||||
import com.aiosman.riderpro.ui.modifiers.noRippleClickable
|
||||
|
||||
@Composable
|
||||
fun TextInputField(
|
||||
modifier: Modifier = Modifier,
|
||||
text: String,
|
||||
onValueChange: (String) -> Unit,
|
||||
password: Boolean = false,
|
||||
label: String? = null,
|
||||
hint: String? = null,
|
||||
error: String? = null
|
||||
) {
|
||||
var showPassword by remember { mutableStateOf(!password) }
|
||||
var isFocused by remember { mutableStateOf(false) }
|
||||
Column(modifier = modifier) {
|
||||
label?.let {
|
||||
Text(it, color = Color(0xFFCCCCCC))
|
||||
Spacer(modifier = Modifier.height(16.dp))
|
||||
}
|
||||
Box(
|
||||
contentAlignment = Alignment.CenterStart
|
||||
) {
|
||||
Row {
|
||||
BasicTextField(
|
||||
value = text,
|
||||
onValueChange = onValueChange,
|
||||
modifier = Modifier
|
||||
.weight(1f)
|
||||
.onFocusChanged { focusState ->
|
||||
isFocused = focusState.isFocused
|
||||
},
|
||||
textStyle = TextStyle(
|
||||
fontSize = 16.sp,
|
||||
fontWeight = FontWeight.W500,
|
||||
color = Color(0xff333333)
|
||||
),
|
||||
keyboardOptions = KeyboardOptions(
|
||||
keyboardType = if (password) KeyboardType.Password else KeyboardType.Text
|
||||
),
|
||||
visualTransformation = if (showPassword) VisualTransformation.None else PasswordVisualTransformation(),
|
||||
singleLine = true,
|
||||
)
|
||||
if (password) {
|
||||
Image(
|
||||
painter = painterResource(id = R.drawable.rider_pro_eye),
|
||||
contentDescription = "Password",
|
||||
modifier = Modifier
|
||||
.size(24.dp)
|
||||
.noRippleClickable {
|
||||
showPassword = !showPassword
|
||||
},
|
||||
colorFilter = ColorFilter.tint(Color.Black)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
if (text.isEmpty()) {
|
||||
hint?.let {
|
||||
Text(it, color = Color(0xFFCCCCCC), fontWeight = FontWeight.W600)
|
||||
}
|
||||
}
|
||||
}
|
||||
Spacer(modifier = Modifier.height(16.dp))
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.height(1.dp)
|
||||
.background(if (isFocused) Color(0xff333333) else Color(0xFFF5F5F5))
|
||||
|
||||
)
|
||||
Spacer(modifier = Modifier.height(8.dp))
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.height(16.dp),
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
if (error != null) {
|
||||
Image(
|
||||
painter = painterResource(id = R.mipmap.rider_pro_input_error),
|
||||
contentDescription = "Error",
|
||||
modifier = Modifier.size(8.dp)
|
||||
)
|
||||
Spacer(modifier = Modifier.size(4.dp))
|
||||
Text(error, color = Color(0xFFE53935), fontSize = 12.sp)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -95,8 +95,12 @@ fun ProfilePage() {
|
||||
val statusBarPaddingValues = WindowInsets.systemBars.asPaddingValues()
|
||||
LazyColumn(
|
||||
modifier = Modifier
|
||||
.fillMaxSize().background(Color(0xFFF5F5F5)).padding(bottom = with(LocalDensity.current) {
|
||||
val da = WindowInsets.navigationBars.getBottom(this).toDp() + 48.dp
|
||||
.fillMaxSize()
|
||||
.background(Color(0xFFF5F5F5))
|
||||
.padding(bottom = with(LocalDensity.current) {
|
||||
val da = WindowInsets.navigationBars
|
||||
.getBottom(this)
|
||||
.toDp() + 48.dp
|
||||
da
|
||||
})
|
||||
) {
|
||||
@@ -118,7 +122,7 @@ fun ProfilePage() {
|
||||
contentScale = ContentScale.Crop
|
||||
)
|
||||
} else {
|
||||
Image(
|
||||
Image(
|
||||
painter = painterResource(id = R.drawable.rider_pro_moment_demo_2),
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
@@ -145,44 +149,60 @@ fun ProfilePage() {
|
||||
},
|
||||
tint = Color.White
|
||||
)
|
||||
MaterialTheme(shapes = MaterialTheme.shapes.copy(extraSmall = RoundedCornerShape(16.dp))) {
|
||||
MaterialTheme(
|
||||
shapes = MaterialTheme.shapes.copy(
|
||||
extraSmall = RoundedCornerShape(
|
||||
16.dp
|
||||
)
|
||||
)
|
||||
) {
|
||||
DropdownMenu(
|
||||
expanded = expanded,
|
||||
onDismissRequest = { expanded = false },
|
||||
modifier = Modifier.width(250.dp).background(Color.White)
|
||||
modifier = Modifier
|
||||
.width(250.dp)
|
||||
.background(Color.White)
|
||||
) {
|
||||
Box(modifier = Modifier.padding(vertical = 14.dp, horizontal = 24.dp)) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.padding(vertical = 14.dp, horizontal = 24.dp)
|
||||
.noRippleClickable {
|
||||
expanded = false
|
||||
scope.launch {
|
||||
model.logout()
|
||||
navController.navigate(NavigationRoute.Login.route) {
|
||||
popUpTo(NavigationRoute.Index.route) {
|
||||
inclusive = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}) {
|
||||
Row {
|
||||
Text("Logout", fontWeight = FontWeight.W500)
|
||||
Spacer(modifier = Modifier.weight(1f))
|
||||
Icon(
|
||||
painter = painterResource(id = R.mipmap.rider_pro_logout),
|
||||
contentDescription = "",
|
||||
modifier = Modifier.size(24.dp).noRippleClickable {
|
||||
scope.launch {
|
||||
model.logout()
|
||||
navController.navigate(NavigationRoute.Login.route) {
|
||||
popUpTo(NavigationRoute.Index.route) {
|
||||
inclusive = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
modifier = Modifier.size(24.dp)
|
||||
)
|
||||
}
|
||||
}
|
||||
Box(modifier = Modifier.padding(vertical = 14.dp, horizontal = 24.dp)) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.padding(vertical = 14.dp, horizontal = 24.dp)
|
||||
.noRippleClickable {
|
||||
expanded = false
|
||||
scope.launch {
|
||||
navController.navigate(NavigationRoute.ChangePasswordScreen.route)
|
||||
}
|
||||
}) {
|
||||
Row {
|
||||
Text("Change password",fontWeight = FontWeight.W500)
|
||||
Text("Change password", fontWeight = FontWeight.W500)
|
||||
Spacer(modifier = Modifier.weight(1f))
|
||||
Icon(
|
||||
painter = painterResource(id = R.mipmap.rider_pro_change_password),
|
||||
contentDescription = "",
|
||||
modifier = Modifier.size(24.dp).noRippleClickable {
|
||||
scope.launch {
|
||||
navController.navigate(NavigationRoute.ChangePasswordScreen.route)
|
||||
}
|
||||
}
|
||||
modifier = Modifier.size(24.dp)
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -444,7 +464,9 @@ fun CommunicationOperatorGroup(
|
||||
contentDescription = ""
|
||||
)
|
||||
Text(
|
||||
text = if (isFollowing) stringResource(R.string.following_upper) else stringResource(R.string.follow_upper),
|
||||
text = if (isFollowing) stringResource(R.string.following_upper) else stringResource(
|
||||
R.string.follow_upper
|
||||
),
|
||||
fontSize = 16.sp,
|
||||
color = Color.White,
|
||||
style = TextStyle(fontWeight = FontWeight.Bold)
|
||||
@@ -565,7 +587,9 @@ fun TimeGroup(time: String = "2024.06.08 12:23") {
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
Image(
|
||||
modifier = Modifier.height(16.dp).width(14.dp),
|
||||
modifier = Modifier
|
||||
.height(16.dp)
|
||||
.width(14.dp),
|
||||
painter = painterResource(id = R.drawable.rider_pro_moment_time_flag),
|
||||
contentDescription = ""
|
||||
)
|
||||
@@ -654,7 +678,7 @@ fun MomentCardPicture(imageUrl: String, momentEntity: MomentEntity) {
|
||||
imageUrl,
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.aspectRatio(3f/2f)
|
||||
.aspectRatio(3f / 2f)
|
||||
.padding(16.dp)
|
||||
.noRippleClickable {
|
||||
PostViewModel.preTransit(momentEntity)
|
||||
|
||||
@@ -33,7 +33,9 @@ import com.aiosman.riderpro.data.ServiceException
|
||||
import com.aiosman.riderpro.data.AccountServiceImpl
|
||||
import com.aiosman.riderpro.ui.NavigationRoute
|
||||
import com.aiosman.riderpro.ui.comment.NoticeScreenHeader
|
||||
import com.aiosman.riderpro.ui.composables.ActionButton
|
||||
import com.aiosman.riderpro.ui.composables.StatusBarMaskLayout
|
||||
import com.aiosman.riderpro.ui.composables.TextInputField
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
package com.aiosman.riderpro.ui.login
|
||||
|
||||
import androidx.annotation.DrawableRes
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Box
|
||||
@@ -18,18 +17,14 @@ import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.layout.ContentScale
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import androidx.navigation.NavOptions
|
||||
import androidx.navigation.navOptions
|
||||
import com.aiosman.riderpro.LocalNavController
|
||||
import com.aiosman.riderpro.R
|
||||
import com.aiosman.riderpro.ui.NavigationRoute
|
||||
import com.aiosman.riderpro.ui.modifiers.noRippleClickable
|
||||
import com.aiosman.riderpro.ui.composables.ActionButton
|
||||
|
||||
@Composable
|
||||
fun LoginPage() {
|
||||
@@ -106,33 +101,3 @@ fun LoginPage() {
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun ActionButton(
|
||||
modifier: Modifier,
|
||||
text: String,
|
||||
color: Color = Color.White,
|
||||
@DrawableRes backgroundImage: Int,
|
||||
leading: @Composable (() -> Unit)? = null,
|
||||
click: () -> Unit = {}
|
||||
) {
|
||||
Box(
|
||||
modifier = modifier.noRippleClickable {
|
||||
click()
|
||||
}
|
||||
) {
|
||||
Image(
|
||||
painter = painterResource(id = backgroundImage),
|
||||
contentDescription = "Rider Pro",
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
contentScale = ContentScale.FillBounds
|
||||
)
|
||||
Row(
|
||||
modifier = Modifier.align(Alignment.Center),
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
leading?.invoke()
|
||||
Text(text, fontSize = 16.sp, color = color, fontWeight = FontWeight.W400)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -15,25 +15,18 @@ import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material3.Scaffold
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import androidx.credentials.Credential
|
||||
import androidx.credentials.CredentialManager
|
||||
import androidx.credentials.CustomCredential
|
||||
import androidx.credentials.GetCredentialRequest
|
||||
import androidx.credentials.GetCredentialResponse
|
||||
import com.aiosman.riderpro.AppStore
|
||||
import com.aiosman.riderpro.LocalNavController
|
||||
import com.aiosman.riderpro.Messaging
|
||||
@@ -42,6 +35,7 @@ import com.aiosman.riderpro.data.AccountService
|
||||
import com.aiosman.riderpro.data.AccountServiceImpl
|
||||
import com.aiosman.riderpro.data.ServiceException
|
||||
import com.aiosman.riderpro.ui.NavigationRoute
|
||||
import com.aiosman.riderpro.ui.composables.ActionButton
|
||||
import com.aiosman.riderpro.ui.modifiers.noRippleClickable
|
||||
import com.aiosman.riderpro.utils.GoogleLogin
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
|
||||
@@ -2,7 +2,6 @@ package com.aiosman.riderpro.ui.login
|
||||
|
||||
import android.widget.Toast
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.border
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
@@ -14,8 +13,6 @@ import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.foundation.text.BasicTextField
|
||||
import androidx.compose.foundation.text.KeyboardOptions
|
||||
import androidx.compose.material3.Checkbox
|
||||
import androidx.compose.material3.CheckboxDefaults
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
@@ -31,13 +28,7 @@ import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.text.TextStyle
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.text.input.KeyboardType
|
||||
import androidx.compose.ui.text.input.PasswordVisualTransformation
|
||||
import androidx.compose.ui.text.input.VisualTransformation
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import androidx.credentials.CredentialManager
|
||||
import com.aiosman.riderpro.AppStore
|
||||
import com.aiosman.riderpro.LocalNavController
|
||||
@@ -48,7 +39,9 @@ import com.aiosman.riderpro.data.AccountServiceImpl
|
||||
import com.aiosman.riderpro.data.ServiceException
|
||||
import com.aiosman.riderpro.ui.NavigationRoute
|
||||
import com.aiosman.riderpro.ui.comment.NoticeScreenHeader
|
||||
import com.aiosman.riderpro.ui.composables.ActionButton
|
||||
import com.aiosman.riderpro.ui.composables.StatusBarMaskLayout
|
||||
import com.aiosman.riderpro.ui.composables.TextInputField
|
||||
import com.aiosman.riderpro.ui.modifiers.noRippleClickable
|
||||
import com.aiosman.riderpro.utils.GoogleLogin
|
||||
import kotlinx.coroutines.launch
|
||||
@@ -227,66 +220,3 @@ fun UserAuthScreen() {
|
||||
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun TextInputField(
|
||||
modifier: Modifier = Modifier,
|
||||
text: String,
|
||||
onValueChange: (String) -> Unit,
|
||||
password: Boolean = false,
|
||||
label: String? = null,
|
||||
hint: String? = null
|
||||
|
||||
) {
|
||||
var showPassword by remember { mutableStateOf(!password) }
|
||||
Column(modifier = modifier) {
|
||||
label?.let {
|
||||
Text(it, color = Color(0xFFCCCCCC))
|
||||
Spacer(modifier = Modifier.height(16.dp))
|
||||
}
|
||||
Box(
|
||||
contentAlignment = Alignment.CenterStart
|
||||
) {
|
||||
Row {
|
||||
BasicTextField(
|
||||
value = text,
|
||||
onValueChange = onValueChange,
|
||||
modifier = Modifier.weight(1f),
|
||||
textStyle = TextStyle(
|
||||
fontSize = 16.sp,
|
||||
fontWeight = FontWeight.W500
|
||||
),
|
||||
keyboardOptions = KeyboardOptions(
|
||||
keyboardType = if (password) KeyboardType.Password else KeyboardType.Text
|
||||
),
|
||||
visualTransformation = if (showPassword) VisualTransformation.None else PasswordVisualTransformation(),
|
||||
singleLine = true
|
||||
)
|
||||
if (password) {
|
||||
Image(
|
||||
painter = painterResource(id = R.drawable.rider_pro_eye),
|
||||
contentDescription = "Password",
|
||||
modifier = Modifier
|
||||
.size(24.dp)
|
||||
.noRippleClickable {
|
||||
showPassword = !showPassword
|
||||
},
|
||||
colorFilter = androidx.compose.ui.graphics.ColorFilter.tint(Color.Black)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
if (text.isEmpty()) {
|
||||
hint?.let {
|
||||
Text(it, color = Color(0xFFCCCCCC), fontWeight = FontWeight.W600)
|
||||
}
|
||||
}
|
||||
}
|
||||
Spacer(modifier = Modifier.height(16.dp))
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.height(1.dp)
|
||||
.background(Color(0xFFF5F5F5))
|
||||
)
|
||||
}
|
||||
}
|
||||
BIN
app/src/main/res/mipmap-hdpi/rider_pro_btn_bg_grey.png
Normal file
|
After Width: | Height: | Size: 2.3 KiB |
BIN
app/src/main/res/mipmap-hdpi/rider_pro_change_password.png
Normal file
|
After Width: | Height: | Size: 708 B |
BIN
app/src/main/res/mipmap-hdpi/rider_pro_input_error.png
Normal file
|
After Width: | Height: | Size: 333 B |
BIN
app/src/main/res/mipmap-hdpi/rider_pro_logout.png
Normal file
|
After Width: | Height: | Size: 909 B |
BIN
app/src/main/res/mipmap-mdpi/rider_pro_btn_bg_grey.png
Normal file
|
After Width: | Height: | Size: 1.4 KiB |
BIN
app/src/main/res/mipmap-mdpi/rider_pro_change_password.png
Normal file
|
After Width: | Height: | Size: 445 B |
BIN
app/src/main/res/mipmap-mdpi/rider_pro_input_error.png
Normal file
|
After Width: | Height: | Size: 197 B |
BIN
app/src/main/res/mipmap-mdpi/rider_pro_logout.png
Normal file
|
After Width: | Height: | Size: 520 B |
BIN
app/src/main/res/mipmap-xhdpi/rider_pro_btn_bg_grey.png
Normal file
|
After Width: | Height: | Size: 3.0 KiB |
BIN
app/src/main/res/mipmap-xhdpi/rider_pro_change_password.png
Normal file
|
After Width: | Height: | Size: 844 B |
BIN
app/src/main/res/mipmap-xhdpi/rider_pro_input_error.png
Normal file
|
After Width: | Height: | Size: 390 B |
BIN
app/src/main/res/mipmap-xhdpi/rider_pro_logout.png
Normal file
|
After Width: | Height: | Size: 1.1 KiB |
BIN
app/src/main/res/mipmap-xxhdpi/rider_pro_btn_bg_grey.png
Normal file
|
After Width: | Height: | Size: 5.3 KiB |
BIN
app/src/main/res/mipmap-xxhdpi/rider_pro_change_password.png
Normal file
|
After Width: | Height: | Size: 1.4 KiB |
BIN
app/src/main/res/mipmap-xxhdpi/rider_pro_input_error.png
Normal file
|
After Width: | Height: | Size: 640 B |
BIN
app/src/main/res/mipmap-xxhdpi/rider_pro_logout.png
Normal file
|
After Width: | Height: | Size: 1.8 KiB |
BIN
app/src/main/res/mipmap-xxxhdpi/rider_pro_btn_bg_grey.png
Normal file
|
After Width: | Height: | Size: 7.2 KiB |
BIN
app/src/main/res/mipmap-xxxhdpi/rider_pro_change_password.png
Normal file
|
After Width: | Height: | Size: 1.7 KiB |
BIN
app/src/main/res/mipmap-xxxhdpi/rider_pro_input_error.png
Normal file
|
After Width: | Height: | Size: 700 B |
BIN
app/src/main/res/mipmap-xxxhdpi/rider_pro_logout.png
Normal file
|
After Width: | Height: | Size: 2.4 KiB |