diff --git a/background/src/main/AndroidManifest.xml b/background/src/main/AndroidManifest.xml index 64952af..5528c76 100644 --- a/background/src/main/AndroidManifest.xml +++ b/background/src/main/AndroidManifest.xml @@ -35,6 +35,7 @@ + \ No newline at end of file diff --git a/background/src/main/java/com/gyf/csams/account/model/LoginViewModel.kt b/background/src/main/java/com/gyf/csams/account/model/LoginViewModel.kt index ad0d804..1aa1c2a 100644 --- a/background/src/main/java/com/gyf/csams/account/model/LoginViewModel.kt +++ b/background/src/main/java/com/gyf/csams/account/model/LoginViewModel.kt @@ -1,11 +1,14 @@ package com.gyf.csams.account.model +import android.app.Activity import android.app.Application import android.os.Build +import com.gyf.csams.account.ui.LoginActivity import com.gyf.lib.model.AbstractLoginViewModel import com.gyf.lib.uikit.FormStatus import com.gyf.lib.uikit.ValidStringForm import com.gyf.lib.util.AccountApi +import com.gyf.lib.util.ClientType data class ManagerVo(val account: String, val password: String, val device: String) @@ -28,4 +31,7 @@ class LoginViewModel(application: Application) : AbstractLoginViewModel(applicat device = "${Build.MANUFACTURER} ${Build.MODEL}" ) } + + override val clientType: ClientType = ClientType.Background + override val loginClass: Class = LoginActivity::class.java } \ No newline at end of file diff --git a/background/src/main/java/com/gyf/csams/account/ui/LoginActivity.kt b/background/src/main/java/com/gyf/csams/account/ui/LoginActivity.kt index f1744dd..30d3d5f 100644 --- a/background/src/main/java/com/gyf/csams/account/ui/LoginActivity.kt +++ b/background/src/main/java/com/gyf/csams/account/ui/LoginActivity.kt @@ -34,7 +34,6 @@ class LoginActivity : ComponentActivity() { setContent { Body { - val context = LocalContext.current as LoginActivity MainBoxFrame( background = { /*TODO 背景图*/ }, contentAlignment = Alignment.Center diff --git a/background/src/main/java/com/gyf/csams/main/ui/MainActivity.kt b/background/src/main/java/com/gyf/csams/main/ui/MainActivity.kt index 38cb0ee..f7cc5bf 100644 --- a/background/src/main/java/com/gyf/csams/main/ui/MainActivity.kt +++ b/background/src/main/java/com/gyf/csams/main/ui/MainActivity.kt @@ -2,7 +2,6 @@ package com.gyf.csams.main.ui import android.content.Intent import android.os.Bundle -import androidx.activity.ComponentActivity import androidx.activity.compose.setContent import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column @@ -17,17 +16,25 @@ import androidx.compose.ui.res.stringResource 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.model.MainViewModel import com.gyf.csams.main.model.MenuType +import com.gyf.lib.service.BaseActivity import com.gyf.lib.uikit.* +import com.gyf.lib.util.ClientType + +class MainActivity : BaseActivity() { + + override val clientType: ClientType = ClientType.Background -class MainActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContent { Body { val model: MainViewModel = viewModel() + val loginViewModel: LoginViewModel = viewModel() + val scaffoldModel: ScaffoldModel = viewModel() val person by model.person.observeAsState() MainColumnFrame(background = { /*TODO*/ }) { person?.let { @@ -68,6 +75,14 @@ class MainActivity : ComponentActivity() { }, modifier = Modifier.fillMaxWidth()) { Text(text = stringResource(id = R.string.activity_management)) } + + OutlinedButton(onClick = { + loginViewModel.logout(this@MainActivity) { + scaffoldModel.update(message = it) + } + }, modifier = Modifier.fillMaxWidth()) { + Text(text = "退出登录") + } } } } diff --git a/background/src/main/java/com/gyf/csams/main/ui/ManagementOfficerActivity.kt b/background/src/main/java/com/gyf/csams/main/ui/ManagementOfficerActivity.kt index 131e6eb..0c10c81 100644 --- a/background/src/main/java/com/gyf/csams/main/ui/ManagementOfficerActivity.kt +++ b/background/src/main/java/com/gyf/csams/main/ui/ManagementOfficerActivity.kt @@ -112,7 +112,6 @@ class ManagementOfficerActivity : ComponentActivity() { Spacer(modifier = Modifier.weight(0.05F)) Text(text = context.getString(id), modifier = Modifier.weight(0.1F)) Spacer(modifier = Modifier.weight(0.05F)) - val columnSize = 4 LazyRow(modifier = Modifier.weight(0.6F)) { officerVoList.withIndex().forEach { diff --git a/foreground/src/main/java/com/gyf/csams/account/model/AccountViewModel.kt b/foreground/src/main/java/com/gyf/csams/account/model/AccountViewModel.kt index 468c0cf..3e7999e 100644 --- a/foreground/src/main/java/com/gyf/csams/account/model/AccountViewModel.kt +++ b/foreground/src/main/java/com/gyf/csams/account/model/AccountViewModel.kt @@ -1,5 +1,6 @@ package com.gyf.csams.account.model +import android.app.Activity import android.app.Application import android.os.Build import androidx.lifecycle.LiveData @@ -7,15 +8,13 @@ import androidx.lifecycle.MutableLiveData import androidx.lifecycle.viewModelScope import com.google.gson.reflect.TypeToken import com.gyf.csams.R +import com.gyf.csams.account.ui.AccountActivity import com.gyf.csams.account.ui.AccountRoute import com.gyf.csams.util.SimpleCallback import com.gyf.lib.model.AbstractLoginViewModel import com.gyf.lib.uikit.FormStatus import com.gyf.lib.uikit.ValidStringForm -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.gyf.lib.util.* import com.orhanobut.logger.Logger import kotlinx.coroutines.Job import kotlinx.coroutines.launch @@ -61,6 +60,9 @@ class AccountViewModel(application: Application) : AbstractLoginViewModel(applic override val api: AccountApi = AccountApi.ForegroundLogin + override val clientType: ClientType = ClientType.Foreground + override val loginClass: Class = AccountActivity::class.java + //学号 override val id = object : ValidStringForm(formDesc = "学号", textLength = 8) { override fun check() { diff --git a/foreground/src/main/java/com/gyf/csams/main/model/MainViewModel.kt b/foreground/src/main/java/com/gyf/csams/main/model/MainViewModel.kt index 2b0676c..ce19116 100644 --- a/foreground/src/main/java/com/gyf/csams/main/model/MainViewModel.kt +++ b/foreground/src/main/java/com/gyf/csams/main/model/MainViewModel.kt @@ -1,17 +1,12 @@ package com.gyf.csams.main.model -import android.app.Activity import android.app.Application -import android.content.Intent import androidx.lifecycle.* import com.google.gson.reflect.TypeToken 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.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 @@ -53,7 +48,7 @@ class NotificationViewModel(application: Application) : AndroidViewModel(applica }, type = object : TypeToken>() {}.type), jsonParam = NotificationDto( receiverId = it.id, - receiverClient = ReceiverType.Foreground.name, + receiverClient = ClientType.Foreground, token = it ) ) @@ -136,7 +131,7 @@ class MarqueeViewModel : AbstractComment() { Logger.e(it) callback("留言获取失败") }, type = object : TypeToken>>() {}.type), - jsonParam = OnlyToken() + jsonParam = OnlyToken(clientType = ClientType.Foreground) ) } } @@ -262,7 +257,6 @@ data class InfoVo( override val desc: String ) : PersonInfoVo() -data class UserLogoutVo(val userId: Int) /** * 个人中心 @@ -293,43 +287,4 @@ class CenterViewModel : ViewModel() { } } - - fun logout(context: Activity, callback: (message: String) -> Unit) { - val userId = TokenManager.token?.id - if (userId != null) { - Logger.i("帐号$userId 将要退出登录") - viewModelScope.launch { - HttpClient.post( - Api.buildUrl(AccountApi.Logout), - SimpleCallback( - action = "登出", onSuccess = { it -> - it.body?.let { - if (it) { - viewModelScope.launch { - val db = AppDatabase.getInstance(context = context) - db?.tokenDao()?.deleteAll() - Logger.i("退出登陆成功") - context.finish() - context.startActivity( - Intent( - context, - AccountActivity::class.java - ) - ) - - } - TokenManager.token = null - } - } - callback(it.message) - }, onFail = { callback("退出登陆失败") }, - type = object : TypeToken>() {}.type - ), - jsonParam = UserLogoutVo(userId = userId) - ) - } - } else { - callback("操作异常,请联系管理员") - } - } } diff --git a/foreground/src/main/java/com/gyf/csams/main/ui/MainActivity.kt b/foreground/src/main/java/com/gyf/csams/main/ui/MainActivity.kt index f1b7aad..7f67775 100644 --- a/foreground/src/main/java/com/gyf/csams/main/ui/MainActivity.kt +++ b/foreground/src/main/java/com/gyf/csams/main/ui/MainActivity.kt @@ -2,7 +2,6 @@ package com.gyf.csams.main.ui import android.content.Intent import android.os.Bundle -import androidx.activity.ComponentActivity import androidx.activity.compose.setContent import androidx.compose.foundation.Image import androidx.compose.foundation.border @@ -25,14 +24,16 @@ import androidx.navigation.NavHostController import androidx.navigation.compose.NavHost import androidx.navigation.compose.composable import com.gyf.csams.R +import com.gyf.csams.account.model.AccountViewModel import com.gyf.csams.activity.ui.ActivityDetailActivity import com.gyf.csams.association.ui.AssociationActivity 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.service.MessageService +import com.gyf.lib.service.BaseActivity import com.gyf.lib.uikit.* +import com.gyf.lib.util.ClientType import com.gyf.lib.util.randomChinese @@ -40,13 +41,13 @@ import com.gyf.lib.util.randomChinese * 主界面 * */ -class MainActivity : ComponentActivity() { +class MainActivity : BaseActivity() { + + override val clientType: ClientType = ClientType.Foreground override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - startService(Intent(this, MessageService::class.java)) - setContent { val imageViewModel: ImageViewModel = viewModel() @@ -76,10 +77,6 @@ class MainActivity : ComponentActivity() { } - override fun onResume() { - super.onResume() - startService(Intent(this, MessageService::class.java)) - } /** * 个人中心 @@ -89,6 +86,7 @@ class MainActivity : ComponentActivity() { private fun Center( model: CenterViewModel = viewModel(), scaffoldModel: ScaffoldModel = viewModel(), + accountViewModel: AccountViewModel = viewModel(), navController: NavHostController ) { MainColumnFrame( @@ -96,8 +94,6 @@ class MainActivity : ComponentActivity() { mainMenu = MainMenu.Center, nav = navController ) { - val context = LocalContext.current as MainActivity - val info by model.info.observeAsState() info?.let { @@ -115,13 +111,13 @@ class MainActivity : ComponentActivity() { verticalArrangement = Arrangement.SpaceEvenly ) { CenterMenuItem(text = model.myAssociationDesc) { - context.startActivity(Intent(context, AssociationActivity::class.java)) + startActivity(Intent(this@MainActivity, AssociationActivity::class.java)) } CenterMenuItem(text = model.myJoinActivity) CenterMenuItem(text = model.myLikeActivity) CenterMenuItem(text = model.myCollectActivity) CenterMenuItem(text = "退出登录") { - model.logout(context = context) { + accountViewModel.logout(this@MainActivity) { scaffoldModel.update(message = it) } } @@ -355,23 +351,26 @@ class MainActivity : ComponentActivity() { @Composable private fun Notification(notificationViewModel: NotificationViewModel = viewModel()) { val context = LocalContext.current - val count by notificationViewModel.count.observeAsState(0) - Row( - horizontalArrangement = Arrangement.End, - modifier = Modifier - .fillMaxWidth() - .padding(10.dp) - ) { - IconButton(onClick = { - context.startActivity(Intent(context, MessageActivity::class.java)) - }) { - Icon( - painter = painterResource(id = if (count > 0) R.drawable.ic_notice else R.drawable.ic_notification), - contentDescription = null - ) - } + val count by notificationViewModel.count.observeAsState(null) + count?.let { + Row( + horizontalArrangement = Arrangement.End, + modifier = Modifier + .fillMaxWidth() + .padding(10.dp) + ) { + IconButton(onClick = { + context.startActivity(Intent(context, MessageActivity::class.java)) + }) { + Icon( + painter = painterResource(id = if (it > 0) R.drawable.ic_notice else R.drawable.ic_notification), + contentDescription = null + ) + } + } } + } /** diff --git a/foreground/src/main/java/com/gyf/csams/message/model/SysMessageViewModel.kt b/foreground/src/main/java/com/gyf/csams/message/model/SysMessageViewModel.kt index 3680088..de7aa97 100644 --- a/foreground/src/main/java/com/gyf/csams/message/model/SysMessageViewModel.kt +++ b/foreground/src/main/java/com/gyf/csams/message/model/SysMessageViewModel.kt @@ -7,9 +7,6 @@ import androidx.lifecycle.viewModelScope import com.google.gson.reflect.TypeToken import com.gyf.csams.util.SimpleCallback 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 @@ -122,7 +119,7 @@ class SysMessageViewModel(application: Application) : ScrollViewModel + /** * 登录 * @@ -77,4 +83,45 @@ abstract class AbstractLoginViewModel(application: Application) : AndroidViewMod } } } + + /** + * 退出登录 + * + * @param context + * @param callback + */ + fun logout(context: Activity, callback: (message: String) -> Unit) { + TokenManager.token?.let { + Logger.i("帐号${it.id}将要退出登录") + viewModelScope.launch { + HttpClient.post( + Api.buildUrl(AccountApi.Logout), + HttpCallback( + action = "登出", onSuccess = { it -> + it.body?.let { + if (it) { + viewModelScope.launch { + val db = AppDatabase.getInstance(context = context) + db?.tokenDao()?.deleteAll() + Logger.i("退出登陆成功") + context.finish() + context.startActivity( + Intent( + context, + loginClass + ) + ) + } + TokenManager.token = null + } + } + callback(it.message) + }, onFail = { callback("退出登陆失败") }, + type = object : TypeToken>() {}.type + ), + jsonParam = OnlyToken(token = it, clientType = clientType) + ) + } + } + } } \ No newline at end of file diff --git a/lib/src/main/java/com/gyf/lib/service/BaseActivity.kt b/lib/src/main/java/com/gyf/lib/service/BaseActivity.kt new file mode 100644 index 0000000..958e25f --- /dev/null +++ b/lib/src/main/java/com/gyf/lib/service/BaseActivity.kt @@ -0,0 +1,26 @@ +package com.gyf.lib.service + +import android.content.Intent +import android.os.Bundle +import androidx.activity.ComponentActivity +import com.gyf.lib.util.ClientType + +abstract class BaseActivity : ComponentActivity() { + + abstract val clientType: ClientType + + private val serviceIntent + get() = Intent(this, MessageService::class.java).apply { + putExtra(ClientType::class.java.name, clientType) + } + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + startService(serviceIntent) + } + + override fun onResume() { + super.onResume() + startService(serviceIntent) + } +} \ No newline at end of file diff --git a/lib/src/main/java/com/gyf/lib/service/MessageService.kt b/lib/src/main/java/com/gyf/lib/service/MessageService.kt index 63ff9d5..0fd9f00 100644 --- a/lib/src/main/java/com/gyf/lib/service/MessageService.kt +++ b/lib/src/main/java/com/gyf/lib/service/MessageService.kt @@ -12,8 +12,15 @@ import com.orhanobut.logger.Logger class MessageService : JobIntentService() { + lateinit var clientType: ClientType + val gson = Gson() + override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { + clientType = intent?.getSerializableExtra(ClientType::class.java.name) as ClientType + return super.onStartCommand(intent, flags, startId) + } + override fun onCreate() { super.onCreate() Logger.i("服务启动") @@ -30,13 +37,13 @@ class MessageService : JobIntentService() { url = Api.buildUrl(NotificationApi.Pull), jsonParam = NotificationDto( receiverId = it.id, - receiverClient = ReceiverType.Foreground.name, + receiverClient = clientType, token = it ), type = object : TypeToken>>() {}.type - )?.let { it -> + )?.let { it1 -> Logger.i("拉取最新通知") - it.body?.forEach { + it1.body?.forEach { Logger.i("构造通知【${it.title}】") val builder = NotificationCompat.Builder(applicationContext, NotificationUtil.CHANNEL_ID) diff --git a/lib/src/main/java/com/gyf/lib/service/NotificationWorker.kt b/lib/src/main/java/com/gyf/lib/service/NotificationWorker.kt deleted file mode 100644 index be3a235..0000000 --- a/lib/src/main/java/com/gyf/lib/service/NotificationWorker.kt +++ /dev/null @@ -1,70 +0,0 @@ -package com.gyf.lib.service - -import android.content.Context -import androidx.work.Data -import androidx.work.Worker -import androidx.work.WorkerParameters -import com.google.gson.Gson -import com.google.gson.reflect.TypeToken -import com.gyf.lib.util.* -import com.orhanobut.logger.Logger -import java.net.SocketTimeoutException - -data class NotificationVo(val title: String, val content: String, val id: Int) - -data class PageDto(val currentPage: Long, val pageSize: Int = 10) - -data class NotificationDto( - val receiverId: Int, - val receiverClient: String, - override val token: Token, - val page: PageDto? = null -) : BaseToken() - -/** - * 通知接收客户端 - * - */ -enum class ReceiverType { - //前台 - Foreground, - - //后台 - Background -} - -class NotificationWorker(context: Context, workerParams: WorkerParameters) : - Worker(context, workerParams) { - - override fun doWork(): Result { - TokenManager.token?.let { - return try { - Logger.i("开始拉取通知") - val data = HttpClient.postAsync( - url = Api.buildUrl(NotificationApi.Pull), - jsonParam = NotificationDto( - receiverId = it.id, - receiverClient = inputData.getString("receiverClient") - ?: throw IllegalArgumentException("缺少receiverClient参数"), - token = it - ), - type = object : TypeToken>() {}.type - ) - val result = - Data.Builder().putString(NotificationVo::class.java.name, Gson().toJson(data)) - .build() - Logger.i("拉取通知成功:\n${result}") - Result.success(result) - } catch (e: SocketTimeoutException) { - Logger.e(e, "网络异常,拉取通知失败稍后再试") - Result.retry() - } catch (e: Exception) { - Logger.e(e, "发生未知异常,中止任务") - Result.failure() - } - } - Logger.w("找不到token信息,中止任务") - return Result.failure() - } - -} \ No newline at end of file diff --git a/lib/src/main/java/com/gyf/lib/util/Api.kt b/lib/src/main/java/com/gyf/lib/util/Api.kt index be2e881..8caf4b2 100644 --- a/lib/src/main/java/com/gyf/lib/util/Api.kt +++ b/lib/src/main/java/com/gyf/lib/util/Api.kt @@ -1,7 +1,7 @@ package com.gyf.lib.util import com.gyf.lib.BuildConfig -import com.gyf.lib.service.ReceiverType + import java.util.* @@ -28,10 +28,10 @@ enum class AccountApi(val path: String) : UrlPath { CheckId("/register/checkId"), //前台登录 - ForegroundLogin("/login/${ReceiverType.Foreground.name.toLowerCase(Locale.ROOT)}"), + ForegroundLogin("/login/${ClientType.Foreground.name.toLowerCase(Locale.ROOT)}"), //后台登陆 - BackgroundLogin("/login/${ReceiverType.Background.name.toLowerCase(Locale.ROOT)}"), + BackgroundLogin("/login/${ClientType.Background.name.toLowerCase(Locale.ROOT)}"), //前台令牌校验 diff --git a/lib/src/main/java/com/gyf/lib/util/ContextUtil.kt b/lib/src/main/java/com/gyf/lib/util/ContextUtil.kt index 7e78ec5..238c19d 100644 --- a/lib/src/main/java/com/gyf/lib/util/ContextUtil.kt +++ b/lib/src/main/java/com/gyf/lib/util/ContextUtil.kt @@ -1,42 +1,11 @@ package com.gyf.lib.util import android.app.Activity -import android.content.Context import android.view.View import android.view.inputmethod.InputMethodManager -import androidx.lifecycle.LiveData -import androidx.work.* -import com.gyf.lib.service.NotificationWorker -import com.gyf.lib.service.ReceiverType import com.orhanobut.logger.Logger -import java.util.* object ContextUtil { - private var name = "pullNotification" - - private fun getNotification(context: Context): UUID { - val data = Data.Builder() - .putString("receiverClient", ReceiverType.Foreground.name) - .build() - val uploadWorkRequest: OneTimeWorkRequest = - OneTimeWorkRequestBuilder() - .setInputData(data) - .build() - Logger.i("构建任务") - val workManager = WorkManager.getInstance(context) - workManager.enqueueUniqueWork(name, ExistingWorkPolicy.KEEP, uploadWorkRequest) - return uploadWorkRequest.id - } - - fun getNotificationLiveData(context: Context): LiveData { - val id = getNotification(context = context) - return WorkManager.getInstance(context).getWorkInfoByIdLiveData(id) - } - - fun getNotification(context: Context, callback: (wordId: UUID) -> Unit) { - callback(getNotification(context = context)) - } - fun hideKeyBoard(activity: Activity?) { Logger.i("隐藏软键盘") diff --git a/lib/src/main/java/com/gyf/lib/util/TokenUtil.kt b/lib/src/main/java/com/gyf/lib/util/TokenUtil.kt index 7a69653..484c1c9 100644 --- a/lib/src/main/java/com/gyf/lib/util/TokenUtil.kt +++ b/lib/src/main/java/com/gyf/lib/util/TokenUtil.kt @@ -16,14 +16,19 @@ data class Token( @ColumnInfo val createTime: Long ) +abstract class ClientBaseVo { + abstract val token: Token + abstract val clientType: ClientType +} abstract class BaseToken { abstract val token: Token } data class OnlyToken( - override val token: Token = TokenManager.token ?: throw IllegalArgumentException("无法获取token") -) : BaseToken() + override val token: Token = TokenManager.token ?: throw IllegalArgumentException("无法获取token"), + override val clientType: ClientType +) : ClientBaseVo() @Dao interface TokenDao { diff --git a/lib/src/main/java/com/gyf/lib/util/vo.kt b/lib/src/main/java/com/gyf/lib/util/vo.kt new file mode 100644 index 0000000..4b5e8d6 --- /dev/null +++ b/lib/src/main/java/com/gyf/lib/util/vo.kt @@ -0,0 +1,27 @@ +package com.gyf.lib.util + + +data class NotificationVo(val title: String, val content: String, val id: Int) + +data class PageDto(val currentPage: Long, val pageSize: Int = 10) + +data class NotificationDto( + val receiverId: Int, + val receiverClient: ClientType, + override val token: Token, + val page: PageDto? = null, + override val clientType: ClientType = receiverClient +) : ClientBaseVo() + + +/** + * 客户端类型 + * + */ +enum class ClientType { + //前台 + Foreground, + + //后台 + Background +} \ No newline at end of file