feat: 「我的」页退出登录/登录接入会话状态
This commit is contained in:
@@ -21,6 +21,7 @@ import androidx.compose.material3.AlertDialog
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TextButton
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
@@ -36,6 +37,7 @@ import com.mingyuan.android_client.core.designsystem.component.Avatar
|
||||
import com.mingyuan.android_client.core.designsystem.component.ButtonVariant
|
||||
import com.mingyuan.android_client.core.designsystem.component.ErrorState
|
||||
import com.mingyuan.android_client.core.designsystem.component.LabeledRow
|
||||
import com.mingyuan.android_client.core.designsystem.component.LoggedOutState
|
||||
import com.mingyuan.android_client.core.designsystem.component.MingyuanButton
|
||||
import com.mingyuan.android_client.core.designsystem.component.SectionCard
|
||||
import com.mingyuan.android_client.core.designsystem.component.SkeletonBox
|
||||
@@ -53,14 +55,20 @@ const val PROFILE_ROUTE = "profile"
|
||||
|
||||
@Composable
|
||||
fun ProfileScreen(
|
||||
onLoggedOut: () -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
viewModel: ProfileViewModel = hiltViewModel(),
|
||||
) {
|
||||
val uiState by viewModel.uiState.collectAsStateWithLifecycle()
|
||||
var showDeleteDialog by remember { mutableStateOf(false) }
|
||||
var showLogoutDialog by remember { mutableStateOf(false) }
|
||||
|
||||
LaunchedEffect(Unit) {
|
||||
viewModel.logoutEvents.collect { onLoggedOut() }
|
||||
}
|
||||
|
||||
when (val state = uiState) {
|
||||
is ProfileUiState.Loading -> ProfileSkeleton(modifier)
|
||||
is ProfileUiState.LoggedOut -> LoggedOutState(onLogin = viewModel::login, modifier = modifier)
|
||||
is ProfileUiState.Error -> ErrorState(
|
||||
message = state.message,
|
||||
onRetry = {},
|
||||
@@ -69,28 +77,28 @@ fun ProfileScreen(
|
||||
|
||||
is ProfileUiState.Success -> ProfileContent(
|
||||
profile = state.profile,
|
||||
onDelete = { showDeleteDialog = true },
|
||||
onLogout = { showLogoutDialog = true },
|
||||
modifier = modifier,
|
||||
)
|
||||
}
|
||||
|
||||
if (showDeleteDialog) {
|
||||
if (showLogoutDialog) {
|
||||
AlertDialog(
|
||||
onDismissRequest = { showDeleteDialog = false },
|
||||
title = { Text("注销账号") },
|
||||
text = { Text("确定要注销账号吗?此操作不可恢复。") },
|
||||
onDismissRequest = { showLogoutDialog = false },
|
||||
title = { Text("退出登录") },
|
||||
text = { Text("确定要退出登录吗?退出后需要重新登录。") },
|
||||
confirmButton = {
|
||||
TextButton(
|
||||
onClick = {
|
||||
showDeleteDialog = false
|
||||
viewModel.deleteAccount()
|
||||
showLogoutDialog = false
|
||||
viewModel.logout()
|
||||
},
|
||||
) {
|
||||
Text("确定", color = Danger)
|
||||
}
|
||||
},
|
||||
dismissButton = {
|
||||
TextButton(onClick = { showDeleteDialog = false }) { Text("取消") }
|
||||
TextButton(onClick = { showLogoutDialog = false }) { Text("取消") }
|
||||
},
|
||||
)
|
||||
}
|
||||
@@ -99,7 +107,7 @@ fun ProfileScreen(
|
||||
@Composable
|
||||
private fun ProfileContent(
|
||||
profile: UserProfile,
|
||||
onDelete: () -> Unit,
|
||||
onLogout: () -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
LazyColumn(
|
||||
@@ -114,8 +122,8 @@ private fun ProfileContent(
|
||||
}
|
||||
item {
|
||||
MingyuanButton(
|
||||
text = "注销账号",
|
||||
onClick = onDelete,
|
||||
text = "退出登录",
|
||||
onClick = onLogout,
|
||||
variant = ButtonVariant.DANGER,
|
||||
fullWidth = true,
|
||||
)
|
||||
|
||||
@@ -3,11 +3,16 @@ package com.mingyuan.android_client.feature.profile
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.mingyuan.android_client.core.domain.repository.ProfileRepository
|
||||
import com.mingyuan.android_client.core.domain.repository.SessionRepository
|
||||
import com.mingyuan.android_client.core.model.UserProfile
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||
import kotlinx.coroutines.flow.SharedFlow
|
||||
import kotlinx.coroutines.flow.SharingStarted
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.catch
|
||||
import kotlinx.coroutines.flow.flatMapLatest
|
||||
import kotlinx.coroutines.flow.flowOf
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.onStart
|
||||
import kotlinx.coroutines.flow.stateIn
|
||||
@@ -17,27 +22,46 @@ import javax.inject.Inject
|
||||
sealed interface ProfileUiState {
|
||||
data object Loading : ProfileUiState
|
||||
data class Success(val profile: UserProfile) : ProfileUiState
|
||||
data object LoggedOut : ProfileUiState
|
||||
data class Error(val message: String) : ProfileUiState
|
||||
}
|
||||
|
||||
@HiltViewModel
|
||||
class ProfileViewModel @Inject constructor(
|
||||
private val profileRepository: ProfileRepository,
|
||||
private val sessionRepository: SessionRepository,
|
||||
) : ViewModel() {
|
||||
|
||||
val uiState: StateFlow<ProfileUiState> = profileRepository.observeProfile()
|
||||
.map<UserProfile, ProfileUiState>(ProfileUiState::Success)
|
||||
.onStart { emit(ProfileUiState.Loading) }
|
||||
val uiState: StateFlow<ProfileUiState> = sessionRepository.isLoggedIn
|
||||
.flatMapLatest { loggedIn ->
|
||||
if (loggedIn) {
|
||||
profileRepository.observeProfile()
|
||||
.map<UserProfile, ProfileUiState>(ProfileUiState::Success)
|
||||
.onStart { emit(ProfileUiState.Loading) }
|
||||
} else {
|
||||
flowOf(ProfileUiState.LoggedOut)
|
||||
}
|
||||
}
|
||||
.catch { emit(ProfileUiState.Error(it.message ?: "加载失败,请稍后再试")) }
|
||||
.stateIn(
|
||||
scope = viewModelScope,
|
||||
started = SharingStarted.WhileSubscribed(5_000),
|
||||
started = SharingStarted.Eagerly,
|
||||
initialValue = ProfileUiState.Loading,
|
||||
)
|
||||
|
||||
fun deleteAccount() {
|
||||
private val _logoutEvents = MutableSharedFlow<Unit>()
|
||||
val logoutEvents: SharedFlow<Unit> = _logoutEvents
|
||||
|
||||
fun login() {
|
||||
viewModelScope.launch {
|
||||
profileRepository.deleteAccount()
|
||||
sessionRepository.login()
|
||||
}
|
||||
}
|
||||
|
||||
fun logout() {
|
||||
viewModelScope.launch {
|
||||
sessionRepository.logout()
|
||||
_logoutEvents.emit(Unit)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user