parent
31e1d9fd92
commit
4ee124d927
@ -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 { |
||||||
|
|
||||||
|
} |
@ -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) |
||||||
|
) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -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> |
Loading…
Reference in new issue