auth to server-V91
This commit is contained in:
parent
321be95ff0
commit
fae89ee041
2 changed files with 200 additions and 9 deletions
|
|
@ -0,0 +1,178 @@
|
|||
package com.example.login_v3.auth.SwitchAccount
|
||||
|
||||
import androidx.compose.foundation.BorderStroke
|
||||
import androidx.compose.foundation.clickable
|
||||
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.Spacer
|
||||
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.size
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.shape.CircleShape
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.foundation.lazy.items // 確保匯入這個
|
||||
import androidx.compose.material.icons.filled.Add
|
||||
import androidx.compose.material.icons.filled.ArrowBack
|
||||
import androidx.compose.material.icons.filled.ExitToApp
|
||||
import androidx.compose.material3.Button
|
||||
import androidx.compose.material3.Card
|
||||
import androidx.compose.material3.CardDefaults
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Scaffold
|
||||
import androidx.compose.material3.Surface
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TopAppBar
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.hilt.navigation.compose.hiltViewModel
|
||||
import com.example.login_v3.auth.login.AuthViewModel
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun AccountSwitchScreen(
|
||||
viewModel: AuthViewModel = hiltViewModel<AuthViewModel>(),
|
||||
onAddAccountClick: () -> Unit,
|
||||
onBack: () -> Unit
|
||||
) {
|
||||
// 觀察 ViewModel 中的狀態
|
||||
val allUsers by viewModel.allUserIds.collectAsState()
|
||||
val currentUserId by viewModel.currentUserId.collectAsState()
|
||||
|
||||
Scaffold(
|
||||
topBar = {
|
||||
TopAppBar(
|
||||
title = { Text("切換帳號") },
|
||||
navigationIcon = {
|
||||
IconButton(onClick = onBack) {
|
||||
Icon(Icons.Default.ArrowBack, contentDescription = null)
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
) { padding ->
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.padding(padding)
|
||||
.padding(16.dp)
|
||||
) {
|
||||
Text(
|
||||
text = "已登入的帳號",
|
||||
style = MaterialTheme.typography.titleMedium,
|
||||
color = MaterialTheme.colorScheme.primary
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.height(8.dp))
|
||||
|
||||
// 帳號清單
|
||||
LazyColumn(
|
||||
modifier = Modifier.weight(1f),
|
||||
verticalArrangement = Arrangement.spacedBy(8.dp)
|
||||
) {
|
||||
// 這裡加上明確的 items(items = ...)
|
||||
items(items = allUsers.toList()) { userId ->
|
||||
val isCurrent = (userId == currentUserId) // 這裡解決 == 類型問題
|
||||
|
||||
AccountItem(
|
||||
userId = userId,
|
||||
isCurrent = isCurrent,
|
||||
onSelect = { viewModel.switchAccount(userId) },
|
||||
onLogout = { viewModel.logout(userId) }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
Spacer(modifier = Modifier.height(16.dp))
|
||||
|
||||
// 新增帳號按鈕
|
||||
Button(
|
||||
onClick = onAddAccountClick,
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
shape = RoundedCornerShape(8.dp)
|
||||
) {
|
||||
Icon(Icons.Default.Add, contentDescription = null)
|
||||
Spacer(modifier = Modifier.width(8.dp))
|
||||
Text("登入另一個帳號")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun AccountItem(
|
||||
userId: String,
|
||||
isCurrent: Boolean,
|
||||
onSelect: () -> Unit,
|
||||
onLogout: () -> Unit
|
||||
) {
|
||||
Card(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.clickable { onSelect() },
|
||||
border = if (isCurrent) BorderStroke(2.dp, MaterialTheme.colorScheme.primary) else null,
|
||||
colors = CardDefaults.cardColors(
|
||||
containerColor = if (isCurrent)
|
||||
MaterialTheme.colorScheme.primaryContainer
|
||||
else
|
||||
MaterialTheme.colorScheme.surfaceVariant
|
||||
)
|
||||
) {
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.padding(16.dp)
|
||||
.fillMaxWidth(),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.SpaceBetween
|
||||
) {
|
||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||
// 模擬頭像
|
||||
Surface(
|
||||
shape = CircleShape,
|
||||
color = MaterialTheme.colorScheme.secondary,
|
||||
modifier = Modifier.size(40.dp)
|
||||
) {
|
||||
Box(contentAlignment = Alignment.Center) {
|
||||
Text(userId.take(1).uppercase(), color = Color.White)
|
||||
}
|
||||
}
|
||||
|
||||
Spacer(modifier = Modifier.width(12.dp))
|
||||
|
||||
Column {
|
||||
Text(text = userId, style = MaterialTheme.typography.bodyLarge)
|
||||
if (isCurrent) {
|
||||
Text(
|
||||
text = "使用中",
|
||||
style = MaterialTheme.typography.labelSmall,
|
||||
color = MaterialTheme.colorScheme.primary
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 登出小按鈕
|
||||
IconButton(onClick = onLogout) {
|
||||
Icon(
|
||||
imageVector = Icons.Default.ExitToApp,
|
||||
contentDescription = "登出",
|
||||
tint = MaterialTheme.colorScheme.error
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -7,10 +7,13 @@ import androidx.lifecycle.ViewModel
|
|||
import androidx.lifecycle.viewModelScope
|
||||
import com.example.login_v3.data.repository.basic.TokenManager
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.SharingStarted
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.asStateFlow
|
||||
import kotlinx.coroutines.flow.first
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.stateIn
|
||||
import kotlinx.coroutines.launch
|
||||
import javax.inject.Inject
|
||||
|
|
@ -36,25 +39,30 @@ class AppViewModel @Inject constructor(
|
|||
private val tokenManager: TokenManager
|
||||
) : ViewModel() {
|
||||
|
||||
private val _currentScreen = MutableStateFlow<AppScreen>(AppScreen.Loading) // 增加一個 Loading 狀態
|
||||
private val _currentScreen = MutableStateFlow<AppScreen>(AppScreen.Loading)
|
||||
val currentScreen: StateFlow<AppScreen> = _currentScreen.asStateFlow()
|
||||
|
||||
// 暴露 Token 給其他需要的 Screen 使用
|
||||
val userToken: StateFlow<String?> = tokenManager.accessToken
|
||||
// 修改:監聽當前活躍帳號的 Token
|
||||
val userToken: StateFlow<String?> = tokenManager.currentAccessToken
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(5000), null)
|
||||
|
||||
// 修改:監聽「是否至少有一個帳號登入中」
|
||||
private val hasAccountLoggedIn: Flow<Boolean> = tokenManager.allUserIds.map { it.isNotEmpty() }
|
||||
|
||||
init {
|
||||
checkLoginStatus()
|
||||
}
|
||||
|
||||
private fun checkLoginStatus() {
|
||||
viewModelScope.launch {
|
||||
// 讀取 DataStore 中的 isLogin 狀態
|
||||
tokenManager.isLogin.collect { loggedIn ->
|
||||
if (loggedIn) {
|
||||
// 修改:根據「帳號清單是否為空」來決定初始頁面
|
||||
hasAccountLoggedIn.collect { hasAccount ->
|
||||
if (hasAccount) {
|
||||
// 只要清單不為空,就進入主頁面
|
||||
_currentScreen.value = AppScreen.ScreensTab
|
||||
} else {
|
||||
_currentScreen.value = AppScreen.PreReg // 或 AppScreen.Register
|
||||
// 如果清單空了(所有人都登出了),回首頁/註冊頁
|
||||
_currentScreen.value = AppScreen.PreReg
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -64,10 +72,15 @@ class AppViewModel @Inject constructor(
|
|||
_currentScreen.value = screen
|
||||
}
|
||||
|
||||
// 修改:登出當前帳號
|
||||
fun onLogout() {
|
||||
viewModelScope.launch {
|
||||
tokenManager.clearAuthData()
|
||||
// 清除後,checkLoginStatus 的 collect 會自動觸發切換回 PreReg
|
||||
// 先獲取目前的 ID
|
||||
val currentId = tokenManager.currentUserId.first()
|
||||
currentId?.let {
|
||||
tokenManager.logout(it)
|
||||
}
|
||||
// logout 完後,hasAccountLoggedIn 的 collect 會自動觸發頁面跳轉邏輯
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue