格式化代码

增加应用通知
master
pan 4 years ago
parent 589f19b69d
commit 6f85668740
  1. 34
      app/src/main/AndroidManifest.xml
  2. 22
      app/src/main/java/com/gyf/csams/APP.kt
  3. 12
      app/src/main/java/com/gyf/csams/Api.kt
  4. 18
      app/src/main/java/com/gyf/csams/InitActivity.kt
  5. 49
      app/src/main/java/com/gyf/csams/InitViewModel.kt
  6. 278
      app/src/main/java/com/gyf/csams/account/model/AccountViewModel.kt
  7. 278
      app/src/main/java/com/gyf/csams/account/ui/AccountActivity.kt
  8. 161
      app/src/main/java/com/gyf/csams/activity/model/ActivityDetailViewModel.kt
  9. 74
      app/src/main/java/com/gyf/csams/association/model/AssociationViewModel.kt
  10. 122
      app/src/main/java/com/gyf/csams/association/model/ExamViewModel.kt
  11. 28
      app/src/main/java/com/gyf/csams/association/model/RegAssociationViewModel.kt
  12. 16
      app/src/main/java/com/gyf/csams/association/model/RenameViewModel.kt
  13. 425
      app/src/main/java/com/gyf/csams/association/ui/AssociationActivity.kt
  14. 93
      app/src/main/java/com/gyf/csams/association/ui/ExamActivity.kt
  15. 65
      app/src/main/java/com/gyf/csams/association/ui/ReNameActivity.kt
  16. 143
      app/src/main/java/com/gyf/csams/association/ui/RegAssociationActivity.kt
  17. 113
      app/src/main/java/com/gyf/csams/main/model/MainViewModel.kt
  18. 77
      app/src/main/java/com/gyf/csams/main/ui/MainActivity.kt
  19. 11
      app/src/main/java/com/gyf/csams/message/model/MessageViewModel.kt
  20. 136
      app/src/main/java/com/gyf/csams/message/model/SysMessageViewModel.kt
  21. 81
      app/src/main/java/com/gyf/csams/message/ui/MessageActivity.kt
  22. 135
      app/src/main/java/com/gyf/csams/message/ui/SysMessageActivity.kt
  23. 154
      app/src/main/java/com/gyf/csams/uikit/BaseView.kt
  24. 69
      app/src/main/java/com/gyf/csams/uikit/ViewModel.kt
  25. 83
      app/src/main/java/com/gyf/csams/util/GsonUtil.kt
  26. 66
      app/src/main/java/com/gyf/csams/util/HttpUtil.kt
  27. 28
      app/src/main/java/com/gyf/csams/util/RandomUtil.kt
  28. 10
      app/src/main/java/com/gyf/csams/util/TokenUtil.kt
  29. 9
      app/src/main/res/drawable/ic_notice.xml

@ -49,24 +49,34 @@
</activity> </activity>
<!--社团主界面--> <!--社团主界面-->
<activity android:name=".association.ui.AssociationActivity" <activity
android:exported="true"> android:name=".association.ui.AssociationActivity"
</activity> android:exported="true"></activity>
<!--社团重命名主界面--> <!--社团重命名主界面-->
<activity android:name=".association.ui.ReNameActivity" <activity
android:exported="true"> android:name=".association.ui.ReNameActivity"
</activity> android:exported="true"></activity>
<!--题库界面--> <!--题库界面-->
<activity android:name=".association.ui.ExamActivity" <activity
android:exported="true"> android:name=".association.ui.ExamActivity"
</activity> android:exported="true" />
<!--活动详情--> <!--活动详情-->
<activity android:name=".activity.ui.ActivityDetailActivity" <activity
android:exported="true"> android:name=".activity.ui.ActivityDetailActivity"
</activity> android:exported="true" />
<!--通知-->
<activity
android:name=".message.ui.MessageActivity"
android:exported="true" />
<!--系统通知-->
<activity
android:name=".message.ui.SysMessageActivity"
android:exported="true" />
</application> </application>
</manifest> </manifest>

@ -15,24 +15,30 @@ import com.orhanobut.logger.Logger
class APP : Application() { class APP : Application() {
private lateinit var memoryCache: LruCache<BackgroundImage, Bitmap> private lateinit var memoryCache: LruCache<BackgroundImage, Bitmap>
// Get max available VM memory, exceeding this amount will throw an // Get max available VM memory, exceeding this amount will throw an
// OutOfMemory exception. Stored in kilobytes as LruCache takes an // OutOfMemory exception. Stored in kilobytes as LruCache takes an
// int in its constructor. // int in its constructor.
private val maxMemory = (Runtime.getRuntime().maxMemory() / 1024).toInt() private val maxMemory = (Runtime.getRuntime().maxMemory() / 1024).toInt()
// Use 1/8th of the available memory for this memory cache. // Use 1/8th of the available memory for this memory cache.
val cacheSize = maxMemory / 8 val cacheSize = maxMemory / 8
fun getImage(image: BackgroundImage, reqWidth: Int, reqHeight: Int): ImageBitmap { fun getImage(image: BackgroundImage, reqWidth: Int, reqHeight: Int): ImageBitmap {
val bitmap=memoryCache.get(image) val bitmap = memoryCache.get(image)
return if(bitmap==null){ return if (bitmap == null) {
Logger.i("reqWidth=$reqWidth,reqHeight=$reqHeight") Logger.i("reqWidth=$reqWidth,reqHeight=$reqHeight")
val cacheValue= decodeSampledBitmapFromResource(res = resources,image.id,reqWidth=reqWidth,reqHeight=reqHeight) val cacheValue = decodeSampledBitmapFromResource(
res = resources,
image.id,
reqWidth = reqWidth,
reqHeight = reqHeight
)
memoryCache.put(image, cacheValue) memoryCache.put(image, cacheValue)
Logger.i("添加缓存:${image}") Logger.i("添加缓存:${image}")
cacheValue.asImageBitmap() cacheValue.asImageBitmap()
}else{ } else {
Logger.i("从缓存读取:${image}") Logger.i("从缓存读取:${image}")
bitmap.asImageBitmap() bitmap.asImageBitmap()
} }
@ -59,7 +65,11 @@ class APP : Application() {
} }
} }
private fun calculateInSampleSize(options: BitmapFactory.Options, reqWidth: Int, reqHeight: Int): Int { private fun calculateInSampleSize(
options: BitmapFactory.Options,
reqWidth: Int,
reqHeight: Int
): Int {
// Raw height and width of image // Raw height and width of image
val (height: Int, width: Int) = options.run { outHeight to outWidth } val (height: Int, width: Int) = options.run { outHeight to outWidth }
var inSampleSize = 1 var inSampleSize = 1

@ -1,8 +1,8 @@
package com.gyf.csams package com.gyf.csams
interface UrlPath{ interface UrlPath {
fun build():String fun build(): String
} }
/** /**
@ -10,7 +10,7 @@ interface UrlPath{
* *
* @property path * @property path
*/ */
enum class AccountApi(val path: String):UrlPath{ enum class AccountApi(val path: String) : UrlPath {
register("/register"), register("/register"),
checkId("/register/checkId"), checkId("/register/checkId"),
login("/login"), login("/login"),
@ -27,13 +27,13 @@ enum class AccountApi(val path: String):UrlPath{
* *
*/ */
class Api { class Api {
companion object{ companion object {
fun buildUrl(urlPath: UrlPath):String{ fun buildUrl(urlPath: UrlPath): String {
return "${BuildConfig.SERVER_ADDRESS}${urlPath.build()}" return "${BuildConfig.SERVER_ADDRESS}${urlPath.build()}"
} }
} }
} }
const val NOT_IMPL_TIP="功能尚未实现!" const val NOT_IMPL_TIP = "功能尚未实现!"

@ -22,16 +22,16 @@ class InitActivity : ComponentActivity() {
// 检查网络 // 检查网络
setContent { setContent {
val initViewModel:InitViewModel= viewModel() val initViewModel: InitViewModel = viewModel()
initViewModel.checkServer() initViewModel.checkServer()
val isNetWorkWorking:Boolean? by initViewModel.isNetWorkWorking.observeAsState(null) val isNetWorkWorking: Boolean? by initViewModel.isNetWorkWorking.observeAsState(null)
when(isNetWorkWorking){ when (isNetWorkWorking) {
null-> AnimationText(text = "检查服务器网络状态中!!!") null -> AnimationText(text = "检查服务器网络状态中!!!")
true-> { true -> {
Init() Init()
finish() finish()
} }
false->{ false -> {
TODO("无法连接到服务器,请检查本地网络或联系管理员") TODO("无法连接到服务器,请检查本地网络或联系管理员")
} }
} }
@ -40,16 +40,16 @@ class InitActivity : ComponentActivity() {
@Composable @Composable
private fun Init(initViewModel:InitViewModel= viewModel()){ private fun Init(initViewModel: InitViewModel = viewModel()) {
Logger.i("初始化。。。。") Logger.i("初始化。。。。")
val context= LocalContext.current val context = LocalContext.current
//后台检查token //后台检查token
initViewModel.hasOnlyUserToken(context) initViewModel.hasOnlyUserToken(context)
//监听token校验状态 //监听token校验状态
val isValid: Boolean? by initViewModel.token.observeAsState(null) val isValid: Boolean? by initViewModel.token.observeAsState(null)
when (isValid) { when (isValid) {
false -> context.startActivity(Intent(context, AccountActivity::class.java)) false -> context.startActivity(Intent(context, AccountActivity::class.java))
true -> context.startActivity(Intent(context, MainActivity::class.java)) true -> context.startActivity(Intent(context, MainActivity::class.java))
} }

@ -11,9 +11,9 @@ import com.gyf.csams.util.*
import com.orhanobut.logger.Logger import com.orhanobut.logger.Logger
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
data class TokenVo(val token:String,val studentId:String) data class TokenVo(val token: String, val studentId: String)
class InitViewModel: ViewModel() { class InitViewModel : ViewModel() {
/** /**
* 服务器网络状态是否正常true=正常false=不正常 * 服务器网络状态是否正常true=正常false=不正常
*/ */
@ -27,7 +27,7 @@ class InitViewModel: ViewModel() {
val token: LiveData<Boolean> = _token val token: LiveData<Boolean> = _token
fun checkServer(){ fun checkServer() {
Logger.i("测试连接到服务端") Logger.i("测试连接到服务端")
_isNetWorkWorking.postValue(true) _isNetWorkWorking.postValue(true)
} }
@ -35,29 +35,38 @@ class InitViewModel: ViewModel() {
/** /**
* 查询本地是否有且只有一个用户token如果有则自动登录 * 查询本地是否有且只有一个用户token如果有则自动登录
*/ */
fun hasOnlyUserToken(context: Context){ fun hasOnlyUserToken(context: Context) {
viewModelScope.launch{ viewModelScope.launch {
val db=AppDatabase.getInstance(context) val db = AppDatabase.getInstance(context)
val tokenList=db?.tokenDao()?.queryAll() val tokenList = db?.tokenDao()?.queryAll()
if (tokenList != null && tokenList.size == 1) { if (tokenList != null && tokenList.size == 1) {
val currentToken: Token = tokenList[0] val currentToken: Token = tokenList[0]
val url=Api.buildUrl(AccountApi.loginToken) val url = Api.buildUrl(AccountApi.loginToken)
val action="校验token" val action = "校验token"
Logger.i("${action}api=$url") Logger.i("${action}api=$url")
HttpClient.post(url,SimpleCallback<Boolean>( HttpClient.post(
action=action, url,
onSuccess = { SimpleCallback<Boolean>(
_token.postValue(it.body) action = action,
Logger.i("token校验结果:${it.body}") onSuccess = {
}, _token.postValue(it.body)
onFail = { TODO("token校验失败")}, Logger.i("token校验结果:${it.body}")
type = object : TypeToken<ApiResponse<Boolean>>(){}.type },
),jsonBody = Gson().toJson(TokenVo(token=currentToken.token,studentId = currentToken.studentId))) onFail = { TODO("token校验失败") },
}else if(tokenList != null && tokenList.size > 1){ type = object : TypeToken<ApiResponse<Boolean>>() {}.type
),
jsonBody = Gson().toJson(
TokenVo(
token = currentToken.token,
studentId = currentToken.studentId
)
)
)
} else if (tokenList != null && tokenList.size > 1) {
//TODO 实现切换历史登录帐号 //TODO 实现切换历史登录帐号
Logger.i("token数量大于一,需要手动登录") Logger.i("token数量大于一,需要手动登录")
_token.postValue(false) _token.postValue(false)
}else{ } else {
Logger.i("本地没有任何token,跳转到登录界面") Logger.i("本地没有任何token,跳转到登录界面")
_token.postValue(false) _token.postValue(false)
} }

@ -25,7 +25,7 @@ import kotlinx.serialization.Serializable
* @property password * @property password
*/ */
@Serializable @Serializable
data class UserResDto(val password:String) data class UserResDto(val password: String)
/** /**
* 构造登录注册信息实体表单 * 构造登录注册信息实体表单
@ -33,7 +33,7 @@ data class UserResDto(val password:String)
* @property studentId 学号 * @property studentId 学号
* @property name 姓名 * @property name 姓名
*/ */
data class UserVo(val studentId:String,val name:String) data class UserVo(val studentId: String, val name: String)
/** /**
* 用户登陆表单 * 用户登陆表单
@ -42,7 +42,7 @@ data class UserVo(val studentId:String,val name:String)
* @property password 密码 * @property password 密码
* @property device 设备型号 * @property device 设备型号
*/ */
data class UserLoginVo(val studentId: String,val password: String,val device: String) data class UserLoginVo(val studentId: String, val password: String, val device: String)
/** /**
* 密码弹窗信息 * 密码弹窗信息
@ -50,9 +50,9 @@ data class UserLoginVo(val studentId: String,val password: String,val device: St
* @property message * @property message
* @property userResDto * @property userResDto
*/ */
data class DialogMessage(val message:String,val userResDto: UserResDto?) data class DialogMessage(val message: String, val userResDto: UserResDto?)
typealias Token= TokenResDto typealias Token = TokenResDto
/** /**
* 注册表单 * 注册表单
@ -61,90 +61,97 @@ class AccountViewModel(application: Application) : AndroidViewModel(application)
//欢迎信息 //欢迎信息
val welcomeStart="同学您好\n" val welcomeStart = "同学您好\n"
val welcomeEnd="欢迎使用" val welcomeEnd = "欢迎使用"
//学号 //学号
private val _studentId=MutableLiveData<String>() private val _studentId = MutableLiveData<String>()
val studentId:LiveData<String> = _studentId val studentId: LiveData<String> = _studentId
private val _isValidStudentId=MutableLiveData<Boolean>() private val _isValidStudentId = MutableLiveData<Boolean>()
val isValidStudentId:LiveData<Boolean> = _isValidStudentId val isValidStudentId: LiveData<Boolean> = _isValidStudentId
val studentIdDesc="学号" val studentIdDesc = "学号"
val studentIdPlaceholder="请输入$studentIdDesc" val studentIdPlaceholder = "请输入$studentIdDesc"
val studentIdFormat="入学年份(四位)+班级代码(两位)+学生代码(两位)" val studentIdFormat = "入学年份(四位)+班级代码(两位)+学生代码(两位)"
//学号已存在 //学号已存在
private val _isRepeat=MutableLiveData<Boolean?>() private val _isRepeat = MutableLiveData<Boolean?>()
val regBtnDesc="注册" val regBtnDesc = "注册"
//已注册 //已注册
val registered="$regBtnDesc" val registered = "$regBtnDesc"
//可注册 //可注册
val canRegister="$regBtnDesc" val canRegister = "$regBtnDesc"
//提示信息 //提示信息
val checkRegTip="检测学号是否已${regBtnDesc}。。。" val checkRegTip = "检测学号是否已${regBtnDesc}。。。"
val isRepeat:LiveData<Boolean?> = _isRepeat val isRepeat: LiveData<Boolean?> = _isRepeat
private var checkJob: Job? = null private var checkJob: Job? = null
//姓名 //姓名
private val _name=MutableLiveData<String>() private val _name = MutableLiveData<String>()
val name:LiveData<String> = _name val name: LiveData<String> = _name
val nameDesc="姓名" val nameDesc = "姓名"
val namePlaceholder="请输入$nameDesc" val namePlaceholder = "请输入$nameDesc"
private val _isValidName=MutableLiveData<Boolean>() private val _isValidName = MutableLiveData<Boolean>()
val isValidName:LiveData<Boolean> = _isValidName val isValidName: LiveData<Boolean> = _isValidName
val nameFormat="姓名不能为空" val nameFormat = "姓名不能为空"
//密码 //密码
private val _password=MutableLiveData<String>() private val _password = MutableLiveData<String>()
val password:LiveData<String> = _password val password: LiveData<String> = _password
val passwordDesc="密码" val passwordDesc = "密码"
val passwordPlaceholder="请输入$passwordDesc" val passwordPlaceholder = "请输入$passwordDesc"
private val _isValidPwd=MutableLiveData<Boolean>() private val _isValidPwd = MutableLiveData<Boolean>()
val isValidPwd:LiveData<Boolean> = _isValidPwd val isValidPwd: LiveData<Boolean> = _isValidPwd
val passwordFormat="八位纯数字" val passwordFormat = "八位纯数字"
//注册按钮 //注册按钮
private val _isValidForm=MutableLiveData<Boolean>() private val _isValidForm = MutableLiveData<Boolean>()
val isValidForm: LiveData<Boolean> = _isValidForm
val isValidForm:LiveData<Boolean> = _isValidForm
//注册请求响应信息 //注册请求响应信息
private val _snackBarMsg=MutableLiveData<String>() private val _snackBarMsg = MutableLiveData<String>()
val snackBarMsg:LiveData<String> = _snackBarMsg val snackBarMsg: LiveData<String> = _snackBarMsg
private val _dialogMsg=MutableLiveData<DialogMessage>() private val _dialogMsg = MutableLiveData<DialogMessage>()
val dialogMsg:LiveData<DialogMessage> = _dialogMsg val dialogMsg: LiveData<DialogMessage> = _dialogMsg
val loginDesc="登陆" val loginDesc = "登陆"
//返回登陆 //返回登陆
val backLogin="返回$loginDesc" val backLogin = "返回$loginDesc"
//确定按钮 //确定按钮
val confirmDesc="确定" val confirmDesc = "确定"
//显示密码提示 //显示密码提示
val title="提示信息" val title = "提示信息"
val passwordTip="密码会在点击${regBtnDesc}以后,在后台自动生成,请留意系统提示。" val passwordTip = "密码会在点击${regBtnDesc}以后,在后台自动生成,请留意系统提示。"
val passwordDialogStart="${regBtnDesc}成功,后台为您自动生成的密码是" val passwordDialogStart = "${regBtnDesc}成功,后台为您自动生成的密码是"
val passwordDialogEnd="\n密码有且只有这里显示一次,请在记住密码后点击确定或${backLogin}" val passwordDialogEnd = "\n密码有且只有这里显示一次,请在记住密码后点击确定或${backLogin}"
//转到注册 //转到注册
var goRegister="转到$regBtnDesc" var goRegister = "转到$regBtnDesc"
/** /**
* 完成登录状态 * 完成登录状态
*/ */
private val _finishLogin=MutableLiveData<Boolean>() private val _finishLogin = MutableLiveData<Boolean>()
val finishLogin:LiveData<Boolean> = _finishLogin val finishLogin: LiveData<Boolean> = _finishLogin
lateinit var route:AccountRoute lateinit var route: AccountRoute
/** /**
* 更新学号 * 更新学号
* *
* @param studentId 学号 * @param studentId 学号
*/ */
fun onStudentIdChange(studentId:String){ fun onStudentIdChange(studentId: String) {
_studentId.value=studentId _studentId.value = studentId
viewModelScope.launch { viewModelScope.launch {
checkRepeat() checkRepeat()
@ -158,35 +165,37 @@ class AccountViewModel(application: Application) : AndroidViewModel(application)
*/ */
private fun checkStudentId(): Boolean { private fun checkStudentId(): Boolean {
_isValidStudentId.value= _studentId.value?.matches(Regex("\\d{8}")) _isValidStudentId.value = _studentId.value?.matches(Regex("\\d{8}"))
return _isValidStudentId.value==true return _isValidStudentId.value == true
} }
/** /**
* 检查学号是否已注册 * 检查学号是否已注册
* *
*/ */
private suspend fun checkRepeat(){ private suspend fun checkRepeat() {
if (checkStudentId()) { if (checkStudentId()) {
if (checkJob?.isActive == true) { if (checkJob?.isActive == true) {
checkJob?.join() checkJob?.join()
}else { } else {
_isRepeat.postValue(null) _isRepeat.postValue(null)
checkJob = viewModelScope.launch { checkJob = viewModelScope.launch {
val url = Api.buildUrl(AccountApi.checkId) val url = Api.buildUrl(AccountApi.checkId)
Logger.i("检测$studentIdDesc,请求接口$url") Logger.i("检测$studentIdDesc,请求接口$url")
HttpClient.get( HttpClient.get(
url, SimpleCallback<Boolean>( url, SimpleCallback<Boolean>(
action = "${studentIdDesc}重复检测", action = "${studentIdDesc}重复检测",
onSuccess = { _isRepeat.postValue(it.body) onSuccess = {
_isValidForm.postValue( _isValidName.value==true && it.body==false) _isRepeat.postValue(it.body)
}, _isValidForm.postValue(_isValidName.value == true && it.body == false)
onFail = { _snackBarMsg.postValue(it) }, },
type = object : TypeToken<ApiResponse<Boolean>>() {}.type) onFail = { _snackBarMsg.postValue(it) },
, mapOf("studentId" to "${_studentId.value}")) type = object : TypeToken<ApiResponse<Boolean>>() {}.type
), mapOf("studentId" to "${_studentId.value}")
)
} }
} }
}else{ } else {
_isValidForm.postValue(false) _isValidForm.postValue(false)
} }
} }
@ -197,8 +206,8 @@ class AccountViewModel(application: Application) : AndroidViewModel(application)
* *
* @param name 姓名 * @param name 姓名
*/ */
fun onNameChange(name:String){ fun onNameChange(name: String) {
_name.value=name _name.value = name
checkForm() checkForm()
} }
@ -207,9 +216,9 @@ class AccountViewModel(application: Application) : AndroidViewModel(application)
* *
* @return * @return
*/ */
private fun checkName():Boolean{ private fun checkName(): Boolean {
_isValidName.value= _name.value?.isNotEmpty() _isValidName.value = _name.value?.isNotEmpty()
return _isValidName.value==true return _isValidName.value == true
} }
/** /**
@ -217,8 +226,8 @@ class AccountViewModel(application: Application) : AndroidViewModel(application)
* *
* @param password 密码 * @param password 密码
*/ */
fun onPasswordChange(password: String){ fun onPasswordChange(password: String) {
_password.value=password _password.value = password
checkForm() checkForm()
} }
@ -227,16 +236,17 @@ class AccountViewModel(application: Application) : AndroidViewModel(application)
* *
* @return * @return
*/ */
private fun checkPassword():Boolean{ private fun checkPassword(): Boolean {
_isValidPwd.value= _password.value?.matches(Regex("\\d{8}")) _isValidPwd.value = _password.value?.matches(Regex("\\d{8}"))
return _isValidPwd.value==true return _isValidPwd.value == true
} }
private fun checkForm(): Boolean { private fun checkForm(): Boolean {
if(checkJob?.isActive==true){ if (checkJob?.isActive == true) {
_isValidForm.value = false _isValidForm.value = false
}else{ } else {
_isValidForm.value = checkStudentId() && (if (route==AccountRoute.register) checkName()&&isRepeat.value==false else checkPassword()) _isValidForm.value =
checkStudentId() && (if (route == AccountRoute.register) checkName() && isRepeat.value == false else checkPassword())
} }
return _isValidForm.value == true return _isValidForm.value == true
} }
@ -245,18 +255,33 @@ class AccountViewModel(application: Application) : AndroidViewModel(application)
* 注册 * 注册
* *
*/ */
fun register(){ fun register() {
if(checkForm()){ if (checkForm()) {
val url= Api.buildUrl(AccountApi.register) val url = Api.buildUrl(AccountApi.register)
Logger.i("开始$regBtnDesc,请求接口:$url") Logger.i("开始$regBtnDesc,请求接口:$url")
HttpClient.post(url,SimpleCallback<UserResDto>( HttpClient.post(
action = regBtnDesc, url, SimpleCallback<UserResDto>(
onSuccess = { _dialogMsg.postValue(DialogMessage(message = it.message,userResDto = it.body)) }, action = regBtnDesc,
onFail = { _snackBarMsg.postValue(it)}, onSuccess = {
type = object : TypeToken<ApiResponse<UserResDto>>() {}.type), _dialogMsg.postValue(
jsonBody = Gson().toJson(UserVo(studentId = "${studentId.value}",name = "${name.value}"))) DialogMessage(
message = it.message,
userResDto = it.body
)
)
},
onFail = { _snackBarMsg.postValue(it) },
type = object : TypeToken<ApiResponse<UserResDto>>() {}.type
),
jsonBody = Gson().toJson(
UserVo(
studentId = "${studentId.value}",
name = "${name.value}"
)
)
)
resetForm() resetForm()
}else{ } else {
Logger.wtf("表单校验失败,无法$regBtnDesc!!!") Logger.wtf("表单校验失败,无法$regBtnDesc!!!")
} }
} }
@ -269,52 +294,61 @@ class AccountViewModel(application: Application) : AndroidViewModel(application)
* 重置信息 * 重置信息
* *
*/ */
fun resetRegisterResMsg(){ fun resetRegisterResMsg() {
_snackBarMsg.value="" _snackBarMsg.value = ""
} }
fun resetDialogMsg(){ fun resetDialogMsg() {
_dialogMsg.value=null _dialogMsg.value = null
} }
private fun resetForm(){ private fun resetForm() {
_studentId.value="" _studentId.value = ""
_name.value="" _name.value = ""
} }
/** /**
* 登录 * 登录
* *
*/ */
fun login(){ fun login() {
if(checkForm()){ if (checkForm()) {
val url = Api.buildUrl(AccountApi.login) val url = Api.buildUrl(AccountApi.login)
Logger.i("开始$loginDesc,请求接口:$url") Logger.i("开始$loginDesc,请求接口:$url")
HttpClient.post(url,SimpleCallback<Token>( HttpClient.post(
action = loginDesc, url,
onSuccess = { SimpleCallback<Token>(
_snackBarMsg.postValue(it.message) action = loginDesc,
onSuccess = {
val context= getApplication<Application>().applicationContext _snackBarMsg.postValue(it.message)
val token = it.body?.token
if(token!=null){ val context = getApplication<Application>().applicationContext
val db= AppDatabase.getInstance(context) val token = it.body?.token
viewModelScope.launch { if (token != null) {
db?.tokenDao()?.save(token = token) val db = AppDatabase.getInstance(context)
}.invokeOnCompletion { viewModelScope.launch {
context.startActivity(Intent(context, InitActivity::class.java)) db?.tokenDao()?.save(token = token)
_finishLogin.postValue(true) }.invokeOnCompletion {
context.startActivity(Intent(context, InitActivity::class.java))
_finishLogin.postValue(true)
}
} }
} },
}, onFail = { _snackBarMsg.postValue(it) },
onFail = {_snackBarMsg.postValue(it)}, type = object : TypeToken<ApiResponse<Token>>() {}.type
type = object : TypeToken<ApiResponse<Token>>(){}.type ),
),jsonBody = Gson().toJson(UserLoginVo(studentId = "${studentId.value}",password = "${password.value}",device = "${Build.MANUFACTURER} ${Build.MODEL}"))) jsonBody = Gson().toJson(
}else{ UserLoginVo(
studentId = "${studentId.value}",
password = "${password.value}",
device = "${Build.MANUFACTURER} ${Build.MODEL}"
)
)
)
} else {
Logger.wtf("表单校验失败,无法$loginDesc!!!") Logger.wtf("表单校验失败,无法$loginDesc!!!")
} }
} }
} }

@ -35,64 +35,79 @@ import com.gyf.csams.uikit.Body
import com.gyf.csams.uikit.theme.CSAMSTheme import com.gyf.csams.uikit.theme.CSAMSTheme
enum class AccountRoute{ enum class AccountRoute {
login, login,
register register
} }
class AccountActivity: ComponentActivity() { class AccountActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
setContent { setContent {
CSAMSTheme { CSAMSTheme {
Body { Body { nav, scaffoldState ->
nav, scaffoldState ->
NavHost(navController = nav, startDestination = AccountRoute.login.name) { NavHost(navController = nav, startDestination = AccountRoute.login.name) {
composable(AccountRoute.login.name) { composable(AccountRoute.login.name) {
Account(scaffoldState=scaffoldState,route = AccountRoute.login) { isValidForm: Boolean, accountViewModel: AccountViewModel -> Account(
scaffoldState = scaffoldState,
route = AccountRoute.login
) { isValidForm: Boolean, accountViewModel: AccountViewModel ->
Spacer(modifier = Modifier.height(10.dp)) Spacer(modifier = Modifier.height(10.dp))
OutlinedButton(onClick = {accountViewModel.login()}, OutlinedButton(
onClick = { accountViewModel.login() },
enabled = isValidForm, enabled = isValidForm,
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.padding(bottom = 10.dp)) { .padding(bottom = 10.dp)
) {
Text(text = accountViewModel.loginDesc) Text(text = accountViewModel.loginDesc)
} }
val finishLogin:Boolean? by accountViewModel.finishLogin.observeAsState() val finishLogin: Boolean? by accountViewModel.finishLogin.observeAsState()
if(finishLogin==true){ if (finishLogin == true) {
finish() finish()
} }
OutlinedButton(onClick = { nav.navigate(AccountRoute.register.name)}, OutlinedButton(
onClick = { nav.navigate(AccountRoute.register.name) },
modifier = Modifier.fillMaxWidth(), modifier = Modifier.fillMaxWidth(),
colors = ButtonDefaults.outlinedButtonColors( colors = ButtonDefaults.outlinedButtonColors(
contentColor = MaterialTheme.colors.onBackground)) { contentColor = MaterialTheme.colors.onBackground
Text(text = accountViewModel.goRegister) )
) {
Text(text = accountViewModel.goRegister)
} }
} }
} }
composable(AccountRoute.register.name) { composable(AccountRoute.register.name) {
Account(scaffoldState=scaffoldState,route = AccountRoute.register) { isValidForm: Boolean, accountViewModel: AccountViewModel -> Account(
scaffoldState = scaffoldState,
route = AccountRoute.register
) { isValidForm: Boolean, accountViewModel: AccountViewModel ->
Spacer(modifier = Modifier.height(10.dp)) Spacer(modifier = Modifier.height(10.dp))
OutlinedButton(onClick = { accountViewModel.register()}, OutlinedButton(
onClick = { accountViewModel.register() },
enabled = isValidForm, enabled = isValidForm,
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.padding(bottom = 10.dp)) { .padding(bottom = 10.dp)
) {
Text(text = accountViewModel.regBtnDesc) Text(text = accountViewModel.regBtnDesc)
} }
OutlinedButton(onClick = { nav.navigate(AccountRoute.login.name)}, OutlinedButton(
onClick = { nav.navigate(AccountRoute.login.name) },
modifier = Modifier.fillMaxWidth(), modifier = Modifier.fillMaxWidth(),
colors = ButtonDefaults.outlinedButtonColors( colors = ButtonDefaults.outlinedButtonColors(
contentColor = MaterialTheme.colors.onBackground)) { contentColor = MaterialTheme.colors.onBackground
)
) {
Text(text = accountViewModel.backLogin) Text(text = accountViewModel.backLogin)
} }
} }
@ -111,64 +126,66 @@ class AccountActivity: ComponentActivity() {
* @param Action 表单操作区域 * @param Action 表单操作区域
*/ */
@Composable @Composable
private fun Account(accountViewModel: AccountViewModel = viewModel(), private fun Account(
scaffoldState: ScaffoldState, accountViewModel: AccountViewModel = viewModel(),
route: AccountRoute, scaffoldState: ScaffoldState,
Action: @Composable (isValidForm:Boolean,accountViewModel: AccountViewModel) -> Unit){ route: AccountRoute,
accountViewModel.route=route Action: @Composable (isValidForm: Boolean, accountViewModel: AccountViewModel) -> Unit
Row( ) {
horizontalArrangement = Arrangement.Center, accountViewModel.route = route
verticalAlignment = Alignment.CenterVertically, Row(
modifier = Modifier.fillMaxSize() horizontalArrangement = Arrangement.Center,
) { verticalAlignment = Alignment.CenterVertically,
Column(modifier = Modifier.width(IntrinsicSize.Min)) { modifier = Modifier.fillMaxSize()
val name: String by accountViewModel.name.observeAsState("") ) {
Text(buildAnnotatedString { Column(modifier = Modifier.width(IntrinsicSize.Min)) {
withStyle( val name: String by accountViewModel.name.observeAsState("")
style = MaterialTheme.typography.subtitle1.toSpanStyle() Text(buildAnnotatedString {
.copy(color = MaterialTheme.colors.primary) withStyle(
) { style = MaterialTheme.typography.subtitle1.toSpanStyle()
append(name) .copy(color = MaterialTheme.colors.primary)
} ) {
withStyle(style = MaterialTheme.typography.subtitle1.toSpanStyle()) { append(name)
append(accountViewModel.welcomeStart) }
} withStyle(style = MaterialTheme.typography.subtitle1.toSpanStyle()) {
withStyle(style = MaterialTheme.typography.subtitle2.toSpanStyle()) { append(accountViewModel.welcomeStart)
append(accountViewModel.welcomeEnd) }
} withStyle(style = MaterialTheme.typography.subtitle2.toSpanStyle()) {
withStyle( append(accountViewModel.welcomeEnd)
style = MaterialTheme.typography.subtitle2.toSpanStyle() }
.copy(color = MaterialTheme.colors.secondary) withStyle(
) { style = MaterialTheme.typography.subtitle2.toSpanStyle()
append(BuildConfig.APP_NAME) .copy(color = MaterialTheme.colors.secondary)
} ) {
}) append(BuildConfig.APP_NAME)
}
})
StudentId(checkRepeat=route==AccountRoute.register) StudentId(checkRepeat = route == AccountRoute.register)
Spacer(modifier = Modifier.height(10.dp)) Spacer(modifier = Modifier.height(10.dp))
if (route==AccountRoute.register) Name(name=name) else Password() if (route == AccountRoute.register) Name(name = name) else Password()
Spacer(modifier = Modifier.height(10.dp)) Spacer(modifier = Modifier.height(10.dp))
PasswordTip() PasswordTip()
val isValidForm: Boolean by accountViewModel.isValidForm.observeAsState(false) val isValidForm: Boolean by accountViewModel.isValidForm.observeAsState(false)
Action(isValidForm=isValidForm,accountViewModel=accountViewModel) Action(isValidForm = isValidForm, accountViewModel = accountViewModel)
val snackBarMsg:String by accountViewModel.snackBarMsg.observeAsState("")
if(snackBarMsg!=""){
LaunchedEffect(scaffoldState) {
scaffoldState.snackbarHostState.showSnackbar(
message = snackBarMsg
)
accountViewModel.resetRegisterResMsg()
}
}
RegisterDialog() val snackBarMsg: String by accountViewModel.snackBarMsg.observeAsState("")
if (snackBarMsg != "") {
LaunchedEffect(scaffoldState) {
scaffoldState.snackbarHostState.showSnackbar(
message = snackBarMsg
)
accountViewModel.resetRegisterResMsg()
}
} }
RegisterDialog()
} }
}
} }
/** /**
@ -177,11 +194,11 @@ private fun Account(accountViewModel: AccountViewModel = viewModel(),
* @param accountViewModel * @param accountViewModel
*/ */
@Composable @Composable
private fun StudentId(accountViewModel: AccountViewModel = viewModel(),checkRepeat:Boolean){ private fun StudentId(accountViewModel: AccountViewModel = viewModel(), checkRepeat: Boolean) {
Column { Column {
val studentId: String by accountViewModel.studentId.observeAsState("") val studentId: String by accountViewModel.studentId.observeAsState("")
val isValidStudentId : Boolean by accountViewModel.isValidStudentId.observeAsState(false) val isValidStudentId: Boolean by accountViewModel.isValidStudentId.observeAsState(false)
val focusManager = LocalFocusManager.current val focusManager = LocalFocusManager.current
OutlinedTextField( OutlinedTextField(
value = studentId, value = studentId,
@ -189,12 +206,15 @@ private fun StudentId(accountViewModel: AccountViewModel = viewModel(),checkRepe
label = { Text(text = accountViewModel.studentIdDesc) }, label = { Text(text = accountViewModel.studentIdDesc) },
placeholder = { Text(text = accountViewModel.studentIdPlaceholder) }, placeholder = { Text(text = accountViewModel.studentIdPlaceholder) },
keyboardActions = KeyboardActions(onDone = { focusManager.clearFocus() }), keyboardActions = KeyboardActions(onDone = { focusManager.clearFocus() }),
keyboardOptions = KeyboardOptions.Default.copy( keyboardType = KeyboardType.Number,imeAction = ImeAction.Done), keyboardOptions = KeyboardOptions.Default.copy(
keyboardType = KeyboardType.Number,
imeAction = ImeAction.Done
),
singleLine = true, singleLine = true,
isError = !isValidStudentId isError = !isValidStudentId
) )
if (isValidStudentId) { if (isValidStudentId) {
if(checkRepeat) { if (checkRepeat) {
val isRepeat: Boolean? by accountViewModel.isRepeat.observeAsState(null) val isRepeat: Boolean? by accountViewModel.isRepeat.observeAsState(null)
when (isRepeat) { when (isRepeat) {
null -> AnimationText(text = accountViewModel.checkRegTip) null -> AnimationText(text = accountViewModel.checkRegTip)
@ -224,7 +244,7 @@ private fun StudentId(accountViewModel: AccountViewModel = viewModel(),checkRepe
}) })
} }
} }
}else{ } else {
Text( Text(
text = accountViewModel.studentIdFormat, text = accountViewModel.studentIdFormat,
color = MaterialTheme.colors.error, color = MaterialTheme.colors.error,
@ -241,11 +261,11 @@ private fun StudentId(accountViewModel: AccountViewModel = viewModel(),checkRepe
* @param accountViewModel * @param accountViewModel
*/ */
@Composable @Composable
private fun RegisterDialog(accountViewModel: AccountViewModel = viewModel()){ private fun RegisterDialog(accountViewModel: AccountViewModel = viewModel()) {
val dialogMsg: DialogMessage? by accountViewModel.dialogMsg.observeAsState(null) val dialogMsg: DialogMessage? by accountViewModel.dialogMsg.observeAsState(null)
val message=dialogMsg?.userResDto?.password val message = dialogMsg?.userResDto?.password
if(message?.isNotEmpty() == true){ if (message?.isNotEmpty() == true) {
PasswordDialog(message = message) PasswordDialog(message = message)
} }
} }
@ -257,21 +277,28 @@ private fun RegisterDialog(accountViewModel: AccountViewModel = viewModel()){
* @param message * @param message
*/ */
@Composable @Composable
private fun PasswordDialog(accountViewModel: AccountViewModel = viewModel(), message:String){ private fun PasswordDialog(accountViewModel: AccountViewModel = viewModel(), message: String) {
val context= LocalContext.current val context = LocalContext.current
val button:@Composable () -> Unit = { val button: @Composable () -> Unit = {
Row(horizontalArrangement= Arrangement.Center,modifier = Modifier Row(
.fillMaxWidth() horizontalArrangement = Arrangement.Center, modifier = Modifier
.padding(bottom = 10.dp)) { .fillMaxWidth()
OutlinedButton(onClick = { accountViewModel.resetDialogMsg() }, .padding(bottom = 10.dp)
modifier = Modifier.padding(end = 10.dp)) { ) {
OutlinedButton(
onClick = { accountViewModel.resetDialogMsg() },
modifier = Modifier.padding(end = 10.dp)
) {
Text(text = accountViewModel.confirmDesc) Text(text = accountViewModel.confirmDesc)
} }
OutlinedButton(onClick = { OutlinedButton(
context.startActivity(Intent(context,AccountActivity::class.java)) onClick = {
}, context.startActivity(Intent(context, AccountActivity::class.java))
},
colors = ButtonDefaults.outlinedButtonColors( colors = ButtonDefaults.outlinedButtonColors(
contentColor = MaterialTheme.colors.onBackground)) { contentColor = MaterialTheme.colors.onBackground
)
) {
Text(text = accountViewModel.backLogin) Text(text = accountViewModel.backLogin)
} }
} }
@ -282,8 +309,10 @@ private fun PasswordDialog(accountViewModel: AccountViewModel = viewModel(), mes
text = { text = {
Text(buildAnnotatedString { Text(buildAnnotatedString {
append(accountViewModel.passwordDialogStart) append(accountViewModel.passwordDialogStart)
withStyle(style = MaterialTheme.typography.body1.toSpanStyle() withStyle(
.copy(color = MaterialTheme.colors.secondary)){ style = MaterialTheme.typography.body1.toSpanStyle()
.copy(color = MaterialTheme.colors.secondary)
) {
append(message) append(message)
} }
append(accountViewModel.passwordDialogEnd) append(accountViewModel.passwordDialogEnd)
@ -292,7 +321,6 @@ private fun PasswordDialog(accountViewModel: AccountViewModel = viewModel(), mes
} }
/** /**
* 姓名文本框 * 姓名文本框
* TODO 需要把逻辑封装到[com.gyf.csams.uikit.BaseTextField] * TODO 需要把逻辑封装到[com.gyf.csams.uikit.BaseTextField]
@ -300,23 +328,27 @@ private fun PasswordDialog(accountViewModel: AccountViewModel = viewModel(), mes
* @param accountViewModel * @param accountViewModel
*/ */
@Composable @Composable
private fun Name(name:String, accountViewModel: AccountViewModel = viewModel()){ private fun Name(name: String, accountViewModel: AccountViewModel = viewModel()) {
Column { Column {
val isValidName:Boolean by accountViewModel.isValidName.observeAsState(false) val isValidName: Boolean by accountViewModel.isValidName.observeAsState(false)
val focusManager = LocalFocusManager.current val focusManager = LocalFocusManager.current
OutlinedTextField(value = name, OutlinedTextField(
onValueChange = {accountViewModel.onNameChange(it)}, value = name,
label={ Text(text = accountViewModel.nameDesc)}, onValueChange = { accountViewModel.onNameChange(it) },
placeholder = { Text(text = accountViewModel.namePlaceholder)}, label = { Text(text = accountViewModel.nameDesc) },
placeholder = { Text(text = accountViewModel.namePlaceholder) },
singleLine = true, singleLine = true,
isError = !isValidName, isError = !isValidName,
keyboardActions = KeyboardActions(onDone = { focusManager.clearFocus() }), keyboardActions = KeyboardActions(onDone = { focusManager.clearFocus() }),
keyboardOptions = KeyboardOptions.Default.copy(imeAction = ImeAction.Done)) keyboardOptions = KeyboardOptions.Default.copy(imeAction = ImeAction.Done)
)
if (!isValidName){ if (!isValidName) {
Text(text = accountViewModel.nameFormat, Text(
color=MaterialTheme.colors.error) text = accountViewModel.nameFormat,
color = MaterialTheme.colors.error
)
} }
} }
@ -328,24 +360,31 @@ private fun Name(name:String, accountViewModel: AccountViewModel = viewModel()){
* @param accountViewModel * @param accountViewModel
*/ */
@Composable @Composable
private fun Password(accountViewModel: AccountViewModel= viewModel()){ private fun Password(accountViewModel: AccountViewModel = viewModel()) {
Column { Column {
val isValidPwd:Boolean by accountViewModel.isValidPwd.observeAsState(false) val isValidPwd: Boolean by accountViewModel.isValidPwd.observeAsState(false)
val focusManager = LocalFocusManager.current val focusManager = LocalFocusManager.current
val password:String by accountViewModel.password.observeAsState("") val password: String by accountViewModel.password.observeAsState("")
OutlinedTextField(value = password, OutlinedTextField(
visualTransformation=PasswordVisualTransformation(), value = password,
onValueChange = {accountViewModel.onPasswordChange(it)}, visualTransformation = PasswordVisualTransformation(),
label={ Text(text = accountViewModel.passwordDesc)}, onValueChange = { accountViewModel.onPasswordChange(it) },
placeholder = { Text(text = accountViewModel.passwordPlaceholder)}, label = { Text(text = accountViewModel.passwordDesc) },
placeholder = { Text(text = accountViewModel.passwordPlaceholder) },
singleLine = true, singleLine = true,
isError = !isValidPwd, isError = !isValidPwd,
keyboardActions = KeyboardActions(onDone = { focusManager.clearFocus() }), keyboardActions = KeyboardActions(onDone = { focusManager.clearFocus() }),
keyboardOptions = KeyboardOptions.Default.copy(imeAction = ImeAction.Done,keyboardType = KeyboardType.Number)) keyboardOptions = KeyboardOptions.Default.copy(
imeAction = ImeAction.Done,
keyboardType = KeyboardType.Number
)
)
if(!isValidPwd){ if (!isValidPwd) {
Text(text = accountViewModel.passwordFormat, Text(
color=MaterialTheme.colors.error) text = accountViewModel.passwordFormat,
color = MaterialTheme.colors.error
)
} }
} }
} }
@ -357,7 +396,7 @@ private fun Password(accountViewModel: AccountViewModel= viewModel()){
*/ */
@Composable @Composable
private fun PasswordTip(accountViewModel: AccountViewModel = viewModel()) { private fun PasswordTip(accountViewModel: AccountViewModel = viewModel()) {
if(accountViewModel.isValidForm.value==true) { if (accountViewModel.isValidForm.value == true) {
Text( Text(
text = accountViewModel.passwordTip, color = MaterialTheme.colors.primary, text = accountViewModel.passwordTip, color = MaterialTheme.colors.primary,
modifier = Modifier.fillMaxWidth() modifier = Modifier.fillMaxWidth()
@ -371,14 +410,15 @@ private fun PasswordTip(accountViewModel: AccountViewModel = viewModel()) {
fun DefaultPreview() { fun DefaultPreview() {
CSAMSTheme { CSAMSTheme {
Row ( Row(
horizontalArrangement=Arrangement.Center, horizontalArrangement = Arrangement.Center,
verticalAlignment = Alignment.CenterVertically, verticalAlignment = Alignment.CenterVertically,
modifier = Modifier.fillMaxSize()) { modifier = Modifier.fillMaxSize()
) {
Column(modifier = Modifier.width(IntrinsicSize.Min)) { Column(modifier = Modifier.width(IntrinsicSize.Min)) {
val model:AccountViewModel= viewModel() val model: AccountViewModel = viewModel()
StudentId(model,false) StudentId(model, false)
Spacer(modifier = Modifier.height(10.dp)) Spacer(modifier = Modifier.height(10.dp))
} }
} }

@ -17,7 +17,7 @@ import java.util.*
* 活动详情菜单通用状态 * 活动详情菜单通用状态
* *
*/ */
class ActivityDetailViewModel:ViewModel(), TopMenuInterface<ActivityDetailMenu> { class ActivityDetailViewModel : ViewModel(), TopMenuInterface<ActivityDetailMenu> {
override val _currentMenu: MutableLiveData<ActivityDetailMenu> = MutableLiveData() override val _currentMenu: MutableLiveData<ActivityDetailMenu> = MutableLiveData()
override val currentMenu: LiveData<ActivityDetailMenu> = _currentMenu override val currentMenu: LiveData<ActivityDetailMenu> = _currentMenu
} }
@ -31,22 +31,23 @@ class ActivityDetailViewModel:ViewModel(), TopMenuInterface<ActivityDetailMenu>
* @property activityLocation 活动地点 * @property activityLocation 活动地点
* @property activityDesc 活动介绍 * @property activityDesc 活动介绍
*/ */
data class ActivityDetailVo(val associationName:String,val activityName:String, data class ActivityDetailVo(
val activityTime:Date,val activityLocation:String, val associationName: String, val activityName: String,
val activityDesc:String) val activityTime: Date, val activityLocation: String,
val activityDesc: String
)
/** /**
* 活动信息 * 活动信息
* *
*/ */
class ActivityInfoViewModel:ViewModel(){ class ActivityInfoViewModel : ViewModel() {
private val _activityDetailVo=MutableLiveData<ActivityDetailVo>() private val _activityDetailVo = MutableLiveData<ActivityDetailVo>()
val activityDetailVo:LiveData<ActivityDetailVo> = _activityDetailVo val activityDetailVo: LiveData<ActivityDetailVo> = _activityDetailVo
val like = "点赞" val like = "点赞"
val collect="收藏" val collect = "收藏"
init { init {
loadInfo() loadInfo()
@ -57,7 +58,7 @@ class ActivityInfoViewModel:ViewModel(){
* *
* @param callback * @param callback
*/ */
fun like(callback:(message:String)->Unit){ fun like(callback: (message: String) -> Unit) {
callback(NOT_IMPL_TIP) callback(NOT_IMPL_TIP)
} }
@ -66,11 +67,11 @@ class ActivityInfoViewModel:ViewModel(){
* *
* @param callback * @param callback
*/ */
fun collect(callback:(message:String)->Unit){ fun collect(callback: (message: String) -> Unit) {
callback(NOT_IMPL_TIP) callback(NOT_IMPL_TIP)
} }
private fun loadInfo(){ private fun loadInfo() {
viewModelScope.launch { viewModelScope.launch {
_activityDetailVo.value = ActivityDetailVo( _activityDetailVo.value = ActivityDetailVo(
activityName = randomChinese(4), activityName = randomChinese(4),
@ -94,20 +95,27 @@ class ActivityInfoViewModel:ViewModel(){
* @property createTime 文件创建时间 * @property createTime 文件创建时间
* @property studentId 文件上传人 * @property studentId 文件上传人
*/ */
data class ActivityPhotoVo(val name:String, val size:Long, val url:String, val md5:String, val createTime: Date, val studentId:String) 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>(){ class ActivityPhotoViewModel : ScrollList<ActivityPhotoVo>() {
override val initSize: Int = 10 override val initSize: Int = 10
init { init {
load() load()
} }
fun upload(callback: (message: String) -> Unit){ fun upload(callback: (message: String) -> Unit) {
callback(NOT_IMPL_TIP) callback(NOT_IMPL_TIP)
} }
@ -118,13 +126,17 @@ class ActivityPhotoViewModel:ScrollList<ActivityPhotoVo>(){
override fun load() { override fun load() {
viewModelScope.launch { viewModelScope.launch {
_data.value?.apply { _data.value?.apply {
repeat(initSize){ repeat(initSize) {
add(ActivityPhotoVo(name=randomChinese(3), add(
size= randomNum(3).toLong(), ActivityPhotoVo(
url="", name = randomChinese(3),
md5 = "", size = randomNum(3).toLong(),
createTime = randomDateTime(), url = "",
studentId = "")) md5 = "",
createTime = randomDateTime(),
studentId = ""
)
)
} }
} }
} }
@ -140,15 +152,19 @@ class ActivityPhotoViewModel:ScrollList<ActivityPhotoVo>(){
Logger.i("加载更多") Logger.i("加载更多")
viewModelScope.launch { viewModelScope.launch {
_data.value?.apply { _data.value?.apply {
val list= mutableListOf<ActivityPhotoVo>() val list = mutableListOf<ActivityPhotoVo>()
list.addAll(this) list.addAll(this)
repeat(initSize){ repeat(initSize) {
add(ActivityPhotoVo(name=randomChinese(3), add(
size= randomNum(3).toLong(), ActivityPhotoVo(
url="", name = randomChinese(3),
md5 = "", size = randomNum(3).toLong(),
createTime = randomDateTime(), url = "",
studentId = "")) md5 = "",
createTime = randomDateTime(),
studentId = ""
)
)
} }
_data.postValue(list) _data.postValue(list)
callback("成功加载更多相册") callback("成功加载更多相册")
@ -157,15 +173,18 @@ class ActivityPhotoViewModel:ScrollList<ActivityPhotoVo>(){
} }
} }
data class ActivityMemberVo(val studentId: String,val name:String) data class ActivityMemberVo(val studentId: String, val name: String)
data class ActivityMembersVo(val organizer:ActivityMemberVo, val participant:MutableList<ActivityMemberVo>?) data class ActivityMembersVo(
val organizer: ActivityMemberVo,
val participant: MutableList<ActivityMemberVo>?
)
class ActivityMemberViewModel:ScrollList<ActivityMemberVo>(){ class ActivityMemberViewModel : ScrollList<ActivityMemberVo>() {
override val initSize: Int = 10 override val initSize: Int = 10
private val _allMember=MutableLiveData<ActivityMembersVo>() private val _allMember = MutableLiveData<ActivityMembersVo>()
val allMember:LiveData<ActivityMembersVo> = _allMember val allMember: LiveData<ActivityMembersVo> = _allMember
init { init {
load() load()
@ -178,10 +197,15 @@ class ActivityMemberViewModel:ScrollList<ActivityMemberVo>(){
override fun load() { override fun load() {
viewModelScope.launch { viewModelScope.launch {
_data.value?.apply { _data.value?.apply {
repeat(initSize){ repeat(initSize) {
add(ActivityMemberVo(studentId = randomNum(),name = randomChinese(3))) add(ActivityMemberVo(studentId = randomNum(), name = randomChinese(3)))
} }
_allMember.value= ActivityMembersVo(organizer = ActivityMemberVo(studentId = randomNum(),name = randomChinese(3)),participant = _data.value) _allMember.value = ActivityMembersVo(
organizer = ActivityMemberVo(
studentId = randomNum(),
name = randomChinese(3)
), participant = _data.value
)
} }
} }
} }
@ -194,14 +218,19 @@ class ActivityMemberViewModel:ScrollList<ActivityMemberVo>(){
override fun loadMore(callback: (message: String) -> Unit) { override fun loadMore(callback: (message: String) -> Unit) {
viewModelScope.launch { viewModelScope.launch {
_data.value?.apply { _data.value?.apply {
val list= mutableListOf<ActivityMemberVo>() val list = mutableListOf<ActivityMemberVo>()
list.addAll(this) list.addAll(this)
repeat(initSize){ repeat(initSize) {
add(ActivityMemberVo(studentId = randomNum(),name = randomChinese(3))) add(ActivityMemberVo(studentId = randomNum(), name = randomChinese(3)))
} }
_allMember.value?.apply { _allMember.value?.apply {
_data.postValue(list) _data.postValue(list)
_allMember.postValue(ActivityMembersVo(organizer=organizer,participant=list)) _allMember.postValue(
ActivityMembersVo(
organizer = organizer,
participant = list
)
)
callback("成功加载更多活动参与者") callback("成功加载更多活动参与者")
} }
} }
@ -209,33 +238,33 @@ class ActivityMemberViewModel:ScrollList<ActivityMemberVo>(){
} }
} }
data class BBSVo(val studentId:String,val name:String,val createTime:Date,val content:String) data class BBSVo(val studentId: String, val name: String, val createTime: Date, val content: String)
/** /**
* 交流区数据状态管理 * 交流区数据状态管理
* *
*/ */
class BBSViewModel:ScrollList<BBSVo>(), SendInterface { class BBSViewModel : ScrollList<BBSVo>(), SendInterface {
override val initSize: Int = 10 override val initSize: Int = 10
val title="发送评论" val title = "发送评论"
override val newContent = StringForm(formDesc = "评论内容",textLength = 80) override val newContent = StringForm(formDesc = "评论内容", textLength = 80)
override val _openDialog=MutableLiveData<Boolean>() override val _openDialog = MutableLiveData<Boolean>()
override val openDialog:LiveData<Boolean> = _openDialog override val openDialog: LiveData<Boolean> = _openDialog
init { init {
load() load()
} }
override fun openDialog(){ override fun openDialog() {
_openDialog.value=true _openDialog.value = true
} }
override fun closeDialog(){ override fun closeDialog() {
_openDialog.value=false _openDialog.value = false
} }
/** /**
@ -243,7 +272,7 @@ class BBSViewModel:ScrollList<BBSVo>(), SendInterface {
* *
* @param callback * @param callback
*/ */
override fun send(callback: (message: String) -> Unit){ override fun send(callback: (message: String) -> Unit) {
callback(NOT_IMPL_TIP) callback(NOT_IMPL_TIP)
} }
@ -254,8 +283,15 @@ class BBSViewModel:ScrollList<BBSVo>(), SendInterface {
override fun load() { override fun load() {
viewModelScope.launch { viewModelScope.launch {
_data.value?.apply { _data.value?.apply {
repeat(initSize){ repeat(initSize) {
add(BBSVo(studentId = randomNum(),createTime = randomDateTime(),content = randomChinese(50),name = randomChinese(3))) add(
BBSVo(
studentId = randomNum(),
createTime = randomDateTime(),
content = randomChinese(50),
name = randomChinese(3)
)
)
} }
} }
} }
@ -269,11 +305,18 @@ class BBSViewModel:ScrollList<BBSVo>(), SendInterface {
override fun loadMore(callback: (message: String) -> Unit) { override fun loadMore(callback: (message: String) -> Unit) {
viewModelScope.launch { viewModelScope.launch {
_data.value?.apply { _data.value?.apply {
repeat(initSize){ repeat(initSize) {
val list= mutableListOf<BBSVo>() val list = mutableListOf<BBSVo>()
list.addAll(this) list.addAll(this)
repeat(initSize){ repeat(initSize) {
add(BBSVo(studentId = randomNum(),name = randomChinese(3),createTime = randomDateTime(),content = randomChinese(50))) add(
BBSVo(
studentId = randomNum(),
name = randomChinese(3),
createTime = randomDateTime(),
content = randomChinese(50)
)
)
} }
_data.postValue(list) _data.postValue(list)
callback("成功加载更多评论") callback("成功加载更多评论")

@ -13,7 +13,7 @@ import com.orhanobut.logger.Logger
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
class AssociationViewModel:ViewModel(),TopMenuInterface<AssociationMenu>{ class AssociationViewModel : ViewModel(), TopMenuInterface<AssociationMenu> {
override val _currentMenu: MutableLiveData<AssociationMenu> = MutableLiveData() override val _currentMenu: MutableLiveData<AssociationMenu> = MutableLiveData()
override val currentMenu: LiveData<AssociationMenu> = _currentMenu override val currentMenu: LiveData<AssociationMenu> = _currentMenu
@ -21,41 +21,40 @@ class AssociationViewModel:ViewModel(),TopMenuInterface<AssociationMenu>{
/** /**
* 下拉菜单状态 * 下拉菜单状态
*/ */
private val _expanded=MutableLiveData(false) private val _expanded = MutableLiveData(false)
val expanded:LiveData<Boolean> = _expanded val expanded: LiveData<Boolean> = _expanded
/** /**
* 切换下拉菜单状态 * 切换下拉菜单状态
* *
*/ */
fun switchType(){ fun switchType() {
_expanded.value?.let { _expanded.value?.let {
_expanded.value = !it _expanded.value = !it
} }
} }
fun close(){ fun close() {
_expanded.value=false _expanded.value = false
} }
} }
data class MemberVo(val name:String) data class MemberVo(val name: String)
/** /**
* 社团会员 * 社团会员
* *
*/ */
class MemberViewModel:ScrollList<MemberVo>(){ class MemberViewModel : ScrollList<MemberVo>() {
val name=StringForm(formDesc = "姓名关键字",5) val name = StringForm(formDesc = "姓名关键字", 5)
val search="搜索" val search = "搜索"
private val _memberList=MutableLiveData<MutableList<MemberVo>>(mutableListOf()) private val _memberList = MutableLiveData<MutableList<MemberVo>>(mutableListOf())
val memberList=_memberList val memberList = _memberList
override val initSize: Int = 10 override val initSize: Int = 10
@ -71,7 +70,7 @@ class MemberViewModel:ScrollList<MemberVo>(){
viewModelScope.launch { viewModelScope.launch {
_memberList.value?.apply { _memberList.value?.apply {
repeat(initSize) { repeat(initSize) {
add(MemberVo(name = "成员${size+1}")) add(MemberVo(name = "成员${size + 1}"))
} }
Logger.i("初始化社团成员size=$size") Logger.i("初始化社团成员size=$size")
} }
@ -87,11 +86,11 @@ class MemberViewModel:ScrollList<MemberVo>(){
override fun loadMore(callback: (message: String) -> Unit) { override fun loadMore(callback: (message: String) -> Unit) {
viewModelScope.launch { viewModelScope.launch {
_memberList.value?.let { _memberList.value?.let {
val t= mutableListOf<MemberVo>() val t = mutableListOf<MemberVo>()
t.addAll(it) t.addAll(it)
t.apply { t.apply {
repeat(10){ repeat(10) {
add(MemberVo(name = "成员${t.size+1}")) add(MemberVo(name = "成员${t.size + 1}"))
} }
} }
_memberList.postValue(t) _memberList.postValue(t)
@ -105,19 +104,18 @@ class MemberViewModel:ScrollList<MemberVo>(){
* *
* @param callback * @param callback
*/ */
fun search(callback: (value: String) -> Unit){ fun search(callback: (value: String) -> Unit) {
Logger.i("搜索条件[成员姓名:${name.formValue.value}]") Logger.i("搜索条件[成员姓名:${name.formValue.value}]")
callback(NOT_IMPL_TIP) callback(NOT_IMPL_TIP)
} }
} }
data class OngoingActVo(val name: String)
data class OngoingActVo(val name:String) class OngoingActViewModel : ViewModel() {
private val _act = MutableLiveData<OngoingActVo>()
class OngoingActViewModel:ViewModel(){ val act: LiveData<OngoingActVo> = _act
private val _act=MutableLiveData<OngoingActVo>()
val act:LiveData<OngoingActVo> = _act
} }
data class HistoryActVo(val name: String) data class HistoryActVo(val name: String)
@ -127,7 +125,7 @@ data class HistoryActVo(val name: String)
* 历史活动 * 历史活动
* *
*/ */
class HistoryActViewModel: ScrollList<HistoryActVo>() { class HistoryActViewModel : ScrollList<HistoryActVo>() {
override val initSize = 10 override val initSize = 10
init { init {
@ -137,25 +135,25 @@ class HistoryActViewModel: ScrollList<HistoryActVo>() {
override fun load() { override fun load() {
viewModelScope.launch { viewModelScope.launch {
_data.value?.apply { _data.value?.apply {
repeat(initSize){ repeat(initSize) {
add(HistoryActVo(name = "活动${size+1}")) add(HistoryActVo(name = "活动${size + 1}"))
} }
Logger.i("初始化活动数量:${size}") Logger.i("初始化活动数量:${size}")
} }
} }
} }
override fun loadMore(callback:(message:String) -> Unit) { override fun loadMore(callback: (message: String) -> Unit) {
_data.value?.apply { _data.value?.apply {
val t= mutableListOf<HistoryActVo>() val t = mutableListOf<HistoryActVo>()
t.addAll(this) t.addAll(this)
t.apply { t.apply {
repeat(10){ repeat(10) {
add(HistoryActVo(name = "活动${t.size+1}")) add(HistoryActVo(name = "活动${t.size + 1}"))
} }
} }
_data.postValue(t) _data.postValue(t)
callback("成功加载更多活动") callback("成功加载更多活动")
} }
} }
} }

@ -13,9 +13,10 @@ import kotlin.random.Random
* 题库界面类型 * 题库界面类型
* *
*/ */
enum class ExamActivityType(val menuName:String){ enum class ExamActivityType(val menuName: String) {
//入团题库 //入团题库
SET_EXAM("入团题库"), SET_EXAM("入团题库"),
//入团申请表 //入团申请表
JOIN_Association("入团申请表") JOIN_Association("入团申请表")
} }
@ -24,16 +25,17 @@ enum class ExamActivityType(val menuName:String){
* 题型 * 题型
* *
*/ */
enum class ExamType(val type:String){ enum class ExamType(val type: String) {
//选择题 //选择题
CQ("选择题"), CQ("选择题"),
//开放题 //开放题
OQ("开放题") OQ("开放题")
} }
sealed class Exam{ sealed class Exam {
abstract val examType:ExamType abstract val examType: ExamType
abstract val question:StringForm abstract val question: StringForm
} }
@ -56,30 +58,29 @@ data class OpenQuestionsVo(
* @property rightAnswer 正确答案 * @property rightAnswer 正确答案
* @property question 问题 * @property question 问题
*/ */
data class ChoiceQuestionVo(override val examType: ExamType = ExamType.CQ, data class ChoiceQuestionVo(
val answers:List<StringForm>, override val examType: ExamType = ExamType.CQ,
val rightAnswer:Int, val answers: List<StringForm>,
override val question: StringForm val rightAnswer: Int,
):Exam() override val question: StringForm
) : Exam()
/** /**
* 问题长度 * 问题长度
*/ */
const val QUESTION_TEXT_LENGTH=30 const val QUESTION_TEXT_LENGTH = 30
/** /**
* 选择题选项数 * 选择题选项数
*/ */
const val ANSWER_SIZE=4 const val ANSWER_SIZE = 4
/** /**
* 答案长度 * 答案长度
* *
*/ */
const val ANSWER_TEXT_LENGTH=15 const val ANSWER_TEXT_LENGTH = 15
/** /**
@ -87,22 +88,22 @@ const val ANSWER_TEXT_LENGTH=15
* *
*/ */
class ExamViewModel:ScrollList<Exam>() { class ExamViewModel : ScrollList<Exam>() {
val questionIsNull: String = "问题不能为空" val questionIsNull: String = "问题不能为空"
val deleteLeastOne: String="至少保留一道题目" val deleteLeastOne: String = "至少保留一道题目"
val updateExam="更新题库" val updateExam = "更新题库"
val postAnswer="提交答案" val postAnswer = "提交答案"
val back="返回" val back = "返回"
val deleteTip="确定删除此题目?" val deleteTip = "确定删除此题目?"
val addTip="确定添加此题目?" val addTip = "确定添加此题目?"
val actionLabel="确定" val actionLabel = "确定"
override val initSize = 10 override val initSize = 10
private val _newExam:MutableLiveData<Exam> = MutableLiveData(createExam(ExamType.CQ)) private val _newExam: MutableLiveData<Exam> = MutableLiveData(createExam(ExamType.CQ))
val newExam:LiveData<Exam> = _newExam val newExam: LiveData<Exam> = _newExam
init { init {
load() load()
@ -112,8 +113,9 @@ class ExamViewModel:ScrollList<Exam>() {
* 切换题型 * 切换题型
* *
*/ */
fun switchType(exam: Exam){ fun switchType(exam: Exam) {
if(exam is ChoiceQuestionVo) _newExam.value=createExam(ExamType.OQ) else _newExam.value=createExam(ExamType.CQ) if (exam is ChoiceQuestionVo) _newExam.value = createExam(ExamType.OQ) else _newExam.value =
createExam(ExamType.CQ)
} }
@ -124,14 +126,20 @@ class ExamViewModel:ScrollList<Exam>() {
* @return * @return
*/ */
private fun createExam(type: ExamType): Exam { private fun createExam(type: ExamType): Exam {
val question=StringForm(formDesc = "问题",textLength = QUESTION_TEXT_LENGTH) val question = StringForm(formDesc = "问题", textLength = QUESTION_TEXT_LENGTH)
return when(type){ return when (type) {
ExamType.CQ-> ChoiceQuestionVo( ExamType.CQ -> ChoiceQuestionVo(
answers = ('A'..'D').map { StringForm(formDesc = "选项",textLength = ANSWER_TEXT_LENGTH,value = "选项$it") }, answers = ('A'..'D').map {
StringForm(
formDesc = "选项",
textLength = ANSWER_TEXT_LENGTH,
value = "选项$it"
)
},
rightAnswer = 0, rightAnswer = 0,
question = question question = question
) )
ExamType.OQ-> OpenQuestionsVo(question = question) ExamType.OQ -> OpenQuestionsVo(question = question)
} }
} }
@ -140,16 +148,16 @@ class ExamViewModel:ScrollList<Exam>() {
* 更新题目 * 更新题目
* *
*/ */
fun update(oldExam: Exam,newExam:Exam){ fun update(oldExam: Exam, newExam: Exam) {
if(oldExam==_newExam.value){ if (oldExam == _newExam.value) {
_newExam.value=newExam _newExam.value = newExam
}else{ } else {
_data.value?.apply { _data.value?.apply {
this[indexOf(oldExam)]=newExam this[indexOf(oldExam)] = newExam
val list = mutableListOf<Exam>() val list = mutableListOf<Exam>()
list.addAll(this) list.addAll(this)
_data.value?.clear() _data.value?.clear()
_data.value=list _data.value = list
} }
} }
} }
@ -159,7 +167,7 @@ class ExamViewModel:ScrollList<Exam>() {
* *
* @param callback * @param callback
*/ */
fun updateExam(callback: (message: String) -> Unit){ fun updateExam(callback: (message: String) -> Unit) {
callback(NOT_IMPL_TIP) callback(NOT_IMPL_TIP)
} }
@ -168,7 +176,7 @@ class ExamViewModel:ScrollList<Exam>() {
* *
* @param callback * @param callback
*/ */
fun postAnswer(callback: (message: String) -> Unit){ fun postAnswer(callback: (message: String) -> Unit) {
callback(NOT_IMPL_TIP) callback(NOT_IMPL_TIP)
} }
@ -180,13 +188,31 @@ class ExamViewModel:ScrollList<Exam>() {
viewModelScope.launch { viewModelScope.launch {
_data.value?.apply { _data.value?.apply {
repeat(initSize) { repeat(initSize) {
if (Random.nextBoolean()){ if (Random.nextBoolean()) {
add(OpenQuestionsVo(question = StringForm(formDesc = "问题",textLength = QUESTION_TEXT_LENGTH,value = "这是一道开放题:$size"))) add(
} else{ OpenQuestionsVo(
question = StringForm(
formDesc = "问题",
textLength = QUESTION_TEXT_LENGTH,
value = "这是一道开放题:$size"
)
)
)
} else {
add( add(
ChoiceQuestionVo( ChoiceQuestionVo(
question = StringForm(formDesc = "问题",textLength = QUESTION_TEXT_LENGTH,value = "这是一道选择题:$size"), question = StringForm(
answers = ('A'..'D').map { StringForm(formDesc = "选项",textLength = ANSWER_TEXT_LENGTH,value = "选项$it") }, formDesc = "问题",
textLength = QUESTION_TEXT_LENGTH,
value = "这是一道选择题:$size"
),
answers = ('A'..'D').map {
StringForm(
formDesc = "选项",
textLength = ANSWER_TEXT_LENGTH,
value = "选项$it"
)
},
rightAnswer = Random.nextInt(ANSWER_SIZE) rightAnswer = Random.nextInt(ANSWER_SIZE)
) )
) )
@ -226,13 +252,13 @@ class ExamViewModel:ScrollList<Exam>() {
fun addQuestion() { fun addQuestion() {
_data.value?.apply { _data.value?.apply {
_newExam.value?.let{ _newExam.value?.let {
val list= mutableListOf<Exam>() val list = mutableListOf<Exam>()
list.addAll(this) list.addAll(this)
list.add(it) list.add(it)
_data.postValue(list) _data.postValue(list)
} }
_newExam.value=createExam(ExamType.CQ) _newExam.value = createExam(ExamType.CQ)
} }
} }

@ -8,30 +8,30 @@ import com.gyf.csams.NOT_IMPL_TIP
import com.gyf.csams.uikit.StringForm import com.gyf.csams.uikit.StringForm
data class Image(val uri:Uri,val createTime:Long,val size:Long) data class Image(val uri: Uri, val createTime: Long, val size: Long)
class RegAssociationViewModel : ViewModel() { class RegAssociationViewModel : ViewModel() {
val frameDesc="社团注册资料" val frameDesc = "社团注册资料"
val name= StringForm(formDesc = "社团名称",textLength = 5) val name = StringForm(formDesc = "社团名称", textLength = 5)
val desc = StringForm(formDesc = "社团简介",textLength = 30) val desc = StringForm(formDesc = "社团简介", textLength = 30)
val _picture=MutableLiveData<Uri>() val _picture = MutableLiveData<Uri>()
val picture:LiveData<Uri> =_picture val picture: LiveData<Uri> = _picture
val piciurePlaceHolder="请上传图片" val piciurePlaceHolder = "请上传图片"
val errorPicture="图片加载失败,请联系管理员" val errorPicture = "图片加载失败,请联系管理员"
val deninedPermission="拒绝授权" val deninedPermission = "拒绝授权"
val register="注册" val register = "注册"
val back="返回" val back = "返回"
fun setPicture(uri: Uri){ fun setPicture(uri: Uri) {
_picture.value=uri _picture.value = uri
} }
/** /**
@ -39,7 +39,7 @@ class RegAssociationViewModel : ViewModel() {
* *
* @param callback * @param callback
*/ */
fun register(callback: (value: String) -> Unit){ fun register(callback: (value: String) -> Unit) {
callback(NOT_IMPL_TIP) callback(NOT_IMPL_TIP)
} }

@ -8,21 +8,21 @@ import com.gyf.csams.uikit.StringForm
* 社团重命名状态管理 * 社团重命名状态管理
* *
*/ */
class RenameViewModel:ViewModel() { class RenameViewModel : ViewModel() {
val menuName="换名申请表" val menuName = "换名申请表"
val oldName=StringForm(formDesc = "社团原名",textLength = 10) val oldName = StringForm(formDesc = "社团原名", textLength = 10)
val newName=StringForm(formDesc = "社团新名",textLength = 10) val newName = StringForm(formDesc = "社团新名", textLength = 10)
val cause=StringForm(formDesc = "换名原因",textLength = 30) val cause = StringForm(formDesc = "换名原因", textLength = 30)
val postDesc="提交申请" val postDesc = "提交申请"
val back="返回" val back = "返回"
/** /**
* TODO 提交表单 * TODO 提交表单
* *
*/ */
fun post(callback:(message:String) -> Unit){ fun post(callback: (message: String) -> Unit) {
callback(NOT_IMPL_TIP) callback(NOT_IMPL_TIP)
} }
} }

@ -34,109 +34,139 @@ import com.gyf.csams.util.randomChinese
import com.orhanobut.logger.Logger import com.orhanobut.logger.Logger
/** /**
* 社团界面 * 社团界面
* *
*/ */
class AssociationActivity: ComponentActivity() { class AssociationActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
setContent { setContent {
CSAMSTheme { CSAMSTheme {
Body { Body { nav, scaffoldState ->
nav, scaffoldState -> val context = LocalContext.current as AssociationActivity
val context= LocalContext.current as AssociationActivity val model: AssociationViewModel = viewModel()
val model:AssociationViewModel= viewModel() val currentMenuName: AssociationMenu by model.currentMenu.observeAsState(
val currentMenuName:AssociationMenu by model.currentMenu.observeAsState(AssociationMenu.startMenu) AssociationMenu.startMenu
val intent=Intent(context,ExamActivity::class.java) )
val expanded by model.expanded.observeAsState(false) val intent = Intent(context, ExamActivity::class.java)
val expanded by model.expanded.observeAsState(false)
Column { Column {
Logger.i("expanded=$expanded") Logger.i("expanded=$expanded")
TextTopAppBar(nav = nav, TextTopAppBar(nav = nav,
currentMenuName= currentMenuName.menuName, currentMenuName = currentMenuName.menuName,
menuNames = AssociationMenu.values(), menuNames = AssociationMenu.values(),
iconMenu = {model.switchType()}){ iconMenu = { model.switchType() }) {
Row{ Row {
DropdownMenu(expanded = expanded, DropdownMenu(
onDismissRequest = { /*TODO*/ }, expanded = expanded,
onDismissRequest = { /*TODO*/ },
// offset = DpOffset.Zero.copy(x=50.dp), // offset = DpOffset.Zero.copy(x=50.dp),
properties = PopupProperties() properties = PopupProperties()
) { ) {
DropdownMenuItem(onClick = { DropdownMenuItem(onClick = {
model.close() model.close()
}) { }) {
Row(verticalAlignment = Alignment.CenterVertically){ Row(verticalAlignment = Alignment.CenterVertically) {
Text(text = "申请活动") Text(text = "申请活动")
Icon(painter = painterResource(id = R.drawable.ic_add_fill), contentDescription = null) Icon(
} painter = painterResource(id = R.drawable.ic_add_fill),
contentDescription = null
)
}
}
DropdownMenuItem(onClick = {
intent.apply {
putExtra(
ExamActivityType::name.name,
ExamActivityType.SET_EXAM
)
}
context.startActivity(intent)
model.close()
}) {
Row(verticalAlignment = Alignment.CenterVertically) {
Text(text = "设置题库")
Icon(
painter = painterResource(id = R.drawable.ic_editor),
contentDescription = null
)
} }
DropdownMenuItem(onClick = { }
intent.apply { DropdownMenuItem(onClick = {
putExtra(ExamActivityType::name.name, ExamActivityType.SET_EXAM) context.startActivity(
} Intent(
context.startActivity(intent) context,
model.close() ReNameActivity::class.java
}) { )
Row(verticalAlignment = Alignment.CenterVertically) { )
Text(text = "设置题库") model.close()
Icon(painter = painterResource(id = R.drawable.ic_editor), contentDescription = null) }) {
} Row(verticalAlignment = Alignment.CenterVertically) {
Text(text = "社团命名")
Icon(
painter = painterResource(id = R.drawable.ic_exchange_rate),
contentDescription = null
)
} }
DropdownMenuItem(onClick = { }
context.startActivity(Intent(context,ReNameActivity::class.java)) DropdownMenuItem(onClick = {
model.close() intent.apply {
}) { putExtra(
Row(verticalAlignment = Alignment.CenterVertically) { ExamActivityType::name.name,
Text(text = "社团命名") ExamActivityType.JOIN_Association
Icon(painter = painterResource(id = R.drawable.ic_exchange_rate), contentDescription = null) )
}
} }
DropdownMenuItem(onClick = { context.startActivity(intent)
intent.apply { model.close()
putExtra(ExamActivityType::name.name, ExamActivityType.JOIN_Association) }) {
} Row(verticalAlignment = Alignment.CenterVertically) {
context.startActivity(intent) Text(text = "申请入团")
model.close() Icon(
}) { painter = painterResource(id = R.drawable.ic_add_account),
Row(verticalAlignment = Alignment.CenterVertically) { contentDescription = null
Text(text = "申请入团") )
Icon(painter = painterResource(id = R.drawable.ic_add_account), contentDescription = null)
}
} }
DropdownMenuItem(onClick = { }
model.close() DropdownMenuItem(onClick = {
}) { model.close()
Row(verticalAlignment = Alignment.CenterVertically) { }) {
Icon(painter = painterResource(id = R.drawable.ic_arrow_up), contentDescription = null, Row(verticalAlignment = Alignment.CenterVertically) {
modifier = Modifier Icon(
.height(30.dp) painter = painterResource(id = R.drawable.ic_arrow_up),
.fillMaxWidth()) contentDescription = null,
} modifier = Modifier
.height(30.dp)
.fillMaxWidth()
)
} }
} }
} }
} }
}
NavHost(navController = nav, startDestination = AssociationMenu.startMenu.name) { NavHost(
composable(AssociationMenu.Member.name){ navController = nav,
model.clickMenu(AssociationMenu.Member) startDestination = AssociationMenu.startMenu.name
Member() ) {
ShowSnackbar(scaffoldState = scaffoldState) composable(AssociationMenu.Member.name) {
} model.clickMenu(AssociationMenu.Member)
composable(AssociationMenu.Main.name){ Member()
model.clickMenu(AssociationMenu.Main) ShowSnackbar(scaffoldState = scaffoldState)
Main() }
ShowSnackbar(scaffoldState = scaffoldState) composable(AssociationMenu.Main.name) {
} model.clickMenu(AssociationMenu.Main)
composable(AssociationMenu.ActivityList.name){ Main()
model.clickMenu(AssociationMenu.ActivityList) ShowSnackbar(scaffoldState = scaffoldState)
AssociationList() }
ShowSnackbar(scaffoldState = scaffoldState) composable(AssociationMenu.ActivityList.name) {
} model.clickMenu(AssociationMenu.ActivityList)
AssociationList()
ShowSnackbar(scaffoldState = scaffoldState)
} }
} }
}
} }
} }
@ -149,15 +179,19 @@ class AssociationActivity: ComponentActivity() {
* *
*/ */
@Composable @Composable
private fun Member(){ private fun Member() {
MainFrame(background = { Background(image = BackgroundImage.AssociationMain) }) { MainFrame(background = { Background(image = BackgroundImage.AssociationMain) }) {
val searchWeight=0.2F val searchWeight = 0.2F
Search(modifier = Modifier Search(
.fillMaxWidth() modifier = Modifier
.weight(searchWeight)) .fillMaxWidth()
MemberList(modifier = Modifier .weight(searchWeight)
.fillMaxWidth() )
.weight(1 - searchWeight)) MemberList(
modifier = Modifier
.fillMaxWidth()
.weight(1 - searchWeight)
)
} }
} }
@ -167,20 +201,33 @@ class AssociationActivity: ComponentActivity() {
* *
*/ */
@Composable @Composable
private fun Search(modifier:Modifier=Modifier, model: MemberViewModel= viewModel(), scaffoldModel: ScaffoldModel= viewModel()){ private fun Search(
modifier: Modifier = Modifier,
model: MemberViewModel = viewModel(),
scaffoldModel: ScaffoldModel = viewModel()
) {
Column(modifier = modifier.fillMaxSize()) { Column(modifier = modifier.fillMaxSize()) {
Spacer(modifier = Modifier.weight(0.5F)) Spacer(modifier = Modifier.weight(0.5F))
Row(modifier = Modifier Row(
.fillMaxWidth() modifier = Modifier
.weight(0.5F),verticalAlignment = Alignment.CenterVertically) { .fillMaxWidth()
.weight(0.5F), verticalAlignment = Alignment.CenterVertically
) {
val textFieldWeight=0.4F val textFieldWeight = 0.4F
val buttonWeight=0.2F val buttonWeight = 0.2F
val spaceWeight=(1-textFieldWeight-buttonWeight)/3 val spaceWeight = (1 - textFieldWeight - buttonWeight) / 3
Spacer(modifier = Modifier.weight((spaceWeight))) Spacer(modifier = Modifier.weight((spaceWeight)))
BaseTextField(modifier = Modifier.weight(textFieldWeight),form = model.name,singeLine = true) BaseTextField(
modifier = Modifier.weight(textFieldWeight),
form = model.name,
singeLine = true
)
Spacer(modifier = Modifier.weight(spaceWeight)) Spacer(modifier = Modifier.weight(spaceWeight))
OutlinedButton(onClick = { model.search { scaffoldModel.update(message=it) } },modifier = Modifier.weight(buttonWeight)) { OutlinedButton(
onClick = { model.search { scaffoldModel.update(message = it) } },
modifier = Modifier.weight(buttonWeight)
) {
Text(text = model.search) Text(text = model.search)
} }
Spacer(modifier = Modifier.weight(spaceWeight)) Spacer(modifier = Modifier.weight(spaceWeight))
@ -193,15 +240,19 @@ class AssociationActivity: ComponentActivity() {
* *
*/ */
@Composable @Composable
private fun MemberList(modifier: Modifier=Modifier, model: MemberViewModel=viewModel(), scaffoldModel: ScaffoldModel= viewModel()){ private fun MemberList(
val list:MutableList<MemberVo>? by model.memberList.observeAsState() modifier: Modifier = Modifier,
val listState= rememberLazyListState() model: MemberViewModel = viewModel(),
LazyColumn(state = listState,modifier = modifier) { scaffoldModel: ScaffoldModel = viewModel()
) {
val list: MutableList<MemberVo>? by model.memberList.observeAsState()
val listState = rememberLazyListState()
LazyColumn(state = listState, modifier = modifier) {
list?.forEach { list?.forEach {
item { item {
Column { Column {
Spacer(modifier = Modifier.height(10.dp)) Spacer(modifier = Modifier.height(10.dp))
Row{ Row {
val weight = 1F / 3 val weight = 1F / 3
Spacer(modifier = Modifier.weight(weight)) Spacer(modifier = Modifier.weight(weight))
Card( Card(
@ -218,11 +269,19 @@ class AssociationActivity: ComponentActivity() {
} }
} }
item { item {
Row(horizontalArrangement = Arrangement.Center,modifier = Modifier.fillMaxWidth()) { Row(
IconButton(onClick = { model.loadMore{ horizontalArrangement = Arrangement.Center,
scaffoldModel.update(message=it) modifier = Modifier.fillMaxWidth()
} }) { ) {
Icon(painter = painterResource(id = R.drawable.ic_arrow_down), contentDescription = null) IconButton(onClick = {
model.loadMore {
scaffoldModel.update(message = it)
}
}) {
Icon(
painter = painterResource(id = R.drawable.ic_arrow_down),
contentDescription = null
)
} }
} }
@ -235,15 +294,17 @@ class AssociationActivity: ComponentActivity() {
* *
*/ */
@Composable @Composable
private fun Main(){ private fun Main() {
MainFrame(background = { MainFrame(background = {
Background(image = BackgroundImage.AssociationMain,alpha = 0.7F) Background(image = BackgroundImage.AssociationMain, alpha = 0.7F)
}) { }) {
val nameW=0.1F val nameW = 0.1F
val cardW=0.66F*0.4F val cardW = 0.66F * 0.4F
Name(modifier = Modifier Name(
.fillMaxWidth() modifier = Modifier
.weight(nameW)) .fillMaxWidth()
.weight(nameW)
)
DescCard( DescCard(
modifier = Modifier modifier = Modifier
.weight(cardW) .weight(cardW)
@ -253,7 +314,7 @@ class AssociationActivity: ComponentActivity() {
Commander( Commander(
modifier = Modifier.weight(cardW) modifier = Modifier.weight(cardW)
) )
Showcase(modifier = Modifier.weight(1F-nameW-cardW-cardW)) Showcase(modifier = Modifier.weight(1F - nameW - cardW - cardW))
} }
} }
@ -263,20 +324,22 @@ class AssociationActivity: ComponentActivity() {
* @param modifier * @param modifier
*/ */
@Composable @Composable
private fun Name(modifier: Modifier){ private fun Name(modifier: Modifier) {
Box(modifier = modifier) { Box(modifier = modifier) {
Image( Image(
painter = painterResource(id = R.drawable.association_name_border), painter = painterResource(id = R.drawable.association_name_border),
contentDescription = null, contentDescription = null,
contentScale = ContentScale.FillBounds, contentScale = ContentScale.FillBounds,
modifier=Modifier.fillMaxSize() modifier = Modifier.fillMaxSize()
) )
Column{ Column {
Spacer(modifier = Modifier.weight(1.7F / 3)) Spacer(modifier = Modifier.weight(1.7F / 3))
Row(modifier = Modifier Row(
.fillMaxWidth() modifier = Modifier
.weight(1F / 3), .fillMaxWidth()
horizontalArrangement = Arrangement.Center) { .weight(1F / 3),
horizontalArrangement = Arrangement.Center
) {
Text(text = "社团名字") Text(text = "社团名字")
} }
Spacer(modifier = Modifier.weight(0.3F / 3)) Spacer(modifier = Modifier.weight(0.3F / 3))
@ -290,11 +353,12 @@ class AssociationActivity: ComponentActivity() {
* @param modifier * @param modifier
*/ */
@Composable @Composable
private fun Commander(modifier: Modifier){ private fun Commander(modifier: Modifier) {
Box(modifier=modifier,contentAlignment = Alignment.Center){ Box(modifier = modifier, contentAlignment = Alignment.Center) {
Row(modifier = Modifier.fillMaxWidth(),horizontalArrangement = Arrangement.Center) { Row(modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.Center) {
Image(painter = painterResource(id = R.drawable.persion_name_border), Image(
painter = painterResource(id = R.drawable.persion_name_border),
contentDescription = null contentDescription = null
) )
} }
@ -308,12 +372,17 @@ class AssociationActivity: ComponentActivity() {
* @param modifier * @param modifier
*/ */
@Composable @Composable
private fun Showcase(modifier: Modifier){ private fun Showcase(modifier: Modifier) {
Box(modifier = modifier,contentAlignment = Alignment.Center) { Box(modifier = modifier, contentAlignment = Alignment.Center) {
Image(painter = painterResource(id = R.drawable.showcase_border), Image(
painter = painterResource(id = R.drawable.showcase_border),
contentDescription = null, contentDescription = null,
modifier=Modifier.fillMaxSize()) modifier = Modifier.fillMaxSize()
Image(painter = painterResource(id = R.drawable.ic_launcher_foreground), contentDescription = null) )
Image(
painter = painterResource(id = R.drawable.ic_launcher_foreground),
contentDescription = null
)
} }
} }
@ -322,16 +391,25 @@ class AssociationActivity: ComponentActivity() {
* *
*/ */
@Composable @Composable
private fun AssociationList(){ private fun AssociationList() {
MainFrame(background = { Background(image = BackgroundImage.AssociationMain,alpha = 07F) }) { MainFrame(background = {
val onGoWeight=0.3F Background(
OngoingActivity(modifier = Modifier image = BackgroundImage.AssociationMain,
.weight(onGoWeight) alpha = 07F
.fillMaxWidth()) )
HistoryActivityList(modifier = Modifier }) {
.fillMaxWidth() val onGoWeight = 0.3F
.weight(1 - onGoWeight) OngoingActivity(
.border(width = 1.dp, color = MaterialTheme.colors.onBackground)) modifier = Modifier
.weight(onGoWeight)
.fillMaxWidth()
)
HistoryActivityList(
modifier = Modifier
.fillMaxWidth()
.weight(1 - onGoWeight)
.border(width = 1.dp, color = MaterialTheme.colors.onBackground)
)
} }
} }
@ -340,16 +418,19 @@ class AssociationActivity: ComponentActivity() {
* *
*/ */
@Composable @Composable
private fun OngoingActivity(modifier: Modifier=Modifier,model:OngoingActViewModel= viewModel()){ private fun OngoingActivity(
val context= LocalContext.current modifier: Modifier = Modifier,
model: OngoingActViewModel = viewModel()
) {
val context = LocalContext.current
val act by model.act.observeAsState() val act by model.act.observeAsState()
Row(modifier = modifier.clickable(onClick = { Row(modifier = modifier.clickable(onClick = {
context.startActivity(Intent(context,ActivityDetailActivity::class.java)) context.startActivity(Intent(context, ActivityDetailActivity::class.java))
}),horizontalArrangement = Arrangement.Center) { }), horizontalArrangement = Arrangement.Center) {
val weight=0.5F val weight = 0.5F
val spaceWeight=(1-0.5F)/2 val spaceWeight = (1 - 0.5F) / 2
Spacer(modifier = Modifier.weight(spaceWeight)) Spacer(modifier = Modifier.weight(spaceWeight))
Poster(id = R.drawable.ic_launcher_foreground,modifier = Modifier.weight(weight)) Poster(id = R.drawable.ic_launcher_foreground, modifier = Modifier.weight(weight))
Spacer(modifier = Modifier.weight(spaceWeight)) Spacer(modifier = Modifier.weight(spaceWeight))
} }
@ -361,16 +442,20 @@ class AssociationActivity: ComponentActivity() {
* @param modifier * @param modifier
*/ */
@Composable @Composable
private fun HistoryActivityList(modifier: Modifier,model:HistoryActViewModel= viewModel(),scaffoldModel: ScaffoldModel= viewModel()){ private fun HistoryActivityList(
val listState= rememberLazyListState() modifier: Modifier,
model: HistoryActViewModel = viewModel(),
scaffoldModel: ScaffoldModel = viewModel()
) {
val listState = rememberLazyListState()
val list by model.data.observeAsState() val list by model.data.observeAsState()
LazyColumn(state = listState,modifier = modifier) { LazyColumn(state = listState, modifier = modifier) {
list?.chunked(2)?.forEach { list?.chunked(2)?.forEach {
item { item {
Row(modifier=Modifier.fillMaxWidth()) { Row(modifier = Modifier.fillMaxWidth()) {
HistoryActivity(modifier = Modifier.weight(0.4F),it[0]) HistoryActivity(modifier = Modifier.weight(0.4F), it[0])
Spacer(modifier = Modifier.weight(0.2F)) Spacer(modifier = Modifier.weight(0.2F))
if (it.size==2) HistoryActivity(modifier = Modifier.weight(0.4F),it[1]) if (it.size == 2) HistoryActivity(modifier = Modifier.weight(0.4F), it[1])
else Box(modifier = Modifier.weight(0.4F)) else Box(modifier = Modifier.weight(0.4F))
} }
Spacer(modifier = Modifier.height(10.dp)) Spacer(modifier = Modifier.height(10.dp))
@ -378,8 +463,8 @@ class AssociationActivity: ComponentActivity() {
} }
} }
} }
if(listState.layoutInfo.totalItemsCount-listState.firstVisibleItemIndex==model.initSize/2-1){ if (listState.layoutInfo.totalItemsCount - listState.firstVisibleItemIndex == model.initSize / 2 - 1) {
model.loadMore { scaffoldModel.update(message=it) } model.loadMore { scaffoldModel.update(message = it) }
} }
} }
@ -389,17 +474,21 @@ class AssociationActivity: ComponentActivity() {
* @param modifier * @param modifier
*/ */
@Composable @Composable
private fun HistoryActivity(modifier: Modifier,historyActVo: HistoryActVo){ private fun HistoryActivity(modifier: Modifier, historyActVo: HistoryActVo) {
val context= LocalContext.current val context = LocalContext.current
Box(modifier=modifier.clickable(onClick = { Box(modifier = modifier.clickable(onClick = {
context.startActivity(Intent(context,ActivityDetailActivity::class.java)) context.startActivity(Intent(context, ActivityDetailActivity::class.java))
}),contentAlignment = Alignment.Center){ }), contentAlignment = Alignment.Center) {
Image(painter = painterResource(id = R.drawable.history_activity_border), Image(
painter = painterResource(id = R.drawable.history_activity_border),
contentDescription = null, contentDescription = null,
modifier = Modifier.fillMaxSize()) modifier = Modifier.fillMaxSize()
Image(painter = painterResource(id = R.drawable.ic_launcher_foreground), )
Image(
painter = painterResource(id = R.drawable.ic_launcher_foreground),
contentDescription = null, contentDescription = null,
modifier = Modifier.fillMaxSize()) modifier = Modifier.fillMaxSize()
)
Text(text = historyActVo.name) Text(text = historyActVo.name)
} }
@ -407,7 +496,7 @@ class AssociationActivity: ComponentActivity() {
@Preview @Preview
@Composable @Composable
fun NamePreview(){ fun NamePreview() {
Divider(color = MaterialTheme.colors.background) Divider(color = MaterialTheme.colors.background)
} }
} }

@ -23,23 +23,22 @@ import com.gyf.csams.association.model.*
import com.gyf.csams.uikit.* import com.gyf.csams.uikit.*
/** /**
* 题库管理 * 题库管理
* *
*/ */
class ExamActivity : ComponentActivity() { class ExamActivity : ComponentActivity() {
lateinit var activityType:ExamActivityType lateinit var activityType: ExamActivityType
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
activityType=intent?.getSerializableExtra(ExamActivityType::name.name) as ExamActivityType activityType = intent?.getSerializableExtra(ExamActivityType::name.name) as ExamActivityType
setContent { setContent {
Body { scaffoldState -> Body { scaffoldState ->
MainFrame(background = { Background(image = BackgroundImage.Exam,alpha = 0.6F) }) { MainFrame(background = { Background(image = BackgroundImage.Exam, alpha = 0.6F) }) {
Spacer(modifier = Modifier.weight(0.1F)) Spacer(modifier = Modifier.weight(0.1F))
Title(modifier = Modifier.weight(0.1F)) Title(modifier = Modifier.weight(0.1F))
Exam(modifier = Modifier.weight(0.8F)) Exam(modifier = Modifier.weight(0.8F))
@ -50,8 +49,6 @@ class ExamActivity : ComponentActivity() {
} }
/** /**
* 底部按钮 * 底部按钮
* *
@ -65,14 +62,14 @@ class ExamActivity : ComponentActivity() {
val context = LocalContext.current as ExamActivity val context = LocalContext.current as ExamActivity
Row(modifier = modifier, horizontalArrangement = Arrangement.Center) { Row(modifier = modifier, horizontalArrangement = Arrangement.Center) {
when(context.activityType){ when (context.activityType) {
ExamActivityType.SET_EXAM->OutlinedButton(onClick = { ExamActivityType.SET_EXAM -> OutlinedButton(onClick = {
model.updateExam { scaffoldModel.update(message=it) } model.updateExam { scaffoldModel.update(message = it) }
}, modifier = Modifier.background(color = MaterialTheme.colors.primary)) { }, modifier = Modifier.background(color = MaterialTheme.colors.primary)) {
Text(text = model.updateExam) Text(text = model.updateExam)
} }
ExamActivityType.JOIN_Association->OutlinedButton(onClick = { ExamActivityType.JOIN_Association -> OutlinedButton(onClick = {
model.postAnswer { scaffoldModel.update(message=it) } model.postAnswer { scaffoldModel.update(message = it) }
}, modifier = Modifier.background(color = MaterialTheme.colors.primary)) { }, modifier = Modifier.background(color = MaterialTheme.colors.primary)) {
Text(text = model.postAnswer) Text(text = model.postAnswer)
} }
@ -94,19 +91,19 @@ class ExamActivity : ComponentActivity() {
*/ */
@Composable @Composable
private fun Title(modifier: Modifier = Modifier) { private fun Title(modifier: Modifier = Modifier) {
val context= LocalContext.current as ExamActivity val context = LocalContext.current as ExamActivity
Row(horizontalArrangement = Arrangement.Center, modifier = modifier.fillMaxWidth()) { Row(horizontalArrangement = Arrangement.Center, modifier = modifier.fillMaxWidth()) {
Text(text = context.activityType.menuName, style = MaterialTheme.typography.h4) Text(text = context.activityType.menuName, style = MaterialTheme.typography.h4)
} }
} }
@Composable @Composable
private fun ExamChild(it:Exam,examHeight: Dp,isAdd: Boolean=false){ private fun ExamChild(it: Exam, examHeight: Dp, isAdd: Boolean = false) {
val questionWeight=0.3F val questionWeight = 0.3F
when (it) { when (it) {
is OpenQuestionsVo -> ExamOQ( is OpenQuestionsVo -> ExamOQ(
openQuestionsVo = it, openQuestionsVo = it,
modifier = Modifier.height(examHeight*questionWeight), modifier = Modifier.height(examHeight * questionWeight),
isAdd = isAdd isAdd = isAdd
) )
is ChoiceQuestionVo -> ExamCQ( is ChoiceQuestionVo -> ExamCQ(
@ -147,7 +144,7 @@ class ExamActivity : ComponentActivity() {
OutlinedButton(onClick = { model.switchType(it) }) { OutlinedButton(onClick = { model.switchType(it) }) {
Text(text = "切换到${if (newExam is ChoiceQuestionVo) "开放题" else "选择题"}") Text(text = "切换到${if (newExam is ChoiceQuestionVo) "开放题" else "选择题"}")
} }
ExamChild(it = it, examHeight = examHeight,isAdd = true) ExamChild(it = it, examHeight = examHeight, isAdd = true)
} }
} }
} }
@ -163,7 +160,7 @@ class ExamActivity : ComponentActivity() {
} }
if (listState.layoutInfo.totalItemsCount - listState.firstVisibleItemIndex == model.initSize / 2 - 1) { if (listState.layoutInfo.totalItemsCount - listState.firstVisibleItemIndex == model.initSize / 2 - 1) {
model.loadMore { scaffoldModel.update(message=it) } model.loadMore { scaffoldModel.update(message = it) }
} }
@ -191,10 +188,12 @@ class ExamActivity : ComponentActivity() {
* *
*/ */
@Composable @Composable
private fun ActionButton(modifier: Modifier = Modifier, isAdd: Boolean, private fun ActionButton(
model: ExamViewModel= viewModel(), modifier: Modifier = Modifier, isAdd: Boolean,
scaffoldModel: ScaffoldModel= viewModel(), model: ExamViewModel = viewModel(),
exam: Exam) { scaffoldModel: ScaffoldModel = viewModel(),
exam: Exam
) {
val list by model.data.observeAsState() val list by model.data.observeAsState()
val newExam by model.newExam.observeAsState() val newExam by model.newExam.observeAsState()
Box( Box(
@ -202,20 +201,26 @@ class ExamActivity : ComponentActivity() {
modifier = modifier modifier = modifier
) { ) {
IconButton(onClick = { IconButton(onClick = {
if(isAdd){ if (isAdd) {
if((newExam?.question?.formValue?.value ?: "").isNotEmpty()){ if ((newExam?.question?.formValue?.value ?: "").isNotEmpty()) {
scaffoldModel.update(message=model.addTip,actionLabel = model.actionLabel){ scaffoldModel.update(
message = model.addTip,
actionLabel = model.actionLabel
) {
model.addQuestion() model.addQuestion()
} }
}else{ } else {
scaffoldModel.update(message = model.questionIsNull) scaffoldModel.update(message = model.questionIsNull)
} }
}else{ } else {
if(list?.size==1){ if (list?.size == 1) {
scaffoldModel.update(model.deleteLeastOne) scaffoldModel.update(model.deleteLeastOne)
}else{ } else {
scaffoldModel.update(message=model.deleteTip,actionLabel = model.actionLabel){ scaffoldModel.update(
message = model.deleteTip,
actionLabel = model.actionLabel
) {
model.deleteQuestion(exam = exam) model.deleteQuestion(exam = exam)
} }
} }
@ -242,15 +247,17 @@ class ExamActivity : ComponentActivity() {
isAdd: Boolean = false isAdd: Boolean = false
) { ) {
Row(modifier = modifier) { Row(modifier = modifier) {
val context= LocalContext.current as ExamActivity val context = LocalContext.current as ExamActivity
Question( Question(
exam = openQuestionsVo, modifier = exam = openQuestionsVo, modifier =
if(context.activityType==ExamActivityType.SET_EXAM) if (context.activityType == ExamActivityType.SET_EXAM)
Modifier.weight(0.8F).fillMaxHeight() Modifier
.weight(0.8F)
.fillMaxHeight()
else else
Modifier Modifier
) )
if(context.activityType==ExamActivityType.SET_EXAM){ if (context.activityType == ExamActivityType.SET_EXAM) {
ActionButton( ActionButton(
modifier = Modifier modifier = Modifier
.weight(0.2F) .weight(0.2F)
@ -273,13 +280,15 @@ class ExamActivity : ComponentActivity() {
choiceQuestionVo: ChoiceQuestionVo, choiceQuestionVo: ChoiceQuestionVo,
isAdd: Boolean = false, isAdd: Boolean = false,
model: ExamViewModel = viewModel(), model: ExamViewModel = viewModel(),
questionWeight:Float questionWeight: Float
) { ) {
Row(modifier = modifier) { Row(modifier = modifier) {
val context= LocalContext.current as ExamActivity val context = LocalContext.current as ExamActivity
Column( Column(
modifier = if(context.activityType==ExamActivityType.SET_EXAM) modifier = if (context.activityType == ExamActivityType.SET_EXAM)
Modifier.weight(0.8F).fillMaxHeight() Modifier
.weight(0.8F)
.fillMaxHeight()
else else
Modifier Modifier
) { ) {
@ -299,9 +308,11 @@ class ExamActivity : ComponentActivity() {
choiceQuestionVo.answers.apply { choiceQuestionVo.answers.apply {
Column { Column {
forEach { forEach {
Row(modifier = Modifier Row(
.fillMaxWidth() modifier = Modifier
.weight(1F / ANSWER_SIZE)) { .fillMaxWidth()
.weight(1F / ANSWER_SIZE)
) {
val answerIndex: Int = indexOf(it) val answerIndex: Int = indexOf(it)
val click = { val click = {
model.update( model.update(
@ -320,7 +331,7 @@ class ExamActivity : ComponentActivity() {
} }
} }
if(context.activityType==ExamActivityType.SET_EXAM) { if (context.activityType == ExamActivityType.SET_EXAM) {
ActionButton( ActionButton(
modifier = Modifier modifier = Modifier
.weight(0.2F) .weight(0.2F)

@ -19,32 +19,31 @@ import com.gyf.csams.uikit.*
* 社团重命名 * 社团重命名
* *
*/ */
class ReNameActivity: ComponentActivity() { class ReNameActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
setContent { setContent {
Body { Body { scaffoldState ->
scaffoldState -> MainFrame(background = { Background(image = BackgroundImage.Rename) }) {
MainFrame(background = { Background(image = BackgroundImage.Rename) }) { Spacer(
Spacer( modifier = Modifier
modifier = Modifier .weight(0.2F)
.weight(0.2F) )
) Title(modifier = Modifier.weight(0.1F))
Title(modifier = Modifier.weight(0.1F))
OldName(modifier = Modifier.weight(0.1F)) OldName(modifier = Modifier.weight(0.1F))
NewName(modifier = Modifier.weight(0.1F)) NewName(modifier = Modifier.weight(0.1F))
Cause(modifier = Modifier.weight(0.2F)) Cause(modifier = Modifier.weight(0.2F))
Spacer(modifier = Modifier.height(10.dp)) Spacer(modifier = Modifier.height(10.dp))
BottomButton(modifier = Modifier.weight(0.1F)) BottomButton(modifier = Modifier.weight(0.1F))
Spacer(modifier = Modifier.weight(1-0.2F*2-0.1F*4)) Spacer(modifier = Modifier.weight(1 - 0.2F * 2 - 0.1F * 4))
ShowSnackbar(scaffoldState = scaffoldState) ShowSnackbar(scaffoldState = scaffoldState)
} }
} }
} }
} }
@ -54,9 +53,9 @@ class ReNameActivity: ComponentActivity() {
* *
*/ */
@Composable @Composable
private fun Title(modifier: Modifier=Modifier,model:RenameViewModel= viewModel()){ private fun Title(modifier: Modifier = Modifier, model: RenameViewModel = viewModel()) {
Row(modifier = modifier.fillMaxWidth(),horizontalArrangement = Arrangement.Center) { Row(modifier = modifier.fillMaxWidth(), horizontalArrangement = Arrangement.Center) {
Text(text = model.menuName,style = MaterialTheme.typography.h4) Text(text = model.menuName, style = MaterialTheme.typography.h4)
} }
} }
@ -65,8 +64,8 @@ class ReNameActivity: ComponentActivity() {
* *
*/ */
@Composable @Composable
private fun OldName(modifier: Modifier=Modifier,model:RenameViewModel= viewModel()){ private fun OldName(modifier: Modifier = Modifier, model: RenameViewModel = viewModel()) {
BaseTextField(form = model.oldName,modifier = modifier.fillMaxWidth(),singeLine = true) BaseTextField(form = model.oldName, modifier = modifier.fillMaxWidth(), singeLine = true)
} }
/** /**
@ -74,8 +73,8 @@ class ReNameActivity: ComponentActivity() {
* *
*/ */
@Composable @Composable
private fun NewName(modifier: Modifier=Modifier,model:RenameViewModel= viewModel()){ private fun NewName(modifier: Modifier = Modifier, model: RenameViewModel = viewModel()) {
BaseTextField(form = model.newName,modifier = modifier.fillMaxWidth(),singeLine = true) BaseTextField(form = model.newName, modifier = modifier.fillMaxWidth(), singeLine = true)
} }
/** /**
@ -83,8 +82,8 @@ class ReNameActivity: ComponentActivity() {
* *
*/ */
@Composable @Composable
private fun Cause(modifier: Modifier=Modifier,model:RenameViewModel= viewModel()){ private fun Cause(modifier: Modifier = Modifier, model: RenameViewModel = viewModel()) {
BaseTextField(form = model.cause,modifier = modifier.fillMaxWidth()) BaseTextField(form = model.cause, modifier = modifier.fillMaxWidth())
} }
/** /**
@ -94,13 +93,17 @@ class ReNameActivity: ComponentActivity() {
* @param model * @param model
*/ */
@Composable @Composable
private fun BottomButton(modifier: Modifier=Modifier,model:RenameViewModel= viewModel(),scaffoldModel: ScaffoldModel= viewModel()){ private fun BottomButton(
modifier: Modifier = Modifier,
model: RenameViewModel = viewModel(),
scaffoldModel: ScaffoldModel = viewModel()
) {
Row(modifier = modifier.fillMaxWidth()) { Row(modifier = modifier.fillMaxWidth()) {
val weight=(1-0.5F)/2 val weight = (1 - 0.5F) / 2
val context= LocalContext.current as ReNameActivity val context = LocalContext.current as ReNameActivity
Spacer(modifier = Modifier.weight(weight)) Spacer(modifier = Modifier.weight(weight))
Row(modifier=Modifier.weight(0.5F)) { Row(modifier = Modifier.weight(0.5F)) {
OutlinedButton(onClick = { model.post{scaffoldModel.update(message=it)} }) { OutlinedButton(onClick = { model.post { scaffoldModel.update(message = it) } }) {
Text(text = model.postDesc) Text(text = model.postDesc)
} }
Spacer(modifier = Modifier.width(10.dp)) Spacer(modifier = Modifier.width(10.dp))

@ -43,37 +43,41 @@ import com.orhanobut.logger.Logger
* 注册社团 * 注册社团
* *
*/ */
class RegAssociationActivity: ComponentActivity(){ class RegAssociationActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
setContent { setContent {
CSAMSTheme { CSAMSTheme {
Body { Body { scaffoldState ->
scaffoldState -> MainFrame(background = {
MainFrame(background = { Background(BackgroundImage.RegAssociation,alpha = 0.5F) }) { Background(
Spacer( BackgroundImage.RegAssociation,
modifier = Modifier alpha = 0.5F
.weight(0.1F) )
) }) {
Title() Spacer(
Name() modifier = Modifier
Desc( .weight(0.1F)
modifier = Modifier )
.weight(0.1F) Title()
.fillMaxWidth() Name()
) Desc(
Spacer(modifier = Modifier.weight(0.05F)) modifier = Modifier
Logo( .weight(0.1F)
modifier = Modifier .fillMaxWidth()
.weight(0.2F) )
.fillMaxWidth() Spacer(modifier = Modifier.weight(0.05F))
) Logo(
Spacer(modifier = Modifier.weight(0.05F)) modifier = Modifier
BottomButton(modifier = Modifier.fillMaxWidth()) .weight(0.2F)
Spacer(modifier = Modifier.weight(0.05F)) .fillMaxWidth()
)
ShowSnackbar(scaffoldState = scaffoldState) Spacer(modifier = Modifier.weight(0.05F))
} BottomButton(modifier = Modifier.fillMaxWidth())
Spacer(modifier = Modifier.weight(0.05F))
ShowSnackbar(scaffoldState = scaffoldState)
}
} }
} }
} }
@ -86,21 +90,22 @@ class RegAssociationActivity: ComponentActivity(){
* @param modifier * @param modifier
*/ */
@Composable @Composable
private fun Logo(model:RegAssociationViewModel= viewModel(),modifier: Modifier) { private fun Logo(model: RegAssociationViewModel = viewModel(), modifier: Modifier) {
val photoIntent=Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI) val photoIntent = Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI)
photoIntent.type = "image/*" photoIntent.type = "image/*"
val uri:Uri? by model.picture.observeAsState() val uri: Uri? by model.picture.observeAsState()
val resultLauncher=rememberLauncherForActivityResult(contract = ActivityResultContracts.StartActivityForResult()) { val resultLauncher =
when(it.resultCode){ rememberLauncherForActivityResult(contract = ActivityResultContracts.StartActivityForResult()) {
Activity.RESULT_OK->{ when (it.resultCode) {
Logger.i("uri=${it.data?.data}") Activity.RESULT_OK -> {
it.data?.data?.let { it1 -> model.setPicture(it1) } Logger.i("uri=${it.data?.data}")
it.data?.data?.let { it1 -> model.setPicture(it1) }
}
} }
} }
}
val loadPicture={ val loadPicture = {
//model.loadPicture(context) //model.loadPicture(context)
resultLauncher.launch(photoIntent) resultLauncher.launch(photoIntent)
} }
@ -118,14 +123,15 @@ class RegAssociationActivity: ComponentActivity(){
} }
val context = LocalContext.current
val context= LocalContext.current Box(contentAlignment = Alignment.Center, modifier = modifier) {
Row(
Box(contentAlignment = Alignment.Center,modifier = modifier) { verticalAlignment = Alignment.CenterVertically,
Row(verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.Center, modifier = Modifier
horizontalArrangement = Arrangement.Center,modifier = Modifier
.fillMaxSize() .fillMaxSize()
.border(width = 1.dp, color = Color.Black)) { .border(width = 1.dp, color = Color.Black)
) {
if (uri == null) { if (uri == null) {
OutlinedButton(onClick = { OutlinedButton(onClick = {
@ -147,19 +153,28 @@ class RegAssociationActivity: ComponentActivity(){
} }
} else { } else {
uri.let { uri.let {
if(it!=null){ if (it != null) {
Row { Row {
Image(bitmap = BitmapFactory.decodeStream(context.contentResolver.openInputStream(it)) Image(
.asImageBitmap(), contentDescription = null) bitmap = BitmapFactory.decodeStream(
context.contentResolver.openInputStream(
it
)
)
.asImageBitmap(), contentDescription = null
)
IconButton(onClick = { IconButton(onClick = {
loadPicture() loadPicture()
}) { }) {
Image(painter = painterResource(id = R.drawable.ic_exchange_rate), contentDescription = null) Image(
painter = painterResource(id = R.drawable.ic_exchange_rate),
contentDescription = null
)
} }
} }
}else{ } else {
Text(text = model.errorPicture) Text(text = model.errorPicture)
} }
} }
@ -174,18 +189,22 @@ class RegAssociationActivity: ComponentActivity(){
} }
@Composable @Composable
private fun BottomButton(modifier: Modifier=Modifier,scaffoldModel: ScaffoldModel= viewModel(),model:RegAssociationViewModel= viewModel()){ private fun BottomButton(
val context= LocalContext.current as RegAssociationActivity modifier: Modifier = Modifier,
Row(modifier = modifier,horizontalArrangement = Arrangement.Center) { scaffoldModel: ScaffoldModel = viewModel(),
model: RegAssociationViewModel = viewModel()
) {
val context = LocalContext.current as RegAssociationActivity
Row(modifier = modifier, horizontalArrangement = Arrangement.Center) {
OutlinedButton(onClick = { OutlinedButton(onClick = {
model.register { scaffoldModel.update(message=it) } model.register { scaffoldModel.update(message = it) }
},modifier = Modifier.background(color = MaterialTheme.colors.primary)) { }, modifier = Modifier.background(color = MaterialTheme.colors.primary)) {
Text(text = model.register) Text(text = model.register)
} }
Spacer(modifier = Modifier.width(10.dp)) Spacer(modifier = Modifier.width(10.dp))
OutlinedButton(onClick = { OutlinedButton(onClick = {
context.onBackPressed() context.onBackPressed()
},modifier = Modifier.background(color = MaterialTheme.colors.secondary)) { }, modifier = Modifier.background(color = MaterialTheme.colors.secondary)) {
Text(text = model.back) Text(text = model.back)
} }
} }
@ -197,9 +216,9 @@ class RegAssociationActivity: ComponentActivity(){
* *
*/ */
@Composable @Composable
private fun Title(model:RegAssociationViewModel= viewModel()){ private fun Title(model: RegAssociationViewModel = viewModel()) {
Row(modifier = Modifier.fillMaxWidth(),horizontalArrangement = Arrangement.Center) { Row(modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.Center) {
Text(text = model.frameDesc,style = MaterialTheme.typography.h4) Text(text = model.frameDesc, style = MaterialTheme.typography.h4)
} }
} }
@ -208,8 +227,8 @@ class RegAssociationActivity: ComponentActivity(){
* @param model * @param model
*/ */
@Composable @Composable
private fun Name(model:RegAssociationViewModel= viewModel()){ private fun Name(model: RegAssociationViewModel = viewModel()) {
BaseTextField(form = model.name,singeLine = true,modifier = Modifier.fillMaxWidth()) BaseTextField(form = model.name, singeLine = true, modifier = Modifier.fillMaxWidth())
} }
/** /**
@ -217,8 +236,8 @@ class RegAssociationActivity: ComponentActivity(){
* @param model * @param model
*/ */
@Composable @Composable
private fun Desc(model:RegAssociationViewModel= viewModel(),modifier:Modifier){ private fun Desc(model: RegAssociationViewModel = viewModel(), modifier: Modifier) {
BaseTextField(form = model.desc,modifier = modifier) BaseTextField(form = model.desc, modifier = modifier)
} }
} }

@ -20,21 +20,20 @@ import kotlinx.coroutines.launch
* 跑马灯 * 跑马灯
* *
*/ */
class MarqueeViewModel:ViewModel() { class MarqueeViewModel : ViewModel() {
val marqueeTexts= listOf("床前明月光","疑是地上霜","举头望明月","低头思故乡") val marqueeTexts = listOf("床前明月光", "疑是地上霜", "举头望明月", "低头思故乡")
private val _marqueeIndex=MutableLiveData(0) private val _marqueeIndex = MutableLiveData(0)
var marqueeIndex:LiveData<Int> = _marqueeIndex var marqueeIndex: LiveData<Int> = _marqueeIndex
private var marqueeJob:Job? = null private var marqueeJob: Job? = null
fun addAsync(delayMillis: Int) {
fun addAsync(delayMillis:Int){ if (marqueeJob == null || marqueeJob?.isCompleted == true) {
if(marqueeJob == null || marqueeJob?.isCompleted==true) {
marqueeJob = viewModelScope.launch { marqueeJob = viewModelScope.launch {
_marqueeIndex.postValue( _marqueeIndex.postValue(
if (_marqueeIndex.value == marqueeTexts.size-1) 0 else _marqueeIndex.value?.plus( if (_marqueeIndex.value == marqueeTexts.size - 1) 0 else _marqueeIndex.value?.plus(
1 1
) )
) )
@ -48,25 +47,30 @@ class MarqueeViewModel:ViewModel() {
* 海报轮播 * 海报轮播
* *
*/ */
class CarouselViewModel:ViewModel(){ class CarouselViewModel : ViewModel() {
val imageList= listOf(R.drawable.ic_launcher_foreground,R.drawable.ic_account_fill,R.drawable.ic_all_fill,R.drawable.ic_home_fill) val imageList = listOf(
R.drawable.ic_launcher_foreground,
R.drawable.ic_account_fill,
R.drawable.ic_all_fill,
R.drawable.ic_home_fill
)
private val _index=MutableLiveData(0) private val _index = MutableLiveData(0)
val index:LiveData<Int> = _index val index: LiveData<Int> = _index
private var job:Job? = null private var job: Job? = null
init { init {
start() start()
} }
private fun start(){ private fun start() {
job = viewModelScope.launch { job = viewModelScope.launch {
do{ do {
_index.postValue(if (_index.value==imageList.size-1) 0 else _index.value?.plus(1)) _index.postValue(if (_index.value == imageList.size - 1) 0 else _index.value?.plus(1))
delay(5000) delay(5000)
}while (job?.isActive==true) } while (job?.isActive == true)
} }
} }
@ -77,25 +81,25 @@ class CarouselViewModel:ViewModel(){
* *
* @property name 社团名称 * @property name 社团名称
*/ */
data class AssociationDto(val name:String) data class AssociationDto(val name: String)
/** /**
* 主页 * 主页
* *
*/ */
class MainViewModel:ViewModel(),SendInterface{ class MainViewModel : ViewModel(), SendInterface {
override val _openDialog: MutableLiveData<Boolean> = MutableLiveData() override val _openDialog: MutableLiveData<Boolean> = MutableLiveData()
override val openDialog: LiveData<Boolean> = _openDialog override val openDialog: LiveData<Boolean> = _openDialog
override val newContent: StringForm = StringForm(formDesc = "留言",textLength = 30) override val newContent: StringForm = StringForm(formDesc = "留言", textLength = 30)
override fun openDialog() { override fun openDialog() {
_openDialog.value=true _openDialog.value = true
} }
override fun closeDialog() { override fun closeDialog() {
_openDialog.value=false _openDialog.value = false
} }
/** /**
@ -106,35 +110,25 @@ class MainViewModel:ViewModel(),SendInterface{
override fun send(callback: (message: String) -> Unit) { override fun send(callback: (message: String) -> Unit) {
callback(NOT_IMPL_TIP) callback(NOT_IMPL_TIP)
} }
/**
* TODO 打开通知
*
* @param callback
*/
fun openNotification(callback: (value: String) -> Unit){
callback(NOT_IMPL_TIP)
}
} }
/** /**
* 社团列表 * 社团列表
* *
*/ */
class ListViewModel: ScrollList<AssociationDto>() { class ListViewModel : ScrollList<AssociationDto>() {
val name = StringForm(formDesc = "社团名称",textLength = 5) val name = StringForm(formDesc = "社团名称", textLength = 5)
val desc = StringForm(formDesc = "社团简介",textLength = 10) val desc = StringForm(formDesc = "社团简介", textLength = 10)
//社团列表加载数量 //社团列表加载数量
val associationListSize=10 val associationListSize = 10
//社团列表 //社团列表
private val _associationList=MutableLiveData<MutableList<AssociationDto>>(mutableListOf()) private val _associationList = MutableLiveData<MutableList<AssociationDto>>(mutableListOf())
val associationDto:LiveData<MutableList<AssociationDto>> = _associationList val associationDto: LiveData<MutableList<AssociationDto>> = _associationList
val searchDesc="搜索"
val searchDesc = "搜索"
/** /**
@ -142,7 +136,7 @@ class ListViewModel: ScrollList<AssociationDto>() {
* *
* @param callback * @param callback
*/ */
fun search(callback: (value: String) -> Unit){ fun search(callback: (value: String) -> Unit) {
Logger.i("搜索条件[社团名称:${name.formValue.value},社团简介:${desc.formValue.value}]") Logger.i("搜索条件[社团名称:${name.formValue.value},社团简介:${desc.formValue.value}]")
callback(NOT_IMPL_TIP) callback(NOT_IMPL_TIP)
} }
@ -161,7 +155,8 @@ class ListViewModel: ScrollList<AssociationDto>() {
override fun load() { override fun load() {
viewModelScope.launch { viewModelScope.launch {
_associationList.value?.apply { _associationList.value?.apply {
repeat(10 repeat(
10
) { ) {
add(AssociationDto(name = "社团${_associationList.value?.size}")) add(AssociationDto(name = "社团${_associationList.value?.size}"))
} }
@ -178,10 +173,10 @@ class ListViewModel: ScrollList<AssociationDto>() {
override fun loadMore(callback: (message: String) -> Unit) { override fun loadMore(callback: (message: String) -> Unit) {
viewModelScope.launch { viewModelScope.launch {
_associationList.value?.apply { _associationList.value?.apply {
val list= mutableListOf<AssociationDto>() val list = mutableListOf<AssociationDto>()
list.addAll(this) list.addAll(this)
list.apply { list.apply {
repeat(10){ repeat(10) {
add(AssociationDto(name = "社团${size}")) add(AssociationDto(name = "社团${size}"))
} }
} }
@ -203,32 +198,40 @@ class ListViewModel: ScrollList<AssociationDto>() {
* @property headImg 头像 * @property headImg 头像
* @property desc 个人简介 * @property desc 个人简介
*/ */
data class InfoVo(val studentId:String,val name:String,val duty:String,val headImg:String,val desc:String) data class InfoVo(
val studentId: String,
val name: String,
val duty: String,
val headImg: String,
val desc: String
)
/** /**
* 个人中心 * 个人中心
* *
*/ */
class CenterViewModel:ViewModel(){ class CenterViewModel : ViewModel() {
val myAssociationDesc="我的社团" val myAssociationDesc = "我的社团"
val myJoinActivity="我参加的社团活动" val myJoinActivity = "我参加的社团活动"
val myLikeActivity="我点赞的社团活动" val myLikeActivity = "我点赞的社团活动"
val myCollectActivity="我收藏的社团活动" val myCollectActivity = "我收藏的社团活动"
private val _info=MutableLiveData<InfoVo>() private val _info = MutableLiveData<InfoVo>()
val info:LiveData<InfoVo> = _info val info: LiveData<InfoVo> = _info
init { init {
load() load()
} }
private fun load(){ private fun load() {
viewModelScope.launch { viewModelScope.launch {
_info.value= InfoVo(studentId = randomNum(), _info.value = InfoVo(
studentId = randomNum(),
name = randomChinese(3), name = randomChinese(3),
duty = randomChinese(3), duty = randomChinese(3),
headImg = "", headImg = "",
desc = randomChinese(10)) desc = randomChinese(10)
)
} }
} }

@ -10,7 +10,6 @@ import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.* import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.rememberLazyListState import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.* import androidx.compose.material.*
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
@ -31,6 +30,7 @@ import com.gyf.csams.activity.ui.ActivityDetailActivity
import com.gyf.csams.association.ui.AssociationActivity import com.gyf.csams.association.ui.AssociationActivity
import com.gyf.csams.association.ui.RegAssociationActivity import com.gyf.csams.association.ui.RegAssociationActivity
import com.gyf.csams.main.model.* import com.gyf.csams.main.model.*
import com.gyf.csams.message.ui.MessageActivity
import com.gyf.csams.uikit.* import com.gyf.csams.uikit.*
import com.gyf.csams.uikit.theme.CSAMSTheme import com.gyf.csams.uikit.theme.CSAMSTheme
import com.gyf.csams.util.randomChinese import com.gyf.csams.util.randomChinese
@ -90,14 +90,18 @@ class MainActivity : ComponentActivity() {
Column( Column(
modifier = Modifier.weight(0.3F).padding(10.dp), modifier = Modifier
.weight(0.3F)
.padding(10.dp),
) { ) {
info?.let { info?.let {
Row(modifier = Modifier Row(
.fillMaxWidth() modifier = Modifier
.weight(0.7F) .fillMaxWidth()
.border(width = 1.dp, color = MaterialTheme.colors.background), .weight(0.7F)
horizontalArrangement = Arrangement.SpaceBetween) { .border(width = 1.dp, color = MaterialTheme.colors.background),
horizontalArrangement = Arrangement.SpaceBetween
) {
Image( Image(
painter = painterResource( painter = painterResource(
id = R.drawable.ic_launcher_foreground id = R.drawable.ic_launcher_foreground
@ -122,7 +126,10 @@ class MainActivity : ComponentActivity() {
Spacer(modifier = Modifier.weight(0.05F)) Spacer(modifier = Modifier.weight(0.05F))
Card(backgroundColor = MaterialTheme.colors.background,modifier = Modifier.weight(0.15F)) { Card(
backgroundColor = MaterialTheme.colors.background,
modifier = Modifier.weight(0.15F)
) {
Row( Row(
modifier = Modifier.fillMaxWidth(), modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.Center horizontalArrangement = Arrangement.Center
@ -186,10 +193,15 @@ class MainActivity : ComponentActivity() {
) { ) {
Column(modifier = Modifier.weight(0.33F)) { Column(modifier = Modifier.weight(0.33F)) {
Notification() Notification()
MessageBoard() Column(
Spacer(modifier = Modifier.height(10.dp)) modifier = Modifier
ClubActivitiesTitle() .fillMaxSize()
Spacer(modifier = Modifier.height(10.dp)) .padding(horizontal = 15.dp),
verticalArrangement = Arrangement.SpaceEvenly
) {
MessageBoard()
ClubActivitiesTitle()
}
} }
Column(modifier = Modifier.weight(0.66F)) { Column(modifier = Modifier.weight(0.66F)) {
PosterWithDesc() PosterWithDesc()
@ -366,10 +378,8 @@ class MainActivity : ComponentActivity() {
* *
*/ */
@Composable @Composable
private fun Notification( private fun Notification() {
mainViewModel: MainViewModel = viewModel(), val context = LocalContext.current
scaffoldModel: ScaffoldModel = viewModel()
) {
Row( Row(
horizontalArrangement = Arrangement.End, horizontalArrangement = Arrangement.End,
modifier = Modifier modifier = Modifier
@ -377,7 +387,7 @@ class MainActivity : ComponentActivity() {
.padding(10.dp) .padding(10.dp)
) { ) {
IconButton(onClick = { IconButton(onClick = {
mainViewModel.openNotification { scaffoldModel.update(message = it) } context.startActivity(Intent(context, MessageActivity::class.java))
}) { }) {
Icon( Icon(
painter = painterResource(id = R.drawable.ic_notification), painter = painterResource(id = R.drawable.ic_notification),
@ -388,37 +398,17 @@ class MainActivity : ComponentActivity() {
} }
} }
/**
* 圆角矩形边框
*
*/
@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 @Composable
private fun MessageBoard( private fun MessageBoard(
modifier: Modifier = Modifier,
model: MarqueeViewModel = viewModel(), model: MarqueeViewModel = viewModel(),
mainViewModel: MainViewModel = viewModel(), mainViewModel: MainViewModel = viewModel()
scaffoldModel: ScaffoldModel = viewModel()
) { ) {
MyBorder { Card(modifier = modifier, backgroundColor = MaterialTheme.colors.background) {
Row( Row(
verticalAlignment = Alignment.CenterVertically verticalAlignment = Alignment.CenterVertically
) { ) {
@ -454,12 +444,11 @@ class MainActivity : ComponentActivity() {
* *
*/ */
@Composable @Composable
private fun ClubActivitiesTitle() { private fun ClubActivitiesTitle(modifier: Modifier = Modifier) {
MyBorder { Card(modifier = modifier, backgroundColor = MaterialTheme.colors.background) {
Row( Row(
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth(),
.height(50.dp),
horizontalArrangement = Arrangement.Center, horizontalArrangement = Arrangement.Center,
verticalAlignment = Alignment.CenterVertically verticalAlignment = Alignment.CenterVertically
) { ) {

@ -0,0 +1,11 @@
package com.gyf.csams.message.model
import androidx.lifecycle.ViewModel
enum class MessageType(val desc: String) {
System("系统通知")
}
class MessageViewModel : ViewModel() {
val message = "消息"
}

@ -0,0 +1,136 @@
package com.gyf.csams.message.model
import androidx.lifecycle.viewModelScope
import com.gyf.csams.NOT_IMPL_TIP
import com.gyf.csams.uikit.ScrollList
import com.gyf.csams.util.randomChinese
import com.gyf.csams.util.randomDateTime
import com.gyf.csams.util.randomNum
import kotlinx.coroutines.launch
import java.util.*
import kotlin.random.Random
enum class SystemType(val desc: String) {
Join("入团通知"),
ActCheck("活动审核通知"),
Rename("社团重命名审核通知")
}
/**
* 通知内容
*
*/
sealed class MessageContent {
//通知时间
abstract val createTime: Date
//通知状态
abstract val readState: Boolean
//通知类型
abstract val type: SystemType
}
/**
* 入团通知
* @param studentId 学号
* @param studentName 姓名
*
*/
data class JoinContent(
val studentId: Long,
val studentName: String,
override val createTime: Date,
override val readState: Boolean,
override val type: SystemType = SystemType.Join
) : MessageContent()
/**
* 活动审核通知
*
* @property activityId 活动id
* @property activityName 活动名
*
*/
data class ActCheckContent(
val activityId: Long, val activityName: String,
override val createTime: Date,
override val readState: Boolean,
override val type: SystemType = SystemType.ActCheck
) : MessageContent()
/**
* 社团重命名审核通知
*
* @property oldAssociationName 老社团名字
* @property newAssociationName 新社团名字
*
*/
data class RenameContent(
val oldAssociationName: String, val newAssociationName: String,
override val createTime: Date,
override val readState: Boolean,
override val type: SystemType = SystemType.Rename
) : MessageContent()
/**
* 系统通知数据状态管理
*
*/
class SysMessageViewModel : ScrollList<MessageContent>() {
val title = "系统通知"
override val initSize: Int = 10
init {
load()
}
/**
* TODO 加载通知
*
*/
override fun load() {
viewModelScope.launch {
_data.value?.apply {
repeat(initSize) {
when ((0..2).random()) {
0 -> add(
JoinContent(
createTime = randomDateTime(),
readState = Random.nextBoolean(),
studentId = randomNum().toLong(),
studentName = randomChinese(5)
)
)
1 -> add(
ActCheckContent(
activityId = randomNum().toLong(),
activityName = randomChinese(5),
createTime = randomDateTime(),
readState = Random.nextBoolean()
)
)
2 -> add(
RenameContent(
oldAssociationName = randomChinese(3),
newAssociationName = randomChinese(3),
createTime = randomDateTime(),
readState = Random.nextBoolean()
)
)
}
}
}
}
}
/**
* TODO 加载更多通知
*
* @param callback
*/
override fun loadMore(callback: (message: String) -> Unit) {
callback(NOT_IMPL_TIP)
}
}

@ -0,0 +1,81 @@
package com.gyf.csams.message.ui
import android.content.Intent
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.*
import androidx.compose.material.Divider
import androidx.compose.material.Icon
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Text
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.unit.dp
import androidx.lifecycle.viewmodel.compose.viewModel
import com.gyf.csams.R
import com.gyf.csams.message.model.MessageType
import com.gyf.csams.message.model.MessageViewModel
import com.gyf.csams.uikit.*
/**
* 消息界面
*
*/
class MessageActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
Body { scaffoldState ->
val model: MessageViewModel = viewModel()
val context = LocalContext.current
MainFrame(background = {
Background(
image = BackgroundImage.ActivityMessage,
alpha = 0.6F
)
}) {
TextTopAppBar(title = model.message)
Spacer(modifier = Modifier.height(5.dp))
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.Center
) {
Column(
horizontalAlignment = Alignment.CenterHorizontally,
modifier = Modifier.clickable(onClick = {
context.startActivity(
Intent(
context,
SysMessageActivity::class.java
)
)
})
) {
Icon(
painter = painterResource(id = R.drawable.ic_notice),
contentDescription = null,
modifier = Modifier.size(30.dp)
)
Text(text = MessageType.System.desc)
}
}
Spacer(modifier = Modifier.height(5.dp))
Divider(
modifier = Modifier.height(10.dp),
color = MaterialTheme.colors.background
)
}
}
}
}
}

@ -0,0 +1,135 @@
package com.gyf.csams.message.ui
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.material.Card
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.livedata.observeAsState
import androidx.compose.ui.Modifier
import androidx.compose.ui.text.SpanStyle
import androidx.compose.ui.text.buildAnnotatedString
import androidx.compose.ui.text.withStyle
import androidx.compose.ui.unit.dp
import androidx.lifecycle.viewmodel.compose.viewModel
import com.gyf.csams.message.model.*
import com.gyf.csams.uikit.*
import com.gyf.csams.util.format
/**
* 系统通知
*
*/
class SysMessageActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
Body { scaffoldState ->
MainFrame(background = {
Background(
image = BackgroundImage.ActivityMessage,
alpha = 0.6F
)
}) {
TextTopAppBar(modifier = Modifier.weight(0.1F), title = MessageType.System.desc)
Spacer(modifier = Modifier.weight(0.05F))
MessageList(modifier = Modifier.weight(0.8F))
}
}
}
}
@Composable
private fun MessageList(
modifier: Modifier = Modifier,
model: SysMessageViewModel = viewModel()
) {
val listState = rememberLazyListState()
val list by model.data.observeAsState()
Box(modifier = modifier.padding(10.dp)) {
LazyColumn(state = listState) {
list?.forEach {
item {
MessageItem(content = it)
Spacer(modifier = Modifier.height(10.dp))
}
}
}
}
}
@Composable
private fun MessageItem(modifier: Modifier = Modifier, content: MessageContent) {
Card(modifier = modifier, backgroundColor = MaterialTheme.colors.background) {
Column(modifier = Modifier.padding(10.dp)) {
Text(text = content.type.desc, style = MaterialTheme.typography.h5)
Spacer(modifier = Modifier.height(5.dp))
Card(
backgroundColor = MaterialTheme.colors.background,
modifier = Modifier
.fillMaxWidth()
.padding(10.dp)
) {
when (content) {
is JoinContent -> JoinMessage(content = content)
is ActCheckContent -> ActCheckMessage(content = content)
is RenameContent -> RenameMessage(content = content)
}
}
Spacer(modifier = Modifier.height(10.dp))
Row(modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.End) {
Text(text = content.createTime.format())
}
}
}
}
@Composable
private fun JoinMessage(content: JoinContent) {
Text(buildAnnotatedString {
withStyle(
style = MaterialTheme.typography.subtitle1.toSpanStyle()
.copy(color = MaterialTheme.colors.primary)
) {
append(content.studentName)
}
append("申请进入社团")
})
}
@Composable
private fun ActCheckMessage(content: ActCheckContent) {
Text(buildAnnotatedString {
append("\"")
withStyle(style = SpanStyle(color = MaterialTheme.colors.primary)) {
append(content.activityName)
}
append("\"活动审核不通过")
})
}
@Composable
private fun RenameMessage(content: RenameContent) {
Text(buildAnnotatedString {
withStyle(style = SpanStyle(color = MaterialTheme.colors.primary)) {
append(content.oldAssociationName)
}
append("重命名为")
withStyle(style = SpanStyle(color = MaterialTheme.colors.secondary)) {
append(content.newAssociationName)
}
append("审核通过")
})
}
}

@ -24,7 +24,6 @@ import androidx.compose.ui.platform.LocalFocusManager
import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.painterResource
import androidx.compose.ui.text.input.ImeAction import androidx.compose.ui.text.input.ImeAction
import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.lifecycle.LiveData import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData import androidx.lifecycle.MutableLiveData
@ -90,7 +89,12 @@ enum class MainMenu(
* @param onClick * @param onClick
*/ */
@Composable @Composable
fun MenuIconButton(_menu: MainMenu, menu: MainMenu, modifier: Modifier=Modifier, onClick: () -> Unit) { fun MenuIconButton(
_menu: MainMenu,
menu: MainMenu,
modifier: Modifier = Modifier,
onClick: () -> Unit
) {
Row( Row(
modifier = modifier, horizontalArrangement = Arrangement.Center modifier = modifier, horizontalArrangement = Arrangement.Center
) { ) {
@ -113,7 +117,7 @@ fun MenuIconButton(_menu: MainMenu, menu: MainMenu, modifier: Modifier=Modifier,
@Composable @Composable
fun MainBottomAppBar(menu: MainMenu, nav: NavHostController, modifier: Modifier = Modifier) { fun MainBottomAppBar(menu: MainMenu, nav: NavHostController, modifier: Modifier = Modifier) {
BottomAppBar(backgroundColor = MaterialTheme.colors.background, modifier = modifier) { BottomAppBar(backgroundColor = MaterialTheme.colors.background, modifier = modifier) {
Row(Modifier.fillMaxWidth(),horizontalArrangement = Arrangement.SpaceBetween) { Row(Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.SpaceBetween) {
MenuIconButton(_menu = menu, menu = MainMenu.Main, MenuIconButton(_menu = menu, menu = MainMenu.Main,
onClick = { nav.navigate(MainMenu.Main.name) }) onClick = { nav.navigate(MainMenu.Main.name) })
MenuIconButton(_menu = menu, menu = MainMenu.List, MenuIconButton(_menu = menu, menu = MainMenu.List,
@ -130,7 +134,7 @@ fun MainBottomAppBar(menu: MainMenu, nav: NavHostController, modifier: Modifier
* 顶部菜单 * 顶部菜单
* *
*/ */
interface TopMenuInterface<T:TopBarMenu>{ interface TopMenuInterface<T : TopBarMenu> {
/** /**
* 当前菜单 * 当前菜单
*/ */
@ -142,59 +146,59 @@ interface TopMenuInterface<T:TopBarMenu>{
* *
* @param menu * @param menu
*/ */
fun clickMenu(menu:T){ fun clickMenu(menu: T) {
_currentMenu.value=menu _currentMenu.value = menu
} }
} }
interface TopBarMenu{ interface TopBarMenu {
val menuName:String val menuName: String
val name:String val name: String
} }
interface StartMenu<T>{ interface StartMenu<T> {
val startMenu:T val startMenu: T
} }
/** /**
* 社团菜单 * 社团菜单
* *
*/ */
enum class AssociationMenu(override val menuName: String):TopBarMenu { enum class AssociationMenu(override val menuName: String) : TopBarMenu {
Member("社团成员"), Member("社团成员"),
Main("社团主页"), Main("社团主页"),
ActivityList("活动列表"); ActivityList("活动列表");
companion object Menu:StartMenu<AssociationMenu>{ companion object Menu : StartMenu<AssociationMenu> {
override val startMenu: AssociationMenu = Main override val startMenu: AssociationMenu = Main
} }
} }
enum class ActivityDetailMenu(override val menuName:String):TopBarMenu{ enum class ActivityDetailMenu(override val menuName: String) : TopBarMenu {
Info("活动信息"), Info("活动信息"),
Photo("相册"), Photo("相册"),
Member("活动成员"), Member("活动成员"),
BBS("交流区"); BBS("交流区");
companion object Menu:StartMenu<ActivityDetailMenu>{ companion object Menu : StartMenu<ActivityDetailMenu> {
override val startMenu: ActivityDetailMenu = Info override val startMenu: ActivityDetailMenu = Info
} }
} }
interface SendInterface{ interface SendInterface {
/** /**
* 弹窗状态 * 弹窗状态
*/ */
val _openDialog:MutableLiveData<Boolean> val _openDialog: MutableLiveData<Boolean>
val openDialog:LiveData<Boolean> val openDialog: LiveData<Boolean>
/** /**
* 编辑内容 * 编辑内容
*/ */
val newContent:StringForm val newContent: StringForm
/** /**
* 打开弹窗 * 打开弹窗
@ -224,9 +228,9 @@ interface SendInterface{
* @param scaffoldModel * @param scaffoldModel
*/ */
@Composable @Composable
fun <T:SendInterface> SendComment(model:T, scaffoldModel: ScaffoldModel= viewModel()){ fun <T : SendInterface> SendComment(model: T, scaffoldModel: ScaffoldModel = viewModel()) {
val openDialog by model.openDialog.observeAsState() val openDialog by model.openDialog.observeAsState()
if(openDialog==true) { if (openDialog == true) {
AlertDialog(onDismissRequest = { /*TODO*/ }, AlertDialog(onDismissRequest = { /*TODO*/ },
buttons = { buttons = {
Row( Row(
@ -265,22 +269,51 @@ fun <T:SendInterface> SendComment(model:T, scaffoldModel: ScaffoldModel= viewMod
} }
/** /**
* 社团顶部菜单 * 只包含返回按钮的顶部菜单
*
* @param title
*/
@Composable
fun TextTopAppBar(modifier: Modifier = Modifier, title: String) {
Row(
modifier = modifier.fillMaxWidth(),
verticalAlignment = Alignment.CenterVertically
) {
val context = LocalContext.current as Activity
Row(modifier = Modifier.weight(1F / 3)) {
IconButton(onClick = {
context.finish()
}) {
Icon(
painter = painterResource(id = R.drawable.ic_arrow_left),
contentDescription = null
)
}
}
Row(modifier = Modifier.weight(1F / 3), horizontalArrangement = Arrangement.Center) {
Text(text = title, style = MaterialTheme.typography.h5)
}
Spacer(modifier = Modifier.weight(1F / 3))
}
}
/**
* 顶部菜单
* *
*/ */
@Composable @Composable
fun TextTopAppBar( fun TextTopAppBar(
nav:NavHostController, nav: NavHostController,
currentMenuName:String, currentMenuName: String,
menuNames:Array<out TopBarMenu>, menuNames: Array<out TopBarMenu>,
iconMenu: (() -> Unit)? = null, iconMenu: (() -> Unit)? = null,
@DrawableRes icon:Int = R.drawable.ic_configuration, @DrawableRes icon: Int = R.drawable.ic_configuration,
dropMenuContent:@Composable () -> Unit = {}, dropMenuContent: @Composable () -> Unit = {},
) { ) {
TopAppBar(backgroundColor = MaterialTheme.colors.secondary) { TopAppBar(backgroundColor = MaterialTheme.colors.secondary) {
Row(modifier = Modifier.fillMaxWidth(), verticalAlignment = Alignment.CenterVertically) { Row(modifier = Modifier.fillMaxWidth(), verticalAlignment = Alignment.CenterVertically) {
val context= LocalContext.current as Activity val context = LocalContext.current as Activity
IconButton(onClick = {context.finish()}, modifier = Modifier.weight(0.1F)) { IconButton(onClick = { context.finish() }, modifier = Modifier.weight(0.1F)) {
Icon( Icon(
painter = painterResource(id = R.drawable.ic_arrow_left), painter = painterResource(id = R.drawable.ic_arrow_left),
contentDescription = null contentDescription = null
@ -307,18 +340,18 @@ fun TextTopAppBar(
} }
} }
} }
if(iconMenu!=null) { if (iconMenu != null) {
IconButton(onClick = iconMenu, modifier = Modifier.weight(0.1F)) { IconButton(onClick = iconMenu, modifier = Modifier.weight(0.1F)) {
Icon( Icon(
painter = painterResource(id = icon), painter = painterResource(id = icon),
contentDescription = null contentDescription = null
) )
} }
}else{ } else {
Spacer(modifier = Modifier.weight(0.1F)) Spacer(modifier = Modifier.weight(0.1F))
} }
} }
if(iconMenu!=null) dropMenuContent() if (iconMenu != null) dropMenuContent()
} }
} }
@ -480,17 +513,17 @@ fun ShowSnackbar(model: ScaffoldModel = viewModel(), scaffoldState: ScaffoldStat
LaunchedEffect(scaffoldState) { LaunchedEffect(scaffoldState) {
launch { launch {
if (actionLabel != null) { if (actionLabel != null) {
val result=scaffoldState.snackbarHostState.showSnackbar( val result = scaffoldState.snackbarHostState.showSnackbar(
message = message, actionLabel = actionLabel, message = message, actionLabel = actionLabel,
duration = duration duration = duration
) )
when(result){ when (result) {
SnackbarResult.ActionPerformed->{ SnackbarResult.ActionPerformed -> {
Logger.i("点击操作按钮") Logger.i("点击操作按钮")
callback() callback()
} }
SnackbarResult.Dismissed->{ SnackbarResult.Dismissed -> {
Logger.d("窗口消失") Logger.d("窗口消失")
} }
} }
@ -535,12 +568,20 @@ enum class BackgroundImage(@DrawableRes val id: Int) {
//活动信息 //活动信息
ActivityInfo(R.drawable.mb_bg_fb_01), ActivityInfo(R.drawable.mb_bg_fb_01),
//活动相册 //活动相册
ActivityPhoto(R.drawable.mb_bg_fb_02), ActivityPhoto(R.drawable.mb_bg_fb_02),
//活动成员 //活动成员
ActivityMember(R.drawable.mb_bg_fb_03), ActivityMember(R.drawable.mb_bg_fb_03),
//交流区 //交流区
ActivityBBS(R.drawable.mb_bg_fb_04) ActivityBBS(R.drawable.mb_bg_fb_04),
//系统通知
ActivityMessage(R.drawable.mb_bg_fb_26)
} }
/** /**
@ -631,7 +672,7 @@ fun Poster(modifier: Modifier = Modifier, @DrawableRes id: Int) {
* *
*/ */
@Composable @Composable
fun DescCard(modifier: Modifier,content:String) { fun DescCard(modifier: Modifier, content: String) {
Card( Card(
modifier = modifier, modifier = modifier,
backgroundColor = Color.Transparent backgroundColor = Color.Transparent
@ -643,9 +684,11 @@ fun DescCard(modifier: Modifier,content:String) {
contentScale = ContentScale.FillBounds, contentScale = ContentScale.FillBounds,
modifier = Modifier.fillMaxSize() modifier = Modifier.fillMaxSize()
) )
Column(modifier = Modifier Column(
.fillMaxSize() modifier = Modifier
.padding(horizontal = 10.dp)) { .fillMaxSize()
.padding(horizontal = 10.dp)
) {
Spacer(modifier = Modifier.weight(0.15F)) Spacer(modifier = Modifier.weight(0.15F))
Text( Text(
modifier = Modifier.weight(0.65F), modifier = Modifier.weight(0.65F),
@ -665,10 +708,10 @@ fun AnimationTextPreview() {
AnimationText(text = "6666") AnimationText(text = "6666")
} }
@Preview //@Preview
@Composable @Composable
fun MyBottomAppBarPreview() { fun MyBottomAppBarPreview() {
val arr:List<Arrangement.Horizontal> = listOf( val arr: List<Arrangement.Horizontal> = listOf(
Arrangement.Start, Arrangement.Start,
Arrangement.End, Arrangement.End,
Arrangement.Center, Arrangement.Center,
@ -680,26 +723,33 @@ fun MyBottomAppBarPreview() {
mutableStateOf(3) mutableStateOf(3)
} }
Column(modifier = Modifier.fillMaxSize()) { Column(modifier = Modifier.fillMaxSize()) {
Row(modifier = Modifier.fillMaxWidth(),horizontalArrangement = Arrangement.SpaceEvenly) { Row(modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.SpaceEvenly) {
OutlinedButton(onClick = { i += 1 }) { OutlinedButton(onClick = { i += 1 }) {
Text(text = "添加元素") Text(text = "添加元素")
} }
if(i>1) { if (i > 1) {
OutlinedButton(onClick = { i -= 1 }) { OutlinedButton(onClick = { i -= 1 }) {
Text(text = "删除元素") Text(text = "删除元素")
} }
} }
} }
arr.forEach { arr.forEach {
Column(modifier = Modifier Column(
.weight(1F / arr.size) modifier = Modifier
.border(width = 1.dp, color = MaterialTheme.colors.background)) { .weight(1F / arr.size)
Row(modifier = Modifier.fillMaxWidth(),horizontalArrangement = Arrangement.Center) { .border(width = 1.dp, color = MaterialTheme.colors.background)
Text(text = "$it",style = MaterialTheme.typography.h5) ) {
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.Center
) {
Text(text = "$it", style = MaterialTheme.typography.h5)
} }
Row(modifier = Modifier.fillMaxSize(), Row(
modifier = Modifier.fillMaxSize(),
horizontalArrangement = it, horizontalArrangement = it,
verticalAlignment = Alignment.CenterVertically) { verticalAlignment = Alignment.CenterVertically
) {
repeat(i) { repeat(i) {
Text(text = "$it", style = MaterialTheme.typography.h3) Text(text = "$it", style = MaterialTheme.typography.h3)
} }

@ -6,16 +6,16 @@ import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import com.orhanobut.logger.Logger import com.orhanobut.logger.Logger
interface FormLength{ interface FormLength {
val nameLengthError:String val nameLengthError: String
} }
abstract class FormName<T>(val formDesc:String){ abstract class FormName<T>(val formDesc: String) {
protected val _formValue= MutableLiveData<T>() protected val _formValue = MutableLiveData<T>()
val formValue: LiveData<T> = _formValue val formValue: LiveData<T> = _formValue
val formPlaceholder="请输入$formDesc" val formPlaceholder = "请输入$formDesc"
abstract fun onChange(value:T) abstract fun onChange(value: T)
} }
@ -28,55 +28,66 @@ abstract class FormName<T>(val formDesc:String){
* *
* @param formDesc * @param formDesc
*/ */
open class StringForm(formDesc: String, val textLength: Int) : FormName<String>(formDesc = formDesc), open class StringForm(formDesc: String, val textLength: Int) :
FormName<String>(formDesc = formDesc),
FormLength { FormLength {
constructor(formDesc: String,textLength: Int,value:String) : this(formDesc = formDesc,textLength = textLength) { constructor(formDesc: String, textLength: Int, value: String) : this(
_formValue.value=value formDesc = formDesc,
textLength = textLength
) {
_formValue.value = value
} }
override val nameLengthError="${formDesc}不能超过最大长度$textLength" override val nameLengthError = "${formDesc}不能超过最大长度$textLength"
override fun onChange(value: String) { override fun onChange(value: String) {
if(value.length>textLength){ if (value.length > textLength) {
_formValue.value=value.slice(IntRange(0,textLength-1)) _formValue.value = value.slice(IntRange(0, textLength - 1))
}else{ } else {
_formValue.value=value _formValue.value = value
} }
Logger.i("${formDesc}更新值:${_formValue.value}") Logger.i("${formDesc}更新值:${_formValue.value}")
} }
} }
data class SnackBar(val message:String?, val actionLabel:String?=null,val duration: SnackbarDuration=SnackbarDuration.Short, val callback: () -> Unit?) data class SnackBar(
val message: String?,
val actionLabel: String? = null,
val duration: SnackbarDuration = SnackbarDuration.Short,
val callback: () -> Unit?
)
/** /**
* snackbar * snackbar
* *
*/ */
class ScaffoldModel:ViewModel(){ class ScaffoldModel : ViewModel() {
private val _data=MutableLiveData<SnackBar>() private val _data = MutableLiveData<SnackBar>()
val data:LiveData<SnackBar> = _data val data: LiveData<SnackBar> = _data
fun update(message:String?=null,actionLabel: String? = null,callback: () -> Unit? = {}){ fun update(message: String? = null, actionLabel: String? = null, callback: () -> Unit? = {}) {
if(message==null){ if (message == null) {
_data.value=null _data.value = null
}else { } else {
_data.value = SnackBar(message = message, actionLabel = actionLabel,callback = callback) _data.value =
SnackBar(message = message, actionLabel = actionLabel, callback = callback)
} }
} }
} }
abstract class ScrollList<T>:ViewModel(){ abstract class ScrollList<T> : ViewModel() {
protected val _data=MutableLiveData<MutableList<T>>(mutableListOf()) protected val _data = MutableLiveData<MutableList<T>>(mutableListOf())
val data:LiveData<MutableList<T>> = _data val data: LiveData<MutableList<T>> = _data
abstract val initSize:Int abstract val initSize: Int
//加载列表 //加载列表
abstract fun load() abstract fun load()
//加载更多数据 //加载更多数据
abstract fun loadMore(callback:(message:String) -> Unit) abstract fun loadMore(callback: (message: String) -> Unit)
} }

@ -6,77 +6,84 @@ import com.gyf.csams.association.model.*
import com.gyf.csams.uikit.StringForm import com.gyf.csams.uikit.StringForm
import java.lang.reflect.Type import java.lang.reflect.Type
class OpenQuestionsVoSerializer: JsonSerializer<OpenQuestionsVo> { class OpenQuestionsVoSerializer : JsonSerializer<OpenQuestionsVo> {
override fun serialize( override fun serialize(
vo: OpenQuestionsVo?, vo: OpenQuestionsVo?,
p1: Type?, p1: Type?,
p2: JsonSerializationContext? p2: JsonSerializationContext?
): JsonElement { ): JsonElement {
val gson= Gson() val gson = Gson()
val c = JsonObject() val c = JsonObject()
c.add("examType", gson.toJsonTree(vo?.examType?.name)) c.add("examType", gson.toJsonTree(vo?.examType?.name))
c.add("question",gson.toJsonTree(vo?.question?.formValue?.value)) c.add("question", gson.toJsonTree(vo?.question?.formValue?.value))
return c return c
} }
} }
class OpenQuestionsVoDeserializer: JsonDeserializer<OpenQuestionsVo> { class OpenQuestionsVoDeserializer : JsonDeserializer<OpenQuestionsVo> {
override fun deserialize( override fun deserialize(
json: JsonElement?, json: JsonElement?,
p1: Type?, p1: Type?,
p2: JsonDeserializationContext? p2: JsonDeserializationContext?
): OpenQuestionsVo { ): OpenQuestionsVo {
val root=json?.asJsonObject val root = json?.asJsonObject
val value=root?.get("question")?.asString val value = root?.get("question")?.asString
val question= StringForm(formDesc = "问题",textLength = QUESTION_TEXT_LENGTH) val question = StringForm(formDesc = "问题", textLength = QUESTION_TEXT_LENGTH)
if (value != null) { if (value != null) {
question.onChange(value) question.onChange(value)
return OpenQuestionsVo(question = question) return OpenQuestionsVo(question = question)
}else{ } else {
throw NullPointerException("问题无法解析!!!!") throw NullPointerException("问题无法解析!!!!")
} }
} }
} }
class ChoiceQuestionVoSerializer: JsonSerializer<ChoiceQuestionVo> { class ChoiceQuestionVoSerializer : JsonSerializer<ChoiceQuestionVo> {
override fun serialize( override fun serialize(
vo: ChoiceQuestionVo?, vo: ChoiceQuestionVo?,
p1: Type?, p1: Type?,
p2: JsonSerializationContext? p2: JsonSerializationContext?
): JsonElement { ): JsonElement {
val gson= Gson() val gson = Gson()
val c = JsonObject() val c = JsonObject()
c.add("examType", gson.toJsonTree(vo?.examType?.name)) c.add("examType", gson.toJsonTree(vo?.examType?.name))
c.add("question",gson.toJsonTree(vo?.question?.formValue?.value)) c.add("question", gson.toJsonTree(vo?.question?.formValue?.value))
c.add("answers",gson.toJsonTree(vo?.answers)) c.add("answers", gson.toJsonTree(vo?.answers))
c.add("rightAnswer",gson.toJsonTree(vo?.rightAnswer)) c.add("rightAnswer", gson.toJsonTree(vo?.rightAnswer))
return c return c
} }
} }
class ChoiceQuestionVoDeserializer: JsonDeserializer<ChoiceQuestionVo> { class ChoiceQuestionVoDeserializer : JsonDeserializer<ChoiceQuestionVo> {
override fun deserialize( override fun deserialize(
json: JsonElement?, json: JsonElement?,
p1: Type?, p1: Type?,
p2: JsonDeserializationContext? p2: JsonDeserializationContext?
): ChoiceQuestionVo { ): ChoiceQuestionVo {
val root=json?.asJsonObject val root = json?.asJsonObject
val value=root?.get("question")?.asString val value = root?.get("question")?.asString
val question=StringForm(formDesc = "问题",textLength = QUESTION_TEXT_LENGTH) val question = StringForm(formDesc = "问题", textLength = QUESTION_TEXT_LENGTH)
if (value != null) { if (value != null) {
question.onChange(value) question.onChange(value)
val gson=Gson() val gson = Gson()
val answers:List<String> = gson.fromJson(root.get("answers"),object : TypeToken<List<String>>() {}.type) val answers: List<String> =
if(answers.size!= ANSWER_SIZE){ gson.fromJson(root.get("answers"), object : TypeToken<List<String>>() {}.type)
if (answers.size != ANSWER_SIZE) {
throw IllegalArgumentException("选项数量!=$QUESTION_TEXT_LENGTH") throw IllegalArgumentException("选项数量!=$QUESTION_TEXT_LENGTH")
} }
val rightAnswer=root.get("rightAnswer").asInt val rightAnswer = root.get("rightAnswer").asInt
return ChoiceQuestionVo( return ChoiceQuestionVo(
question = question, question = question,
answers = answers.map { StringForm(formDesc = "选项",textLength = ANSWER_TEXT_LENGTH,value=it) }, answers = answers.map {
StringForm(
formDesc = "选项",
textLength = ANSWER_TEXT_LENGTH,
value = it
)
},
rightAnswer = rightAnswer rightAnswer = rightAnswer
) )
}else{ } else {
throw NullPointerException("问题无法解析!!!!") throw NullPointerException("问题无法解析!!!!")
} }
} }
@ -86,25 +93,29 @@ class ChoiceQuestionVoDeserializer: JsonDeserializer<ChoiceQuestionVo> {
* 题目反序列化 * 题目反序列化
* *
*/ */
class ExamDeserializer:JsonDeserializer<Exam>{ class ExamDeserializer : JsonDeserializer<Exam> {
companion object{ companion object {
val gson: Gson =GsonBuilder() val gson: Gson = GsonBuilder()
.registerTypeAdapter(OpenQuestionsVo::class.java,OpenQuestionsVoDeserializer()) .registerTypeAdapter(OpenQuestionsVo::class.java, OpenQuestionsVoDeserializer())
.registerTypeAdapter(ChoiceQuestionVo::class.java,ChoiceQuestionVoDeserializer()) .registerTypeAdapter(ChoiceQuestionVo::class.java, ChoiceQuestionVoDeserializer())
.create() .create()
} }
override fun deserialize(json: JsonElement?, p1: Type?, p2: JsonDeserializationContext?): Exam { override fun deserialize(json: JsonElement?, p1: Type?, p2: JsonDeserializationContext?): Exam {
val root=json?.asJsonObject val root = json?.asJsonObject
val type=root?.get("examType")?.asString val type = root?.get("examType")?.asString
return when (gson.fromJson(type, ExamType::class.java)) { return when (gson.fromJson(type, ExamType::class.java)) {
ExamType.CQ -> gson.fromJson(json, ExamType.CQ -> gson.fromJson(
object : TypeToken<ChoiceQuestionVo>() {}.type) json,
ExamType.OQ -> gson.fromJson(json, object : TypeToken<ChoiceQuestionVo>() {}.type
object : TypeToken<OpenQuestionsVo>() {}.type) )
null->throw NullPointerException("无法识别题目类型!") ExamType.OQ -> gson.fromJson(
json,
object : TypeToken<OpenQuestionsVo>() {}.type
)
null -> throw NullPointerException("无法识别题目类型!")
} }
} }

@ -10,30 +10,30 @@ import okhttp3.RequestBody.Companion.toRequestBody
import java.io.IOException import java.io.IOException
import java.lang.reflect.Type import java.lang.reflect.Type
object HttpClient{ object HttpClient {
private val httpClient:OkHttpClient=OkHttpClient() private val httpClient: OkHttpClient = OkHttpClient()
private val JSON_CONTENT_TYPE="application/json; charset=UTF-8".toMediaType() private val JSON_CONTENT_TYPE = "application/json; charset=UTF-8".toMediaType()
private fun buildQueryParams(params:Map<String,String>?):String{ private fun buildQueryParams(params: Map<String, String>?): String {
return if(params?.isNotEmpty() == true) { return if (params?.isNotEmpty() == true) {
val urlPath = StringBuilder("?") val urlPath = StringBuilder("?")
for(i in params){ for (i in params) {
urlPath.append(i.key).append("=").append(i.value) urlPath.append(i.key).append("=").append(i.value)
} }
urlPath.toString() urlPath.toString()
}else{ } else {
"" ""
} }
} }
private fun buildFormBody(params: Map<String, String>?):FormBody{ private fun buildFormBody(params: Map<String, String>?): FormBody {
val builder=FormBody.Builder() val builder = FormBody.Builder()
if(params?.isNotEmpty()==true){ if (params?.isNotEmpty() == true) {
for(item in params){ for (item in params) {
builder.add(item.key,item.value) builder.add(item.key, item.value)
} }
} }
return builder.build() return builder.build()
@ -46,11 +46,11 @@ object HttpClient{
* @param callback * @param callback
* @param params * @param params
*/ */
fun get(url:String, callback: Callback, params: Map<String, String>?=null){ fun get(url: String, callback: Callback, params: Map<String, String>? = null) {
val request = Request.Builder() val request = Request.Builder()
.url(url.plus(buildQueryParams(params = params))) .url(url.plus(buildQueryParams(params = params)))
.build() .build()
val call=httpClient.newCall(request) val call = httpClient.newCall(request)
call.enqueue(callback) call.enqueue(callback)
} }
@ -62,12 +62,12 @@ object HttpClient{
* @param callback * @param callback
* @param params * @param params
*/ */
fun post(url:String, callback: Callback, params: Map<String, String>?=null){ fun post(url: String, callback: Callback, params: Map<String, String>? = null) {
val request = Request.Builder() val request = Request.Builder()
.url(url) .url(url)
.post(body = buildFormBody(params)) .post(body = buildFormBody(params))
.build() .build()
val call=httpClient.newCall(request) val call = httpClient.newCall(request)
call.enqueue(callback) call.enqueue(callback)
} }
@ -79,13 +79,13 @@ object HttpClient{
* @param callback * @param callback
* @param jsonBody * @param jsonBody
*/ */
fun post(url:String, callback: Callback, jsonBody:String){ fun post(url: String, callback: Callback, jsonBody: String) {
Logger.json(jsonBody) Logger.json(jsonBody)
val request = Request.Builder() val request = Request.Builder()
.url(url) .url(url)
.post(body = jsonBody.toRequestBody(contentType = JSON_CONTENT_TYPE)) .post(body = jsonBody.toRequestBody(contentType = JSON_CONTENT_TYPE))
.build() .build()
val call=httpClient.newCall(request) val call = httpClient.newCall(request)
call.enqueue(callback) call.enqueue(callback)
} }
@ -93,31 +93,33 @@ object HttpClient{
} }
data class ApiResponse<T>(val code:Int,val message:String,val body:T?=null) data class ApiResponse<T>(val code: Int, val message: String, val body: T? = null)
class SimpleCallback<T>(private val action:String, class SimpleCallback<T>(
private val onSuccess:(res:ApiResponse<T>) -> Unit, private val action: String,
private val onFail:(error:String) -> Unit, private val onSuccess: (res: ApiResponse<T>) -> Unit,
private val type: Type):Callback{ private val onFail: (error: String) -> Unit,
private val type: Type
) : Callback {
companion object{ companion object {
val gson: Gson =GsonBuilder() val gson: Gson = GsonBuilder()
.registerTypeAdapter(Exam::class.java,ExamDeserializer()) .registerTypeAdapter(Exam::class.java, ExamDeserializer())
.create() .create()
} }
override fun onFailure(call: Call, e: IOException) { override fun onFailure(call: Call, e: IOException) {
onFail("${action}失败,请联系管理员") onFail("${action}失败,请联系管理员")
Logger.e(e,"${action}请求失败,发生IO异常") Logger.e(e, "${action}请求失败,发生IO异常")
} }
override fun onResponse(call: Call, response: Response) { override fun onResponse(call: Call, response: Response) {
if (response.code == 200) { if (response.code == 200) {
val body=response.body val body = response.body
if (body!=null&&body.contentType()?.subtype == "json") { if (body != null && body.contentType()?.subtype == "json") {
val jsonRes=body.string() val jsonRes = body.string()
val res:ApiResponse<T> = gson.fromJson(jsonRes, type) val res: ApiResponse<T> = gson.fromJson(jsonRes, type)
Logger.i("${action}请求响应成功:") Logger.i("${action}请求响应成功:")
Logger.json(jsonRes) Logger.json(jsonRes)
onSuccess(res) onSuccess(res)
@ -125,7 +127,7 @@ class SimpleCallback<T>(private val action:String,
onFail("${action}失败,请联系管理员") onFail("${action}失败,请联系管理员")
Logger.e("无法解析${action}请求响应数据:,响应码:${response.code},${response.body}") Logger.e("无法解析${action}请求响应数据:,响应码:${response.code},${response.body}")
} }
}else{ } else {
onFail("${action}失败,请联系管理员") onFail("${action}失败,请联系管理员")
Logger.e("${action}失败,请求响应码:${response.code}") Logger.e("${action}失败,请求响应码:${response.code}")
} }

@ -4,8 +4,8 @@ import okhttp3.internal.toHexString
import java.text.SimpleDateFormat import java.text.SimpleDateFormat
import java.util.* import java.util.*
fun randomNum(length:Int=8):String{ fun randomNum(length: Int = 8): String {
return List(length) {('0' .. '9').random()}.joinToString("") return List(length) { ('0'..'9').random() }.joinToString("")
} }
@ -22,7 +22,7 @@ fun String.decodeUnicode(): String {
return String(unicodes.toCharArray()) return String(unicodes.toCharArray())
} }
val CHINESE_UNICODE_AREA=0X4e00..0X9fa5 val CHINESE_UNICODE_AREA = 0X4e00..0X9fa5
/** /**
* 随机中文 * 随机中文
@ -30,26 +30,30 @@ val CHINESE_UNICODE_AREA=0X4e00..0X9fa5
* @param length * @param length
* @return * @return
*/ */
fun randomChinese(length:Int=8):String{ fun randomChinese(length: Int = 8): String {
return List(length){ "\\u${CHINESE_UNICODE_AREA.random().toHexString()}".decodeUnicode() }.joinToString("") return List(length) {
"\\u${
CHINESE_UNICODE_AREA.random().toHexString()
}".decodeUnicode()
}.joinToString("")
} }
const val DATETIME_FORMAT="yyyy-MM-dd HH:mm" const val DATETIME_FORMAT = "yyyy-MM-dd HH:mm"
const val START_TIME="2021-01-01 00:00" const val START_TIME = "2021-01-01 00:00"
val FORMAT=SimpleDateFormat(DATETIME_FORMAT,Locale.US) val FORMAT = SimpleDateFormat(DATETIME_FORMAT, Locale.US)
val startUnix= FORMAT.parse(START_TIME)?.time val startUnix = FORMAT.parse(START_TIME)?.time
fun randomDateTime():Date{ fun randomDateTime(): Date {
if (startUnix != null) { if (startUnix != null) {
return Date("${(startUnix..Date().time).random()}".toLong()) return Date("${(startUnix..Date().time).random()}".toLong())
}else{ } else {
throw IllegalArgumentException("生成随机失败,无法获取起始时间") throw IllegalArgumentException("生成随机失败,无法获取起始时间")
} }
} }
fun Date.format():String{ fun Date.format(): String {
return FORMAT.format(this) return FORMAT.format(this)
} }

@ -12,7 +12,11 @@ import kotlinx.serialization.Serializable
*/ */
@Entity @Entity
@Serializable @Serializable
data class Token(@PrimaryKey val studentId:String,@ColumnInfo val token:String,@ColumnInfo val createTime:Long) data class Token(
@PrimaryKey val studentId: String,
@ColumnInfo val token: String,
@ColumnInfo val createTime: Long
)
/** /**
* 令牌传输 * 令牌传输
@ -21,7 +25,7 @@ data class Token(@PrimaryKey val studentId:String,@ColumnInfo val token:String,@
* @property token * @property token
*/ */
@Serializable @Serializable
data class TokenResDto(val isValid:Boolean,val token: Token?) data class TokenResDto(val isValid: Boolean, val token: Token?)
@Dao @Dao
interface TokenDao { interface TokenDao {
@ -40,7 +44,7 @@ class TokenManager private constructor(private var token: Token?) {
@Volatile @Volatile
private var instance: TokenManager? = null private var instance: TokenManager? = null
fun getInstance(token: Token?=null) = fun getInstance(token: Token? = null) =
instance ?: synchronized(this) { instance ?: synchronized(this) {
instance ?: TokenManager(token).also { instance = it } instance ?: TokenManager(token).also { instance = it }
} }

@ -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="M641.77,222.1L641.77,768.21c0,43.63 -53.87,64.79 -84.05,33.02l-140.31,-149.42 -12.07,-0.02L405.33,746.67a64,64 0,0 1,-64 64h-64a64,64 0,0 1,-64 -64v-94.89L182.06,651.78a64,64 0,0 1,-64 -64v-192.36a64,64 0,0 1,60.22 -63.89l4.61,-0.11 236.67,3.11 138.18,-145.45c30.17,-31.79 84.05,-10.6 84.05,33.02zM769.45,234.41c92.54,47.08 158.23,139.39 167.96,247.83v56.02c-9.45,105.47 -71.85,195.69 -160.43,243.88L747.46,725.33A245.27,245.27 0,0 0,874.67 510.25a245.33,245.33 0,0 0,-134.7 -219.03l29.48,-56.81zM577.77,260.91l-131.07,137.98 -264.64,-3.48v192.38l95.25,-0.04L277.33,746.67h64v-158.98l103.79,0.13 132.65,141.25L577.77,260.91zM715.54,338.33a191.47,191.47 0,0 1,94.44 165.42,191.47 191.47,0 0,1 -92.42,164.2l-29.65,-56.96a127.49,127.49 0,0 0,58.07 -107.24,127.49 127.49,0 0,0 -60.01,-108.5l29.57,-56.92z" />
</vector>
Loading…
Cancel
Save