parent
e8dfc71a90
commit
54ecee40c0
@ -0,0 +1,227 @@ |
|||||||
|
package com.gyf.csams.association.model |
||||||
|
|
||||||
|
import androidx.lifecycle.LiveData |
||||||
|
import androidx.lifecycle.MutableLiveData |
||||||
|
import com.gyf.csams.uikit.ScrollList |
||||||
|
import com.gyf.csams.uikit.StringForm |
||||||
|
import kotlin.random.Random |
||||||
|
|
||||||
|
/** |
||||||
|
* 题型 |
||||||
|
* |
||||||
|
*/ |
||||||
|
enum class ExamType(val type:String){ |
||||||
|
//选择题 |
||||||
|
cq("选择题"), |
||||||
|
//开放题 |
||||||
|
oq("开放题") |
||||||
|
} |
||||||
|
|
||||||
|
sealed class Exam{ |
||||||
|
abstract val examType:ExamType |
||||||
|
abstract val question:StringForm |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* 开放题 |
||||||
|
* |
||||||
|
* @property examType 题型描述 |
||||||
|
* @property question 问题 |
||||||
|
*/ |
||||||
|
data class OpenQuestionsVo( |
||||||
|
override val examType: ExamType = ExamType.oq, override val question: StringForm |
||||||
|
|
||||||
|
) : Exam() |
||||||
|
|
||||||
|
/** |
||||||
|
* 选择题 |
||||||
|
* |
||||||
|
* @property examType 题型描述 |
||||||
|
* @property answers 答案 |
||||||
|
* @property rightAnswer 正确答案 |
||||||
|
* @property question 问题 |
||||||
|
*/ |
||||||
|
data class ChoiceQuestionVo(override val examType: ExamType = ExamType.cq, |
||||||
|
val answers:List<StringForm>, |
||||||
|
val rightAnswer:Int, |
||||||
|
override val question: StringForm |
||||||
|
):Exam() |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* 题库状态管理 |
||||||
|
* |
||||||
|
*/ |
||||||
|
|
||||||
|
/** |
||||||
|
* 问题长度 |
||||||
|
*/ |
||||||
|
const val QUESTION_TEXT_LENGTH=30 |
||||||
|
|
||||||
|
/** |
||||||
|
* 选择题选项数 |
||||||
|
*/ |
||||||
|
const val ANSWER_SIZE=4 |
||||||
|
|
||||||
|
/** |
||||||
|
* 答案长度 |
||||||
|
* |
||||||
|
*/ |
||||||
|
const val ANSWER_TEXT_LENGTH=15 |
||||||
|
|
||||||
|
|
||||||
|
class ExamViewModel:ScrollList<Exam>() { |
||||||
|
val questionIsNull: String = "问题不能为空" |
||||||
|
val deleteLeastOne: String="至少保留一道题目" |
||||||
|
val updateExam="更新题库" |
||||||
|
val back="返回" |
||||||
|
val menuName="入团题库" |
||||||
|
val deleteTip="确定删除此题目?" |
||||||
|
val addTip="确定添加此题目?" |
||||||
|
val actionLabel="确定" |
||||||
|
|
||||||
|
|
||||||
|
override val initSize = 10 |
||||||
|
|
||||||
|
|
||||||
|
private val _newExam:MutableLiveData<Exam> = MutableLiveData(createExam(ExamType.cq)) |
||||||
|
val newExam:LiveData<Exam> = _newExam |
||||||
|
|
||||||
|
init { |
||||||
|
load() |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 切换题型 |
||||||
|
* |
||||||
|
*/ |
||||||
|
fun switchType(exam: Exam){ |
||||||
|
if(exam is ChoiceQuestionVo) _newExam.value=createExam(ExamType.oq) else _newExam.value=createExam(ExamType.cq) |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* 创建题目 |
||||||
|
* |
||||||
|
* @param type |
||||||
|
* @return |
||||||
|
*/ |
||||||
|
private fun createExam(type: ExamType): Exam { |
||||||
|
val question=StringForm(formDesc = "问题",textLength = QUESTION_TEXT_LENGTH) |
||||||
|
return when(type){ |
||||||
|
ExamType.cq-> ChoiceQuestionVo( |
||||||
|
answers = ('A'..'D').map { StringForm(formDesc = "选项",textLength = ANSWER_TEXT_LENGTH,value = "选项$it") }, |
||||||
|
rightAnswer = 0, |
||||||
|
question = question |
||||||
|
) |
||||||
|
ExamType.oq-> OpenQuestionsVo(question = question) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* 更新题目 |
||||||
|
* |
||||||
|
*/ |
||||||
|
fun update(oldExam: Exam,newExam:Exam){ |
||||||
|
if(oldExam==_newExam.value){ |
||||||
|
_newExam.value=newExam |
||||||
|
}else{ |
||||||
|
_data.value?.apply { |
||||||
|
this[indexOf(oldExam)]=newExam |
||||||
|
val list = mutableListOf<Exam>() |
||||||
|
list.addAll(this) |
||||||
|
_data.value?.clear() |
||||||
|
_data.value=list |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* TODO 更新题库 |
||||||
|
* |
||||||
|
* @param callback |
||||||
|
*/ |
||||||
|
fun updateExam(callback: (message: String) -> Unit){ |
||||||
|
callback("功能尚未实现,敬请期待") |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 加载题目 |
||||||
|
* |
||||||
|
*/ |
||||||
|
override fun load() { |
||||||
|
_data.value?.apply { |
||||||
|
repeat(initSize) { |
||||||
|
if (Random.nextBoolean()){ |
||||||
|
add(OpenQuestionsVo(question = StringForm(formDesc = "问题",textLength = QUESTION_TEXT_LENGTH,value = "这是一道开放题:$size"))) |
||||||
|
} else{ |
||||||
|
add( |
||||||
|
ChoiceQuestionVo( |
||||||
|
question = StringForm(formDesc = "问题",textLength = QUESTION_TEXT_LENGTH,value = "这是一道选择题:$size"), |
||||||
|
answers = ('A'..'D').map { StringForm(formDesc = "选项",textLength = ANSWER_TEXT_LENGTH,value = "选项$it") }, |
||||||
|
rightAnswer = Random.nextInt(ANSWER_SIZE) |
||||||
|
) |
||||||
|
) |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
*TODO 加载更多题目 |
||||||
|
* |
||||||
|
* @param callback |
||||||
|
*/ |
||||||
|
override fun loadMore(callback: (message: String) -> Unit) { |
||||||
|
// _data.value?.apply { |
||||||
|
// val list= mutableListOf<Exam>() |
||||||
|
// list.addAll(this) |
||||||
|
// list.apply { |
||||||
|
// repeat(10) { |
||||||
|
// if (Random.nextBoolean()) add(OpenQuestionsVo(question = "这是一道开放题:$size")) else add( |
||||||
|
// ChoiceQuestionVo( |
||||||
|
// question = "这是一道选择题:$size,请从选项中选出正确答案", |
||||||
|
// answers = listOf("选项A", "选项B", "选项C", "选项D"), |
||||||
|
// rightAnswer = 3 |
||||||
|
// ) |
||||||
|
// ) |
||||||
|
// } |
||||||
|
// } |
||||||
|
// _data.postValue(list) |
||||||
|
// callback("成功加载更多题目") |
||||||
|
// } |
||||||
|
|
||||||
|
// callback("功能尚未实现,敬请期待") |
||||||
|
} |
||||||
|
|
||||||
|
fun addQuestion() { |
||||||
|
_data.value?.apply { |
||||||
|
_newExam.value?.let{ |
||||||
|
val list= mutableListOf<Exam>() |
||||||
|
list.addAll(this) |
||||||
|
list.add(it) |
||||||
|
_data.postValue(list) |
||||||
|
} |
||||||
|
_newExam.value=createExam(ExamType.cq) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* TODO 删除题目 |
||||||
|
* |
||||||
|
*/ |
||||||
|
fun deleteQuestion(exam: Exam) { |
||||||
|
_data.value?.apply { |
||||||
|
val list = mutableListOf<Exam>() |
||||||
|
remove(exam) |
||||||
|
list.addAll(this) |
||||||
|
_data.postValue(list) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,306 @@ |
|||||||
|
package com.gyf.csams.association.ui |
||||||
|
|
||||||
|
import android.os.Bundle |
||||||
|
import androidx.activity.ComponentActivity |
||||||
|
import androidx.activity.compose.setContent |
||||||
|
import androidx.compose.foundation.background |
||||||
|
import androidx.compose.foundation.layout.* |
||||||
|
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.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.painterResource |
||||||
|
import androidx.compose.ui.unit.Dp |
||||||
|
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.uikit.* |
||||||
|
|
||||||
|
/** |
||||||
|
* 题库管理 |
||||||
|
* |
||||||
|
*/ |
||||||
|
class ExamActivity : ComponentActivity() { |
||||||
|
override fun onCreate(savedInstanceState: Bundle?) { |
||||||
|
super.onCreate(savedInstanceState) |
||||||
|
setContent { |
||||||
|
Body { scaffoldState -> |
||||||
|
MainFrame(background = { Background(image = BackgroundImage.exam) }) { |
||||||
|
Spacer(modifier = Modifier.weight(0.1F)) |
||||||
|
Title(modifier = Modifier.weight(0.1F)) |
||||||
|
Exam(modifier = Modifier.weight(0.8F)) |
||||||
|
ShowSnackbar(scaffoldState = scaffoldState) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 底部按钮 |
||||||
|
* |
||||||
|
*/ |
||||||
|
@Composable |
||||||
|
private fun BottomButton( |
||||||
|
modifier: Modifier = Modifier, |
||||||
|
model: ExamViewModel = viewModel(), |
||||||
|
scaffoldModel: ScaffoldModel = viewModel() |
||||||
|
) { |
||||||
|
val context = LocalContext.current as ExamActivity |
||||||
|
Row(modifier = modifier, horizontalArrangement = Arrangement.Center) { |
||||||
|
OutlinedButton(onClick = { |
||||||
|
model.updateExam { scaffoldModel.update(message=it) } |
||||||
|
}, modifier = Modifier.background(color = MaterialTheme.colors.primary)) { |
||||||
|
Text(text = model.updateExam) |
||||||
|
} |
||||||
|
Spacer(modifier = Modifier.width(10.dp)) |
||||||
|
OutlinedButton(onClick = { |
||||||
|
context.onBackPressed() |
||||||
|
}, modifier = Modifier.background(color = MaterialTheme.colors.secondary)) { |
||||||
|
Text(text = model.back) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 标题 |
||||||
|
* |
||||||
|
* @param modifier |
||||||
|
* @param model |
||||||
|
*/ |
||||||
|
@Composable |
||||||
|
private fun Title(modifier: Modifier = Modifier, model: ExamViewModel = viewModel()) { |
||||||
|
Row(horizontalArrangement = Arrangement.Center, modifier = modifier.fillMaxWidth()) { |
||||||
|
Text(text = model.menuName, style = MaterialTheme.typography.h4) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
@Composable |
||||||
|
private fun ExamChild(it:Exam,examHeight: Dp,isAdd: Boolean=false){ |
||||||
|
val questionWeight=0.3F |
||||||
|
when (it) { |
||||||
|
is OpenQuestionsVo -> ExamOQ( |
||||||
|
openQuestionsVo = it, |
||||||
|
modifier = Modifier.height(examHeight*questionWeight), |
||||||
|
isAdd = isAdd |
||||||
|
) |
||||||
|
is ChoiceQuestionVo -> ExamCQ( |
||||||
|
choiceQuestionVo = it, |
||||||
|
modifier = Modifier.height(examHeight), |
||||||
|
questionWeight = questionWeight, |
||||||
|
isAdd = isAdd |
||||||
|
) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 题目列表 |
||||||
|
* |
||||||
|
* @param modifier |
||||||
|
* @param model |
||||||
|
*/ |
||||||
|
@Composable |
||||||
|
private fun Exam( |
||||||
|
modifier: Modifier = Modifier, |
||||||
|
model: ExamViewModel = viewModel(), |
||||||
|
scaffoldModel: ScaffoldModel = viewModel(), |
||||||
|
examHeight: Dp = 350.dp |
||||||
|
) { |
||||||
|
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)) |
||||||
|
} |
||||||
|
} |
||||||
|
newExam?.let { |
||||||
|
item { |
||||||
|
Column { |
||||||
|
OutlinedButton(onClick = { model.switchType(it) }) { |
||||||
|
Text(text = "切换到${if (newExam is ChoiceQuestionVo) "开放题" else "选择题"}") |
||||||
|
} |
||||||
|
ExamChild(it = it, examHeight = examHeight,isAdd = true) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
item { |
||||||
|
Column { |
||||||
|
Divider(color = MaterialTheme.colors.background) |
||||||
|
Spacer(modifier = Modifier.height(30.dp)) |
||||||
|
BottomButton(modifier = Modifier.fillMaxWidth()) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
} |
||||||
|
if (listState.layoutInfo.totalItemsCount - listState.firstVisibleItemIndex == model.initSize / 2 - 1) { |
||||||
|
model.loadMore { scaffoldModel.update(message=it) } |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 问题 |
||||||
|
* |
||||||
|
* @param modifier |
||||||
|
* @param exam |
||||||
|
*/ |
||||||
|
@Composable |
||||||
|
private fun Question(modifier: Modifier = Modifier, exam: Exam) { |
||||||
|
BaseTextField( |
||||||
|
form = exam.question, |
||||||
|
modifier = modifier |
||||||
|
.fillMaxSize() |
||||||
|
.background(color = MaterialTheme.colors.background) |
||||||
|
) |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 操作按钮 |
||||||
|
* |
||||||
|
*/ |
||||||
|
@Composable |
||||||
|
private fun ActionButton(modifier: Modifier = Modifier, isAdd: Boolean, |
||||||
|
model: ExamViewModel= viewModel(), |
||||||
|
scaffoldModel: ScaffoldModel= viewModel(), |
||||||
|
exam: Exam) { |
||||||
|
val list by model.data.observeAsState() |
||||||
|
val newExam by model.newExam.observeAsState() |
||||||
|
Box( |
||||||
|
contentAlignment = Alignment.Center, |
||||||
|
modifier = modifier |
||||||
|
) { |
||||||
|
IconButton(onClick = { |
||||||
|
if(isAdd){ |
||||||
|
if((newExam?.question?.formValue?.value ?: "").isNotEmpty()){ |
||||||
|
scaffoldModel.update(message=model.addTip,actionLabel = model.actionLabel){ |
||||||
|
model.addQuestion() |
||||||
|
} |
||||||
|
}else{ |
||||||
|
scaffoldModel.update(message = model.questionIsNull) |
||||||
|
} |
||||||
|
|
||||||
|
}else{ |
||||||
|
if(list?.size==1){ |
||||||
|
scaffoldModel.update(model.deleteLeastOne) |
||||||
|
}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 |
||||||
|
) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* 开放题 |
||||||
|
* |
||||||
|
* @param openQuestionsVo |
||||||
|
*/ |
||||||
|
@Composable |
||||||
|
private fun ExamOQ( |
||||||
|
modifier: Modifier = Modifier, |
||||||
|
openQuestionsVo: OpenQuestionsVo, |
||||||
|
isAdd: Boolean = false |
||||||
|
) { |
||||||
|
Row(modifier = modifier) { |
||||||
|
Question( |
||||||
|
exam = openQuestionsVo, modifier = Modifier |
||||||
|
.weight(0.8F) |
||||||
|
.fillMaxHeight() |
||||||
|
) |
||||||
|
ActionButton( |
||||||
|
modifier = Modifier |
||||||
|
.weight(0.2F) |
||||||
|
.fillMaxHeight(), |
||||||
|
isAdd = isAdd, |
||||||
|
exam = openQuestionsVo |
||||||
|
) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 选择题 |
||||||
|
* |
||||||
|
* @param choiceQuestionVo |
||||||
|
*/ |
||||||
|
@Composable |
||||||
|
private fun ExamCQ( |
||||||
|
modifier: Modifier = Modifier, |
||||||
|
choiceQuestionVo: ChoiceQuestionVo, |
||||||
|
isAdd: Boolean = false, |
||||||
|
model: ExamViewModel = viewModel(), |
||||||
|
questionWeight:Float |
||||||
|
) { |
||||||
|
Row(modifier = modifier) { |
||||||
|
Column( |
||||||
|
modifier = Modifier |
||||||
|
.weight(0.8F) |
||||||
|
.fillMaxHeight() |
||||||
|
) { |
||||||
|
Question( |
||||||
|
exam = choiceQuestionVo, |
||||||
|
modifier = Modifier |
||||||
|
.fillMaxWidth() |
||||||
|
.weight(questionWeight) |
||||||
|
) |
||||||
|
Card( |
||||||
|
backgroundColor = MaterialTheme.colors.secondaryVariant, |
||||||
|
modifier = Modifier |
||||||
|
.fillMaxWidth() |
||||||
|
.weight(1 - questionWeight) |
||||||
|
) { |
||||||
|
|
||||||
|
choiceQuestionVo.answers.apply { |
||||||
|
Column { |
||||||
|
forEach { |
||||||
|
Row(modifier = Modifier |
||||||
|
.fillMaxWidth() |
||||||
|
.weight(1F / ANSWER_SIZE)) { |
||||||
|
val answerIndex: Int = indexOf(it) |
||||||
|
val click = { |
||||||
|
model.update( |
||||||
|
oldExam = choiceQuestionVo, |
||||||
|
newExam = choiceQuestionVo.copy(rightAnswer = answerIndex) |
||||||
|
) |
||||||
|
} |
||||||
|
val isRightAnswer = |
||||||
|
choiceQuestionVo.rightAnswer == answerIndex |
||||||
|
RadioButton(selected = isRightAnswer, onClick = click) |
||||||
|
BaseTextField(form = it) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
ActionButton( |
||||||
|
modifier = Modifier |
||||||
|
.weight(0.2F) |
||||||
|
.fillMaxHeight(), |
||||||
|
isAdd = isAdd, |
||||||
|
exam = choiceQuestionVo |
||||||
|
) |
||||||
|
|
||||||
|
} |
||||||
|
} |
@ -0,0 +1,111 @@ |
|||||||
|
package com.gyf.csams.util |
||||||
|
|
||||||
|
import com.google.gson.* |
||||||
|
import com.google.gson.reflect.TypeToken |
||||||
|
import com.gyf.csams.association.model.* |
||||||
|
import com.gyf.csams.uikit.StringForm |
||||||
|
import java.lang.reflect.Type |
||||||
|
|
||||||
|
class OpenQuestionsVoSerializer: JsonSerializer<OpenQuestionsVo> { |
||||||
|
override fun serialize( |
||||||
|
vo: OpenQuestionsVo?, |
||||||
|
p1: Type?, |
||||||
|
p2: JsonSerializationContext? |
||||||
|
): JsonElement { |
||||||
|
val gson= Gson() |
||||||
|
val c = JsonObject() |
||||||
|
c.add("examType", gson.toJsonTree(vo?.examType?.name)) |
||||||
|
c.add("question",gson.toJsonTree(vo?.question?.formValue?.value)) |
||||||
|
return c |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
class OpenQuestionsVoDeserializer: JsonDeserializer<OpenQuestionsVo> { |
||||||
|
override fun deserialize( |
||||||
|
json: JsonElement?, |
||||||
|
p1: Type?, |
||||||
|
p2: JsonDeserializationContext? |
||||||
|
): OpenQuestionsVo { |
||||||
|
val root=json?.asJsonObject |
||||||
|
val value=root?.get("question")?.asString |
||||||
|
val question= StringForm(formDesc = "问题",textLength = QUESTION_TEXT_LENGTH) |
||||||
|
if (value != null) { |
||||||
|
question.onChange(value) |
||||||
|
return OpenQuestionsVo(question = question) |
||||||
|
}else{ |
||||||
|
throw NullPointerException("问题无法解析!!!!") |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
class ChoiceQuestionVoSerializer: JsonSerializer<ChoiceQuestionVo> { |
||||||
|
override fun serialize( |
||||||
|
vo: ChoiceQuestionVo?, |
||||||
|
p1: Type?, |
||||||
|
p2: JsonSerializationContext? |
||||||
|
): JsonElement { |
||||||
|
val gson= Gson() |
||||||
|
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("rightAnswer",gson.toJsonTree(vo?.rightAnswer)) |
||||||
|
return c |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
class ChoiceQuestionVoDeserializer: JsonDeserializer<ChoiceQuestionVo> { |
||||||
|
override fun deserialize( |
||||||
|
json: JsonElement?, |
||||||
|
p1: Type?, |
||||||
|
p2: JsonDeserializationContext? |
||||||
|
): ChoiceQuestionVo { |
||||||
|
val root=json?.asJsonObject |
||||||
|
val value=root?.get("question")?.asString |
||||||
|
val question=StringForm(formDesc = "问题",textLength = QUESTION_TEXT_LENGTH) |
||||||
|
if (value != null) { |
||||||
|
question.onChange(value) |
||||||
|
val gson=Gson() |
||||||
|
val answers:List<String> = gson.fromJson(root.get("answers"),object : TypeToken<List<String>>() {}.type) |
||||||
|
if(answers.size!= ANSWER_SIZE){ |
||||||
|
throw IllegalArgumentException("选项数量!=$QUESTION_TEXT_LENGTH") |
||||||
|
} |
||||||
|
val rightAnswer=root.get("rightAnswer").asInt |
||||||
|
return ChoiceQuestionVo( |
||||||
|
question = question, |
||||||
|
answers = answers.map { StringForm(formDesc = "选项",textLength = ANSWER_TEXT_LENGTH,value=it) }, |
||||||
|
rightAnswer = rightAnswer |
||||||
|
) |
||||||
|
}else{ |
||||||
|
throw NullPointerException("问题无法解析!!!!") |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 题目反序列化 |
||||||
|
* |
||||||
|
*/ |
||||||
|
class ExamDeserializer:JsonDeserializer<Exam>{ |
||||||
|
companion object{ |
||||||
|
val gson: Gson =GsonBuilder() |
||||||
|
.registerTypeAdapter(OpenQuestionsVo::class.java,OpenQuestionsVoDeserializer()) |
||||||
|
.registerTypeAdapter(ChoiceQuestionVo::class.java,ChoiceQuestionVoDeserializer()) |
||||||
|
.create() |
||||||
|
} |
||||||
|
|
||||||
|
override fun deserialize(json: JsonElement?, p1: Type?, p2: JsonDeserializationContext?): Exam { |
||||||
|
val root=json?.asJsonObject |
||||||
|
|
||||||
|
val type=root?.get("examType")?.asString |
||||||
|
|
||||||
|
return when (gson.fromJson(type, ExamType::class.java)) { |
||||||
|
ExamType.cq -> gson.fromJson(json, |
||||||
|
object : TypeToken<ChoiceQuestionVo>() {}.type) |
||||||
|
ExamType.oq -> gson.fromJson(json, |
||||||
|
object : TypeToken<OpenQuestionsVo>() {}.type) |
||||||
|
null->throw NullPointerException("无法识别题目类型!") |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
} |
@ -0,0 +1,9 @@ |
|||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android" |
||||||
|
android:width="200dp" |
||||||
|
android:height="200dp" |
||||||
|
android:viewportWidth="1024" |
||||||
|
android:viewportHeight="1024"> |
||||||
|
<path |
||||||
|
android:fillColor="#FF000000" |
||||||
|
android:pathData="M544,213.33v266.67H810.67v64H544V810.67h-64V544H213.33v-64h266.67V213.33z"/> |
||||||
|
</vector> |
@ -0,0 +1,9 @@ |
|||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android" |
||||||
|
android:width="200dp" |
||||||
|
android:height="200dp" |
||||||
|
android:viewportWidth="1024" |
||||||
|
android:viewportHeight="1024"> |
||||||
|
<path |
||||||
|
android:fillColor="#FF000000" |
||||||
|
android:pathData="M810.67,480v64H213.33v-64z"/> |
||||||
|
</vector> |
Loading…
Reference in new issue