feat: 「首页」支持游客模式
This commit is contained in:
@@ -74,6 +74,7 @@ fun AppNavHost() {
|
|||||||
HomeScreen(
|
HomeScreen(
|
||||||
onNavigateToCheckin = { navigateToTab(CHECKIN_ROUTE) },
|
onNavigateToCheckin = { navigateToTab(CHECKIN_ROUTE) },
|
||||||
onNavigateToPlan = { navigateToTab(PLAN_ROUTE) },
|
onNavigateToPlan = { navigateToTab(PLAN_ROUTE) },
|
||||||
|
onNavigateToProfile = { navigateToTab(PROFILE_ROUTE) },
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
composable(CHECKIN_ROUTE) { CheckinScreen() }
|
composable(CHECKIN_ROUTE) { CheckinScreen() }
|
||||||
|
|||||||
@@ -18,16 +18,34 @@ class FakeHomeRepository @Inject constructor() : HomeRepository {
|
|||||||
emit(seedHome())
|
emit(seedHome())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun observeGuestHome(): Flow<HomeData> = flow {
|
||||||
|
delay(250)
|
||||||
|
emit(seedGuestHome())
|
||||||
|
}
|
||||||
|
|
||||||
private fun seedHome() = HomeData(
|
private fun seedHome() = HomeData(
|
||||||
greeting = "晚上好",
|
greeting = "晚上好",
|
||||||
displayName = "张三",
|
displayName = "张三",
|
||||||
encouragement = "坚持每周打卡,与小组共同进步。",
|
encouragement = "坚持每周打卡,与小组共同进步。",
|
||||||
modules = listOf(
|
modules = modules(),
|
||||||
|
intros = intros(),
|
||||||
|
)
|
||||||
|
|
||||||
|
private fun seedGuestHome() = HomeData(
|
||||||
|
greeting = "欢迎来到明缘云道场",
|
||||||
|
displayName = "游客",
|
||||||
|
encouragement = "登录后即可打卡、提交计划",
|
||||||
|
modules = modules(),
|
||||||
|
intros = intros(),
|
||||||
|
)
|
||||||
|
|
||||||
|
private fun modules() = listOf(
|
||||||
HomeModule("checkin", "📋", "打卡介绍", "每日打卡记录", ModuleDestination.CHECKIN),
|
HomeModule("checkin", "📋", "打卡介绍", "每日打卡记录", ModuleDestination.CHECKIN),
|
||||||
HomeModule("plan", "📝", "计划介绍", "周/月/年计划", ModuleDestination.PLAN),
|
HomeModule("plan", "📝", "计划介绍", "周/月/年计划", ModuleDestination.PLAN),
|
||||||
HomeModule("about", "ℹ️", "关于我们", "了解明缘云道场", ModuleDestination.ABOUT),
|
HomeModule("about", "ℹ️", "关于我们", "了解明缘云道场", ModuleDestination.ABOUT),
|
||||||
),
|
)
|
||||||
intros = listOf(
|
|
||||||
|
private fun intros() = listOf(
|
||||||
IntroCard(
|
IntroCard(
|
||||||
"📚 学习成长工具",
|
"📚 学习成长工具",
|
||||||
"明缘云道场是一款专注于个人成长的效率工具,通过每周打卡与计划管理,帮助你养成良好的学习习惯,实现持续进步。好好学习,天天向上。",
|
"明缘云道场是一款专注于个人成长的效率工具,通过每周打卡与计划管理,帮助你养成良好的学习习惯,实现持续进步。好好学习,天天向上。",
|
||||||
@@ -44,6 +62,5 @@ class FakeHomeRepository @Inject constructor() : HomeRepository {
|
|||||||
"👥 小组共学",
|
"👥 小组共学",
|
||||||
"加入学习小组,查看组员的打卡与计划完成情况。在集体的氛围中保持学习动力,与志同道合的伙伴一起成长。",
|
"加入学习小组,查看组员的打卡与计划完成情况。在集体的氛围中保持学习动力,与志同道合的伙伴一起成长。",
|
||||||
),
|
),
|
||||||
),
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,4 +5,6 @@ import kotlinx.coroutines.flow.Flow
|
|||||||
|
|
||||||
interface HomeRepository {
|
interface HomeRepository {
|
||||||
fun observeHome(): Flow<HomeData>
|
fun observeHome(): Flow<HomeData>
|
||||||
|
|
||||||
|
fun observeGuestHome(): Flow<HomeData>
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,9 +16,14 @@ import androidx.compose.foundation.layout.size
|
|||||||
import androidx.compose.foundation.lazy.LazyColumn
|
import androidx.compose.foundation.lazy.LazyColumn
|
||||||
import androidx.compose.foundation.shape.CircleShape
|
import androidx.compose.foundation.shape.CircleShape
|
||||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
|
import androidx.compose.material3.AlertDialog
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.material3.TextButton
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.mutableStateOf
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.runtime.setValue
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.draw.shadow
|
import androidx.compose.ui.draw.shadow
|
||||||
@@ -51,10 +56,12 @@ const val HOME_ROUTE = "home"
|
|||||||
fun HomeScreen(
|
fun HomeScreen(
|
||||||
onNavigateToCheckin: () -> Unit,
|
onNavigateToCheckin: () -> Unit,
|
||||||
onNavigateToPlan: () -> Unit,
|
onNavigateToPlan: () -> Unit,
|
||||||
|
onNavigateToProfile: () -> Unit,
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
viewModel: HomeViewModel = hiltViewModel(),
|
viewModel: HomeViewModel = hiltViewModel(),
|
||||||
) {
|
) {
|
||||||
val uiState by viewModel.uiState.collectAsStateWithLifecycle()
|
val uiState by viewModel.uiState.collectAsStateWithLifecycle()
|
||||||
|
var showLoginDialog by remember { mutableStateOf(false) }
|
||||||
|
|
||||||
when (val state = uiState) {
|
when (val state = uiState) {
|
||||||
is HomeUiState.Loading -> HomeSkeleton(modifier)
|
is HomeUiState.Loading -> HomeSkeleton(modifier)
|
||||||
@@ -67,15 +74,40 @@ fun HomeScreen(
|
|||||||
is HomeUiState.Success -> HomeContent(
|
is HomeUiState.Success -> HomeContent(
|
||||||
data = state.data,
|
data = state.data,
|
||||||
onModuleClick = { module ->
|
onModuleClick = { module ->
|
||||||
|
if (state.isGuest) {
|
||||||
|
showLoginDialog = true
|
||||||
|
} else {
|
||||||
when (module.destination) {
|
when (module.destination) {
|
||||||
ModuleDestination.CHECKIN -> onNavigateToCheckin()
|
ModuleDestination.CHECKIN -> onNavigateToCheckin()
|
||||||
ModuleDestination.PLAN -> onNavigateToPlan()
|
ModuleDestination.PLAN -> onNavigateToPlan()
|
||||||
ModuleDestination.ABOUT -> Unit
|
ModuleDestination.ABOUT -> Unit
|
||||||
}
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
modifier = modifier,
|
modifier = modifier,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (showLoginDialog) {
|
||||||
|
AlertDialog(
|
||||||
|
onDismissRequest = { showLoginDialog = false },
|
||||||
|
title = { Text("登录提示") },
|
||||||
|
text = { Text("登录后使用此功能,是否前往登录?") },
|
||||||
|
confirmButton = {
|
||||||
|
TextButton(
|
||||||
|
onClick = {
|
||||||
|
showLoginDialog = false
|
||||||
|
onNavigateToProfile()
|
||||||
|
},
|
||||||
|
) {
|
||||||
|
Text("去登录")
|
||||||
|
}
|
||||||
|
},
|
||||||
|
dismissButton = {
|
||||||
|
TextButton(onClick = { showLoginDialog = false }) { Text("取消") }
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
|
|||||||
@@ -3,11 +3,13 @@ package com.mingyuan.android_client.feature.home
|
|||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
import com.mingyuan.android_client.core.domain.repository.HomeRepository
|
import com.mingyuan.android_client.core.domain.repository.HomeRepository
|
||||||
|
import com.mingyuan.android_client.core.domain.repository.SessionRepository
|
||||||
import com.mingyuan.android_client.core.model.HomeData
|
import com.mingyuan.android_client.core.model.HomeData
|
||||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||||
import kotlinx.coroutines.flow.SharingStarted
|
import kotlinx.coroutines.flow.SharingStarted
|
||||||
import kotlinx.coroutines.flow.StateFlow
|
import kotlinx.coroutines.flow.StateFlow
|
||||||
import kotlinx.coroutines.flow.catch
|
import kotlinx.coroutines.flow.catch
|
||||||
|
import kotlinx.coroutines.flow.flatMapLatest
|
||||||
import kotlinx.coroutines.flow.map
|
import kotlinx.coroutines.flow.map
|
||||||
import kotlinx.coroutines.flow.onStart
|
import kotlinx.coroutines.flow.onStart
|
||||||
import kotlinx.coroutines.flow.stateIn
|
import kotlinx.coroutines.flow.stateIn
|
||||||
@@ -15,22 +17,31 @@ import javax.inject.Inject
|
|||||||
|
|
||||||
sealed interface HomeUiState {
|
sealed interface HomeUiState {
|
||||||
data object Loading : HomeUiState
|
data object Loading : HomeUiState
|
||||||
data class Success(val data: HomeData) : HomeUiState
|
data class Success(val data: HomeData, val isGuest: Boolean) : HomeUiState
|
||||||
data class Error(val message: String) : HomeUiState
|
data class Error(val message: String) : HomeUiState
|
||||||
}
|
}
|
||||||
|
|
||||||
@HiltViewModel
|
@HiltViewModel
|
||||||
class HomeViewModel @Inject constructor(
|
class HomeViewModel @Inject constructor(
|
||||||
homeRepository: HomeRepository,
|
homeRepository: HomeRepository,
|
||||||
|
sessionRepository: SessionRepository,
|
||||||
) : ViewModel() {
|
) : ViewModel() {
|
||||||
|
|
||||||
val uiState: StateFlow<HomeUiState> = homeRepository.observeHome()
|
val uiState: StateFlow<HomeUiState> = sessionRepository.isLoggedIn
|
||||||
.map<HomeData, HomeUiState>(HomeUiState::Success)
|
.flatMapLatest { loggedIn ->
|
||||||
|
val source = if (loggedIn) {
|
||||||
|
homeRepository.observeHome()
|
||||||
|
} else {
|
||||||
|
homeRepository.observeGuestHome()
|
||||||
|
}
|
||||||
|
source
|
||||||
|
.map<HomeData, HomeUiState> { HomeUiState.Success(it, isGuest = !loggedIn) }
|
||||||
.onStart { emit(HomeUiState.Loading) }
|
.onStart { emit(HomeUiState.Loading) }
|
||||||
|
}
|
||||||
.catch { emit(HomeUiState.Error(it.message ?: "加载失败,请稍后再试")) }
|
.catch { emit(HomeUiState.Error(it.message ?: "加载失败,请稍后再试")) }
|
||||||
.stateIn(
|
.stateIn(
|
||||||
scope = viewModelScope,
|
scope = viewModelScope,
|
||||||
started = SharingStarted.WhileSubscribed(5_000),
|
started = SharingStarted.Eagerly,
|
||||||
initialValue = HomeUiState.Loading,
|
initialValue = HomeUiState.Loading,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user