package com.gyf.csams.account.ui import android.content.Intent import android.os.Bundle import androidx.activity.ComponentActivity import androidx.activity.compose.setContent import androidx.compose.foundation.layout.* import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.material.* import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.livedata.observeAsState import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.buildAnnotatedString import androidx.compose.ui.text.input.ImeAction import androidx.compose.ui.text.input.KeyboardType import androidx.compose.ui.text.input.PasswordVisualTransformation import androidx.compose.ui.text.withStyle import androidx.compose.ui.unit.dp import androidx.lifecycle.viewmodel.compose.viewModel import androidx.navigation.compose.NavHost import androidx.navigation.compose.composable import com.gyf.csams.BuildConfig import com.gyf.csams.R import com.gyf.csams.account.model.AccountViewModel import com.gyf.csams.account.model.DialogMessage import com.gyf.lib.uikit.* enum class AccountRoute { Login, Register } class AccountActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContent { TestBody { nav, scaffoldState -> NavHost(navController = nav, startDestination = AccountRoute.Login.name) { composable(AccountRoute.Login.name) { Account( route = AccountRoute.Login ) { isValidForm: Boolean, accountViewModel: AccountViewModel, scaffoldModel: ScaffoldModel -> Spacer(modifier = Modifier.height(10.dp)) OutlinedButton( onClick = { accountViewModel.login { scaffoldModel.update(message = it) } }, enabled = isValidForm, modifier = Modifier .fillMaxWidth() .padding(bottom = 10.dp) ) { Text(text = accountViewModel.loginDesc) } val finishLogin: Boolean? by accountViewModel.finishLogin.observeAsState() if (finishLogin == true) { finish() } OutlinedButton( onClick = { nav.navigate(AccountRoute.Register.name) }, modifier = Modifier.fillMaxWidth(), colors = ButtonDefaults.outlinedButtonColors( contentColor = MaterialTheme.colors.onBackground ) ) { Text(text = accountViewModel.goRegister) } ShowSnackbar(scaffoldState = scaffoldState) } } composable(AccountRoute.Register.name) { Account( route = AccountRoute.Register ) { isValidForm: Boolean, accountViewModel: AccountViewModel, _: ScaffoldModel -> Spacer(modifier = Modifier.height(10.dp)) OutlinedButton( onClick = { accountViewModel.register { } }, enabled = isValidForm, modifier = Modifier .fillMaxWidth() .padding(bottom = 10.dp) ) { Text(text = accountViewModel.regBtnDesc) } OutlinedButton( onClick = { nav.navigate(AccountRoute.Login.name) }, modifier = Modifier.fillMaxWidth(), colors = ButtonDefaults.outlinedButtonColors( contentColor = MaterialTheme.colors.onBackground ) ) { Text(text = accountViewModel.backLogin) } } } } } } } /** * 帐号表单 * * @param accountViewModel * @param Action 表单操作区域 */ @Composable private fun Account( accountViewModel: AccountViewModel = viewModel(), scaffoldModel: ScaffoldModel = viewModel(), route: AccountRoute, Action: @Composable (isValidForm: Boolean, accountViewModel: AccountViewModel, scaffoldModel: ScaffoldModel) -> Unit ) { accountViewModel.route = route Row( horizontalArrangement = Arrangement.Center, verticalAlignment = Alignment.CenterVertically, modifier = Modifier.fillMaxSize() ) { Column(modifier = Modifier.width(IntrinsicSize.Min)) { Text(buildAnnotatedString { withStyle( style = MaterialTheme.typography.subtitle1.toSpanStyle() .copy(color = MaterialTheme.colors.primary) ) { append(accountViewModel.name.formValue.value ?: "") } withStyle(style = MaterialTheme.typography.subtitle1.toSpanStyle()) { append(accountViewModel.welcomeStart) } withStyle(style = MaterialTheme.typography.subtitle2.toSpanStyle()) { append(accountViewModel.welcomeEnd) } withStyle( style = MaterialTheme.typography.subtitle2.toSpanStyle() .copy(color = MaterialTheme.colors.secondary) ) { append(BuildConfig.foreground_app_name) } }) StudentId() Spacer(modifier = Modifier.height(10.dp)) if (route == AccountRoute.Register) Name() else Password() Spacer(modifier = Modifier.height(10.dp)) PasswordTip() val isValidForm: Boolean by accountViewModel.isValidForm.observeAsState(false) Action( isValidForm = isValidForm, accountViewModel = accountViewModel, scaffoldModel = scaffoldModel ) RegisterDialog() } } } /** * 学号 * @param accountViewModel */ @Composable private fun StudentId(accountViewModel: AccountViewModel = viewModel()) { Column { val isValidStudentId by accountViewModel.studentId.statusForm.observeAsState() BaseTextField( form = accountViewModel.studentId, keyboardOptions = KeyboardOptions.Default.copy( keyboardType = KeyboardType.Number, imeAction = ImeAction.Done ), isError = isValidStudentId != FormStatus.Valid ) when (isValidStudentId) { FormStatus.Empty, FormStatus.FormatError -> Text( text = stringResource(id = R.string.student_id_format), color = MaterialTheme.colors.error, style = MaterialTheme.typography.body1 ) FormStatus.Repeat -> Text(buildAnnotatedString { append(accountViewModel.studentId.formDesc) withStyle( style = MaterialTheme.typography.body1.toSpanStyle().copy( color = MaterialTheme.colors.error ) ) { append(accountViewModel.studentId.formValue.value ?: "") } append(accountViewModel.registered) }) else -> { } } } } /** * 注册弹窗 * * @param accountViewModel */ @Composable private fun RegisterDialog(accountViewModel: AccountViewModel = viewModel()) { val dialogMsg: DialogMessage? by accountViewModel.dialogMsg.observeAsState(null) val message = dialogMsg?.userResDto?.password if (message?.isNotEmpty() == true) { PasswordDialog(message = message) } } /** * 密码弹窗 * * @param accountViewModel * @param message */ @Composable private fun PasswordDialog(accountViewModel: AccountViewModel = viewModel(), message: String) { val context = LocalContext.current val button: @Composable () -> Unit = { Row( horizontalArrangement = Arrangement.Center, modifier = Modifier .fillMaxWidth() .padding(bottom = 10.dp) ) { OutlinedButton( onClick = { accountViewModel.resetDialogMsg() }, modifier = Modifier.padding(end = 10.dp) ) { Text(text = accountViewModel.confirmDesc) } OutlinedButton( onClick = { context.startActivity(Intent(context, AccountActivity::class.java)) }, colors = ButtonDefaults.outlinedButtonColors( contentColor = MaterialTheme.colors.onBackground ) ) { Text(text = accountViewModel.backLogin) } } } AlertDialog(onDismissRequest = { accountViewModel.resetDialogMsg() }, buttons = button, title = { Text(text = accountViewModel.title) }, text = { Text(buildAnnotatedString { append(accountViewModel.passwordDialogStart) withStyle( style = MaterialTheme.typography.body1.toSpanStyle() .copy(color = MaterialTheme.colors.secondary) ) { append(message) } append(accountViewModel.passwordDialogEnd) }) }) } /** * 姓名文本框 * @param accountViewModel */ @Composable private fun Name(accountViewModel: AccountViewModel = viewModel()) { Column { val isValidName: Boolean by accountViewModel.isValidName.observeAsState(false) BaseTextField(form = accountViewModel.name, isError = !isValidName) if (!isValidName) { Text( text = accountViewModel.nameFormat, color = MaterialTheme.colors.error ) } } } /** * 密码框 * @param accountViewModel */ @Composable private fun Password(accountViewModel: AccountViewModel = viewModel()) { Column { val isValidPwd: Boolean by accountViewModel.isValidPwd.observeAsState(false) BaseTextField( form = accountViewModel.password, isError = !isValidPwd, keyboardOptions = KeyboardOptions.Default.copy( imeAction = ImeAction.Done, keyboardType = KeyboardType.Number, ), visualTransformation = PasswordVisualTransformation() ) if (!isValidPwd) { Text( text = accountViewModel.passwordFormat, color = MaterialTheme.colors.error ) } } } /** * 提示自动生成密码 * * @param accountViewModel */ @Composable private fun PasswordTip(accountViewModel: AccountViewModel = viewModel()) { if (accountViewModel.isValidForm.value == true) { Text( text = accountViewModel.passwordTip, color = MaterialTheme.colors.primary, modifier = Modifier.fillMaxWidth() ) } } }