前台AndroidManifest.xml 删除部分Activity exported配置

继承登录模块到lib
移动动画文本组件到lib
ScrollList.kt->ScrollViewModel.kt
Api移动到lib
master
pan 4 years ago
parent e7f07a3415
commit f15fd6588e
  1. 7
      background/src/main/AndroidManifest.xml
  2. 14
      background/src/main/java/com/gyf/csams/InitActivity.kt
  3. 32
      background/src/main/java/com/gyf/csams/account/model/LoginViewModel.kt
  4. 38
      background/src/main/java/com/gyf/csams/account/ui/LoginActivity.kt
  5. 7
      background/src/main/java/com/gyf/csams/main/model/AssociationManagementViewModel.kt
  6. 2
      background/src/main/java/com/gyf/csams/main/model/CheckActViewModel.kt
  7. 2
      background/src/main/java/com/gyf/csams/main/model/CheckQualityReportViewModel.kt
  8. 4
      background/src/main/java/com/gyf/csams/main/model/ManagerActViewModel.kt
  9. 4
      background/src/main/java/com/gyf/csams/main/model/RenameViewModel.kt
  10. 2
      background/src/main/java/com/gyf/csams/main/ui/AssociationManagementActivity.kt
  11. 1
      background/src/main/java/com/gyf/csams/main/ui/MainActivity.kt
  12. 4
      background/src/main/java/com/gyf/csams/uikit/Table.kt
  13. 40
      foreground/src/main/AndroidManifest.xml
  14. 63
      foreground/src/main/java/com/gyf/csams/InitActivity.kt
  15. 142
      foreground/src/main/java/com/gyf/csams/account/model/AccountViewModel.kt
  16. 28
      foreground/src/main/java/com/gyf/csams/account/ui/AccountActivity.kt
  17. 13
      foreground/src/main/java/com/gyf/csams/activity/model/ActivityDetailViewModel.kt
  18. 2
      foreground/src/main/java/com/gyf/csams/activity/model/ApplyActViewModel.kt
  19. 9
      foreground/src/main/java/com/gyf/csams/association/model/AssociationViewModel.kt
  20. 7
      foreground/src/main/java/com/gyf/csams/association/model/ExamViewModel.kt
  21. 8
      foreground/src/main/java/com/gyf/csams/association/model/RegAssociationViewModel.kt
  22. 2
      foreground/src/main/java/com/gyf/csams/association/model/RenameViewModel.kt
  23. 9
      foreground/src/main/java/com/gyf/csams/main/model/MainViewModel.kt
  24. 2
      foreground/src/main/java/com/gyf/csams/main/ui/MainActivity.kt
  25. 18
      foreground/src/main/java/com/gyf/csams/message/model/SysMessageViewModel.kt
  26. 24
      foreground/src/main/java/com/gyf/csams/uikit/BaseView.kt
  27. 4
      foreground/src/main/java/com/gyf/csams/uikit/ViewModel.kt
  28. 34
      lib/src/main/java/com/gyf/lib/ScrollList.kt
  29. 80
      lib/src/main/java/com/gyf/lib/model/AbstractLoginViewModel.kt
  30. 5
      lib/src/main/java/com/gyf/lib/model/ApplyViewModel.kt
  31. 15
      lib/src/main/java/com/gyf/lib/model/InitViewModel.kt
  32. 19
      lib/src/main/java/com/gyf/lib/model/ScrollViewModel.kt
  33. 15
      lib/src/main/java/com/gyf/lib/service/MessageService.kt
  34. 9
      lib/src/main/java/com/gyf/lib/service/NotificationWorker.kt
  35. 66
      lib/src/main/java/com/gyf/lib/uikit/AbstractInitActivity.kt
  36. 33
      lib/src/main/java/com/gyf/lib/uikit/AnimationText.kt
  37. 24
      lib/src/main/java/com/gyf/lib/util/Api.kt
  38. 4
      lib/src/main/java/com/gyf/lib/util/ContextUtil.kt
  39. 1
      lib/src/main/res/values-en/strings.xml
  40. 1
      lib/src/main/res/values-zh/strings.xml
  41. 1
      lib/src/main/res/values/strings.xml

@ -2,6 +2,9 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.gyf.csams">
<!--访问网络-->
<uses-permission android:name="android.permission.INTERNET" />
<application
android:allowBackup="true"
android:fullBackupOnly="true"
@ -12,7 +15,7 @@
android:theme="@style/Theme.CSAMS"
android:name=".MainApplication">
<activity
android:name=".account.ui.LoginActivity"
android:name=".InitActivity"
android:exported="true"
android:label="${background_app_name}"
android:theme="@style/Theme.CSAMS.NoActionBar">
@ -22,7 +25,7 @@
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name=".account.ui.LoginActivity" />
<activity android:name=".main.ui.MainActivity" />
<activity android:name=".main.ui.DepartmentActivity" />
<activity android:name=".main.ui.ManagementOfficerActivity" />

@ -0,0 +1,14 @@
package com.gyf.csams
import android.app.Activity
import com.gyf.csams.account.ui.LoginActivity
import com.gyf.csams.main.ui.MainActivity
import com.gyf.lib.uikit.AbstractInitActivity
import com.gyf.lib.util.AccountApi
class InitActivity : AbstractInitActivity() {
override val main: Class<out Activity> = MainActivity::class.java
override val login: Class<out Activity> = LoginActivity::class.java
override val api: AccountApi = AccountApi.BackgroundToken
}

@ -1,11 +1,31 @@
package com.gyf.csams.account.model
import androidx.lifecycle.ViewModel
import com.gyf.lib.uikit.StringForm
import android.app.Application
import android.os.Build
import com.gyf.lib.model.AbstractLoginViewModel
import com.gyf.lib.uikit.FormStatus
import com.gyf.lib.uikit.ValidStringForm
import com.gyf.lib.util.AccountApi
class LoginViewModel : ViewModel() {
val user = StringForm(formDesc = "管理帐号", textLength = 8)
val password = StringForm(formDesc = "管理密码", textLength = 8)
data class ManagerVo(val account: String, val password: String, val device: String)
val login = "登录"
class LoginViewModel(application: Application) : AbstractLoginViewModel(application) {
override val id = ValidStringForm(formDesc = "管理帐号", textLength = 8)
override val password: ValidStringForm = ValidStringForm(formDesc = "管理密码", textLength = 8)
override val api: AccountApi = AccountApi.BackgroundLogin
override fun checkForm(): Boolean {
return id.statusForm.value == FormStatus.Valid && password.statusForm.value == FormStatus.Valid
}
override fun loginParam(): Any {
val account = "${id.formValue.value}"
val password = "${password.formValue.value}"
return ManagerVo(
account = account,
password = password,
device = "${Build.MANUFACTURER} ${Build.MODEL}"
)
}
}

@ -10,17 +10,19 @@ import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.material.OutlinedButton
import androidx.compose.material.Text
import androidx.compose.runtime.getValue
import androidx.compose.runtime.livedata.observeAsState
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.input.PasswordVisualTransformation
import androidx.compose.ui.unit.dp
import androidx.lifecycle.viewmodel.compose.viewModel
import com.gyf.csams.R
import com.gyf.csams.account.model.LoginViewModel
import com.gyf.csams.main.ui.MainActivity
import com.gyf.lib.uikit.BaseTextField
import com.gyf.lib.uikit.Body
import com.gyf.lib.uikit.MainBoxFrame
import com.gyf.lib.uikit.*
/**
* 登录
@ -45,16 +47,34 @@ class LoginActivity : ComponentActivity() {
horizontalAlignment = Alignment.CenterHorizontally
) {
val model: LoginViewModel = viewModel()
BaseTextField(form = model.user)
val scaffoldModel: ScaffoldModel = viewModel()
val idStatus by model.id.statusForm.observeAsState()
val passwordStatus by model.password.statusForm.observeAsState()
BaseTextField(form = model.id)
BaseTextField(
form = model.password,
visualTransformation = PasswordVisualTransformation()
)
OutlinedButton(onClick = {
context.startActivity(Intent(context, MainActivity::class.java))
context.finish()
}) {
Text(text = model.login)
OutlinedButton(
onClick = {
model.login {
scaffoldModel.update(message = it)
}
},
enabled = idStatus == FormStatus.Valid && passwordStatus == FormStatus.Valid
) {
Text(text = stringResource(id = R.string.login_btn))
}
val finishLogin: Boolean? by model.finishLogin.observeAsState()
if (finishLogin == true) {
startActivity(
Intent(
LocalContext.current,
MainActivity::class.java
)
)
finish()
}
}
}

@ -1,7 +1,8 @@
package com.gyf.csams.main.model
import android.app.Application
import androidx.lifecycle.viewModelScope
import com.gyf.lib.ScrollList
import com.gyf.lib.model.ScrollViewModel
import com.gyf.lib.util.randomChinese
import kotlinx.coroutines.launch
@ -48,7 +49,9 @@ data class AssociationVo(
* 数据状态管理
*
*/
class AssociationManagementViewModel : ScrollList<AssociationVo>() {
class AssociationManagementViewModel(application: Application) : ScrollViewModel<AssociationVo>(
application
) {
override val initSize: Int = 10
init {

@ -2,7 +2,7 @@ package com.gyf.csams.main.model
import android.app.Application
import androidx.lifecycle.viewModelScope
import com.gyf.ApplyViewModel
import com.gyf.lib.model.ApplyViewModel
import com.gyf.lib.util.format
import com.gyf.lib.util.randomChinese
import com.gyf.lib.util.randomDateTime

@ -3,7 +3,7 @@ package com.gyf.csams.main.model
import android.app.Application
import androidx.annotation.IntRange
import androidx.lifecycle.viewModelScope
import com.gyf.ApplyViewModel
import com.gyf.lib.model.ApplyViewModel
import com.gyf.lib.util.randomChinese
import kotlinx.coroutines.launch

@ -2,7 +2,7 @@ package com.gyf.csams.main.model
import android.app.Application
import androidx.annotation.IntRange
import com.gyf.lib.ScrollListW
import com.gyf.lib.model.ScrollViewModel
import com.gyf.lib.util.randomChinese
import com.gyf.lib.util.randomDateTime
import com.gyf.lib.util.randomNum
@ -20,7 +20,7 @@ data class ActivityVo(
*
* @param application
*/
class ManagerActViewModel(application: Application) : ScrollListW<ActivityVo>(application) {
class ManagerActViewModel(application: Application) : ScrollViewModel<ActivityVo>(application) {
override val initSize: Int = 10
init {

@ -3,7 +3,7 @@ package com.gyf.csams.main.model
import android.app.Application
import androidx.lifecycle.viewModelScope
import com.gyf.csams.R
import com.gyf.lib.ScrollListW
import com.gyf.lib.model.ScrollViewModel
import com.gyf.lib.uikit.StringForm
import com.gyf.lib.util.randomChinese
import com.gyf.lib.util.randomNum
@ -24,7 +24,7 @@ data class RenameVo(
val reason: String
)
class RenameViewModel(application: Application) : ScrollListW<RenameVo>(application) {
class RenameViewModel(application: Application) : ScrollViewModel<RenameVo>(application) {
val approverOrigin =
StringForm(formDesc = application.getString(R.string.approver_origin), textLength = 30)

@ -20,7 +20,6 @@ import com.gyf.csams.main.model.AssociationLevel
import com.gyf.csams.main.model.AssociationManagementViewModel
import com.gyf.lib.uikit.Body
import com.gyf.lib.uikit.MainBoxFrame
import com.gyf.lib.uikit.ScaffoldModel
/**
* 社团管理
@ -36,7 +35,6 @@ class AssociationManagementActivity : ComponentActivity() {
val model: AssociationManagementViewModel = viewModel()
val data by model.data.observeAsState()
val listState = rememberLazyListState()
val scaffoldModel: ScaffoldModel = viewModel()
LazyColumn(modifier = Modifier.fillMaxSize(), state = listState) {
data?.forEach {
it.apply {

@ -24,6 +24,7 @@ import com.gyf.lib.uikit.*
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
Body {
val model: MainViewModel = viewModel()

@ -17,7 +17,7 @@ import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import androidx.lifecycle.viewmodel.compose.viewModel
import com.gyf.lib.ScrollListW
import com.gyf.lib.model.ScrollViewModel
import com.gyf.lib.uikit.Body
import com.gyf.lib.uikit.MainColumnFrame
@ -29,7 +29,7 @@ import com.gyf.lib.uikit.MainColumnFrame
@ExperimentalComposeApi
@Composable
fun <A> TestTable(
clazz: Class<out ScrollListW<A>>,
clazz: Class<out ScrollViewModel<A>>,
@StringRes title: Int? = null,
callback: @Composable (vo: A) -> Unit
) {

@ -54,58 +54,38 @@
<!--登录界面-->
<activity
android:name=".account.ui.AccountActivity"
android:windowSoftInputMode="stateVisible|adjustResize"
android:exported="true">
</activity>
android:windowSoftInputMode="stateVisible|adjustResize" />
<!--主界面-->
<activity
android:name=".main.ui.MainActivity"
android:exported="true">
</activity>
<activity android:name=".main.ui.MainActivity" />
<!--注册社团界面-->
<activity android:name=".association.ui.RegAssociationActivity"
android:exported="true">
</activity>
<activity android:name=".association.ui.RegAssociationActivity" />
<!--社团主界面-->
<activity
android:name=".association.ui.AssociationActivity"
android:exported="true" />
<activity android:name=".association.ui.AssociationActivity" />
<!--社团重命名主界面-->
<activity
android:name=".association.ui.ReNameActivity"
android:exported="true" />
<activity android:name=".association.ui.ReNameActivity" />
<!--题库界面-->
<activity
android:name=".association.ui.ExamActivity"
android:exported="true" />
<activity android:name=".association.ui.ExamActivity" />
<!--活动详情-->
<activity
android:name=".activity.ui.ActivityDetailActivity"
android:exported="true" />
<activity android:name=".activity.ui.ActivityDetailActivity" />
<!--申请活动-->
<activity
android:name=".activity.ui.ApplyActActivity"
android:exported="true"
android:theme="@style/Theme.CSAMS.NoActionBar" />
<!--通知-->
<activity
android:name=".message.ui.MessageActivity"
android:exported="true" />
<activity android:name=".message.ui.MessageActivity" />
<!--系统通知-->
<activity
android:name=".message.ui.SysMessageActivity"
android:exported="true" />
<activity android:name=".message.ui.SysMessageActivity" />
<service android:name="com.gyf.lib.MessageService" />
<service android:name="com.gyf.lib.service.MessageService" />
</application>
</manifest>

@ -1,63 +1,14 @@
package com.gyf.csams
import android.content.Intent
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.runtime.getValue
import androidx.compose.runtime.livedata.observeAsState
import androidx.compose.ui.Alignment
import androidx.lifecycle.viewmodel.compose.viewModel
import android.app.Activity
import com.gyf.csams.account.ui.AccountActivity
import com.gyf.csams.main.ui.MainActivity
import com.gyf.csams.uikit.AnimationText
import com.gyf.lib.uikit.Body
import com.gyf.lib.uikit.MainBoxFrame
import com.orhanobut.logger.Logger
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import com.gyf.lib.uikit.AbstractInitActivity
import com.gyf.lib.util.AccountApi
class InitActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
Body {
MainBoxFrame(background = { /*TODO*/ }, contentAlignment = Alignment.Center) {
val initViewModel: InitViewModel = viewModel()
//检查网络
val isNetWorkWorking: Boolean? by initViewModel.isNetWorkWorking.observeAsState(
null
)
Logger.i("初始化")
when (isNetWorkWorking) {
null -> AnimationText(text = "测试服务端运行状态中。。。")
true -> init(initViewModel = initViewModel)
false -> AnimationText(text = "无法连接到服务端,请检查服务端地址${BuildConfig.SERVER_ADDRESS}是否配置正确")
}
}
}
}
}
private fun init(initViewModel: InitViewModel) {
//后台检查token
initViewModel.hasOnlyUserToken(onSuccess = {
startActivity(Intent(this, MainActivity::class.java))
}, onFail = {
startActivity(Intent(this, AccountActivity::class.java))
})
GlobalScope.launch {
delay(1000)
finish()
}
}
class InitActivity : AbstractInitActivity() {
override val main: Class<out Activity> = MainActivity::class.java
override val login: Class<out Activity> = AccountActivity::class.java
override val api: AccountApi = AccountApi.ForegroundToken
}

@ -2,20 +2,20 @@ package com.gyf.csams.account.model
import android.app.Application
import android.os.Build
import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.viewModelScope
import com.google.gson.reflect.TypeToken
import com.gyf.csams.AccountApi
import com.gyf.csams.Api
import com.gyf.csams.R
import com.gyf.csams.account.ui.AccountRoute
import com.gyf.csams.util.SimpleCallback
import com.gyf.lib.model.AbstractLoginViewModel
import com.gyf.lib.uikit.FormStatus
import com.gyf.lib.uikit.StringForm
import com.gyf.lib.uikit.ValidStringForm
import com.gyf.lib.util.*
import com.gyf.lib.util.AccountApi
import com.gyf.lib.util.Api
import com.gyf.lib.util.ApiResponse
import com.gyf.lib.util.HttpClient
import com.orhanobut.logger.Logger
import kotlinx.coroutines.Job
import kotlinx.coroutines.launch
@ -55,12 +55,14 @@ data class DialogMessage(val message: String, val userResDto: UserResDto?)
/**
* 注册表单
*/
class AccountViewModel(application: Application) : AndroidViewModel(application) {
class AccountViewModel(application: Application) : AbstractLoginViewModel(application) {
val welcomeEnd = application.getString(R.string.welcome_end)
val welcomeStart = application.getString(R.string.welcome_start)
override val api: AccountApi = AccountApi.ForegroundLogin
//学号
val studentId = object : ValidStringForm(formDesc = "学号", textLength = 8) {
override val id = object : ValidStringForm(formDesc = "学号", textLength = 8) {
override fun check() {
_formValue.value?.let {
when {
@ -80,38 +82,31 @@ class AccountViewModel(application: Application) : AndroidViewModel(application)
private var checkJob: Job? = null
//姓名
val name = object : StringForm(formDesc = "姓名", textLength = 4) {
override fun onChange(value: String) {
super.onChange(value)
val name = object : ValidStringForm(formDesc = "姓名", textLength = 4) {
override fun check() {
_statusForm.value = FormStatus.Valid
checkForm()
}
}
private val _isValidName = MutableLiveData<Boolean>()
val isValidName: LiveData<Boolean> = _isValidName
val nameFormat = "姓名不能为空"
//密码
val password = object : StringForm(formDesc = "密码", textLength = 8) {
override fun onChange(value: String) {
super.onChange(value)
override val password = object : ValidStringForm(formDesc = "密码", textLength = 8) {
override fun check() {
_formValue.value?.let {
if (it.matches(Regex("\\d{8}"))) _statusForm.value =
FormStatus.Valid else _statusForm.value = FormStatus.FormatError
}
checkForm()
}
}
private val _isValidPwd = MutableLiveData<Boolean>()
val isValidPwd: LiveData<Boolean> = _isValidPwd
val passwordFormat = "八位纯数字"
//注册按钮
private val _isValidForm = MutableLiveData<Boolean>()
val passwordFormat = "八位纯数字"
val isValidForm: LiveData<Boolean> = _isValidForm
private val _dialogMsg = MutableLiveData<DialogMessage?>()
val dialogMsg: LiveData<DialogMessage?> = _dialogMsg
val loginDesc = "登陆"
//返回登陆
val backLogin = "返回$loginDesc"
@ -127,12 +122,6 @@ class AccountViewModel(application: Application) : AndroidViewModel(application)
//转到注册
var goRegister = "转到$regBtnDesc"
/**
* 完成登录状态
*/
private val _finishLogin = MutableLiveData<Boolean>()
val finishLogin: LiveData<Boolean> = _finishLogin
lateinit var route: AccountRoute
/**
@ -146,51 +135,44 @@ class AccountViewModel(application: Application) : AndroidViewModel(application)
}
checkJob = viewModelScope.launch {
val url = Api.buildUrl(AccountApi.CheckId)
Logger.i("检测${studentId.formDesc},请求接口$url")
Logger.i("检测${id.formDesc},请求接口$url")
HttpClient.get(
url, SimpleCallback<Boolean>(
action = "${studentId.formDesc}重复检测",
action = "${id.formDesc}重复检测",
onSuccess = {
if (it.body == true) {
result.postValue(FormStatus.Repeat)
} else {
result.postValue(FormStatus.Valid)
}
checkForm()
},
onFail = { Logger.e(it) },
type = object : TypeToken<ApiResponse<Boolean>>() {}.type
), mapOf("studentId" to "${studentId.formValue.value}")
), mapOf("studentId" to "${id.formValue.value}")
)
}
}
}
/**
* 检测姓名
*
* @return
*/
private fun checkName(): Boolean {
_isValidName.value = name.formValue.value?.isNotEmpty()
return _isValidName.value == true
}
/**
* 检测密码
*
* @return
*/
private fun checkPassword(): Boolean {
_isValidPwd.value = password.formValue.value?.matches(Regex("\\d{8}"))
return _isValidPwd.value == true
override fun loginParam(): Any {
val studentId = "${id.formValue.value}"
val password = "${password.formValue.value}"
return UserLoginVo(
studentId = studentId,
password = password,
device = "${Build.MANUFACTURER} ${Build.MODEL}"
)
}
private fun checkForm(): Boolean {
override fun checkForm(): Boolean {
if (checkJob?.isActive == true) {
_isValidForm.value = false
_isValidForm.postValue(false)
} else {
_isValidForm.value =
studentId.statusForm.value == FormStatus.Valid && (if (route == AccountRoute.Register) checkName() else checkPassword())
_isValidForm.postValue(
id.statusForm.value == FormStatus.Valid && (if (route == AccountRoute.Register) name.statusForm.value == FormStatus.Valid
else password.statusForm.value == FormStatus.Valid)
)
}
return _isValidForm.value == true
}
@ -218,7 +200,7 @@ class AccountViewModel(application: Application) : AndroidViewModel(application)
type = object : TypeToken<ApiResponse<UserResDto>>() {}.type
),
jsonParam = UserVo(
studentId = "${studentId.formValue.value}",
studentId = "${id.formValue.value}",
name = "${name.formValue.value}"
)
)
@ -233,52 +215,8 @@ class AccountViewModel(application: Application) : AndroidViewModel(application)
}
private fun resetForm() {
studentId.onChange("")
name.onChange("")
}
/**
* 登录
*
*/
fun login(callback: (message: String) -> Unit) {
if (checkForm()) {
val url = Api.buildUrl(AccountApi.Login)
Logger.i("开始$loginDesc,请求接口:$url")
val studentId = "${studentId.formValue.value}"
val password = "${password.formValue.value}"
this.studentId.formValue
Logger.i("使用学号:$studentId,密码:$password 进行登录")
HttpClient.post(
url,
SimpleCallback<Token>(
action = loginDesc,
onSuccess = {
Logger.i(it.message)
callback(it.message)
val context = getApplication<Application>().applicationContext
it.body?.let {
val db = AppDatabase.getInstance(context)
viewModelScope.launch {
TokenManager.token = it
db?.tokenDao()?.save(token = it)
}.invokeOnCompletion {
_finishLogin.postValue(true)
}
}
},
onFail = { callback(it) },
type = object : TypeToken<ApiResponse<Token>>() {}.type
),
jsonParam = UserLoginVo(
studentId = studentId,
password = password,
device = "${Build.MANUFACTURER} ${Build.MODEL}"
)
)
} else {
Logger.wtf("表单校验失败,无法$loginDesc!!!")
}
id.clean()
name.clean()
}

@ -62,7 +62,7 @@ class AccountActivity : ComponentActivity() {
.padding(bottom = 10.dp)
) {
Text(text = accountViewModel.loginDesc)
Text(text = stringResource(id = R.string.login_btn))
}
val finishLogin: Boolean? by accountViewModel.finishLogin.observeAsState()
@ -107,7 +107,7 @@ class AccountActivity : ComponentActivity() {
.fillMaxWidth()
.padding(bottom = 10.dp)
) {
Text(text = accountViewModel.regBtnDesc)
Text(text = stringResource(id = R.string.reg_btn))
}
OutlinedButton(
@ -196,9 +196,9 @@ class AccountActivity : ComponentActivity() {
Column {
val isValidStudentId by accountViewModel.studentId.statusForm.observeAsState()
val isValidStudentId by accountViewModel.id.statusForm.observeAsState()
BaseTextField(
form = accountViewModel.studentId, keyboardOptions = KeyboardOptions.Default.copy(
form = accountViewModel.id, keyboardOptions = KeyboardOptions.Default.copy(
keyboardType = KeyboardType.Number,
imeAction = ImeAction.Done
), isError = isValidStudentId != FormStatus.Valid
@ -213,13 +213,13 @@ class AccountActivity : ComponentActivity() {
)
FormStatus.Repeat ->
Text(buildAnnotatedString {
append(accountViewModel.studentId.formDesc)
append(accountViewModel.id.formDesc)
withStyle(
style = MaterialTheme.typography.body1.toSpanStyle().copy(
color = MaterialTheme.colors.error
)
) {
append(accountViewModel.studentId.formValue.value ?: "")
append(accountViewModel.id.formValue.value ?: "")
}
append(accountViewModel.registered)
})
@ -306,10 +306,10 @@ class AccountActivity : ComponentActivity() {
private fun Name(accountViewModel: AccountViewModel = viewModel()) {
Column {
val isValidName: Boolean by accountViewModel.isValidName.observeAsState(false)
BaseTextField(form = accountViewModel.name, isError = !isValidName)
val formStatus by accountViewModel.name.statusForm.observeAsState()
BaseTextField(form = accountViewModel.name, isError = formStatus !== FormStatus.Valid)
if (!isValidName) {
if (formStatus == FormStatus.Empty) {
Text(
text = accountViewModel.nameFormat,
color = MaterialTheme.colors.error
@ -326,10 +326,10 @@ class AccountActivity : ComponentActivity() {
@Composable
private fun Password(accountViewModel: AccountViewModel = viewModel()) {
Column {
val isValidPwd: Boolean by accountViewModel.isValidPwd.observeAsState(false)
val formStatus by accountViewModel.password.statusForm.observeAsState()
BaseTextField(
form = accountViewModel.password, isError = !isValidPwd,
form = accountViewModel.password, isError = formStatus !== FormStatus.Valid,
keyboardOptions = KeyboardOptions.Default.copy(
imeAction = ImeAction.Done,
keyboardType = KeyboardType.Number,
@ -337,11 +337,13 @@ class AccountActivity : ComponentActivity() {
)
if (!isValidPwd) {
Text(
when (formStatus) {
FormStatus.Empty, FormStatus.FormatError -> Text(
text = accountViewModel.passwordFormat,
color = MaterialTheme.colors.error
)
else -> {
}
}
}
}

@ -1,15 +1,16 @@
package com.gyf.csams.activity.model
import android.app.Application
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.gyf.csams.NOT_IMPL_TIP
import com.gyf.csams.uikit.AbstractComment
import com.gyf.csams.uikit.ActivityDetailMenu
import com.gyf.csams.uikit.TopMenuInterface
import com.gyf.lib.ScrollList
import com.gyf.lib.model.ScrollViewModel
import com.gyf.lib.uikit.ValidStringForm
import com.gyf.lib.util.NOT_IMPL_TIP
import com.gyf.lib.util.randomChinese
import com.gyf.lib.util.randomDateTime
import com.gyf.lib.util.randomNum
@ -112,7 +113,8 @@ data class ActivityPhotoVo(
* 活动相册数据状态管理
*
*/
class ActivityPhotoViewModel : ScrollList<ActivityPhotoVo>() {
class ActivityPhotoViewModel(application: Application) :
ScrollViewModel<ActivityPhotoVo>(application) {
override val initSize: Int = 10
init {
@ -184,7 +186,8 @@ data class ActivityMembersVo(
val participant: MutableList<ActivityMemberVo>?
)
class ActivityMemberViewModel : ScrollList<ActivityMemberVo>() {
class ActivityMemberViewModel(application: Application) :
ScrollViewModel<ActivityMemberVo>(application) {
override val initSize: Int = 10
private val _allMember = MutableLiveData<ActivityMembersVo>()
@ -264,7 +267,7 @@ class BBSCommentModel : AbstractComment() {
* 交流区数据状态管理
*
*/
class BBSViewModel : ScrollList<BBSVo>() {
class BBSViewModel(application: Application) : ScrollViewModel<BBSVo>(application) {
override val initSize: Int = 10
val title = "发送评论"

@ -19,12 +19,12 @@ import com.baidu.mapapi.search.sug.SuggestionSearch
import com.baidu.mapapi.search.sug.SuggestionSearchOption
import com.gyf.csams.BuildConfig
import com.gyf.csams.MyLocationListener
import com.gyf.csams.NOT_IMPL_TIP
import com.gyf.csams.R
import com.gyf.lib.uikit.ScaffoldModel
import com.gyf.lib.uikit.StringForm
import com.gyf.lib.util.ContextUtil
import com.gyf.lib.util.DATETIME_FORMAT
import com.gyf.lib.util.NOT_IMPL_TIP
import com.orhanobut.logger.Logger
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch

@ -1,14 +1,15 @@
package com.gyf.csams.association.model
import android.app.Application
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.gyf.csams.NOT_IMPL_TIP
import com.gyf.csams.uikit.AssociationMenu
import com.gyf.csams.uikit.TopMenuInterface
import com.gyf.lib.ScrollList
import com.gyf.lib.model.ScrollViewModel
import com.gyf.lib.uikit.StringForm
import com.gyf.lib.util.NOT_IMPL_TIP
import com.orhanobut.logger.Logger
import kotlinx.coroutines.launch
@ -47,7 +48,7 @@ data class MemberVo(val name: String)
* 社团会员
*
*/
class MemberViewModel : ScrollList<MemberVo>() {
class MemberViewModel(application: Application) : ScrollViewModel<MemberVo>(application) {
val name = StringForm(formDesc = "姓名关键字", 5)
val search = "搜索"
@ -125,7 +126,7 @@ data class HistoryActVo(val name: String)
* 历史活动
*
*/
class HistoryActViewModel : ScrollList<HistoryActVo>() {
class HistoryActViewModel(application: Application) : ScrollViewModel<HistoryActVo>(application) {
override val initSize = 10
init {

@ -1,11 +1,12 @@
package com.gyf.csams.association.model
import android.app.Application
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.viewModelScope
import com.gyf.csams.NOT_IMPL_TIP
import com.gyf.lib.ScrollList
import com.gyf.lib.model.ScrollViewModel
import com.gyf.lib.uikit.StringForm
import com.gyf.lib.util.NOT_IMPL_TIP
import kotlinx.coroutines.launch
import kotlin.random.Random
@ -88,7 +89,7 @@ const val ANSWER_TEXT_LENGTH = 15
*
*/
class ExamViewModel : ScrollList<Exam>() {
class ExamViewModel(application: Application) : ScrollViewModel<Exam>(application) {
val questionIsNull: String = "问题不能为空"
val deleteLeastOne: String = "至少保留一道题目"
val deleteTip = "确定删除此题目?"

@ -7,17 +7,11 @@ import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.viewModelScope
import com.google.gson.reflect.TypeToken
import com.gyf.csams.Api
import com.gyf.csams.AssociationApi
import com.gyf.csams.MainApplication
import com.gyf.csams.UNKNOW_ERROR
import com.gyf.csams.util.SimpleCallback
import com.gyf.lib.uikit.FormStatus
import com.gyf.lib.uikit.ValidStringForm
import com.gyf.lib.util.ApiResponse
import com.gyf.lib.util.HttpClient
import com.gyf.lib.util.Token
import com.gyf.lib.util.TokenManager
import com.gyf.lib.util.*
import com.orhanobut.logger.Logger
import kotlinx.coroutines.launch
import java.io.File

@ -1,8 +1,8 @@
package com.gyf.csams.association.model
import androidx.lifecycle.ViewModel
import com.gyf.csams.NOT_IMPL_TIP
import com.gyf.lib.uikit.StringForm
import com.gyf.lib.util.NOT_IMPL_TIP
/**
* 社团重命名状态管理

@ -5,14 +5,13 @@ import android.app.Application
import android.content.Intent
import androidx.lifecycle.*
import com.google.gson.reflect.TypeToken
import com.gyf.NotificationDto
import com.gyf.ReceiverType
import com.gyf.csams.*
import com.gyf.csams.account.model.UserVo
import com.gyf.csams.account.ui.AccountActivity
import com.gyf.csams.uikit.AbstractComment
import com.gyf.csams.util.SimpleCallback
import com.gyf.lib.ScrollList
import com.gyf.lib.model.ScrollViewModel
import com.gyf.lib.service.NotificationDto
import com.gyf.lib.service.ReceiverType
import com.gyf.lib.uikit.FormStatus
import com.gyf.lib.uikit.PersonInfoVo
import com.gyf.lib.uikit.StringForm
@ -173,7 +172,7 @@ data class LeaveMessageVo(val message: String, val token: Token)
* 社团列表
*
*/
class ListViewModel : ScrollList<AssociationListVo>() {
class ListViewModel(application: Application) : ScrollViewModel<AssociationListVo>(application) {
val name = StringForm(formDesc = "社团名称", textLength = 5)
val desc = StringForm(formDesc = "社团简介", textLength = 10)

@ -31,7 +31,7 @@ import com.gyf.csams.association.ui.RegAssociationActivity
import com.gyf.csams.main.model.*
import com.gyf.csams.message.ui.MessageActivity
import com.gyf.csams.uikit.*
import com.gyf.lib.MessageService
import com.gyf.lib.service.MessageService
import com.gyf.lib.uikit.*
import com.gyf.lib.util.randomChinese

@ -1,20 +1,16 @@
package com.gyf.csams.message.model
import android.app.Application
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.viewModelScope
import com.google.gson.reflect.TypeToken
import com.gyf.NotificationDto
import com.gyf.PageDto
import com.gyf.ReceiverType
import com.gyf.csams.Api
import com.gyf.csams.NOT_IMPL_TIP
import com.gyf.csams.NotificationApi
import com.gyf.csams.util.SimpleCallback
import com.gyf.lib.ScrollList
import com.gyf.lib.util.ApiResponse
import com.gyf.lib.util.HttpClient
import com.gyf.lib.util.TokenManager
import com.gyf.lib.model.ScrollViewModel
import com.gyf.lib.service.NotificationDto
import com.gyf.lib.service.PageDto
import com.gyf.lib.service.ReceiverType
import com.gyf.lib.util.*
import com.orhanobut.logger.Logger
import kotlinx.coroutines.launch
import java.util.*
@ -89,7 +85,7 @@ data class RenameContent(
* 系统通知数据状态管理
*
*/
class SysMessageViewModel : ScrollList<NotificationVo>() {
class SysMessageViewModel(application: Application) : ScrollViewModel<NotificationVo>(application) {
val title = "系统通知"
override val initSize: Int = 10

@ -3,7 +3,6 @@ package com.gyf.csams.uikit
import android.app.Activity
import androidx.annotation.DrawableRes
import androidx.compose.animation.Crossfade
import androidx.compose.animation.animateColor
import androidx.compose.animation.core.*
import androidx.compose.foundation.Image
import androidx.compose.foundation.background
@ -39,29 +38,6 @@ import com.gyf.csams.main.model.MarqueeViewModel
import com.gyf.lib.uikit.*
import com.orhanobut.logger.Logger
/**
* 淡入淡出并且颜色变化文本
*
* @param text
*/
@Composable
fun AnimationText(text: String) {
val infiniteTransition = rememberInfiniteTransition()
val color by infiniteTransition.animateColor(
initialValue = MaterialTheme.colors.primary,
targetValue = MaterialTheme.colors.onPrimary,
animationSpec = infiniteRepeatable(
animation = tween(1000, easing = LinearEasing),
repeatMode = RepeatMode.Reverse
)
)
Text(
text = text,
color = color,
style = MaterialTheme.typography.body1
)
}
/**
* 主菜单

@ -7,12 +7,12 @@ import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.viewModelScope
import com.google.gson.reflect.TypeToken
import com.gyf.csams.Api
import com.gyf.csams.MainApi
import com.gyf.csams.R
import com.gyf.csams.util.SimpleCallback
import com.gyf.lib.util.Api
import com.gyf.lib.util.HttpClient
import com.gyf.lib.util.ImageUtil
import com.gyf.lib.util.MainApi
import com.orhanobut.logger.Logger
import kotlinx.coroutines.Job
import kotlinx.coroutines.delay

@ -1,34 +0,0 @@
package com.gyf.lib
import android.app.Application
import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
@Deprecated(message = "", replaceWith = ReplaceWith(""))
abstract class ScrollList<T> : ViewModel() {
protected val _data = MutableLiveData<MutableList<T>>(mutableListOf())
val data: LiveData<MutableList<T>> = _data
abstract val initSize: Int
//加载列表
abstract fun load()
//加载更多数据
abstract fun loadMore(callback: (message: String) -> Unit)
}
abstract class ScrollListW<T>(application: Application) : AndroidViewModel(application) {
protected val _data = MutableLiveData<MutableList<T>>(mutableListOf())
val data: LiveData<MutableList<T>> = _data
abstract val initSize: Int
//加载列表
abstract fun load()
//加载更多数据
abstract fun loadMore(callback: (message: String) -> Unit)
}

@ -0,0 +1,80 @@
package com.gyf.lib.model
import android.app.Application
import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.viewModelScope
import com.google.gson.reflect.TypeToken
import com.gyf.lib.R
import com.gyf.lib.uikit.ValidStringForm
import com.gyf.lib.util.*
import com.orhanobut.logger.Logger
import kotlinx.coroutines.launch
abstract class AbstractLoginViewModel(application: Application) : AndroidViewModel(application) {
protected val loginDesc = application.getString(R.string.login_btn)
abstract val id: ValidStringForm
abstract val password: ValidStringForm
//注册按钮
protected val _isValidForm = MutableLiveData<Boolean>()
val isValidForm: LiveData<Boolean> = _isValidForm
/**
* 完成登录状态
*/
private val _finishLogin = MutableLiveData<Boolean>()
val finishLogin: LiveData<Boolean> = _finishLogin
abstract fun checkForm(): Boolean
abstract fun loginParam(): Any
abstract val api: AccountApi
/**
* 登录
*
*/
fun login(callback: (message: String) -> Unit) {
viewModelScope.launch {
if (checkForm()) {
val url = Api.buildUrl(api)
Logger.i("开始$loginDesc,请求接口:$url")
val id = "${id.formValue.value}"
val password = "${password.formValue.value}"
Logger.i("使用账号:$id,密码:$password 进行登录")
HttpClient.post(
url,
HttpCallback<Token>(
action = loginDesc,
onSuccess = {
Logger.i(it.message)
callback(it.message)
val context = getApplication<Application>().applicationContext
it.body?.let {
val db = AppDatabase.getInstance(context)
viewModelScope.launch {
TokenManager.token = it
db?.tokenDao()?.save(token = it)
}.invokeOnCompletion {
_finishLogin.postValue(true)
}
}
},
onFail = { callback(it) },
type = object : TypeToken<ApiResponse<Token>>() {}.type
),
jsonParam = loginParam()
)
} else {
Logger.wtf("表单校验失败,无法$loginDesc!!!")
}
}
}
}

@ -1,11 +1,10 @@
package com.gyf
package com.gyf.lib.model
import android.app.Application
import com.gyf.lib.R
import com.gyf.lib.ScrollListW
import com.gyf.lib.uikit.StringForm
abstract class ApplyViewModel<T>(application: Application) : ScrollListW<T>(application) {
abstract class ApplyViewModel<T>(application: Application) : ScrollViewModel<T>(application) {
val approverOrigin =
StringForm(formDesc = application.getString(R.string.approver_origin), textLength = 30)
}

@ -1,4 +1,4 @@
package com.gyf.csams
package com.gyf.lib.model
import android.app.Application
import androidx.lifecycle.AndroidViewModel
@ -6,12 +6,10 @@ import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.viewModelScope
import com.google.gson.reflect.TypeToken
import com.gyf.csams.util.SimpleCallback
import com.gyf.lib.util.*
import com.orhanobut.logger.Logger
import kotlinx.coroutines.launch
class InitViewModel(application: Application) : AndroidViewModel(application) {
/**
* 服务器网络状态是否正常true=正常false=不正常
@ -29,7 +27,7 @@ class InitViewModel(application: Application) : AndroidViewModel(application) {
viewModelScope.launch {
HttpClient.get(
Api.buildUrl(TestApi.Test),
SimpleCallback<Boolean>(action = "测试", onSuccess = {
HttpCallback<Boolean>(action = "测试", onSuccess = {
_isNetWorkWorking.postValue(true)
}, onFail = {
Logger.e(it)
@ -40,23 +38,22 @@ class InitViewModel(application: Application) : AndroidViewModel(application) {
}
/**
* 查询本地是否有且只有一个用户token如果有则自动登录
*/
fun hasOnlyUserToken(onSuccess: () -> Unit, onFail: () -> Unit) {
fun hasOnlyUserToken(onSuccess: () -> Unit, onFail: () -> Unit, api: AccountApi) {
viewModelScope.launch {
val context = getApplication<MainApplication>()
val context = getApplication<Application>()
val db = AppDatabase.getInstance(context)
val tokenList = db?.tokenDao()?.queryAll()
if (tokenList != null && tokenList.size == 1) {
val currentToken: Token = tokenList[0]
val url = Api.buildUrl(AccountApi.LoginToken)
val url = Api.buildUrl(api)
val action = "校验token"
Logger.i("${action}api=$url")
HttpClient.post(
url,
SimpleCallback<Boolean>(
HttpCallback<Boolean>(
action = action,
onSuccess = { it ->
it.body?.let {

@ -0,0 +1,19 @@
package com.gyf.lib.model
import android.app.Application
import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
abstract class ScrollViewModel<T>(application: Application) : AndroidViewModel(application) {
protected val _data = MutableLiveData<MutableList<T>>(mutableListOf())
val data: LiveData<MutableList<T>> = _data
abstract val initSize: Int
//加载列表
abstract fun load()
//加载更多数据
abstract fun loadMore(callback: (message: String) -> Unit)
}

@ -1,4 +1,4 @@
package com.gyf.lib
package com.gyf.lib.service
import android.content.Intent
import androidx.core.app.JobIntentService
@ -6,14 +6,8 @@ import androidx.core.app.NotificationCompat
import androidx.core.app.NotificationManagerCompat
import com.google.gson.Gson
import com.google.gson.reflect.TypeToken
import com.gyf.NOTIFICATION_API
import com.gyf.NotificationDto
import com.gyf.NotificationVo
import com.gyf.ReceiverType
import com.gyf.lib.util.ApiResponse
import com.gyf.lib.util.HttpClient
import com.gyf.lib.util.NotificationUtil
import com.gyf.lib.util.TokenManager
import com.gyf.lib.R
import com.gyf.lib.util.*
import com.orhanobut.logger.Logger
class MessageService : JobIntentService() {
@ -32,7 +26,8 @@ class MessageService : JobIntentService() {
override fun onHandleWork(intent: Intent) {
TokenManager.token?.let { it ->
HttpClient.postAsync<List<NotificationVo>>(url = NOTIFICATION_API,
HttpClient.postAsync<List<NotificationVo>>(
url = Api.buildUrl(NotificationApi.Pull),
jsonParam = NotificationDto(
receiverId = it.id,
receiverClient = ReceiverType.Foreground.name,

@ -1,4 +1,4 @@
package com.gyf
package com.gyf.lib.service
import android.content.Context
import androidx.work.Data
@ -6,14 +6,10 @@ import androidx.work.Worker
import androidx.work.WorkerParameters
import com.google.gson.Gson
import com.google.gson.reflect.TypeToken
import com.gyf.lib.BuildConfig
import com.gyf.lib.util.*
import com.orhanobut.logger.Logger
import java.net.SocketTimeoutException
const val NOTIFICATION_API = "${BuildConfig.SERVER_ADDRESS}/api/notification/pull"
data class NotificationVo(val title: String, val content: String, val id: Int)
data class PageDto(val currentPage: Long, val pageSize: Int = 10)
@ -44,7 +40,8 @@ class NotificationWorker(context: Context, workerParams: WorkerParameters) :
TokenManager.token?.let {
return try {
Logger.i("开始拉取通知")
val data = HttpClient.postAsync<NotificationVo>(url = NOTIFICATION_API,
val data = HttpClient.postAsync<NotificationVo>(
url = Api.buildUrl(NotificationApi.Pull),
jsonParam = NotificationDto(
receiverId = it.id,
receiverClient = inputData.getString("receiverClient")

@ -0,0 +1,66 @@
package com.gyf.lib.uikit
import android.app.Activity
import android.content.Intent
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.runtime.getValue
import androidx.compose.runtime.livedata.observeAsState
import androidx.compose.ui.Alignment
import androidx.lifecycle.viewmodel.compose.viewModel
import com.gyf.lib.BuildConfig
import com.gyf.lib.model.InitViewModel
import com.gyf.lib.util.AccountApi
import com.orhanobut.logger.Logger
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
abstract class AbstractInitActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
Body {
MainBoxFrame(background = { /*TODO*/ }, contentAlignment = Alignment.Center) {
val initViewModel: InitViewModel = viewModel()
//检查网络
val isNetWorkWorking: Boolean? by initViewModel.isNetWorkWorking.observeAsState(
null
)
Logger.i("初始化")
when (isNetWorkWorking) {
null -> AnimationText(text = "测试服务端运行状态中。。。")
true -> init(initViewModel = initViewModel)
false -> AnimationText(text = "无法连接到服务端,请检查服务端地址${BuildConfig.SERVER_ADDRESS}是否配置正确")
}
}
}
}
}
protected abstract val main: Class<out Activity>
protected abstract val login: Class<out Activity>
abstract val api: AccountApi
private fun init(initViewModel: InitViewModel) {
//后台检查token
initViewModel.hasOnlyUserToken(onSuccess = {
startActivity(Intent(this, main))
}, onFail = {
startActivity(Intent(this, login))
}, api = api)
GlobalScope.launch {
delay(1000)
finish()
}
}
}

@ -0,0 +1,33 @@
package com.gyf.lib.uikit
import androidx.compose.animation.animateColor
import androidx.compose.animation.core.*
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
/**
* 淡入淡出并且颜色变化文本
*
* @param text
*/
@Composable
fun AnimationText(text: String) {
val infiniteTransition = rememberInfiniteTransition()
val color by infiniteTransition.animateColor(
initialValue = MaterialTheme.colors.primary,
targetValue = MaterialTheme.colors.onPrimary,
animationSpec = infiniteRepeatable(
animation = tween(1000, easing = LinearEasing),
repeatMode = RepeatMode.Reverse
)
)
Text(
text = text,
color = color,
style = MaterialTheme.typography.body1
)
}

@ -1,4 +1,8 @@
package com.gyf.csams
package com.gyf.lib.util
import com.gyf.lib.BuildConfig
import com.gyf.lib.service.ReceiverType
import java.util.*
interface UrlPath {
@ -23,11 +27,18 @@ enum class AccountApi(val path: String) : UrlPath {
//学号检测
CheckId("/register/checkId"),
//登录
Login("/login"),
//前台登录
ForegroundLogin("/login/${ReceiverType.Foreground.name.toLowerCase(Locale.ROOT)}"),
//后台登陆
BackgroundLogin("/login/${ReceiverType.Background.name.toLowerCase(Locale.ROOT)}"),
//前台令牌校验
ForegroundToken("${ForegroundLogin.path}/token"),
//令牌校验
LoginToken("/login/token"),
//后台令牌校验
BackgroundToken("${BackgroundLogin.path}/token"),
//登出
Logout("/logout");
@ -73,7 +84,8 @@ enum class AssociationApi(val path: String) : UrlPath {
enum class NotificationApi(val path: String) : UrlPath {
Count("/count"),
List("/list");
List("/list"),
Pull("/pull");
override fun build(): String {
return "/api/notification${this.path}"

@ -6,8 +6,8 @@ import android.view.View
import android.view.inputmethod.InputMethodManager
import androidx.lifecycle.LiveData
import androidx.work.*
import com.gyf.NotificationWorker
import com.gyf.ReceiverType
import com.gyf.lib.service.NotificationWorker
import com.gyf.lib.service.ReceiverType
import com.orhanobut.logger.Logger
import java.util.*

@ -21,4 +21,5 @@
<string name="approver_origin">审核理由</string>
<string name="not_impl_error">抱歉此功能尚未开放</string>
<string name="quality_report_title">活动质量汇报单</string>
<string name="login_btn">登录</string>
</resources>

@ -21,4 +21,5 @@
<string name="approver_origin">审核理由</string>
<string name="not_impl_error">抱歉此功能尚未开放</string>
<string name="quality_report_title">活动质量汇报单</string>
<string name="login_btn">登录</string>
</resources>

@ -21,4 +21,5 @@
<string name="approver_origin">审核理由</string>
<string name="not_impl_error">抱歉此功能尚未开放</string>
<string name="quality_report_title">活动质量汇报单</string>
<string name="login_btn">登录</string>
</resources>
Loading…
Cancel
Save