feat: 新 UI 双击底栏刷新
This commit is contained in:
parent
18cbbe1b76
commit
37f378f59f
|
|
@ -18,6 +18,7 @@ import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.LaunchedEffect
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
import androidx.compose.runtime.collectAsState
|
import androidx.compose.runtime.collectAsState
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
import androidx.compose.runtime.rememberCoroutineScope
|
import androidx.compose.runtime.rememberCoroutineScope
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
|
|
@ -49,6 +50,7 @@ import com.huanchengfly.tieba.post.utils.appPreferences
|
||||||
import com.ramcosta.composedestinations.annotation.Destination
|
import com.ramcosta.composedestinations.annotation.Destination
|
||||||
import com.ramcosta.composedestinations.annotation.RootNavGraph
|
import com.ramcosta.composedestinations.annotation.RootNavGraph
|
||||||
import com.ramcosta.composedestinations.navigation.DestinationsNavigator
|
import com.ramcosta.composedestinations.navigation.DestinationsNavigator
|
||||||
|
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||||
import kotlinx.coroutines.flow.StateFlow
|
import kotlinx.coroutines.flow.StateFlow
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
|
|
@ -56,6 +58,7 @@ import kotlinx.coroutines.launch
|
||||||
private fun NavigationWrapper(
|
private fun NavigationWrapper(
|
||||||
currentPosition: Int,
|
currentPosition: Int,
|
||||||
onChangePosition: (position: Int) -> Unit,
|
onChangePosition: (position: Int) -> Unit,
|
||||||
|
onReselected: (position: Int) -> Unit,
|
||||||
navigationItems: List<NavigationItem>,
|
navigationItems: List<NavigationItem>,
|
||||||
navigationType: MainNavigationType,
|
navigationType: MainNavigationType,
|
||||||
navigationContentPosition: MainNavigationContentPosition,
|
navigationContentPosition: MainNavigationContentPosition,
|
||||||
|
|
@ -66,6 +69,7 @@ private fun NavigationWrapper(
|
||||||
NavigationDrawerContent(
|
NavigationDrawerContent(
|
||||||
currentPosition = currentPosition,
|
currentPosition = currentPosition,
|
||||||
onChangePosition = onChangePosition,
|
onChangePosition = onChangePosition,
|
||||||
|
onReselected = onReselected,
|
||||||
navigationItems = navigationItems,
|
navigationItems = navigationItems,
|
||||||
navigationContentPosition = navigationContentPosition
|
navigationContentPosition = navigationContentPosition
|
||||||
)
|
)
|
||||||
|
|
@ -74,6 +78,7 @@ private fun NavigationWrapper(
|
||||||
NavigationRail(
|
NavigationRail(
|
||||||
currentPosition = currentPosition,
|
currentPosition = currentPosition,
|
||||||
onChangePosition = onChangePosition,
|
onChangePosition = onChangePosition,
|
||||||
|
onReselected = onReselected,
|
||||||
navigationItems = navigationItems,
|
navigationItems = navigationItems,
|
||||||
navigationContentPosition = navigationContentPosition
|
navigationContentPosition = navigationContentPosition
|
||||||
)
|
)
|
||||||
|
|
@ -100,6 +105,15 @@ fun MainPage(
|
||||||
initial = 0
|
initial = 0
|
||||||
)
|
)
|
||||||
|
|
||||||
|
val eventFlows = remember {
|
||||||
|
listOf(
|
||||||
|
MutableSharedFlow<MainUiEvent>(),
|
||||||
|
MutableSharedFlow<MainUiEvent>(),
|
||||||
|
MutableSharedFlow<MainUiEvent>(),
|
||||||
|
MutableSharedFlow<MainUiEvent>(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
val notificationCountFlow = LocalNotificationCountFlow.current
|
val notificationCountFlow = LocalNotificationCountFlow.current
|
||||||
LaunchedEffect(null) {
|
LaunchedEffect(null) {
|
||||||
notificationCountFlow.collect {
|
notificationCountFlow.collect {
|
||||||
|
|
@ -118,13 +132,13 @@ fun MainPage(
|
||||||
title = stringResource(id = R.string.title_main),
|
title = stringResource(id = R.string.title_main),
|
||||||
content = {
|
content = {
|
||||||
HomePage(
|
HomePage(
|
||||||
canOpenExplore = !LocalContext.current.appPreferences.hideExplore,
|
eventFlow = eventFlows[0],
|
||||||
onOpenExplore = {
|
canOpenExplore = !LocalContext.current.appPreferences.hideExplore
|
||||||
coroutineScope.launch {
|
) {
|
||||||
pagerState.scrollToPage(1)
|
coroutineScope.launch {
|
||||||
}
|
pagerState.scrollToPage(1)
|
||||||
}
|
}
|
||||||
)
|
}
|
||||||
}
|
}
|
||||||
),
|
),
|
||||||
if (LocalContext.current.appPreferences.hideExplore) null
|
if (LocalContext.current.appPreferences.hideExplore) null
|
||||||
|
|
@ -136,7 +150,7 @@ fun MainPage(
|
||||||
},
|
},
|
||||||
title = stringResource(id = R.string.title_explore),
|
title = stringResource(id = R.string.title_explore),
|
||||||
content = {
|
content = {
|
||||||
ExplorePage()
|
ExplorePage(eventFlows[1])
|
||||||
}
|
}
|
||||||
),
|
),
|
||||||
NavigationItem(
|
NavigationItem(
|
||||||
|
|
@ -187,17 +201,25 @@ fun MainPage(
|
||||||
WindowHeightSizeClass.Compact -> {
|
WindowHeightSizeClass.Compact -> {
|
||||||
MainNavigationContentPosition.TOP
|
MainNavigationContentPosition.TOP
|
||||||
}
|
}
|
||||||
|
|
||||||
WindowHeightSizeClass.Medium,
|
WindowHeightSizeClass.Medium,
|
||||||
WindowHeightSizeClass.Expanded -> {
|
WindowHeightSizeClass.Expanded -> {
|
||||||
MainNavigationContentPosition.CENTER
|
MainNavigationContentPosition.CENTER
|
||||||
}
|
}
|
||||||
|
|
||||||
else -> {
|
else -> {
|
||||||
MainNavigationContentPosition.TOP
|
MainNavigationContentPosition.TOP
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
val onReselected: (Int) -> Unit = {
|
||||||
|
coroutineScope.launch {
|
||||||
|
eventFlows[it].emit(MainUiEvent.Refresh)
|
||||||
|
}
|
||||||
|
}
|
||||||
NavigationWrapper(
|
NavigationWrapper(
|
||||||
currentPosition = pagerState.currentPage,
|
currentPosition = pagerState.currentPage,
|
||||||
onChangePosition = { coroutineScope.launch { pagerState.scrollToPage(it) } },
|
onChangePosition = { coroutineScope.launch { pagerState.scrollToPage(it) } },
|
||||||
|
onReselected = onReselected,
|
||||||
navigationItems = navigationItems,
|
navigationItems = navigationItems,
|
||||||
navigationType = navigationType,
|
navigationType = navigationType,
|
||||||
navigationContentPosition = navigationContentPosition
|
navigationContentPosition = navigationContentPosition
|
||||||
|
|
@ -209,7 +231,10 @@ fun MainPage(
|
||||||
AnimatedVisibility(visible = navigationType == MainNavigationType.BOTTOM_NAVIGATION) {
|
AnimatedVisibility(visible = navigationType == MainNavigationType.BOTTOM_NAVIGATION) {
|
||||||
BottomNavigation(
|
BottomNavigation(
|
||||||
currentPosition = pagerState.currentPage,
|
currentPosition = pagerState.currentPage,
|
||||||
onChangePosition = { coroutineScope.launch { pagerState.scrollToPage(it) } },
|
onChangePosition = {
|
||||||
|
coroutineScope.launch { pagerState.scrollToPage(it) }
|
||||||
|
},
|
||||||
|
onReselected = onReselected,
|
||||||
navigationItems = navigationItems,
|
navigationItems = navigationItems,
|
||||||
themeColors = themeColors,
|
themeColors = themeColors,
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,11 @@
|
||||||
package com.huanchengfly.tieba.post.ui.page.main
|
package com.huanchengfly.tieba.post.ui.page.main
|
||||||
|
|
||||||
import com.huanchengfly.tieba.post.arch.*
|
import com.huanchengfly.tieba.post.arch.BaseViewModel
|
||||||
|
import com.huanchengfly.tieba.post.arch.PartialChange
|
||||||
|
import com.huanchengfly.tieba.post.arch.PartialChangeProducer
|
||||||
|
import com.huanchengfly.tieba.post.arch.UiEvent
|
||||||
|
import com.huanchengfly.tieba.post.arch.UiIntent
|
||||||
|
import com.huanchengfly.tieba.post.arch.UiState
|
||||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
import kotlinx.coroutines.flow.filterIsInstance
|
import kotlinx.coroutines.flow.filterIsInstance
|
||||||
|
|
@ -50,4 +55,6 @@ sealed interface MainPartialChange : PartialChange<MainUiState> {
|
||||||
|
|
||||||
data class MainUiState(val messageCount: Int = 0) : UiState
|
data class MainUiState(val messageCount: Int = 0) : UiState
|
||||||
|
|
||||||
sealed interface MainUiEvent : UiEvent
|
sealed interface MainUiEvent : UiEvent {
|
||||||
|
object Refresh : MainUiEvent
|
||||||
|
}
|
||||||
|
|
@ -129,6 +129,7 @@ fun NavigationDrawerItem(
|
||||||
fun NavigationDrawerContent(
|
fun NavigationDrawerContent(
|
||||||
currentPosition: Int,
|
currentPosition: Int,
|
||||||
onChangePosition: (position: Int) -> Unit,
|
onChangePosition: (position: Int) -> Unit,
|
||||||
|
onReselected: (position: Int) -> Unit,
|
||||||
navigationItems: List<NavigationItem>,
|
navigationItems: List<NavigationItem>,
|
||||||
navigationContentPosition: MainNavigationContentPosition
|
navigationContentPosition: MainNavigationContentPosition
|
||||||
) {
|
) {
|
||||||
|
|
@ -191,7 +192,13 @@ fun NavigationDrawerContent(
|
||||||
navigationItems.forEachIndexed { index, navigationItem ->
|
navigationItems.forEachIndexed { index, navigationItem ->
|
||||||
NavigationDrawerItem(
|
NavigationDrawerItem(
|
||||||
selected = index == currentPosition,
|
selected = index == currentPosition,
|
||||||
onClick = { onChangePosition(index) },
|
onClick = {
|
||||||
|
if (index == currentPosition) {
|
||||||
|
onReselected(index)
|
||||||
|
} else {
|
||||||
|
onChangePosition(index)
|
||||||
|
}
|
||||||
|
},
|
||||||
label = { Text(text = navigationItem.title) },
|
label = { Text(text = navigationItem.title) },
|
||||||
icon = {
|
icon = {
|
||||||
Box {
|
Box {
|
||||||
|
|
@ -275,6 +282,7 @@ private fun PositionLayout(
|
||||||
fun NavigationRail(
|
fun NavigationRail(
|
||||||
currentPosition: Int,
|
currentPosition: Int,
|
||||||
onChangePosition: (position: Int) -> Unit,
|
onChangePosition: (position: Int) -> Unit,
|
||||||
|
onReselected: (position: Int) -> Unit,
|
||||||
navigationItems: List<NavigationItem>,
|
navigationItems: List<NavigationItem>,
|
||||||
navigationContentPosition: MainNavigationContentPosition
|
navigationContentPosition: MainNavigationContentPosition
|
||||||
) {
|
) {
|
||||||
|
|
@ -296,7 +304,13 @@ fun NavigationRail(
|
||||||
navigationItems.forEachIndexed { index, navigationItem ->
|
navigationItems.forEachIndexed { index, navigationItem ->
|
||||||
NavigationRailItem(
|
NavigationRailItem(
|
||||||
selected = index == currentPosition,
|
selected = index == currentPosition,
|
||||||
onClick = { onChangePosition(index) },
|
onClick = {
|
||||||
|
if (index == currentPosition) {
|
||||||
|
onReselected(index)
|
||||||
|
} else {
|
||||||
|
onChangePosition(index)
|
||||||
|
}
|
||||||
|
},
|
||||||
icon = {
|
icon = {
|
||||||
Box {
|
Box {
|
||||||
Icon(
|
Icon(
|
||||||
|
|
@ -345,6 +359,7 @@ fun BottomNavigationDivider(
|
||||||
fun BottomNavigation(
|
fun BottomNavigation(
|
||||||
currentPosition: Int,
|
currentPosition: Int,
|
||||||
onChangePosition: (position: Int) -> Unit,
|
onChangePosition: (position: Int) -> Unit,
|
||||||
|
onReselected: (position: Int) -> Unit,
|
||||||
navigationItems: List<NavigationItem>,
|
navigationItems: List<NavigationItem>,
|
||||||
themeColors: ExtendedColors = ExtendedTheme.colors
|
themeColors: ExtendedColors = ExtendedTheme.colors
|
||||||
) {
|
) {
|
||||||
|
|
@ -358,7 +373,11 @@ fun BottomNavigation(
|
||||||
BottomNavigationItem(
|
BottomNavigationItem(
|
||||||
selected = index == currentPosition,
|
selected = index == currentPosition,
|
||||||
onClick = {
|
onClick = {
|
||||||
onChangePosition(index)
|
if (index == currentPosition) {
|
||||||
|
onReselected(index)
|
||||||
|
} else {
|
||||||
|
onChangePosition(index)
|
||||||
|
}
|
||||||
navigationItem.onClick?.invoke()
|
navigationItem.onClick?.invoke()
|
||||||
},
|
},
|
||||||
icon = {
|
icon = {
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ import androidx.compose.material.Text
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
import androidx.compose.material.icons.rounded.Search
|
import androidx.compose.material.icons.rounded.Search
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
import androidx.compose.runtime.rememberCoroutineScope
|
import androidx.compose.runtime.rememberCoroutineScope
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
|
|
@ -21,8 +22,10 @@ import com.google.accompanist.pager.HorizontalPager
|
||||||
import com.google.accompanist.pager.rememberPagerState
|
import com.google.accompanist.pager.rememberPagerState
|
||||||
import com.huanchengfly.tieba.post.R
|
import com.huanchengfly.tieba.post.R
|
||||||
import com.huanchengfly.tieba.post.activities.NewSearchActivity
|
import com.huanchengfly.tieba.post.activities.NewSearchActivity
|
||||||
|
import com.huanchengfly.tieba.post.arch.onEvent
|
||||||
import com.huanchengfly.tieba.post.goToActivity
|
import com.huanchengfly.tieba.post.goToActivity
|
||||||
import com.huanchengfly.tieba.post.ui.common.theme.compose.ExtendedTheme
|
import com.huanchengfly.tieba.post.ui.common.theme.compose.ExtendedTheme
|
||||||
|
import com.huanchengfly.tieba.post.ui.page.main.MainUiEvent
|
||||||
import com.huanchengfly.tieba.post.ui.page.main.explore.concern.ConcernPage
|
import com.huanchengfly.tieba.post.ui.page.main.explore.concern.ConcernPage
|
||||||
import com.huanchengfly.tieba.post.ui.page.main.explore.hot.HotPage
|
import com.huanchengfly.tieba.post.ui.page.main.explore.hot.HotPage
|
||||||
import com.huanchengfly.tieba.post.ui.page.main.explore.personalized.PersonalizedPage
|
import com.huanchengfly.tieba.post.ui.page.main.explore.personalized.PersonalizedPage
|
||||||
|
|
@ -31,27 +34,47 @@ import com.huanchengfly.tieba.post.ui.widgets.compose.PagerTabIndicator
|
||||||
import com.huanchengfly.tieba.post.ui.widgets.compose.Toolbar
|
import com.huanchengfly.tieba.post.ui.widgets.compose.Toolbar
|
||||||
import com.huanchengfly.tieba.post.ui.widgets.compose.accountNavIconIfCompact
|
import com.huanchengfly.tieba.post.ui.widgets.compose.accountNavIconIfCompact
|
||||||
import com.huanchengfly.tieba.post.utils.AccountUtil.LocalAccount
|
import com.huanchengfly.tieba.post.utils.AccountUtil.LocalAccount
|
||||||
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
|
|
||||||
@OptIn(ExperimentalPagerApi::class)
|
@OptIn(ExperimentalPagerApi::class)
|
||||||
@Composable
|
@Composable
|
||||||
fun ExplorePage() {
|
fun ExplorePage(
|
||||||
|
eventFlow: Flow<MainUiEvent>,
|
||||||
|
) {
|
||||||
val account = LocalAccount.current
|
val account = LocalAccount.current
|
||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
|
|
||||||
|
val eventFlows = remember {
|
||||||
|
listOf(
|
||||||
|
MutableSharedFlow<MainUiEvent>(),
|
||||||
|
MutableSharedFlow<MainUiEvent>(),
|
||||||
|
MutableSharedFlow<MainUiEvent>()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
val firstIndex = if (account != null) 0 else -1
|
||||||
|
|
||||||
val pages = listOfNotNull<Pair<String, (@Composable () -> Unit)>>(
|
val pages = listOfNotNull<Pair<String, (@Composable () -> Unit)>>(
|
||||||
if (account != null) stringResource(id = R.string.title_concern) to @Composable {
|
if (account != null) stringResource(id = R.string.title_concern) to @Composable {
|
||||||
ConcernPage()
|
ConcernPage(eventFlows[firstIndex + 0])
|
||||||
} else null,
|
} else null,
|
||||||
stringResource(id = R.string.title_personalized) to @Composable {
|
stringResource(id = R.string.title_personalized) to @Composable {
|
||||||
PersonalizedPage()
|
PersonalizedPage(eventFlows[firstIndex + 1])
|
||||||
},
|
},
|
||||||
stringResource(id = R.string.title_hot) to @Composable {
|
stringResource(id = R.string.title_hot) to @Composable {
|
||||||
HotPage()
|
HotPage(eventFlows[firstIndex + 2])
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
val pagerState = rememberPagerState(initialPage = if (account != null) 1 else 0)
|
val pagerState = rememberPagerState(initialPage = if (account != null) 1 else 0)
|
||||||
val coroutineScope = rememberCoroutineScope()
|
val coroutineScope = rememberCoroutineScope()
|
||||||
|
|
||||||
|
eventFlow.onEvent<MainUiEvent.Refresh> {
|
||||||
|
eventFlows[pagerState.currentPage].emit(it)
|
||||||
|
}
|
||||||
|
|
||||||
Scaffold(
|
Scaffold(
|
||||||
backgroundColor = Color.Transparent,
|
backgroundColor = Color.Transparent,
|
||||||
topBar = {
|
topBar = {
|
||||||
|
|
@ -88,7 +111,11 @@ fun ExplorePage() {
|
||||||
selected = pagerState.currentPage == index,
|
selected = pagerState.currentPage == index,
|
||||||
onClick = {
|
onClick = {
|
||||||
coroutineScope.launch {
|
coroutineScope.launch {
|
||||||
pagerState.animateScrollToPage(index)
|
if (pagerState.currentPage == index) {
|
||||||
|
eventFlows[pagerState.currentPage].emit(MainUiEvent.Refresh)
|
||||||
|
} else {
|
||||||
|
pagerState.animateScrollToPage(index)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -19,16 +19,20 @@ import androidx.compose.ui.platform.LocalContext
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import com.huanchengfly.tieba.post.activities.ThreadActivity
|
import com.huanchengfly.tieba.post.activities.ThreadActivity
|
||||||
import com.huanchengfly.tieba.post.arch.collectPartialAsState
|
import com.huanchengfly.tieba.post.arch.collectPartialAsState
|
||||||
|
import com.huanchengfly.tieba.post.arch.onEvent
|
||||||
import com.huanchengfly.tieba.post.arch.pageViewModel
|
import com.huanchengfly.tieba.post.arch.pageViewModel
|
||||||
import com.huanchengfly.tieba.post.arch.wrapImmutable
|
import com.huanchengfly.tieba.post.arch.wrapImmutable
|
||||||
|
import com.huanchengfly.tieba.post.ui.page.main.MainUiEvent
|
||||||
import com.huanchengfly.tieba.post.ui.widgets.compose.FeedCard
|
import com.huanchengfly.tieba.post.ui.widgets.compose.FeedCard
|
||||||
import com.huanchengfly.tieba.post.ui.widgets.compose.LazyLoad
|
import com.huanchengfly.tieba.post.ui.widgets.compose.LazyLoad
|
||||||
import com.huanchengfly.tieba.post.ui.widgets.compose.LoadMoreLayout
|
import com.huanchengfly.tieba.post.ui.widgets.compose.LoadMoreLayout
|
||||||
import com.huanchengfly.tieba.post.ui.widgets.compose.VerticalDivider
|
import com.huanchengfly.tieba.post.ui.widgets.compose.VerticalDivider
|
||||||
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
|
||||||
@OptIn(ExperimentalFoundationApi::class, ExperimentalMaterialApi::class)
|
@OptIn(ExperimentalFoundationApi::class, ExperimentalMaterialApi::class)
|
||||||
@Composable
|
@Composable
|
||||||
fun ConcernPage(
|
fun ConcernPage(
|
||||||
|
eventFlow: Flow<MainUiEvent>,
|
||||||
viewModel: ConcernViewModel = pageViewModel()
|
viewModel: ConcernViewModel = pageViewModel()
|
||||||
) {
|
) {
|
||||||
LazyLoad(loaded = viewModel.initialized) {
|
LazyLoad(loaded = viewModel.initialized) {
|
||||||
|
|
@ -55,6 +59,11 @@ fun ConcernPage(
|
||||||
val pullRefreshState = rememberPullRefreshState(
|
val pullRefreshState = rememberPullRefreshState(
|
||||||
refreshing = isRefreshing,
|
refreshing = isRefreshing,
|
||||||
onRefresh = { viewModel.send(ConcernUiIntent.Refresh) })
|
onRefresh = { viewModel.send(ConcernUiIntent.Refresh) })
|
||||||
|
|
||||||
|
eventFlow.onEvent<MainUiEvent.Refresh> {
|
||||||
|
viewModel.send(ConcernUiIntent.Refresh)
|
||||||
|
}
|
||||||
|
|
||||||
Box(
|
Box(
|
||||||
modifier = Modifier.pullRefresh(pullRefreshState)
|
modifier = Modifier.pullRefresh(pullRefreshState)
|
||||||
) {
|
) {
|
||||||
|
|
|
||||||
|
|
@ -47,6 +47,7 @@ import com.google.accompanist.placeholder.material.placeholder
|
||||||
import com.huanchengfly.tieba.post.R
|
import com.huanchengfly.tieba.post.R
|
||||||
import com.huanchengfly.tieba.post.api.models.protos.ThreadInfo
|
import com.huanchengfly.tieba.post.api.models.protos.ThreadInfo
|
||||||
import com.huanchengfly.tieba.post.arch.collectPartialAsState
|
import com.huanchengfly.tieba.post.arch.collectPartialAsState
|
||||||
|
import com.huanchengfly.tieba.post.arch.onEvent
|
||||||
import com.huanchengfly.tieba.post.arch.pageViewModel
|
import com.huanchengfly.tieba.post.arch.pageViewModel
|
||||||
import com.huanchengfly.tieba.post.ui.common.theme.compose.ExtendedTheme
|
import com.huanchengfly.tieba.post.ui.common.theme.compose.ExtendedTheme
|
||||||
import com.huanchengfly.tieba.post.ui.common.theme.compose.OrangeA700
|
import com.huanchengfly.tieba.post.ui.common.theme.compose.OrangeA700
|
||||||
|
|
@ -55,6 +56,7 @@ import com.huanchengfly.tieba.post.ui.common.theme.compose.White
|
||||||
import com.huanchengfly.tieba.post.ui.common.theme.compose.Yellow
|
import com.huanchengfly.tieba.post.ui.common.theme.compose.Yellow
|
||||||
import com.huanchengfly.tieba.post.ui.page.LocalNavigator
|
import com.huanchengfly.tieba.post.ui.page.LocalNavigator
|
||||||
import com.huanchengfly.tieba.post.ui.page.destinations.HotTopicListPageDestination
|
import com.huanchengfly.tieba.post.ui.page.destinations.HotTopicListPageDestination
|
||||||
|
import com.huanchengfly.tieba.post.ui.page.main.MainUiEvent
|
||||||
import com.huanchengfly.tieba.post.ui.widgets.compose.LazyLoad
|
import com.huanchengfly.tieba.post.ui.widgets.compose.LazyLoad
|
||||||
import com.huanchengfly.tieba.post.ui.widgets.compose.NetworkImage
|
import com.huanchengfly.tieba.post.ui.widgets.compose.NetworkImage
|
||||||
import com.huanchengfly.tieba.post.ui.widgets.compose.ProvideContentColor
|
import com.huanchengfly.tieba.post.ui.widgets.compose.ProvideContentColor
|
||||||
|
|
@ -64,17 +66,22 @@ import com.huanchengfly.tieba.post.ui.widgets.compose.items
|
||||||
import com.huanchengfly.tieba.post.ui.widgets.compose.itemsIndexed
|
import com.huanchengfly.tieba.post.ui.widgets.compose.itemsIndexed
|
||||||
import com.huanchengfly.tieba.post.utils.StringUtil.getShortNumString
|
import com.huanchengfly.tieba.post.utils.StringUtil.getShortNumString
|
||||||
import com.ramcosta.composedestinations.annotation.Destination
|
import com.ramcosta.composedestinations.annotation.Destination
|
||||||
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
|
||||||
@OptIn(ExperimentalFoundationApi::class, ExperimentalMaterialApi::class)
|
@OptIn(ExperimentalFoundationApi::class, ExperimentalMaterialApi::class)
|
||||||
@Destination
|
@Destination
|
||||||
@Composable
|
@Composable
|
||||||
fun HotPage(
|
fun HotPage(
|
||||||
|
eventFlow: Flow<MainUiEvent>,
|
||||||
viewModel: HotViewModel = pageViewModel()
|
viewModel: HotViewModel = pageViewModel()
|
||||||
) {
|
) {
|
||||||
LazyLoad(loaded = viewModel.initialized) {
|
LazyLoad(loaded = viewModel.initialized) {
|
||||||
viewModel.send(HotUiIntent.Load)
|
viewModel.send(HotUiIntent.Load)
|
||||||
viewModel.initialized = true
|
viewModel.initialized = true
|
||||||
}
|
}
|
||||||
|
eventFlow.onEvent<MainUiEvent.Refresh> {
|
||||||
|
viewModel.send(HotUiIntent.Load)
|
||||||
|
}
|
||||||
val navigator = LocalNavigator.current
|
val navigator = LocalNavigator.current
|
||||||
val isLoading by viewModel.uiState.collectPartialAsState(
|
val isLoading by viewModel.uiState.collectPartialAsState(
|
||||||
prop1 = HotUiState::isRefreshing,
|
prop1 = HotUiState::isRefreshing,
|
||||||
|
|
|
||||||
|
|
@ -53,20 +53,22 @@ import com.huanchengfly.tieba.post.api.models.protos.ThreadInfo
|
||||||
import com.huanchengfly.tieba.post.api.models.protos.personalized.DislikeReason
|
import com.huanchengfly.tieba.post.api.models.protos.personalized.DislikeReason
|
||||||
import com.huanchengfly.tieba.post.api.models.protos.personalized.ThreadPersonalized
|
import com.huanchengfly.tieba.post.api.models.protos.personalized.ThreadPersonalized
|
||||||
import com.huanchengfly.tieba.post.arch.collectPartialAsState
|
import com.huanchengfly.tieba.post.arch.collectPartialAsState
|
||||||
|
import com.huanchengfly.tieba.post.arch.onEvent
|
||||||
import com.huanchengfly.tieba.post.arch.pageViewModel
|
import com.huanchengfly.tieba.post.arch.pageViewModel
|
||||||
import com.huanchengfly.tieba.post.arch.wrapImmutable
|
import com.huanchengfly.tieba.post.arch.wrapImmutable
|
||||||
import com.huanchengfly.tieba.post.ui.common.theme.compose.ExtendedTheme
|
import com.huanchengfly.tieba.post.ui.common.theme.compose.ExtendedTheme
|
||||||
|
import com.huanchengfly.tieba.post.ui.page.main.MainUiEvent
|
||||||
import com.huanchengfly.tieba.post.ui.widgets.compose.FeedCard
|
import com.huanchengfly.tieba.post.ui.widgets.compose.FeedCard
|
||||||
import com.huanchengfly.tieba.post.ui.widgets.compose.LazyLoad
|
import com.huanchengfly.tieba.post.ui.widgets.compose.LazyLoad
|
||||||
import com.huanchengfly.tieba.post.ui.widgets.compose.LoadMoreLayout
|
import com.huanchengfly.tieba.post.ui.widgets.compose.LoadMoreLayout
|
||||||
import com.huanchengfly.tieba.post.ui.widgets.compose.VerticalDivider
|
import com.huanchengfly.tieba.post.ui.widgets.compose.VerticalDivider
|
||||||
import kotlinx.coroutines.delay
|
import kotlinx.coroutines.delay
|
||||||
import kotlinx.coroutines.flow.filterIsInstance
|
import kotlinx.coroutines.flow.Flow
|
||||||
import kotlinx.coroutines.launch
|
|
||||||
|
|
||||||
@OptIn(ExperimentalFoundationApi::class, ExperimentalMaterialApi::class)
|
@OptIn(ExperimentalFoundationApi::class, ExperimentalMaterialApi::class)
|
||||||
@Composable
|
@Composable
|
||||||
fun PersonalizedPage(
|
fun PersonalizedPage(
|
||||||
|
eventFlow: Flow<MainUiEvent>,
|
||||||
viewModel: PersonalizedViewModel = pageViewModel()
|
viewModel: PersonalizedViewModel = pageViewModel()
|
||||||
) {
|
) {
|
||||||
LazyLoad(loaded = viewModel.initialized) {
|
LazyLoad(loaded = viewModel.initialized) {
|
||||||
|
|
@ -113,16 +115,15 @@ fun PersonalizedPage(
|
||||||
var showRefreshTip by remember {
|
var showRefreshTip by remember {
|
||||||
mutableStateOf(false)
|
mutableStateOf(false)
|
||||||
}
|
}
|
||||||
LaunchedEffect(Unit) {
|
|
||||||
launch {
|
eventFlow.onEvent<MainUiEvent.Refresh> {
|
||||||
viewModel.uiEventFlow
|
viewModel.send(PersonalizedUiIntent.Refresh)
|
||||||
.filterIsInstance<PersonalizedUiEvent.RefreshSuccess>()
|
|
||||||
.collect {
|
|
||||||
refreshCount = it.count
|
|
||||||
showRefreshTip = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
viewModel.onEvent<PersonalizedUiEvent.RefreshSuccess> {
|
||||||
|
refreshCount = it.count
|
||||||
|
showRefreshTip = true
|
||||||
|
}
|
||||||
|
|
||||||
if (showRefreshTip) {
|
if (showRefreshTip) {
|
||||||
LaunchedEffect(Unit) {
|
LaunchedEffect(Unit) {
|
||||||
delay(2000)
|
delay(2000)
|
||||||
|
|
|
||||||
|
|
@ -70,11 +70,13 @@ import com.huanchengfly.tieba.post.R
|
||||||
import com.huanchengfly.tieba.post.activities.LoginActivity
|
import com.huanchengfly.tieba.post.activities.LoginActivity
|
||||||
import com.huanchengfly.tieba.post.activities.NewSearchActivity
|
import com.huanchengfly.tieba.post.activities.NewSearchActivity
|
||||||
import com.huanchengfly.tieba.post.arch.collectPartialAsState
|
import com.huanchengfly.tieba.post.arch.collectPartialAsState
|
||||||
|
import com.huanchengfly.tieba.post.arch.onEvent
|
||||||
import com.huanchengfly.tieba.post.arch.pageViewModel
|
import com.huanchengfly.tieba.post.arch.pageViewModel
|
||||||
import com.huanchengfly.tieba.post.goToActivity
|
import com.huanchengfly.tieba.post.goToActivity
|
||||||
import com.huanchengfly.tieba.post.ui.common.theme.compose.ExtendedTheme
|
import com.huanchengfly.tieba.post.ui.common.theme.compose.ExtendedTheme
|
||||||
import com.huanchengfly.tieba.post.ui.page.LocalNavigator
|
import com.huanchengfly.tieba.post.ui.page.LocalNavigator
|
||||||
import com.huanchengfly.tieba.post.ui.page.destinations.ForumPageDestination
|
import com.huanchengfly.tieba.post.ui.page.destinations.ForumPageDestination
|
||||||
|
import com.huanchengfly.tieba.post.ui.page.main.MainUiEvent
|
||||||
import com.huanchengfly.tieba.post.ui.widgets.Chip
|
import com.huanchengfly.tieba.post.ui.widgets.Chip
|
||||||
import com.huanchengfly.tieba.post.ui.widgets.compose.ActionItem
|
import com.huanchengfly.tieba.post.ui.widgets.compose.ActionItem
|
||||||
import com.huanchengfly.tieba.post.ui.widgets.compose.Avatar
|
import com.huanchengfly.tieba.post.ui.widgets.compose.Avatar
|
||||||
|
|
@ -93,6 +95,7 @@ import com.huanchengfly.tieba.post.utils.AccountUtil.LocalAccount
|
||||||
import com.huanchengfly.tieba.post.utils.ImageUtil
|
import com.huanchengfly.tieba.post.utils.ImageUtil
|
||||||
import com.huanchengfly.tieba.post.utils.TiebaUtil
|
import com.huanchengfly.tieba.post.utils.TiebaUtil
|
||||||
import com.huanchengfly.tieba.post.utils.appPreferences
|
import com.huanchengfly.tieba.post.utils.appPreferences
|
||||||
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
|
||||||
private fun getGridCells(context: Context, listSingle: Boolean = context.appPreferences.listSingle): GridCells {
|
private fun getGridCells(context: Context, listSingle: Boolean = context.appPreferences.listSingle): GridCells {
|
||||||
return if (listSingle) {
|
return if (listSingle) {
|
||||||
|
|
@ -370,6 +373,7 @@ private fun ForumItem(
|
||||||
@OptIn(ExperimentalMaterialApi::class)
|
@OptIn(ExperimentalMaterialApi::class)
|
||||||
@Composable
|
@Composable
|
||||||
fun HomePage(
|
fun HomePage(
|
||||||
|
eventFlow: Flow<MainUiEvent>,
|
||||||
viewModel: HomeViewModel = pageViewModel<HomeUiIntent, HomeViewModel>(
|
viewModel: HomeViewModel = pageViewModel<HomeUiIntent, HomeViewModel>(
|
||||||
listOf(
|
listOf(
|
||||||
HomeUiIntent.Refresh
|
HomeUiIntent.Refresh
|
||||||
|
|
@ -400,6 +404,10 @@ fun HomePage(
|
||||||
var listSingle by remember { mutableStateOf(context.appPreferences.listSingle) }
|
var listSingle by remember { mutableStateOf(context.appPreferences.listSingle) }
|
||||||
val gridCells by remember { derivedStateOf { getGridCells(context, listSingle) } }
|
val gridCells by remember { derivedStateOf { getGridCells(context, listSingle) } }
|
||||||
|
|
||||||
|
eventFlow.onEvent<MainUiEvent.Refresh> {
|
||||||
|
viewModel.send(HomeUiIntent.Refresh)
|
||||||
|
}
|
||||||
|
|
||||||
Scaffold(
|
Scaffold(
|
||||||
backgroundColor = Color.Transparent,
|
backgroundColor = Color.Transparent,
|
||||||
topBar = {
|
topBar = {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue