完善活动详情,和服务端接口联调

master
pan 3 years ago
parent f093f47c37
commit 5ec8924532
  1. 2
      background/src/main/java/com/gyf/csams/InitActivity.kt
  2. 2
      background/src/main/java/com/gyf/csams/main/model/AssociationManagementViewModel.kt
  3. 3
      background/src/main/java/com/gyf/csams/main/model/AuditActViewModel.kt
  4. 3
      background/src/main/java/com/gyf/csams/main/model/AuditAssociationViewModel.kt
  5. 5
      background/src/main/java/com/gyf/csams/main/model/BaseAuditViewModel.kt
  6. 10
      background/src/main/java/com/gyf/csams/main/model/MenuViewModel.kt
  7. 11
      background/src/main/java/com/gyf/csams/main/ui/MainActivity.kt
  8. 2
      background/src/test/java/com/gyf/csams/ExampleUnitTest.kt
  9. 3
      foreground/src/main/java/com/gyf/csams/InitActivity.kt
  10. 5
      foreground/src/main/java/com/gyf/csams/account/model/AccountViewModel.kt
  11. 145
      foreground/src/main/java/com/gyf/csams/activity/model/ActivityDetailViewModel.kt
  12. 5
      foreground/src/main/java/com/gyf/csams/activity/model/ApplyActViewModel.kt
  13. 238
      foreground/src/main/java/com/gyf/csams/activity/ui/ActivityDetailActivity.kt
  14. 23
      foreground/src/main/java/com/gyf/csams/association/model/AssociationViewModel.kt
  15. 3
      foreground/src/main/java/com/gyf/csams/association/model/RegAssociationViewModel.kt
  16. 15
      foreground/src/main/java/com/gyf/csams/association/ui/AssociationActivity.kt
  17. 8
      foreground/src/main/java/com/gyf/csams/main/model/MainViewModel.kt
  18. 2
      foreground/src/main/java/com/gyf/csams/main/ui/MainActivity.kt
  19. 15
      foreground/src/main/java/com/gyf/csams/uikit/BaseView.kt
  20. 1
      foreground/src/main/java/com/gyf/csams/uikit/ViewModel.kt
  21. 3
      foreground/src/main/java/com/gyf/csams/util/HttpCallback.kt
  22. 4
      foreground/src/main/res/values-en/strings.xml
  23. 4
      foreground/src/main/res/values-zh/strings.xml
  24. 4
      foreground/src/main/res/values/strings.xml
  25. 2
      foreground/src/test/java/com/gyf/csams/ExampleUnitTest.kt
  26. 1
      lib/src/main/java/com/gyf/lib/model/AbstractLoginViewModel.kt
  27. 1
      lib/src/main/java/com/gyf/lib/model/InitViewModel.kt
  28. 1
      lib/src/main/java/com/gyf/lib/model/SysMessageViewModel.kt
  29. 1
      lib/src/main/java/com/gyf/lib/service/MessageService.kt
  30. 20
      lib/src/main/java/com/gyf/lib/util/Api.kt
  31. 4
      lib/src/main/java/com/gyf/lib/util/BottomButton.kt
  32. 21
      lib/src/main/java/com/gyf/lib/util/HttpUtil.kt

@ -4,10 +4,10 @@ import android.app.Activity
import com.google.gson.reflect.TypeToken
import com.gyf.csams.account.ui.LoginActivity
import com.gyf.csams.main.ui.MainActivity
import com.gyf.csams.module.ApiResponse
import com.gyf.csams.module.ManagerVo
import com.gyf.lib.uikit.AbstractInitActivity
import com.gyf.lib.util.AccountApi
import com.gyf.lib.util.ApiResponse
import java.lang.reflect.Type
class InitActivity : AbstractInitActivity<ManagerVo>() {

@ -20,7 +20,7 @@ class AssociationManagementViewModel(application: Application) : ScrollViewModel
}
fun load() {
TODO()
TODO("数据状态管理")
}
fun loadMore(callback: (message: String) -> Unit) {

@ -2,10 +2,9 @@ package com.gyf.csams.main.model
import android.app.Application
import com.google.gson.reflect.TypeToken
import com.gyf.csams.module.ApiResponse
import com.gyf.csams.module.AuditActVo
import com.gyf.lib.util.ActivityApi
import com.gyf.lib.util.ApiResponse
import com.gyf.lib.util.UrlPath
import java.lang.reflect.Type

@ -2,10 +2,9 @@ package com.gyf.csams.main.model
import android.app.Application
import com.google.gson.reflect.TypeToken
import com.gyf.csams.module.ApiResponse
import com.gyf.csams.module.AuditAssociationVo
import com.gyf.lib.util.ApiResponse
import com.gyf.lib.util.AssociationApi
import com.gyf.lib.util.UrlPath
import java.lang.reflect.Type

@ -3,10 +3,7 @@ package com.gyf.csams.main.model
import android.app.Application
import androidx.lifecycle.viewModelScope
import com.google.gson.reflect.TypeToken
import com.gyf.csams.module.AcceptVo
import com.gyf.csams.module.AuditVo
import com.gyf.csams.module.CheckVo
import com.gyf.csams.module.ClientType
import com.gyf.csams.module.*
import com.gyf.lib.model.ScrollViewModel
import com.gyf.lib.util.*
import kotlinx.coroutines.launch

@ -2,13 +2,15 @@ package com.gyf.csams.main.model
import android.app.Activity
import androidx.lifecycle.ViewModel
import com.gyf.csams.main.ui.*
import com.gyf.csams.main.ui.AuditActActivity
import com.gyf.csams.main.ui.AuditAssociationActivity
import com.gyf.csams.main.ui.RenameActivity
enum class MenuType(val desc: String, val clazz: Map<String, Class<out Activity>>) {
Association(
"社团管理",
mapOf(
"社团信息管理" to AssociationManagementActivity::class.java,
// TODO "社团信息管理" to AssociationManagementActivity::class.java,
"审核社团换名" to RenameActivity::class.java,
"审核社团注册" to AuditAssociationActivity::class.java
),
@ -16,8 +18,8 @@ enum class MenuType(val desc: String, val clazz: Map<String, Class<out Activity>
Act(
"活动管理", mapOf(
"审核社团活动" to AuditActActivity::class.java,
"审核质量报告单" to CheckQualityReportActivity::class.java,
"查看社团活动" to ManagerActActivity::class.java
// TODO "审核质量报告单" to CheckQualityReportActivity::class.java,
// "查看社团活动" to ManagerActActivity::class.java
)
)
}

@ -59,11 +59,12 @@ class MainActivity : BaseActivity() {
Text(text = "我的通知")
}
OutlinedButton(onClick = {
startActivity(Intent(this@MainActivity, DepartmentActivity::class.java))
}, modifier = Modifier.fillMaxWidth()) {
Text(text = stringResource(id = R.string.department_management))
}
// TODO 部门管理
// OutlinedButton(onClick = {
// startActivity(Intent(this@MainActivity, DepartmentActivity::class.java))
// }, modifier = Modifier.fillMaxWidth()) {
// Text(text = stringResource(id = R.string.department_management))
// }
OutlinedButton(onClick = {
startActivity(
Intent(

@ -1,7 +1,7 @@
package com.gyf.csams
import com.google.gson.reflect.TypeToken
import com.gyf.lib.util.ApiResponse
import com.gyf.csams.module.ApiResponse
import com.orhanobut.logger.Logger
import org.junit.Assert.assertEquals
import org.junit.Test

@ -4,11 +4,10 @@ import android.app.Activity
import com.google.gson.reflect.TypeToken
import com.gyf.csams.account.ui.AccountActivity
import com.gyf.csams.main.ui.MainActivity
import com.gyf.csams.module.ApiResponse
import com.gyf.csams.module.UserVo
import com.gyf.lib.uikit.AbstractInitActivity
import com.gyf.lib.util.AccountApi
import com.gyf.lib.util.ApiResponse
import java.lang.reflect.Type
class InitActivity : AbstractInitActivity<UserVo>() {

@ -11,10 +11,7 @@ import com.google.gson.reflect.TypeToken
import com.gyf.csams.R
import com.gyf.csams.account.ui.AccountActivity
import com.gyf.csams.account.ui.AccountRoute
import com.gyf.csams.module.ClientType
import com.gyf.csams.module.UserLoginVo
import com.gyf.csams.module.UserRegVo
import com.gyf.csams.module.UserVo
import com.gyf.csams.module.*
import com.gyf.lib.model.AbstractLoginViewModel
import com.gyf.lib.uikit.FormStatus
import com.gyf.lib.uikit.ValidStringForm

@ -1,19 +1,22 @@
package com.gyf.csams.activity.model
import android.app.Application
import android.net.Uri
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import com.gyf.csams.module.ActivityDetailVo
import com.gyf.csams.module.ActivityPhotoVo
import com.gyf.csams.module.BBSVo
import com.gyf.csams.module.UserInfoVo
import androidx.lifecycle.viewModelScope
import com.google.gson.reflect.TypeToken
import com.gyf.csams.MainApplication
import com.gyf.csams.module.*
import com.gyf.csams.uikit.AbstractComment
import com.gyf.csams.uikit.ActivityDetailMenu
import com.gyf.csams.uikit.TopMenuInterface
import com.gyf.lib.model.ScrollViewModel
import com.gyf.lib.uikit.ValidStringForm
import com.gyf.lib.util.NOT_IMPL_TIP
import com.gyf.lib.util.*
import kotlinx.coroutines.launch
import java.io.File
/**
* 活动详情菜单通用状态
@ -36,9 +39,6 @@ class ActivityInfoViewModel : ViewModel() {
val like = "点赞"
val collect = "收藏"
init {
loadInfo()
}
/**
* TODO 点赞
@ -58,8 +58,24 @@ class ActivityInfoViewModel : ViewModel() {
callback(NOT_IMPL_TIP)
}
private fun loadInfo() {
TODO()
/**
* 加载活动详情
*
* @param activityId
*/
fun load(activityId: Int) {
viewModelScope.launch {
HttpClient.post(url = Api.buildUrl(ActivityApi.Show),
callback = HttpCallback<ActivityDetailVo>(action = "加载活动详情",
onSuccess = { it ->
it.body?.let {
_activityDetailVo.postValue(it)
}
}, typeToken = object : TypeToken<ApiResponse<ActivityDetailVo>>() {}.type
),
jsonParam = ShowActivityVo(activityId = activityId, token = TokenManager.getToken())
)
}
}
}
@ -71,32 +87,61 @@ class ActivityInfoViewModel : ViewModel() {
*/
class ActivityPhotoViewModel(application: Application) :
ScrollViewModel<ActivityPhotoVo>(application) {
override val initSize: Int = 10
init {
load()
}
fun upload(callback: (message: String) -> Unit) {
callback(NOT_IMPL_TIP)
}
val name = ValidStringForm("照片名", textLength = 10)
/**
* 上传照片
*
*
* @param uri
*/
fun load() {
TODO("加载相册")
fun upload(activityId: Int, uri: Uri, callback: (message: String) -> Unit) {
val resolver = getApplication<MainApplication>().contentResolver
resolver.openInputStream(uri)?.readBytes()?.apply {
name.clean()
viewModelScope.launch {
val context = getApplication<MainApplication>()
runCatching {
val cacheFile = File(context.cacheDir, "${System.currentTimeMillis()}")
cacheFile.writeBytes(this@apply)
HttpClient.uploadFile(url = Api.buildUrl(ActivityApi.UploadPhoto),
callback = HttpCallback<Boolean>(action = "上传照片",
onSuccess = {
callback("上传成功")
}, typeToken = object : TypeToken<ApiResponse<Boolean>>() {}.type
),
params = mapOf(
"activityId" to "$activityId",
"name" to (name.formValue.value
?: throw IllegalArgumentException("照片名字为空"))
),
fileList = arrayOf(cacheFile)
)
}
}
}
}
/**
* 加载相册
*
*
* @param callback
*/
fun loadMore(callback: (message: String) -> Unit) {
TODO("加载更多相册")
fun load(activityId: Int) {
viewModelScope.launch {
HttpClient.post(
url = Api.buildUrl(ActivityApi.Photo),
callback = HttpCallback<MutableList<ActivityPhotoVo>>(
action = "加载相册",
onSuccess = {
_data.postValue(it.body)
},
typeToken = object :
TypeToken<ApiResponse<MutableList<ActivityPhotoVo>>>() {}.type
),
jsonParam = SearchActivityPhotoVo(activityId = activityId)
)
}
}
}
@ -104,25 +149,36 @@ class ActivityPhotoViewModel(application: Application) :
class ActivityMemberViewModel(application: Application) :
ScrollViewModel<UserInfoVo>(application) {
/**
*
*
*/
fun load() {
TODO("加载活动成员")
}
}
class BBSCommentModel : AbstractComment() {
override val newContent = ValidStringForm(formDesc = "评论内容", textLength = 80)
var activityId: Int? = null
/**
* TODO 发送评论
*
* 发送评论
* @param callback
*/
override fun send(callback: (message: String) -> Unit) {
callback(NOT_IMPL_TIP)
viewModelScope.launch {
HttpClient.post(url = Api.buildUrl(ActivityApi.SendComment),
callback = HttpCallback<Boolean>(action = "发送评论",
onSuccess = {
callback(it.message)
}, typeToken = object : TypeToken<ApiResponse<Boolean>>() {}.type
),
jsonParam =
SendBBSVo(
content = newContent.formValue.value
?: throw IllegalArgumentException("评论内容为空"),
token = TokenManager.getToken(),
activityId = activityId ?: throw IllegalArgumentException("活动id没有初始化")
)
)
}
}
}
@ -131,14 +187,21 @@ class BBSCommentModel : AbstractComment() {
*
*/
class BBSViewModel(application: Application) : ScrollViewModel<BBSVo>(application) {
override val initSize: Int = 10
val title = "发送评论"
/**
*
* 加载评论
*/
fun load() {
TODO("加载评论")
fun load(activityId: Int) {
viewModelScope.launch {
HttpClient.post(url = Api.buildUrl(ActivityApi.Comment),
callback = HttpCallback<MutableList<BBSVo>>(action = "加载评论",
onSuccess = {
_data.postValue(it.body)
}, typeToken = object : TypeToken<ApiResponse<MutableList<BBSVo>>>() {}.type
),
jsonParam = SearchCommentVo(activityId = activityId)
)
}
}
}

@ -25,7 +25,6 @@ import com.gyf.csams.R
import com.gyf.csams.module.*
import com.gyf.lib.uikit.*
import com.gyf.lib.util.*
import com.gyf.lib.util.ApiResponse
import com.gyf.lib.util.DateTimeUtil.DATE_FORMAT
import com.gyf.lib.util.DateTimeUtil.TIME_FORMAT
import com.gyf.lib.util.DateTimeUtil.dateFormat
@ -613,9 +612,9 @@ class ApplyActViewModel(application: Application) : AndroidViewModel(application
activityTime = "$activityDate $activityTime".toDate().time,
activityAddress = activityAddress,
activityDesc = activityDesc,
activitySize = activitySize.toInt()
activitySize = activitySize.toInt(),
activityId = _checkInfo.value?.body?.activityId
),
activityId = _checkInfo.value?.body?.activityId,
token = TokenManager.getToken()
)
)

@ -1,8 +1,13 @@
package com.gyf.csams.activity.ui
import android.content.Intent
import android.net.Uri
import android.os.Bundle
import android.provider.MediaStore
import androidx.activity.ComponentActivity
import androidx.activity.compose.rememberLauncherForActivityResult
import androidx.activity.compose.setContent
import androidx.activity.result.contract.ActivityResultContracts
import androidx.compose.foundation.Canvas
import androidx.compose.foundation.Image
import androidx.compose.foundation.border
@ -10,38 +15,63 @@ 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.*
import androidx.compose.runtime.livedata.observeAsState
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.unit.dp
import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.navigation.NavHostController
import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable
import com.google.accompanist.coil.rememberCoilPainter
import com.google.accompanist.imageloading.ImageLoadState
import com.google.accompanist.insets.ExperimentalAnimatedInsets
import com.google.accompanist.insets.navigationBarsWithImePadding
import com.gyf.csams.R
import com.gyf.csams.activity.model.*
import com.gyf.csams.association.ui.AssociationActivity
import com.gyf.csams.module.ActivityPhotoVo
import com.gyf.csams.module.BBSVo
import com.gyf.csams.module.UserInfoVo
import com.gyf.csams.uikit.*
import com.gyf.lib.uikit.MainColumnFrame
import com.gyf.lib.uikit.NavBody
import com.gyf.lib.uikit.ScaffoldModel
import com.gyf.lib.uikit.ShowSnackbar
import com.gyf.lib.uikit.*
import com.gyf.lib.util.Api
import com.gyf.lib.util.BottomButton
import com.gyf.lib.util.DateTimeUtil.datetimeFormat
import com.gyf.lib.util.TokenManager
import com.orhanobut.logger.Logger
import java.util.*
val PHOTO_HEIGHT = 200.dp
/**
* 活动详情
*
*/
class ActivityDetailActivity : ComponentActivity() {
private val associationId: Int
get() {
val id = intent.getIntExtra(
AssociationActivity::class.java.name,
0
)
return if (id == 0) throw IllegalArgumentException("社团id:${id}不合法,初始化失败") else id
}
private val activityId: Int
get() {
val id = intent.getIntExtra(
ActivityDetailActivity::class.java.name,
0
)
return if (id == 0) throw IllegalArgumentException("活动id:${id}不合法,初始化失败") else id
}
@ExperimentalAnimatedInsets
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
@ -66,15 +96,15 @@ class ActivityDetailActivity : ComponentActivity() {
model.clickMenu(ActivityDetailMenu.Info)
}
composable(ActivityDetailMenu.Photo.name) {
Photo()
Photo(nav = nav)
ShowSnackbar(scaffoldState = scaffoldState)
model.clickMenu(ActivityDetailMenu.Photo)
}
composable(ActivityDetailMenu.Member.name) {
Member()
ShowSnackbar(scaffoldState = scaffoldState)
model.clickMenu(ActivityDetailMenu.Member)
}
// composable(ActivityDetailMenu.Member.name) {
// Member()
// ShowSnackbar(scaffoldState = scaffoldState)
// model.clickMenu(ActivityDetailMenu.Member)
// }
composable(ActivityDetailMenu.BBS.name) {
BBS()
ShowSnackbar(scaffoldState = scaffoldState)
@ -87,32 +117,17 @@ class ActivityDetailActivity : ComponentActivity() {
}
/**
* 底部按钮
* 活动信息
*
* @param modifier
*/
@Composable
private fun BottomButton(
modifier: Modifier = Modifier,
private fun Info(
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)
}
LaunchedEffect(activityId) {
model.load(activityId = activityId)
}
}
/**
* 活动信息
*
*/
@Composable
private fun Info() {
MainColumnFrame(background = {
Background(
image = BackgroundImage.ActivityInfo,
@ -122,7 +137,17 @@ class ActivityDetailActivity : ComponentActivity() {
RectList(modifier = Modifier.weight(0.4F))
ActivityDesc(modifier = Modifier.weight(0.4F))
Spacer(modifier = Modifier.weight(0.05F))
BottomButton()
BottomButton(
modifier = Modifier.fillMaxWidth(),
confirmDesc = R.string.like_btn,
backDesc = R.string.collect_btn,
onConfirm = {
model.like { scaffoldModel.update(message = it) }
},
onBack = {
model.collect { scaffoldModel.update(message = it) }
})
Spacer(modifier = Modifier.weight(0.05F))
}
}
@ -199,28 +224,106 @@ class ActivityDetailActivity : ComponentActivity() {
* 相册
*
*/
@ExperimentalAnimatedInsets
@Composable
private fun Photo(
model: ActivityPhotoViewModel = viewModel(),
scaffoldModel: ScaffoldModel = viewModel()
scaffoldModel: ScaffoldModel = viewModel(),
nav: NavHostController
) {
LaunchedEffect(activityId) {
model.load(activityId = activityId)
}
MainColumnFrame(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
)
if (TokenManager.getUserInfo()?.associationVo?.associationId == associationId && TokenManager.getUserInfo()?.isHead == true) {
var photoUri: Uri? by remember {
mutableStateOf(null)
}
}
Row(modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.End) {
val resultLauncher =
rememberLauncherForActivityResult(contract = ActivityResultContracts.StartActivityForResult()) {
when (it.resultCode) {
RESULT_OK -> {
it.data?.data?.apply {
Logger.i("uri=$this")
photoUri = this
}
}
}
}
IconButton(onClick = {
resultLauncher.launch(
Intent(
Intent.ACTION_PICK,
MediaStore.Images.Media.EXTERNAL_CONTENT_URI
)
)
}) {
Icon(
painter = painterResource(id = R.drawable.ic_upload),
contentDescription = null
)
}
}
photoUri?.let {
val status by model.name.statusForm.observeAsState()
AlertDialog(onDismissRequest = { /*TODO*/ }, title = {
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.Center
) {
Text(text = "上传照片")
}
}, text = {
val photo = rememberCoilPainter(request = it)
Column {
BaseTextField(
modifier = Modifier.navigationBarsWithImePadding(),
form = model.name
)
Image(
// modifier=Modifier.weight(0.5F),
painter = photo,
contentDescription = null,
contentScale = ContentScale.Inside
)
}
Spacer(modifier = Modifier.height(10.dp))
}, buttons = {
BottomButton(
modifier = Modifier.fillMaxWidth(),
confirmDesc = R.string.upload_btn,
backDesc = R.string.close_btn,
onConfirm = {
model.upload(activityId = activityId, uri = it) {
photoUri = null
scaffoldModel.update(it, actionLabel = "关闭提示") {
nav.navigate(ActivityDetailMenu.Photo.name)
}
}
},
onBack = {
photoUri = null
},
enabled = status == FormStatus.Valid
)
}
)
}
Spacer(modifier = Modifier.height(10.dp))
}
Box(
modifier = Modifier
.fillMaxSize()
@ -242,10 +345,18 @@ class ActivityDetailActivity : ComponentActivity() {
horizontalArrangement = Arrangement.SpaceEvenly
) {
Spacer(modifier = Modifier.weight(0.05F))
PhotoItem(vo = it[0], modifier = Modifier.weight(0.4F))
PhotoItem(
vo = it[0], modifier = Modifier
.weight(0.4F)
.height(PHOTO_HEIGHT)
)
Spacer(modifier = Modifier.weight(0.1F))
if (it.size == 2) {
PhotoItem(vo = it[1], modifier = Modifier.weight(0.4F))
PhotoItem(
vo = it[1], modifier = Modifier
.weight(0.4F)
.height(PHOTO_HEIGHT)
)
} else {
Spacer(modifier = Modifier.weight(0.4F))
}
@ -255,25 +366,35 @@ class ActivityDetailActivity : ComponentActivity() {
}
}
}
// 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.onBackground),
contentAlignment = Alignment.Center
) {
val photo = rememberCoilPainter(request = Api.buildUrl(vo.url))
Image(
painter = painterResource(id = R.drawable.ic_launcher_foreground),
contentDescription = null,
painter = photo,
contentDescription = vo.name,
)
when (photo.loadState) {
is ImageLoadState.Loading -> {
// Display a circular progress indicator whilst loading
CircularProgressIndicator(Modifier.align(Alignment.Center))
}
is ImageLoadState.Error -> {
// If you wish to display some content if the request fails
}
else -> {
}
}
}
}
@ -307,6 +428,7 @@ class ActivityDetailActivity : ComponentActivity() {
painter = painterResource(id = R.drawable.persion_name_border),
contentDescription = null
)
Text(text = first().name)
}
}
@ -377,9 +499,12 @@ class ActivityDetailActivity : ComponentActivity() {
@Composable
private fun BBS(
model: BBSViewModel = viewModel(),
scaffoldModel: ScaffoldModel = viewModel(),
bbsCommentModel: BBSCommentModel = viewModel()
) {
LaunchedEffect(activityId) {
bbsCommentModel.activityId = this@ActivityDetailActivity.activityId
model.load(activityId)
}
MainColumnFrame(background = {
Background(
image = BackgroundImage.ActivityBBS,
@ -402,7 +527,9 @@ class ActivityDetailActivity : ComponentActivity() {
}
}
SendComment(model = bbsCommentModel)
SendComment(model = bbsCommentModel) {
model.load(activityId)
}
Box(
modifier = Modifier
@ -421,9 +548,6 @@ class ActivityDetailActivity : ComponentActivity() {
}
}
}
if (listState.layoutInfo.totalItemsCount - listState.firstVisibleItemIndex == model.initSize / 2 - 1) {
TODO("加载更多")
}
}
}
@ -445,8 +569,8 @@ class ActivityDetailActivity : ComponentActivity() {
modifier = Modifier.height(50.dp),
verticalArrangement = Arrangement.SpaceEvenly
) {
Text(text = vo.name)
Text(text = vo.createTime.datetimeFormat())
Text(text = vo.user.name)
Text(text = Date(vo.createTime).datetimeFormat())
}
}
Spacer(modifier = Modifier.weight(0.5F))

@ -13,7 +13,6 @@ import com.gyf.csams.uikit.TopMenuInterface
import com.gyf.lib.model.ScrollViewModel
import com.gyf.lib.uikit.StringForm
import com.gyf.lib.util.*
import com.gyf.lib.util.ApiResponse
import kotlinx.coroutines.launch
@ -105,6 +104,24 @@ class OngoingActViewModel : ViewModel() {
* 历史活动
*
*/
class HistoryActViewModel(application: Application) : ScrollViewModel<HistoryActVo>(application) {
override val initSize = 10
class HistoryActViewModel(application: Application) : ScrollViewModel<ActivityVo>(application) {
fun load(associationId: Int) {
viewModelScope.launch {
HttpClient.post(
url = Api.buildUrl(ActivityApi.Load),
callback = HttpCallback<MutableList<ActivityVo>>(
action = "查看社团活动",
onSuccess = {
_data.postValue(it.body)
},
typeToken = object : TypeToken<ApiResponse<MutableList<ActivityVo>>>() {}.type
),
jsonParam = SearchActivityVo(
associationId = associationId,
token = TokenManager.getToken()
)
)
}
}
}

@ -12,6 +12,7 @@ import coil.imageLoader
import coil.request.ImageRequest
import com.google.gson.reflect.TypeToken
import com.gyf.csams.MainApplication
import com.gyf.csams.module.ApiResponse
import com.gyf.csams.module.AssociationCheckVo
import com.gyf.csams.module.AssociationRegVo
import com.gyf.csams.module.ClientType
@ -54,7 +55,7 @@ class RegAssociationViewModel(application: Application) : AndroidViewModel(appli
_picture.value = uri
}
fun getInputSteam(): InputStream? {
private fun getInputSteam(): InputStream? {
_picture.value?.let {
val resolver = getApplication<MainApplication>().contentResolver
return resolver.openInputStream(it)

@ -30,7 +30,7 @@ import com.gyf.csams.R
import com.gyf.csams.activity.ui.ActivityDetailActivity
import com.gyf.csams.activity.ui.ApplyActActivity
import com.gyf.csams.association.model.*
import com.gyf.csams.module.HistoryActVo
import com.gyf.csams.module.ActivityVo
import com.gyf.csams.uikit.*
import com.gyf.lib.uikit.*
import com.gyf.lib.util.TokenManager
@ -488,6 +488,10 @@ class AssociationActivity : ComponentActivity() {
modifier: Modifier,
model: HistoryActViewModel = viewModel()
) {
LaunchedEffect(associationId) {
model.load(associationId = associationId)
}
val listState = rememberLazyListState()
val list by model.data.observeAsState()
LazyColumn(state = listState, modifier = modifier) {
@ -515,9 +519,12 @@ class AssociationActivity : ComponentActivity() {
* @param modifier
*/
@Composable
private fun HistoryActivity(modifier: Modifier, historyActVo: HistoryActVo) {
private fun HistoryActivity(modifier: Modifier, historyActVo: ActivityVo) {
Box(modifier = modifier.clickable(onClick = {
startActivity(Intent(this, ActivityDetailActivity::class.java))
startActivity(Intent(this, ActivityDetailActivity::class.java).apply {
putExtra(ActivityDetailActivity::class.java.name, historyActVo.activityId)
putExtra(AssociationActivity::class.java.name, associationId)
})
}), contentAlignment = Alignment.Center) {
Image(
painter = painterResource(id = R.drawable.history_activity_border),
@ -529,7 +536,7 @@ class AssociationActivity : ComponentActivity() {
contentDescription = null,
modifier = Modifier.fillMaxSize()
)
Text(text = historyActVo.name)
Text(text = historyActVo.activityName)
}
}

@ -10,7 +10,6 @@ import com.gyf.lib.uikit.FormStatus
import com.gyf.lib.uikit.StringForm
import com.gyf.lib.uikit.ValidStringForm
import com.gyf.lib.util.*
import com.gyf.lib.util.ApiResponse
import com.orhanobut.logger.Logger
import kotlinx.coroutines.Job
import kotlinx.coroutines.delay
@ -203,11 +202,4 @@ class CenterViewModel : ViewModel() {
val myLikeActivity = "我点赞的社团活动"
val myCollectActivity = "我收藏的社团活动"
private fun load() {
viewModelScope.launch {
TODO()
}
}
}

@ -127,7 +127,7 @@ class MainActivity : BaseActivity() {
putExtra(AssociationActivity::javaClass.name, it)
})
}
CenterMenuItem(text = model.myJoinActivity)
// CenterMenuItem(text = model.myJoinActivity)
CenterMenuItem(text = model.myLikeActivity)
CenterMenuItem(text = model.myCollectActivity)
}

@ -117,7 +117,9 @@ enum class AssociationMenu(override val menuName: String) : TopBarMenu {
enum class ActivityDetailMenu(override val menuName: String) : TopBarMenu {
Info("活动信息"),
Photo("相册"),
Member("活动成员"),
//TODO 活动成员
// Member("活动成员"),
BBS("交流区");
companion object Menu : StartMenu<ActivityDetailMenu> {
@ -175,7 +177,11 @@ abstract class AbstractComment : ViewModel() {
*/
@Composable
fun <T : AbstractComment> SendComment(model: T, scaffoldModel: ScaffoldModel = viewModel()) {
fun <T : AbstractComment> SendComment(
model: T,
scaffoldModel: ScaffoldModel = viewModel(),
callback: () -> Unit = {}
) {
val openDialog by model.openDialog.observeAsState()
val status by model.newContent.statusForm.observeAsState()
@ -191,7 +197,10 @@ fun <T : AbstractComment> SendComment(model: T, scaffoldModel: ScaffoldModel = v
OutlinedButton(onClick = {
model.send {
model.closeDialog()
scaffoldModel.update(message = it)
scaffoldModel.update(message = it, actionLabel = "知道了") {
}
callback()
}
}, enabled = status == FormStatus.Valid) {
Text(text = "发送")

@ -8,6 +8,7 @@ import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.viewModelScope
import com.google.gson.reflect.TypeToken
import com.gyf.csams.R
import com.gyf.csams.module.ApiResponse
import com.gyf.lib.util.*
import com.orhanobut.logger.Logger
import kotlinx.coroutines.Job

@ -2,9 +2,8 @@ package com.gyf.csams.util
import com.google.gson.Gson
import com.google.gson.GsonBuilder
import com.gyf.csams.module.ApiResponse
import com.gyf.csams.module.Exam
import com.gyf.lib.util.ApiResponse
import com.gyf.lib.util.HttpCallback
import java.lang.reflect.Type

@ -16,4 +16,8 @@
<string name="welcome_start">同学您好\n</string>
<string name="welcome_end">欢迎使用</string>
<string name="reg_again_btn">再次申请</string>
<string name="like_btn">点赞</string>
<string name="collect_btn">收藏</string>
<string name="upload_btn">上传</string>
<string name="close_btn">关闭</string>
</resources>

@ -16,4 +16,8 @@
<string name="welcome_start">同学您好\n</string>
<string name="welcome_end">欢迎使用</string>
<string name="reg_again_btn">再次申请</string>
<string name="like_btn">点赞</string>
<string name="collect_btn">收藏</string>
<string name="upload_btn">上传</string>
<string name="close_btn">关闭</string>
</resources>

@ -16,4 +16,8 @@
<string name="welcome_start">同学您好\n</string>
<string name="welcome_end">欢迎使用</string>
<string name="reg_again_btn">再次申请</string>
<string name="like_btn">点赞</string>
<string name="collect_btn">收藏</string>
<string name="upload_btn">上传</string>
<string name="close_btn">关闭</string>
</resources>

@ -2,8 +2,8 @@ package com.gyf.csams
import com.google.gson.Gson
import com.google.gson.reflect.TypeToken
import com.gyf.csams.module.ApiResponse
import com.gyf.lib.uikit.StringForm
import com.gyf.lib.util.ApiResponse
import com.gyf.lib.util.randomChinese
import org.junit.Assert.assertEquals
import org.junit.Test

@ -8,6 +8,7 @@ import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.viewModelScope
import com.google.gson.reflect.TypeToken
import com.gyf.csams.module.ApiResponse
import com.gyf.csams.module.ClientType
import com.gyf.csams.module.ManagerVo
import com.gyf.csams.module.UserVo

@ -6,6 +6,7 @@ import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.viewModelScope
import com.google.gson.reflect.TypeToken
import com.gyf.csams.module.ApiResponse
import com.gyf.csams.module.OwnInfoVo
import com.gyf.csams.module.Token
import com.gyf.lib.util.*

@ -5,6 +5,7 @@ import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.viewModelScope
import com.google.gson.reflect.TypeToken
import com.gyf.csams.module.ApiResponse
import com.gyf.csams.module.ClientType
import com.gyf.csams.module.NotificationDto
import com.gyf.csams.module.NotificationVo

@ -6,6 +6,7 @@ import androidx.core.app.NotificationCompat
import androidx.core.app.NotificationManagerCompat
import com.google.gson.Gson
import com.google.gson.reflect.TypeToken
import com.gyf.csams.module.ApiResponse
import com.gyf.csams.module.ClientType
import com.gyf.csams.module.NotificationDto
import com.gyf.csams.module.NotificationVo

@ -130,7 +130,25 @@ enum class ActivityApi(val path: String) : UrlPath {
Check("/check"),
//审核进度
Read("/read");
Read("/read"),
//加载活动
Load("/load"),
//加载活动详情
Show("/show"),
//加载活动照片
Photo("/photo"),
//上传照片
UploadPhoto("${Photo.path}/upload"),
//查看评论
Comment("/comment"),
//发送评论
SendComment("${Comment.path}/send");
override fun build(): String {

@ -26,7 +26,7 @@ fun BottomButton(
onBack: (() -> Unit)? = null,
onConfirm: () -> Unit
) {
val context = LocalContext.current as Activity
val context = LocalContext.current as? Activity
Row(modifier = modifier, horizontalArrangement = Arrangement.Center) {
OutlinedButton(
onClick = onConfirm,
@ -39,7 +39,7 @@ fun BottomButton(
if (backDesc != null) {
Spacer(modifier = Modifier.width(10.dp))
OutlinedButton(onClick = {
if (onBack == null) context.onBackPressed() else onBack()
if (onBack == null) context?.onBackPressed() else onBack()
}, modifier = Modifier.background(color = MaterialTheme.colors.secondary)) {
Text(text = stringResource(id = backDesc))
}

@ -1,6 +1,7 @@
package com.gyf.lib.util
import com.google.gson.*
import com.gyf.csams.module.ApiResponse
import com.gyf.csams.module.Token
import com.orhanobut.logger.Logger
import okhttp3.*
@ -152,13 +153,21 @@ object HttpClient {
* @param url
* @param callback
*/
fun uploadFile(url: String, callback: Callback, vararg fileList: File) {
fun uploadFile(
url: String,
callback: Callback,
params: Map<String, String>? = null,
vararg fileList: File
) {
Logger.i("request url=$url")
val token = TokenManager.getToken()
val body = MultipartBody.Builder()
.addFormDataPart("id", token.id.toString())
.addFormDataPart("token", token.token)
.addFormDataPart("createTime", token.createTime.toString())
params?.forEach {
body.addFormDataPart(it.key, it.value)
}
fileList.withIndex().forEach {
body.addFormDataPart(
"file${it.index}",
@ -175,16 +184,6 @@ object HttpClient {
}
}
/**
* 接口响应实体
*
* @param T
* @property code
* @property message
* @property body
*/
data class ApiResponse<T>(val code: Int, val message: String, val body: T? = null)
interface GsonBuilderInterface {
val gson: Gson

Loading…
Cancel
Save