fix:修复登录的 bug
This commit is contained in:
@@ -13,11 +13,11 @@ android {
|
||||
applicationId = "com.healthflow.app"
|
||||
minSdk = 26
|
||||
targetSdk = 35
|
||||
versionCode = 32
|
||||
versionName = "2.0.9"
|
||||
versionCode = 33
|
||||
versionName = "2.1.0"
|
||||
|
||||
buildConfigField("String", "API_BASE_URL", "\"https://health.amos.us.kg/api/\"")
|
||||
buildConfigField("int", "VERSION_CODE", "32")
|
||||
buildConfigField("int", "VERSION_CODE", "33")
|
||||
}
|
||||
|
||||
signingConfigs {
|
||||
|
||||
@@ -11,46 +11,42 @@ import androidx.compose.material3.Surface
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
import com.healthflow.app.data.UpdateManager
|
||||
import com.healthflow.app.data.api.ApiClient
|
||||
import com.healthflow.app.data.local.TokenManager
|
||||
import com.healthflow.app.data.model.User
|
||||
import com.healthflow.app.data.model.VersionInfo
|
||||
import com.healthflow.app.ui.components.UpdateDialog
|
||||
import com.healthflow.app.ui.navigation.MainNavigation
|
||||
import com.healthflow.app.ui.screen.LoginScreen
|
||||
import com.healthflow.app.ui.theme.HealthFlowTheme
|
||||
import com.healthflow.app.ui.viewmodel.AuthViewModel
|
||||
import kotlinx.coroutines.flow.first
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.runBlocking
|
||||
|
||||
class MainActivity : ComponentActivity() {
|
||||
private lateinit var tokenManager: TokenManager
|
||||
private lateinit var updateManager: UpdateManager
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
enableEdgeToEdge()
|
||||
|
||||
// 初始化 TokenManager
|
||||
val tokenManager = TokenManager(this)
|
||||
tokenManager = TokenManager(this)
|
||||
ApiClient.init(tokenManager)
|
||||
|
||||
// 初始化 UpdateManager
|
||||
updateManager = UpdateManager(this)
|
||||
|
||||
// 检查是否已登录
|
||||
val initialToken = runBlocking { tokenManager.token.first() }
|
||||
|
||||
setContent {
|
||||
val authViewModel: AuthViewModel = viewModel()
|
||||
val isLoggedIn by authViewModel.isLoggedIn.collectAsState()
|
||||
val user by authViewModel.user.collectAsState()
|
||||
var isLoggedIn by remember { mutableStateOf<Boolean?>(null) }
|
||||
var currentUser by remember { mutableStateOf<User?>(null) }
|
||||
var updateInfo by remember { mutableStateOf<VersionInfo?>(null) }
|
||||
|
||||
// 恢复会话 - 直接从本地读取,不需要网络请求
|
||||
LaunchedEffect(Unit) {
|
||||
if (initialToken != null) {
|
||||
authViewModel.checkAuth()
|
||||
val (token, user) = tokenManager.restoreSession()
|
||||
if (token != null && user != null) {
|
||||
currentUser = user
|
||||
isLoggedIn = true
|
||||
} else {
|
||||
isLoggedIn = false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -80,29 +76,44 @@ class MainActivity : ComponentActivity() {
|
||||
)
|
||||
}
|
||||
|
||||
if (isLoggedIn && user != null) {
|
||||
MainNavigation(
|
||||
user = user,
|
||||
onLogout = { authViewModel.logout() },
|
||||
onCheckUpdate = {
|
||||
lifecycleScope.launch {
|
||||
val info = updateManager.checkUpdate()
|
||||
if (info != null) {
|
||||
updateInfo = info
|
||||
} else {
|
||||
Toast.makeText(
|
||||
this@MainActivity,
|
||||
"已是最新版本",
|
||||
Toast.LENGTH_SHORT
|
||||
).show()
|
||||
when (isLoggedIn) {
|
||||
null -> {
|
||||
// 正在检查,什么都不显示(很快)
|
||||
}
|
||||
false -> {
|
||||
LoginScreen(
|
||||
onLoginSuccess = { user ->
|
||||
currentUser = user
|
||||
isLoggedIn = true
|
||||
}
|
||||
)
|
||||
}
|
||||
true -> {
|
||||
MainNavigation(
|
||||
user = currentUser,
|
||||
onLogout = {
|
||||
lifecycleScope.launch {
|
||||
tokenManager.clearToken()
|
||||
currentUser = null
|
||||
isLoggedIn = false
|
||||
}
|
||||
},
|
||||
onCheckUpdate = {
|
||||
lifecycleScope.launch {
|
||||
val info = updateManager.checkUpdate()
|
||||
if (info != null) {
|
||||
updateInfo = info
|
||||
} else {
|
||||
Toast.makeText(
|
||||
this@MainActivity,
|
||||
"已是最新版本",
|
||||
Toast.LENGTH_SHORT
|
||||
).show()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
} else {
|
||||
LoginScreen(
|
||||
onLoginSuccess = { authViewModel.checkAuth() }
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,29 +6,71 @@ import androidx.datastore.preferences.core.Preferences
|
||||
import androidx.datastore.preferences.core.edit
|
||||
import androidx.datastore.preferences.core.stringPreferencesKey
|
||||
import androidx.datastore.preferences.preferencesDataStore
|
||||
import com.healthflow.app.data.model.User
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.first
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.serialization.encodeToString
|
||||
import kotlinx.serialization.json.Json
|
||||
|
||||
private val Context.dataStore: DataStore<Preferences> by preferencesDataStore(name = "healthflow_prefs")
|
||||
|
||||
class TokenManager(private val context: Context) {
|
||||
companion object {
|
||||
private val TOKEN_KEY = stringPreferencesKey("auth_token")
|
||||
private val USER_KEY = stringPreferencesKey("user")
|
||||
}
|
||||
|
||||
val token: Flow<String?> = context.dataStore.data.map { preferences ->
|
||||
preferences[TOKEN_KEY]
|
||||
}
|
||||
|
||||
val user: Flow<User?> = context.dataStore.data.map { preferences ->
|
||||
preferences[USER_KEY]?.let {
|
||||
try {
|
||||
Json.decodeFromString<User>(it)
|
||||
} catch (e: Exception) {
|
||||
null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun saveAuth(token: String, user: User) {
|
||||
context.dataStore.edit { preferences ->
|
||||
preferences[TOKEN_KEY] = token
|
||||
preferences[USER_KEY] = Json.encodeToString(user)
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun saveToken(token: String) {
|
||||
context.dataStore.edit { preferences ->
|
||||
preferences[TOKEN_KEY] = token
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun updateUser(user: User) {
|
||||
context.dataStore.edit { preferences ->
|
||||
preferences[USER_KEY] = Json.encodeToString(user)
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun clearToken() {
|
||||
context.dataStore.edit { preferences ->
|
||||
preferences.remove(TOKEN_KEY)
|
||||
preferences.remove(USER_KEY)
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun restoreSession(): Pair<String?, User?> {
|
||||
val prefs = context.dataStore.data.first()
|
||||
val token = prefs[TOKEN_KEY]
|
||||
val user = prefs[USER_KEY]?.let {
|
||||
try {
|
||||
Json.decodeFromString<User>(it)
|
||||
} catch (e: Exception) {
|
||||
null
|
||||
}
|
||||
}
|
||||
return Pair(token, user)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,11 +23,12 @@ import androidx.compose.ui.unit.sp
|
||||
import com.healthflow.app.data.api.ApiClient
|
||||
import com.healthflow.app.data.model.LoginRequest
|
||||
import com.healthflow.app.data.model.RegisterRequest
|
||||
import com.healthflow.app.data.model.User
|
||||
import com.healthflow.app.ui.theme.*
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
@Composable
|
||||
fun LoginScreen(onLoginSuccess: () -> Unit) {
|
||||
fun LoginScreen(onLoginSuccess: (User) -> Unit) {
|
||||
var isLogin by remember { mutableStateOf(true) }
|
||||
var username by remember { mutableStateOf("") }
|
||||
var password by remember { mutableStateOf("") }
|
||||
@@ -174,9 +175,10 @@ fun LoginScreen(onLoginSuccess: () -> Unit) {
|
||||
}
|
||||
|
||||
if (response.isSuccessful) {
|
||||
response.body()?.let {
|
||||
ApiClient.getTokenManager().saveToken(it.token)
|
||||
onLoginSuccess()
|
||||
response.body()?.let { loginResponse ->
|
||||
// 保存 token 和 user 到本地
|
||||
ApiClient.getTokenManager().saveAuth(loginResponse.token, loginResponse.user)
|
||||
onLoginSuccess(loginResponse.user)
|
||||
}
|
||||
} else {
|
||||
errorMessage = if (isLogin) "用户名或密码错误" else "注册失败,用户名可能已存在"
|
||||
|
||||
@@ -1,41 +0,0 @@
|
||||
package com.healthflow.app.ui.viewmodel
|
||||
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.healthflow.app.data.api.ApiClient
|
||||
import com.healthflow.app.data.model.User
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
class AuthViewModel : ViewModel() {
|
||||
private val _isLoggedIn = MutableStateFlow(false)
|
||||
val isLoggedIn: StateFlow<Boolean> = _isLoggedIn
|
||||
|
||||
private val _user = MutableStateFlow<User?>(null)
|
||||
val user: StateFlow<User?> = _user
|
||||
|
||||
fun checkAuth() {
|
||||
viewModelScope.launch {
|
||||
try {
|
||||
val response = ApiClient.api.getProfile()
|
||||
if (response.isSuccessful) {
|
||||
_user.value = response.body()?.user
|
||||
_isLoggedIn.value = true
|
||||
} else {
|
||||
logout()
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
logout()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun logout() {
|
||||
viewModelScope.launch {
|
||||
ApiClient.getTokenManager().clearToken()
|
||||
_user.value = null
|
||||
_isLoggedIn.value = false
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user