社团主界面设置下拉菜单

题库界面拆分为入团申请表和入团题库
master
pan 4 years ago
parent 1568cc1ffa
commit 707684bda3
  1. 29
      app/src/main/java/com/gyf/csams/association/model/AssociationViewModel.kt
  2. 39
      app/src/main/java/com/gyf/csams/association/model/ExamViewModel.kt
  3. 71
      app/src/main/java/com/gyf/csams/association/ui/AssociationActivity.kt
  4. 82
      app/src/main/java/com/gyf/csams/association/ui/ExamActivity.kt
  5. 70
      app/src/main/java/com/gyf/csams/uikit/BaseView.kt
  6. 4
      app/src/main/java/com/gyf/csams/util/GsonUtil.kt
  7. 9
      app/src/main/res/drawable/ic_add_account.xml
  8. 9
      app/src/main/res/drawable/ic_arrow_up.xml
  9. 9
      app/src/main/res/drawable/ic_editor.xml

@ -11,12 +11,41 @@ import com.orhanobut.logger.Logger
import kotlinx.coroutines.launch
class AssociationViewModel:ViewModel() {
/**
* 当前菜单
*/
private val _currentMenu=MutableLiveData<AssociationMenu>()
val currentMenu:LiveData<AssociationMenu> = _currentMenu
/**
* 下拉菜单状态
*/
private val _expanded=MutableLiveData(false)
val expanded:LiveData<Boolean> = _expanded
/**
* 切换顶部菜单
*
* @param menu
*/
fun clickMenu(menu:AssociationMenu){
_currentMenu.value=menu
}
/**
* 切换下拉菜单状态
*
*/
fun switchType(){
_expanded.value?.let {
_expanded.value = !it
}
}
fun close(){
_expanded.value=false
}
}
data class MemberVo(val name:String)

@ -6,15 +6,26 @@ import com.gyf.csams.uikit.ScrollList
import com.gyf.csams.uikit.StringForm
import kotlin.random.Random
/**
* 题库界面类型
*
*/
enum class ExamActivityType(val menuName:String){
//入团题库
SET_EXAM("入团题库"),
//入团申请表
JOIN_Association("入团申请表")
}
/**
* 题型
*
*/
enum class ExamType(val type:String){
//选择题
cq("选择题"),
CQ("选择题"),
//开放题
oq("开放题")
OQ("开放题")
}
sealed class Exam{
@ -30,7 +41,7 @@ sealed class Exam{
* @property question 问题
*/
data class OpenQuestionsVo(
override val examType: ExamType = ExamType.oq, override val question: StringForm
override val examType: ExamType = ExamType.OQ, override val question: StringForm
) : Exam()
@ -42,7 +53,7 @@ data class OpenQuestionsVo(
* @property rightAnswer 正确答案
* @property question 问题
*/
data class ChoiceQuestionVo(override val examType: ExamType = ExamType.cq,
data class ChoiceQuestionVo(override val examType: ExamType = ExamType.CQ,
val answers:List<StringForm>,
val rightAnswer:Int,
override val question: StringForm
@ -77,8 +88,8 @@ class ExamViewModel:ScrollList<Exam>() {
val questionIsNull: String = "问题不能为空"
val deleteLeastOne: String="至少保留一道题目"
val updateExam="更新题库"
val postAnswer="提交答案"
val back="返回"
val menuName="入团题库"
val deleteTip="确定删除此题目?"
val addTip="确定添加此题目?"
val actionLabel="确定"
@ -87,7 +98,7 @@ class ExamViewModel:ScrollList<Exam>() {
override val initSize = 10
private val _newExam:MutableLiveData<Exam> = MutableLiveData(createExam(ExamType.cq))
private val _newExam:MutableLiveData<Exam> = MutableLiveData(createExam(ExamType.CQ))
val newExam:LiveData<Exam> = _newExam
init {
@ -99,7 +110,7 @@ class ExamViewModel:ScrollList<Exam>() {
*
*/
fun switchType(exam: Exam){
if(exam is ChoiceQuestionVo) _newExam.value=createExam(ExamType.oq) else _newExam.value=createExam(ExamType.cq)
if(exam is ChoiceQuestionVo) _newExam.value=createExam(ExamType.OQ) else _newExam.value=createExam(ExamType.CQ)
}
@ -112,12 +123,12 @@ class ExamViewModel:ScrollList<Exam>() {
private fun createExam(type: ExamType): Exam {
val question=StringForm(formDesc = "问题",textLength = QUESTION_TEXT_LENGTH)
return when(type){
ExamType.cq-> ChoiceQuestionVo(
ExamType.CQ-> ChoiceQuestionVo(
answers = ('A'..'D').map { StringForm(formDesc = "选项",textLength = ANSWER_TEXT_LENGTH,value = "选项$it") },
rightAnswer = 0,
question = question
)
ExamType.oq-> OpenQuestionsVo(question = question)
ExamType.OQ-> OpenQuestionsVo(question = question)
}
}
@ -147,7 +158,15 @@ class ExamViewModel:ScrollList<Exam>() {
*/
fun updateExam(callback: (message: String) -> Unit){
callback("功能尚未实现,敬请期待")
}
/**
* TODO 提交答案
*
* @param callback
*/
fun postAnswer(callback: (message: String) -> Unit){
callback("功能尚未实现,敬请期待")
}
/**
@ -208,7 +227,7 @@ class ExamViewModel:ScrollList<Exam>() {
list.add(it)
_data.postValue(list)
}
_newExam.value=createExam(ExamType.cq)
_newExam.value=createExam(ExamType.CQ)
}
}

@ -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
@ -18,7 +19,9 @@ import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.DpOffset
import androidx.compose.ui.unit.dp
import androidx.compose.ui.window.PopupProperties
import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable
@ -26,6 +29,7 @@ import com.gyf.csams.R
import com.gyf.csams.association.model.*
import com.gyf.csams.uikit.*
import com.gyf.csams.uikit.theme.CSAMSTheme
import com.orhanobut.logger.Logger
/**
* 社团界面
@ -42,11 +46,74 @@ class AssociationActivity: ComponentActivity() {
val model:AssociationViewModel= viewModel()
val startMenu=AssociationMenu.main
val menu:AssociationMenu by model.currentMenu.observeAsState(startMenu)
val intent=Intent(context,ExamActivity::class.java)
val expanded by model.expanded.observeAsState(false)
Column {
AssociationAppBar(menu = menu,nav = nav,back = { context.onBackPressed() }){
//TODO 显示下拉菜单
Logger.i("expanded=$expanded")
AssociationAppBar(menu = menu,nav = nav,back = { context.onBackPressed() },dropMenu = {model.switchType()}){
Row{
DropdownMenu(expanded = expanded,
onDismissRequest = { /*TODO*/ },
offset = DpOffset.Zero.copy(x=50.dp),
properties = PopupProperties()
) {
DropdownMenuItem(onClick = {
model.close()
}) {
Row(verticalAlignment = Alignment.CenterVertically){
Text(text = "申请活动")
Icon(painter = painterResource(id = R.drawable.ic_add_fill), contentDescription = null)
}
}
DropdownMenuItem(onClick = {
intent.apply {
putExtra(ExamActivityType::name.name, ExamActivityType.SET_EXAM)
}
context.startActivity(intent)
model.close()
}) {
Row(verticalAlignment = Alignment.CenterVertically) {
Text(text = "设置题库")
Icon(painter = painterResource(id = R.drawable.ic_editor), contentDescription = null)
}
}
DropdownMenuItem(onClick = {
context.startActivity(Intent(context,ReNameActivity::class.java))
model.close()
}) {
Row(verticalAlignment = Alignment.CenterVertically) {
Text(text = "社团命名")
Icon(painter = painterResource(id = R.drawable.ic_exchange_rate), contentDescription = null)
}
}
DropdownMenuItem(onClick = {
intent.apply {
putExtra(ExamActivityType::name.name, ExamActivityType.JOIN_Association)
}
context.startActivity(intent)
model.close()
}) {
Row(verticalAlignment = Alignment.CenterVertically) {
Text(text = "申请入团")
Icon(painter = painterResource(id = R.drawable.ic_add_account), contentDescription = null)
}
}
DropdownMenuItem(onClick = {
model.close()
}) {
Row(verticalAlignment = Alignment.CenterVertically) {
Icon(painter = painterResource(id = R.drawable.ic_arrow_up), contentDescription = null,
modifier = Modifier
.height(30.dp)
.fillMaxWidth())
}
}
}
}
}
NavHost(navController = nav, startDestination = startMenu.name) {
composable(AssociationMenu.member.name){
model.clickMenu(AssociationMenu.member)

@ -22,13 +22,21 @@ import com.gyf.csams.R
import com.gyf.csams.association.model.*
import com.gyf.csams.uikit.*
/**
* 题库管理
*
*/
class ExamActivity : ComponentActivity() {
lateinit var activityType:ExamActivityType
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
activityType=intent?.getSerializableExtra(ExamActivityType::name.name) as ExamActivityType
setContent {
Body { scaffoldState ->
MainFrame(background = { Background(image = BackgroundImage.exam) }) {
@ -42,6 +50,8 @@ class ExamActivity : ComponentActivity() {
}
}
/**
* 底部按钮
*
@ -53,12 +63,21 @@ private fun BottomButton(
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)
when(context.activityType){
ExamActivityType.SET_EXAM->OutlinedButton(onClick = {
model.updateExam { scaffoldModel.update(message=it) }
}, modifier = Modifier.background(color = MaterialTheme.colors.primary)) {
Text(text = model.updateExam)
}
ExamActivityType.JOIN_Association->OutlinedButton(onClick = {
model.postAnswer { scaffoldModel.update(message=it) }
}, modifier = Modifier.background(color = MaterialTheme.colors.primary)) {
Text(text = model.postAnswer)
}
}
Spacer(modifier = Modifier.width(10.dp))
OutlinedButton(onClick = {
context.onBackPressed()
@ -72,12 +91,12 @@ private fun BottomButton(
* 标题
*
* @param modifier
* @param model
*/
@Composable
private fun Title(modifier: Modifier = Modifier, model: ExamViewModel = viewModel()) {
private fun Title(modifier: Modifier = Modifier) {
val context= LocalContext.current as ExamActivity
Row(horizontalArrangement = Arrangement.Center, modifier = modifier.fillMaxWidth()) {
Text(text = model.menuName, style = MaterialTheme.typography.h4)
Text(text = context.activityType.menuName, style = MaterialTheme.typography.h4)
}
}
@ -223,18 +242,23 @@ private fun ExamOQ(
isAdd: Boolean = false
) {
Row(modifier = modifier) {
val context= LocalContext.current as ExamActivity
Question(
exam = openQuestionsVo, modifier = Modifier
.weight(0.8F)
.fillMaxHeight()
)
ActionButton(
modifier = Modifier
.weight(0.2F)
.fillMaxHeight(),
isAdd = isAdd,
exam = openQuestionsVo
exam = openQuestionsVo, modifier =
if(context.activityType==ExamActivityType.SET_EXAM)
Modifier.weight(0.8F).fillMaxHeight()
else
Modifier
)
if(context.activityType==ExamActivityType.SET_EXAM){
ActionButton(
modifier = Modifier
.weight(0.2F)
.fillMaxHeight(),
isAdd = isAdd,
exam = openQuestionsVo
)
}
}
}
@ -252,10 +276,12 @@ private fun ExamCQ(
questionWeight:Float
) {
Row(modifier = modifier) {
val context= LocalContext.current as ExamActivity
Column(
modifier = Modifier
.weight(0.8F)
.fillMaxHeight()
modifier = if(context.activityType==ExamActivityType.SET_EXAM)
Modifier.weight(0.8F).fillMaxHeight()
else
Modifier
) {
Question(
exam = choiceQuestionVo,
@ -294,13 +320,15 @@ private fun ExamCQ(
}
}
ActionButton(
modifier = Modifier
.weight(0.2F)
.fillMaxHeight(),
isAdd = isAdd,
exam = choiceQuestionVo
)
if(context.activityType==ExamActivityType.SET_EXAM) {
ActionButton(
modifier = Modifier
.weight(0.2F)
.fillMaxHeight(),
isAdd = isAdd,
exam = choiceQuestionVo
)
}
}
}

@ -148,45 +148,47 @@ fun AssociationAppBar(
menu: AssociationMenu,
nav: NavHostController,
back: () -> Unit,
dropMenu: () -> Unit
dropMenu: () -> Unit,
content:@Composable () -> Unit
) {
TopAppBar(backgroundColor = MaterialTheme.colors.secondary) {
Row(modifier = Modifier.fillMaxWidth(), verticalAlignment = Alignment.CenterVertically) {
IconButton(onClick = back, modifier = Modifier.weight(0.1F)) {
Icon(
painter = painterResource(id = R.drawable.ic_arrow_left),
contentDescription = null
)
}
Row(
modifier = Modifier
.weight(0.8F)
.fillMaxHeight(),
horizontalArrangement = Arrangement.Center,
verticalAlignment = Alignment.CenterVertically
) {
val menus = AssociationMenu.values()
menus.forEach {
Row(
modifier = Modifier
.weight(1F / menus.size)
.clickable(onClick = { nav.navigate(it.name) }),
horizontalArrangement = Arrangement.Center
) {
Text(
text = it.menuName,
color = if (menu == it) MaterialTheme.colors.primary else MaterialTheme.colors.onBackground
)
Row(modifier = Modifier.fillMaxWidth(), verticalAlignment = Alignment.CenterVertically) {
IconButton(onClick = back, modifier = Modifier.weight(0.1F)) {
Icon(
painter = painterResource(id = R.drawable.ic_arrow_left),
contentDescription = null
)
}
Row(
modifier = Modifier
.weight(0.8F)
.fillMaxHeight(),
horizontalArrangement = Arrangement.Center,
verticalAlignment = Alignment.CenterVertically
) {
val menus = AssociationMenu.values()
menus.forEach {
Row(
modifier = Modifier
.weight(1F / menus.size)
.clickable(onClick = { nav.navigate(it.name) }),
horizontalArrangement = Arrangement.Center
) {
Text(
text = it.menuName,
color = if (menu == it) MaterialTheme.colors.primary else MaterialTheme.colors.onBackground
)
}
}
}
IconButton(onClick = dropMenu, modifier = Modifier.weight(0.1F)) {
Icon(
painter = painterResource(id = R.drawable.ic_configuration),
contentDescription = null
)
}
}
IconButton(onClick = dropMenu, modifier = Modifier.weight(0.1F)) {
Icon(
painter = painterResource(id = R.drawable.ic_configuration),
contentDescription = null
)
}
}
content()
}
}

@ -100,9 +100,9 @@ class ExamDeserializer:JsonDeserializer<Exam>{
val type=root?.get("examType")?.asString
return when (gson.fromJson(type, ExamType::class.java)) {
ExamType.cq -> gson.fromJson(json,
ExamType.CQ -> gson.fromJson(json,
object : TypeToken<ChoiceQuestionVo>() {}.type)
ExamType.oq -> gson.fromJson(json,
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="M605.03,597.97l24.28,28.33L629.33,682.67h-85.82v149.33L629.33,832l-0.15,42.67L213.33,874.67a64,64 0,0 1,-48.6 -105.64l146.6,-171.05A276.05,276.05 0,0 0,458.18 640a276.05,276.05 0,0 0,146.86 -42.03zM735.51,640v85.33h85.33v64h-85.33v85.33h-64v-85.33h-85.33v-64h85.33v-85.33h64zM458.18,149.33c117.82,0 213.33,95.51 213.33,213.33s-95.51,213.33 -213.33,213.33 -213.33,-95.51 -213.33,-213.33 95.51,-213.33 213.33,-213.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="M500.8,461.91L267.31,695.3l-45.23,-45.27 278.74,-278.61L779.31,650.03l-45.25,45.23z"/>
</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="M694.04,213.33v64L234.67,277.33v469.33h512L746.67,512h64v234.67a64,64 0,0 1,-64 64L234.67,810.67a64,64 0,0 1,-64 -64L170.67,277.33a64,64 0,0 1,64 -64h459.37zM830.78,237.57l45.1,45.4 -343.72,341.29 0.13,0.13 -46.59,1.58 1.32,-47.27 0.09,0.11 343.68,-341.23z"/>
</vector>
Loading…
Cancel
Save