增加活动详情界面

master
pan 4 years ago
parent 31e1d9fd92
commit 4ee124d927
  1. 2
      app/src/androidTest/java/com/gyf/csams/ExampleInstrumentedTest.kt
  2. 9
      app/src/androidTest/java/com/gyf/csams/MainActivityTest.kt
  3. 5
      app/src/main/AndroidManifest.xml
  4. 13
      app/src/main/java/com/gyf/csams/Api.kt
  5. 29
      app/src/main/java/com/gyf/csams/InitActivity.kt
  6. 290
      app/src/main/java/com/gyf/csams/activity/model/ActivityDetailViewModel.kt
  7. 491
      app/src/main/java/com/gyf/csams/activity/ui/ActivityDetailActivity.kt
  8. 34
      app/src/main/java/com/gyf/csams/association/model/AssociationViewModel.kt
  9. 7
      app/src/main/java/com/gyf/csams/association/model/ExamViewModel.kt
  10. 3
      app/src/main/java/com/gyf/csams/association/model/RegAssociationViewModel.kt
  11. 3
      app/src/main/java/com/gyf/csams/association/model/RenameViewModel.kt
  12. 446
      app/src/main/java/com/gyf/csams/association/ui/AssociationActivity.kt
  13. 469
      app/src/main/java/com/gyf/csams/association/ui/ExamActivity.kt
  14. 110
      app/src/main/java/com/gyf/csams/association/ui/ReNameActivity.kt
  15. 220
      app/src/main/java/com/gyf/csams/association/ui/RegAssociationActivity.kt
  16. 7
      app/src/main/java/com/gyf/csams/main/model/MainViewModel.kt
  17. 520
      app/src/main/java/com/gyf/csams/main/ui/MainActivity.kt
  18. 258
      app/src/main/java/com/gyf/csams/uikit/BaseView.kt
  19. 55
      app/src/main/java/com/gyf/csams/util/RandomUtil.kt
  20. 9
      app/src/main/res/drawable/ic_upload.xml
  21. 15
      app/src/test/java/com/gyf/csams/ExampleUnitTest.kt

@ -18,7 +18,5 @@ class ExampleInstrumentedTest {
// Context of the app under test. // Context of the app under test.
val appContext = InstrumentationRegistry.getInstrumentation().targetContext val appContext = InstrumentationRegistry.getInstrumentation().targetContext
assertEquals("com.gyf.csams", appContext.packageName) assertEquals("com.gyf.csams", appContext.packageName)
} }
} }

@ -0,0 +1,9 @@
package com.gyf.csams
import androidx.test.ext.junit.runners.AndroidJUnit4
import org.junit.runner.RunWith
@RunWith(AndroidJUnit4::class)
class MainActivityTest {
}

@ -62,6 +62,11 @@
<activity android:name=".association.ui.ExamActivity" <activity android:name=".association.ui.ExamActivity"
android:exported="true"> android:exported="true">
</activity> </activity>
<!--活动详情-->
<activity android:name=".activity.ui.ActivityDetailActivity"
android:exported="true">
</activity>
</application> </application>
</manifest> </manifest>

@ -5,6 +5,11 @@ interface UrlPath{
fun build():String fun build():String
} }
/**
* 帐号接口
*
* @property path
*/
enum class AccountApi(val path: String):UrlPath{ enum class AccountApi(val path: String):UrlPath{
register("/register"), register("/register"),
checkId("/register/checkId"), checkId("/register/checkId"),
@ -17,7 +22,10 @@ enum class AccountApi(val path: String):UrlPath{
} }
} }
/**
* 构建服务端请求接口地址
*
*/
class Api { class Api {
companion object{ companion object{
fun buildUrl(urlPath: UrlPath):String{ fun buildUrl(urlPath: UrlPath):String{
@ -26,3 +34,6 @@ class Api {
} }
} }
const val NOT_IMPL_TIP="功能尚未实现!"

@ -37,20 +37,21 @@ class InitActivity : ComponentActivity() {
} }
} }
} }
}
@Composable
private fun Init(initViewModel:InitViewModel= viewModel()){
Logger.i("初始化。。。。")
val context= LocalContext.current
//后台检查token
initViewModel.hasOnlyUserToken(context)
//监听token校验状态
val isValid: Boolean? by initViewModel.token.observeAsState(null)
when (isValid) {
false -> context.startActivity(Intent(context, AccountActivity::class.java))
true -> context.startActivity(Intent(context, MainActivity::class.java))
}
@Composable
private fun Init(initViewModel:InitViewModel= viewModel()){
Logger.i("初始化。。。。")
val context= LocalContext.current
//后台检查token
initViewModel.hasOnlyUserToken(context)
//监听token校验状态
val isValid: Boolean? by initViewModel.token.observeAsState(null)
when (isValid) {
false -> context.startActivity(Intent(context, AccountActivity::class.java))
true -> context.startActivity(Intent(context, MainActivity::class.java))
}
}
} }

@ -0,0 +1,290 @@
package com.gyf.csams.activity.model
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.gyf.csams.NOT_IMPL_TIP
import com.gyf.csams.uikit.ActivityDetailMenu
import com.gyf.csams.uikit.ScrollList
import com.gyf.csams.uikit.StringForm
import com.gyf.csams.uikit.TopMenuInterface
import com.gyf.csams.util.randomChinese
import com.gyf.csams.util.randomDateTime
import com.gyf.csams.util.randomNum
import com.orhanobut.logger.Logger
import kotlinx.coroutines.launch
import java.util.*
/**
* 活动详情菜单通用状态
*
*/
class ActivityDetailViewModel:ViewModel(), TopMenuInterface<ActivityDetailMenu> {
override val _currentMenu: MutableLiveData<ActivityDetailMenu> = MutableLiveData()
override val currentMenu: LiveData<ActivityDetailMenu> = _currentMenu
}
/**
* TODO
*
* @property associationName 社团名字
* @property activityName 活动名
* @property activityTime 活动时间
* @property activityLocation 活动地点
* @property activityDesc 活动介绍
*/
data class ActivityDetailVo(val associationName:String,val activityName:String,
val activityTime:Date,val activityLocation:String,
val activityDesc:String)
/**
* 活动信息
*
*/
class ActivityInfoViewModel:ViewModel(){
private val _activityDetailVo=MutableLiveData<ActivityDetailVo>()
val activityDetailVo:LiveData<ActivityDetailVo> = _activityDetailVo
val like = "点赞"
val collect="收藏"
init {
loadInfo()
}
/**
* TODO 点赞
*
* @param callback
*/
fun like(callback:(message:String)->Unit){
callback(NOT_IMPL_TIP)
}
/**
* TODO 收藏
*
* @param callback
*/
fun collect(callback:(message:String)->Unit){
callback(NOT_IMPL_TIP)
}
private fun loadInfo(){
viewModelScope.launch {
_activityDetailVo.value = ActivityDetailVo(
activityName = randomChinese(4),
associationName = randomChinese(4),
activityTime = randomDateTime(),
activityLocation = randomChinese(3),
activityDesc = randomChinese(500)
)
}
}
}
/**
* 图片
* @property name 文件名
* @property size 文件大小
* @property url 文件路径
* @property md5 文件hash
* @property createTime 文件创建时间
* @property studentId 文件上传人
*/
data class ActivityPhotoVo(val name:String, val size:Long, val url:String, val md5:String, val createTime: Date, val studentId:String)
/**
* 活动相册数据状态管理
*
*/
class ActivityPhotoViewModel:ScrollList<ActivityPhotoVo>(){
override val initSize: Int = 10
init {
load()
}
fun upload(callback: (message: String) -> Unit){
callback(NOT_IMPL_TIP)
}
/**
* TODO 加载相册
*
*/
override fun load() {
viewModelScope.launch {
_data.value?.apply {
repeat(initSize){
add(ActivityPhotoVo(name=randomChinese(3),
size= randomNum(3).toLong(),
url="",
md5 = "",
createTime = randomDateTime(),
studentId = ""))
}
}
}
}
/**
* TODO 加载更多相册
*
* @param callback
*/
override fun loadMore(callback: (message: String) -> Unit) {
Logger.i("加载更多")
viewModelScope.launch {
_data.value?.apply {
val list= mutableListOf<ActivityPhotoVo>()
list.addAll(this)
repeat(initSize){
add(ActivityPhotoVo(name=randomChinese(3),
size= randomNum(3).toLong(),
url="",
md5 = "",
createTime = randomDateTime(),
studentId = ""))
}
_data.postValue(list)
callback("成功加载更多相册")
}
}
}
}
data class ActivityMemberVo(val studentId: String,val name:String)
data class ActivityMembersVo(val organizer:ActivityMemberVo, val participant:MutableList<ActivityMemberVo>?)
class ActivityMemberViewModel:ScrollList<ActivityMemberVo>(){
override val initSize: Int = 10
private val _allMember=MutableLiveData<ActivityMembersVo>()
val allMember:LiveData<ActivityMembersVo> = _allMember
init {
load()
}
/**
* TODO 加载活动成员
*
*/
override fun load() {
viewModelScope.launch {
_data.value?.apply {
repeat(initSize){
add(ActivityMemberVo(studentId = randomNum(),name = randomChinese(3)))
}
_allMember.value= ActivityMembersVo(organizer = ActivityMemberVo(studentId = randomNum(),name = randomChinese(3)),participant = _data.value)
}
}
}
/**
* TODO 加载更多活动成员
*
* @param callback
*/
override fun loadMore(callback: (message: String) -> Unit) {
viewModelScope.launch {
_data.value?.apply {
val list= mutableListOf<ActivityMemberVo>()
list.addAll(this)
repeat(initSize){
add(ActivityMemberVo(studentId = randomNum(),name = randomChinese(3)))
}
_allMember.value?.apply {
_data.postValue(list)
_allMember.postValue(ActivityMembersVo(organizer=organizer,participant=list))
callback("成功加载更多活动参与者")
}
}
}
}
}
data class BBSVo(val studentId:String,val name:String,val createTime:Date,val content:String)
/**
* 交流区数据状态管理
*
*/
class BBSViewModel:ScrollList<BBSVo>(){
override val initSize: Int = 10
val title="发送评论"
val newContent = StringForm(formDesc = "评论内容",textLength = 80)
private val _openDialog=MutableLiveData<Boolean>()
val openDialog:LiveData<Boolean> = _openDialog
init {
load()
}
/**
* 打开评论弹窗
*
*/
fun openDialog(){
_openDialog.value=true
}
fun closeDialog(){
_openDialog.value=false
}
/**
* TODO 发送评论
*
* @param callback
*/
fun send(callback: (message: String) -> Unit){
callback(NOT_IMPL_TIP)
}
/**
* TODO 加载评论
*
*/
override fun load() {
viewModelScope.launch {
_data.value?.apply {
repeat(initSize){
add(BBSVo(studentId = randomNum(),createTime = randomDateTime(),content = randomChinese(50),name = randomChinese(3)))
}
}
}
}
/**
* TODO 加载更多评论
*
* @param callback
*/
override fun loadMore(callback: (message: String) -> Unit) {
viewModelScope.launch {
_data.value?.apply {
repeat(initSize){
val list= mutableListOf<BBSVo>()
list.addAll(this)
repeat(initSize){
add(BBSVo(studentId = randomNum(),name = randomChinese(3),createTime = randomDateTime(),content = randomChinese(50)))
}
_data.postValue(list)
callback("成功加载更多评论")
}
}
}
}
}

@ -0,0 +1,491 @@
package com.gyf.csams.activity.ui
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.Canvas
import androidx.compose.foundation.Image
import androidx.compose.foundation.border
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.res.painterResource
import androidx.compose.ui.unit.dp
import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable
import com.gyf.csams.R
import com.gyf.csams.activity.model.*
import com.gyf.csams.uikit.*
import com.gyf.csams.util.format
/**
* 活动详情
*
*/
class ActivityDetailActivity : ComponentActivity() {
@ExperimentalMaterialApi
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
Body { nav, scaffoldState ->
val model: ActivityDetailViewModel = viewModel()
val currentMenuName by model.currentMenu.observeAsState(ActivityDetailMenu.startMenu)
Column {
TextTopAppBar(
nav = nav,
currentMenuName = currentMenuName.menuName,
menuNames = ActivityDetailMenu.values()
)
NavHost(
navController = nav,
startDestination = ActivityDetailMenu.startMenu.name
) {
composable(ActivityDetailMenu.Info.name) {
Info()
ShowSnackbar(scaffoldState = scaffoldState)
model.clickMenu(ActivityDetailMenu.Info)
}
composable(ActivityDetailMenu.Photo.name) {
Photo()
ShowSnackbar(scaffoldState = scaffoldState)
model.clickMenu(ActivityDetailMenu.Photo)
}
composable(ActivityDetailMenu.Member.name) {
Member()
ShowSnackbar(scaffoldState = scaffoldState)
model.clickMenu(ActivityDetailMenu.Member)
}
composable(ActivityDetailMenu.BBS.name) {
BBS()
ShowSnackbar(scaffoldState = scaffoldState)
model.clickMenu(ActivityDetailMenu.BBS)
}
}
}
}
}
}
/**
* 底部按钮
*
* @param modifier
*/
@Composable
private fun BottomButton(
modifier: Modifier = Modifier,
model: ActivityInfoViewModel = viewModel(),
scaffoldModel: ScaffoldModel = viewModel()
) {
Row(modifier = modifier.fillMaxWidth(), horizontalArrangement = Arrangement.SpaceEvenly) {
OutlinedButton(onClick = { model.like { scaffoldModel.update(message = it) } }) {
Text(text = model.like)
}
OutlinedButton(onClick = { model.collect { scaffoldModel.update(message = it) } }) {
Text(text = model.collect)
}
}
}
/**
* 活动信息
*
*/
@Composable
private fun Info() {
MainFrame(background = { Background(image = BackgroundImage.ActivityInfo, alpha = 0.7F) }) {
RectList(modifier = Modifier.weight(0.4F))
ActivityDesc(modifier = Modifier.weight(0.4F))
Spacer(modifier = Modifier.weight(0.05F))
BottomButton()
Spacer(modifier = Modifier.weight(0.05F))
}
}
/**
* 活动基础信息
*
*/
@Composable
private fun RectList(
modifier: Modifier = Modifier,
model: ActivityInfoViewModel = viewModel()
) {
val activityDetailVo by model.activityDetailVo.observeAsState()
activityDetailVo?.let {
Card(modifier = modifier, backgroundColor = MaterialTheme.colors.background) {
Column(
modifier = Modifier.fillMaxSize(),
verticalArrangement = Arrangement.SpaceAround
) {
RectListItem(text = it.associationName)
RectListItem(text = it.activityName)
RectListItem(text = it.activityTime.format())
RectListItem(text = it.activityLocation)
}
}
}
}
/**
* 列表项
*
* @param text
*/
@Composable
private fun RectListItem(text: String) {
Row(modifier = Modifier.fillMaxWidth()) {
val color = MaterialTheme.colors.secondaryVariant
val canvasSize = 30.dp
Box(modifier = Modifier.weight(0.5F), contentAlignment = Alignment.Center) {
Canvas(modifier = Modifier.size(canvasSize)) {
drawCircle(color = color)
}
}
Text(text = text, style = MaterialTheme.typography.h5, modifier = Modifier.weight(0.5F))
}
}
/**
* 活动介绍
*
* @param modifier
* @param model
*/
@Composable
private fun ActivityDesc(
modifier: Modifier = Modifier,
model: ActivityInfoViewModel = viewModel()
) {
Column(modifier = modifier) {
val activityDetailVo by model.activityDetailVo.observeAsState()
activityDetailVo?.let {
DescCard(modifier = Modifier.weight(0.5F), content = it.activityDesc)
}
}
}
/**
* 相册
*
*/
@Composable
private fun Photo(
model: ActivityPhotoViewModel = viewModel(),
scaffoldModel: ScaffoldModel = viewModel()
) {
MainFrame(background = {
Background(
image = BackgroundImage.ActivityPhoto,
alpha = 0.7F
)
}) {
Row(modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.End) {
IconButton(onClick = { model.upload { scaffoldModel.update(message = it) } }) {
Icon(
painter = painterResource(id = R.drawable.ic_upload),
contentDescription = null
)
}
}
Spacer(modifier = Modifier.height(10.dp))
Box(
modifier = Modifier
.fillMaxSize()
.padding(10.dp)
.border(
width = 1.dp,
color = MaterialTheme.colors.background
)
) {
val listState = rememberLazyListState()
val photos by model.data.observeAsState()
photos?.let {
LazyColumn(state = listState) {
it.chunked(2).forEach {
item {
Spacer(modifier = Modifier.height(20.dp))
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceEvenly
) {
Spacer(modifier = Modifier.weight(0.05F))
PhotoItem(vo = it[0], modifier = Modifier.weight(0.4F))
Spacer(modifier = Modifier.weight(0.1F))
if (it.size == 2) {
PhotoItem(vo = it[1], modifier = Modifier.weight(0.4F))
} else {
Spacer(modifier = Modifier.weight(0.4F))
}
Spacer(modifier = Modifier.weight(0.05F))
}
Spacer(modifier = Modifier.height(20.dp))
}
}
}
// Logger.i("totalItemsCount=${listState.layoutInfo.totalItemsCount},firstVisibleItemIndex=${listState.firstVisibleItemIndex}")
if (listState.layoutInfo.totalItemsCount - listState.firstVisibleItemIndex == model.initSize / 2 - 1) {
model.loadMore { scaffoldModel.update(message = it) }
}
}
}
}
}
@Composable
private fun PhotoItem(modifier: Modifier = Modifier, vo: ActivityPhotoVo) {
Box(
modifier = modifier.border(width = 1.dp, color = MaterialTheme.colors.background),
contentAlignment = Alignment.Center
) {
Image(
painter = painterResource(id = R.drawable.ic_launcher_foreground),
contentDescription = null,
)
}
}
/**
* 活动成员
*
*/
@Composable
private fun Member(
model: ActivityMemberViewModel = viewModel(),
scaffoldModel: ScaffoldModel = viewModel()
) {
MainFrame(background = {
Background(
image = BackgroundImage.ActivityMember,
alpha = 0.7F
)
}) {
val data by model.allMember.observeAsState()
data?.apply {
Spacer(modifier = Modifier.height(5.dp))
Row(
modifier = Modifier
.fillMaxWidth()
.weight(0.2F), horizontalArrangement = Arrangement.Center
) {
Box(contentAlignment = Alignment.Center) {
Image(
painter = painterResource(id = R.drawable.persion_name_border),
contentDescription = null
)
Text(text = organizer.name)
}
}
Spacer(modifier = Modifier.height(5.dp))
Box(
modifier = Modifier
.fillMaxWidth()
.weight(0.8F)
.padding(10.dp)
.border(width = 1.dp, color = MaterialTheme.colors.background)
) {
val listState = rememberLazyListState()
participant?.let {
LazyColumn(state = listState) {
it.chunked(2).forEach {
item {
Spacer(modifier = Modifier.height(10.dp))
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceEvenly
) {
Spacer(modifier = Modifier.weight(0.05F))
Participant(vo = it[0], modifier = Modifier.weight(0.4F))
Spacer(modifier = Modifier.weight(0.1F))
if (it.size == 2) {
Participant(
vo = it[1],
modifier = Modifier.weight(0.4F)
)
} else {
Spacer(modifier = Modifier.weight(0.4F))
}
Spacer(modifier = Modifier.weight(0.05F))
}
Spacer(modifier = Modifier.height(10.dp))
}
}
}
// Logger.i("totalItemsCount=${listState.layoutInfo.totalItemsCount},firstVisibleItemIndex=${listState.firstVisibleItemIndex}")
if (listState.layoutInfo.totalItemsCount - listState.firstVisibleItemIndex == model.initSize / 2 - 1) {
model.loadMore { scaffoldModel.update(message = it) }
}
}
}
}
}
}
@Composable
private fun Participant(modifier: Modifier = Modifier, vo: ActivityMemberVo) {
Box(modifier = modifier, contentAlignment = Alignment.Center) {
Image(
painter = painterResource(id = R.drawable.participant_border),
contentDescription = null,
// contentScale = ContentScale.FillBounds,
// modifier = Modifier.fillMaxSize()
)
Text(text = vo.name)
}
}
/**
* 交流区
*
*/
@ExperimentalMaterialApi
@Composable
private fun BBS(model: BBSViewModel = viewModel(), scaffoldModel: ScaffoldModel = viewModel()) {
MainFrame(background = { Background(image = BackgroundImage.ActivityBBS, alpha = 0.7F) }) {
// val drawerState = rememberBottomDrawerState(BottomDrawerValue.Closed)
val openDialog=model.openDialog.observeAsState()
Row(
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = 10.dp),
horizontalArrangement = Arrangement.End,
verticalAlignment = Alignment.CenterVertically
) {
// IconToggleButton(checked = false, onCheckedChange = { /*TODO*/ }) {
// Row(horizontalArrangement = Arrangement.SpaceEvenly) {
// Icon(painter = painterResource(id = R.drawable.ic_configuration), contentDescription = null)
// }
// }
// Text(text = "")
IconButton(onClick = { model.openDialog() }) {
Icon(
painter = painterResource(id = R.drawable.ic_editor),
contentDescription = null
)
}
}
if(openDialog.value ==true) {
AlertDialog(onDismissRequest = { /*TODO*/ },
buttons = {
Row(
modifier = Modifier
.padding(10.dp)
.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceEvenly
) {
OutlinedButton(onClick = {
model.send { scaffoldModel.update(message = it) }
}) {
Text(text = "发送")
}
OutlinedButton(onClick = {
model.closeDialog()
}) {
Text(text = "关闭")
}
}
}, text = {
Column(modifier = Modifier.padding(10.dp)) {
Card(
backgroundColor = MaterialTheme.colors.background,
modifier = Modifier.padding(10.dp)
) {
BaseTextField(
form = model.newContent, modifier = Modifier
.fillMaxWidth()
.height(200.dp)
)
}
}
})
}
Box(
modifier = Modifier
.weight(0.9F)
.padding(10.dp)
.border(width = 1.dp, color = MaterialTheme.colors.background)
) {
val listState = rememberLazyListState()
val data by model.data.observeAsState()
LazyColumn(state = listState) {
data?.forEach {
item {
BBSItem(vo = it)
Spacer(modifier = Modifier.height(5.dp))
Divider(color = MaterialTheme.colors.onBackground)
}
}
}
// Logger.i("totalItemsCount=${listState.layoutInfo.totalItemsCount},firstVisibleItemIndex=${listState.firstVisibleItemIndex}")
if (listState.layoutInfo.totalItemsCount - listState.firstVisibleItemIndex == model.initSize / 2 - 1) {
model.loadMore { scaffoldModel.update(message = it) }
}
}
}
}
@Composable
private fun BBSItem(vo: BBSVo) {
Column {
Row(
modifier = Modifier
.fillMaxWidth()
.padding(10.dp)
) {
Card(
backgroundColor = MaterialTheme.colors.secondaryVariant,
modifier = Modifier.weight(0.5F)
) {
Column(
modifier = Modifier.height(50.dp),
verticalArrangement = Arrangement.SpaceEvenly
) {
Text(text = vo.name)
Text(text = vo.createTime.format())
}
}
Spacer(modifier = Modifier.weight(0.5F))
}
Card(
backgroundColor = MaterialTheme.colors.background,
modifier = Modifier.padding(10.dp)
) {
Text(
text = vo.content, modifier = Modifier
.fillMaxWidth()
.height(100.dp)
)
}
}
}
}

@ -4,18 +4,19 @@ import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import com.gyf.csams.NOT_IMPL_TIP
import com.gyf.csams.uikit.AssociationMenu import com.gyf.csams.uikit.AssociationMenu
import com.gyf.csams.uikit.ScrollList import com.gyf.csams.uikit.ScrollList
import com.gyf.csams.uikit.StringForm import com.gyf.csams.uikit.StringForm
import com.gyf.csams.uikit.TopMenuInterface
import com.orhanobut.logger.Logger import com.orhanobut.logger.Logger
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
class AssociationViewModel:ViewModel() {
/** class AssociationViewModel:ViewModel(),TopMenuInterface<AssociationMenu>{
* 当前菜单
*/ override val _currentMenu: MutableLiveData<AssociationMenu> = MutableLiveData()
private val _currentMenu=MutableLiveData<AssociationMenu>() override val currentMenu: LiveData<AssociationMenu> = _currentMenu
val currentMenu:LiveData<AssociationMenu> = _currentMenu
/** /**
* 下拉菜单状态 * 下拉菜单状态
@ -23,14 +24,7 @@ class AssociationViewModel:ViewModel() {
private val _expanded=MutableLiveData(false) private val _expanded=MutableLiveData(false)
val expanded:LiveData<Boolean> = _expanded val expanded:LiveData<Boolean> = _expanded
/**
* 切换顶部菜单
*
* @param menu
*/
fun clickMenu(menu:AssociationMenu){
_currentMenu.value=menu
}
/** /**
* 切换下拉菜单状态 * 切换下拉菜单状态
@ -113,7 +107,7 @@ class MemberViewModel:ScrollList<MemberVo>(){
*/ */
fun search(callback: (value: String) -> Unit){ fun search(callback: (value: String) -> Unit){
Logger.i("搜索条件[成员姓名:${name.formValue.value}]") Logger.i("搜索条件[成员姓名:${name.formValue.value}]")
callback("功能尚未实现,敬请期待") callback(NOT_IMPL_TIP)
} }
} }
@ -131,11 +125,13 @@ class HistoryActViewModel: ScrollList<HistoryActVo>() {
} }
override fun load() { override fun load() {
_data.value?.apply { viewModelScope.launch {
repeat(initSize){ _data.value?.apply {
add(HistoryActVo(name = "活动${size+1}")) repeat(initSize){
add(HistoryActVo(name = "活动${size+1}"))
}
Logger.i("初始化活动数量:${size}")
} }
Logger.i("初始化活动数量:${size}")
} }
} }

@ -3,6 +3,7 @@ package com.gyf.csams.association.model
import androidx.lifecycle.LiveData import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import com.gyf.csams.NOT_IMPL_TIP
import com.gyf.csams.uikit.ScrollList import com.gyf.csams.uikit.ScrollList
import com.gyf.csams.uikit.StringForm import com.gyf.csams.uikit.StringForm
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
@ -159,7 +160,7 @@ class ExamViewModel:ScrollList<Exam>() {
* @param callback * @param callback
*/ */
fun updateExam(callback: (message: String) -> Unit){ fun updateExam(callback: (message: String) -> Unit){
callback("功能尚未实现,敬请期待") callback(NOT_IMPL_TIP)
} }
/** /**
@ -168,7 +169,7 @@ class ExamViewModel:ScrollList<Exam>() {
* @param callback * @param callback
*/ */
fun postAnswer(callback: (message: String) -> Unit){ fun postAnswer(callback: (message: String) -> Unit){
callback("功能尚未实现,敬请期待") callback(NOT_IMPL_TIP)
} }
/** /**
@ -220,7 +221,7 @@ class ExamViewModel:ScrollList<Exam>() {
// callback("成功加载更多题目") // callback("成功加载更多题目")
// } // }
// callback("功能尚未实现,敬请期待") // callback(NOT_IMPL_TIP)
} }
fun addQuestion() { fun addQuestion() {

@ -4,6 +4,7 @@ import android.net.Uri
import androidx.lifecycle.LiveData import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import com.gyf.csams.NOT_IMPL_TIP
import com.gyf.csams.uikit.StringForm import com.gyf.csams.uikit.StringForm
@ -39,7 +40,7 @@ class RegAssociationViewModel : ViewModel() {
* @param callback * @param callback
*/ */
fun register(callback: (value: String) -> Unit){ fun register(callback: (value: String) -> Unit){
callback("功能尚未实现,敬请期待") callback(NOT_IMPL_TIP)
} }
} }

@ -1,6 +1,7 @@
package com.gyf.csams.association.model package com.gyf.csams.association.model
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import com.gyf.csams.NOT_IMPL_TIP
import com.gyf.csams.uikit.StringForm import com.gyf.csams.uikit.StringForm
/** /**
@ -22,6 +23,6 @@ class RenameViewModel:ViewModel() {
* *
*/ */
fun post(callback:(message:String) -> Unit){ fun post(callback:(message:String) -> Unit){
callback("功能尚未实现,敬请期待") callback(NOT_IMPL_TIP)
} }
} }

@ -19,7 +19,6 @@ 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.compose.ui.window.PopupProperties
import androidx.lifecycle.viewmodel.compose.viewModel import androidx.lifecycle.viewmodel.compose.viewModel
@ -29,8 +28,11 @@ 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.gyf.csams.util.randomChinese
import com.orhanobut.logger.Logger import com.orhanobut.logger.Logger
/** /**
* 社团界面 * 社团界面
* *
@ -44,18 +46,20 @@ class AssociationActivity: ComponentActivity() {
nav, scaffoldState -> nav, scaffoldState ->
val context= LocalContext.current as AssociationActivity val context= LocalContext.current as AssociationActivity
val model:AssociationViewModel= viewModel() val model:AssociationViewModel= viewModel()
val startMenu=AssociationMenu.main val currentMenuName:AssociationMenu by model.currentMenu.observeAsState(AssociationMenu.startMenu)
val menu:AssociationMenu by model.currentMenu.observeAsState(startMenu)
val intent=Intent(context,ExamActivity::class.java) val intent=Intent(context,ExamActivity::class.java)
val expanded by model.expanded.observeAsState(false) val expanded by model.expanded.observeAsState(false)
Column { Column {
Logger.i("expanded=$expanded") Logger.i("expanded=$expanded")
AssociationAppBar(menu = menu,nav = nav,back = { context.onBackPressed() },dropMenu = {model.switchType()}){ TextTopAppBar(nav = nav,
currentMenuName= currentMenuName.menuName,
menuNames = AssociationMenu.values(),
iconMenu = {model.switchType()}){
Row{ Row{
DropdownMenu(expanded = expanded, DropdownMenu(expanded = expanded,
onDismissRequest = { /*TODO*/ }, onDismissRequest = { /*TODO*/ },
offset = DpOffset.Zero.copy(x=50.dp), // offset = DpOffset.Zero.copy(x=50.dp),
properties = PopupProperties() properties = PopupProperties()
) { ) {
DropdownMenuItem(onClick = { DropdownMenuItem(onClick = {
@ -111,22 +115,21 @@ class AssociationActivity: ComponentActivity() {
} }
} }
} }
} }
NavHost(navController = nav, startDestination = startMenu.name) { NavHost(navController = nav, startDestination = AssociationMenu.startMenu.name) {
composable(AssociationMenu.member.name){ composable(AssociationMenu.Member.name){
model.clickMenu(AssociationMenu.member) model.clickMenu(AssociationMenu.Member)
Member() Member()
ShowSnackbar(scaffoldState = scaffoldState) ShowSnackbar(scaffoldState = scaffoldState)
} }
composable(AssociationMenu.main.name){ composable(AssociationMenu.Main.name){
model.clickMenu(AssociationMenu.main) model.clickMenu(AssociationMenu.Main)
Main() Main()
ShowSnackbar(scaffoldState = scaffoldState) ShowSnackbar(scaffoldState = scaffoldState)
} }
composable(AssociationMenu.list.name){ composable(AssociationMenu.ActivityList.name){
model.clickMenu(AssociationMenu.list) model.clickMenu(AssociationMenu.ActivityList)
AssociationList() AssociationList()
ShowSnackbar(scaffoldState = scaffoldState) ShowSnackbar(scaffoldState = scaffoldState)
} }
@ -137,80 +140,80 @@ class AssociationActivity: ComponentActivity() {
} }
} }
} }
}
/**
* 社团成员
*
*/
@Composable
private fun Member(){
MainFrame(background = { Background(image = BackgroundImage.association_main) }) {
val searchWeight=0.2F
Search(modifier = Modifier
.fillMaxWidth()
.weight(searchWeight))
MemberList(modifier = Modifier
.fillMaxWidth()
.weight(1 - searchWeight))
/**
* 社团成员
*
*/
@Composable
private fun Member(){
MainFrame(background = { Background(image = BackgroundImage.AssociationMain) }) {
val searchWeight=0.2F
Search(modifier = Modifier
.fillMaxWidth()
.weight(searchWeight))
MemberList(modifier = Modifier
.fillMaxWidth()
.weight(1 - searchWeight))
}
} }
}
/** /**
* 检索成员 * 检索成员
* *
*/ */
@Composable @Composable
private fun Search(modifier:Modifier=Modifier, model: MemberViewModel= viewModel(), scaffoldModel: ScaffoldModel= viewModel()){ private fun Search(modifier:Modifier=Modifier, model: MemberViewModel= viewModel(), scaffoldModel: ScaffoldModel= viewModel()){
Column(modifier = modifier.fillMaxSize()) { Column(modifier = modifier.fillMaxSize()) {
Spacer(modifier = Modifier.weight(0.5F)) Spacer(modifier = Modifier.weight(0.5F))
Row(modifier = Modifier Row(modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.weight(0.5F),verticalAlignment = Alignment.CenterVertically) { .weight(0.5F),verticalAlignment = Alignment.CenterVertically) {
val textFieldWeight=0.4F val textFieldWeight=0.4F
val buttonWeight=0.2F val buttonWeight=0.2F
val spaceWeight=(1-textFieldWeight-buttonWeight)/3 val spaceWeight=(1-textFieldWeight-buttonWeight)/3
Spacer(modifier = Modifier.weight((spaceWeight))) Spacer(modifier = Modifier.weight((spaceWeight)))
BaseTextField(modifier = Modifier.weight(textFieldWeight),form = model.name,singeLine = true) BaseTextField(modifier = Modifier.weight(textFieldWeight),form = model.name,singeLine = true)
Spacer(modifier = Modifier.weight(spaceWeight)) Spacer(modifier = Modifier.weight(spaceWeight))
OutlinedButton(onClick = { model.search { scaffoldModel.update(message=it) } },modifier = Modifier.weight(buttonWeight)) { OutlinedButton(onClick = { model.search { scaffoldModel.update(message=it) } },modifier = Modifier.weight(buttonWeight)) {
Text(text = model.search) Text(text = model.search)
}
Spacer(modifier = Modifier.weight(spaceWeight))
} }
Spacer(modifier = Modifier.weight(spaceWeight))
} }
} }
}
/** /**
* 成员列表 * 成员列表
* *
*/ */
@Composable @Composable
private fun MemberList(modifier: Modifier=Modifier, model: MemberViewModel=viewModel(), scaffoldModel: ScaffoldModel= viewModel()){ private fun MemberList(modifier: Modifier=Modifier, model: MemberViewModel=viewModel(), scaffoldModel: ScaffoldModel= viewModel()){
val list:MutableList<MemberVo>? by model.memberList.observeAsState() val list:MutableList<MemberVo>? by model.memberList.observeAsState()
val listState= rememberLazyListState() val listState= rememberLazyListState()
LazyColumn(state = listState,modifier = modifier) { LazyColumn(state = listState,modifier = modifier) {
list?.forEach { list?.forEach {
item { item {
Column { Column {
Spacer(modifier = Modifier.height(10.dp)) Spacer(modifier = Modifier.height(10.dp))
Row{ Row{
val weight = 1F / 3 val weight = 1F / 3
Spacer(modifier = Modifier.weight(weight)) Spacer(modifier = Modifier.weight(weight))
Card( Card(
modifier = Modifier.weight(weight), modifier = Modifier.weight(weight),
backgroundColor = MaterialTheme.colors.background backgroundColor = MaterialTheme.colors.background
) { ) {
Text(text = it.name) Text(text = it.name)
}
Spacer(modifier = Modifier.weight(weight))
} }
Spacer(modifier = Modifier.height(10.dp)) Spacer(modifier = Modifier.weight(weight))
Divider(color = MaterialTheme.colors.background)
} }
Spacer(modifier = Modifier.height(10.dp))
Divider(color = MaterialTheme.colors.background)
} }
}
} }
item { item {
Row(horizontalArrangement = Arrangement.Center,modifier = Modifier.fillMaxWidth()) { Row(horizontalArrangement = Arrangement.Center,modifier = Modifier.fillMaxWidth()) {
@ -222,180 +225,183 @@ private fun MemberList(modifier: Modifier=Modifier, model: MemberViewModel=viewM
} }
} }
}
} }
}
/** /**
* 社团主页 * 社团主页
* *
*/ */
@Composable @Composable
private fun Main(){ private fun Main(){
MainFrame(background = { MainFrame(background = {
Background(image = BackgroundImage.association_main,alpha = 0.7F) Background(image = BackgroundImage.AssociationMain,alpha = 0.7F)
}) { }) {
val nameW=0.1F val nameW=0.1F
val cardW=0.66F*0.4F val cardW=0.66F*0.4F
Name(modifier = Modifier Name(modifier = Modifier
.fillMaxWidth()
.weight(nameW))
DescCard(
modifier = Modifier
.weight(cardW)
.fillMaxWidth() .fillMaxWidth()
) .weight(nameW))
Commander( DescCard(
modifier = Modifier.weight(cardW) modifier = Modifier
) .weight(cardW)
Showcase(modifier = Modifier.weight(1F-nameW-cardW-cardW)) .fillMaxWidth(),
content = randomChinese(500)
)
Commander(
modifier = Modifier.weight(cardW)
)
Showcase(modifier = Modifier.weight(1F-nameW-cardW-cardW))
}
} }
}
/** /**
* 社团名字 * 社团名字
* *
* @param modifier * @param modifier
*/ */
@Composable @Composable
private fun Name(modifier: Modifier){ private fun Name(modifier: Modifier){
Box(modifier = modifier) { Box(modifier = modifier) {
Image( Image(
painter = painterResource(id = R.drawable.association_name_border), painter = painterResource(id = R.drawable.association_name_border),
contentDescription = null, contentDescription = null,
contentScale = ContentScale.FillBounds, contentScale = ContentScale.FillBounds,
modifier=Modifier.fillMaxSize() modifier=Modifier.fillMaxSize()
) )
Column{ Column{
Spacer(modifier = Modifier.weight(1.7F / 3)) Spacer(modifier = Modifier.weight(1.7F / 3))
Row(modifier = Modifier Row(modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.weight(1F / 3), .weight(1F / 3),
horizontalArrangement = Arrangement.Center) { horizontalArrangement = Arrangement.Center) {
Text(text = "社团名字") Text(text = "社团名字")
}
Spacer(modifier = Modifier.weight(0.3F / 3))
} }
Spacer(modifier = Modifier.weight(0.3F / 3))
} }
} }
}
/** /**
* 团长名字 * 团长名字
* *
* @param modifier * @param modifier
*/ */
@Composable @Composable
private fun Commander(modifier: Modifier){ private fun Commander(modifier: Modifier){
Box(modifier=modifier,contentAlignment = Alignment.Center){ Box(modifier=modifier,contentAlignment = Alignment.Center){
Row(modifier = Modifier.fillMaxWidth(),horizontalArrangement = Arrangement.Center) { Row(modifier = Modifier.fillMaxWidth(),horizontalArrangement = Arrangement.Center) {
Image(painter = painterResource(id = R.drawable.association_persion_name_border), Image(painter = painterResource(id = R.drawable.persion_name_border),
contentDescription = null contentDescription = null
) )
}
Text(text = "团长")
} }
Text(text = "团长")
} }
}
/** /**
* 风采展示区 * 风采展示区
* *
* @param modifier * @param modifier
*/ */
@Composable @Composable
private fun Showcase(modifier: Modifier){ private fun Showcase(modifier: Modifier){
Box(modifier = modifier,contentAlignment = Alignment.Center) { Box(modifier = modifier,contentAlignment = Alignment.Center) {
Image(painter = painterResource(id = R.drawable.showcase_border), Image(painter = painterResource(id = R.drawable.showcase_border),
contentDescription = null, contentDescription = null,
modifier=Modifier.fillMaxSize()) modifier=Modifier.fillMaxSize())
Image(painter = painterResource(id = R.drawable.ic_launcher_foreground), contentDescription = null) Image(painter = painterResource(id = R.drawable.ic_launcher_foreground), contentDescription = null)
}
} }
}
/** /**
* 活动列表 * 活动列表
* *
*/ */
@Composable @Composable
private fun AssociationList(){ private fun AssociationList(){
MainFrame(background = { Background(image = BackgroundImage.association_main,alpha = 07F) }) { MainFrame(background = { Background(image = BackgroundImage.AssociationMain,alpha = 07F) }) {
val onGoWeight=0.3F val onGoWeight=0.3F
OngoingActivity(modifier = Modifier OngoingActivity(modifier = Modifier
.weight(onGoWeight) .weight(onGoWeight)
.fillMaxWidth()) .fillMaxWidth())
HistoryActivityList(modifier = Modifier HistoryActivityList(modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.weight(1 - onGoWeight) .weight(1 - onGoWeight)
.border(width = 1.dp, color = MaterialTheme.colors.onBackground)) .border(width = 1.dp, color = MaterialTheme.colors.onBackground))
}
} }
}
/** /**
* 进行中的活动 * 进行中的活动
* *
*/ */
@Composable @Composable
private fun OngoingActivity(modifier: Modifier=Modifier){ private fun OngoingActivity(modifier: Modifier=Modifier){
Row(modifier = modifier,horizontalArrangement = Arrangement.Center) { Row(modifier = modifier,horizontalArrangement = Arrangement.Center) {
val weight=0.5F val weight=0.5F
val spaceWeight=(1-0.5F)/2 val spaceWeight=(1-0.5F)/2
Spacer(modifier = Modifier.weight(spaceWeight)) Spacer(modifier = Modifier.weight(spaceWeight))
Poster(id = R.drawable.ic_launcher_foreground,modifier = Modifier.weight(weight)) Poster(id = R.drawable.ic_launcher_foreground,modifier = Modifier.weight(weight))
Spacer(modifier = Modifier.weight(spaceWeight)) Spacer(modifier = Modifier.weight(spaceWeight))
} }
} }
/** /**
* 历史活动列表 * 历史活动列表
* *
* @param modifier * @param modifier
*/ */
@Composable @Composable
private fun HistoryActivityList(modifier: Modifier,model:HistoryActViewModel= viewModel(),scaffoldModel: ScaffoldModel= viewModel()){ private fun HistoryActivityList(modifier: Modifier,model:HistoryActViewModel= viewModel(),scaffoldModel: ScaffoldModel= viewModel()){
val listState= rememberLazyListState() val listState= rememberLazyListState()
val list by model.data.observeAsState() val list by model.data.observeAsState()
LazyColumn(state = listState,modifier = modifier) { LazyColumn(state = listState,modifier = modifier) {
list?.chunked(2)?.forEach { list?.chunked(2)?.forEach {
item { item {
Row(modifier=Modifier.fillMaxWidth()) { Row(modifier=Modifier.fillMaxWidth()) {
HistoryActivity(modifier = Modifier.weight(0.4F),it[0]) HistoryActivity(modifier = Modifier.weight(0.4F),it[0])
Spacer(modifier = Modifier.weight(0.2F)) Spacer(modifier = Modifier.weight(0.2F))
if (it.size==2) HistoryActivity(modifier = Modifier.weight(0.4F),it[1]) if (it.size==2) HistoryActivity(modifier = Modifier.weight(0.4F),it[1])
else Box(modifier = Modifier.weight(0.4F)) 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){
model.loadMore { scaffoldModel.update(message=it) }
}
} }
if(listState.layoutInfo.totalItemsCount-listState.firstVisibleItemIndex==model.initSize/2-1){
model.loadMore { scaffoldModel.update(message=it) }
}
}
/** /**
* 历史活动 * 历史活动
* *
* @param modifier * @param modifier
*/ */
@Composable @Composable
private fun HistoryActivity(modifier: Modifier,historyActVo: HistoryActVo){ private fun HistoryActivity(modifier: Modifier,historyActVo: HistoryActVo){
Box(modifier=modifier,contentAlignment = Alignment.Center){ Box(modifier=modifier,contentAlignment = Alignment.Center){
Image(painter = painterResource(id = R.drawable.history_activity_border), Image(painter = painterResource(id = R.drawable.history_activity_border),
contentDescription = null, contentDescription = null,
modifier = Modifier.fillMaxSize()) modifier = Modifier.fillMaxSize())
Image(painter = painterResource(id = R.drawable.ic_launcher_foreground), Image(painter = painterResource(id = R.drawable.ic_launcher_foreground),
contentDescription = null, contentDescription = null,
modifier = Modifier.fillMaxSize()) modifier = Modifier.fillMaxSize())
Text(text = historyActVo.name) Text(text = historyActVo.name)
}
} }
}
@Preview @Preview
@Composable @Composable
fun NamePreview(){ fun NamePreview(){
Divider(color = MaterialTheme.colors.background) Divider(color = MaterialTheme.colors.background)
}
} }

@ -39,7 +39,7 @@ class ExamActivity : ComponentActivity() {
setContent { setContent {
Body { scaffoldState -> Body { scaffoldState ->
MainFrame(background = { Background(image = BackgroundImage.exam) }) { MainFrame(background = { Background(image = BackgroundImage.Exam,alpha = 0.6F) }) {
Spacer(modifier = Modifier.weight(0.1F)) Spacer(modifier = Modifier.weight(0.1F))
Title(modifier = Modifier.weight(0.1F)) Title(modifier = Modifier.weight(0.1F))
Exam(modifier = Modifier.weight(0.8F)) Exam(modifier = Modifier.weight(0.8F))
@ -48,287 +48,288 @@ class ExamActivity : ComponentActivity() {
} }
} }
} }
}
/**
* 底部按钮 /**
* * 底部按钮
*/ *
@Composable */
private fun BottomButton( @Composable
modifier: Modifier = Modifier, private fun BottomButton(
model: ExamViewModel = viewModel(), modifier: Modifier = Modifier,
scaffoldModel: ScaffoldModel = viewModel() model: ExamViewModel = viewModel(),
) { scaffoldModel: ScaffoldModel = viewModel()
val context = LocalContext.current as ExamActivity ) {
val context = LocalContext.current as ExamActivity
Row(modifier = modifier, horizontalArrangement = Arrangement.Center) {
when(context.activityType){ Row(modifier = modifier, horizontalArrangement = Arrangement.Center) {
ExamActivityType.SET_EXAM->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) } ExamActivityType.JOIN_Association->OutlinedButton(onClick = {
}, modifier = Modifier.background(color = MaterialTheme.colors.primary)) { model.postAnswer { scaffoldModel.update(message=it) }
Text(text = model.postAnswer) }, 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()
}, modifier = Modifier.background(color = MaterialTheme.colors.secondary)) { }, modifier = Modifier.background(color = MaterialTheme.colors.secondary)) {
Text(text = model.back) Text(text = model.back)
}
} }
} }
}
/** /**
* 标题 * 标题
* *
* @param modifier * @param modifier
*/ */
@Composable @Composable
private fun Title(modifier: Modifier = Modifier) { private fun Title(modifier: Modifier = Modifier) {
val context= LocalContext.current as ExamActivity val context= LocalContext.current as ExamActivity
Row(horizontalArrangement = Arrangement.Center, modifier = modifier.fillMaxWidth()) { Row(horizontalArrangement = Arrangement.Center, modifier = modifier.fillMaxWidth()) {
Text(text = context.activityType.menuName, style = MaterialTheme.typography.h4) Text(text = context.activityType.menuName, style = MaterialTheme.typography.h4)
}
} }
}
@Composable @Composable
private fun ExamChild(it:Exam,examHeight: Dp,isAdd: Boolean=false){ private fun ExamChild(it:Exam,examHeight: Dp,isAdd: Boolean=false){
val questionWeight=0.3F val questionWeight=0.3F
when (it) { when (it) {
is OpenQuestionsVo -> ExamOQ( is OpenQuestionsVo -> ExamOQ(
openQuestionsVo = it, openQuestionsVo = it,
modifier = Modifier.height(examHeight*questionWeight), modifier = Modifier.height(examHeight*questionWeight),
isAdd = isAdd isAdd = isAdd
) )
is ChoiceQuestionVo -> ExamCQ( is ChoiceQuestionVo -> ExamCQ(
choiceQuestionVo = it, choiceQuestionVo = it,
modifier = Modifier.height(examHeight), modifier = Modifier.height(examHeight),
questionWeight = questionWeight, questionWeight = questionWeight,
isAdd = isAdd isAdd = isAdd
) )
}
} }
}
/** /**
* 题目列表 * 题目列表
* *
* @param modifier * @param modifier
* @param model * @param model
*/ */
@Composable @Composable
private fun Exam( private fun Exam(
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
model: ExamViewModel = viewModel(), model: ExamViewModel = viewModel(),
scaffoldModel: ScaffoldModel = viewModel(), scaffoldModel: ScaffoldModel = viewModel(),
examHeight: Dp = 350.dp examHeight: Dp = 350.dp
) { ) {
val listState = rememberLazyListState() val listState = rememberLazyListState()
val data by model.data.observeAsState() val data by model.data.observeAsState()
val newExam by model.newExam.observeAsState() val newExam by model.newExam.observeAsState()
LazyColumn(state = listState, modifier = modifier) { LazyColumn(state = listState, modifier = modifier) {
data?.forEach { data?.forEach {
item { item {
ExamChild(it = it, examHeight = examHeight) ExamChild(it = it, examHeight = examHeight)
Spacer(modifier = Modifier.height(20.dp)) Spacer(modifier = Modifier.height(20.dp))
}
} }
} newExam?.let {
newExam?.let { item {
item { Column {
Column { OutlinedButton(onClick = { model.switchType(it) }) {
OutlinedButton(onClick = { model.switchType(it) }) { Text(text = "切换到${if (newExam is ChoiceQuestionVo) "开放题" else "选择题"}")
Text(text = "切换到${if (newExam is ChoiceQuestionVo) "开放题" else "选择题"}") }
ExamChild(it = it, examHeight = examHeight,isAdd = true)
} }
ExamChild(it = it, examHeight = examHeight,isAdd = true)
} }
} }
}
item { item {
Column { Column {
Divider(color = MaterialTheme.colors.background) Divider(color = MaterialTheme.colors.background)
Spacer(modifier = Modifier.height(30.dp)) Spacer(modifier = Modifier.height(30.dp))
BottomButton(modifier = Modifier.fillMaxWidth()) BottomButton(modifier = Modifier.fillMaxWidth())
}
} }
}
} }
if (listState.layoutInfo.totalItemsCount - listState.firstVisibleItemIndex == model.initSize / 2 - 1) { if (listState.layoutInfo.totalItemsCount - listState.firstVisibleItemIndex == model.initSize / 2 - 1) {
model.loadMore { scaffoldModel.update(message=it) } model.loadMore { scaffoldModel.update(message=it) }
} }
} }
/** /**
* 问题 * 问题
* *
* @param modifier * @param modifier
* @param exam * @param exam
*/ */
@Composable @Composable
private fun Question(modifier: Modifier = Modifier, exam: Exam) { private fun Question(modifier: Modifier = Modifier, exam: Exam) {
BaseTextField( BaseTextField(
form = exam.question, form = exam.question,
modifier = modifier modifier = modifier
.fillMaxSize() .fillMaxSize()
.background(color = MaterialTheme.colors.background) .background(color = MaterialTheme.colors.background)
) )
} }
/** /**
* 操作按钮 * 操作按钮
* *
*/ */
@Composable @Composable
private fun ActionButton(modifier: Modifier = Modifier, isAdd: Boolean, private fun ActionButton(modifier: Modifier = Modifier, isAdd: Boolean,
model: ExamViewModel= viewModel(), model: ExamViewModel= viewModel(),
scaffoldModel: ScaffoldModel= viewModel(), scaffoldModel: ScaffoldModel= viewModel(),
exam: Exam) { exam: Exam) {
val list by model.data.observeAsState() val list by model.data.observeAsState()
val newExam by model.newExam.observeAsState() val newExam by model.newExam.observeAsState()
Box( Box(
contentAlignment = Alignment.Center, contentAlignment = Alignment.Center,
modifier = modifier modifier = modifier
) { ) {
IconButton(onClick = { IconButton(onClick = {
if(isAdd){ if(isAdd){
if((newExam?.question?.formValue?.value ?: "").isNotEmpty()){ if((newExam?.question?.formValue?.value ?: "").isNotEmpty()){
scaffoldModel.update(message=model.addTip,actionLabel = model.actionLabel){ scaffoldModel.update(message=model.addTip,actionLabel = model.actionLabel){
model.addQuestion() model.addQuestion()
}
}else{
scaffoldModel.update(message = model.questionIsNull)
} }
}else{
scaffoldModel.update(message = model.questionIsNull)
}
}else{
if(list?.size==1){
scaffoldModel.update(model.deleteLeastOne)
}else{ }else{
scaffoldModel.update(message=model.deleteTip,actionLabel = model.actionLabel){ if(list?.size==1){
model.deleteQuestion(exam = exam) 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
)
} }
}) {
Icon(
painter = painterResource(id = if (isAdd) R.drawable.ic_add_select else R.drawable.ic_sami_select),
contentDescription = null
)
} }
} }
}
/** /**
* 开放题 * 开放题
* *
* @param openQuestionsVo * @param openQuestionsVo
*/ */
@Composable @Composable
private fun ExamOQ( private fun ExamOQ(
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
openQuestionsVo: OpenQuestionsVo, openQuestionsVo: OpenQuestionsVo,
isAdd: Boolean = false isAdd: Boolean = false
) { ) {
Row(modifier = modifier) { Row(modifier = modifier) {
val context= LocalContext.current as ExamActivity val context= LocalContext.current as ExamActivity
Question( Question(
exam = openQuestionsVo, modifier = exam = openQuestionsVo, modifier =
if(context.activityType==ExamActivityType.SET_EXAM) if(context.activityType==ExamActivityType.SET_EXAM)
Modifier.weight(0.8F).fillMaxHeight() Modifier.weight(0.8F).fillMaxHeight()
else else
Modifier Modifier
)
if(context.activityType==ExamActivityType.SET_EXAM){
ActionButton(
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
)
}
} }
} }
}
/** /**
* 选择题 * 选择题
* *
* @param choiceQuestionVo * @param choiceQuestionVo
*/ */
@Composable @Composable
private fun ExamCQ( private fun ExamCQ(
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
choiceQuestionVo: ChoiceQuestionVo, choiceQuestionVo: ChoiceQuestionVo,
isAdd: Boolean = false, isAdd: Boolean = false,
model: ExamViewModel = viewModel(), model: ExamViewModel = viewModel(),
questionWeight:Float questionWeight:Float
) { ) {
Row(modifier = modifier) { Row(modifier = modifier) {
val context= LocalContext.current as ExamActivity val context= LocalContext.current as ExamActivity
Column( Column(
modifier = if(context.activityType==ExamActivityType.SET_EXAM) modifier = if(context.activityType==ExamActivityType.SET_EXAM)
Modifier.weight(0.8F).fillMaxHeight() Modifier.weight(0.8F).fillMaxHeight()
else else
Modifier Modifier
) {
Question(
exam = choiceQuestionVo,
modifier = Modifier
.fillMaxWidth()
.weight(questionWeight)
)
Card(
backgroundColor = MaterialTheme.colors.secondaryVariant,
modifier = Modifier
.fillMaxWidth()
.weight(1 - questionWeight)
) { ) {
Question(
exam = choiceQuestionVo,
modifier = Modifier
.fillMaxWidth()
.weight(questionWeight)
)
Card(
backgroundColor = MaterialTheme.colors.secondaryVariant,
modifier = Modifier
.fillMaxWidth()
.weight(1 - questionWeight)
) {
choiceQuestionVo.answers.apply { choiceQuestionVo.answers.apply {
Column { Column {
forEach { forEach {
Row(modifier = Modifier Row(modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.weight(1F / ANSWER_SIZE)) { .weight(1F / ANSWER_SIZE)) {
val answerIndex: Int = indexOf(it) val answerIndex: Int = indexOf(it)
val click = { val click = {
model.update( model.update(
oldExam = choiceQuestionVo, oldExam = choiceQuestionVo,
newExam = choiceQuestionVo.copy(rightAnswer = answerIndex) newExam = choiceQuestionVo.copy(rightAnswer = answerIndex)
) )
}
val isRightAnswer =
choiceQuestionVo.rightAnswer == answerIndex
RadioButton(selected = isRightAnswer, onClick = click)
BaseTextField(form = it)
} }
val isRightAnswer =
choiceQuestionVo.rightAnswer == answerIndex
RadioButton(selected = isRightAnswer, onClick = click)
BaseTextField(form = it)
} }
} }
} }
} }
} }
}
if(context.activityType==ExamActivityType.SET_EXAM) { if(context.activityType==ExamActivityType.SET_EXAM) {
ActionButton( ActionButton(
modifier = Modifier modifier = Modifier
.weight(0.2F) .weight(0.2F)
.fillMaxHeight(), .fillMaxHeight(),
isAdd = isAdd, isAdd = isAdd,
exam = choiceQuestionVo exam = choiceQuestionVo
) )
} }
}
} }
} }

@ -26,7 +26,7 @@ class ReNameActivity: ComponentActivity() {
setContent { setContent {
Body { Body {
scaffoldState -> scaffoldState ->
MainFrame(background = { Background(image = BackgroundImage.rename) }) { MainFrame(background = { Background(image = BackgroundImage.Rename) }) {
Spacer( Spacer(
modifier = Modifier modifier = Modifier
.weight(0.2F) .weight(0.2F)
@ -48,67 +48,67 @@ class ReNameActivity: ComponentActivity() {
} }
} }
} }
}
/** /**
* 标题 * 标题
* *
*/ */
@Composable @Composable
private fun Title(modifier: Modifier=Modifier,model:RenameViewModel= viewModel()){ private fun Title(modifier: Modifier=Modifier,model:RenameViewModel= viewModel()){
Row(modifier = modifier.fillMaxWidth(),horizontalArrangement = Arrangement.Center) { Row(modifier = modifier.fillMaxWidth(),horizontalArrangement = Arrangement.Center) {
Text(text = model.menuName,style = MaterialTheme.typography.h4) Text(text = model.menuName,style = MaterialTheme.typography.h4)
}
} }
}
/** /**
* 社团原名 * 社团原名
* *
*/ */
@Composable @Composable
private fun OldName(modifier: Modifier=Modifier,model:RenameViewModel= viewModel()){ private fun OldName(modifier: Modifier=Modifier,model:RenameViewModel= viewModel()){
BaseTextField(form = model.oldName,modifier = modifier.fillMaxWidth(),singeLine = true) BaseTextField(form = model.oldName,modifier = modifier.fillMaxWidth(),singeLine = true)
} }
/** /**
* 社团新名 * 社团新名
* *
*/ */
@Composable @Composable
private fun NewName(modifier: Modifier=Modifier,model:RenameViewModel= viewModel()){ private fun NewName(modifier: Modifier=Modifier,model:RenameViewModel= viewModel()){
BaseTextField(form = model.newName,modifier = modifier.fillMaxWidth(),singeLine = true) BaseTextField(form = model.newName,modifier = modifier.fillMaxWidth(),singeLine = true)
} }
/** /**
* 换名原因 * 换名原因
* *
*/ */
@Composable @Composable
private fun Cause(modifier: Modifier=Modifier,model:RenameViewModel= viewModel()){ private fun Cause(modifier: Modifier=Modifier,model:RenameViewModel= viewModel()){
BaseTextField(form = model.cause,modifier = modifier.fillMaxWidth()) BaseTextField(form = model.cause,modifier = modifier.fillMaxWidth())
} }
/** /**
* 操作按钮 * 操作按钮
* *
* @param modifier * @param modifier
* @param model * @param model
*/ */
@Composable @Composable
private fun BottomButton(modifier: Modifier=Modifier,model:RenameViewModel= viewModel(),scaffoldModel: ScaffoldModel= viewModel()){ private fun BottomButton(modifier: Modifier=Modifier,model:RenameViewModel= viewModel(),scaffoldModel: ScaffoldModel= viewModel()){
Row(modifier = modifier.fillMaxWidth()) { Row(modifier = modifier.fillMaxWidth()) {
val weight=(1-0.5F)/2 val weight=(1-0.5F)/2
val context= LocalContext.current as ReNameActivity val context= LocalContext.current as ReNameActivity
Spacer(modifier = Modifier.weight(weight)) Spacer(modifier = Modifier.weight(weight))
Row(modifier=Modifier.weight(0.5F)) { Row(modifier=Modifier.weight(0.5F)) {
OutlinedButton(onClick = { model.post{scaffoldModel.update(message=it)} }) { OutlinedButton(onClick = { model.post{scaffoldModel.update(message=it)} }) {
Text(text = model.postDesc) Text(text = model.postDesc)
} }
Spacer(modifier = Modifier.width(10.dp)) Spacer(modifier = Modifier.width(10.dp))
OutlinedButton(onClick = { context.onBackPressed() }) { OutlinedButton(onClick = { context.onBackPressed() }) {
Text(text = model.back) Text(text = model.back)
}
} }
Spacer(modifier = Modifier.weight(weight))
} }
Spacer(modifier = Modifier.weight(weight))
} }
} }

@ -50,7 +50,7 @@ class RegAssociationActivity: ComponentActivity(){
CSAMSTheme { CSAMSTheme {
Body { Body {
scaffoldState -> scaffoldState ->
MainFrame(background = { Background(BackgroundImage.reg_association,alpha = 0.5F) }) { MainFrame(background = { Background(BackgroundImage.RegAssociation,alpha = 0.5F) }) {
Spacer( Spacer(
modifier = Modifier modifier = Modifier
.weight(0.1F) .weight(0.1F)
@ -79,145 +79,147 @@ class RegAssociationActivity: ComponentActivity(){
} }
} }
}
/** /**
* 社团Logo * 社团Logo
* *
* @param modifier * @param modifier
*/ */
@Composable @Composable
private fun Logo(model:RegAssociationViewModel= viewModel(),modifier: Modifier) { private fun Logo(model:RegAssociationViewModel= viewModel(),modifier: Modifier) {
val photoIntent=Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI) val photoIntent=Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI)
photoIntent.type = "image/*" photoIntent.type = "image/*"
val uri:Uri? by model.picture.observeAsState() val uri:Uri? by model.picture.observeAsState()
val resultLauncher=rememberLauncherForActivityResult(contract = ActivityResultContracts.StartActivityForResult()) { val resultLauncher=rememberLauncherForActivityResult(contract = ActivityResultContracts.StartActivityForResult()) {
when(it.resultCode){ when(it.resultCode){
Activity.RESULT_OK->{ Activity.RESULT_OK->{
Logger.i("uri=${it.data?.data}") Logger.i("uri=${it.data?.data}")
it.data?.data?.let { it1 -> model.setPicture(it1) } it.data?.data?.let { it1 -> model.setPicture(it1) }
}
} }
} }
}
val loadPicture={ val loadPicture={
//model.loadPicture(context) //model.loadPicture(context)
resultLauncher.launch(photoIntent) resultLauncher.launch(photoIntent)
} }
val launcher = rememberLauncherForActivityResult( val launcher = rememberLauncherForActivityResult(
ActivityResultContracts.RequestPermission() ActivityResultContracts.RequestPermission()
) { isGranted: Boolean -> ) { isGranted: Boolean ->
if (isGranted) { if (isGranted) {
// Permission Accepted: Do something // Permission Accepted: Do something
loadPicture() loadPicture()
} else { } else {
// Permission Denied: Do something // Permission Denied: Do something
Logger.w(model.deninedPermission) Logger.w(model.deninedPermission)
}
} }
}
val context= LocalContext.current val context= LocalContext.current
Box(contentAlignment = Alignment.Center,modifier = modifier) { Box(contentAlignment = Alignment.Center,modifier = modifier) {
Row(verticalAlignment = Alignment.CenterVertically, Row(verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.Center,modifier = Modifier horizontalArrangement = Arrangement.Center,modifier = Modifier
.fillMaxSize() .fillMaxSize()
.border(width = 1.dp, color = Color.Black)) { .border(width = 1.dp, color = Color.Black)) {
if (uri == null) { if (uri == null) {
OutlinedButton(onClick = { OutlinedButton(onClick = {
when (PackageManager.PERMISSION_GRANTED) { when (PackageManager.PERMISSION_GRANTED) {
ContextCompat.checkSelfPermission( ContextCompat.checkSelfPermission(
context, context,
Manifest.permission.READ_EXTERNAL_STORAGE Manifest.permission.READ_EXTERNAL_STORAGE
) -> { ) -> {
// Some works that require permission // Some works that require permission
loadPicture()
}
else -> {
// Asking for permission
launcher.launch(Manifest.permission.READ_EXTERNAL_STORAGE)
}
}
}) {
Text(text = model.piciurePlaceHolder)
}
} else {
uri.let {
if(it!=null){
Row {
Image(bitmap = BitmapFactory.decodeStream(context.contentResolver.openInputStream(it))
.asImageBitmap(), contentDescription = null)
IconButton(onClick = {
loadPicture() loadPicture()
}) { }
Image(painter = painterResource(id = R.drawable.ic_exchange_rate), contentDescription = null) else -> {
// Asking for permission
launcher.launch(Manifest.permission.READ_EXTERNAL_STORAGE)
} }
} }
}) {
Text(text = model.piciurePlaceHolder)
}
} else {
uri.let {
if(it!=null){
Row {
Image(bitmap = BitmapFactory.decodeStream(context.contentResolver.openInputStream(it))
.asImageBitmap(), contentDescription = null)
IconButton(onClick = {
loadPicture()
}) {
Image(painter = painterResource(id = R.drawable.ic_exchange_rate), contentDescription = null)
}
}
}else{ }else{
Text(text = model.errorPicture) Text(text = model.errorPicture)
}
} }
} }
}
}
} }
} }
@Composable
private fun BottomButton(modifier: Modifier=Modifier,scaffoldModel: ScaffoldModel= viewModel(),model:RegAssociationViewModel= viewModel()){
val context= LocalContext.current as RegAssociationActivity
Row(modifier = modifier,horizontalArrangement = Arrangement.Center) {
OutlinedButton(onClick = {
model.register { scaffoldModel.update(message=it) }
},modifier = Modifier.background(color = MaterialTheme.colors.primary)) {
Text(text = model.register)
}
Spacer(modifier = Modifier.width(10.dp))
OutlinedButton(onClick = {
context.onBackPressed()
},modifier = Modifier.background(color = MaterialTheme.colors.secondary)) {
Text(text = model.back)
}
}
} }
@Composable /**
private fun BottomButton(modifier: Modifier=Modifier,scaffoldModel: ScaffoldModel= viewModel(),model:RegAssociationViewModel= viewModel()){ * 菜单标题
val context= LocalContext.current as RegAssociationActivity *
Row(modifier = modifier,horizontalArrangement = Arrangement.Center) { */
OutlinedButton(onClick = { @Composable
model.register { scaffoldModel.update(message=it) } private fun Title(model:RegAssociationViewModel= viewModel()){
},modifier = Modifier.background(color = MaterialTheme.colors.primary)) { Row(modifier = Modifier.fillMaxWidth(),horizontalArrangement = Arrangement.Center) {
Text(text = model.register) Text(text = model.frameDesc,style = MaterialTheme.typography.h4)
}
Spacer(modifier = Modifier.width(10.dp))
OutlinedButton(onClick = {
context.onBackPressed()
},modifier = Modifier.background(color = MaterialTheme.colors.secondary)) {
Text(text = model.back)
} }
} }
} /**
* 社团名称
* @param model
*/
@Composable
private fun Name(model:RegAssociationViewModel= viewModel()){
BaseTextField(form = model.name,singeLine = true,modifier = Modifier.fillMaxWidth())
}
/** /**
* 菜单标题 * 社团简介
* * @param model
*/ */
@Composable @Composable
private fun Title(model:RegAssociationViewModel= viewModel()){ private fun Desc(model:RegAssociationViewModel= viewModel(),modifier:Modifier){
Row(modifier = Modifier.fillMaxWidth(),horizontalArrangement = Arrangement.Center) { BaseTextField(form = model.desc,modifier = modifier)
Text(text = model.frameDesc,style = MaterialTheme.typography.h4)
} }
}
/**
* 社团名称
* @param model
*/
@Composable
private fun Name(model:RegAssociationViewModel= viewModel()){
BaseTextField(form = model.name,singeLine = true,modifier = Modifier.fillMaxWidth())
} }
/**
* 社团简介
* @param model
*/
@Composable
private fun Desc(model:RegAssociationViewModel= viewModel(),modifier:Modifier){
BaseTextField(form = model.desc,modifier = modifier)
}

@ -4,6 +4,7 @@ import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import com.gyf.csams.NOT_IMPL_TIP
import com.gyf.csams.R import com.gyf.csams.R
import com.gyf.csams.uikit.ScrollList import com.gyf.csams.uikit.ScrollList
import com.gyf.csams.uikit.StringForm import com.gyf.csams.uikit.StringForm
@ -85,7 +86,7 @@ class MainViewModel:ViewModel(){
* *
*/ */
fun sendMessage(callback: (value: String) -> Unit){ fun sendMessage(callback: (value: String) -> Unit){
callback("功能尚未实现,敬请期待") callback(NOT_IMPL_TIP)
} }
/** /**
@ -94,7 +95,7 @@ class MainViewModel:ViewModel(){
* @param callback * @param callback
*/ */
fun openNotification(callback: (value: String) -> Unit){ fun openNotification(callback: (value: String) -> Unit){
callback("功能尚未实现,敬请期待") callback(NOT_IMPL_TIP)
} }
} }
@ -125,7 +126,7 @@ class ListViewModel: ScrollList<AssociationDto>() {
*/ */
fun search(callback: (value: String) -> Unit){ fun search(callback: (value: String) -> Unit){
Logger.i("搜索条件[社团名称:${name.formValue.value},社团简介:${desc.formValue.value}]") Logger.i("搜索条件[社团名称:${name.formValue.value},社团简介:${desc.formValue.value}]")
callback("功能尚未实现,敬请期待") callback(NOT_IMPL_TIP)
} }
override val initSize: Int = 10 override val initSize: Int = 10

@ -32,6 +32,7 @@ import com.gyf.csams.association.ui.RegAssociationActivity
import com.gyf.csams.main.model.* import com.gyf.csams.main.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.gyf.csams.util.randomChinese
/** /**
@ -66,328 +67,331 @@ class MainActivity : ComponentActivity() {
} }
}
/** /**
* 个人中心 * 个人中心
* *
*/ */
@Composable @Composable
private fun Center(model:CenterViewModel= viewModel(), scaffoldModel: ScaffoldModel= viewModel(), navController: NavHostController){ private fun Center(model:CenterViewModel= viewModel(), scaffoldModel: ScaffoldModel= viewModel(), navController: NavHostController){
MainFrame(background = { Background(image = BackgroundImage.center,alpha = 0.5F) }, mainMenu = MainMenu.Center, nav = navController) { MainFrame(background = { Background(image = BackgroundImage.Center,alpha = 0.5F) }, mainMenu = MainMenu.Center, nav = navController) {
Column(modifier = Modifier Column(modifier = Modifier
.weight(0.33F) .weight(0.33F)
.fillMaxWidth(),verticalArrangement = Arrangement.Bottom) { .fillMaxWidth(),verticalArrangement = Arrangement.Bottom) {
Card(backgroundColor = MaterialTheme.colors.background) { Card(backgroundColor = MaterialTheme.colors.background) {
val context= LocalContext.current val context= LocalContext.current
Row(modifier = Modifier Row(modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.clickable(onClick = { .clickable(onClick = {
context.startActivity(Intent(context, AssociationActivity::class.java)) context.startActivity(Intent(context, AssociationActivity::class.java))
}),verticalAlignment = Alignment.CenterVertically) { }),verticalAlignment = Alignment.CenterVertically) {
Spacer(modifier = Modifier.weight(0.33F)) Spacer(modifier = Modifier.weight(0.33F))
Row(modifier = Modifier.weight(0.33F),horizontalArrangement = Arrangement.Center) { Row(modifier = Modifier.weight(0.33F),horizontalArrangement = Arrangement.Center) {
Text(text = model.myAssociationDesc) Text(text = model.myAssociationDesc)
} }
Row(modifier = Modifier.weight(0.33F),horizontalArrangement = Arrangement.End) { Row(modifier = Modifier.weight(0.33F),horizontalArrangement = Arrangement.End) {
Icon( Icon(
painter = painterResource(id = R.drawable.ic_arrow_right), painter = painterResource(id = R.drawable.ic_arrow_right),
contentDescription = null, contentDescription = null,
modifier = Modifier.size(50.dp) modifier = Modifier.size(50.dp)
) )
}
} }
}
}
} }
Spacer(modifier = Modifier
.weight(0.66F)
.fillMaxWidth())
} }
Spacer(modifier = Modifier
.weight(0.66F)
.fillMaxWidth())
} }
}
/** /**
* 主界面 * 主界面
*/ */
@Composable @Composable
private fun Main(navController: NavHostController) { private fun Main(navController: NavHostController) {
MainFrame(background = { Background(image = BackgroundImage.main) }, mainMenu = MainMenu.Main, nav = navController) { MainFrame(background = { Background(image = BackgroundImage.Main) }, mainMenu = MainMenu.Main, nav = navController) {
Column(modifier = Modifier.weight(0.33F)) { Column(modifier = Modifier.weight(0.33F)) {
Notification() Notification()
MessageBoard() MessageBoard()
Spacer(modifier = Modifier.height(10.dp)) Spacer(modifier = Modifier.height(10.dp))
ClubActivitiesTitle() ClubActivitiesTitle()
Spacer(modifier = Modifier.height(10.dp)) Spacer(modifier = Modifier.height(10.dp))
} }
Column(modifier = Modifier.weight(0.66F)) { Column(modifier = Modifier.weight(0.66F)) {
PosterWithDesc() PosterWithDesc()
}
} }
} }
}
/** /**
* 社团列表 * 社团列表
* *
* @param navController * @param navController
*/ */
@Composable @Composable
private fun AssociationList(navController: NavHostController) { private fun AssociationList(navController: NavHostController) {
MainFrame( MainFrame(
background = { Background(image = BackgroundImage.list) }, background = { Background(image = BackgroundImage.AssociationList) },
mainMenu = MainMenu.List, mainMenu = MainMenu.List,
nav = navController nav = navController
) { ) {
RegisterAssociation() RegisterAssociation()
AssociationSearch() AssociationSearch()
AssociationListBody() AssociationListBody()
}
} }
}
/** /**
* 注册社团按钮 * 注册社团按钮
* *
*/ */
@Composable @Composable
private fun RegisterAssociation() { private fun RegisterAssociation() {
val context= LocalContext.current val context= LocalContext.current
Row( Row(
horizontalArrangement = Arrangement.End, horizontalArrangement = Arrangement.End,
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.padding(10.dp) .padding(10.dp)
) { ) {
IconButton(onClick = { IconButton(onClick = {
context.startActivity(Intent(context, RegAssociationActivity::class.java)) context.startActivity(Intent(context, RegAssociationActivity::class.java))
}) { }) {
Icon( Icon(
painter = painterResource(id = R.drawable.ic_add_fill), painter = painterResource(id = R.drawable.ic_add_fill),
contentDescription = null, contentDescription = null,
modifier = Modifier.size(50.dp), modifier = Modifier.size(50.dp),
) )
}
} }
} }
}
/** /**
* 社团列表 * 社团列表
* *
*/ */
@Composable @Composable
private fun AssociationListBody(model: ListViewModel = viewModel(),scaffoldModel: ScaffoldModel= viewModel()) { private fun AssociationListBody(model: ListViewModel = viewModel(),scaffoldModel: ScaffoldModel= viewModel()) {
val associationList: MutableList<AssociationDto>? by model.associationDto.observeAsState() val associationList: MutableList<AssociationDto>? by model.associationDto.observeAsState()
val listState = rememberLazyListState() val listState = rememberLazyListState()
LazyColumn(state = listState) { LazyColumn(state = listState) {
associationList?.chunked(2)?.forEach { associationList?.chunked(2)?.forEach {
item{ item{
Row { Row {
Spacer(modifier = Modifier.weight(0.1F)) Spacer(modifier = Modifier.weight(0.1F))
Box(modifier = Modifier.weight(0.35F)) {
Association(associationDto = it[0])
}
Spacer(modifier = Modifier.weight(0.05F))
if(it.size==2) {
Box(modifier = Modifier.weight(0.35F)) { Box(modifier = Modifier.weight(0.35F)) {
Association(associationDto = it[1]) Association(associationDto = it[0])
} }
}else{ Spacer(modifier = Modifier.weight(0.05F))
Box(modifier = Modifier if(it.size==2) {
.weight(0.35F) Box(modifier = Modifier.weight(0.35F)) {
.border(width = 1.dp, color = MaterialTheme.colors.onBackground)) Association(associationDto = it[1])
}
}else{
Box(modifier = Modifier
.weight(0.35F)
.border(width = 1.dp, color = MaterialTheme.colors.onBackground))
}
Spacer(modifier = Modifier.weight(0.1F))
} }
Spacer(modifier = Modifier.weight(0.1F)) Spacer(modifier = Modifier
.fillMaxWidth()
.height(10.dp))
} }
Spacer(modifier = Modifier
.fillMaxWidth()
.height(10.dp))
} }
} }
}
if(listState.layoutInfo.totalItemsCount-listState.firstVisibleItemIndex==model.associationListSize/2-1){ if(listState.layoutInfo.totalItemsCount-listState.firstVisibleItemIndex==model.associationListSize/2-1){
model.loadMore { scaffoldModel.update(message=it) } model.loadMore { scaffoldModel.update(message=it) }
}
} }
}
@Composable @Composable
private fun Association(associationDto: AssociationDto) { private fun Association(associationDto: AssociationDto) {
val context= LocalContext.current val context= LocalContext.current
Card(modifier = Modifier.clickable(onClick = { context.startActivity(Intent(context,AssociationActivity::class.java)) })) { Card(modifier = Modifier.clickable(onClick = { context.startActivity(Intent(context,AssociationActivity::class.java)) })) {
Image( Image(
painter = painterResource(id = R.drawable.association_list_border), painter = painterResource(id = R.drawable.association_list_border),
contentDescription = null contentDescription = null
) )
Row(modifier = Modifier.fillMaxWidth(), Row(modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.Center) { horizontalArrangement = Arrangement.Center) {
Text(text = associationDto.name) Text(text = associationDto.name)
}
} }
} }
} /**
* 社团检索
/** *
* 社团检索 */
* @Composable
*/ private fun AssociationSearch(model: ListViewModel = viewModel(),scaffoldModel: ScaffoldModel= viewModel()) {
@Composable
private fun AssociationSearch(model: ListViewModel = viewModel(),scaffoldModel: ScaffoldModel= viewModel()) {
Card(modifier = Modifier.padding(horizontal = 50.dp, vertical = 10.dp)) { Card(modifier = Modifier.padding(horizontal = 50.dp, vertical = 10.dp)) {
Column { Column {
BaseTextField(form = model.name,singeLine = true,modifier = Modifier.padding(horizontal = 10.dp)) BaseTextField(form = model.name,singeLine = true,modifier = Modifier.padding(horizontal = 10.dp))
BaseTextField(form = model.desc,singeLine = true,modifier = Modifier.padding(horizontal = 10.dp)) BaseTextField(form = model.desc,singeLine = true,modifier = Modifier.padding(horizontal = 10.dp))
Spacer( Spacer(
modifier = Modifier.height(10.dp) modifier = Modifier.height(10.dp)
) )
Row(horizontalArrangement = Arrangement.Center, modifier = Modifier.fillMaxWidth()) { Row(horizontalArrangement = Arrangement.Center, modifier = Modifier.fillMaxWidth()) {
OutlinedButton(onClick = { model.search { scaffoldModel.update(message=it) } }, modifier = Modifier.width(100.dp)) { OutlinedButton(onClick = { model.search { scaffoldModel.update(message=it) } }, modifier = Modifier.width(100.dp)) {
Text(text = model.searchDesc) Text(text = model.searchDesc)
}
} }
Spacer(
modifier = Modifier.height(10.dp)
)
} }
Spacer(
modifier = Modifier.height(10.dp)
)
} }
} }
} /**
* 通知
*
*/
@Composable
private fun Notification(mainViewModel: MainViewModel= viewModel(),scaffoldModel: ScaffoldModel= viewModel()) {
Row(
horizontalArrangement = Arrangement.End,
modifier = Modifier
.fillMaxWidth()
.padding(10.dp)
) {
IconButton(onClick = {
mainViewModel.openNotification { scaffoldModel.update(message=it) }
}) {
Icon(
painter = painterResource(id = R.drawable.ic_notification),
contentDescription = null
)
}
/**
* 通知
*
*/
@Composable
private fun Notification(mainViewModel: MainViewModel= viewModel(),scaffoldModel: ScaffoldModel= viewModel()) {
Row(
horizontalArrangement = Arrangement.End,
modifier = Modifier
.fillMaxWidth()
.padding(10.dp)
) {
IconButton(onClick = {
mainViewModel.openNotification { scaffoldModel.update(message=it) }
}) {
Icon(
painter = painterResource(id = R.drawable.ic_notification),
contentDescription = null
)
} }
} }
}
/** /**
* 圆角矩形边框 * 圆角矩形边框
* *
*/ */
@Composable @Composable
private fun MyBorder(content: @Composable BoxScope.() -> Unit) { private fun MyBorder(content: @Composable BoxScope.() -> Unit) {
Box(modifier = Modifier.padding(horizontal = 15.dp)) { Box(modifier = Modifier.padding(horizontal = 15.dp)) {
Box( Box(
modifier = Modifier modifier = Modifier
.border( .border(
width = 1.dp, width = 1.dp,
color = MaterialTheme.colors.onBackground, color = MaterialTheme.colors.onBackground,
shape = RoundedCornerShape(size = 20.dp) shape = RoundedCornerShape(size = 20.dp)
), ),
) { ) {
content() content()
}
} }
} }
}
/** /**
* 留言板 * 留言板
* *
*/ */
@Composable @Composable
private fun MessageBoard(model: MarqueeViewModel = viewModel(),mainViewModel:MainViewModel= viewModel(),scaffoldModel: ScaffoldModel= viewModel()) { private fun MessageBoard(model: MarqueeViewModel = viewModel(),mainViewModel:MainViewModel= viewModel(),scaffoldModel: ScaffoldModel= viewModel()) {
MyBorder { MyBorder {
Row( Row(
verticalAlignment = Alignment.CenterVertically verticalAlignment = Alignment.CenterVertically
) { ) {
IconButton(onClick = { mainViewModel.sendMessage { scaffoldModel.update(message=it) } }) { IconButton(onClick = { mainViewModel.sendMessage { scaffoldModel.update(message=it) } }) {
Icon( Icon(
painter = painterResource(id = R.drawable.ic_comments), painter = painterResource(id = R.drawable.ic_comments),
contentDescription = null, contentDescription = null,
) )
}
Row(
horizontalArrangement = Arrangement.Center,
modifier = Modifier
.fillMaxWidth()
) {
Marquee(model = model) { model, value ->
MarqueeText(
model = model,
offset = value
)
}
}
} }
}
}
/**
* 活动标题
*
*/
@Composable
private fun ClubActivitiesTitle() {
MyBorder {
Row( Row(
horizontalArrangement = Arrangement.Center,
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.height(50.dp),
horizontalArrangement = Arrangement.Center,
verticalAlignment = Alignment.CenterVertically
) { ) {
Marquee(model = model) { model, value -> Text(
MarqueeText( text = "超级课程表X滴滴出行-了不起的社团",
model = model, style = MaterialTheme.typography.h6,
offset = value overflow = TextOverflow.Ellipsis,
) maxLines = 1
} )
} }
} }
} }
}
/**
* 活动标题 /**
* * 带介绍活动海报
*/ *
@Composable */
private fun ClubActivitiesTitle() { @Composable
MyBorder { private fun PosterWithDesc(model: CarouselViewModel = viewModel()) {
Row( Carousel(model = model) {
modifier = Modifier Column {
.fillMaxWidth() Poster(modifier = Modifier
.height(50.dp), .weight(0.6F)
horizontalArrangement = Arrangement.Center, .fillMaxWidth(),id = it)
verticalAlignment = Alignment.CenterVertically DescCard(
) { modifier = Modifier
Text( .weight(0.4F)
text = "超级课程表X滴滴出行-了不起的社团", .fillMaxWidth(),
style = MaterialTheme.typography.h6, content = randomChinese(500)
overflow = TextOverflow.Ellipsis, )
maxLines = 1 }
)
} }
} }
}
/** @Preview(showBackground = true)
* 带介绍活动海报 @Composable
* fun DefaultPreview() {
*/ CSAMSTheme {
@Composable Text(text = "666")
private fun PosterWithDesc(model: CarouselViewModel = viewModel()) {
Carousel(model = model) {
Column {
Poster(modifier = Modifier
.weight(0.6F)
.fillMaxWidth(),id = it)
DescCard(
modifier = Modifier
.weight(0.4F)
.fillMaxWidth()
)
} }
} }
} }
@Preview(showBackground = true)
@Composable
fun DefaultPreview() {
CSAMSTheme {
Text(text = "666")
}
}

@ -1,19 +1,18 @@
package com.gyf.csams.uikit package com.gyf.csams.uikit
import android.app.Activity
import androidx.annotation.DrawableRes import androidx.annotation.DrawableRes
import androidx.compose.animation.Crossfade import androidx.compose.animation.Crossfade
import androidx.compose.animation.animateColor import androidx.compose.animation.animateColor
import androidx.compose.animation.core.* import androidx.compose.animation.core.*
import androidx.compose.foundation.Image import androidx.compose.foundation.Image
import androidx.compose.foundation.border
import androidx.compose.foundation.clickable import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.* import androidx.compose.foundation.layout.*
import androidx.compose.foundation.text.KeyboardActions import androidx.compose.foundation.text.KeyboardActions
import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.material.* import androidx.compose.material.*
import androidx.compose.runtime.Composable import androidx.compose.runtime.*
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.State
import androidx.compose.runtime.getValue
import androidx.compose.runtime.livedata.observeAsState import androidx.compose.runtime.livedata.observeAsState
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
@ -27,6 +26,8 @@ import androidx.compose.ui.text.input.ImeAction
import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.viewmodel.compose.viewModel import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.navigation.NavHostController import androidx.navigation.NavHostController
import androidx.navigation.compose.navigate import androidx.navigation.compose.navigate
@ -35,7 +36,6 @@ import com.gyf.csams.APP
import com.gyf.csams.R import com.gyf.csams.R
import com.gyf.csams.main.model.CarouselViewModel import com.gyf.csams.main.model.CarouselViewModel
import com.gyf.csams.main.model.MarqueeViewModel import com.gyf.csams.main.model.MarqueeViewModel
import com.gyf.csams.uikit.theme.CSAMSTheme
import com.orhanobut.logger.Logger import com.orhanobut.logger.Logger
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
@ -90,7 +90,7 @@ enum class MainMenu(
* @param onClick * @param onClick
*/ */
@Composable @Composable
fun MenuIconButton(_menu: MainMenu, menu: MainMenu, modifier: Modifier, onClick: () -> Unit) { fun MenuIconButton(_menu: MainMenu, menu: MainMenu, modifier: Modifier=Modifier, onClick: () -> Unit) {
Row( Row(
modifier = modifier, horizontalArrangement = Arrangement.Center modifier = modifier, horizontalArrangement = Arrangement.Center
) { ) {
@ -113,30 +113,74 @@ fun MenuIconButton(_menu: MainMenu, menu: MainMenu, modifier: Modifier, onClick:
@Composable @Composable
fun MainBottomAppBar(menu: MainMenu, nav: NavHostController, modifier: Modifier = Modifier) { fun MainBottomAppBar(menu: MainMenu, nav: NavHostController, modifier: Modifier = Modifier) {
BottomAppBar(backgroundColor = MaterialTheme.colors.background, modifier = modifier) { BottomAppBar(backgroundColor = MaterialTheme.colors.background, modifier = modifier) {
//图标宽度平等分 Row(Modifier.fillMaxWidth(),horizontalArrangement = Arrangement.SpaceBetween) {
MenuIconButton(_menu = menu, menu = MainMenu.Main,
val weight = 1 / (MainMenu.values().size * 1.0f)
Row(Modifier.fillMaxWidth()) {
MenuIconButton(_menu = menu, menu = MainMenu.Main, Modifier.weight(weight),
onClick = { nav.navigate(MainMenu.Main.name) }) onClick = { nav.navigate(MainMenu.Main.name) })
MenuIconButton(_menu = menu, menu = MainMenu.List, Modifier.weight(weight), MenuIconButton(_menu = menu, menu = MainMenu.List,
onClick = { nav.navigate(MainMenu.List.name) }) onClick = { nav.navigate(MainMenu.List.name) })
MenuIconButton(_menu = menu, menu = MainMenu.Center, Modifier.weight(weight), MenuIconButton(_menu = menu, menu = MainMenu.Center,
onClick = { nav.navigate(MainMenu.Center.name) }) onClick = { nav.navigate(MainMenu.Center.name) })
} }
} }
} }
/**
* 顶部菜单
*
*/
interface TopMenuInterface<T:TopBarMenu>{
/**
* 当前菜单
*/
val _currentMenu: MutableLiveData<T>
val currentMenu: LiveData<T>
/**
* 切换顶部菜单
*
* @param menu
*/
fun clickMenu(menu:T){
_currentMenu.value=menu
}
}
interface TopBarMenu{
val menuName:String
val name:String
}
interface StartMenu<T>{
val startMenu:T
}
/** /**
* 社团菜单 * 社团菜单
* *
*/ */
enum class AssociationMenu(val menuName: String) { enum class AssociationMenu(override val menuName: String):TopBarMenu {
member("社团成员"), Member("社团成员"),
main("社团主页"), Main("社团主页"),
list("活动列表") ActivityList("活动列表");
companion object Menu:StartMenu<AssociationMenu>{
override val startMenu: AssociationMenu = Main
}
}
enum class ActivityDetailMenu(override val menuName:String):TopBarMenu{
Info("活动信息"),
Photo("相册"),
Member("活动成员"),
BBS("交流区");
companion object Menu:StartMenu<ActivityDetailMenu>{
override val startMenu: ActivityDetailMenu = Info
}
} }
/** /**
@ -144,51 +188,56 @@ enum class AssociationMenu(val menuName: String) {
* *
*/ */
@Composable @Composable
fun AssociationAppBar( fun TextTopAppBar(
menu: AssociationMenu, nav:NavHostController,
nav: NavHostController, currentMenuName:String,
back: () -> Unit, menuNames:Array<out TopBarMenu>,
dropMenu: () -> Unit, iconMenu: (() -> Unit)? = null,
content:@Composable () -> Unit @DrawableRes icon:Int = R.drawable.ic_configuration,
dropMenuContent:@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)) { val context= LocalContext.current as Activity
Icon( IconButton(onClick = {context.onBackPressed()}, modifier = Modifier.weight(0.1F)) {
painter = painterResource(id = R.drawable.ic_arrow_left), Icon(
contentDescription = null painter = painterResource(id = R.drawable.ic_arrow_left),
) contentDescription = null
} )
Row( }
modifier = Modifier Row(
.weight(0.8F) modifier = Modifier
.fillMaxHeight(), .weight(0.8F)
horizontalArrangement = Arrangement.Center, .fillMaxHeight(),
verticalAlignment = Alignment.CenterVertically horizontalArrangement = Arrangement.SpaceAround,
) { verticalAlignment = Alignment.CenterVertically
val menus = AssociationMenu.values() ) {
menus.forEach { menuNames.forEach {
Row( Row(
modifier = Modifier modifier = Modifier
.weight(1F / menus.size) .weight(1F / menuNames.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 (currentMenuName == it.menuName) MaterialTheme.colors.primary else MaterialTheme.colors.onBackground
) )
}
} }
} }
IconButton(onClick = dropMenu, modifier = Modifier.weight(0.1F)) { }
if(iconMenu!=null) {
IconButton(onClick = iconMenu, modifier = Modifier.weight(0.1F)) {
Icon( Icon(
painter = painterResource(id = R.drawable.ic_configuration), painter = painterResource(id = icon),
contentDescription = null contentDescription = null
) )
} }
}else{
Spacer(modifier = Modifier.weight(0.1F))
} }
content() }
if(iconMenu!=null) dropMenuContent()
} }
} }
@ -383,26 +432,34 @@ fun ShowSnackbar(model: ScaffoldModel = viewModel(), scaffoldState: ScaffoldStat
*/ */
enum class BackgroundImage(@DrawableRes val id: Int) { enum class BackgroundImage(@DrawableRes val id: Int) {
//主页 //主页
main(R.drawable.mb_bg_fb_08), Main(R.drawable.mb_bg_fb_08),
//社团列表 //社团列表
list(R.drawable.mb_bg_fb_07), AssociationList(R.drawable.mb_bg_fb_07),
//个人中心 //个人中心
center(R.drawable.mb_bg_fb_28), Center(R.drawable.mb_bg_fb_28),
//注册社团 //注册社团
reg_association(R.drawable.mb_bg_fb_06), RegAssociation(R.drawable.mb_bg_fb_06),
//社团主界面 //社团主界面
association_main(R.drawable.mb_bg_fb_25_180), AssociationMain(R.drawable.mb_bg_fb_25_180),
//社团重命名 //社团重命名
rename(R.drawable.mb_bg_fb_27), Rename(R.drawable.mb_bg_fb_27),
//社团题库管理 //社团题库管理
exam(R.drawable.mb_bg_fb_02) Exam(R.drawable.mb_bg_fb_09),
//活动信息
ActivityInfo(R.drawable.mb_bg_fb_01),
//活动相册
ActivityPhoto(R.drawable.mb_bg_fb_02),
//活动成员
ActivityMember(R.drawable.mb_bg_fb_03),
//交流区
ActivityBBS(R.drawable.mb_bg_fb_04)
} }
/** /**
@ -493,47 +550,78 @@ fun Poster(modifier: Modifier = Modifier, @DrawableRes id: Int) {
* *
*/ */
@Composable @Composable
fun DescCard(modifier: Modifier) { fun DescCard(modifier: Modifier,content:String) {
Card( Card(
modifier = modifier, modifier = modifier,
backgroundColor = Color.Transparent backgroundColor = Color.Transparent
) { ) {
Image( Box {
painter = painterResource(id = R.drawable.hot_activity_desc_background), Image(
contentDescription = null painter = painterResource(id = R.drawable.hot_activity_desc_background),
) contentDescription = null,
contentScale = ContentScale.FillBounds,
Row(modifier = Modifier.fillMaxWidth()) { modifier = Modifier.fillMaxSize()
Spacer(modifier = Modifier.weight(0.2F)) )
Column( Column(modifier = Modifier.fillMaxSize().padding(horizontal = 10.dp)) {
modifier = Modifier Spacer(modifier = Modifier.weight(0.15F))
.weight(0.5F)
) {
Spacer(modifier = Modifier.weight(0.1F))
Text( Text(
text = "文字对任何界面都属于核心内容,而利用 Jetpack Compose 可以更轻松地显示或写入文字。Compose 可以充分利用其构建块的组合,这意味着您无需覆盖各种属性和方法,也无需扩展大型类,即可拥有特定的可组合项设计以及按您期望的方式运行的逻辑。" modifier = Modifier.weight(0.65F),
.repeat(10), overflow = TextOverflow.Ellipsis, text = content,
modifier = Modifier.weight(0.8F) overflow = TextOverflow.Ellipsis
) )
Spacer(modifier = Modifier.weight(0.1F)) Spacer(modifier = Modifier.weight(0.15F))
} }
Spacer(modifier = Modifier.weight(0.2F))
} }
} }
} }
//@Preview
@Preview
@Composable @Composable
fun AnimationTextPreview() { fun AnimationTextPreview() {
AnimationText(text = "6666") AnimationText(text = "6666")
} }
//@Preview @Preview
@Composable @Composable
fun MyBottomAppBarPreview() { fun MyBottomAppBarPreview() {
CSAMSTheme { val arr:List<Arrangement.Horizontal> = listOf(
Arrangement.Start,
Arrangement.End,
Arrangement.Center,
Arrangement.SpaceBetween,
Arrangement.SpaceAround,
Arrangement.SpaceEvenly
)
var i by remember {
mutableStateOf(3)
}
Column(modifier = Modifier.fillMaxSize()) {
Row(modifier = Modifier.fillMaxWidth(),horizontalArrangement = Arrangement.SpaceEvenly) {
OutlinedButton(onClick = { i += 1 }) {
Text(text = "添加元素")
}
if(i>1) {
OutlinedButton(onClick = { i -= 1 }) {
Text(text = "删除元素")
}
}
}
arr.forEach {
Column(modifier = Modifier
.weight(1F / arr.size)
.border(width = 1.dp, color = MaterialTheme.colors.background)) {
Row(modifier = Modifier.fillMaxWidth(),horizontalArrangement = Arrangement.Center) {
Text(text = "$it",style = MaterialTheme.typography.h5)
}
Row(modifier = Modifier.fillMaxSize(),
horizontalArrangement = it,
verticalAlignment = Alignment.CenterVertically) {
repeat(i) {
Text(text = "$it", style = MaterialTheme.typography.h3)
}
}
}
}
} }
} }

@ -0,0 +1,55 @@
package com.gyf.csams.util
import okhttp3.internal.toHexString
import java.text.SimpleDateFormat
import java.util.*
fun randomNum(length:Int=8):String{
return List(length) {('0' .. '9').random()}.joinToString("")
}
fun encode(char: Char) = "\\u${char.toInt().toHexString()}"
//String ->unicode
fun String.encodeUnicode(text: String) = text
.toCharArray().joinToString(separator = "", truncated = "") { encode(it) }
//unicode ->String
fun String.decodeUnicode(): String {
fun decode1(unicode: String) = unicode.toInt(16).toChar()
val unicodes = this.split("\\u").mapNotNull { if (it.isNotBlank()) decode1(it) else null }
return String(unicodes.toCharArray())
}
val CHINESE_UNICODE_AREA=0X4e00..0X9fa5
/**
* 随机中文
*
* @param length
* @return
*/
fun randomChinese(length:Int=8):String{
return List(length){ "\\u${CHINESE_UNICODE_AREA.random().toHexString()}".decodeUnicode() }.joinToString("")
}
const val DATETIME_FORMAT="yyyy-MM-dd HH:mm"
const val START_TIME="2021-01-01 00:00"
val FORMAT=SimpleDateFormat(DATETIME_FORMAT,Locale.US)
val startUnix= FORMAT.parse(START_TIME)?.time
fun randomDateTime():Date{
if (startUnix != null) {
return Date("${(startUnix..Date().time).random()}".toLong())
}else{
throw IllegalArgumentException("生成随机失败,无法获取起始时间")
}
}
fun Date.format():String{
return FORMAT.format(this)
}

@ -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="M704,341.33h64a64,64 0,0 1,64 64v362.67a64,64 0,0 1,-64 64H256a64,64 0,0 1,-64 -64V405.33a64,64 0,0 1,64 -64h64v64h-64v362.67h512V405.33h-64v-64zM517.65,124.63l150.83,150.83 -45.23,45.27 -74.03,-74.01v304.77h-64V247.62l-73.17,73.13 -45.25,-45.25 150.83,-150.85z"/>
</vector>

@ -3,6 +3,7 @@ package com.gyf.csams
import com.google.gson.Gson import com.google.gson.Gson
import com.google.gson.reflect.TypeToken import com.google.gson.reflect.TypeToken
import com.gyf.csams.util.ApiResponse import com.gyf.csams.util.ApiResponse
import com.gyf.csams.util.randomChinese
import org.junit.Assert.assertEquals import org.junit.Assert.assertEquals
import org.junit.Test import org.junit.Test
@ -32,16 +33,16 @@ class ExampleUnitTest {
println(e.body) println(e.body)
} }
@Test
fun testYear(){
repeat(10,{
println(it)
})
}
@Test @Test
fun testCharRange(){ fun testCharRange(){
println(('A'..'D').map { "选项$it" }) repeat(100){
println(randomChinese())
}
// println(java.time.format.DateTimeFormatter.ISO_INSTANT
// .format(java.time.Instant.ofEpochMilli(1532358895000)))
} }
} }

Loading…
Cancel
Save