fix:修复登录的 bug

This commit is contained in:
amos
2025-12-22 17:57:10 +08:00
parent e619aee36c
commit 4227de462f
5 changed files with 99 additions and 85 deletions

View File

@@ -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 {

View File

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

View File

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

View File

@@ -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 "注册失败,用户名可能已存在"

View File

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