1、账号绑定、解绑
2、账户管理、切换
3、切换、绑定、解绑后更新
This commit is contained in:
shenzuqiang 2026-02-28 11:33:37 +08:00
parent f78f459616
commit 1168061f72
14 changed files with 466 additions and 54 deletions

View File

@ -93,7 +93,9 @@ class MainActivity : ComponentActivity() {
var loginViewModel: LoginViewModel = viewModel() var loginViewModel: LoginViewModel = viewModel()
val context = LocalContext.current val context = LocalContext.current
var showSplash by remember { mutableStateOf(false) } 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) { LaunchedEffect(generalViewModel.agreementStatus.value) {
if (generalViewModel.agreementStatus.value == true){ if (generalViewModel.agreementStatus.value == true){
@ -111,13 +113,36 @@ class MainActivity : ComponentActivity() {
} }
} }
//初始化微信登录
//loginViewModel.initWXApi(this)
// 设置启动页显示条件 // 设置启动页显示条件
splashScreen.setKeepOnScreenCondition { splashScreen.setKeepOnScreenCondition {
splashViewModel.isLoading.value // 当为 true 时,启动页不消失 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 { AppTheme {
SplashScreenContent{ SplashScreenContent{
@ -148,10 +173,6 @@ class MainActivity : ComponentActivity() {
loginViewModel.requestUserConfig() loginViewModel.requestUserConfig()
//loginViewModel.initWXApi(this) //loginViewModel.initWXApi(this)
} }
// 初始化全局注销状态为 false
GlobalScope.launch {
GlobalStateManager(context).storeGlobalLogout(false)
}
val token = PreferenceUtil.getAccessToken() val token = PreferenceUtil.getAccessToken()
// 未登录,显示登录页 // 未登录,显示登录页

View File

@ -28,5 +28,10 @@ class UserInfoEntity(
val weixinAppId: String = "", val weixinAppId: String = "",
val weixinAppIdType: String = "", val weixinAppIdType: String = "",
val weixinAppOpenId: 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<String>,
) )

View File

@ -106,14 +106,22 @@ fun LoginScreen(navController: NavHostController? = null, generalViewModel: Gene
if (loginViewModel.loginState.value !=null && loginViewModel.loginState.value?.data?.token != null) { if (loginViewModel.loginState.value !=null && loginViewModel.loginState.value?.data?.token != null) {
//登录成功 //登录成功
PreferenceUtil.saveAccessToken(loginViewModel.loginState.value?.data?.token) PreferenceUtil.saveAccessToken(loginViewModel.loginState.value?.data?.token)
// 获取用户配置
loginViewModel.requestUserConfig()
// 获取用户信息 // 获取用户信息
loginViewModel.requestUserInfo() loginViewModel.requestUserInfo()
loginViewModel.setLogin(true) loginViewModel.setLogin(true)
Toast.makeText(context, "登录成功", Toast.LENGTH_SHORT).show() //更新登录状态
GlobalStateManager(context).storeGlobalLoginNotify(true)
//清理loginState //清理loginState
loginViewModel.loginState.value = null 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){ }else if(loginViewModel.loginState.value !=null && loginViewModel.loginState.value?.data?.token == null){
//登录失败 //登录失败
loginViewModel.setLogin(false) loginViewModel.setLogin(false)

View File

@ -214,10 +214,10 @@ fun MainScreen(generalViewModel: GeneralViewModel, loginViewModel: LoginViewMode
// 设置页面Setting // 设置页面Setting
composable(ScreenRoute.BindAccount.route) { composable(ScreenRoute.BindAccount.route) {
AccountBindScreen(navController = navController) AccountBindScreen(navController = navController, loginViewModel = loginViewModel)
} }
composable(ScreenRoute.ManagerAccount.route) { composable(ScreenRoute.ManagerAccount.route) {
AccountManagerScreen(navController = navController) AccountManagerScreen(navController = navController, loginViewModel = loginViewModel)
} }
composable(ScreenRoute.AboutMine.route) { composable(ScreenRoute.AboutMine.route) {
AboutScreen(navController = navController) AboutScreen(navController = navController)

View File

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

View File

@ -1,5 +1,6 @@
package com.img.rabbit.pages.screen package com.img.rabbit.pages.screen
import android.annotation.SuppressLint
import android.util.Log import android.util.Log
import android.widget.Toast import android.widget.Toast
import androidx.compose.foundation.Image import androidx.compose.foundation.Image
@ -21,9 +22,12 @@ import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip import androidx.compose.ui.draw.clip
@ -44,11 +48,17 @@ import androidx.navigation.compose.rememberNavController
import coil3.compose.AsyncImage import coil3.compose.AsyncImage
import com.img.rabbit.BuildConfig import com.img.rabbit.BuildConfig
import com.img.rabbit.R import com.img.rabbit.R
import com.img.rabbit.provider.storage.GlobalStateManager
import com.img.rabbit.provider.storage.PreferenceUtil import com.img.rabbit.provider.storage.PreferenceUtil
import com.img.rabbit.utils.AppUpdate import com.img.rabbit.utils.AppUpdate
import com.img.rabbit.viewmodel.GeneralViewModel import com.img.rabbit.viewmodel.GeneralViewModel
import com.img.rabbit.viewmodel.LoginViewModel 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 @Composable
fun MineScreen( fun MineScreen(
navController: NavHostController, navController: NavHostController,
@ -56,8 +66,12 @@ fun MineScreen(
) { ) {
val TAG = "Rabbit_Mine" val TAG = "Rabbit_Mine"
val context = LocalContext.current 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 vipMember by remember { mutableStateOf(false) }
val userInfo by remember { mutableStateOf(PreferenceUtil.getUserInfo()) } var userInfo by remember { mutableStateOf(PreferenceUtil.getUserInfo()) }
// 监听返回事件 // 监听返回事件
val currentBackStackEntry = navController.currentBackStackEntry 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( Box(
modifier = Modifier modifier = Modifier

View File

@ -1,5 +1,6 @@
package com.img.rabbit.pages.screen.mine package com.img.rabbit.pages.screen.mine
import android.annotation.SuppressLint
import androidx.compose.foundation.Image import androidx.compose.foundation.Image
import androidx.compose.foundation.background import androidx.compose.foundation.background
import androidx.compose.foundation.border import androidx.compose.foundation.border
@ -20,6 +21,7 @@ import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
@ -41,12 +43,15 @@ import androidx.navigation.NavHostController
import androidx.navigation.compose.rememberNavController import androidx.navigation.compose.rememberNavController
import com.img.rabbit.R import com.img.rabbit.R
import com.img.rabbit.pages.toolbar.TitleBar import com.img.rabbit.pages.toolbar.TitleBar
import com.img.rabbit.provider.storage.GlobalStateManager
import com.img.rabbit.utils.AppDataStoreUtils import com.img.rabbit.utils.AppDataStoreUtils
import com.img.rabbit.viewmodel.LoginViewModel import com.img.rabbit.viewmodel.LoginViewModel
@SuppressLint("UnrememberedMutableState")
@Composable @Composable
fun SettingScreen(navController: NavHostController, loginViewModel: LoginViewModel) { fun SettingScreen(navController: NavHostController, loginViewModel: LoginViewModel) {
val context = LocalContext.current val context = LocalContext.current
var globalLogin by mutableStateOf(GlobalStateManager(context).globalLoginNotifyFlow().collectAsState(initial = false))
var cacheDataSize by remember { mutableStateOf("正在计算...") } var cacheDataSize by remember { mutableStateOf("正在计算...") }
/* /*
LaunchedEffect(loginViewModel.logoutState.value) { LaunchedEffect(loginViewModel.logoutState.value) {
@ -73,6 +78,11 @@ fun SettingScreen(navController: NavHostController, loginViewModel: LoginViewMod
cacheDataSize = totalDataCacheSize cacheDataSize = totalDataCacheSize
} }
} }
if(globalLogin.value == true){
navController.popBackStack()
}
Scaffold{ Scaffold{
Column( Column(

View File

@ -46,13 +46,15 @@ import androidx.navigation.NavHostController
import androidx.navigation.compose.rememberNavController import androidx.navigation.compose.rememberNavController
import com.img.rabbit.R import com.img.rabbit.R
import com.img.rabbit.pages.toolbar.TitleBar 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.provider.storage.PreferenceUtil
import com.img.rabbit.viewmodel.AccountBindViewModel import com.img.rabbit.viewmodel.AccountBindViewModel
import com.img.rabbit.viewmodel.BindViewModel import com.img.rabbit.viewmodel.BindViewModel
import com.img.rabbit.viewmodel.LoginViewModel
@SuppressLint("UnrememberedMutableState") @SuppressLint("UnrememberedMutableState")
@Composable @Composable
fun AccountBindScreen(navController: NavHostController, viewModel: AccountBindViewModel = viewModel()) { fun AccountBindScreen(navController: NavHostController, viewModel: AccountBindViewModel = viewModel(), loginViewModel: LoginViewModel) {
val context = LocalContext.current val context = LocalContext.current
/** /**
* 0:m默认未绑定1:已绑定手机号去解绑2:已绑定微信去解绑 * 0:m默认未绑定1:已绑定手机号去解绑2:已绑定微信去解绑
@ -63,8 +65,15 @@ fun AccountBindScreen(navController: NavHostController, viewModel: AccountBindVi
LaunchedEffect(viewModel.unBindState.value) { LaunchedEffect(viewModel.unBindState.value) {
if(viewModel.unBindState.value != null){ if(viewModel.unBindState.value != null){
// 获取用户配置
loginViewModel.requestUserConfig()
// 获取用户信息
loginViewModel.requestUserInfo()
Toast.makeText(context, "解绑成功!", Toast.LENGTH_SHORT).show() Toast.makeText(context, "解绑成功!", Toast.LENGTH_SHORT).show()
viewModel.unBindState.value = null viewModel.unBindState.value = null
GlobalStateManager(context).storeGlobalUnBindNotify(true)
navController.popBackStack()
} }
} }
LaunchedEffect(viewModel.errorState.value) { LaunchedEffect(viewModel.errorState.value) {
@ -453,7 +462,7 @@ private fun UnBindPhoneDialog(
@Preview(showBackground = true) @Preview(showBackground = true)
@Composable @Composable
private fun PreviewAccountBindScreen(){ private fun PreviewAccountBindScreen(){
AccountBindScreen(navController = rememberNavController()) AccountBindScreen(navController = rememberNavController(), loginViewModel = LoginViewModel())
} }
@SuppressLint("UnrememberedMutableState") @SuppressLint("UnrememberedMutableState")

View File

@ -1,5 +1,7 @@
package com.img.rabbit.pages.screen.mine.setting 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.Image
import androidx.compose.foundation.background import androidx.compose.foundation.background
import androidx.compose.foundation.border import androidx.compose.foundation.border
@ -21,9 +23,11 @@ import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip 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.draw.shadow
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.painterResource
import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.Preview
@ -40,27 +45,60 @@ import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.navigation.NavController import androidx.navigation.NavController
import androidx.navigation.NavHostController import androidx.navigation.NavHostController
import androidx.navigation.compose.rememberNavController import androidx.navigation.compose.rememberNavController
import coil3.compose.AsyncImage
import com.img.rabbit.R 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.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.AccountManagerViewModel
import com.img.rabbit.viewmodel.LoginViewModel import com.img.rabbit.viewmodel.LoginViewModel
@SuppressLint("UnrememberedMutableState")
@Composable @Composable
fun AccountManagerScreen(navController: NavHostController, viewModel: AccountManagerViewModel = viewModel()) { fun AccountManagerScreen(navController: NavHostController, viewModel: AccountManagerViewModel = viewModel(), loginViewModel: LoginViewModel) {
val userList by remember { val context = LocalContext.current
mutableStateOf( var globalLogin by mutableStateOf(GlobalStateManager(context).globalLoginNotifyFlow().collectAsState(initial = false))
listOf( var showDialogStatus by mutableStateOf(false)
UserInfo(1, "张三", "https://cdn.batiao8.com/jietutu/logo.png","",true), var selectedUserInfo by mutableStateOf<UserInfoEntity?>(null)
UserInfo(2, "李四", "https://cdn.batiao8.com/jietutu/logo.png","",false),
UserInfo(3, "王五", "https://cdn.batiao8.com/jietutu/logo.png","",false), val userList by remember { viewModel.accountState }
)
)
}
LaunchedEffect(Unit) { LaunchedEffect(Unit) {
viewModel.requestAccount() 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{ Scaffold{
Box( Box(
modifier = Modifier.fillMaxSize() modifier = Modifier.fillMaxSize()
@ -94,11 +132,16 @@ fun AccountManagerScreen(navController: NavHostController, viewModel: AccountMan
Box( Box(
modifier = Modifier.fillMaxSize().padding(top = 55.dp, start = 17.dp, end = 17.dp) modifier = Modifier.fillMaxSize().padding(top = 55.dp, start = 17.dp, end = 17.dp)
){ ){
//TODO 设置内容 // 设置内容
LazyColumn { LazyColumn {
// 添加五个项目 // 添加五个项目
items(userList.size) { index -> items(userList?.size ?: 0) { index ->
ListItem(userList[index]) userList?.get(index)?.let {userInfoEntity ->
ListItem(userInfoEntity){
showDialogStatus = true
selectedUserInfo = userInfoEntity
}
}
} }
item { item {
AddItem(navController) 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 @Composable
private fun ListItem(item: UserInfo){ private fun ListItem(item: UserInfoEntity, onChange: (UserInfoEntity) -> Unit){
Column( Column(
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
@ -136,26 +198,28 @@ private fun ListItem(item: UserInfo){
indication = null, indication = null,
interactionSource = remember { MutableInteractionSource() } interactionSource = remember { MutableInteractionSource() }
) { ) {
//TODO 切换账号 // 切换账号
//navController.navigate("feedback") onChange(item)
}, },
verticalAlignment = Alignment.CenterVertically verticalAlignment = Alignment.CenterVertically
) { ) {
Image( AsyncImage(
painter = painterResource(id = R.mipmap.ic_launcher_logo), model = item.avater,
contentDescription = null, contentDescription = "用户头像",
contentScale = ContentScale.FillWidth, contentScale = ContentScale.FillWidth,
modifier = Modifier modifier = Modifier
.size(46.dp) .size(46.dp)
.align(Alignment.CenterVertically) .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( Column(
modifier = Modifier.weight(1f) modifier = Modifier.weight(1f)
){ ){
Text( Text(
text = "小林", text = item.name,
fontSize = 14.sp, fontSize = 14.sp,
fontWeight = FontWeight.Bold, fontWeight = FontWeight.Bold,
color = Color(0xFF1A1A1A), color = Color(0xFF1A1A1A),
@ -164,7 +228,7 @@ private fun ListItem(item: UserInfo){
.padding(start = 8.dp) .padding(start = 8.dp)
) )
Text( Text(
text = "ID:123456", text = "ID:${item.user_id}",
fontSize = 12.sp, fontSize = 12.sp,
color = Color(0xFF767676), color = Color(0xFF767676),
fontWeight = FontWeight.Normal, fontWeight = FontWeight.Normal,
@ -174,11 +238,13 @@ private fun ListItem(item: UserInfo){
) )
} }
Row( Row(
modifier = Modifier.wrapContentSize() modifier = Modifier.wrapContentSize()
) { ) {
val isLogin = PreferenceUtil.getUserInfo()?.user_id == item.user_id
Checkbox( Checkbox(
checked = item.login, checked = isLogin,
onCheckedChange = { isChecked -> onCheckedChange = { isChecked ->
//viewModel.setIsPolicyAgreement(isChecked) //viewModel.setIsPolicyAgreement(isChecked)
}, },
@ -187,13 +253,13 @@ private fun ListItem(item: UserInfo){
.scale(0.35f) .scale(0.35f)
.padding(start = 6.dp) .padding(start = 6.dp)
.background( .background(
if (item.login) Color(0xFF252525) if (isLogin) Color(0xFF252525)
else Color.Transparent, else Color.Transparent,
shape = RoundedCornerShape(36.dp) shape = RoundedCornerShape(36.dp)
) )
.border( .border(
width = 1.dp, width = 1.dp,
color = if (item.login) Color(0xFF252525) color = if (isLogin) Color(0xFF252525)
else Color(0xFFCCCCCC), else Color(0xFFCCCCCC),
shape = RoundedCornerShape(36.dp) shape = RoundedCornerShape(36.dp)
) )
@ -273,5 +339,5 @@ private fun AddItem(navController: NavController){
@Preview(showBackground = true) @Preview(showBackground = true)
@Composable @Composable
private fun PreviewAccountManagerScreen(){ private fun PreviewAccountManagerScreen(){
AccountManagerScreen(navController = rememberNavController()) AccountManagerScreen(navController = rememberNavController(), loginViewModel = viewModel())
} }

View File

@ -19,7 +19,9 @@ class GlobalStateManager(
companion object { companion object {
private val GLOBAL_LOADING = booleanPreferencesKey("global_loading") private val GLOBAL_LOADING = booleanPreferencesKey("global_loading")
private val GLOBAL_WX_AUTHORIZATION = stringPreferencesKey("global_wx_authorization") 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) { 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 -> context.storeData.edit { preferences ->
preferences[GLOBAL_LOGOUT] = value preferences[GLOBAL_LOGIN_NOTIFY] = value
} }
} }
fun globalLogoutFlow(): Flow<Boolean?> { fun globalLoginNotifyFlow(): Flow<Boolean?> {
return context.storeData.data.map { return context.storeData.data.map {
preferences -> 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<Boolean?> {
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<Boolean?> {
return context.storeData.data.map {
preferences ->
preferences[GLOBAL_LOGOUT_NOTIFY]
} }
} }

View File

@ -10,7 +10,7 @@ import com.img.rabbit.provider.storage.PreferenceUtil
import okhttp3.RequestBody.Companion.toRequestBody import okhttp3.RequestBody.Companion.toRequestBody
class AccountBindViewModel : BaseViewModel() { class AccountBindViewModel : BaseViewModel() {
// 登录状态 // 解绑状态
val unBindState = mutableStateOf<ResultVo<LoginInfoEntity>?>(null) val unBindState = mutableStateOf<ResultVo<LoginInfoEntity>?>(null)
// 错误状态 // 错误状态
val errorState = mutableStateOf<ErrorBean?>(null) val errorState = mutableStateOf<ErrorBean?>(null)

View File

@ -1,11 +1,21 @@
package com.img.rabbit.viewmodel package com.img.rabbit.viewmodel
import android.annotation.SuppressLint
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf
import com.google.gson.JsonObject
import com.img.rabbit.bean.local.ErrorBean 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 com.img.rabbit.provider.api.ApiManager
import okhttp3.RequestBody import com.img.rabbit.provider.api.ResultVo
import okhttp3.RequestBody.Companion.toRequestBody
class AccountManagerViewModel : BaseViewModel() { class AccountManagerViewModel : BaseViewModel() {
// 获取账号状态
@SuppressLint("MutableCollectionMutableState")
val accountState = mutableStateOf<MutableList<UserInfoEntity>?>(null)
@SuppressLint("MutableCollectionMutableState")
val switchState = mutableStateOf<ResultVo<LoginInfoEntity>?>(null)
// 错误状态 // 错误状态
val errorState = mutableStateOf<ErrorBean?>(null) val errorState = mutableStateOf<ErrorBean?>(null)
@ -14,9 +24,33 @@ class AccountManagerViewModel : BaseViewModel() {
mLaunch { mLaunch {
val response = ApiManager.serviceVo.account() val response = ApiManager.serviceVo.account()
if (response.status) { if (response.status) {
// TODO 处理获取账号列表 // 处理获取账号列表
accountState.value = response.data
}else{ }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 // 开始加载 isLoading.value = false // 开始加载
} }

View File

@ -408,7 +408,7 @@ class LoginViewModel : BaseViewModel() {
// 跳转登录页面 // 跳转登录页面
//restViewModel.intValue = 1 //restViewModel.intValue = 1
GlobalScope.launch { GlobalScope.launch {
GlobalStateManager(context).storeGlobalLogout(true) GlobalStateManager(context).storeGlobalLogoutNotify(true)
} }
} else { } else {
errorState.value = ErrorBean(response.code.toString(), response.message.ifEmpty { "退出登录失败" }) errorState.value = ErrorBean(response.code.toString(), response.message.ifEmpty { "退出登录失败" })

View File

@ -82,8 +82,8 @@ interface ServiceVo {
/** /**
* 获取账号列表 * 获取账号列表
*/ */
@POST("/api/user/account") @GET("/api/user/account")
suspend fun account(): ResultVo<Any>//@Query("scene") scene: String="account" suspend fun account(@Query("scene") scene: String="account"): ResultVo<MutableList<UserInfoEntity>?>
/** /**
* 上传文件 * 上传文件