refactor: 优化前端登录注册界面

- 优化LoginScreen登录界面
- 优化RegisterScreen注册界面
- 优化AuthViewModel认证ViewModel
This commit is contained in:
iammm0
2026-01-27 14:30:45 +08:00
parent b13877dcb7
commit ffa5b425f3
3 changed files with 175 additions and 29 deletions

View File

@@ -32,6 +32,8 @@ fun LoginScreen(
onLoginSuccess: () -> Unit,
onNavigateToRegister: () -> Unit,
onNavigateToResetPassword: (() -> Unit)? = null,
onNavigateToTerms: () -> Unit = {},
onNavigateToPrivacy: () -> Unit = {},
viewModel: AuthViewModel = viewModel(
factory = ViewModelFactory(LocalContext.current)
)
@@ -43,6 +45,7 @@ fun LoginScreen(
var password by remember { mutableStateOf("") }
var passwordVisible by remember { mutableStateOf(false) }
var smsCode by remember { mutableStateOf("") }
var agreedToTerms by remember { mutableStateOf(false) }
var showResultDialog by remember { mutableStateOf(false) }
val isLoading by viewModel.isLoading.collectAsState()
@@ -211,14 +214,18 @@ fun LoginScreen(
Spacer(modifier = Modifier.height(16.dp))
// 验证码输入框
SmsCodeInput(
code = smsCode,
onCodeChange = { smsCode = it },
codeLength = 6,
enabled = !isLoading,
modifier = Modifier.fillMaxWidth()
)
// 验证码输入框 - 居中显示
Box(
modifier = Modifier.fillMaxWidth(),
contentAlignment = Alignment.Center
) {
SmsCodeInput(
code = smsCode,
onCodeChange = { smsCode = it },
codeLength = 6,
enabled = !isLoading
)
}
}
}
@@ -250,19 +257,84 @@ fun LoginScreen(
)
}
Spacer(modifier = Modifier.height(24.dp))
// 同意协议复选框 - 使用Column支持换行
Row(
modifier = Modifier.fillMaxWidth(),
verticalAlignment = Alignment.Top,
horizontalArrangement = Arrangement.Start
) {
Checkbox(
checked = agreedToTerms,
onCheckedChange = { agreedToTerms = it },
enabled = !isLoading,
modifier = Modifier.padding(top = 2.dp)
)
Spacer(modifier = Modifier.width(8.dp))
Column(
modifier = Modifier.weight(1f)
) {
Row(
modifier = Modifier.wrapContentWidth(),
verticalAlignment = Alignment.CenterVertically
) {
Text(
text = "我已阅读并同意",
fontSize = 12.sp,
color = MaterialTheme.colorScheme.onSurfaceVariant
)
TextButton(
onClick = onNavigateToTerms,
contentPadding = PaddingValues(horizontal = 4.dp, vertical = 0.dp),
modifier = Modifier.height(24.dp)
) {
Text(
text = "《用户协议》",
fontSize = 12.sp,
color = LightPurple
)
}
}
Row(
modifier = Modifier.wrapContentWidth(),
verticalAlignment = Alignment.CenterVertically
) {
Text(
text = "",
fontSize = 12.sp,
color = MaterialTheme.colorScheme.onSurfaceVariant
)
TextButton(
onClick = onNavigateToPrivacy,
contentPadding = PaddingValues(horizontal = 4.dp, vertical = 0.dp),
modifier = Modifier.height(24.dp)
) {
Text(
text = "《隐私政策》",
fontSize = 12.sp,
color = LightPurple
)
}
}
}
}
Spacer(modifier = Modifier.height(16.dp))
// 登录按钮
Button(
onClick = {
val trimmedPhone = phone.trim()
if (isPasswordMode) {
// 密码登录
if (trimmedPhone.length == 11 && password.length >= 6) {
viewModel.login(trimmedPhone, password)
if (trimmedPhone.length == 11 && password.length >= 6 && agreedToTerms) {
viewModel.login(trimmedPhone, password, agreedToTerms)
}
} else {
// 验证码登录
if (trimmedPhone.length == 11 && smsCode.length == 6) {
viewModel.loginWithSms(trimmedPhone, smsCode)
if (trimmedPhone.length == 11 && smsCode.length == 6 && agreedToTerms) {
viewModel.loginWithSms(trimmedPhone, smsCode, agreedToTerms)
}
}
},
@@ -270,7 +342,8 @@ fun LoginScreen(
.fillMaxWidth()
.height(48.dp),
enabled = !isLoading && phone.trim().length == 11 &&
(if (isPasswordMode) password.length >= 6 else smsCode.length == 6),
(if (isPasswordMode) password.length >= 6 else smsCode.length == 6) &&
agreedToTerms,
colors = ButtonDefaults.buttonColors(
containerColor = LightPurple,
disabledContainerColor = MaterialTheme.colorScheme.surfaceVariant

View File

@@ -32,6 +32,8 @@ import com.huaga.life_echo.ui.viewmodel.ViewModelFactory
@Composable
fun RegisterScreen(
onRegisterSuccess: () -> Unit,
onNavigateToTerms: () -> Unit = {},
onNavigateToPrivacy: () -> Unit = {},
viewModel: AuthViewModel = viewModel(
factory = ViewModelFactory(LocalContext.current)
)
@@ -44,6 +46,7 @@ fun RegisterScreen(
var email by remember { mutableStateOf("") }
var passwordVisible by remember { mutableStateOf(false) }
var confirmPasswordVisible by remember { mutableStateOf(false) }
var agreedToTerms by remember { mutableStateOf(false) }
var showResultDialog by remember { mutableStateOf(false) }
val isLoading by viewModel.isLoading.collectAsState()
@@ -75,7 +78,8 @@ fun RegisterScreen(
smsCode.length == 6 &&
password.length >= 6 &&
password == confirmPassword &&
nickname.isNotBlank()
nickname.isNotBlank() &&
agreedToTerms
// 错误消息Snackbar
val snackbarHostState = remember { SnackbarHostState() }
@@ -168,12 +172,17 @@ fun RegisterScreen(
color = MaterialTheme.colorScheme.onSurfaceVariant
)
SmsCodeInput(
code = smsCode,
onCodeChange = { smsCode = it },
enabled = !isLoading,
modifier = Modifier.fillMaxWidth()
)
// 验证码输入框 - 居中显示
Box(
modifier = Modifier.fillMaxWidth(),
contentAlignment = Alignment.Center
) {
SmsCodeInput(
code = smsCode,
onCodeChange = { smsCode = it },
enabled = !isLoading
)
}
}
}
@@ -273,6 +282,69 @@ fun RegisterScreen(
item {
Spacer(modifier = Modifier.height(16.dp))
// 同意协议复选框 - 使用Column支持换行
Row(
modifier = Modifier.fillMaxWidth(),
verticalAlignment = Alignment.Top,
horizontalArrangement = Arrangement.Start
) {
Checkbox(
checked = agreedToTerms,
onCheckedChange = { agreedToTerms = it },
enabled = !isLoading,
modifier = Modifier.padding(top = 2.dp)
)
Spacer(modifier = Modifier.width(8.dp))
Column(
modifier = Modifier.weight(1f)
) {
Row(
modifier = Modifier.wrapContentWidth(),
verticalAlignment = Alignment.CenterVertically
) {
Text(
text = "我已阅读并同意",
fontSize = 12.sp,
color = MaterialTheme.colorScheme.onSurfaceVariant
)
TextButton(
onClick = onNavigateToTerms,
contentPadding = PaddingValues(horizontal = 4.dp, vertical = 0.dp),
modifier = Modifier.height(24.dp)
) {
Text(
text = "《用户协议》",
fontSize = 12.sp,
color = LightPurple
)
}
}
Row(
modifier = Modifier.wrapContentWidth(),
verticalAlignment = Alignment.CenterVertically
) {
Text(
text = "",
fontSize = 12.sp,
color = MaterialTheme.colorScheme.onSurfaceVariant
)
TextButton(
onClick = onNavigateToPrivacy,
contentPadding = PaddingValues(horizontal = 4.dp, vertical = 0.dp),
modifier = Modifier.height(24.dp)
) {
Text(
text = "《隐私政策》",
fontSize = 12.sp,
color = LightPurple
)
}
}
}
}
Spacer(modifier = Modifier.height(16.dp))
// 注册按钮
Button(
onClick = {
@@ -282,7 +354,8 @@ fun RegisterScreen(
code = smsCode,
password = password,
nickname = nickname,
email = if (email.isNotBlank()) email else null
email = if (email.isNotBlank()) email else null,
agreedToTerms = agreedToTerms
)
}
},

View File

@@ -68,14 +68,14 @@ class AuthViewModel(private val context: Context) : ViewModel() {
/**
* 用户登录
*/
fun login(phone: String, password: String) {
fun login(phone: String, password: String, agreedToTerms: Boolean) {
viewModelScope.launch {
_isLoading.value = true
_errorMessage.value = null
_successMessage.value = null
_operationResult.value = null
val result = authService.login(phone, password)
val result = authService.login(phone, password, agreedToTerms)
result.fold(
onSuccess = { tokenResponse ->
@@ -127,14 +127,14 @@ class AuthViewModel(private val context: Context) : ViewModel() {
/**
* 用户注册
*/
fun register(phone: String, password: String, nickname: String, email: String? = null) {
fun register(phone: String, password: String, nickname: String, email: String? = null, agreedToTerms: Boolean) {
viewModelScope.launch {
_isLoading.value = true
_errorMessage.value = null
_successMessage.value = null
_operationResult.value = null
val result = authService.register(phone, password, nickname, email)
val result = authService.register(phone, password, nickname, email, agreedToTerms)
result.fold(
onSuccess = { tokenResponse ->
@@ -340,14 +340,14 @@ class AuthViewModel(private val context: Context) : ViewModel() {
/**
* 验证码登录
*/
fun loginWithSms(phone: String, code: String) {
fun loginWithSms(phone: String, code: String, agreedToTerms: Boolean) {
viewModelScope.launch {
_isLoading.value = true
_errorMessage.value = null
_successMessage.value = null
_operationResult.value = null
val result = authService.loginWithSms(phone, code)
val result = authService.loginWithSms(phone, code, agreedToTerms)
result.fold(
onSuccess = { tokenResponse ->
@@ -391,14 +391,14 @@ class AuthViewModel(private val context: Context) : ViewModel() {
/**
* 验证码注册
*/
fun registerWithSms(phone: String, code: String, password: String, nickname: String, email: String? = null) {
fun registerWithSms(phone: String, code: String, password: String, nickname: String, email: String? = null, agreedToTerms: Boolean) {
viewModelScope.launch {
_isLoading.value = true
_errorMessage.value = null
_successMessage.value = null
_operationResult.value = null
val result = authService.registerWithSms(phone, code, password, nickname, email)
val result = authService.registerWithSms(phone, code, password, nickname, email, agreedToTerms)
result.fold(
onSuccess = { tokenResponse ->