重构登录注册页面UI

- 提取ActionButton组件以复用
- 提取TextInputField组件以复用
- 更新Profile页面布局

- 更新ChangePasswordScreen页面布局
- 更新EmailSignup页面布局
- 更新UserAuth页面布局
- 更新Signup页面布局
- 更新Login页面布局
This commit is contained in:
2024-09-05 23:30:37 +08:00
parent fda6fe4dcf
commit 37dcd19227
28 changed files with 325 additions and 186 deletions

View File

@@ -1,12 +1,30 @@
import androidx.compose.foundation.layout.* import androidx.compose.foundation.background
import androidx.compose.material3.* import androidx.compose.foundation.layout.Box
import androidx.compose.runtime.* 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.Modifier
import androidx.compose.ui.text.input.PasswordVisualTransformation import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import com.aiosman.riderpro.LocalNavController import com.aiosman.riderpro.LocalNavController
import com.aiosman.riderpro.R
import com.aiosman.riderpro.data.AccountService import com.aiosman.riderpro.data.AccountService
import com.aiosman.riderpro.data.AccountServiceImpl 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 import kotlinx.coroutines.launch
/** /**
@@ -37,60 +55,93 @@ fun ChangePasswordScreen() {
var errorMessage by remember { mutableStateOf("") } var errorMessage by remember { mutableStateOf("") }
val scope = rememberCoroutineScope() val scope = rememberCoroutineScope()
val navController = LocalNavController.current val navController = LocalNavController.current
Scaffold { paddingValues -> var oldPasswordError by remember { mutableStateOf<String?>(null) }
Column( var confirmPasswordError by remember { mutableStateOf<String?>(null) }
modifier = Modifier var passwordError by remember { mutableStateOf<String?>(null) }
.fillMaxSize() fun validate(): Boolean {
.padding(paddingValues), oldPasswordError =
verticalArrangement = Arrangement.Center 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( NoticeScreenHeader(
value = currentPassword, 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 }, onValueChange = { currentPassword = it },
label = { Text("Current Password") }, password = true,
visualTransformation = PasswordVisualTransformation(), label = "Current password",
modifier = Modifier.fillMaxWidth() hint = "Enter your current password",
error = oldPasswordError
) )
Spacer(modifier = Modifier.height(16.dp)) Spacer(modifier = Modifier.height(24.dp))
TextField( TextInputField(
value = newPassword, text = newPassword,
onValueChange = { newPassword = it }, onValueChange = { newPassword = it },
label = { Text("New Password") }, password = true,
visualTransformation = PasswordVisualTransformation(), label = "New password",
modifier = Modifier.fillMaxWidth() hint = "Enter your new password",
error = passwordError
) )
Spacer(modifier = Modifier.height(16.dp)) Spacer(modifier = Modifier.height(24.dp))
TextField( TextInputField(
value = confirmPassword, text = confirmPassword,
onValueChange = { confirmPassword = it }, onValueChange = { confirmPassword = it },
label = { Text("Confirm New Password") }, password = true,
visualTransformation = PasswordVisualTransformation(), label = "Confirm new password",
modifier = Modifier.fillMaxWidth() hint = "Enter your new password again",
error = confirmPasswordError
) )
Spacer(modifier = Modifier.height(16.dp)) Spacer(modifier = Modifier.height(80.dp))
if (errorMessage.isNotEmpty()) { ActionButton(
Text( modifier = Modifier
text = errorMessage, .width(345.dp)
color = MaterialTheme.colorScheme.error, .height(48.dp),
modifier = Modifier.padding(bottom = 16.dp) text = "LET'S RIDE".uppercase(),
) backgroundImage = R.mipmap.rider_pro_signup_red_bg
} ) {
Button( if (validate()) {
onClick = { scope.launch {
if (newPassword == confirmPassword) { try {
scope.launch {
viewModel.changePassword(currentPassword, newPassword) viewModel.changePassword(currentPassword, newPassword)
navController.popBackStack() navController.popBackStack()
} catch (e: Exception) {
errorMessage = e.message ?: "An error occurred"
} }
} else {
errorMessage = "Passwords do not match"
} }
}, }
modifier = Modifier.fillMaxWidth()
) {
Text("Change Password")
} }
} }
} }
} }

View File

@@ -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)
}
}
}

View File

@@ -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)
}
}
}
}

View File

@@ -95,8 +95,12 @@ fun ProfilePage() {
val statusBarPaddingValues = WindowInsets.systemBars.asPaddingValues() val statusBarPaddingValues = WindowInsets.systemBars.asPaddingValues()
LazyColumn( LazyColumn(
modifier = Modifier modifier = Modifier
.fillMaxSize().background(Color(0xFFF5F5F5)).padding(bottom = with(LocalDensity.current) { .fillMaxSize()
val da = WindowInsets.navigationBars.getBottom(this).toDp() + 48.dp .background(Color(0xFFF5F5F5))
.padding(bottom = with(LocalDensity.current) {
val da = WindowInsets.navigationBars
.getBottom(this)
.toDp() + 48.dp
da da
}) })
) { ) {
@@ -118,7 +122,7 @@ fun ProfilePage() {
contentScale = ContentScale.Crop contentScale = ContentScale.Crop
) )
} else { } else {
Image( Image(
painter = painterResource(id = R.drawable.rider_pro_moment_demo_2), painter = painterResource(id = R.drawable.rider_pro_moment_demo_2),
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
@@ -145,44 +149,60 @@ fun ProfilePage() {
}, },
tint = Color.White tint = Color.White
) )
MaterialTheme(shapes = MaterialTheme.shapes.copy(extraSmall = RoundedCornerShape(16.dp))) { MaterialTheme(
shapes = MaterialTheme.shapes.copy(
extraSmall = RoundedCornerShape(
16.dp
)
)
) {
DropdownMenu( DropdownMenu(
expanded = expanded, expanded = expanded,
onDismissRequest = { expanded = false }, 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 { Row {
Text("Logout", fontWeight = FontWeight.W500) Text("Logout", fontWeight = FontWeight.W500)
Spacer(modifier = Modifier.weight(1f)) Spacer(modifier = Modifier.weight(1f))
Icon( Icon(
painter = painterResource(id = R.mipmap.rider_pro_logout), painter = painterResource(id = R.mipmap.rider_pro_logout),
contentDescription = "", contentDescription = "",
modifier = Modifier.size(24.dp).noRippleClickable { modifier = Modifier.size(24.dp)
scope.launch {
model.logout()
navController.navigate(NavigationRoute.Login.route) {
popUpTo(NavigationRoute.Index.route) {
inclusive = true
}
}
}
}
) )
} }
} }
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 { Row {
Text("Change password",fontWeight = FontWeight.W500) Text("Change password", fontWeight = FontWeight.W500)
Spacer(modifier = Modifier.weight(1f)) Spacer(modifier = Modifier.weight(1f))
Icon( Icon(
painter = painterResource(id = R.mipmap.rider_pro_change_password), painter = painterResource(id = R.mipmap.rider_pro_change_password),
contentDescription = "", contentDescription = "",
modifier = Modifier.size(24.dp).noRippleClickable { modifier = Modifier.size(24.dp)
scope.launch {
navController.navigate(NavigationRoute.ChangePasswordScreen.route)
}
}
) )
} }
} }
@@ -444,7 +464,9 @@ fun CommunicationOperatorGroup(
contentDescription = "" contentDescription = ""
) )
Text( 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, fontSize = 16.sp,
color = Color.White, color = Color.White,
style = TextStyle(fontWeight = FontWeight.Bold) style = TextStyle(fontWeight = FontWeight.Bold)
@@ -565,7 +587,9 @@ fun TimeGroup(time: String = "2024.06.08 12:23") {
verticalAlignment = Alignment.CenterVertically verticalAlignment = Alignment.CenterVertically
) { ) {
Image( 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), painter = painterResource(id = R.drawable.rider_pro_moment_time_flag),
contentDescription = "" contentDescription = ""
) )
@@ -654,7 +678,7 @@ fun MomentCardPicture(imageUrl: String, momentEntity: MomentEntity) {
imageUrl, imageUrl,
modifier = Modifier modifier = Modifier
.fillMaxSize() .fillMaxSize()
.aspectRatio(3f/2f) .aspectRatio(3f / 2f)
.padding(16.dp) .padding(16.dp)
.noRippleClickable { .noRippleClickable {
PostViewModel.preTransit(momentEntity) PostViewModel.preTransit(momentEntity)

View File

@@ -33,7 +33,9 @@ import com.aiosman.riderpro.data.ServiceException
import com.aiosman.riderpro.data.AccountServiceImpl import com.aiosman.riderpro.data.AccountServiceImpl
import com.aiosman.riderpro.ui.NavigationRoute import com.aiosman.riderpro.ui.NavigationRoute
import com.aiosman.riderpro.ui.comment.NoticeScreenHeader 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.StatusBarMaskLayout
import com.aiosman.riderpro.ui.composables.TextInputField
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch import kotlinx.coroutines.launch

View File

@@ -1,6 +1,5 @@
package com.aiosman.riderpro.ui.login package com.aiosman.riderpro.ui.login
import androidx.annotation.DrawableRes
import androidx.compose.foundation.Image import androidx.compose.foundation.Image
import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Box
@@ -18,18 +17,14 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.LaunchedEffect
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier 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.res.painterResource
import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp import androidx.compose.ui.unit.sp
import androidx.navigation.NavOptions
import androidx.navigation.navOptions
import com.aiosman.riderpro.LocalNavController import com.aiosman.riderpro.LocalNavController
import com.aiosman.riderpro.R import com.aiosman.riderpro.R
import com.aiosman.riderpro.ui.NavigationRoute import com.aiosman.riderpro.ui.NavigationRoute
import com.aiosman.riderpro.ui.modifiers.noRippleClickable import com.aiosman.riderpro.ui.composables.ActionButton
@Composable @Composable
fun LoginPage() { 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)
}
}
}

View File

@@ -15,25 +15,18 @@ import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width import androidx.compose.foundation.layout.width
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.Scaffold import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.painterResource
import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp 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.AppStore
import com.aiosman.riderpro.LocalNavController import com.aiosman.riderpro.LocalNavController
import com.aiosman.riderpro.Messaging 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.AccountServiceImpl
import com.aiosman.riderpro.data.ServiceException import com.aiosman.riderpro.data.ServiceException
import com.aiosman.riderpro.ui.NavigationRoute import com.aiosman.riderpro.ui.NavigationRoute
import com.aiosman.riderpro.ui.composables.ActionButton
import com.aiosman.riderpro.ui.modifiers.noRippleClickable import com.aiosman.riderpro.ui.modifiers.noRippleClickable
import com.aiosman.riderpro.utils.GoogleLogin import com.aiosman.riderpro.utils.GoogleLogin
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers

View File

@@ -2,7 +2,6 @@ package com.aiosman.riderpro.ui.login
import android.widget.Toast import android.widget.Toast
import androidx.compose.foundation.Image import androidx.compose.foundation.Image
import androidx.compose.foundation.background
import androidx.compose.foundation.border import androidx.compose.foundation.border
import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column 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.padding
import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width 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.Checkbox
import androidx.compose.material3.CheckboxDefaults import androidx.compose.material3.CheckboxDefaults
import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.ExperimentalMaterial3Api
@@ -31,13 +28,7 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.painterResource 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.dp
import androidx.compose.ui.unit.sp
import androidx.credentials.CredentialManager import androidx.credentials.CredentialManager
import com.aiosman.riderpro.AppStore import com.aiosman.riderpro.AppStore
import com.aiosman.riderpro.LocalNavController 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.data.ServiceException
import com.aiosman.riderpro.ui.NavigationRoute import com.aiosman.riderpro.ui.NavigationRoute
import com.aiosman.riderpro.ui.comment.NoticeScreenHeader 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.StatusBarMaskLayout
import com.aiosman.riderpro.ui.composables.TextInputField
import com.aiosman.riderpro.ui.modifiers.noRippleClickable import com.aiosman.riderpro.ui.modifiers.noRippleClickable
import com.aiosman.riderpro.utils.GoogleLogin import com.aiosman.riderpro.utils.GoogleLogin
import kotlinx.coroutines.launch 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))
)
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 708 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 333 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 909 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 445 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 197 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 520 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 844 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 390 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 640 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 700 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB