From 1168061f72cd09c802795451f8e741dbd60c5491 Mon Sep 17 00:00:00 2001 From: shenzuqiang Date: Sat, 28 Feb 2026 11:33:37 +0800 Subject: [PATCH] =?UTF-8?q?Dev=EF=BC=9A=201=E3=80=81=E8=B4=A6=E5=8F=B7?= =?UTF-8?q?=E7=BB=91=E5=AE=9A=E3=80=81=E8=A7=A3=E7=BB=91=202=E3=80=81?= =?UTF-8?q?=E8=B4=A6=E6=88=B7=E7=AE=A1=E7=90=86=E3=80=81=E5=88=87=E6=8D=A2?= =?UTF-8?q?=203=E3=80=81=E5=88=87=E6=8D=A2=E3=80=81=E7=BB=91=E5=AE=9A?= =?UTF-8?q?=E3=80=81=E8=A7=A3=E7=BB=91=E5=90=8E=E6=9B=B4=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/com/img/rabbit/MainActivity.kt | 35 ++- .../rabbit/bean/response/UserInfoEntity.kt | 7 +- .../java/com/img/rabbit/pages/LoginPage.kt | 12 +- .../java/com/img/rabbit/pages/MainPage.kt | 4 +- .../com/img/rabbit/pages/dialog/TipsDialog.kt | 211 ++++++++++++++++++ .../com/img/rabbit/pages/screen/MineScreen.kt | 23 +- .../rabbit/pages/screen/mine/SettingScreen.kt | 10 + .../screen/mine/setting/AccountBindScreen.kt | 13 +- .../mine/setting/AccountManagerScreen.kt | 120 +++++++--- .../provider/storage/GlobalStateManager.kt | 37 ++- .../rabbit/viewmodel/AccountBindViewModel.kt | 2 +- .../viewmodel/AccountManagerViewModel.kt | 40 +++- .../img/rabbit/viewmodel/LoginViewModel.kt | 2 +- .../rabbit/viewmodel/interface/ServiceVo.kt | 4 +- 14 files changed, 466 insertions(+), 54 deletions(-) create mode 100644 app/src/main/java/com/img/rabbit/pages/dialog/TipsDialog.kt diff --git a/app/src/main/java/com/img/rabbit/MainActivity.kt b/app/src/main/java/com/img/rabbit/MainActivity.kt index af1f8e2..b176969 100644 --- a/app/src/main/java/com/img/rabbit/MainActivity.kt +++ b/app/src/main/java/com/img/rabbit/MainActivity.kt @@ -93,7 +93,9 @@ class MainActivity : ComponentActivity() { var loginViewModel: LoginViewModel = viewModel() val context = LocalContext.current var showSplash by remember { mutableStateOf(false) } - var globalLogout by mutableStateOf(GlobalStateManager(context).globalLogoutFlow().collectAsState(initial = false)) + var globalLogin by mutableStateOf(GlobalStateManager(context).globalLoginNotifyFlow().collectAsState(initial = false)) + var globalLogout by mutableStateOf(GlobalStateManager(context).globalLogoutNotifyFlow().collectAsState(initial = false)) + var globalUnBind by mutableStateOf(GlobalStateManager(context).globalUnBindNotifyFlow().collectAsState(initial = false)) LaunchedEffect(generalViewModel.agreementStatus.value) { if (generalViewModel.agreementStatus.value == true){ @@ -111,13 +113,36 @@ class MainActivity : ComponentActivity() { } } - //初始化微信登录 - //loginViewModel.initWXApi(this) // 设置启动页显示条件 splashScreen.setKeepOnScreenCondition { splashViewModel.isLoading.value // 当为 true 时,启动页不消失 } + // 登录成功后,2秒后自动更新状态 + if(globalLogin.value == true){ + GlobalScope.launch { + //延迟2秒,方便处理多有事件都收到通知 + delay(2*1000) + GlobalStateManager(context).storeGlobalLoginNotify(false) + } + } + // 退出成功后,2秒后自动更新状态 + if(globalLogout.value == true){ + GlobalScope.launch { + //延迟2秒,方便处理多有事件都收到通知 + delay(2*1000) + GlobalStateManager(context).storeGlobalLogoutNotify(false) + } + } + + // 解绑成功后,2秒后自动更新状态 + if(globalUnBind.value == true){ + GlobalScope.launch { + //延迟2秒,方便处理多有事件都收到通知 + delay(2*1000) + GlobalStateManager(context).storeGlobalUnBindNotify(false) + } + } AppTheme { SplashScreenContent{ @@ -148,10 +173,6 @@ class MainActivity : ComponentActivity() { loginViewModel.requestUserConfig() //loginViewModel.initWXApi(this) } - // 初始化全局注销状态为 false - GlobalScope.launch { - GlobalStateManager(context).storeGlobalLogout(false) - } val token = PreferenceUtil.getAccessToken() // 未登录,显示登录页 diff --git a/app/src/main/java/com/img/rabbit/bean/response/UserInfoEntity.kt b/app/src/main/java/com/img/rabbit/bean/response/UserInfoEntity.kt index 0c19cf3..1e12c97 100644 --- a/app/src/main/java/com/img/rabbit/bean/response/UserInfoEntity.kt +++ b/app/src/main/java/com/img/rabbit/bean/response/UserInfoEntity.kt @@ -28,5 +28,10 @@ class UserInfoEntity( val weixinAppId: String = "", val weixinAppIdType: String = "", val weixinAppOpenId: String = "", - val weixinOpenId: String = "" + val weixinOpenId: String = "", + + //目前由/api/user/account提供 + val vip_type: Int = 0, + val create_time: String = "", + val bind: ArrayList, ) \ No newline at end of file diff --git a/app/src/main/java/com/img/rabbit/pages/LoginPage.kt b/app/src/main/java/com/img/rabbit/pages/LoginPage.kt index ba05d00..e20fb6a 100644 --- a/app/src/main/java/com/img/rabbit/pages/LoginPage.kt +++ b/app/src/main/java/com/img/rabbit/pages/LoginPage.kt @@ -106,14 +106,22 @@ fun LoginScreen(navController: NavHostController? = null, generalViewModel: Gene if (loginViewModel.loginState.value !=null && loginViewModel.loginState.value?.data?.token != null) { //登录成功 PreferenceUtil.saveAccessToken(loginViewModel.loginState.value?.data?.token) + // 获取用户配置 + loginViewModel.requestUserConfig() // 获取用户信息 loginViewModel.requestUserInfo() loginViewModel.setLogin(true) - Toast.makeText(context, "登录成功", Toast.LENGTH_SHORT).show() - + //更新登录状态 + GlobalStateManager(context).storeGlobalLoginNotify(true) //清理loginState loginViewModel.loginState.value = null + //提示登录成功 + Toast.makeText(context, "登录成功", Toast.LENGTH_SHORT).show() + // 当允许返回上一页时,登录成功后,返回上一页 + if(isVisibilityBreak){ + navController?.popBackStack() + } }else if(loginViewModel.loginState.value !=null && loginViewModel.loginState.value?.data?.token == null){ //登录失败 loginViewModel.setLogin(false) diff --git a/app/src/main/java/com/img/rabbit/pages/MainPage.kt b/app/src/main/java/com/img/rabbit/pages/MainPage.kt index e10a142..6cd64cd 100644 --- a/app/src/main/java/com/img/rabbit/pages/MainPage.kt +++ b/app/src/main/java/com/img/rabbit/pages/MainPage.kt @@ -214,10 +214,10 @@ fun MainScreen(generalViewModel: GeneralViewModel, loginViewModel: LoginViewMode // 设置页面(Setting) composable(ScreenRoute.BindAccount.route) { - AccountBindScreen(navController = navController) + AccountBindScreen(navController = navController, loginViewModel = loginViewModel) } composable(ScreenRoute.ManagerAccount.route) { - AccountManagerScreen(navController = navController) + AccountManagerScreen(navController = navController, loginViewModel = loginViewModel) } composable(ScreenRoute.AboutMine.route) { AboutScreen(navController = navController) diff --git a/app/src/main/java/com/img/rabbit/pages/dialog/TipsDialog.kt b/app/src/main/java/com/img/rabbit/pages/dialog/TipsDialog.kt new file mode 100644 index 0000000..59b6d5c --- /dev/null +++ b/app/src/main/java/com/img/rabbit/pages/dialog/TipsDialog.kt @@ -0,0 +1,211 @@ +package com.img.rabbit.pages.dialog + +import androidx.compose.foundation.Image +import androidx.compose.foundation.background +import androidx.compose.foundation.border +import androidx.compose.foundation.clickable +import androidx.compose.foundation.interaction.MutableInteractionSource +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.width +import androidx.compose.foundation.layout.wrapContentHeight +import androidx.compose.foundation.layout.wrapContentSize +import androidx.compose.foundation.layout.wrapContentWidth +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.remember +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.layout.ContentScale +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import com.img.rabbit.R + +@Composable +fun TipsDialog( + title: String?, + content1: String?, + content2: String?, + cancel: String="取消", + confirm: String="确定", + data: Any? = null, + onStatusChange: (state: Boolean, isCancel:Boolean, data: Any?) -> Unit +){ + Column( + modifier = Modifier + .fillMaxSize() + .background(Color(0x80000000)) + .clickable( + indication = null, + interactionSource = remember { MutableInteractionSource() } + ) { + onStatusChange(false, true, data) + }, + verticalArrangement = Arrangement.Center + ){ + Box( + modifier = Modifier + .fillMaxWidth() + .wrapContentHeight() + .padding(horizontal = 36.dp) + .background(Color.White, shape = RoundedCornerShape(26.dp)) + .align(Alignment.CenterHorizontally) + .clickable( + indication = null, + interactionSource = remember { MutableInteractionSource() } + ) { + //什么都不用做,只是解决点击穿透问题 + } + ) { + Image( + painter = painterResource(id = R.mipmap.ic_dialog_top_mask1), + contentDescription = null, + contentScale = ContentScale.FillWidth, + modifier = Modifier + .fillMaxWidth() + ) + + Column( + modifier = Modifier + .fillMaxWidth() + .wrapContentHeight() + .padding(top = 46.dp) + ) { + if(!title.isNullOrEmpty()){ + Text( + text = title, + fontSize = 18.sp, + fontWeight = FontWeight.Bold, + color = Color(0xFF1A1A1A), + modifier = Modifier + .wrapContentSize() + .align(Alignment.CenterHorizontally) + ) + } + + Box( + modifier = Modifier + .fillMaxWidth() + .height(14.dp) + ) + + if(!content1.isNullOrEmpty()){ + Text( + text = content1, + fontSize = 12.sp, + fontWeight = FontWeight.Normal, + color = Color(0xFF767676), + modifier = Modifier + .wrapContentSize() + .align(Alignment.CenterHorizontally) + ) + } + + if(!content2.isNullOrEmpty()){ + Text( + text = content2, + fontSize = 12.sp, + fontWeight = FontWeight.Normal, + color = Color(0xFF767676), + modifier = Modifier + .wrapContentSize() + .align(Alignment.CenterHorizontally) + ) + } + + Box( + modifier = Modifier + .fillMaxWidth() + .height(16.dp) + ) + + //取消 + Row( + modifier = Modifier + .fillMaxWidth() + .padding(start = 18.dp, end = 18.dp, bottom = 20.dp) + ) { + Box( + modifier = Modifier + .fillMaxWidth() + .wrapContentHeight() + .weight(1f) + .background( + Color(0x00000000), + shape = RoundedCornerShape(359.dp), + ) + .border( + width = 1.dp, + color = Color(0xFF000000), + shape = RoundedCornerShape(359.dp) + ) + .clickable( + indication = null, + interactionSource = remember { MutableInteractionSource() } + ) { + onStatusChange(false, true, data) + } + ) { + Text( + cancel, + color = Color(0xFF1A1A1A), + fontSize = 16.sp, + fontWeight = FontWeight.Bold, + modifier = Modifier + .wrapContentWidth() + .wrapContentHeight() + .padding(vertical = 12.dp) + .align(Alignment.Center) + ) + } + + Box( + modifier = Modifier + .width(11.dp) + ) + + //确定 + Box( + modifier = Modifier + .fillMaxWidth() + .wrapContentHeight() + .weight(1f) + .background( + Color(0xFF252525), + shape = RoundedCornerShape(359.dp), + ) + .clickable( + indication = null, + interactionSource = remember { MutableInteractionSource() } + ) { + onStatusChange(false, false, data) + } + ) { + Text( + confirm, + color = Color(0xFFC2FF43), + fontSize = 16.sp, + fontWeight = FontWeight.Bold, + modifier = Modifier + .wrapContentWidth() + .wrapContentHeight() + .padding(vertical = 12.dp) + .align(Alignment.Center) + ) + } + } + } + + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/img/rabbit/pages/screen/MineScreen.kt b/app/src/main/java/com/img/rabbit/pages/screen/MineScreen.kt index 30b0888..941fe91 100644 --- a/app/src/main/java/com/img/rabbit/pages/screen/MineScreen.kt +++ b/app/src/main/java/com/img/rabbit/pages/screen/MineScreen.kt @@ -1,5 +1,6 @@ package com.img.rabbit.pages.screen +import android.annotation.SuppressLint import android.util.Log import android.widget.Toast import androidx.compose.foundation.Image @@ -21,9 +22,12 @@ import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember +import androidx.compose.runtime.rememberCoroutineScope +import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip @@ -44,11 +48,17 @@ import androidx.navigation.compose.rememberNavController import coil3.compose.AsyncImage import com.img.rabbit.BuildConfig import com.img.rabbit.R +import com.img.rabbit.provider.storage.GlobalStateManager import com.img.rabbit.provider.storage.PreferenceUtil import com.img.rabbit.utils.AppUpdate import com.img.rabbit.viewmodel.GeneralViewModel import com.img.rabbit.viewmodel.LoginViewModel +import kotlinx.coroutines.GlobalScope +import kotlinx.coroutines.coroutineScope +import kotlinx.coroutines.delay +import kotlinx.coroutines.launch +@SuppressLint("UnrememberedMutableState", "CoroutineCreationDuringComposition") @Composable fun MineScreen( navController: NavHostController, @@ -56,8 +66,12 @@ fun MineScreen( ) { val TAG = "Rabbit_Mine" val context = LocalContext.current + val scope = rememberCoroutineScope() + var globalLogin by mutableStateOf(GlobalStateManager(context).globalLoginNotifyFlow().collectAsState(initial = false)) + var globalUnBind by mutableStateOf(GlobalStateManager(context).globalUnBindNotifyFlow().collectAsState(initial = false)) + val vipMember by remember { mutableStateOf(false) } - val userInfo by remember { mutableStateOf(PreferenceUtil.getUserInfo()) } + var userInfo by remember { mutableStateOf(PreferenceUtil.getUserInfo()) } // 监听返回事件 val currentBackStackEntry = navController.currentBackStackEntry @@ -70,6 +84,13 @@ fun MineScreen( } } + //刷新用户信息 + if(globalLogin.value == true || globalUnBind.value == true){ + scope.launch { + delay(300) + userInfo = PreferenceUtil.getUserInfo() + } + } Box( modifier = Modifier diff --git a/app/src/main/java/com/img/rabbit/pages/screen/mine/SettingScreen.kt b/app/src/main/java/com/img/rabbit/pages/screen/mine/SettingScreen.kt index ea3fec7..00afda3 100644 --- a/app/src/main/java/com/img/rabbit/pages/screen/mine/SettingScreen.kt +++ b/app/src/main/java/com/img/rabbit/pages/screen/mine/SettingScreen.kt @@ -1,5 +1,6 @@ package com.img.rabbit.pages.screen.mine +import android.annotation.SuppressLint import androidx.compose.foundation.Image import androidx.compose.foundation.background import androidx.compose.foundation.border @@ -20,6 +21,7 @@ import androidx.compose.material3.Scaffold import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember @@ -41,12 +43,15 @@ import androidx.navigation.NavHostController import androidx.navigation.compose.rememberNavController import com.img.rabbit.R import com.img.rabbit.pages.toolbar.TitleBar +import com.img.rabbit.provider.storage.GlobalStateManager import com.img.rabbit.utils.AppDataStoreUtils import com.img.rabbit.viewmodel.LoginViewModel +@SuppressLint("UnrememberedMutableState") @Composable fun SettingScreen(navController: NavHostController, loginViewModel: LoginViewModel) { val context = LocalContext.current + var globalLogin by mutableStateOf(GlobalStateManager(context).globalLoginNotifyFlow().collectAsState(initial = false)) var cacheDataSize by remember { mutableStateOf("正在计算...") } /* LaunchedEffect(loginViewModel.logoutState.value) { @@ -73,6 +78,11 @@ fun SettingScreen(navController: NavHostController, loginViewModel: LoginViewMod cacheDataSize = totalDataCacheSize } } + if(globalLogin.value == true){ + navController.popBackStack() + } + + Scaffold{ Column( diff --git a/app/src/main/java/com/img/rabbit/pages/screen/mine/setting/AccountBindScreen.kt b/app/src/main/java/com/img/rabbit/pages/screen/mine/setting/AccountBindScreen.kt index c45bc10..82a5e31 100644 --- a/app/src/main/java/com/img/rabbit/pages/screen/mine/setting/AccountBindScreen.kt +++ b/app/src/main/java/com/img/rabbit/pages/screen/mine/setting/AccountBindScreen.kt @@ -46,13 +46,15 @@ import androidx.navigation.NavHostController import androidx.navigation.compose.rememberNavController import com.img.rabbit.R import com.img.rabbit.pages.toolbar.TitleBar +import com.img.rabbit.provider.storage.GlobalStateManager import com.img.rabbit.provider.storage.PreferenceUtil import com.img.rabbit.viewmodel.AccountBindViewModel import com.img.rabbit.viewmodel.BindViewModel +import com.img.rabbit.viewmodel.LoginViewModel @SuppressLint("UnrememberedMutableState") @Composable -fun AccountBindScreen(navController: NavHostController, viewModel: AccountBindViewModel = viewModel()) { +fun AccountBindScreen(navController: NavHostController, viewModel: AccountBindViewModel = viewModel(), loginViewModel: LoginViewModel) { val context = LocalContext.current /** * 0:m默认未绑定,1:已绑定手机号(去解绑),2:已绑定微信(去解绑) @@ -63,8 +65,15 @@ fun AccountBindScreen(navController: NavHostController, viewModel: AccountBindVi LaunchedEffect(viewModel.unBindState.value) { if(viewModel.unBindState.value != null){ + // 获取用户配置 + loginViewModel.requestUserConfig() + // 获取用户信息 + loginViewModel.requestUserInfo() + Toast.makeText(context, "解绑成功!", Toast.LENGTH_SHORT).show() viewModel.unBindState.value = null + GlobalStateManager(context).storeGlobalUnBindNotify(true) + navController.popBackStack() } } LaunchedEffect(viewModel.errorState.value) { @@ -453,7 +462,7 @@ private fun UnBindPhoneDialog( @Preview(showBackground = true) @Composable private fun PreviewAccountBindScreen(){ - AccountBindScreen(navController = rememberNavController()) + AccountBindScreen(navController = rememberNavController(), loginViewModel = LoginViewModel()) } @SuppressLint("UnrememberedMutableState") diff --git a/app/src/main/java/com/img/rabbit/pages/screen/mine/setting/AccountManagerScreen.kt b/app/src/main/java/com/img/rabbit/pages/screen/mine/setting/AccountManagerScreen.kt index c0694b3..ac0a197 100644 --- a/app/src/main/java/com/img/rabbit/pages/screen/mine/setting/AccountManagerScreen.kt +++ b/app/src/main/java/com/img/rabbit/pages/screen/mine/setting/AccountManagerScreen.kt @@ -1,5 +1,7 @@ package com.img.rabbit.pages.screen.mine.setting +import android.annotation.SuppressLint +import android.widget.Toast import androidx.compose.foundation.Image import androidx.compose.foundation.background import androidx.compose.foundation.border @@ -21,9 +23,11 @@ import androidx.compose.material3.Scaffold import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip @@ -31,6 +35,7 @@ import androidx.compose.ui.draw.scale import androidx.compose.ui.draw.shadow import androidx.compose.ui.graphics.Color import androidx.compose.ui.layout.ContentScale +import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.painterResource import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.tooling.preview.Preview @@ -40,27 +45,60 @@ import androidx.lifecycle.viewmodel.compose.viewModel import androidx.navigation.NavController import androidx.navigation.NavHostController import androidx.navigation.compose.rememberNavController +import coil3.compose.AsyncImage import com.img.rabbit.R -import com.img.rabbit.bean.local.UserInfo +import com.img.rabbit.bean.response.UserInfoEntity +import com.img.rabbit.pages.dialog.TipsDialog import com.img.rabbit.pages.toolbar.TitleBar +import com.img.rabbit.provider.storage.GlobalStateManager +import com.img.rabbit.provider.storage.PreferenceUtil import com.img.rabbit.viewmodel.AccountManagerViewModel import com.img.rabbit.viewmodel.LoginViewModel +@SuppressLint("UnrememberedMutableState") @Composable -fun AccountManagerScreen(navController: NavHostController, viewModel: AccountManagerViewModel = viewModel()) { - val userList by remember { - mutableStateOf( - listOf( - UserInfo(1, "张三", "https://cdn.batiao8.com/jietutu/logo.png","",true), - UserInfo(2, "李四", "https://cdn.batiao8.com/jietutu/logo.png","",false), - UserInfo(3, "王五", "https://cdn.batiao8.com/jietutu/logo.png","",false), - ) - ) - } +fun AccountManagerScreen(navController: NavHostController, viewModel: AccountManagerViewModel = viewModel(), loginViewModel: LoginViewModel) { + val context = LocalContext.current + var globalLogin by mutableStateOf(GlobalStateManager(context).globalLoginNotifyFlow().collectAsState(initial = false)) + var showDialogStatus by mutableStateOf(false) + var selectedUserInfo by mutableStateOf(null) + + val userList by remember { viewModel.accountState } + LaunchedEffect(Unit) { viewModel.requestAccount() } + if(globalLogin.value == true){ + viewModel.requestAccount() + } + + LaunchedEffect(viewModel.switchState.value) { + if (viewModel.switchState.value != null && viewModel.switchState.value?.data?.token != null) { + // 切换账号成功 + PreferenceUtil.saveAccessToken(viewModel.switchState.value?.data?.token) + // 获取用户配置 + loginViewModel.requestUserConfig() + // 获取用户信息 + loginViewModel.requestUserInfo() + + loginViewModel.setLogin(true) + //更新登录状态 + GlobalStateManager(context).storeGlobalLoginNotify(true) + //清理loginState + loginViewModel.loginState.value = null + Toast.makeText(context, "切换账号成功!", Toast.LENGTH_SHORT).show() + + navController.popBackStack() + } + } + LaunchedEffect(viewModel.errorState.value) { + if(viewModel.errorState.value != null){ + Toast.makeText(context, "切换账号失败...", Toast.LENGTH_SHORT).show() + viewModel.errorState.value = null + } + } + Scaffold{ Box( modifier = Modifier.fillMaxSize() @@ -94,11 +132,16 @@ fun AccountManagerScreen(navController: NavHostController, viewModel: AccountMan Box( modifier = Modifier.fillMaxSize().padding(top = 55.dp, start = 17.dp, end = 17.dp) ){ - //TODO 设置内容 + // 设置内容 LazyColumn { // 添加五个项目 - items(userList.size) { index -> - ListItem(userList[index]) + items(userList?.size ?: 0) { index -> + userList?.get(index)?.let {userInfoEntity -> + ListItem(userInfoEntity){ + showDialogStatus = true + selectedUserInfo = userInfoEntity + } + } } item { AddItem(navController) @@ -106,12 +149,31 @@ fun AccountManagerScreen(navController: NavHostController, viewModel: AccountMan } } } + if(showDialogStatus){ + TipsDialog( + title = "您确定要切换账户吗?", + content1 = "", + content2 = null, + cancel = "取消", + confirm = "确定", + data = selectedUserInfo, + onStatusChange = { status, isCancel, data -> + if(!isCancel && data != null){ + // 切换账号 + viewModel.switchAccount((data as UserInfoEntity).user_id) + } + showDialogStatus = status + } + ) + } } } + + } @Composable -private fun ListItem(item: UserInfo){ +private fun ListItem(item: UserInfoEntity, onChange: (UserInfoEntity) -> Unit){ Column( modifier = Modifier .fillMaxWidth() @@ -136,26 +198,28 @@ private fun ListItem(item: UserInfo){ indication = null, interactionSource = remember { MutableInteractionSource() } ) { - //TODO 切换账号 - //navController.navigate("feedback") + // 切换账号 + onChange(item) }, verticalAlignment = Alignment.CenterVertically ) { - Image( - painter = painterResource(id = R.mipmap.ic_launcher_logo), - contentDescription = null, + AsyncImage( + model = item.avater, + contentDescription = "用户头像", contentScale = ContentScale.FillWidth, modifier = Modifier .size(46.dp) .align(Alignment.CenterVertically) - .clip(RoundedCornerShape(8.dp)) + .clip(RoundedCornerShape(8.dp)), + fallback = painterResource(id = R.mipmap.ic_launcher_logo), + error = painterResource(id = R.mipmap.ic_launcher_logo) ) Column( modifier = Modifier.weight(1f) ){ Text( - text = "小林", + text = item.name, fontSize = 14.sp, fontWeight = FontWeight.Bold, color = Color(0xFF1A1A1A), @@ -164,7 +228,7 @@ private fun ListItem(item: UserInfo){ .padding(start = 8.dp) ) Text( - text = "ID:123456", + text = "ID:${item.user_id}", fontSize = 12.sp, color = Color(0xFF767676), fontWeight = FontWeight.Normal, @@ -174,11 +238,13 @@ private fun ListItem(item: UserInfo){ ) } + Row( modifier = Modifier.wrapContentSize() ) { + val isLogin = PreferenceUtil.getUserInfo()?.user_id == item.user_id Checkbox( - checked = item.login, + checked = isLogin, onCheckedChange = { isChecked -> //viewModel.setIsPolicyAgreement(isChecked) }, @@ -187,13 +253,13 @@ private fun ListItem(item: UserInfo){ .scale(0.35f) .padding(start = 6.dp) .background( - if (item.login) Color(0xFF252525) + if (isLogin) Color(0xFF252525) else Color.Transparent, shape = RoundedCornerShape(36.dp) ) .border( width = 1.dp, - color = if (item.login) Color(0xFF252525) + color = if (isLogin) Color(0xFF252525) else Color(0xFFCCCCCC), shape = RoundedCornerShape(36.dp) ) @@ -273,5 +339,5 @@ private fun AddItem(navController: NavController){ @Preview(showBackground = true) @Composable private fun PreviewAccountManagerScreen(){ - AccountManagerScreen(navController = rememberNavController()) + AccountManagerScreen(navController = rememberNavController(), loginViewModel = viewModel()) } \ No newline at end of file diff --git a/app/src/main/java/com/img/rabbit/provider/storage/GlobalStateManager.kt b/app/src/main/java/com/img/rabbit/provider/storage/GlobalStateManager.kt index b2e751e..e207a6b 100644 --- a/app/src/main/java/com/img/rabbit/provider/storage/GlobalStateManager.kt +++ b/app/src/main/java/com/img/rabbit/provider/storage/GlobalStateManager.kt @@ -19,7 +19,9 @@ class GlobalStateManager( companion object { private val GLOBAL_LOADING = booleanPreferencesKey("global_loading") private val GLOBAL_WX_AUTHORIZATION = stringPreferencesKey("global_wx_authorization") - private val GLOBAL_LOGOUT = booleanPreferencesKey("global_logout") + private val GLOBAL_LOGIN_NOTIFY = booleanPreferencesKey("global_login_notify") + private val GLOBAL_LOGOUT_NOTIFY = booleanPreferencesKey("global_logout_notify") + private val GLOBAL_UNBIND_NOTIFY = booleanPreferencesKey("global_unbind_notify") } suspend fun storeGlobalLoading(value: Boolean) { @@ -49,15 +51,40 @@ class GlobalStateManager( } - suspend fun storeGlobalLogout(value: Boolean) { + suspend fun storeGlobalLoginNotify(value: Boolean) { context.storeData.edit { preferences -> - preferences[GLOBAL_LOGOUT] = value + preferences[GLOBAL_LOGIN_NOTIFY] = value } } - fun globalLogoutFlow(): Flow { + fun globalLoginNotifyFlow(): Flow { return context.storeData.data.map { preferences -> - preferences[GLOBAL_LOGOUT] + preferences[GLOBAL_LOGIN_NOTIFY] + } + } + + suspend fun storeGlobalUnBindNotify(value: Boolean) { + context.storeData.edit { preferences -> + preferences[GLOBAL_UNBIND_NOTIFY] = value + } + } + fun globalUnBindNotifyFlow(): Flow { + return context.storeData.data.map { + preferences -> + preferences[GLOBAL_UNBIND_NOTIFY] + } + } + + + suspend fun storeGlobalLogoutNotify(value: Boolean) { + context.storeData.edit { preferences -> + preferences[GLOBAL_LOGOUT_NOTIFY] = value + } + } + fun globalLogoutNotifyFlow(): Flow { + return context.storeData.data.map { + preferences -> + preferences[GLOBAL_LOGOUT_NOTIFY] } } diff --git a/app/src/main/java/com/img/rabbit/viewmodel/AccountBindViewModel.kt b/app/src/main/java/com/img/rabbit/viewmodel/AccountBindViewModel.kt index 8dadbfa..65dd29c 100644 --- a/app/src/main/java/com/img/rabbit/viewmodel/AccountBindViewModel.kt +++ b/app/src/main/java/com/img/rabbit/viewmodel/AccountBindViewModel.kt @@ -10,7 +10,7 @@ import com.img.rabbit.provider.storage.PreferenceUtil import okhttp3.RequestBody.Companion.toRequestBody class AccountBindViewModel : BaseViewModel() { - // 登录状态 + // 解绑状态 val unBindState = mutableStateOf?>(null) // 错误状态 val errorState = mutableStateOf(null) diff --git a/app/src/main/java/com/img/rabbit/viewmodel/AccountManagerViewModel.kt b/app/src/main/java/com/img/rabbit/viewmodel/AccountManagerViewModel.kt index 5792986..e3988d6 100644 --- a/app/src/main/java/com/img/rabbit/viewmodel/AccountManagerViewModel.kt +++ b/app/src/main/java/com/img/rabbit/viewmodel/AccountManagerViewModel.kt @@ -1,11 +1,21 @@ package com.img.rabbit.viewmodel +import android.annotation.SuppressLint import androidx.compose.runtime.mutableStateOf +import com.google.gson.JsonObject import com.img.rabbit.bean.local.ErrorBean +import com.img.rabbit.bean.response.LoginInfoEntity +import com.img.rabbit.bean.response.UserInfoEntity import com.img.rabbit.provider.api.ApiManager -import okhttp3.RequestBody +import com.img.rabbit.provider.api.ResultVo +import okhttp3.RequestBody.Companion.toRequestBody class AccountManagerViewModel : BaseViewModel() { + // 获取账号状态 + @SuppressLint("MutableCollectionMutableState") + val accountState = mutableStateOf?>(null) + @SuppressLint("MutableCollectionMutableState") + val switchState = mutableStateOf?>(null) // 错误状态 val errorState = mutableStateOf(null) @@ -14,9 +24,33 @@ class AccountManagerViewModel : BaseViewModel() { mLaunch { val response = ApiManager.serviceVo.account() if (response.status) { - // TODO 处理获取账号列表 + // 处理获取账号列表 + accountState.value = response.data }else{ - errorState.value = ErrorBean(response.code.toString(), response.message.ifEmpty { "提交失败..." }) + errorState.value = ErrorBean(response.code.toString(), response.message.ifEmpty { "获取账号失败..." }) + } + isLoading.value = false // 开始加载 + } + } + + fun switchAccount(userId: String) { + isLoading.value = true // 开始加载 + + // 调用 API 获取数据 + val jsonSwitch = JsonObject() + jsonSwitch.addProperty("user_id", userId) + + val jsonObject = JsonObject() + jsonObject.addProperty("type", "device") + jsonObject.add("data", jsonSwitch) + + mLaunch { + val response = ApiManager.serviceVo.login(jsonObject.toString().toRequestBody()) + if (response.status) { + // 处理切换账号 + switchState.value = response + }else{ + errorState.value = ErrorBean(response.code.toString(), response.message.ifEmpty { "切换账号失败..." }) } isLoading.value = false // 开始加载 } diff --git a/app/src/main/java/com/img/rabbit/viewmodel/LoginViewModel.kt b/app/src/main/java/com/img/rabbit/viewmodel/LoginViewModel.kt index 658165e..444aa70 100644 --- a/app/src/main/java/com/img/rabbit/viewmodel/LoginViewModel.kt +++ b/app/src/main/java/com/img/rabbit/viewmodel/LoginViewModel.kt @@ -408,7 +408,7 @@ class LoginViewModel : BaseViewModel() { // 跳转登录页面 //restViewModel.intValue = 1 GlobalScope.launch { - GlobalStateManager(context).storeGlobalLogout(true) + GlobalStateManager(context).storeGlobalLogoutNotify(true) } } else { errorState.value = ErrorBean(response.code.toString(), response.message.ifEmpty { "退出登录失败" }) diff --git a/app/src/main/java/com/img/rabbit/viewmodel/interface/ServiceVo.kt b/app/src/main/java/com/img/rabbit/viewmodel/interface/ServiceVo.kt index aaa60cd..843df65 100644 --- a/app/src/main/java/com/img/rabbit/viewmodel/interface/ServiceVo.kt +++ b/app/src/main/java/com/img/rabbit/viewmodel/interface/ServiceVo.kt @@ -82,8 +82,8 @@ interface ServiceVo { /** * 获取账号列表 */ - @POST("/api/user/account") - suspend fun account(): ResultVo//@Query("scene") scene: String="account" + @GET("/api/user/account") + suspend fun account(@Query("scene") scene: String="account"): ResultVo?> /** * 上传文件