社团主界面设置下拉菜单

题库界面拆分为入团申请表和入团题库
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 import kotlinx.coroutines.launch
class AssociationViewModel:ViewModel() { class AssociationViewModel:ViewModel() {
/**
* 当前菜单
*/
private val _currentMenu=MutableLiveData<AssociationMenu>() private val _currentMenu=MutableLiveData<AssociationMenu>()
val currentMenu:LiveData<AssociationMenu> = _currentMenu val currentMenu:LiveData<AssociationMenu> = _currentMenu
/**
* 下拉菜单状态
*/
private val _expanded=MutableLiveData(false)
val expanded:LiveData<Boolean> = _expanded
/**
* 切换顶部菜单
*
* @param menu
*/
fun clickMenu(menu:AssociationMenu){ fun clickMenu(menu:AssociationMenu){
_currentMenu.value=menu _currentMenu.value=menu
} }
/**
* 切换下拉菜单状态
*
*/
fun switchType(){
_expanded.value?.let {
_expanded.value = !it
}
}
fun close(){
_expanded.value=false
}
} }
data class MemberVo(val name:String) data class MemberVo(val name:String)

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

@ -1,5 +1,6 @@
package com.gyf.csams.association.ui package com.gyf.csams.association.ui
import android.content.Intent
import android.os.Bundle import android.os.Bundle
import androidx.activity.ComponentActivity import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent 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.platform.LocalContext
import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.painterResource
import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.DpOffset
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.window.PopupProperties
import androidx.lifecycle.viewmodel.compose.viewModel import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.navigation.compose.NavHost import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable import androidx.navigation.compose.composable
@ -26,6 +29,7 @@ import com.gyf.csams.R
import com.gyf.csams.association.model.* import com.gyf.csams.association.model.*
import com.gyf.csams.uikit.* import com.gyf.csams.uikit.*
import com.gyf.csams.uikit.theme.CSAMSTheme import com.gyf.csams.uikit.theme.CSAMSTheme
import com.orhanobut.logger.Logger
/** /**
* 社团界面 * 社团界面
@ -42,11 +46,74 @@ class AssociationActivity: ComponentActivity() {
val model:AssociationViewModel= viewModel() val model:AssociationViewModel= viewModel()
val startMenu=AssociationMenu.main val startMenu=AssociationMenu.main
val menu:AssociationMenu by model.currentMenu.observeAsState(startMenu) val menu:AssociationMenu by model.currentMenu.observeAsState(startMenu)
val intent=Intent(context,ExamActivity::class.java)
val expanded by model.expanded.observeAsState(false)
Column { Column {
AssociationAppBar(menu = menu,nav = nav,back = { context.onBackPressed() }){ Logger.i("expanded=$expanded")
//TODO 显示下拉菜单 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) { NavHost(navController = nav, startDestination = startMenu.name) {
composable(AssociationMenu.member.name){ composable(AssociationMenu.member.name){
model.clickMenu(AssociationMenu.member) model.clickMenu(AssociationMenu.member)

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

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

@ -100,9 +100,9 @@ class ExamDeserializer:JsonDeserializer<Exam>{
val type=root?.get("examType")?.asString val type=root?.get("examType")?.asString
return when (gson.fromJson(type, ExamType::class.java)) { return when (gson.fromJson(type, ExamType::class.java)) {
ExamType.cq -> gson.fromJson(json, ExamType.CQ -> gson.fromJson(json,
object : TypeToken<ChoiceQuestionVo>() {}.type) object : TypeToken<ChoiceQuestionVo>() {}.type)
ExamType.oq -> gson.fromJson(json, ExamType.OQ -> gson.fromJson(json,
object : TypeToken<OpenQuestionsVo>() {}.type) object : TypeToken<OpenQuestionsVo>() {}.type)
null->throw NullPointerException("无法识别题目类型!") 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