增加活动详情界面

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. 3
      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. 26
      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. 44
      app/src/main/java/com/gyf/csams/association/ui/AssociationActivity.kt
  13. 5
      app/src/main/java/com/gyf/csams/association/ui/ExamActivity.kt
  14. 4
      app/src/main/java/com/gyf/csams/association/ui/ReNameActivity.kt
  15. 6
      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. 14
      app/src/main/java/com/gyf/csams/main/ui/MainActivity.kt
  18. 206
      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,7 +37,7 @@ class InitActivity : ComponentActivity() {
}
}
}
}
@Composable
private fun Init(initViewModel:InitViewModel= viewModel()){
@ -54,3 +54,4 @@ private fun Init(initViewModel:InitViewModel= viewModel()){
}
}
}

@ -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,6 +125,7 @@ class HistoryActViewModel: ScrollList<HistoryActVo>() {
}
override fun load() {
viewModelScope.launch {
_data.value?.apply {
repeat(initSize){
add(HistoryActVo(name = "活动${size+1}"))
@ -138,6 +133,7 @@ class HistoryActViewModel: ScrollList<HistoryActVo>() {
Logger.i("初始化活动数量:${size}")
}
}
}
override fun loadMore(callback:(message:String) -> Unit) {
_data.value?.apply {

@ -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,7 +140,7 @@ class AssociationActivity: ComponentActivity() {
}
}
}
}
/**
* 社团成员
@ -145,7 +148,7 @@ class AssociationActivity: ComponentActivity() {
*/
@Composable
private fun Member(){
MainFrame(background = { Background(image = BackgroundImage.association_main) }) {
MainFrame(background = { Background(image = BackgroundImage.AssociationMain) }) {
val searchWeight=0.2F
Search(modifier = Modifier
.fillMaxWidth()
@ -232,7 +235,7 @@ private fun MemberList(modifier: Modifier=Modifier, model: MemberViewModel=viewM
@Composable
private fun Main(){
MainFrame(background = {
Background(image = BackgroundImage.association_main,alpha = 0.7F)
Background(image = BackgroundImage.AssociationMain,alpha = 0.7F)
}) {
val nameW=0.1F
val cardW=0.66F*0.4F
@ -242,7 +245,8 @@ private fun Main(){
DescCard(
modifier = Modifier
.weight(cardW)
.fillMaxWidth()
.fillMaxWidth(),
content = randomChinese(500)
)
Commander(
modifier = Modifier.weight(cardW)
@ -288,7 +292,7 @@ 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),
Image(painter = painterResource(id = R.drawable.persion_name_border),
contentDescription = null
)
}
@ -317,7 +321,7 @@ private fun Showcase(modifier: Modifier){
*/
@Composable
private fun AssociationList(){
MainFrame(background = { Background(image = BackgroundImage.association_main,alpha = 07F) }) {
MainFrame(background = { Background(image = BackgroundImage.AssociationMain,alpha = 07F) }) {
val onGoWeight=0.3F
OngoingActivity(modifier = Modifier
.weight(onGoWeight)
@ -397,5 +401,7 @@ private fun HistoryActivity(modifier: Modifier,historyActVo: HistoryActVo){
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,7 +48,7 @@ class ExamActivity : ComponentActivity() {
}
}
}
}
@ -332,3 +332,4 @@ private fun ExamCQ(
}
}
}

@ -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,7 +48,6 @@ class ReNameActivity: ComponentActivity() {
}
}
}
}
/**
* 标题
@ -112,3 +111,4 @@ private fun BottomButton(modifier: Modifier=Modifier,model:RenameViewModel= view
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,7 +79,6 @@ class RegAssociationActivity: ComponentActivity(){
}
}
}
/**
* 社团Logo
@ -221,3 +220,6 @@ private fun Name(model:RegAssociationViewModel= viewModel()){
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,7 +67,6 @@ class MainActivity : ComponentActivity() {
}
}
/**
* 个人中心
@ -74,7 +74,7 @@ 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) {
MainFrame(background = { Background(image = BackgroundImage.Center,alpha = 0.5F) }, mainMenu = MainMenu.Center, nav = navController) {
Column(modifier = Modifier
.weight(0.33F)
.fillMaxWidth(),verticalArrangement = Arrangement.Bottom) {
@ -111,7 +111,7 @@ private fun Center(model:CenterViewModel= viewModel(), scaffoldModel: ScaffoldMo
*/
@Composable
private fun Main(navController: NavHostController) {
MainFrame(background = { Background(image = BackgroundImage.main) }, mainMenu = MainMenu.Main, nav = navController) {
MainFrame(background = { Background(image = BackgroundImage.Main) }, mainMenu = MainMenu.Main, nav = navController) {
Column(modifier = Modifier.weight(0.33F)) {
Notification()
MessageBoard()
@ -134,7 +134,7 @@ private fun Main(navController: NavHostController) {
@Composable
private fun AssociationList(navController: NavHostController) {
MainFrame(
background = { Background(image = BackgroundImage.list) },
background = { Background(image = BackgroundImage.AssociationList) },
mainMenu = MainMenu.List,
nav = navController
) {
@ -374,7 +374,8 @@ private fun PosterWithDesc(model: CarouselViewModel = viewModel()) {
DescCard(
modifier = Modifier
.weight(0.4F)
.fillMaxWidth()
.fillMaxWidth(),
content = randomChinese(500)
)
}
}
@ -388,6 +389,9 @@ fun DefaultPreview() {
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,16 +188,18 @@ enum class AssociationMenu(val menuName: String) {
*
*/
@Composable
fun AssociationAppBar(
menu: AssociationMenu,
fun TextTopAppBar(
nav:NavHostController,
back: () -> Unit,
dropMenu: () -> Unit,
content:@Composable () -> Unit
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)) {
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
@ -163,32 +209,35 @@ fun AssociationAppBar(
modifier = Modifier
.weight(0.8F)
.fillMaxHeight(),
horizontalArrangement = Arrangement.Center,
horizontalArrangement = Arrangement.SpaceAround,
verticalAlignment = Alignment.CenterVertically
) {
val menus = AssociationMenu.values()
menus.forEach {
menuNames.forEach {
Row(
modifier = Modifier
.weight(1F / menus.size)
.weight(1F / menuNames.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
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
) {
Box {
Image(
painter = painterResource(id = R.drawable.hot_activity_desc_background),
contentDescription = null
contentDescription = null,
contentScale = ContentScale.FillBounds,
modifier = Modifier.fillMaxSize()
)
Row(modifier = Modifier.fillMaxWidth()) {
Spacer(modifier = Modifier.weight(0.2F))
Column(
modifier = Modifier
.weight(0.5F)
) {
Spacer(modifier = Modifier.weight(0.1F))
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