注册账号界面ui调整
This commit is contained in:
@@ -43,6 +43,10 @@ import com.aiosman.ravenow.LocalAppTheme
|
||||
import com.aiosman.ravenow.R
|
||||
import com.aiosman.ravenow.ui.modifiers.noRippleClickable
|
||||
|
||||
private val LabelTextColor = Color(red = 60f / 255f, green = 60f / 255f, blue = 67f / 255f, alpha = 0.6f)
|
||||
private val HintTextColor = Color(red = 60f / 255f, green = 60f / 255f, blue = 67f / 255f, alpha = 0.3f)
|
||||
private val PasswordIconColor = Color(red = 17f / 255f, green = 12f / 255f, blue = 19f / 255f)
|
||||
|
||||
@Composable
|
||||
fun TextInputField(
|
||||
modifier: Modifier = Modifier,
|
||||
@@ -52,69 +56,96 @@ fun TextInputField(
|
||||
label: String? = null,
|
||||
hint: String? = null,
|
||||
error: String? = null,
|
||||
enabled: Boolean = true
|
||||
enabled: Boolean = true,
|
||||
leadingIcon: @Composable (() -> Unit)? = null,
|
||||
customBackgroundColor: Color? = null,
|
||||
customCornerRadius: Float = 24f
|
||||
) {
|
||||
val AppColors = LocalAppTheme.current
|
||||
var showPassword by remember { mutableStateOf(!password) }
|
||||
var isFocused by remember { mutableStateOf(false) }
|
||||
val backgroundColor = customBackgroundColor ?: AppColors.inputBackground
|
||||
Column(modifier = modifier) {
|
||||
label?.let {
|
||||
Text(it, color = AppColors.secondaryText)
|
||||
Spacer(modifier = Modifier.height(16.dp))
|
||||
Text(
|
||||
text = it,
|
||||
color = LabelTextColor,
|
||||
fontSize = 13.sp,
|
||||
modifier = Modifier.padding(start = 8.dp, top = 8.dp, bottom = 8.dp)
|
||||
)
|
||||
}
|
||||
Box(
|
||||
contentAlignment = Alignment.CenterStart,
|
||||
modifier = Modifier
|
||||
.clip(RoundedCornerShape(24.dp))
|
||||
.background(AppColors.inputBackground)
|
||||
.clip(RoundedCornerShape(customCornerRadius.dp))
|
||||
.background(backgroundColor)
|
||||
.border(
|
||||
width = 2.dp,
|
||||
color = if (error == null) Color.Transparent else AppColors.error,
|
||||
shape = RoundedCornerShape(24.dp)
|
||||
shape = RoundedCornerShape(customCornerRadius.dp)
|
||||
)
|
||||
.padding(horizontal = 16.dp, vertical = 16.dp)
|
||||
) {
|
||||
Row(verticalAlignment = Alignment.CenterVertically){
|
||||
BasicTextField(
|
||||
value = text,
|
||||
onValueChange = onValueChange,
|
||||
modifier = Modifier
|
||||
.weight(1f)
|
||||
.onFocusChanged { focusState ->
|
||||
isFocused = focusState.isFocused
|
||||
},
|
||||
textStyle = TextStyle(
|
||||
fontSize = 16.sp,
|
||||
fontWeight = FontWeight.W500,
|
||||
color = AppColors.text
|
||||
),
|
||||
keyboardOptions = KeyboardOptions(
|
||||
keyboardType = if (password) KeyboardType.Password else KeyboardType.Text
|
||||
),
|
||||
visualTransformation = if (showPassword) VisualTransformation.None else PasswordVisualTransformation(),
|
||||
singleLine = true,
|
||||
enabled = enabled,
|
||||
cursorBrush = SolidColor(AppColors.text),
|
||||
)
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
){
|
||||
leadingIcon?.let {
|
||||
Box(modifier = Modifier.size(24.dp)) {
|
||||
it()
|
||||
}
|
||||
Spacer(modifier = Modifier.size(12.dp))
|
||||
}
|
||||
Box(modifier = Modifier.weight(1f)) {
|
||||
BasicTextField(
|
||||
value = text,
|
||||
onValueChange = onValueChange,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.onFocusChanged { focusState ->
|
||||
isFocused = focusState.isFocused
|
||||
},
|
||||
textStyle = TextStyle(
|
||||
fontSize = 16.sp,
|
||||
fontWeight = FontWeight.W400,
|
||||
color = AppColors.text
|
||||
),
|
||||
keyboardOptions = KeyboardOptions(
|
||||
keyboardType = if (password) KeyboardType.Password else KeyboardType.Email
|
||||
),
|
||||
visualTransformation = if (showPassword) VisualTransformation.None else PasswordVisualTransformation(),
|
||||
singleLine = true,
|
||||
enabled = enabled,
|
||||
cursorBrush = SolidColor(AppColors.text),
|
||||
)
|
||||
if (text.isEmpty() && hint != null) {
|
||||
Text(
|
||||
text = hint,
|
||||
color = HintTextColor,
|
||||
fontSize = 16.sp,
|
||||
fontWeight = FontWeight.W400
|
||||
)
|
||||
}
|
||||
}
|
||||
if (password) {
|
||||
Image(
|
||||
painter = painterResource(id = R.drawable.rider_pro_eye),
|
||||
painter = painterResource(
|
||||
id = if (showPassword) {
|
||||
R.drawable.rider_pro_eye
|
||||
} else {
|
||||
R.mipmap.icon_eyes_closed_light
|
||||
}
|
||||
),
|
||||
contentDescription = "Password",
|
||||
modifier = Modifier
|
||||
.size(18.dp)
|
||||
.size(24.dp)
|
||||
.noRippleClickable {
|
||||
showPassword = !showPassword
|
||||
},
|
||||
colorFilter = ColorFilter.tint(AppColors.text)
|
||||
colorFilter = ColorFilter.tint(PasswordIconColor)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
if (text.isEmpty()) {
|
||||
hint?.let {
|
||||
Text(it, modifier = Modifier.padding(start = 5.dp), color = AppColors.inputHint, fontWeight = FontWeight.W600)
|
||||
}
|
||||
}
|
||||
}
|
||||
Spacer(modifier = Modifier.height(8.dp))
|
||||
Row(
|
||||
|
||||
@@ -1,15 +1,19 @@
|
||||
package com.aiosman.ravenow.ui.login
|
||||
|
||||
import android.widget.Toast
|
||||
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.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
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.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
@@ -19,9 +23,13 @@ import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.ColorFilter
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import com.aiosman.ravenow.AppState
|
||||
import com.aiosman.ravenow.AppStore
|
||||
import com.aiosman.ravenow.LocalAppTheme
|
||||
@@ -33,25 +41,28 @@ import com.aiosman.ravenow.data.ServiceException
|
||||
import com.aiosman.ravenow.data.AccountServiceImpl
|
||||
import com.aiosman.ravenow.data.api.getErrorMessageCode
|
||||
import com.aiosman.ravenow.ui.NavigationRoute
|
||||
import com.aiosman.ravenow.ui.comment.NoticeScreenHeader
|
||||
import com.aiosman.ravenow.ui.composables.ActionButton
|
||||
import com.aiosman.ravenow.ui.composables.CheckboxWithLabel
|
||||
import com.aiosman.ravenow.ui.composables.PolicyCheckbox
|
||||
import com.aiosman.ravenow.ui.composables.StatusBarSpacer
|
||||
import com.aiosman.ravenow.ui.composables.TextInputField
|
||||
import com.aiosman.ravenow.ui.modifiers.noRippleClickable
|
||||
import com.aiosman.ravenow.utils.PasswordValidator
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
private val LightGrayBackground = Color(red = 250f / 255f, green = 249f / 255f, blue = 251f / 255f)
|
||||
private val IconGray = Color(red = 151f / 255f, green = 148f / 255f, blue = 153f / 255f)
|
||||
private val PurpleButton = Color(0xFF7C45ED)
|
||||
|
||||
@Composable
|
||||
fun EmailSignupScreen() {
|
||||
var appColor = LocalAppTheme.current
|
||||
val appColor = LocalAppTheme.current
|
||||
var email by remember { mutableStateOf("") }
|
||||
var password by remember { mutableStateOf("") }
|
||||
var confirmPassword by remember { mutableStateOf("") }
|
||||
var rememberMe by remember { mutableStateOf(false) }
|
||||
var acceptTerms by remember { mutableStateOf(false) }
|
||||
var acceptPromotions by remember { mutableStateOf(false) }
|
||||
val scope = rememberCoroutineScope()
|
||||
val navController = LocalNavController.current
|
||||
val context = LocalContext.current
|
||||
@@ -60,7 +71,6 @@ fun EmailSignupScreen() {
|
||||
var passwordError by remember { mutableStateOf<String?>(null) }
|
||||
var confirmPasswordError by remember { mutableStateOf<String?>(null) }
|
||||
var termsError by remember { mutableStateOf<Boolean>(false) }
|
||||
var promotionsError by remember { mutableStateOf<Boolean>(false) }
|
||||
fun validateForm(): Boolean {
|
||||
emailError = when {
|
||||
// 非空
|
||||
@@ -88,22 +98,8 @@ fun EmailSignupScreen() {
|
||||
}
|
||||
termsError = true
|
||||
return false
|
||||
} else {
|
||||
termsError = false
|
||||
}
|
||||
if (!acceptPromotions) {
|
||||
scope.launch(Dispatchers.Main) {
|
||||
Toast.makeText(
|
||||
context,
|
||||
context.getString(R.string.error_not_accept_recive_notice),
|
||||
Toast.LENGTH_SHORT
|
||||
).show()
|
||||
}
|
||||
promotionsError = true
|
||||
return false
|
||||
} else {
|
||||
promotionsError = false
|
||||
}
|
||||
termsError = false
|
||||
|
||||
return emailError == null && passwordError == null && confirmPasswordError == null
|
||||
}
|
||||
@@ -158,63 +154,127 @@ fun EmailSignupScreen() {
|
||||
}
|
||||
|
||||
Column(
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.background(appColor.background)
|
||||
) {
|
||||
StatusBarSpacer()
|
||||
Box(
|
||||
// 顶部导航栏:返回箭头 + "注册"标题,左对齐
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(top = 16.dp, start = 16.dp, end = 16.dp)
|
||||
.padding(top = 15.dp, start = 16.dp, bottom = 15.dp, end = 16.dp),
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
NoticeScreenHeader(stringResource(R.string.sign_up_upper), moreIcon = false)
|
||||
Image(
|
||||
painter = painterResource(id = R.drawable.rider_pro_back_icon),
|
||||
contentDescription = "Back",
|
||||
modifier = Modifier
|
||||
.size(24.dp)
|
||||
.noRippleClickable {
|
||||
navController.navigateUp()
|
||||
},
|
||||
colorFilter = ColorFilter.tint(Color.Black)
|
||||
)
|
||||
Spacer(modifier = Modifier.width(8.dp))
|
||||
Text(
|
||||
text = stringResource(R.string.sign_up_upper),
|
||||
fontSize = 20.sp,
|
||||
fontWeight = FontWeight.W600,
|
||||
color = Color.Black
|
||||
)
|
||||
}
|
||||
Spacer(modifier = Modifier.padding(32.dp))
|
||||
|
||||
// 输入区域
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.weight(1f)
|
||||
.padding(horizontal = 24.dp)
|
||||
.padding(horizontal = 0.dp)
|
||||
) {
|
||||
Spacer(modifier = Modifier.height(16.dp))
|
||||
|
||||
// 邮箱输入框
|
||||
TextInputField(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth(),
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 24.dp),
|
||||
text = email,
|
||||
onValueChange = {
|
||||
email = it
|
||||
},
|
||||
hint = stringResource(R.string.text_hint_email),
|
||||
error = emailError
|
||||
label = stringResource(R.string.login_email_label),
|
||||
hint = "输入电子邮件",
|
||||
error = emailError,
|
||||
leadingIcon = {
|
||||
Image(
|
||||
painter = painterResource(id = R.mipmap.icon_email_light),
|
||||
contentDescription = "Email",
|
||||
modifier = Modifier.size(24.dp),
|
||||
colorFilter = ColorFilter.tint(IconGray)
|
||||
)
|
||||
},
|
||||
customBackgroundColor = LightGrayBackground,
|
||||
customCornerRadius = 16f
|
||||
)
|
||||
Spacer(modifier = Modifier.padding(4.dp))
|
||||
|
||||
// 密码输入框
|
||||
TextInputField(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth(),
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 24.dp),
|
||||
text = password,
|
||||
onValueChange = {
|
||||
password = it
|
||||
},
|
||||
password = true,
|
||||
label = stringResource(R.string.text_hint_password).replace("输入", ""),
|
||||
hint = stringResource(R.string.text_hint_password),
|
||||
error = passwordError
|
||||
error = passwordError,
|
||||
leadingIcon = {
|
||||
Image(
|
||||
painter = painterResource(id = R.mipmap.icon_lock_light),
|
||||
contentDescription = "Lock",
|
||||
modifier = Modifier.size(24.dp),
|
||||
colorFilter = ColorFilter.tint(IconGray)
|
||||
)
|
||||
},
|
||||
customBackgroundColor = LightGrayBackground,
|
||||
customCornerRadius = 16f
|
||||
)
|
||||
Spacer(modifier = Modifier.padding(4.dp))
|
||||
|
||||
// 确认密码输入框
|
||||
TextInputField(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth(),
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 24.dp),
|
||||
text = confirmPassword,
|
||||
onValueChange = {
|
||||
confirmPassword = it
|
||||
},
|
||||
password = true,
|
||||
hint = stringResource(R.string.text_hint_confirm_password),
|
||||
error = confirmPasswordError
|
||||
label = stringResource(R.string.confirm_password_label),
|
||||
hint = stringResource(R.string.text_hint_password),
|
||||
error = confirmPasswordError,
|
||||
leadingIcon = {
|
||||
Image(
|
||||
painter = painterResource(id = R.mipmap.icon_lock_light),
|
||||
contentDescription = "Lock",
|
||||
modifier = Modifier.size(24.dp),
|
||||
colorFilter = ColorFilter.tint(IconGray)
|
||||
)
|
||||
},
|
||||
customBackgroundColor = LightGrayBackground,
|
||||
customCornerRadius = 16f
|
||||
)
|
||||
Spacer(modifier = Modifier.height(8.dp))
|
||||
|
||||
Spacer(modifier = Modifier.height(16.dp))
|
||||
|
||||
// 功能选项区域
|
||||
Column(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 24.dp),
|
||||
horizontalAlignment = Alignment.Start,
|
||||
) {
|
||||
CheckboxWithLabel(
|
||||
@@ -236,42 +296,31 @@ fun EmailSignupScreen() {
|
||||
termsError = false
|
||||
}
|
||||
}
|
||||
Spacer(modifier = Modifier.height(16.dp))
|
||||
CheckboxWithLabel(
|
||||
checked = acceptPromotions,
|
||||
checkSize = 16,
|
||||
fontSize = 12,
|
||||
label = stringResource(R.string.agree_promotion),
|
||||
error = promotionsError
|
||||
) {
|
||||
acceptPromotions = it
|
||||
// 当用户勾选时,立即清除错误状态
|
||||
if (it) {
|
||||
promotionsError = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Spacer(modifier = Modifier.height(32.dp))
|
||||
Spacer(modifier = Modifier.height(76.dp))
|
||||
|
||||
// 底部注册按钮
|
||||
Box(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 24.dp),
|
||||
contentAlignment = Alignment.Center
|
||||
) {
|
||||
ActionButton(
|
||||
modifier = Modifier
|
||||
.width(345.dp),
|
||||
text = stringResource(R.string.lets_ride_upper),
|
||||
backgroundColor = Color(0xffda3832),
|
||||
color = Color.White
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
text = stringResource(R.string.sign_up_upper),
|
||||
backgroundColor = PurpleButton,
|
||||
color = Color.White,
|
||||
fontSize = 17.sp,
|
||||
fontWeight = FontWeight.W600
|
||||
) {
|
||||
scope.launch(Dispatchers.IO) {
|
||||
registerUser()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user