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