From e033c18acaadaeb91c904bf459820b8636c1dfa1 Mon Sep 17 00:00:00 2001 From: AndyChen1024 Date: Wed, 9 Sep 2026 22:20:01 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E3=80=8C=E8=AE=A1=E5=88=92=E3=80=8D?= =?UTF-8?q?=E6=9C=AA=E7=99=BB=E5=BD=95=E8=87=AA=E5=8A=A8=E8=B7=B3=E8=BD=AC?= =?UTF-8?q?=E3=80=8C=E6=88=91=E7=9A=84=E3=80=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/mingyuan/android_client/AppNavHost.kt | 1 + .../android_client/feature/plan/PlanScreen.kt | 16 ++++++++++ .../feature/plan/PlanViewModel.kt | 32 +++++++++++++------ 3 files changed, 39 insertions(+), 10 deletions(-) diff --git a/app/src/main/java/com/mingyuan/android_client/AppNavHost.kt b/app/src/main/java/com/mingyuan/android_client/AppNavHost.kt index 78d59c0..c14f43c 100644 --- a/app/src/main/java/com/mingyuan/android_client/AppNavHost.kt +++ b/app/src/main/java/com/mingyuan/android_client/AppNavHost.kt @@ -85,6 +85,7 @@ fun AppNavHost() { onNavigateToPlanSubmit = { type, periodKey -> navController.navigate(planSubmitRoute(type, periodKey)) }, + onNavigateToProfile = { navigateToTab(PROFILE_ROUTE) }, ) } composable( diff --git a/feature/plan/src/main/kotlin/com/mingyuan/android_client/feature/plan/PlanScreen.kt b/feature/plan/src/main/kotlin/com/mingyuan/android_client/feature/plan/PlanScreen.kt index a2cb346..738058b 100644 --- a/feature/plan/src/main/kotlin/com/mingyuan/android_client/feature/plan/PlanScreen.kt +++ b/feature/plan/src/main/kotlin/com/mingyuan/android_client/feature/plan/PlanScreen.kt @@ -22,6 +22,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 @@ -39,6 +40,7 @@ import com.mingyuan.android_client.core.designsystem.component.AmberProgressBar import com.mingyuan.android_client.core.designsystem.component.Avatar import com.mingyuan.android_client.core.designsystem.component.EmptyState import com.mingyuan.android_client.core.designsystem.component.ErrorState +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.SegmentedControl @@ -66,12 +68,24 @@ const val PLAN_ROUTE = "plan" @Composable fun PlanScreen( onNavigateToPlanSubmit: (PlanType, String) -> Unit, + onNavigateToProfile: () -> Unit, modifier: Modifier = Modifier, viewModel: PlanViewModel = hiltViewModel(), ) { val uiState by viewModel.uiState.collectAsStateWithLifecycle() val selectedType by viewModel.selectedType.collectAsStateWithLifecycle() + LaunchedEffect(uiState) { + if (uiState is PlanUiState.LoggedOut) { + onNavigateToProfile() + } + } + + if (uiState is PlanUiState.LoggedOut) { + LoggedOutState(modifier = modifier.fillMaxSize().background(PlanBackground)) + return + } + Column(modifier = modifier.fillMaxSize().background(PlanBackground)) { Box(Modifier.fillMaxWidth().padding(16.dp)) { SegmentedControl( @@ -94,6 +108,8 @@ fun PlanScreen( selectedType = selectedType, onNavigateToPlanSubmit = onNavigateToPlanSubmit, ) + + is PlanUiState.LoggedOut -> Unit // handled above } } } diff --git a/feature/plan/src/main/kotlin/com/mingyuan/android_client/feature/plan/PlanViewModel.kt b/feature/plan/src/main/kotlin/com/mingyuan/android_client/feature/plan/PlanViewModel.kt index d44b315..5d0c6c0 100644 --- a/feature/plan/src/main/kotlin/com/mingyuan/android_client/feature/plan/PlanViewModel.kt +++ b/feature/plan/src/main/kotlin/com/mingyuan/android_client/feature/plan/PlanViewModel.kt @@ -3,6 +3,7 @@ package com.mingyuan.android_client.feature.plan import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.mingyuan.android_client.core.domain.repository.PlanRepository +import com.mingyuan.android_client.core.domain.repository.SessionRepository import com.mingyuan.android_client.core.model.PlanRecord import com.mingyuan.android_client.core.model.PlanType import dagger.hilt.android.lifecycle.HiltViewModel @@ -11,7 +12,9 @@ import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.catch +import kotlinx.coroutines.flow.combine 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 @@ -20,27 +23,36 @@ import javax.inject.Inject sealed interface PlanUiState { data object Loading : PlanUiState data class Success(val record: PlanRecord) : PlanUiState + data object LoggedOut : PlanUiState data class Error(val message: String) : PlanUiState } @HiltViewModel class PlanViewModel @Inject constructor( private val planRepository: PlanRepository, + private val sessionRepository: SessionRepository, ) : ViewModel() { private val _selectedType = MutableStateFlow(PlanType.WEEKLY) val selectedType: StateFlow = _selectedType.asStateFlow() - val uiState: StateFlow = _selectedType - .flatMapLatest { type -> planRepository.observePlan(type) } - .map(PlanUiState::Success) - .onStart { emit(PlanUiState.Loading) } - .catch { emit(PlanUiState.Error(it.message ?: "加载失败,请稍后再试")) } - .stateIn( - scope = viewModelScope, - started = SharingStarted.WhileSubscribed(5_000), - initialValue = PlanUiState.Loading, - ) + val uiState: StateFlow = + combine(sessionRepository.isLoggedIn, _selectedType) { loggedIn, type -> loggedIn to type } + .flatMapLatest { (loggedIn, type) -> + if (loggedIn) { + planRepository.observePlan(type) + .map(PlanUiState::Success) + .onStart { emit(PlanUiState.Loading) } + } else { + flowOf(PlanUiState.LoggedOut) + } + } + .catch { emit(PlanUiState.Error(it.message ?: "加载失败,请稍后再试")) } + .stateIn( + scope = viewModelScope, + started = SharingStarted.Eagerly, + initialValue = PlanUiState.Loading, + ) fun selectType(type: PlanType) { _selectedType.value = type