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 17c8ad5..d2dea13 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 @@ -77,7 +77,7 @@ fun LoginScreen( - + //background Column( modifier = Modifier .fillMaxSize() diff --git a/app/src/main/java/com/example/login_v3/auth/login/Login_Page_ViewModel.kt b/app/src/main/java/com/example/login_v3/auth/login/Login_Page_ViewModel.kt index b4220c5..9d3fb48 100644 --- a/app/src/main/java/com/example/login_v3/auth/login/Login_Page_ViewModel.kt +++ b/app/src/main/java/com/example/login_v3/auth/login/Login_Page_ViewModel.kt @@ -8,8 +8,10 @@ import com.example.login_v3.data.repository.basic.AuthRepository import com.example.login_v3.data.repository.basic.TokenManager import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.launch import javax.inject.Inject @@ -23,12 +25,20 @@ sealed class LoginUiState { @HiltViewModel class AuthViewModel @Inject constructor( private val repository: AuthRepository, - private val tokenManager: TokenManager // 注入 TokenManager + private val tokenManager: TokenManager ) : ViewModel() { private val _loginState = MutableStateFlow(LoginUiState.Idle) val loginState: StateFlow = _loginState.asStateFlow() + // --- 新增:供 UI 顯示所有已登入帳號與當前帳號 --- + val allUserIds: StateFlow> = tokenManager.allUserIds + .stateIn(viewModelScope, SharingStarted.WhileSubscribed(5000), emptySet()) + + val currentUserId: StateFlow = tokenManager.currentUserId + .stateIn(viewModelScope, SharingStarted.WhileSubscribed(5000), null) + // ------------------------------------------ + fun login(username: String, password: String) { viewModelScope.launch { _loginState.value = LoginUiState.Loading @@ -39,10 +49,15 @@ class AuthViewModel @Inject constructor( if (response.isSuccessful && response.body() != null) { val loginResponse = response.body()!! - // 1. 先把 Token 存入 DataStore - tokenManager.saveAuthData(loginResponse.access_token) + // 修改:存入 token 時同時存入 userId (假設你的 user 物件裡有 id) + // 如果 LoginResponse 沒給 id,也可以用 username 作為唯一識別碼 + val userId = loginResponse.user.id.toString() + + tokenManager.saveAuthData( + userId = userId, + token = loginResponse.access_token + ) - // 2. 更新 UI 狀態 _loginState.value = LoginUiState.Success(loginResponse.user) } else { _loginState.value = LoginUiState.Error("登入失敗:${response.code()}") @@ -52,4 +67,19 @@ class AuthViewModel @Inject constructor( } } } + + // --- 新增:切換帳號功能 --- + fun switchAccount(userId: String) { + viewModelScope.launch { + tokenManager.switchAccount(userId) + // 切換後,通常會需要重新初始化某些頁面資料,或發送一個事件通知 UI + } + } + + // --- 新增:登出功能 --- + fun logout(userId: String) { + viewModelScope.launch { + tokenManager.logout(userId) + } + } } \ No newline at end of file diff --git a/app/src/main/java/com/example/login_v3/data/di/NetworkModule.kt b/app/src/main/java/com/example/login_v3/data/di/NetworkModule.kt index f08cd04..11b9a92 100644 --- a/app/src/main/java/com/example/login_v3/data/di/NetworkModule.kt +++ b/app/src/main/java/com/example/login_v3/data/di/NetworkModule.kt @@ -46,20 +46,30 @@ object NetworkModule { @Singleton fun provideOkHttpClient(tokenManager: TokenManager): OkHttpClient { return OkHttpClient.Builder() - .connectTimeout(15, TimeUnit.SECONDS) // 連線逾時 - .readTimeout(15, TimeUnit.SECONDS) // 讀取逾時 + .connectTimeout(15, TimeUnit.SECONDS) + .readTimeout(15, TimeUnit.SECONDS) .addInterceptor { chain -> - val token = runBlocking { tokenManager.accessToken.first() } - val requestBuilder = chain.request().newBuilder() + // 1. 動態獲取「目前選中帳號」的 Token + // 使用 first() 確保只取目前最新的那一個值 + val token = runBlocking { tokenManager.currentAccessToken.first() } + val requestBuilder = chain.request().newBuilder() token?.let { requestBuilder.addHeader("Authorization", "Bearer $it") } val response = chain.proceed(requestBuilder.build()) + // 2. 處理 Token 失效 (401) if (response.code == 401) { - runBlocking { tokenManager.clearAuthData() } + runBlocking { + // 獲取目前是哪個 ID 失效了 + val currentId = tokenManager.currentUserId.first() + currentId?.let { + // 只登出當前失效的帳號,不影響其他帳號 + tokenManager.logout(it) + } + } } response diff --git a/app/src/main/java/com/example/login_v3/data/repository/basic/Token_Manager.kt b/app/src/main/java/com/example/login_v3/data/repository/basic/Token_Manager.kt index 90c681d..5006426 100644 --- a/app/src/main/java/com/example/login_v3/data/repository/basic/Token_Manager.kt +++ b/app/src/main/java/com/example/login_v3/data/repository/basic/Token_Manager.kt @@ -20,11 +20,10 @@ class TokenManager @Inject constructor( preferences[USER_ID_LIST] ?: emptySet() } + // TokenManager 內部建議改動 companion object { - // 1. 記錄目前正在使用的 UserId + private val USER_ID_LIST = stringSetPreferencesKey("user_id_list") // 移到這裡 private val CURRENT_USER_ID = stringPreferencesKey("current_user_id") - - // 2. 輔助函式:根據 userId 動態產生 Token 的 Key private fun accessTokenKey(userId: String) = stringPreferencesKey("access_token_$userId") }