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.

375 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.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.orhanobut.logger.Logger
enum class AccountRoute {
login,
register
}
class AccountActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
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()
)
}
}
}