增加活动详情界面

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. 31
      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. 471
      app/src/main/java/com/gyf/csams/association/ui/ExamActivity.kt
  14. 112
      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.
val appContext = InstrumentationRegistry.getInstrumentation().targetContext
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"
android:exported="true">
</activity>
<!--活动详情-->
<activity android:name=".activity.ui.ActivityDetailActivity"
android:exported="true">
</activity>
</application>
</manifest>

@ -5,6 +5,11 @@ interface UrlPath{
fun build():String
}
/**
* 帐号接口
*
* @property path
*/
enum class AccountApi(val path: String):UrlPath{
register("/register"),
checkId("/register/checkId"),
@ -17,7 +22,10 @@ enum class AccountApi(val path: String):UrlPath{
}
}
/**
* 构建服务端请求接口地址
*
*/
class Api {
companion object{
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.ViewModel
import androidx.lifecycle.viewModelScope
import com.gyf.csams.NOT_IMPL_TIP
import com.gyf.csams.uikit.AssociationMenu
import com.gyf.csams.uikit.ScrollList
import com.gyf.csams.uikit.StringForm
import com.gyf.csams.uikit.TopMenuInterface
import com.orhanobut.logger.Logger
import kotlinx.coroutines.launch
class AssociationViewModel:ViewModel() {
/**
* 当前菜单
*/
private val _currentMenu=MutableLiveData<AssociationMenu>()
val currentMenu:LiveData<AssociationMenu> = _currentMenu
class AssociationViewModel:ViewModel(),TopMenuInterface<AssociationMenu>{
override val _currentMenu: MutableLiveData<AssociationMenu> = MutableLiveData()
override val currentMenu: LiveData<AssociationMenu> = _currentMenu
/**
* 下拉菜单状态
@ -23,14 +24,7 @@ class AssociationViewModel:ViewModel() {
private val _expanded=MutableLiveData(false)
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){
Logger.i("搜索条件[成员姓名:${name.formValue.value}]")
callback("功能尚未实现,敬请期待")
callback(NOT_IMPL_TIP)
}
}
@ -131,11 +125,13 @@ class HistoryActViewModel: ScrollList<HistoryActVo>() {
}
override fun load() {
_data.value?.apply {
repeat(initSize){
add(HistoryActVo(name = "活动${size+1}"))
viewModelScope.launch {
_data.value?.apply {
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.MutableLiveData
import androidx.lifecycle.viewModelScope
import com.gyf.csams.NOT_IMPL_TIP
import com.gyf.csams.uikit.ScrollList
import com.gyf.csams.uikit.StringForm
import kotlinx.coroutines.launch
@ -159,7 +160,7 @@ class ExamViewModel:ScrollList<Exam>() {
* @param callback
*/
fun updateExam(callback: (message: String) -> Unit){
callback("功能尚未实现,敬请期待")
callback(NOT_IMPL_TIP)
}
/**
@ -168,7 +169,7 @@ class ExamViewModel:ScrollList<Exam>() {
* @param callback
*/
fun postAnswer(callback: (message: String) -> Unit){
callback("功能尚未实现,敬请期待")
callback(NOT_IMPL_TIP)
}
/**
@ -220,7 +221,7 @@ class ExamViewModel:ScrollList<Exam>() {
// callback("成功加载更多题目")
// }
// callback("功能尚未实现,敬请期待")
// callback(NOT_IMPL_TIP)
}
fun addQuestion() {

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

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

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

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

@ -50,7 +50,7 @@ class RegAssociationActivity: ComponentActivity(){
CSAMSTheme {
Body {
scaffoldState ->
MainFrame(background = { Background(BackgroundImage.reg_association,alpha = 0.5F) }) {
MainFrame(background = { Background(BackgroundImage.RegAssociation,alpha = 0.5F) }) {
Spacer(
modifier = Modifier
.weight(0.1F)
@ -79,145 +79,147 @@ class RegAssociationActivity: ComponentActivity(){
}
}
}
/**
* 社团Logo
*
* @param modifier
*/
@Composable
private fun Logo(model:RegAssociationViewModel= viewModel(),modifier: Modifier) {
val photoIntent=Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI)
photoIntent.type = "image/*"
val uri:Uri? by model.picture.observeAsState()
val resultLauncher=rememberLauncherForActivityResult(contract = ActivityResultContracts.StartActivityForResult()) {
when(it.resultCode){
Activity.RESULT_OK->{
Logger.i("uri=${it.data?.data}")
it.data?.data?.let { it1 -> model.setPicture(it1) }
/**
* 社团Logo
*
* @param modifier
*/
@Composable
private fun Logo(model:RegAssociationViewModel= viewModel(),modifier: Modifier) {
val photoIntent=Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI)
photoIntent.type = "image/*"
val uri:Uri? by model.picture.observeAsState()
val resultLauncher=rememberLauncherForActivityResult(contract = ActivityResultContracts.StartActivityForResult()) {
when(it.resultCode){
Activity.RESULT_OK->{
Logger.i("uri=${it.data?.data}")
it.data?.data?.let { it1 -> model.setPicture(it1) }
}
}
}
}
val loadPicture={
//model.loadPicture(context)
resultLauncher.launch(photoIntent)
}
val loadPicture={
//model.loadPicture(context)
resultLauncher.launch(photoIntent)
}
val launcher = rememberLauncherForActivityResult(
ActivityResultContracts.RequestPermission()
) { isGranted: Boolean ->
if (isGranted) {
// Permission Accepted: Do something
loadPicture()
} else {
// Permission Denied: Do something
Logger.w(model.deninedPermission)
val launcher = rememberLauncherForActivityResult(
ActivityResultContracts.RequestPermission()
) { isGranted: Boolean ->
if (isGranted) {
// Permission Accepted: Do something
loadPicture()
} else {
// Permission Denied: Do something
Logger.w(model.deninedPermission)
}
}
}
val context= LocalContext.current
val context= LocalContext.current
Box(contentAlignment = Alignment.Center,modifier = modifier) {
Row(verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.Center,modifier = Modifier
.fillMaxSize()
.border(width = 1.dp, color = Color.Black)) {
Box(contentAlignment = Alignment.Center,modifier = modifier) {
Row(verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.Center,modifier = Modifier
.fillMaxSize()
.border(width = 1.dp, color = Color.Black)) {
if (uri == null) {
OutlinedButton(onClick = {
when (PackageManager.PERMISSION_GRANTED) {
ContextCompat.checkSelfPermission(
context,
Manifest.permission.READ_EXTERNAL_STORAGE
) -> {
// 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 = {
if (uri == null) {
OutlinedButton(onClick = {
when (PackageManager.PERMISSION_GRANTED) {
ContextCompat.checkSelfPermission(
context,
Manifest.permission.READ_EXTERNAL_STORAGE
) -> {
// Some works that require permission
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{
Text(text = model.errorPicture)
}else{
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 = {
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 Title(model:RegAssociationViewModel= viewModel()){
Row(modifier = Modifier.fillMaxWidth(),horizontalArrangement = Arrangement.Center) {
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())
}
/**
* 菜单标题
*
*/
@Composable
private fun Title(model:RegAssociationViewModel= viewModel()){
Row(modifier = Modifier.fillMaxWidth(),horizontalArrangement = Arrangement.Center) {
Text(text = model.frameDesc,style = MaterialTheme.typography.h4)
/**
* 社团简介
* @param model
*/
@Composable
private fun Desc(model:RegAssociationViewModel= viewModel(),modifier:Modifier){
BaseTextField(form = model.desc,modifier = modifier)
}
}
/**
* 社团名称
* @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.ViewModel
import androidx.lifecycle.viewModelScope
import com.gyf.csams.NOT_IMPL_TIP
import com.gyf.csams.R
import com.gyf.csams.uikit.ScrollList
import com.gyf.csams.uikit.StringForm
@ -85,7 +86,7 @@ class MainViewModel:ViewModel(){
*
*/
fun sendMessage(callback: (value: String) -> Unit){
callback("功能尚未实现,敬请期待")
callback(NOT_IMPL_TIP)
}
/**
@ -94,7 +95,7 @@ class MainViewModel:ViewModel(){
* @param callback
*/
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){
Logger.i("搜索条件[社团名称:${name.formValue.value},社团简介:${desc.formValue.value}]")
callback("功能尚未实现,敬请期待")
callback(NOT_IMPL_TIP)
}
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.uikit.*
import com.gyf.csams.uikit.theme.CSAMSTheme
import com.gyf.csams.util.randomChinese
/**
@ -66,328 +67,331 @@ class MainActivity : ComponentActivity() {
}
}
/**
* 个人中心
*
*/
@Composable
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) {
Column(modifier = Modifier
.weight(0.33F)
.fillMaxWidth(),verticalArrangement = Arrangement.Bottom) {
Card(backgroundColor = MaterialTheme.colors.background) {
val context= LocalContext.current
Row(modifier = Modifier
.fillMaxWidth()
.clickable(onClick = {
context.startActivity(Intent(context, AssociationActivity::class.java))
}),verticalAlignment = Alignment.CenterVertically) {
Spacer(modifier = Modifier.weight(0.33F))
Row(modifier = Modifier.weight(0.33F),horizontalArrangement = Arrangement.Center) {
Text(text = model.myAssociationDesc)
}
Row(modifier = Modifier.weight(0.33F),horizontalArrangement = Arrangement.End) {
Icon(
painter = painterResource(id = R.drawable.ic_arrow_right),
contentDescription = null,
modifier = Modifier.size(50.dp)
)
/**
* 个人中心
*
*/
@Composable
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) {
Column(modifier = Modifier
.weight(0.33F)
.fillMaxWidth(),verticalArrangement = Arrangement.Bottom) {
Card(backgroundColor = MaterialTheme.colors.background) {
val context= LocalContext.current
Row(modifier = Modifier
.fillMaxWidth()
.clickable(onClick = {
context.startActivity(Intent(context, AssociationActivity::class.java))
}),verticalAlignment = Alignment.CenterVertically) {
Spacer(modifier = Modifier.weight(0.33F))
Row(modifier = Modifier.weight(0.33F),horizontalArrangement = Arrangement.Center) {
Text(text = model.myAssociationDesc)
}
Row(modifier = Modifier.weight(0.33F),horizontalArrangement = Arrangement.End) {
Icon(
painter = painterResource(id = R.drawable.ic_arrow_right),
contentDescription = null,
modifier = Modifier.size(50.dp)
)
}
}
}
}
}
Spacer(modifier = Modifier
.weight(0.66F)
.fillMaxWidth())
}
Spacer(modifier = Modifier
.weight(0.66F)
.fillMaxWidth())
}
}
/**
* 主界面
*/
@Composable
private fun Main(navController: NavHostController) {
MainFrame(background = { Background(image = BackgroundImage.main) }, mainMenu = MainMenu.Main, nav = navController) {
Column(modifier = Modifier.weight(0.33F)) {
Notification()
MessageBoard()
Spacer(modifier = Modifier.height(10.dp))
ClubActivitiesTitle()
Spacer(modifier = Modifier.height(10.dp))
}
Column(modifier = Modifier.weight(0.66F)) {
PosterWithDesc()
/**
* 主界面
*/
@Composable
private fun Main(navController: NavHostController) {
MainFrame(background = { Background(image = BackgroundImage.Main) }, mainMenu = MainMenu.Main, nav = navController) {
Column(modifier = Modifier.weight(0.33F)) {
Notification()
MessageBoard()
Spacer(modifier = Modifier.height(10.dp))
ClubActivitiesTitle()
Spacer(modifier = Modifier.height(10.dp))
}
Column(modifier = Modifier.weight(0.66F)) {
PosterWithDesc()
}
}
}
}
/**
* 社团列表
*
* @param navController
*/
@Composable
private fun AssociationList(navController: NavHostController) {
MainFrame(
background = { Background(image = BackgroundImage.list) },
mainMenu = MainMenu.List,
nav = navController
) {
RegisterAssociation()
AssociationSearch()
AssociationListBody()
/**
* 社团列表
*
* @param navController
*/
@Composable
private fun AssociationList(navController: NavHostController) {
MainFrame(
background = { Background(image = BackgroundImage.AssociationList) },
mainMenu = MainMenu.List,
nav = navController
) {
RegisterAssociation()
AssociationSearch()
AssociationListBody()
}
}
}
/**
* 注册社团按钮
*
*/
@Composable
private fun RegisterAssociation() {
val context= LocalContext.current
Row(
horizontalArrangement = Arrangement.End,
modifier = Modifier
.fillMaxWidth()
.padding(10.dp)
) {
IconButton(onClick = {
context.startActivity(Intent(context, RegAssociationActivity::class.java))
}) {
Icon(
painter = painterResource(id = R.drawable.ic_add_fill),
contentDescription = null,
modifier = Modifier.size(50.dp),
)
/**
* 注册社团按钮
*
*/
@Composable
private fun RegisterAssociation() {
val context= LocalContext.current
Row(
horizontalArrangement = Arrangement.End,
modifier = Modifier
.fillMaxWidth()
.padding(10.dp)
) {
IconButton(onClick = {
context.startActivity(Intent(context, RegAssociationActivity::class.java))
}) {
Icon(
painter = painterResource(id = R.drawable.ic_add_fill),
contentDescription = null,
modifier = Modifier.size(50.dp),
)
}
}
}
}
/**
* 社团列表
*
*/
@Composable
private fun AssociationListBody(model: ListViewModel = viewModel(),scaffoldModel: ScaffoldModel= viewModel()) {
val associationList: MutableList<AssociationDto>? by model.associationDto.observeAsState()
val listState = rememberLazyListState()
LazyColumn(state = listState) {
associationList?.chunked(2)?.forEach {
item{
Row {
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) {
/**
* 社团列表
*
*/
@Composable
private fun AssociationListBody(model: ListViewModel = viewModel(),scaffoldModel: ScaffoldModel= viewModel()) {
val associationList: MutableList<AssociationDto>? by model.associationDto.observeAsState()
val listState = rememberLazyListState()
LazyColumn(state = listState) {
associationList?.chunked(2)?.forEach {
item{
Row {
Spacer(modifier = Modifier.weight(0.1F))
Box(modifier = Modifier.weight(0.35F)) {
Association(associationDto = it[1])
Association(associationDto = it[0])
}
}else{
Box(modifier = Modifier
.weight(0.35F)
.border(width = 1.dp, color = MaterialTheme.colors.onBackground))
Spacer(modifier = Modifier.weight(0.05F))
if(it.size==2) {
Box(modifier = Modifier.weight(0.35F)) {
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){
model.loadMore { scaffoldModel.update(message=it) }
if(listState.layoutInfo.totalItemsCount-listState.firstVisibleItemIndex==model.associationListSize/2-1){
model.loadMore { scaffoldModel.update(message=it) }
}
}
}
@Composable
private fun Association(associationDto: AssociationDto) {
val context= LocalContext.current
Card(modifier = Modifier.clickable(onClick = { context.startActivity(Intent(context,AssociationActivity::class.java)) })) {
Image(
painter = painterResource(id = R.drawable.association_list_border),
contentDescription = null
)
Row(modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.Center) {
Text(text = associationDto.name)
@Composable
private fun Association(associationDto: AssociationDto) {
val context= LocalContext.current
Card(modifier = Modifier.clickable(onClick = { context.startActivity(Intent(context,AssociationActivity::class.java)) })) {
Image(
painter = painterResource(id = R.drawable.association_list_border),
contentDescription = null
)
Row(modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.Center) {
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)) {
Column {
Card(modifier = Modifier.padding(horizontal = 50.dp, vertical = 10.dp)) {
Column {
BaseTextField(form = model.name,singeLine = true,modifier = Modifier.padding(horizontal = 10.dp))
BaseTextField(form = model.desc,singeLine = true,modifier = Modifier.padding(horizontal = 10.dp))
Spacer(
modifier = Modifier.height(10.dp)
)
Row(horizontalArrangement = Arrangement.Center, modifier = Modifier.fillMaxWidth()) {
OutlinedButton(onClick = { model.search { scaffoldModel.update(message=it) } }, modifier = Modifier.width(100.dp)) {
Text(text = model.searchDesc)
BaseTextField(form = model.name,singeLine = true,modifier = Modifier.padding(horizontal = 10.dp))
BaseTextField(form = model.desc,singeLine = true,modifier = Modifier.padding(horizontal = 10.dp))
Spacer(
modifier = Modifier.height(10.dp)
)
Row(horizontalArrangement = Arrangement.Center, modifier = Modifier.fillMaxWidth()) {
OutlinedButton(onClick = { model.search { scaffoldModel.update(message=it) } }, modifier = Modifier.width(100.dp)) {
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
private fun MyBorder(content: @Composable BoxScope.() -> Unit) {
Box(modifier = Modifier.padding(horizontal = 15.dp)) {
Box(
modifier = Modifier
.border(
width = 1.dp,
color = MaterialTheme.colors.onBackground,
shape = RoundedCornerShape(size = 20.dp)
),
) {
content()
/**
* 圆角矩形边框
*
*/
@Composable
private fun MyBorder(content: @Composable BoxScope.() -> Unit) {
Box(modifier = Modifier.padding(horizontal = 15.dp)) {
Box(
modifier = Modifier
.border(
width = 1.dp,
color = MaterialTheme.colors.onBackground,
shape = RoundedCornerShape(size = 20.dp)
),
) {
content()
}
}
}
}
/**
* 留言板
*
*/
@Composable
private fun MessageBoard(model: MarqueeViewModel = viewModel(),mainViewModel:MainViewModel= viewModel(),scaffoldModel: ScaffoldModel= viewModel()) {
MyBorder {
Row(
verticalAlignment = Alignment.CenterVertically
) {
/**
* 留言板
*
*/
@Composable
private fun MessageBoard(model: MarqueeViewModel = viewModel(),mainViewModel:MainViewModel= viewModel(),scaffoldModel: ScaffoldModel= viewModel()) {
MyBorder {
Row(
verticalAlignment = Alignment.CenterVertically
) {
IconButton(onClick = { mainViewModel.sendMessage { scaffoldModel.update(message=it) } }) {
Icon(
painter = painterResource(id = R.drawable.ic_comments),
contentDescription = null,
)
IconButton(onClick = { mainViewModel.sendMessage { scaffoldModel.update(message=it) } }) {
Icon(
painter = painterResource(id = R.drawable.ic_comments),
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(
horizontalArrangement = Arrangement.Center,
modifier = Modifier
.fillMaxWidth()
.height(50.dp),
horizontalArrangement = Arrangement.Center,
verticalAlignment = Alignment.CenterVertically
) {
Marquee(model = model) { model, value ->
MarqueeText(
model = model,
offset = value
)
}
Text(
text = "超级课程表X滴滴出行-了不起的社团",
style = MaterialTheme.typography.h6,
overflow = TextOverflow.Ellipsis,
maxLines = 1
)
}
}
}
}
/**
* 活动标题
*
*/
@Composable
private fun ClubActivitiesTitle() {
MyBorder {
Row(
modifier = Modifier
.fillMaxWidth()
.height(50.dp),
horizontalArrangement = Arrangement.Center,
verticalAlignment = Alignment.CenterVertically
) {
Text(
text = "超级课程表X滴滴出行-了不起的社团",
style = MaterialTheme.typography.h6,
overflow = TextOverflow.Ellipsis,
maxLines = 1
)
/**
* 带介绍活动海报
*
*/
@Composable
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(),
content = randomChinese(500)
)
}
}
}
}
/**
* 带介绍活动海报
*
*/
@Composable
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")
}
}
}
@Preview(showBackground = true)
@Composable
fun DefaultPreview() {
CSAMSTheme {
Text(text = "666")
}
}

@ -1,19 +1,18 @@
package com.gyf.csams.uikit
import android.app.Activity
import androidx.annotation.DrawableRes
import androidx.compose.animation.Crossfade
import androidx.compose.animation.animateColor
import androidx.compose.animation.core.*
import androidx.compose.foundation.Image
import androidx.compose.foundation.border
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.text.KeyboardActions
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.material.*
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.State
import androidx.compose.runtime.getValue
import androidx.compose.runtime.*
import androidx.compose.runtime.livedata.observeAsState
import androidx.compose.ui.Alignment
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.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.navigation.NavHostController
import androidx.navigation.compose.navigate
@ -35,7 +36,6 @@ import com.gyf.csams.APP
import com.gyf.csams.R
import com.gyf.csams.main.model.CarouselViewModel
import com.gyf.csams.main.model.MarqueeViewModel
import com.gyf.csams.uikit.theme.CSAMSTheme
import com.orhanobut.logger.Logger
import kotlinx.coroutines.launch
@ -90,7 +90,7 @@ enum class MainMenu(
* @param onClick
*/
@Composable
fun MenuIconButton(_menu: MainMenu, menu: MainMenu, modifier: Modifier, onClick: () -> Unit) {
fun MenuIconButton(_menu: MainMenu, menu: MainMenu, modifier: Modifier=Modifier, onClick: () -> Unit) {
Row(
modifier = modifier, horizontalArrangement = Arrangement.Center
) {
@ -113,30 +113,74 @@ fun MenuIconButton(_menu: MainMenu, menu: MainMenu, modifier: Modifier, onClick:
@Composable
fun MainBottomAppBar(menu: MainMenu, nav: NavHostController, modifier: Modifier = Modifier) {
BottomAppBar(backgroundColor = MaterialTheme.colors.background, modifier = modifier) {
//图标宽度平等分
val weight = 1 / (MainMenu.values().size * 1.0f)
Row(Modifier.fillMaxWidth()) {
MenuIconButton(_menu = menu, menu = MainMenu.Main, Modifier.weight(weight),
Row(Modifier.fillMaxWidth(),horizontalArrangement = Arrangement.SpaceBetween) {
MenuIconButton(_menu = menu, menu = MainMenu.Main,
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) })
MenuIconButton(_menu = menu, menu = MainMenu.Center, Modifier.weight(weight),
MenuIconButton(_menu = menu, menu = MainMenu.Center,
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) {
member("社团成员"),
main("社团主页"),
list("活动列表")
enum class AssociationMenu(override val menuName: String):TopBarMenu {
Member("社团成员"),
Main("社团主页"),
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
fun AssociationAppBar(
menu: AssociationMenu,
nav: NavHostController,
back: () -> Unit,
dropMenu: () -> Unit,
content:@Composable () -> Unit
fun TextTopAppBar(
nav:NavHostController,
currentMenuName:String,
menuNames:Array<out TopBarMenu>,
iconMenu: (() -> Unit)? = null,
@DrawableRes icon:Int = R.drawable.ic_configuration,
dropMenuContent:@Composable () -> Unit = {},
) {
TopAppBar(backgroundColor = MaterialTheme.colors.secondary) {
Row(modifier = Modifier.fillMaxWidth(), verticalAlignment = Alignment.CenterVertically) {
IconButton(onClick = back, modifier = Modifier.weight(0.1F)) {
Icon(
painter = painterResource(id = R.drawable.ic_arrow_left),
contentDescription = null
)
}
Row(
modifier = Modifier
.weight(0.8F)
.fillMaxHeight(),
horizontalArrangement = Arrangement.Center,
verticalAlignment = Alignment.CenterVertically
) {
val menus = AssociationMenu.values()
menus.forEach {
Row(
modifier = Modifier
.weight(1F / menus.size)
.clickable(onClick = { nav.navigate(it.name) }),
horizontalArrangement = Arrangement.Center
) {
Text(
text = it.menuName,
color = if (menu == it) MaterialTheme.colors.primary else MaterialTheme.colors.onBackground
)
}
Row(modifier = Modifier.fillMaxWidth(), verticalAlignment = Alignment.CenterVertically) {
val context= LocalContext.current as Activity
IconButton(onClick = {context.onBackPressed()}, modifier = Modifier.weight(0.1F)) {
Icon(
painter = painterResource(id = R.drawable.ic_arrow_left),
contentDescription = null
)
}
Row(
modifier = Modifier
.weight(0.8F)
.fillMaxHeight(),
horizontalArrangement = Arrangement.SpaceAround,
verticalAlignment = Alignment.CenterVertically
) {
menuNames.forEach {
Row(
modifier = Modifier
.weight(1F / menuNames.size)
.clickable(onClick = { nav.navigate(it.name) }),
horizontalArrangement = Arrangement.Center
) {
Text(
text = it.menuName,
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(
painter = painterResource(id = R.drawable.ic_configuration),
painter = painterResource(id = icon),
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) {
//主页
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
fun DescCard(modifier: Modifier) {
fun DescCard(modifier: Modifier,content:String) {
Card(
modifier = modifier,
backgroundColor = Color.Transparent
) {
Image(
painter = painterResource(id = R.drawable.hot_activity_desc_background),
contentDescription = null
)
Row(modifier = Modifier.fillMaxWidth()) {
Spacer(modifier = Modifier.weight(0.2F))
Column(
modifier = Modifier
.weight(0.5F)
) {
Spacer(modifier = Modifier.weight(0.1F))
Box {
Image(
painter = painterResource(id = R.drawable.hot_activity_desc_background),
contentDescription = null,
contentScale = ContentScale.FillBounds,
modifier = Modifier.fillMaxSize()
)
Column(modifier = Modifier.fillMaxSize().padding(horizontal = 10.dp)) {
Spacer(modifier = Modifier.weight(0.15F))
Text(
text = "文字对任何界面都属于核心内容,而利用 Jetpack Compose 可以更轻松地显示或写入文字。Compose 可以充分利用其构建块的组合,这意味着您无需覆盖各种属性和方法,也无需扩展大型类,即可拥有特定的可组合项设计以及按您期望的方式运行的逻辑。"
.repeat(10), overflow = TextOverflow.Ellipsis,
modifier = Modifier.weight(0.8F)
modifier = Modifier.weight(0.65F),
text = content,
overflow = TextOverflow.Ellipsis
)
Spacer(modifier = Modifier.weight(0.1F))
Spacer(modifier = Modifier.weight(0.15F))
}
Spacer(modifier = Modifier.weight(0.2F))
}
}
}
@Preview
//@Preview
@Composable
fun AnimationTextPreview() {
AnimationText(text = "6666")
}
//@Preview
@Preview
@Composable
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.reflect.TypeToken
import com.gyf.csams.util.ApiResponse
import com.gyf.csams.util.randomChinese
import org.junit.Assert.assertEquals
import org.junit.Test
@ -32,16 +33,16 @@ class ExampleUnitTest {
println(e.body)
}
@Test
fun testYear(){
repeat(10,{
println(it)
})
}
@Test
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