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 39445d7..78d59c0 100644 --- a/app/src/main/java/com/mingyuan/android_client/AppNavHost.kt +++ b/app/src/main/java/com/mingyuan/android_client/AppNavHost.kt @@ -77,7 +77,9 @@ fun AppNavHost() { onNavigateToProfile = { navigateToTab(PROFILE_ROUTE) }, ) } - composable(CHECKIN_ROUTE) { CheckinScreen() } + composable(CHECKIN_ROUTE) { + CheckinScreen(onNavigateToProfile = { navigateToTab(PROFILE_ROUTE) }) + } composable(PLAN_ROUTE) { PlanScreen( onNavigateToPlanSubmit = { type, periodKey -> diff --git a/feature/checkin/src/main/kotlin/com/mingyuan/android_client/feature/checkin/CheckinScreen.kt b/feature/checkin/src/main/kotlin/com/mingyuan/android_client/feature/checkin/CheckinScreen.kt index 58b5a4f..e157157 100644 --- a/feature/checkin/src/main/kotlin/com/mingyuan/android_client/feature/checkin/CheckinScreen.kt +++ b/feature/checkin/src/main/kotlin/com/mingyuan/android_client/feature/checkin/CheckinScreen.kt @@ -18,6 +18,7 @@ import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material3.Text 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 @@ -33,6 +34,7 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle 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.SectionCard import com.mingyuan.android_client.core.designsystem.component.SkeletonBox import com.mingyuan.android_client.core.designsystem.theme.BrandAmber @@ -56,6 +58,7 @@ const val CHECKIN_ROUTE = "checkin" @Composable fun CheckinScreen( + onNavigateToProfile: () -> Unit, modifier: Modifier = Modifier, viewModel: CheckinViewModel = hiltViewModel(), ) { @@ -63,8 +66,15 @@ fun CheckinScreen( val selectedStatus by viewModel.selectedStatus.collectAsStateWithLifecycle() val submitting by viewModel.submitting.collectAsStateWithLifecycle() + LaunchedEffect(uiState) { + if (uiState is CheckinUiState.LoggedOut) { + onNavigateToProfile() + } + } + when (val state = uiState) { is CheckinUiState.Loading -> CheckinSkeleton(modifier) + is CheckinUiState.LoggedOut -> LoggedOutState(modifier = modifier) is CheckinUiState.Error -> ErrorState( message = state.message, onRetry = {}, diff --git a/feature/checkin/src/main/kotlin/com/mingyuan/android_client/feature/checkin/CheckinViewModel.kt b/feature/checkin/src/main/kotlin/com/mingyuan/android_client/feature/checkin/CheckinViewModel.kt index ba32800..97a6144 100644 --- a/feature/checkin/src/main/kotlin/com/mingyuan/android_client/feature/checkin/CheckinViewModel.kt +++ b/feature/checkin/src/main/kotlin/com/mingyuan/android_client/feature/checkin/CheckinViewModel.kt @@ -3,6 +3,7 @@ package com.mingyuan.android_client.feature.checkin import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.mingyuan.android_client.core.domain.repository.CheckinRepository +import com.mingyuan.android_client.core.domain.repository.SessionRepository import com.mingyuan.android_client.core.model.CheckinRecord import com.mingyuan.android_client.core.model.CheckinStatus import dagger.hilt.android.lifecycle.HiltViewModel @@ -11,6 +12,8 @@ import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.asStateFlow 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 @@ -20,12 +23,14 @@ import javax.inject.Inject sealed interface CheckinUiState { data object Loading : CheckinUiState data class Success(val record: CheckinRecord) : CheckinUiState + data object LoggedOut : CheckinUiState data class Error(val message: String) : CheckinUiState } @HiltViewModel class CheckinViewModel @Inject constructor( private val checkinRepository: CheckinRepository, + private val sessionRepository: SessionRepository, ) : ViewModel() { private val _selectedStatus = MutableStateFlow(CheckinStatus.NORMAL) @@ -34,13 +39,20 @@ class CheckinViewModel @Inject constructor( private val _submitting = MutableStateFlow(false) val submitting: StateFlow = _submitting.asStateFlow() - val uiState: StateFlow = checkinRepository.observeCheckin() - .map(CheckinUiState::Success) - .onStart { emit(CheckinUiState.Loading) } + val uiState: StateFlow = sessionRepository.isLoggedIn + .flatMapLatest { loggedIn -> + if (loggedIn) { + checkinRepository.observeCheckin() + .map(CheckinUiState::Success) + .onStart { emit(CheckinUiState.Loading) } + } else { + flowOf(CheckinUiState.LoggedOut) + } + } .catch { emit(CheckinUiState.Error(it.message ?: "加载失败,请稍后再试")) } .stateIn( scope = viewModelScope, - started = SharingStarted.WhileSubscribed(5_000), + started = SharingStarted.Eagerly, initialValue = CheckinUiState.Loading, )