diff --git a/app/src/main/java/com/huanchengfly/tieba/post/ui/page/main/MainPage.kt b/app/src/main/java/com/huanchengfly/tieba/post/ui/page/main/MainPage.kt index 680b5d73..8549f873 100644 --- a/app/src/main/java/com/huanchengfly/tieba/post/ui/page/main/MainPage.kt +++ b/app/src/main/java/com/huanchengfly/tieba/post/ui/page/main/MainPage.kt @@ -18,6 +18,7 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue +import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.ui.Alignment 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.RootNavGraph import com.ramcosta.composedestinations.navigation.DestinationsNavigator +import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.launch @@ -56,6 +58,7 @@ import kotlinx.coroutines.launch private fun NavigationWrapper( currentPosition: Int, onChangePosition: (position: Int) -> Unit, + onReselected: (position: Int) -> Unit, navigationItems: List, navigationType: MainNavigationType, navigationContentPosition: MainNavigationContentPosition, @@ -66,6 +69,7 @@ private fun NavigationWrapper( NavigationDrawerContent( currentPosition = currentPosition, onChangePosition = onChangePosition, + onReselected = onReselected, navigationItems = navigationItems, navigationContentPosition = navigationContentPosition ) @@ -74,6 +78,7 @@ private fun NavigationWrapper( NavigationRail( currentPosition = currentPosition, onChangePosition = onChangePosition, + onReselected = onReselected, navigationItems = navigationItems, navigationContentPosition = navigationContentPosition ) @@ -100,6 +105,15 @@ fun MainPage( initial = 0 ) + val eventFlows = remember { + listOf( + MutableSharedFlow(), + MutableSharedFlow(), + MutableSharedFlow(), + MutableSharedFlow(), + ) + } + val notificationCountFlow = LocalNotificationCountFlow.current LaunchedEffect(null) { notificationCountFlow.collect { @@ -118,13 +132,13 @@ fun MainPage( title = stringResource(id = R.string.title_main), content = { HomePage( - canOpenExplore = !LocalContext.current.appPreferences.hideExplore, - onOpenExplore = { - coroutineScope.launch { - pagerState.scrollToPage(1) - } + eventFlow = eventFlows[0], + canOpenExplore = !LocalContext.current.appPreferences.hideExplore + ) { + coroutineScope.launch { + pagerState.scrollToPage(1) } - ) + } } ), if (LocalContext.current.appPreferences.hideExplore) null @@ -136,7 +150,7 @@ fun MainPage( }, title = stringResource(id = R.string.title_explore), content = { - ExplorePage() + ExplorePage(eventFlows[1]) } ), NavigationItem( @@ -187,17 +201,25 @@ fun MainPage( WindowHeightSizeClass.Compact -> { MainNavigationContentPosition.TOP } + WindowHeightSizeClass.Medium, WindowHeightSizeClass.Expanded -> { MainNavigationContentPosition.CENTER } + else -> { MainNavigationContentPosition.TOP } } + val onReselected: (Int) -> Unit = { + coroutineScope.launch { + eventFlows[it].emit(MainUiEvent.Refresh) + } + } NavigationWrapper( currentPosition = pagerState.currentPage, onChangePosition = { coroutineScope.launch { pagerState.scrollToPage(it) } }, + onReselected = onReselected, navigationItems = navigationItems, navigationType = navigationType, navigationContentPosition = navigationContentPosition @@ -209,7 +231,10 @@ fun MainPage( AnimatedVisibility(visible = navigationType == MainNavigationType.BOTTOM_NAVIGATION) { BottomNavigation( currentPosition = pagerState.currentPage, - onChangePosition = { coroutineScope.launch { pagerState.scrollToPage(it) } }, + onChangePosition = { + coroutineScope.launch { pagerState.scrollToPage(it) } + }, + onReselected = onReselected, navigationItems = navigationItems, themeColors = themeColors, ) diff --git a/app/src/main/java/com/huanchengfly/tieba/post/ui/page/main/MainViewModel.kt b/app/src/main/java/com/huanchengfly/tieba/post/ui/page/main/MainViewModel.kt index 66030c68..382980e7 100644 --- a/app/src/main/java/com/huanchengfly/tieba/post/ui/page/main/MainViewModel.kt +++ b/app/src/main/java/com/huanchengfly/tieba/post/ui/page/main/MainViewModel.kt @@ -1,6 +1,11 @@ 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 kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.filterIsInstance @@ -50,4 +55,6 @@ sealed interface MainPartialChange : PartialChange { data class MainUiState(val messageCount: Int = 0) : UiState -sealed interface MainUiEvent : UiEvent \ No newline at end of file +sealed interface MainUiEvent : UiEvent { + object Refresh : MainUiEvent +} \ No newline at end of file diff --git a/app/src/main/java/com/huanchengfly/tieba/post/ui/page/main/NavigationComponents.kt b/app/src/main/java/com/huanchengfly/tieba/post/ui/page/main/NavigationComponents.kt index 650162bc..b2be6f5b 100644 --- a/app/src/main/java/com/huanchengfly/tieba/post/ui/page/main/NavigationComponents.kt +++ b/app/src/main/java/com/huanchengfly/tieba/post/ui/page/main/NavigationComponents.kt @@ -129,6 +129,7 @@ fun NavigationDrawerItem( fun NavigationDrawerContent( currentPosition: Int, onChangePosition: (position: Int) -> Unit, + onReselected: (position: Int) -> Unit, navigationItems: List, navigationContentPosition: MainNavigationContentPosition ) { @@ -191,7 +192,13 @@ fun NavigationDrawerContent( navigationItems.forEachIndexed { index, navigationItem -> NavigationDrawerItem( selected = index == currentPosition, - onClick = { onChangePosition(index) }, + onClick = { + if (index == currentPosition) { + onReselected(index) + } else { + onChangePosition(index) + } + }, label = { Text(text = navigationItem.title) }, icon = { Box { @@ -275,6 +282,7 @@ private fun PositionLayout( fun NavigationRail( currentPosition: Int, onChangePosition: (position: Int) -> Unit, + onReselected: (position: Int) -> Unit, navigationItems: List, navigationContentPosition: MainNavigationContentPosition ) { @@ -296,7 +304,13 @@ fun NavigationRail( navigationItems.forEachIndexed { index, navigationItem -> NavigationRailItem( selected = index == currentPosition, - onClick = { onChangePosition(index) }, + onClick = { + if (index == currentPosition) { + onReselected(index) + } else { + onChangePosition(index) + } + }, icon = { Box { Icon( @@ -345,6 +359,7 @@ fun BottomNavigationDivider( fun BottomNavigation( currentPosition: Int, onChangePosition: (position: Int) -> Unit, + onReselected: (position: Int) -> Unit, navigationItems: List, themeColors: ExtendedColors = ExtendedTheme.colors ) { @@ -358,7 +373,11 @@ fun BottomNavigation( BottomNavigationItem( selected = index == currentPosition, onClick = { - onChangePosition(index) + if (index == currentPosition) { + onReselected(index) + } else { + onChangePosition(index) + } navigationItem.onClick?.invoke() }, icon = { diff --git a/app/src/main/java/com/huanchengfly/tieba/post/ui/page/main/explore/ExplorePage.kt b/app/src/main/java/com/huanchengfly/tieba/post/ui/page/main/explore/ExplorePage.kt index d6cffd18..55a068f5 100644 --- a/app/src/main/java/com/huanchengfly/tieba/post/ui/page/main/explore/ExplorePage.kt +++ b/app/src/main/java/com/huanchengfly/tieba/post/ui/page/main/explore/ExplorePage.kt @@ -9,6 +9,7 @@ import androidx.compose.material.Text import androidx.compose.material.icons.Icons import androidx.compose.material.icons.rounded.Search import androidx.compose.runtime.Composable +import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier @@ -21,8 +22,10 @@ import com.google.accompanist.pager.HorizontalPager import com.google.accompanist.pager.rememberPagerState import com.huanchengfly.tieba.post.R 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.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.hot.HotPage 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.accountNavIconIfCompact import com.huanchengfly.tieba.post.utils.AccountUtil.LocalAccount +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.launch @OptIn(ExperimentalPagerApi::class) @Composable -fun ExplorePage() { +fun ExplorePage( + eventFlow: Flow, +) { val account = LocalAccount.current val context = LocalContext.current + + val eventFlows = remember { + listOf( + MutableSharedFlow(), + MutableSharedFlow(), + MutableSharedFlow() + ) + } + + val firstIndex = if (account != null) 0 else -1 + val pages = listOfNotNull Unit)>>( if (account != null) stringResource(id = R.string.title_concern) to @Composable { - ConcernPage() + ConcernPage(eventFlows[firstIndex + 0]) } else null, stringResource(id = R.string.title_personalized) to @Composable { - PersonalizedPage() + PersonalizedPage(eventFlows[firstIndex + 1]) }, stringResource(id = R.string.title_hot) to @Composable { - HotPage() + HotPage(eventFlows[firstIndex + 2]) }, ) val pagerState = rememberPagerState(initialPage = if (account != null) 1 else 0) val coroutineScope = rememberCoroutineScope() + + eventFlow.onEvent { + eventFlows[pagerState.currentPage].emit(it) + } + Scaffold( backgroundColor = Color.Transparent, topBar = { @@ -88,7 +111,11 @@ fun ExplorePage() { selected = pagerState.currentPage == index, onClick = { coroutineScope.launch { - pagerState.animateScrollToPage(index) + if (pagerState.currentPage == index) { + eventFlows[pagerState.currentPage].emit(MainUiEvent.Refresh) + } else { + pagerState.animateScrollToPage(index) + } } }, ) diff --git a/app/src/main/java/com/huanchengfly/tieba/post/ui/page/main/explore/concern/ConcernPage.kt b/app/src/main/java/com/huanchengfly/tieba/post/ui/page/main/explore/concern/ConcernPage.kt index 211d1a6c..8e132666 100644 --- a/app/src/main/java/com/huanchengfly/tieba/post/ui/page/main/explore/concern/ConcernPage.kt +++ b/app/src/main/java/com/huanchengfly/tieba/post/ui/page/main/explore/concern/ConcernPage.kt @@ -19,16 +19,20 @@ import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.unit.dp import com.huanchengfly.tieba.post.activities.ThreadActivity 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.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.LazyLoad import com.huanchengfly.tieba.post.ui.widgets.compose.LoadMoreLayout import com.huanchengfly.tieba.post.ui.widgets.compose.VerticalDivider +import kotlinx.coroutines.flow.Flow @OptIn(ExperimentalFoundationApi::class, ExperimentalMaterialApi::class) @Composable fun ConcernPage( + eventFlow: Flow, viewModel: ConcernViewModel = pageViewModel() ) { LazyLoad(loaded = viewModel.initialized) { @@ -55,6 +59,11 @@ fun ConcernPage( val pullRefreshState = rememberPullRefreshState( refreshing = isRefreshing, onRefresh = { viewModel.send(ConcernUiIntent.Refresh) }) + + eventFlow.onEvent { + viewModel.send(ConcernUiIntent.Refresh) + } + Box( modifier = Modifier.pullRefresh(pullRefreshState) ) { diff --git a/app/src/main/java/com/huanchengfly/tieba/post/ui/page/main/explore/hot/HotPage.kt b/app/src/main/java/com/huanchengfly/tieba/post/ui/page/main/explore/hot/HotPage.kt index 856f0a96..d0673132 100644 --- a/app/src/main/java/com/huanchengfly/tieba/post/ui/page/main/explore/hot/HotPage.kt +++ b/app/src/main/java/com/huanchengfly/tieba/post/ui/page/main/explore/hot/HotPage.kt @@ -47,6 +47,7 @@ import com.google.accompanist.placeholder.material.placeholder import com.huanchengfly.tieba.post.R import com.huanchengfly.tieba.post.api.models.protos.ThreadInfo 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.ui.common.theme.compose.ExtendedTheme 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.page.LocalNavigator 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.NetworkImage 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.utils.StringUtil.getShortNumString import com.ramcosta.composedestinations.annotation.Destination +import kotlinx.coroutines.flow.Flow @OptIn(ExperimentalFoundationApi::class, ExperimentalMaterialApi::class) @Destination @Composable fun HotPage( + eventFlow: Flow, viewModel: HotViewModel = pageViewModel() ) { LazyLoad(loaded = viewModel.initialized) { viewModel.send(HotUiIntent.Load) viewModel.initialized = true } + eventFlow.onEvent { + viewModel.send(HotUiIntent.Load) + } val navigator = LocalNavigator.current val isLoading by viewModel.uiState.collectPartialAsState( prop1 = HotUiState::isRefreshing, diff --git a/app/src/main/java/com/huanchengfly/tieba/post/ui/page/main/explore/personalized/PersonalizedPage.kt b/app/src/main/java/com/huanchengfly/tieba/post/ui/page/main/explore/personalized/PersonalizedPage.kt index c2d3067b..31d10280 100644 --- a/app/src/main/java/com/huanchengfly/tieba/post/ui/page/main/explore/personalized/PersonalizedPage.kt +++ b/app/src/main/java/com/huanchengfly/tieba/post/ui/page/main/explore/personalized/PersonalizedPage.kt @@ -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.ThreadPersonalized 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.wrapImmutable 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.LazyLoad import com.huanchengfly.tieba.post.ui.widgets.compose.LoadMoreLayout import com.huanchengfly.tieba.post.ui.widgets.compose.VerticalDivider import kotlinx.coroutines.delay -import kotlinx.coroutines.flow.filterIsInstance -import kotlinx.coroutines.launch +import kotlinx.coroutines.flow.Flow @OptIn(ExperimentalFoundationApi::class, ExperimentalMaterialApi::class) @Composable fun PersonalizedPage( + eventFlow: Flow, viewModel: PersonalizedViewModel = pageViewModel() ) { LazyLoad(loaded = viewModel.initialized) { @@ -113,16 +115,15 @@ fun PersonalizedPage( var showRefreshTip by remember { mutableStateOf(false) } - LaunchedEffect(Unit) { - launch { - viewModel.uiEventFlow - .filterIsInstance() - .collect { - refreshCount = it.count - showRefreshTip = true - } - } + + eventFlow.onEvent { + viewModel.send(PersonalizedUiIntent.Refresh) } + viewModel.onEvent { + refreshCount = it.count + showRefreshTip = true + } + if (showRefreshTip) { LaunchedEffect(Unit) { delay(2000) diff --git a/app/src/main/java/com/huanchengfly/tieba/post/ui/page/main/home/HomePage.kt b/app/src/main/java/com/huanchengfly/tieba/post/ui/page/main/home/HomePage.kt index b0d3d78b..c82eac10 100644 --- a/app/src/main/java/com/huanchengfly/tieba/post/ui/page/main/home/HomePage.kt +++ b/app/src/main/java/com/huanchengfly/tieba/post/ui/page/main/home/HomePage.kt @@ -70,11 +70,13 @@ import com.huanchengfly.tieba.post.R import com.huanchengfly.tieba.post.activities.LoginActivity import com.huanchengfly.tieba.post.activities.NewSearchActivity 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.goToActivity 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.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.compose.ActionItem 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.TiebaUtil import com.huanchengfly.tieba.post.utils.appPreferences +import kotlinx.coroutines.flow.Flow private fun getGridCells(context: Context, listSingle: Boolean = context.appPreferences.listSingle): GridCells { return if (listSingle) { @@ -370,6 +373,7 @@ private fun ForumItem( @OptIn(ExperimentalMaterialApi::class) @Composable fun HomePage( + eventFlow: Flow, viewModel: HomeViewModel = pageViewModel( listOf( HomeUiIntent.Refresh @@ -400,6 +404,10 @@ fun HomePage( var listSingle by remember { mutableStateOf(context.appPreferences.listSingle) } val gridCells by remember { derivedStateOf { getGridCells(context, listSingle) } } + eventFlow.onEvent { + viewModel.send(HomeUiIntent.Refresh) + } + Scaffold( backgroundColor = Color.Transparent, topBar = {