You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

398 lines
14 KiB

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.LaunchedEffect
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.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.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable
import androidx.navigation.compose.navigate
import com.gyf.csams.BuildConfig
import com.gyf.csams.account.model.AccountViewModel
import com.gyf.csams.account.model.DialogMessage
import com.gyf.csams.uikit.AnimationText
import com.gyf.csams.uikit.BaseTextField
import com.gyf.csams.uikit.Body
import com.gyf.csams.uikit.theme.CSAMSTheme
import com.orhanobut.logger.Logger
enum class AccountRoute {
login,
register
}
class AccountActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
CSAMSTheme {
Body { nav, scaffoldState ->
NavHost(navController = nav, startDestination = AccountRoute.login.name) {
composable(AccountRoute.login.name) {
Account(
scaffoldState = scaffoldState,
route = AccountRoute.login
) { isValidForm: Boolean, accountViewModel: AccountViewModel ->
Spacer(modifier = Modifier.height(10.dp))
OutlinedButton(
onClick = { accountViewModel.login() },
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)
}
}
}
composable(AccountRoute.register.name) {
Account(
scaffoldState = scaffoldState,
route = AccountRoute.register
) { isValidForm: Boolean, accountViewModel: AccountViewModel ->
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(),
scaffoldState: ScaffoldState,
route: AccountRoute,
Action: @Composable (isValidForm: Boolean, accountViewModel: AccountViewModel) -> 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(checkRepeat = route == AccountRoute.register)
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)
val snackBarMsg: String by accountViewModel.snackBarMsg.observeAsState("")
if (snackBarMsg != "") {
LaunchedEffect(scaffoldState) {
scaffoldState.snackbarHostState.showSnackbar(
message = snackBarMsg
)
accountViewModel.resetRegisterResMsg()
}
}
RegisterDialog()
}
}
}
/**
* 学号
* @param accountViewModel
*/
@Composable
private fun StudentId(accountViewModel: AccountViewModel = viewModel(), checkRepeat: Boolean) {
Column {
val isValidStudentId: Boolean by accountViewModel.isValidStudentId.observeAsState(false)
BaseTextField(
form = accountViewModel.studentId, keyboardOptions = KeyboardOptions.Default.copy(
keyboardType = KeyboardType.Number,
imeAction = ImeAction.Done
), isError = !isValidStudentId
)
if (isValidStudentId) {
if (checkRepeat) {
val isRepeat: Boolean? by accountViewModel.isRepeat.observeAsState(null)
Logger.i("isRepeat=$isRepeat")
when (isRepeat) {
null -> AnimationText(text = accountViewModel.checkRegTip)
true ->
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)
})
false ->
Text(buildAnnotatedString {
append(accountViewModel.studentId.formDesc)
withStyle(
style = MaterialTheme.typography.body1.toSpanStyle().copy(
color = MaterialTheme.colors.primary
)
) {
append(accountViewModel.studentId.formValue.value ?: "")
}
append(accountViewModel.canRegister)
})
}
}
} else {
Text(
text = accountViewModel.studentIdFormat,
color = MaterialTheme.colors.error,
style = MaterialTheme.typography.body1
)
}
}
}
/**
* 注册弹窗
*
* @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()
)
}
}
@Preview(showBackground = true)
@Composable
fun DefaultPreview() {
CSAMSTheme {
Row(
horizontalArrangement = Arrangement.Center,
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier.fillMaxSize()
) {
Column(modifier = Modifier.width(IntrinsicSize.Min)) {
val model: AccountViewModel = viewModel()
StudentId(model, false)
Spacer(modifier = Modifier.height(10.dp))
}
}
}
}