diff --git a/foreground/src/main/AndroidManifest.xml b/foreground/src/main/AndroidManifest.xml index b45d465..c44cc94 100644 --- a/foreground/src/main/AndroidManifest.xml +++ b/foreground/src/main/AndroidManifest.xml @@ -86,6 +86,9 @@ + + + diff --git a/foreground/src/main/java/com/gyf/csams/account/model/AccountViewModel.kt b/foreground/src/main/java/com/gyf/csams/account/model/AccountViewModel.kt index 2789789..fa6bd27 100644 --- a/foreground/src/main/java/com/gyf/csams/account/model/AccountViewModel.kt +++ b/foreground/src/main/java/com/gyf/csams/account/model/AccountViewModel.kt @@ -176,6 +176,7 @@ class AccountViewModel(application: Application) : AbstractLoginViewModel(applic password = it.body ?: throw IllegalArgumentException("无法获取生成密码") ) ) + resetForm() }, onFail = onFail, typeToken = object : TypeToken>() {}.type @@ -185,7 +186,6 @@ class AccountViewModel(application: Application) : AbstractLoginViewModel(applic name = name.getValue() ) ) - resetForm() } else { Logger.wtf("表单校验失败,无法$regBtnDesc!!!") } @@ -198,6 +198,7 @@ class AccountViewModel(application: Application) : AbstractLoginViewModel(applic private fun resetForm() { id.clean() name.clean() + checkForm() } diff --git a/foreground/src/main/java/com/gyf/csams/association/model/AssociationViewModel.kt b/foreground/src/main/java/com/gyf/csams/association/model/AssociationViewModel.kt index 3b1e9df..154b313 100644 --- a/foreground/src/main/java/com/gyf/csams/association/model/AssociationViewModel.kt +++ b/foreground/src/main/java/com/gyf/csams/association/model/AssociationViewModel.kt @@ -21,10 +21,6 @@ class AssociationViewModel : ViewModel(), TopMenuInterface { override val _currentMenu: MutableLiveData = MutableLiveData() override val currentMenu: LiveData = _currentMenu - private val _dropDownMenuResult = MutableLiveData() - val dropDownMenuResult: LiveData = _dropDownMenuResult - - /** * 下拉菜单状态 */ @@ -34,10 +30,21 @@ class AssociationViewModel : ViewModel(), TopMenuInterface { private val _associationVo = MutableLiveData() val associationVo: LiveData = _associationVo - fun update(message: String?) { - _dropDownMenuResult.postValue(message) + private val _applyAssociationResultVo = MutableLiveData() + val applyAssociationResultVo: LiveData = _applyAssociationResultVo + + private val _dropMenuMessage = MutableLiveData() + val dropMenuMessage: LiveData = _dropMenuMessage + + fun update(message: String? = null) { + _dropMenuMessage.postValue(message) + } + + fun update(applyAssociationResultVo: ApplyAssociationResultVo? = null) { + _applyAssociationResultVo.postValue(applyAssociationResultVo) } + fun load(id: Int) { viewModelScope.launch { HttpClient.post( @@ -64,6 +71,29 @@ class AssociationViewModel : ViewModel(), TopMenuInterface { _expanded.value = false } + /** + * 申请入团 + * + */ + fun applyAssociation(associationId: Int, callback: (result: ApplyAssociationResultVo) -> Unit) { + viewModelScope.launch { + HttpClient.post( + url = Api.buildUrl(AssociationApi.CheckApply), + callback = HttpCallback( + action = "申请入团", + onSuccess = { + it.body?.let { + callback(it) + } + }, + typeToken = object : TypeToken>() {}.type + ), + jsonParam = + SearchExamVo(associationId = associationId, token = TokenManager.getToken()) + ) + } + } + } /** diff --git a/foreground/src/main/java/com/gyf/csams/association/model/AuditJoinViewModel.kt b/foreground/src/main/java/com/gyf/csams/association/model/AuditJoinViewModel.kt new file mode 100644 index 0000000..313111a --- /dev/null +++ b/foreground/src/main/java/com/gyf/csams/association/model/AuditJoinViewModel.kt @@ -0,0 +1,53 @@ +package com.gyf.csams.association.model + +import android.app.Application +import androidx.lifecycle.viewModelScope +import com.google.gson.reflect.TypeToken +import com.gyf.csams.module.ApiResponse +import com.gyf.csams.module.AuditJoinVo +import com.gyf.csams.module.JoinAssociationVo +import com.gyf.csams.module.SearchExamVo +import com.gyf.lib.model.ScrollViewModel +import com.gyf.lib.util.* +import kotlinx.coroutines.launch + +class AuditJoinViewModel(application: Application) : + ScrollViewModel(application = application) { + + fun load(associationId: Int) { + viewModelScope.launch { + HttpClient.post( + url = Api.buildUrl(AssociationApi.CheckJoin), + callback = HttpCallback>( + action = "查看入团申请记录", + onSuccess = { + it.body?.let { + _data.postValue(it) + } + }, + typeToken = object : + TypeToken>>() {}.type + ), jsonParam = + SearchExamVo(associationId = associationId, token = TokenManager.getToken()) + ) + } + } + + /** + * 审核结果 + * + * @param joinId + * @param result + */ + fun audit(joinId: Int, result: Boolean, callback: (message: String) -> Unit) { + viewModelScope.launch { + HttpClient.post( + url = Api.buildUrl(AssociationApi.AuditJoin), + callback = HttpCallback(action = "审核入团申请", onSuccess = { + callback(it.message) + }, typeToken = object : TypeToken>() {}.type), jsonParam = + AuditJoinVo(joinId = joinId, result = result, token = TokenManager.getToken()) + ) + } + } +} \ No newline at end of file diff --git a/foreground/src/main/java/com/gyf/csams/association/model/ExamViewModel.kt b/foreground/src/main/java/com/gyf/csams/association/model/ExamViewModel.kt index ce2929d..ea1f17f 100644 --- a/foreground/src/main/java/com/gyf/csams/association/model/ExamViewModel.kt +++ b/foreground/src/main/java/com/gyf/csams/association/model/ExamViewModel.kt @@ -3,10 +3,15 @@ package com.gyf.csams.association.model import android.app.Application import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData +import androidx.lifecycle.viewModelScope +import com.google.gson.reflect.TypeToken +import com.gyf.csams.module.* import com.gyf.lib.model.ScrollViewModel +import com.gyf.lib.uikit.AsyncStringForm import com.gyf.lib.uikit.StringForm -import com.gyf.lib.uikit.ValidStringForm -import com.gyf.lib.util.NOT_IMPL_TIP +import com.gyf.lib.util.* +import com.orhanobut.logger.Logger +import kotlinx.coroutines.launch /** * 题库界面类型 @@ -17,7 +22,10 @@ enum class ExamActivityType(val menuName: String) { SET_EXAM("入团题库"), //入团申请表 - JOIN_Association("入团申请表") + JOIN_Association("入团申请表"), + + //查看答卷 + Answer("查看答卷") } @@ -51,48 +59,57 @@ enum class ExamType(val type: String) { OQ("开放题") } -abstract class Exam { +abstract class Exam() { abstract val examType: ExamType + abstract val _question: StringForm - //**TODO 题目反序列化 - abstract val question: String? - abstract val _question: StringForm? + abstract fun check(): Boolean + abstract val questionId: Int? } /** * 选择题 * - * @property examType 题型描述 - * @property answers 答案 - * @property rightAnswer 正确答案 - * @property question 问题 - * TODO 题目反序列化 + * */ data class ChoiceQuestionVo( - val id: Int? = null, override val examType: ExamType = ExamType.CQ, - val _answers: MutableList = mutableListOf(), - val answers: List = ('A'..'D').map { "选项${it}" }.toList(), + val _answers: MutableList, val rightAnswer: Int, - override val question: String? = null, - override val _question: StringForm?, + val chooseOption: Int? = null, + override val _question: StringForm, + override val questionId: Int? = null, + + ) : Exam() { - ) : Exam() + override fun check(): Boolean { + if (_question.formValue.value?.isEmpty() == true || _question.formValue.value == null) { + return false + } + _answers.forEach { + if (it.formValue.value == null || it.formValue.value?.isEmpty() == true) { + return false + } + } + return true + } +} /** * 开放题 * - * @property examType 题型描述 - * @property question 问题 - * TODO 题目反序列化 */ data class OpenQuestionsVo( override val examType: ExamType = ExamType.OQ, - override val question: String? = null, - override val _question: StringForm? + override val _question: StringForm, + override val questionId: Int?, -) : Exam() + ) : Exam() { + override fun check(): Boolean { + TODO("Not yet implemented") + } +} /** * 题库状态管理 @@ -100,53 +117,64 @@ data class OpenQuestionsVo( */ class ExamViewModel(application: Application) : ScrollViewModel(application) { - val questionIsNull: String = "问题不能为空" - val deleteLeastOne: String = "至少保留一道题目" + val questionIsNull: String = "问题或答案为空" val deleteTip = "确定删除此题目?" val addTip = "确定添加此题目?" val actionLabel = "确定" - private val _newExam: MutableLiveData = MutableLiveData(createExam(ExamType.CQ)) + private val _newExam: MutableLiveData = MutableLiveData() val newExam: LiveData = _newExam - init { - load() - } - - - - /** - * 切换题型 - * - */ - fun switchType(exam: Exam) { - if (exam is ChoiceQuestionVo) _newExam.value = createExam(ExamType.OQ) else _newExam.value = - createExam(ExamType.CQ) - } + private val _deleteIds = mutableListOf() + private val _allowPostAnswer = MutableLiveData() + val allowPostAnswer: LiveData = _allowPostAnswer /** * 创建题目 * - * @param type * @return */ - private fun createExam(type: ExamType): Exam { - - val questionForm = ValidStringForm(formDesc = "", textLength = QUESTION_TEXT_LENGTH) - val answerA = ValidStringForm(formDesc = "选项A", textLength = ANSWER_TEXT_LENGTH) - val answerB = ValidStringForm(formDesc = "选项B", textLength = ANSWER_TEXT_LENGTH) - val answerC = ValidStringForm(formDesc = "选项C", textLength = ANSWER_TEXT_LENGTH) - val answerD = ValidStringForm(formDesc = "选项D", textLength = ANSWER_TEXT_LENGTH) - - return ChoiceQuestionVo( - _answers = mutableListOf(answerA, answerB, answerC, answerD), - rightAnswer = 0, - _question = questionForm, - ) + private fun createExam(examVo: ExamVo? = null, answer: Int? = null): Exam { + val questionForm = AsyncStringForm(formDesc = "问题", textLength = QUESTION_TEXT_LENGTH) + val answerA = AsyncStringForm(formDesc = "选项A", textLength = ANSWER_TEXT_LENGTH) + val answerB = AsyncStringForm(formDesc = "选项B", textLength = ANSWER_TEXT_LENGTH) + val answerC = AsyncStringForm(formDesc = "选项C", textLength = ANSWER_TEXT_LENGTH) + val answerD = AsyncStringForm(formDesc = "选项D", textLength = ANSWER_TEXT_LENGTH) + if (examVo != null) { + questionForm.setValue(examVo.question) + answerA.setValue(examVo.optionsA) + answerB.setValue(examVo.optionsB) + answerC.setValue(examVo.optionsC) + answerD.setValue(examVo.optionsD) + return ChoiceQuestionVo( + _answers = mutableListOf(answerA, answerB, answerC, answerD), + rightAnswer = examVo.rightOption, + _question = questionForm, + questionId = examVo.questionId, + chooseOption = answer + ) + } else { + return ChoiceQuestionVo( + _answers = mutableListOf(answerA, answerB, answerC, answerD), + rightAnswer = 0, + _question = questionForm, + ) + } + + } + fun checkChooseAnswer() { + _data.value?.forEach { + if (it is ChoiceQuestionVo && it.chooseOption == null) { + _allowPostAnswer.postValue(false) + return + } + } + _allowPostAnswer.postValue(true) + } /** * 更新题目 @@ -167,32 +195,153 @@ class ExamViewModel(application: Application) : ScrollViewModel(applicatio } /** - * TODO 更新题库 + * 更新题库 * * @param callback */ - fun updateExam(callback: (message: String) -> Unit) { + fun updateExam(associationId: Int, callback: (message: String) -> Unit) { + viewModelScope.launch { + _data.value?.dropLast(1)?.mapNotNull { it -> + if (it is ChoiceQuestionVo) { + toExamVo(choiceQuestionVo = it) + } else { + null + } + }?.apply { + HttpClient.post(url = Api.buildUrl(AssociationApi.UpdateExam), + callback = HttpCallback(action = "更新题库", + onSuccess = { + callback(it.message) + }, typeToken = object : TypeToken>() {}.type + ), + jsonParam = AddExamVo( + questions = this, + associationId = associationId, + token = TokenManager.getToken(), + deleteIds = _deleteIds + ) + ) + } + } + } + private fun toExamVo(choiceQuestionVo: ChoiceQuestionVo): ExamVo? { + return choiceQuestionVo.let { + val options = it._answers.map { + it.getValue() + } + if (options.size == 4) { + ExamVo( + question = it._question.getValue(), optionsA = options[0], + optionsB = options[1], optionsC = options[2], optionsD = options[3], + rightOption = it.rightAnswer, + + questionId = it.questionId + ) + } else { + null + } + } } /** - * TODO 提交答案 - * + * 提交答卷 * @param callback */ - fun postAnswer(callback: (message: String) -> Unit) { - callback(NOT_IMPL_TIP) + fun postAnswer(associationId: Int, callback: (message: String) -> Unit) { + viewModelScope.launch { + _data.value?.mapNotNull { it -> + if (it is ChoiceQuestionVo) { + toExamVo(choiceQuestionVo = it)?.let { choice -> + ApplyAnswerVo( + examVo = choice, + answer = it.chooseOption + ?: throw IllegalArgumentException("题目[id=${choice.questionId}]没有填写答案???") + ) + }.apply { + Logger.i("$this") + } + } else { + null + } + }?.let { + Logger.i("提交${it.size}道题目答案") + HttpClient.post(url = Api.buildUrl(AssociationApi.ApplyAnswer), + callback = HttpCallback(action = "提交答案", + onSuccess = { + callback(it.message) + }, typeToken = object : TypeToken>() {}.type + ), + jsonParam = AddAnswerVo( + answers = it, token = TokenManager.getToken(), + associationId = associationId + ) + ) + } + + } } /** - * 加载题目 + * 加载题库 * */ - fun load() { + fun load(associationId: Int, activityType: ExamActivityType) { + viewModelScope.launch { + HttpClient.post( + url = Api.buildUrl( + when (activityType) { + ExamActivityType.SET_EXAM -> AssociationApi.LoadExam + ExamActivityType.JOIN_Association -> AssociationApi.CreatePaper + else -> throw IllegalArgumentException("非法类型:${activityType}") + } + ), + callback = HttpCallback>(action = "加载题库", onSuccess = { it -> + it.body?.let { it1 -> + _data.postValue(it1.map { + createExam(examVo = it) + }.toMutableList().apply { + if (activityType == ExamActivityType.SET_EXAM) { + add(createExam()) + } + }) + } + }, typeToken = object : TypeToken>>() {}.type), + jsonParam = + SearchExamVo(associationId = associationId, token = TokenManager.getToken()) + ) + } + } + /** + * 加载答卷 + * + * @param joinId + * @param callback + */ + fun showAnswer(joinId: Int, callback: (message: String) -> Unit) { + viewModelScope.launch { + HttpClient.post( + url = Api.buildUrl(AssociationApi.ShowAnswers), + callback = HttpCallback>(action = "查看答案", onSuccess = { it -> + it.body?.apply { + val exam = map { + createExam(examVo = it.examVo, answer = it.answer) + } + _data.postValue(exam.toMutableList()) + } + callback(it.message) + }, typeToken = object : TypeToken>>() {}.type), + jsonParam = ShowAnswerVo(joinId = joinId, token = TokenManager.getToken()) + ) + } } + /** + * 添加题目 + * + */ fun addQuestion() { _data.value?.apply { _newExam.value?.let { @@ -201,20 +350,24 @@ class ExamViewModel(application: Application) : ScrollViewModel(applicatio list.add(it) _data.postValue(list) } - _newExam.value = createExam(ExamType.CQ) + _newExam.value = createExam() } } /** - * TODO 删除题目 - * + *删除题目 */ fun deleteQuestion(exam: Exam) { _data.value?.apply { val list = mutableListOf() remove(exam) list.addAll(this) + Logger.i("size=${list.size}") + _data.value?.clear() _data.postValue(list) + exam.questionId?.let { + _deleteIds.add(it) + } } } } \ No newline at end of file diff --git a/foreground/src/main/java/com/gyf/csams/association/ui/AssociationActivity.kt b/foreground/src/main/java/com/gyf/csams/association/ui/AssociationActivity.kt index d875346..07836e4 100644 --- a/foreground/src/main/java/com/gyf/csams/association/ui/AssociationActivity.kt +++ b/foreground/src/main/java/com/gyf/csams/association/ui/AssociationActivity.kt @@ -3,6 +3,7 @@ package com.gyf.csams.association.ui import android.content.Intent import android.os.Bundle import androidx.activity.ComponentActivity +import androidx.activity.compose.ManagedActivityResultLauncher import androidx.activity.compose.rememberLauncherForActivityResult import androidx.activity.compose.setContent import androidx.activity.result.contract.ActivityResultContracts @@ -62,21 +63,27 @@ class AssociationActivity : ComponentActivity() { val currentMenuName: AssociationMenu by model.currentMenu.observeAsState( AssociationMenu.startMenu ) - val intent = Intent(this, ExamActivity::class.java) + val expanded by model.expanded.observeAsState(false) - var message: String? by remember { - mutableStateOf(null) - } //TODO重命名操作反馈 val rename = rememberLauncherForActivityResult(contract = ActivityResultContracts.StartActivityForResult()) { if (it.resultCode == RESULT_OK) { val m = it.data?.getStringExtra(RenameActivity::class.java.name) Logger.i("社团重命名返回:${m}") - message = m + model.update(message = m) } } + val examResult = + rememberLauncherForActivityResult(contract = ActivityResultContracts.StartActivityForResult()) { + if (it.resultCode == RESULT_OK) { + val m = it.data?.getStringExtra(ExamActivity::class.java.name) + Logger.i("试卷提交结果:${m}") + model.update(message = m) + } + } + Column { TextTopAppBar(nav = nav, currentMenuName = currentMenuName.menuName, @@ -90,7 +97,6 @@ class AssociationActivity : ComponentActivity() { onDismissRequest = { }, properties = PopupProperties() ) { - when { TokenManager.getUserInfo()?.associationVo?.associationId == associationId && TokenManager.getUserInfo()?.isHead == true -> { DropdownMenuItem(onClick = { @@ -118,13 +124,20 @@ class AssociationActivity : ComponentActivity() { } } DropdownMenuItem(onClick = { - intent.apply { - putExtra( - ExamActivityType::name.name, - ExamActivityType.SET_EXAM - ) - } - startActivity(intent) + startActivity( + Intent( + this@AssociationActivity, + ExamActivity::class.java + ).apply { + putExtra( + AssociationActivity::class.java.name, + associationId + ) + putExtra( + ExamActivityType::name.name, + ExamActivityType.SET_EXAM + ) + }) model.close() }) { Row(verticalAlignment = Alignment.CenterVertically) { @@ -135,6 +148,27 @@ class AssociationActivity : ComponentActivity() { ) } } + DropdownMenuItem(onClick = { + startActivity( + Intent( + this@AssociationActivity, + AuditJoinActivity::class.java + ).apply { + putExtra( + AssociationActivity::class.java.name, + associationId + ) + }) + model.close() + }) { + Row(verticalAlignment = Alignment.CenterVertically) { + Text(text = ("入团审核")) + Icon( + painter = painterResource(id = R.drawable.ic_exchange_rate), + contentDescription = null + ) + } + } DropdownMenuItem(onClick = { rename.launch(Intent( this@AssociationActivity, @@ -159,13 +193,9 @@ class AssociationActivity : ComponentActivity() { } TokenManager.getUserInfo()?.associationVo == null -> DropdownMenuItem( onClick = { - intent.apply { - putExtra( - ExamActivityType::name.name, - ExamActivityType.JOIN_Association - ) + model.applyAssociation(associationId = associationId) { + model.update(applyAssociationResultVo = it) } - startActivity(intent) model.close() }) { Row(verticalAlignment = Alignment.CenterVertically) { @@ -177,7 +207,6 @@ class AssociationActivity : ComponentActivity() { } } } - DropdownMenuItem(onClick = { model.close() }) { @@ -202,32 +231,19 @@ class AssociationActivity : ComponentActivity() { composable(AssociationMenu.Member.name) { model.clickMenu(AssociationMenu.Member) Member() + ShowTip(model = model, examResult = examResult) ShowSnackbar(scaffoldState = scaffoldState) } composable(AssociationMenu.Main.name) { model.clickMenu(AssociationMenu.Main) Main() - //TODO 提示 - val scaffoldModel: ScaffoldModel = viewModel() - message?.let { - scaffoldModel.update(message = message, actionLabel = "刷新") - - val s by scaffoldModel.data.observeAsState() - if (s == null) { - message = null -// nav.navigate(AssociationMenu.Main.name) - } - LaunchedEffect(message) { - delay(it.length * 300L) - message = null -// nav.navigate(AssociationMenu.Main.name) - } - } + ShowTip(model = model, examResult = examResult) ShowSnackbar(scaffoldState = scaffoldState) } composable(AssociationMenu.ActivityList.name) { model.clickMenu(AssociationMenu.ActivityList) AssociationList() + ShowTip(model = model, examResult = examResult) ShowSnackbar(scaffoldState = scaffoldState) } } @@ -238,16 +254,71 @@ class AssociationActivity : ComponentActivity() { } } - //TODO下拉菜单操作反馈 + /** + * 显示提示 + * + * @param model + * @param examResult + */ @Composable private fun ShowTip( model: AssociationViewModel = viewModel(), - scaffoldModel: ScaffoldModel = viewModel() + examResult: ManagedActivityResultLauncher ) { - val m by model.dropDownMenuResult.observeAsState() - m?.let { - Logger.i("收到${it}") - scaffoldModel.update(message = it, actionLabel = "关闭提示") + val scaffoldModel: ScaffoldModel = viewModel() + val message by model.dropMenuMessage.observeAsState() + message?.let { + scaffoldModel.update(message = message, actionLabel = "刷新") + + val s by scaffoldModel.data.observeAsState() + if (s == null) { + model.update(message = null) + } + LaunchedEffect(message) { + delay(it.length * 300L) + model.update(message = null) + } + } + val applyAssociationResultVo by model.applyAssociationResultVo.observeAsState() + applyAssociationResultVo?.let { + when { + it.result == true && it.hasPaper == true -> + scaffoldModel.update( + message = "申请此社团需要完成一份笔试题,点击确认获取试卷", + actionLabel = "确认" + ) { + examResult.launch( + Intent( + this@AssociationActivity, + ExamActivity::class.java + ).apply { + putExtra(AssociationActivity::class.java.name, associationId) + putExtra( + ExamActivityType::name.name, + ExamActivityType.JOIN_Association + ) + }) + + } + it.result == true -> + scaffoldModel.update( + message = "入团申请发送成功,请耐心等待审核结果", + actionLabel = "收到" + ) + + it.associationVo != null -> + scaffoldModel.update( + message = "您已申请进入${it.associationVo?.name},请耐心等待审核结果", + actionLabel = "收到" + ) + + else -> + scaffoldModel.update( + message = "入团申请发送失败!", + actionLabel = "确认" + ) + } + model.update(applyAssociationResultVo = null) } } @@ -491,16 +562,15 @@ class AssociationActivity : ComponentActivity() { alpha = 07F ) }) { - val onGoWeight = 0.3F - OngoingActivity( - modifier = Modifier - .weight(onGoWeight) - .fillMaxWidth() - ) +// val onGoWeight = 0.3F +// OngoingActivity( +// modifier = Modifier +// .weight(onGoWeight) +// .fillMaxWidth() +// ) HistoryActivityList( modifier = Modifier .fillMaxWidth() - .weight(1 - onGoWeight) .border(width = 1.dp, color = MaterialTheme.colors.onBackground) ) } @@ -540,23 +610,30 @@ class AssociationActivity : ComponentActivity() { val listState = rememberLazyListState() val list by model.data.observeAsState() - LazyColumn(state = listState, modifier = modifier) { - list?.chunked(2)?.forEach { - item { - Row(modifier = Modifier.fillMaxWidth()) { - HistoryActivity(modifier = Modifier.weight(0.4F), it[0]) - Spacer(modifier = Modifier.weight(0.2F)) - if (it.size == 2) HistoryActivity(modifier = Modifier.weight(0.4F), it[1]) - else Box(modifier = Modifier.weight(0.4F)) + if (list?.size == 0) { + Row(modifier = Modifier.fillMaxWidth()) { + Text(text = "目前社团没有任何活动") + } + } else { + LazyColumn(state = listState, modifier = modifier) { + list?.chunked(2)?.forEach { + item { + Row(modifier = Modifier.fillMaxWidth()) { + HistoryActivity(modifier = Modifier.weight(0.4F), it[0]) + Spacer(modifier = Modifier.weight(0.2F)) + if (it.size == 2) HistoryActivity( + modifier = Modifier.weight(0.4F), + it[1] + ) + else Box(modifier = Modifier.weight(0.4F)) + } + Spacer(modifier = Modifier.height(10.dp)) + Divider(color = MaterialTheme.colors.background) } - Spacer(modifier = Modifier.height(10.dp)) - Divider(color = MaterialTheme.colors.background) } } } - if (listState.layoutInfo.totalItemsCount - listState.firstVisibleItemIndex == model.initSize / 2 - 1) { - TODO("加载更多") - } + } /** diff --git a/foreground/src/main/java/com/gyf/csams/association/ui/AuditJoinActivity.kt b/foreground/src/main/java/com/gyf/csams/association/ui/AuditJoinActivity.kt new file mode 100644 index 0000000..6adc829 --- /dev/null +++ b/foreground/src/main/java/com/gyf/csams/association/ui/AuditJoinActivity.kt @@ -0,0 +1,133 @@ +package com.gyf.csams.association.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.lazy.LazyColumn +import androidx.compose.material.Card +import androidx.compose.material.OutlinedButton +import androidx.compose.material.Text +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.unit.dp +import androidx.lifecycle.viewmodel.compose.viewModel +import com.gyf.csams.R +import com.gyf.csams.association.model.AuditJoinViewModel +import com.gyf.csams.association.model.ExamActivityType +import com.gyf.lib.uikit.Body +import com.gyf.lib.uikit.MainColumnFrame +import com.gyf.lib.uikit.ScaffoldModel +import com.gyf.lib.util.BottomButton +import com.gyf.lib.util.DateTimeUtil.datetimeFormat +import java.util.* + +/** + * 审核入团申请 + * + */ +class AuditJoinActivity : ComponentActivity() { + + private val associationId: Int + get() { + val id = intent.getIntExtra( + AssociationActivity::class.java.name, + 0 + ) + return if (id == 0) throw IllegalArgumentException("社团id:${id}不合法,初始化失败") else id + } + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + + setContent { + Body { + MainColumnFrame(background = { }) { + val model: AuditJoinViewModel = viewModel() + val data by model.data.observeAsState() + val scaffoldModel: ScaffoldModel = viewModel() + LaunchedEffect(associationId) { + model.load(associationId = associationId) + } + LazyColumn( + verticalArrangement = Arrangement.spacedBy( + 10.dp, + Alignment.CenterVertically + ) + ) { + data?.forEach { + item { + Card(elevation = 5.dp) { + Column( + modifier = Modifier.fillMaxWidth(), + horizontalAlignment = Alignment.CenterHorizontally + ) { + Text(text = "申请人:${it.user.name}") + Text(text = "申请时间:${Date(it.applyTime).datetimeFormat()}") + if (it.hasPaper) { + Spacer(modifier = Modifier.height(5.dp)) + OutlinedButton(onClick = { + startActivity( + Intent( + this@AuditJoinActivity, + ExamActivity::class.java + ).apply { + putExtra( + ExamActivityType::name.name, + ExamActivityType.Answer + ) + putExtra( + AuditJoinActivity::class.java.name, + it.id + ) + putExtra( + AssociationActivity::class.java.name, + it.associationVo.associationId + ) + }) + }) { + Text(text = "查看申请答卷") + } + Spacer(modifier = Modifier.height(5.dp)) + } + when (val result = it.result) { + null -> BottomButton(confirmDesc = R.string.allow_btn, + backDesc = R.string.refuse_btn, + modifier = Modifier.fillMaxWidth(), + onBack = { + model.audit(joinId = it.id, result = false) { + scaffoldModel.update( + message = it, + actionLabel = "关闭提示" + ) + model.load(associationId = associationId) + } + }, + onConfirm = { + model.audit(joinId = it.id, result = true) { + scaffoldModel.update( + message = it, + actionLabel = "关闭提示" + ) + model.load(associationId = associationId) + } + }) + true, false -> { + Text("审核结果:${if (result) "通过" else "不通过"}") + Text("审核时间:${it.auditTime?.let { Date(it).datetimeFormat() }}") + } + } + } + } + } + } + } + } + } + } + } +} \ No newline at end of file diff --git a/foreground/src/main/java/com/gyf/csams/association/ui/ExamActivity.kt b/foreground/src/main/java/com/gyf/csams/association/ui/ExamActivity.kt index a0572ce..60cc303 100644 --- a/foreground/src/main/java/com/gyf/csams/association/ui/ExamActivity.kt +++ b/foreground/src/main/java/com/gyf/csams/association/ui/ExamActivity.kt @@ -1,5 +1,6 @@ package com.gyf.csams.association.ui +import android.content.Intent import android.os.Bundle import androidx.activity.ComponentActivity import androidx.activity.compose.setContent @@ -9,6 +10,7 @@ import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.rememberLazyListState 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 @@ -19,6 +21,7 @@ import androidx.compose.ui.unit.dp import androidx.lifecycle.viewmodel.compose.viewModel import com.gyf.csams.R import com.gyf.csams.association.model.* +import com.gyf.csams.module.QUESTION_MIN_SIZE import com.gyf.csams.uikit.Background import com.gyf.csams.uikit.BackgroundImage import com.gyf.lib.uikit.BaseTextField @@ -26,6 +29,7 @@ import com.gyf.lib.uikit.Body import com.gyf.lib.uikit.MainColumnFrame import com.gyf.lib.uikit.ScaffoldModel import com.gyf.lib.util.BottomButton +import com.orhanobut.logger.Logger /** @@ -34,13 +38,32 @@ import com.gyf.lib.util.BottomButton */ class ExamActivity : ComponentActivity() { - lateinit var activityType: ExamActivityType + private val activityType: ExamActivityType + get() { + return intent?.getSerializableExtra(ExamActivityType::name.name) as ExamActivityType + } + + private val associationId: Int + get() { + val id = intent.getIntExtra( + AssociationActivity::class.java.name, + 0 + ) + return if (id == 0) throw IllegalArgumentException("不存在社团id,获取失败") else id + } + + private val joinId: Int + get() { + val id = intent.getIntExtra( + AuditJoinActivity::class.java.name, + 0 + ) + return if (id == 0) throw IllegalArgumentException("不存在申请记录id,获取失败") else id + } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - activityType = intent?.getSerializableExtra(ExamActivityType::name.name) as ExamActivityType - setContent { Body { MainColumnFrame(background = { @@ -49,14 +72,35 @@ class ExamActivity : ComponentActivity() { alpha = 0.6F ) }) { - Spacer(modifier = Modifier.weight(0.1F)) - Title(modifier = Modifier.weight(0.1F)) + Title() + Spacer(modifier = Modifier.height(10.dp)) Exam(modifier = Modifier.weight(0.8F)) } } } } + @Composable + private fun ErrorRadioButton(onClick: () -> Unit = {}) { + RadioButton( + selected = true, + colors = + RadioButtonDefaults.colors(disabledColor = MaterialTheme.colors.error), + onClick = onClick, + enabled = false + ) + } + + @Composable + private fun RightRadioButton(selected: Boolean, onClick: () -> Unit = {}) { + RadioButton( + selected = selected, + colors = + RadioButtonDefaults.colors(disabledColor = MaterialTheme.colors.primary), + onClick = onClick, + enabled = false + ) + } /** * 标题 @@ -64,12 +108,44 @@ class ExamActivity : ComponentActivity() { * @param modifier */ @Composable - private fun Title(modifier: Modifier = Modifier) { - Row(horizontalArrangement = Arrangement.Center, modifier = modifier.fillMaxWidth()) { - Text(text = activityType.menuName, style = MaterialTheme.typography.h4) + private fun Title(modifier: Modifier = Modifier, model: ExamViewModel = viewModel()) { + val data by model.data.observeAsState() + Column(modifier = modifier, horizontalAlignment = Alignment.CenterHorizontally) { + Text(text = activityType.menuName, style = MaterialTheme.typography.h5) + data?.size?.let { + Text(buildString { + append("共有${if (activityType == ExamActivityType.SET_EXAM) it - 1 else it}道题目") + if (it < QUESTION_MIN_SIZE) { + append(",还差${QUESTION_MIN_SIZE - it}道题目才可以生成入团笔试题") + } + }, style = MaterialTheme.typography.h6.copy(color = MaterialTheme.colors.primary)) + } + when (activityType) { + ExamActivityType.Answer -> Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.SpaceEvenly + ) { + Row { + RightRadioButton(selected = true) + Text(text = "表示正确选项") + } + Row { + ErrorRadioButton() + Text(text = "表示错误选项") + } + } + ExamActivityType.SET_EXAM -> Row(modifier = Modifier.fillMaxWidth()) { + Text(text = "通过单选按钮设置正确答案") + } + ExamActivityType.JOIN_Association -> Row(modifier = Modifier.fillMaxWidth()) { + Text(text = "通过单选按钮选择正确答案") + } + } + } } + @Composable private fun ExamChild(it: Exam, examHeight: Dp, isAdd: Boolean = false) { val questionWeight = 0.3F @@ -77,7 +153,7 @@ class ExamActivity : ComponentActivity() { is OpenQuestionsVo -> ExamOQ( openQuestionsVo = it, modifier = Modifier.height(examHeight * questionWeight), - isAdd = isAdd + isAdd = isAdd, ) is ChoiceQuestionVo -> ExamCQ( choiceQuestionVo = it, @@ -101,64 +177,88 @@ class ExamActivity : ComponentActivity() { scaffoldModel: ScaffoldModel = viewModel(), examHeight: Dp = 350.dp ) { + LaunchedEffect(associationId) { + when (activityType) { + ExamActivityType.JOIN_Association, ExamActivityType.SET_EXAM -> model.load( + associationId = associationId, + activityType = activityType + ) + ExamActivityType.Answer -> model.showAnswer(joinId = joinId) { + scaffoldModel.update(message = "答卷加载成功", actionLabel = "关闭提示") + } + } + + } val listState = rememberLazyListState() val data by model.data.observeAsState() val newExam by model.newExam.observeAsState() - LazyColumn(state = listState, modifier = modifier) { - data?.forEach { - item { - ExamChild(it = it, examHeight = examHeight) - Spacer(modifier = Modifier.height(20.dp)) + Column(modifier = modifier) { + LazyColumn(state = listState, modifier = Modifier.weight(0.8F)) { + data?.forEach { + item { + ExamChild(it = it, examHeight = examHeight) + Spacer(modifier = Modifier.height(20.dp)) + } } - } - newExam?.let { - item { - Column { + newExam?.let { + item { + Column { // OutlinedButton(onClick = { model.switchType(it) }) { // Text(text = "切换到${if (newExam is ChoiceQuestionVo) "开放题" else "选择题"}") // } - ExamChild(it = it, examHeight = examHeight, isAdd = true) + ExamChild(it = it, examHeight = examHeight, isAdd = true) + } } } + } - item { - Column { - Divider(color = MaterialTheme.colors.background) - Spacer(modifier = Modifier.height(30.dp)) - - when (activityType) { - ExamActivityType.SET_EXAM -> { - BottomButton( - modifier = Modifier.fillMaxWidth(), - confirmDesc = R.string.update_exam - ) { - model.updateExam { scaffoldModel.update(message = it) } - } + Divider(color = MaterialTheme.colors.background) + Spacer(modifier = Modifier.height(30.dp)) + when (activityType) { + ExamActivityType.SET_EXAM -> { + BottomButton( + modifier = Modifier.fillMaxWidth(), + confirmDesc = R.string.update_exam, + enabled = data?.size ?: 0 > 0 + ) { + model.updateExam(associationId = associationId) { + scaffoldModel.update( + message = it, actionLabel = "关闭提示" + ) } - ExamActivityType.JOIN_Association -> { - BottomButton( - modifier = Modifier.fillMaxWidth(), - confirmDesc = R.string.post_answer - ) { - model.postAnswer { scaffoldModel.update(message = it) } - } + } + } + ExamActivityType.JOIN_Association -> { + val allowPostAnswer by model.allowPostAnswer.observeAsState(false) + BottomButton( + modifier = Modifier.fillMaxWidth(), + confirmDesc = R.string.post_answer, + backDesc = R.string.cancel_apply, + enabled = allowPostAnswer + ) { + model.postAnswer(associationId = associationId) { + scaffoldModel.update(message = it) + setResult(RESULT_OK, Intent().apply { + putExtra(ExamActivity::class.java.name, it) + }) + finish() + } + } + } + ExamActivityType.Answer -> { + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.Center + ) { + OutlinedButton(onClick = { onBackPressed() }) { + Text(text = "返回") } - - } - } } - - } -// if (listState.layoutInfo.totalItemsCount - listState.firstVisibleItemIndex == model.initSize / 2 - 1) { -// model.loadMore { scaffoldModel.update(message = it) } -// } - - } /** @@ -172,12 +272,14 @@ class ExamActivity : ComponentActivity() { modifier: Modifier = Modifier, exam: Exam ) { - exam._question?.let { + exam._question.let { BaseTextField( form = it, modifier = modifier .fillMaxSize() - .background(color = MaterialTheme.colors.background) + .background(color = MaterialTheme.colors.background), + readOnly = activityType != ExamActivityType.SET_EXAM, + showTrailingIcon = activityType == ExamActivityType.SET_EXAM ) } @@ -194,44 +296,36 @@ class ExamActivity : ComponentActivity() { scaffoldModel: ScaffoldModel = viewModel(), exam: Exam ) { - val list by model.data.observeAsState() - model.newExam.value?._question?.let { - val value by it.formValue.observeAsState() - Box( - contentAlignment = Alignment.Center, - modifier = modifier - ) { - IconButton(onClick = { - if (isAdd) { - if ((value?.isNotEmpty() == true)) { - scaffoldModel.update( - message = model.addTip, - actionLabel = model.actionLabel - ) { - model.addQuestion() - } - } else { - scaffoldModel.update(message = model.questionIsNull) + Box( + contentAlignment = Alignment.Center, + modifier = modifier + ) { + IconButton(onClick = { + if (isAdd) { + if (exam.check()) { + scaffoldModel.update( + message = model.addTip, + actionLabel = model.actionLabel + ) { + model.addQuestion() } - } else { - if (list?.size == 1) { - scaffoldModel.update(model.deleteLeastOne) - } else { - scaffoldModel.update( - message = model.deleteTip, - actionLabel = model.actionLabel - ) { - model.deleteQuestion(exam = exam) - } - } + scaffoldModel.update(message = model.questionIsNull, actionLabel = "知道了") + } + + } else { + scaffoldModel.update( + message = model.deleteTip, + actionLabel = model.actionLabel + ) { + model.deleteQuestion(exam = exam) } - }) { - Icon( - painter = painterResource(id = if (isAdd) R.drawable.ic_add_select else R.drawable.ic_sami_select), - contentDescription = null - ) } + }) { + Icon( + painter = painterResource(id = if (isAdd) R.drawable.ic_add_select else R.drawable.ic_sami_select), + contentDescription = null + ) } } @@ -247,9 +341,15 @@ class ExamActivity : ComponentActivity() { private fun ExamOQ( modifier: Modifier = Modifier, openQuestionsVo: OpenQuestionsVo, - isAdd: Boolean = false + isAdd: Boolean = false, + model: ExamViewModel = viewModel() ) { + val data by model.data.observeAsState() Row(modifier = modifier) { + Logger.i("index=${data?.indexOf(openQuestionsVo)}") + data?.indexOf(openQuestionsVo)?.let { + Text(text = "${it}.", modifier = Modifier.weight(0.05F)) + } Question( exam = openQuestionsVo, modifier = if (activityType == ExamActivityType.SET_EXAM) @@ -262,7 +362,7 @@ class ExamActivity : ComponentActivity() { if (activityType == ExamActivityType.SET_EXAM) { ActionButton( modifier = Modifier - .weight(0.2F) + .weight(0.15F) .fillMaxHeight(), isAdd = isAdd, exam = openQuestionsVo @@ -285,6 +385,16 @@ class ExamActivity : ComponentActivity() { questionWeight: Float ) { Row(modifier = modifier) { + model.data.value?.let { + + Text( + text = "${ + if (it.indexOf(choiceQuestionVo) == -1) it.size else it.indexOf( + choiceQuestionVo + ) + 1 + }." + ) + } Column( modifier = if (activityType == ExamActivityType.SET_EXAM) Modifier @@ -315,16 +425,52 @@ class ExamActivity : ComponentActivity() { .weight(1F / ANSWER_SIZE) ) { val answerIndex: Int = indexOf(it) - val click = { - model.update( - oldExam = choiceQuestionVo, - newExam = choiceQuestionVo.copy(rightAnswer = answerIndex) - ) + + + when (activityType) { + ExamActivityType.SET_EXAM -> { + RadioButton( + selected = choiceQuestionVo.rightAnswer == answerIndex, + onClick = { + model.update( + oldExam = choiceQuestionVo, + newExam = choiceQuestionVo.copy(rightAnswer = answerIndex) + ) + }) + } + ExamActivityType.JOIN_Association -> { + RadioButton( + selected = choiceQuestionVo.chooseOption == answerIndex, + onClick = { + model.update( + oldExam = choiceQuestionVo, + newExam = choiceQuestionVo.copy(chooseOption = answerIndex) + ) + model.checkChooseAnswer() + }) + } + ExamActivityType.Answer -> { + when { + choiceQuestionVo.rightAnswer == answerIndex -> RightRadioButton( + selected = true + ) + choiceQuestionVo.chooseOption != choiceQuestionVo.rightAnswer && choiceQuestionVo.chooseOption == answerIndex -> + ErrorRadioButton() + else -> RadioButton( + selected = false, + onClick = {}, + enabled = false + ) + } + + } } - val isRightAnswer = - choiceQuestionVo.rightAnswer == answerIndex - RadioButton(selected = isRightAnswer, onClick = click) - BaseTextField(form = it) + + BaseTextField( + form = it, + enabled = activityType != ExamActivityType.Answer, + showTrailingIcon = activityType == ExamActivityType.SET_EXAM + ) } } @@ -333,15 +479,13 @@ class ExamActivity : ComponentActivity() { } } - if (activityType == ExamActivityType.SET_EXAM) { - ActionButton( - modifier = Modifier - .weight(0.2F) - .fillMaxHeight(), - isAdd = isAdd, - exam = choiceQuestionVo - ) - } + ActionButton( + modifier = Modifier + .weight(0.2F) + .fillMaxHeight(), + isAdd = isAdd, + exam = choiceQuestionVo + ) } } diff --git a/foreground/src/main/java/com/gyf/csams/util/GsonUtil.kt b/foreground/src/main/java/com/gyf/csams/util/GsonUtil.kt index 78754d7..f8d0df6 100644 --- a/foreground/src/main/java/com/gyf/csams/util/GsonUtil.kt +++ b/foreground/src/main/java/com/gyf/csams/util/GsonUtil.kt @@ -50,7 +50,7 @@ class ChoiceQuestionVoSerializer : JsonSerializer { val c = JsonObject() c.add("examType", gson.toJsonTree(vo?.examType?.name)) // c.add("question", gson.toJsonTree(vo?.question?.formValue?.value)) - c.add("answers", gson.toJsonTree(vo?.answers)) +// c.add("answers", gson.toJsonTree(vo?.answers)) c.add("rightAnswer", gson.toJsonTree(vo?.rightAnswer)) return c } diff --git a/foreground/src/main/res/values-en/strings.xml b/foreground/src/main/res/values-en/strings.xml index 8f46ff8..925e6c5 100644 --- a/foreground/src/main/res/values-en/strings.xml +++ b/foreground/src/main/res/values-en/strings.xml @@ -20,4 +20,5 @@ 收藏 上传 关闭 + 放弃申请 \ No newline at end of file diff --git a/foreground/src/main/res/values-zh/strings.xml b/foreground/src/main/res/values-zh/strings.xml index 8f46ff8..925e6c5 100644 --- a/foreground/src/main/res/values-zh/strings.xml +++ b/foreground/src/main/res/values-zh/strings.xml @@ -20,4 +20,5 @@ 收藏 上传 关闭 + 放弃申请 \ No newline at end of file diff --git a/foreground/src/main/res/values/strings.xml b/foreground/src/main/res/values/strings.xml index eea6d84..86dea0d 100644 --- a/foreground/src/main/res/values/strings.xml +++ b/foreground/src/main/res/values/strings.xml @@ -20,4 +20,5 @@ 收藏 上传 关闭 + 放弃申请 \ No newline at end of file diff --git a/foreground/src/test/java/com/gyf/csams/ExampleUnitTest.kt b/foreground/src/test/java/com/gyf/csams/ExampleUnitTest.kt index d553186..f8eb402 100644 --- a/foreground/src/test/java/com/gyf/csams/ExampleUnitTest.kt +++ b/foreground/src/test/java/com/gyf/csams/ExampleUnitTest.kt @@ -14,13 +14,24 @@ import org.junit.Test * * See [testing documentation](http://d.android.com/tools/testing). */ +abstract class TestA { + val i: Int = 3 +} + +data class TestB(val b: Int = 3) : TestA() { + + fun test() { + println("${i}") + } +} + class ExampleUnitTest { @Test fun addition_isCorrect() { assertEquals(4, 2 + 2) } - data class Fuck(val name:String) + data class Fuck(val name: String) diff --git a/lib/src/main/java/com/gyf/lib/uikit/BaseTextField.kt b/lib/src/main/java/com/gyf/lib/uikit/BaseTextField.kt index 92ca230..4478c9e 100644 --- a/lib/src/main/java/com/gyf/lib/uikit/BaseTextField.kt +++ b/lib/src/main/java/com/gyf/lib/uikit/BaseTextField.kt @@ -131,6 +131,7 @@ fun BaseTextField( isError: Boolean = false, visualTransformation: VisualTransformation = VisualTransformation.None, readOnly: Boolean = false, + enabled: Boolean = true, textStyle: TextStyle = LocalTextStyle.current, leadingIcon: @Composable (() -> Unit)? = null, trailingIcon: @Composable (() -> Unit)? = null, @@ -151,7 +152,8 @@ fun BaseTextField( isError = isError, visualTransformation = visualTransformation, readOnly = readOnly, - textStyle = textStyle + textStyle = textStyle, + enabled = enabled ) } @@ -174,7 +176,9 @@ fun BaseTextField( keyboardOptions: KeyboardOptions = KeyboardOptions.Default.copy(imeAction = ImeAction.Done), isError: Boolean = false, visualTransformation: VisualTransformation = VisualTransformation.None, - readOnly: Boolean = false + readOnly: Boolean = false, + showTrailingIcon: Boolean = true, + enabled: Boolean = true ) { val name: String by form.formValue.observeAsState("") BaseTextField( @@ -184,8 +188,9 @@ fun BaseTextField( keyboardOptions, isError, visualTransformation, - trailingIcon = { Text(text = "${name.length}/${form.textLength}") }, - readOnly = readOnly + trailingIcon = { if (showTrailingIcon) Text(text = "${name.length}/${form.textLength}") }, + readOnly = readOnly, + enabled = enabled ) } diff --git a/lib/src/main/java/com/gyf/lib/uikit/Snackbar.kt b/lib/src/main/java/com/gyf/lib/uikit/Snackbar.kt index 717a5a3..1b572a7 100644 --- a/lib/src/main/java/com/gyf/lib/uikit/Snackbar.kt +++ b/lib/src/main/java/com/gyf/lib/uikit/Snackbar.kt @@ -17,7 +17,7 @@ import kotlinx.coroutines.launch data class SnackBar( val message: String?, - val actionLabel: String? = null, + val actionLabel: String, val duration: SnackbarDuration = SnackbarDuration.Short, val callback: () -> Unit? ) @@ -30,7 +30,7 @@ class ScaffoldModel : ViewModel() { private val _data = MutableLiveData() val data: LiveData = _data - fun update(message: String? = null, actionLabel: String? = null, callback: () -> Unit? = {}) { + fun update(message: String? = null, actionLabel: String = "关闭提示", callback: () -> Unit? = {}) { if (message == null) { _data.postValue(null) } else { @@ -55,23 +55,19 @@ fun ShowSnackbar(model: ScaffoldModel = viewModel(), scaffoldState: ScaffoldStat if (message != null) { LaunchedEffect(scaffoldState) { launch { - if (actionLabel != null) { - val result = scaffoldState.snackbarHostState.showSnackbar( - message = message, actionLabel = actionLabel, - duration = duration + val result = scaffoldState.snackbarHostState.showSnackbar( + message = message, actionLabel = actionLabel, + duration = duration - ) - when (result) { - SnackbarResult.ActionPerformed -> { - Logger.i("点击操作按钮") - callback() - } - SnackbarResult.Dismissed -> { - Logger.d("窗口消失") - } + ) + when (result) { + SnackbarResult.ActionPerformed -> { + Logger.d("点击操作按钮") + callback() + } + SnackbarResult.Dismissed -> { + Logger.d("窗口消失") } - } else { - scaffoldState.snackbarHostState.showSnackbar(message = message) } model.update() } diff --git a/lib/src/main/java/com/gyf/lib/util/Api.kt b/lib/src/main/java/com/gyf/lib/util/Api.kt index 9588dc0..612e160 100644 --- a/lib/src/main/java/com/gyf/lib/util/Api.kt +++ b/lib/src/main/java/com/gyf/lib/util/Api.kt @@ -131,7 +131,31 @@ enum class AssociationApi(val path: String) : UrlPath { RenameAudit("${Rename.path}${Audit.path}"), //换名申请表审核进度 - RenameRead("${Rename.path}${Read.path}"); + RenameRead("${Rename.path}${Read.path}"), + + //更新题库 + UpdateExam("/update/exam"), + + //加载题库 + LoadExam("/load/exam"), + + //申请入团 + CheckApply("/check/apply"), + + //创建试卷 + CreatePaper("/create/paper"), + + //提交答卷 + ApplyAnswer("/apply/paper"), + + //检查入团申请 + CheckJoin("/check/join"), + + //审核入团申请 + AuditJoin("/audit/join"), + + //显示答案 + ShowAnswers("/show/answer"); override fun build(): String { return "/api/association${this.path}" diff --git a/lib/src/main/res/values-en/strings.xml b/lib/src/main/res/values-en/strings.xml index 83ac1ab..9df4988 100644 --- a/lib/src/main/res/values-en/strings.xml +++ b/lib/src/main/res/values-en/strings.xml @@ -31,4 +31,6 @@ 审核阶段 复审意见 活动日期 + 通过 + 拒绝 \ No newline at end of file diff --git a/lib/src/main/res/values-zh/strings.xml b/lib/src/main/res/values-zh/strings.xml index 83ac1ab..9df4988 100644 --- a/lib/src/main/res/values-zh/strings.xml +++ b/lib/src/main/res/values-zh/strings.xml @@ -31,4 +31,6 @@ 审核阶段 复审意见 活动日期 + 通过 + 拒绝 \ No newline at end of file diff --git a/lib/src/main/res/values/strings.xml b/lib/src/main/res/values/strings.xml index 83ac1ab..9df4988 100644 --- a/lib/src/main/res/values/strings.xml +++ b/lib/src/main/res/values/strings.xml @@ -31,4 +31,6 @@ 审核阶段 复审意见 活动日期 + 通过 + 拒绝 \ No newline at end of file