From b3d00e12fca414914c1d5b49120ff06abfd764e9 Mon Sep 17 00:00:00 2001 From: Eric85710 Date: Wed, 1 Jul 2026 17:15:02 +0800 Subject: [PATCH] dm-184 --- .../example/login_v3/auth/login/Login_Page.kt | 8 ++++-- .../data/repository/basic/Token_Auth.kt | 6 +++++ .../login_v3/navigation/MainViewModel.kt | 26 +++++++++++++++---- .../login_v3/navigation/nav_controller.kt | 6 ++++- 4 files changed, 38 insertions(+), 8 deletions(-) diff --git a/app/src/main/java/com/example/login_v3/auth/login/Login_Page.kt b/app/src/main/java/com/example/login_v3/auth/login/Login_Page.kt index 1c4be78..245215a 100644 --- a/app/src/main/java/com/example/login_v3/auth/login/Login_Page.kt +++ b/app/src/main/java/com/example/login_v3/auth/login/Login_Page.kt @@ -63,6 +63,7 @@ import kotlin.text.ifEmpty @Composable fun LoginScreen( paddingValues: PaddingValues, + onLoginSuccess: () -> Unit = {}, viewModel: AuthViewModel = hiltViewModel() ){ @@ -75,6 +76,11 @@ fun LoginScreen( var usernameError by remember { mutableStateOf("") } var passwordError by remember { mutableStateOf("") } + LaunchedEffect(uiState) { + if (uiState is LoginUiState.Success) { + onLoginSuccess() + } + } //background @@ -97,7 +103,6 @@ fun LoginScreen( - //Motion_logo SvgImage( resId = R.raw.tg_chat_v3, @@ -145,7 +150,6 @@ fun LoginScreen( - Column( modifier = Modifier .fillMaxSize() diff --git a/app/src/main/java/com/example/login_v3/data/repository/basic/Token_Auth.kt b/app/src/main/java/com/example/login_v3/data/repository/basic/Token_Auth.kt index 1534640..acf7d82 100644 --- a/app/src/main/java/com/example/login_v3/data/repository/basic/Token_Auth.kt +++ b/app/src/main/java/com/example/login_v3/data/repository/basic/Token_Auth.kt @@ -1,5 +1,6 @@ package com.example.login_v3.data.repository.basic +import android.util.Log import com.example.login_v3.data.api.RefreshRequest import com.example.login_v3.data.api.TecnologiaApi import kotlinx.coroutines.flow.first @@ -18,8 +19,10 @@ class TokenAuthenticator @Inject constructor( override fun authenticate(route: Route?, response: Response): Request? { // 1. 取得 DataStore 中的當前帳號資訊 + Log.d("AuthDebug", "--- 進入 Authenticator (觸發網址: ${response.request.url}) ---") val refreshToken = runBlocking { tokenManager.currentRefreshToken.first() } val currentUserId = runBlocking { tokenManager.currentUserId.first() } + Log.d("AuthDebug", "當前用戶: $currentUserId, Token是否存在: ${!refreshToken.isNullOrEmpty()}") if (refreshToken.isNullOrEmpty() || currentUserId.isNullOrEmpty()) { return null // 沒有憑證資訊,不重試,直接拋出原 401 錯誤 @@ -37,6 +40,9 @@ class TokenAuthenticator @Inject constructor( // 3. 判斷刷新是否成功 if (refreshResponse != null && refreshResponse.isSuccessful) { + Log.d("AuthDebug", "✅ Token 刷新成功,準備寫入 DataStore") + // saveAuthData... + Log.d("AuthDebug", "✅ DataStore 寫入完成,重新發送原請求") val newAuthData = refreshResponse.body() if (newAuthData != null) { diff --git a/app/src/main/java/com/example/login_v3/navigation/MainViewModel.kt b/app/src/main/java/com/example/login_v3/navigation/MainViewModel.kt index 4526321..38a2f73 100644 --- a/app/src/main/java/com/example/login_v3/navigation/MainViewModel.kt +++ b/app/src/main/java/com/example/login_v3/navigation/MainViewModel.kt @@ -13,6 +13,7 @@ import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.first import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.stateIn @@ -71,11 +72,26 @@ class AppViewModel @Inject constructor( private fun observeGlobalLogout() { viewModelScope.launch { - // 監聽全域狀態。如果使用者在操作過程中(例如 TokenAuthenticator 刷新失敗觸發 logout), - // 導致帳號清單變空了,就把畫面強制踢回歡迎頁。 - hasAccountLoggedIn.collect { hasAccount -> - if (!hasAccount && _currentScreen.value == AppScreen.ScreensTab) { - _currentScreen.value = AppScreen.PreReg + // 同時監聽「帳號清單」與「當前 Access Token」的狀態 + // 只要這兩個其中一個被清空(變成空或 null),就代表完全失聯,必須踢回登入流程 + combine(hasAccountLoggedIn, tokenManager.currentAccessToken) { hasAccount, token -> + hasAccount to token + }.collect { (hasAccount, token) -> + + // 🌟 修正後的黃金判斷式: + // 如果判定「已經沒有帳號登入」或者「當前畫面在主分頁但 Token 卻是空值」 + if (!hasAccount || (token.isNullOrEmpty() && _currentScreen.value == AppScreen.ScreensTab)) { + Log.e("AuthDebug", "🚨 觸發強制跳轉條件!") + + // 為了避免干擾正在註冊(PreReg, Register, Login)的使用者, + // 只有在當前不在這些認證頁面時,才強制踢回 PreReg + if (_currentScreen.value != AppScreen.PreReg && + _currentScreen.value != AppScreen.Login && + _currentScreen.value != AppScreen.Register) { + + Log.d("NavTest", "偵測到 Token 或帳號失效,強制回歡迎頁") + _currentScreen.value = AppScreen.PreReg + } } } } diff --git a/app/src/main/java/com/example/login_v3/navigation/nav_controller.kt b/app/src/main/java/com/example/login_v3/navigation/nav_controller.kt index 0e822ad..307d0c0 100644 --- a/app/src/main/java/com/example/login_v3/navigation/nav_controller.kt +++ b/app/src/main/java/com/example/login_v3/navigation/nav_controller.kt @@ -43,7 +43,11 @@ fun AppNavGraph( ) AppScreen.Login -> LoginScreen( - paddingValues = paddingValues + paddingValues = paddingValues, + // 🌟 在這裡呼叫 AppViewModel 跳轉到主頁分頁 + onLoginSuccess = { + appViewModel.goTo(AppScreen.ScreensTab) + } ) AppScreen.AddAccount -> {