格式化代码

增加应用通知
master
pan 4 years ago
parent 589f19b69d
commit 6f85668740
  1. 34
      app/src/main/AndroidManifest.xml
  2. 16
      app/src/main/java/com/gyf/csams/APP.kt
  3. 13
      app/src/main/java/com/gyf/csams/InitViewModel.kt
  4. 56
      app/src/main/java/com/gyf/csams/account/model/AccountViewModel.kt
  5. 106
      app/src/main/java/com/gyf/csams/account/ui/AccountActivity.kt
  6. 69
      app/src/main/java/com/gyf/csams/activity/model/ActivityDetailViewModel.kt
  7. 2
      app/src/main/java/com/gyf/csams/association/model/AssociationViewModel.kt
  8. 42
      app/src/main/java/com/gyf/csams/association/model/ExamViewModel.kt
  9. 185
      app/src/main/java/com/gyf/csams/association/ui/AssociationActivity.kt
  10. 33
      app/src/main/java/com/gyf/csams/association/ui/ExamActivity.kt
  11. 9
      app/src/main/java/com/gyf/csams/association/ui/ReNameActivity.kt
  12. 41
      app/src/main/java/com/gyf/csams/association/ui/RegAssociationActivity.kt
  13. 35
      app/src/main/java/com/gyf/csams/main/model/MainViewModel.kt
  14. 67
      app/src/main/java/com/gyf/csams/main/ui/MainActivity.kt
  15. 11
      app/src/main/java/com/gyf/csams/message/model/MessageViewModel.kt
  16. 136
      app/src/main/java/com/gyf/csams/message/model/SysMessageViewModel.kt
  17. 81
      app/src/main/java/com/gyf/csams/message/ui/MessageActivity.kt
  18. 135
      app/src/main/java/com/gyf/csams/message/ui/SysMessageActivity.kt
  19. 74
      app/src/main/java/com/gyf/csams/uikit/BaseView.kt
  20. 19
      app/src/main/java/com/gyf/csams/uikit/ViewModel.kt
  21. 23
      app/src/main/java/com/gyf/csams/util/GsonUtil.kt
  22. 6
      app/src/main/java/com/gyf/csams/util/HttpUtil.kt
  23. 6
      app/src/main/java/com/gyf/csams/util/RandomUtil.kt
  24. 6
      app/src/main/java/com/gyf/csams/util/TokenUtil.kt
  25. 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,12 +15,13 @@ 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
@ -28,7 +29,12 @@ class APP : Application() {
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()
@ -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

@ -44,7 +44,9 @@ class InitViewModel: ViewModel() {
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(
url,
SimpleCallback<Boolean>(
action = action, action = action,
onSuccess = { onSuccess = {
_token.postValue(it.body) _token.postValue(it.body)
@ -52,7 +54,14 @@ class InitViewModel: ViewModel() {
}, },
onFail = { TODO("token校验失败") }, onFail = { TODO("token校验失败") },
type = object : TypeToken<ApiResponse<Boolean>>() {}.type type = object : TypeToken<ApiResponse<Boolean>>() {}.type
),jsonBody = Gson().toJson(TokenVo(token=currentToken.token,studentId = currentToken.studentId))) ),
jsonBody = Gson().toJson(
TokenVo(
token = currentToken.token,
studentId = currentToken.studentId
)
)
)
} else if (tokenList != null && tokenList.size > 1) { } else if (tokenList != null && tokenList.size > 1) {
//TODO 实现切换历史登录帐号 //TODO 实现切换历史登录帐号
Logger.i("token数量大于一,需要手动登录") Logger.i("token数量大于一,需要手动登录")

@ -80,12 +80,15 @@ class AccountViewModel(application: Application) : AndroidViewModel(application)
//已注册 //已注册
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
@ -94,6 +97,7 @@ class AccountViewModel(application: Application) : AndroidViewModel(application)
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
@ -108,6 +112,7 @@ class AccountViewModel(application: Application) : AndroidViewModel(application)
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
@ -119,8 +124,10 @@ class AccountViewModel(application: Application) : AndroidViewModel(application)
//返回登陆 //返回登陆
val backLogin = "返回$loginDesc" val backLogin = "返回$loginDesc"
//确定按钮 //确定按钮
val confirmDesc = "确定" val confirmDesc = "确定"
//显示密码提示 //显示密码提示
val title = "提示信息" val title = "提示信息"
val passwordTip = "密码会在点击${regBtnDesc}以后,在后台自动生成,请留意系统提示。" val passwordTip = "密码会在点击${regBtnDesc}以后,在后台自动生成,请留意系统提示。"
@ -178,12 +185,14 @@ class AccountViewModel(application: Application) : AndroidViewModel(application)
HttpClient.get( HttpClient.get(
url, SimpleCallback<Boolean>( url, SimpleCallback<Boolean>(
action = "${studentIdDesc}重复检测", action = "${studentIdDesc}重复检测",
onSuccess = { _isRepeat.postValue(it.body) onSuccess = {
_isRepeat.postValue(it.body)
_isValidForm.postValue(_isValidName.value == true && it.body == false) _isValidForm.postValue(_isValidName.value == true && it.body == false)
}, },
onFail = { _snackBarMsg.postValue(it) }, onFail = { _snackBarMsg.postValue(it) },
type = object : TypeToken<ApiResponse<Boolean>>() {}.type) type = object : TypeToken<ApiResponse<Boolean>>() {}.type
, mapOf("studentId" to "${_studentId.value}")) ), mapOf("studentId" to "${_studentId.value}")
)
} }
} }
} else { } else {
@ -236,7 +245,8 @@ class AccountViewModel(application: Application) : AndroidViewModel(application)
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
} }
@ -249,12 +259,27 @@ class AccountViewModel(application: Application) : AndroidViewModel(application)
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(
url, SimpleCallback<UserResDto>(
action = regBtnDesc, action = regBtnDesc,
onSuccess = { _dialogMsg.postValue(DialogMessage(message = it.message,userResDto = it.body)) }, onSuccess = {
_dialogMsg.postValue(
DialogMessage(
message = it.message,
userResDto = it.body
)
)
},
onFail = { _snackBarMsg.postValue(it) }, onFail = { _snackBarMsg.postValue(it) },
type = object : TypeToken<ApiResponse<UserResDto>>() {}.type), type = object : TypeToken<ApiResponse<UserResDto>>() {}.type
jsonBody = Gson().toJson(UserVo(studentId = "${studentId.value}",name = "${name.value}"))) ),
jsonBody = Gson().toJson(
UserVo(
studentId = "${studentId.value}",
name = "${name.value}"
)
)
)
resetForm() resetForm()
} else { } else {
Logger.wtf("表单校验失败,无法$regBtnDesc!!!") Logger.wtf("表单校验失败,无法$regBtnDesc!!!")
@ -290,7 +315,9 @@ class AccountViewModel(application: Application) : AndroidViewModel(application)
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(
url,
SimpleCallback<Token>(
action = loginDesc, action = loginDesc,
onSuccess = { onSuccess = {
_snackBarMsg.postValue(it.message) _snackBarMsg.postValue(it.message)
@ -309,12 +336,19 @@ class AccountViewModel(application: Application) : AndroidViewModel(application)
}, },
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(
UserLoginVo(
studentId = "${studentId.value}",
password = "${password.value}",
device = "${Build.MANUFACTURER} ${Build.MODEL}"
)
)
)
} else { } else {
Logger.wtf("表单校验失败,无法$loginDesc!!!") Logger.wtf("表单校验失败,无法$loginDesc!!!")
} }
} }
} }

@ -46,18 +46,22 @@ class AccountActivity: ComponentActivity() {
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)
} }
@ -67,10 +71,13 @@ class AccountActivity: ComponentActivity() {
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)
} }
} }
@ -78,21 +85,29 @@ class AccountActivity: ComponentActivity() {
} }
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,10 +126,12 @@ class AccountActivity: ComponentActivity() {
* @param Action 表单操作区域 * @param Action 表单操作区域
*/ */
@Composable @Composable
private fun Account(accountViewModel: AccountViewModel = viewModel(), private fun Account(
accountViewModel: AccountViewModel = viewModel(),
scaffoldState: ScaffoldState, scaffoldState: ScaffoldState,
route: AccountRoute, route: AccountRoute,
Action: @Composable (isValidForm:Boolean,accountViewModel: AccountViewModel) -> Unit){ Action: @Composable (isValidForm: Boolean, accountViewModel: AccountViewModel) -> Unit
) {
accountViewModel.route = route accountViewModel.route = route
Row( Row(
horizontalArrangement = Arrangement.Center, horizontalArrangement = Arrangement.Center,
@ -189,7 +206,10 @@ 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
) )
@ -260,18 +280,25 @@ private fun RegisterDialog(accountViewModel: AccountViewModel = viewModel()){
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(
horizontalArrangement = Arrangement.Center, modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.padding(bottom = 10.dp)) { .padding(bottom = 10.dp)
OutlinedButton(onClick = { accountViewModel.resetDialogMsg() }, ) {
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(
onClick = {
context.startActivity(Intent(context, AccountActivity::class.java)) 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]
@ -305,18 +333,22 @@ private fun Name(name:String, accountViewModel: AccountViewModel = viewModel()){
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(
value = name,
onValueChange = { accountViewModel.onNameChange(it) }, onValueChange = { accountViewModel.onNameChange(it) },
label = { Text(text = accountViewModel.nameDesc) }, label = { Text(text = accountViewModel.nameDesc) },
placeholder = { Text(text = accountViewModel.namePlaceholder) }, 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
)
} }
} }
@ -333,7 +365,8 @@ private fun Password(accountViewModel: AccountViewModel= viewModel()){
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(
value = password,
visualTransformation = PasswordVisualTransformation(), visualTransformation = PasswordVisualTransformation(),
onValueChange = { accountViewModel.onPasswordChange(it) }, onValueChange = { accountViewModel.onPasswordChange(it) },
label = { Text(text = accountViewModel.passwordDesc) }, label = { Text(text = accountViewModel.passwordDesc) },
@ -341,11 +374,17 @@ private fun Password(accountViewModel: AccountViewModel= viewModel()){
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
)
} }
} }
} }
@ -374,7 +413,8 @@ fun DefaultPreview() {
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()

@ -31,10 +31,11 @@ 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 associationName: String, val activityName: String,
val activityTime: Date, val activityLocation: String, val activityTime: Date, val activityLocation: String,
val activityDesc:String) val activityDesc: String
)
/** /**
@ -94,7 +95,14 @@ 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
)
/** /**
* 活动相册数据状态管理 * 活动相册数据状态管理
@ -119,12 +127,16 @@ class ActivityPhotoViewModel:ScrollList<ActivityPhotoVo>(){
viewModelScope.launch { viewModelScope.launch {
_data.value?.apply { _data.value?.apply {
repeat(initSize) { repeat(initSize) {
add(ActivityPhotoVo(name=randomChinese(3), add(
ActivityPhotoVo(
name = randomChinese(3),
size = randomNum(3).toLong(), size = randomNum(3).toLong(),
url = "", url = "",
md5 = "", md5 = "",
createTime = randomDateTime(), createTime = randomDateTime(),
studentId = "")) studentId = ""
)
)
} }
} }
} }
@ -143,12 +155,16 @@ class ActivityPhotoViewModel:ScrollList<ActivityPhotoVo>(){
val list = mutableListOf<ActivityPhotoVo>() val list = mutableListOf<ActivityPhotoVo>()
list.addAll(this) list.addAll(this)
repeat(initSize) { repeat(initSize) {
add(ActivityPhotoVo(name=randomChinese(3), add(
ActivityPhotoVo(
name = randomChinese(3),
size = randomNum(3).toLong(), size = randomNum(3).toLong(),
url = "", url = "",
md5 = "", md5 = "",
createTime = randomDateTime(), createTime = randomDateTime(),
studentId = "")) studentId = ""
)
)
} }
_data.postValue(list) _data.postValue(list)
callback("成功加载更多相册") callback("成功加载更多相册")
@ -159,7 +175,10 @@ 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
@ -181,7 +200,12 @@ class ActivityMemberViewModel:ScrollList<ActivityMemberVo>(){
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
)
} }
} }
} }
@ -201,7 +225,12 @@ class ActivityMemberViewModel:ScrollList<ActivityMemberVo>(){
} }
_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("成功加载更多活动参与者")
} }
} }
@ -255,7 +284,14 @@ class BBSViewModel:ScrollList<BBSVo>(), SendInterface {
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)
)
)
} }
} }
} }
@ -273,7 +309,14 @@ class BBSViewModel:ScrollList<BBSVo>(), SendInterface {
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("成功加载更多评论")

@ -25,7 +25,6 @@ class AssociationViewModel:ViewModel(),TopMenuInterface<AssociationMenu>{
val expanded: LiveData<Boolean> = _expanded val expanded: LiveData<Boolean> = _expanded
/** /**
* 切换下拉菜单状态 * 切换下拉菜单状态
* *
@ -112,7 +111,6 @@ class MemberViewModel:ScrollList<MemberVo>(){
} }
data class OngoingActVo(val name: String) data class OngoingActVo(val name: String)
class OngoingActViewModel : ViewModel() { class OngoingActViewModel : ViewModel() {

@ -16,6 +16,7 @@ import kotlin.random.Random
enum class ExamActivityType(val menuName: String) { enum class ExamActivityType(val menuName: String) {
//入团题库 //入团题库
SET_EXAM("入团题库"), SET_EXAM("入团题库"),
//入团申请表 //入团申请表
JOIN_Association("入团申请表") JOIN_Association("入团申请表")
} }
@ -27,6 +28,7 @@ enum class ExamActivityType(val menuName:String){
enum class ExamType(val type: String) { enum class ExamType(val type: String) {
//选择题 //选择题
CQ("选择题"), CQ("选择题"),
//开放题 //开放题
OQ("开放题") OQ("开放题")
} }
@ -56,15 +58,14 @@ data class OpenQuestionsVo(
* @property rightAnswer 正确答案 * @property rightAnswer 正确答案
* @property question 问题 * @property question 问题
*/ */
data class ChoiceQuestionVo(override val examType: ExamType = ExamType.CQ, data class ChoiceQuestionVo(
override val examType: ExamType = ExamType.CQ,
val answers: List<StringForm>, val answers: List<StringForm>,
val rightAnswer: Int, val rightAnswer: Int,
override val question: StringForm override val question: StringForm
) : Exam() ) : Exam()
/** /**
* 问题长度 * 问题长度
*/ */
@ -113,7 +114,8 @@ 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)
} }
@ -127,7 +129,13 @@ class ExamViewModel:ScrollList<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
) )
@ -181,12 +189,30 @@ class ExamViewModel:ScrollList<Exam>() {
_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(
OpenQuestionsVo(
question = StringForm(
formDesc = "问题",
textLength = QUESTION_TEXT_LENGTH,
value = "这是一道开放题:$size"
)
)
)
} else { } 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)
) )
) )

@ -34,7 +34,6 @@ import com.gyf.csams.util.randomChinese
import com.orhanobut.logger.Logger import com.orhanobut.logger.Logger
/** /**
* 社团界面 * 社团界面
* *
@ -44,11 +43,12 @@ class AssociationActivity: ComponentActivity() {
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(AssociationMenu.startMenu) val currentMenuName: AssociationMenu by model.currentMenu.observeAsState(
AssociationMenu.startMenu
)
val intent = Intent(context, ExamActivity::class.java) val intent = Intent(context, ExamActivity::class.java)
val expanded by model.expanded.observeAsState(false) val expanded by model.expanded.observeAsState(false)
@ -59,7 +59,8 @@ class AssociationActivity: ComponentActivity() {
menuNames = AssociationMenu.values(), menuNames = AssociationMenu.values(),
iconMenu = { model.switchType() }) { iconMenu = { model.switchType() }) {
Row { Row {
DropdownMenu(expanded = expanded, DropdownMenu(
expanded = expanded,
onDismissRequest = { /*TODO*/ }, onDismissRequest = { /*TODO*/ },
// offset = DpOffset.Zero.copy(x=50.dp), // offset = DpOffset.Zero.copy(x=50.dp),
properties = PopupProperties() properties = PopupProperties()
@ -69,57 +70,86 @@ class AssociationActivity: ComponentActivity() {
}) { }) {
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 = { DropdownMenuItem(onClick = {
intent.apply { intent.apply {
putExtra(ExamActivityType::name.name, ExamActivityType.SET_EXAM) putExtra(
ExamActivityType::name.name,
ExamActivityType.SET_EXAM
)
} }
context.startActivity(intent) context.startActivity(intent)
model.close() model.close()
}) { }) {
Row(verticalAlignment = Alignment.CenterVertically) { Row(verticalAlignment = Alignment.CenterVertically) {
Text(text = "设置题库") Text(text = "设置题库")
Icon(painter = painterResource(id = R.drawable.ic_editor), contentDescription = null) Icon(
painter = painterResource(id = R.drawable.ic_editor),
contentDescription = null
)
} }
} }
DropdownMenuItem(onClick = { DropdownMenuItem(onClick = {
context.startActivity(Intent(context,ReNameActivity::class.java)) context.startActivity(
Intent(
context,
ReNameActivity::class.java
)
)
model.close() model.close()
}) { }) {
Row(verticalAlignment = Alignment.CenterVertically) { Row(verticalAlignment = Alignment.CenterVertically) {
Text(text = "社团命名") Text(text = "社团命名")
Icon(painter = painterResource(id = R.drawable.ic_exchange_rate), contentDescription = null) Icon(
painter = painterResource(id = R.drawable.ic_exchange_rate),
contentDescription = null
)
} }
} }
DropdownMenuItem(onClick = { DropdownMenuItem(onClick = {
intent.apply { intent.apply {
putExtra(ExamActivityType::name.name, ExamActivityType.JOIN_Association) putExtra(
ExamActivityType::name.name,
ExamActivityType.JOIN_Association
)
} }
context.startActivity(intent) context.startActivity(intent)
model.close() model.close()
}) { }) {
Row(verticalAlignment = Alignment.CenterVertically) { Row(verticalAlignment = Alignment.CenterVertically) {
Text(text = "申请入团") Text(text = "申请入团")
Icon(painter = painterResource(id = R.drawable.ic_add_account), contentDescription = null) Icon(
painter = painterResource(id = R.drawable.ic_add_account),
contentDescription = null
)
} }
} }
DropdownMenuItem(onClick = { DropdownMenuItem(onClick = {
model.close() model.close()
}) { }) {
Row(verticalAlignment = Alignment.CenterVertically) { Row(verticalAlignment = Alignment.CenterVertically) {
Icon(painter = painterResource(id = R.drawable.ic_arrow_up), contentDescription = null, Icon(
painter = painterResource(id = R.drawable.ic_arrow_up),
contentDescription = null,
modifier = Modifier modifier = Modifier
.height(30.dp) .height(30.dp)
.fillMaxWidth()) .fillMaxWidth()
)
} }
} }
} }
} }
} }
NavHost(navController = nav, startDestination = AssociationMenu.startMenu.name) { NavHost(
navController = nav,
startDestination = AssociationMenu.startMenu.name
) {
composable(AssociationMenu.Member.name) { composable(AssociationMenu.Member.name) {
model.clickMenu(AssociationMenu.Member) model.clickMenu(AssociationMenu.Member)
Member() Member()
@ -152,12 +182,16 @@ class AssociationActivity: ComponentActivity() {
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(
modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.weight(searchWeight)) .weight(searchWeight)
MemberList(modifier = Modifier )
MemberList(
modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.weight(1 - searchWeight)) .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(
modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.weight(0.5F),verticalAlignment = Alignment.CenterVertically) { .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,7 +240,11 @@ class AssociationActivity: ComponentActivity() {
* *
*/ */
@Composable @Composable
private fun MemberList(modifier: Modifier=Modifier, model: MemberViewModel=viewModel(), scaffoldModel: ScaffoldModel= viewModel()){ private fun MemberList(
modifier: Modifier = Modifier,
model: MemberViewModel = viewModel(),
scaffoldModel: ScaffoldModel = viewModel()
) {
val list: MutableList<MemberVo>? by model.memberList.observeAsState() val list: MutableList<MemberVo>? by model.memberList.observeAsState()
val listState = rememberLazyListState() val listState = rememberLazyListState()
LazyColumn(state = listState, modifier = modifier) { LazyColumn(state = listState, modifier = modifier) {
@ -218,11 +269,19 @@ class AssociationActivity: ComponentActivity() {
} }
} }
item { item {
Row(horizontalArrangement = Arrangement.Center,modifier = Modifier.fillMaxWidth()) { Row(
IconButton(onClick = { model.loadMore{ horizontalArrangement = Arrangement.Center,
modifier = Modifier.fillMaxWidth()
) {
IconButton(onClick = {
model.loadMore {
scaffoldModel.update(message = it) scaffoldModel.update(message = it)
} }) { }
Icon(painter = painterResource(id = R.drawable.ic_arrow_down), contentDescription = null) }) {
Icon(
painter = painterResource(id = R.drawable.ic_arrow_down),
contentDescription = null
)
} }
} }
@ -241,9 +300,11 @@ class AssociationActivity: ComponentActivity() {
}) { }) {
val nameW = 0.1F val nameW = 0.1F
val cardW = 0.66F * 0.4F val cardW = 0.66F * 0.4F
Name(modifier = Modifier Name(
modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.weight(nameW)) .weight(nameW)
)
DescCard( DescCard(
modifier = Modifier modifier = Modifier
.weight(cardW) .weight(cardW)
@ -273,10 +334,12 @@ class AssociationActivity: ComponentActivity() {
) )
Column { Column {
Spacer(modifier = Modifier.weight(1.7F / 3)) Spacer(modifier = Modifier.weight(1.7F / 3))
Row(modifier = Modifier Row(
modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.weight(1F / 3), .weight(1F / 3),
horizontalArrangement = Arrangement.Center) { horizontalArrangement = Arrangement.Center
) {
Text(text = "社团名字") Text(text = "社团名字")
} }
Spacer(modifier = Modifier.weight(0.3F / 3)) Spacer(modifier = Modifier.weight(0.3F / 3))
@ -294,7 +357,8 @@ class AssociationActivity: ComponentActivity() {
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
) )
} }
@ -310,10 +374,15 @@ class AssociationActivity: ComponentActivity() {
@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
)
} }
} }
@ -323,15 +392,24 @@ class AssociationActivity: ComponentActivity() {
*/ */
@Composable @Composable
private fun AssociationList() { private fun AssociationList() {
MainFrame(background = { Background(image = BackgroundImage.AssociationMain,alpha = 07F) }) { MainFrame(background = {
Background(
image = BackgroundImage.AssociationMain,
alpha = 07F
)
}) {
val onGoWeight = 0.3F val onGoWeight = 0.3F
OngoingActivity(modifier = Modifier OngoingActivity(
modifier = Modifier
.weight(onGoWeight) .weight(onGoWeight)
.fillMaxWidth()) .fillMaxWidth()
HistoryActivityList(modifier = Modifier )
HistoryActivityList(
modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.weight(1 - onGoWeight) .weight(1 - onGoWeight)
.border(width = 1.dp, color = MaterialTheme.colors.onBackground)) .border(width = 1.dp, color = MaterialTheme.colors.onBackground)
)
} }
} }
@ -340,7 +418,10 @@ class AssociationActivity: ComponentActivity() {
* *
*/ */
@Composable @Composable
private fun OngoingActivity(modifier: Modifier=Modifier,model:OngoingActViewModel= viewModel()){ private fun OngoingActivity(
modifier: Modifier = Modifier,
model: OngoingActViewModel = viewModel()
) {
val context = LocalContext.current 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 = {
@ -361,7 +442,11 @@ class AssociationActivity: ComponentActivity() {
* @param modifier * @param modifier
*/ */
@Composable @Composable
private fun HistoryActivityList(modifier: Modifier,model:HistoryActViewModel= viewModel(),scaffoldModel: ScaffoldModel= viewModel()){ private fun HistoryActivityList(
modifier: Modifier,
model: HistoryActViewModel = viewModel(),
scaffoldModel: ScaffoldModel = viewModel()
) {
val listState = rememberLazyListState() 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) {
@ -394,12 +479,16 @@ class AssociationActivity: ComponentActivity() {
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)
} }

@ -23,7 +23,6 @@ import com.gyf.csams.association.model.*
import com.gyf.csams.uikit.* import com.gyf.csams.uikit.*
/** /**
* 题库管理 * 题库管理
* *
@ -50,8 +49,6 @@ class ExamActivity : ComponentActivity() {
} }
/** /**
* 底部按钮 * 底部按钮
* *
@ -191,10 +188,12 @@ class ExamActivity : ComponentActivity() {
* *
*/ */
@Composable @Composable
private fun ActionButton(modifier: Modifier = Modifier, isAdd: Boolean, private fun ActionButton(
modifier: Modifier = Modifier, isAdd: Boolean,
model: ExamViewModel = viewModel(), model: ExamViewModel = viewModel(),
scaffoldModel: ScaffoldModel = viewModel(), scaffoldModel: ScaffoldModel = viewModel(),
exam: Exam) { 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(
@ -204,7 +203,10 @@ class ExamActivity : ComponentActivity() {
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 {
@ -215,7 +217,10 @@ class ExamActivity : ComponentActivity() {
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)
} }
} }
@ -246,7 +251,9 @@ class ExamActivity : ComponentActivity() {
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
) )
@ -279,7 +286,9 @@ class ExamActivity : ComponentActivity() {
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(
modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.weight(1F / ANSWER_SIZE)) { .weight(1F / ANSWER_SIZE)
) {
val answerIndex: Int = indexOf(it) val answerIndex: Int = indexOf(it)
val click = { val click = {
model.update( model.update(

@ -24,8 +24,7 @@ class ReNameActivity: ComponentActivity() {
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
@ -94,7 +93,11 @@ 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

@ -48,9 +48,13 @@ class RegAssociationActivity: ComponentActivity(){
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(
BackgroundImage.RegAssociation,
alpha = 0.5F
)
}) {
Spacer( Spacer(
modifier = Modifier modifier = Modifier
.weight(0.1F) .weight(0.1F)
@ -91,7 +95,8 @@ class RegAssociationActivity: ComponentActivity(){
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 =
rememberLauncherForActivityResult(contract = ActivityResultContracts.StartActivityForResult()) {
when (it.resultCode) { when (it.resultCode) {
Activity.RESULT_OK -> { Activity.RESULT_OK -> {
Logger.i("uri=${it.data?.data}") Logger.i("uri=${it.data?.data}")
@ -118,14 +123,15 @@ class RegAssociationActivity: ComponentActivity(){
} }
val context = LocalContext.current val context = LocalContext.current
Box(contentAlignment = Alignment.Center, modifier = modifier) { Box(contentAlignment = Alignment.Center, modifier = modifier) {
Row(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 = {
@ -149,12 +155,21 @@ class RegAssociationActivity: ComponentActivity(){
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
)
} }
} }
@ -174,7 +189,11 @@ class RegAssociationActivity: ComponentActivity(){
} }
@Composable @Composable
private fun BottomButton(modifier: Modifier=Modifier,scaffoldModel: ScaffoldModel= viewModel(),model:RegAssociationViewModel= viewModel()){ private fun BottomButton(
modifier: Modifier = Modifier,
scaffoldModel: ScaffoldModel = viewModel(),
model: RegAssociationViewModel = viewModel()
) {
val context = LocalContext.current as RegAssociationActivity val context = LocalContext.current as RegAssociationActivity
Row(modifier = modifier, horizontalArrangement = Arrangement.Center) { Row(modifier = modifier, horizontalArrangement = Arrangement.Center) {
OutlinedButton(onClick = { OutlinedButton(onClick = {

@ -29,7 +29,6 @@ class MarqueeViewModel:ViewModel() {
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 {
@ -49,7 +48,12 @@ 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)
@ -106,15 +110,6 @@ 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)
}
} }
/** /**
@ -136,7 +131,6 @@ class ListViewModel: ScrollList<AssociationDto>() {
val searchDesc = "搜索" val searchDesc = "搜索"
/** /**
* TODO 社团检索 * TODO 社团检索
* *
@ -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}"))
} }
@ -203,7 +198,13 @@ 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
)
/** /**
* 个人中心 * 个人中心
@ -224,11 +225,13 @@ class CenterViewModel:ViewModel(){
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(
modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.weight(0.7F) .weight(0.7F)
.border(width = 1.dp, color = MaterialTheme.colors.background), .border(width = 1.dp, color = MaterialTheme.colors.background),
horizontalArrangement = Arrangement.SpaceBetween) { 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()
Column(
modifier = Modifier
.fillMaxSize()
.padding(horizontal = 15.dp),
verticalArrangement = Arrangement.SpaceEvenly
) {
MessageBoard() MessageBoard()
Spacer(modifier = Modifier.height(10.dp))
ClubActivitiesTitle() ClubActivitiesTitle()
Spacer(modifier = Modifier.height(10.dp)) }
} }
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
) { ) {
@ -265,7 +269,36 @@ 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
@ -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)
} }
/** /**
@ -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(
modifier = Modifier
.fillMaxSize() .fillMaxSize()
.padding(horizontal = 10.dp)) { .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,7 +708,7 @@ 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(
@ -691,15 +734,22 @@ fun MyBottomAppBarPreview() {
} }
} }
arr.forEach { arr.forEach {
Column(modifier = Modifier Column(
modifier = Modifier
.weight(1F / arr.size) .weight(1F / arr.size)
.border(width = 1.dp, color = MaterialTheme.colors.background)) { .border(width = 1.dp, color = MaterialTheme.colors.background)
Row(modifier = Modifier.fillMaxWidth(),horizontalArrangement = Arrangement.Center) { ) {
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.Center
) {
Text(text = "$it", style = MaterialTheme.typography.h5) 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)
} }

@ -28,10 +28,14 @@ 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(
formDesc = formDesc,
textLength = textLength
) {
_formValue.value = value _formValue.value = value
} }
@ -48,7 +52,12 @@ open class StringForm(formDesc: String, val textLength: Int) : FormName<String>(
} }
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
@ -62,7 +71,8 @@ class ScaffoldModel:ViewModel(){
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)
} }
} }
} }
@ -75,6 +85,7 @@ abstract class ScrollList<T>:ViewModel(){
//加载列表 //加载列表
abstract fun load() abstract fun load()
//加载更多数据 //加载更多数据
abstract fun loadMore(callback: (message: String) -> Unit) abstract fun loadMore(callback: (message: String) -> Unit)
} }

@ -66,14 +66,21 @@ class ChoiceQuestionVoDeserializer: JsonDeserializer<ChoiceQuestionVo> {
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> =
gson.fromJson(root.get("answers"), object : TypeToken<List<String>>() {}.type)
if (answers.size != ANSWER_SIZE) { 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 {
@ -100,10 +107,14 @@ class ExamDeserializer:JsonDeserializer<Exam>{
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) )
ExamType.OQ -> gson.fromJson(
json,
object : TypeToken<OpenQuestionsVo>() {}.type
)
null -> throw NullPointerException("无法识别题目类型!") null -> throw NullPointerException("无法识别题目类型!")
} }

@ -96,10 +96,12 @@ 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 action: String,
private val onSuccess: (res: ApiResponse<T>) -> Unit, private val onSuccess: (res: ApiResponse<T>) -> Unit,
private val onFail: (error: String) -> Unit, private val onFail: (error: String) -> Unit,
private val type: Type):Callback{ private val type: Type
) : Callback {
companion object { companion object {
val gson: Gson = GsonBuilder() val gson: Gson = GsonBuilder()

@ -31,7 +31,11 @@ val CHINESE_UNICODE_AREA=0X4e00..0X9fa5
* @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"

@ -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
)
/** /**
* 令牌传输 * 令牌传输

@ -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