mirror of
https://github.com/vitorpamplona/amethyst.git
synced 2025-03-18 05:41:56 +01:00
Adds Home-only empty feed screen.
This commit is contained in:
parent
16c171ec40
commit
a301421915
@ -54,7 +54,7 @@ fun RefreshingChatroomFeedView(
|
||||
scrollStateKey: String? = null,
|
||||
enablePullRefresh: Boolean = true,
|
||||
) {
|
||||
RefresheableView(viewModel, enablePullRefresh) {
|
||||
RefresheableBox(viewModel, enablePullRefresh) {
|
||||
SaveableFeedState(viewModel, scrollStateKey) { listState ->
|
||||
RenderChatroomFeedView(
|
||||
viewModel,
|
||||
|
@ -45,7 +45,7 @@ fun ChatroomListFeedView(
|
||||
nav: (String) -> Unit,
|
||||
markAsRead: MutableState<Boolean>,
|
||||
) {
|
||||
RefresheableView(viewModel, true) { CrossFadeState(viewModel, accountViewModel, nav, markAsRead) }
|
||||
RefresheableBox(viewModel, true) { CrossFadeState(viewModel, accountViewModel, nav, markAsRead) }
|
||||
}
|
||||
|
||||
@Composable
|
||||
|
@ -27,6 +27,7 @@ import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxHeight
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
@ -56,6 +57,7 @@ import com.vitorpamplona.amethyst.R
|
||||
import com.vitorpamplona.amethyst.ui.note.NoteCompose
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
||||
import com.vitorpamplona.amethyst.ui.theme.FeedPadding
|
||||
import com.vitorpamplona.amethyst.ui.theme.StdVertSpacer
|
||||
import kotlin.time.ExperimentalTime
|
||||
|
||||
@Composable
|
||||
@ -67,13 +69,15 @@ fun RefresheableFeedView(
|
||||
accountViewModel: AccountViewModel,
|
||||
nav: (String) -> Unit,
|
||||
) {
|
||||
RefresheableView(viewModel, enablePullRefresh) {
|
||||
SaveableFeedState(viewModel, routeForLastRead, scrollStateKey, accountViewModel, nav)
|
||||
RefresheableBox(viewModel, enablePullRefresh) {
|
||||
SaveableFeedState(viewModel, scrollStateKey) { listState ->
|
||||
RenderFeedState(viewModel, accountViewModel, listState, nav, routeForLastRead)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun RefresheableView(
|
||||
fun RefresheableBox(
|
||||
viewModel: InvalidatableViewModel,
|
||||
enablePullRefresh: Boolean = true,
|
||||
content: @Composable () -> Unit,
|
||||
@ -108,19 +112,6 @@ fun RefresheableView(
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun SaveableFeedState(
|
||||
viewModel: FeedViewModel,
|
||||
routeForLastRead: String?,
|
||||
scrollStateKey: String? = null,
|
||||
accountViewModel: AccountViewModel,
|
||||
nav: (String) -> Unit,
|
||||
) {
|
||||
SaveableFeedState(viewModel, scrollStateKey) { listState ->
|
||||
RenderFeed(viewModel, accountViewModel, listState, nav, routeForLastRead)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun SaveableFeedState(
|
||||
viewModel: FeedViewModel,
|
||||
@ -158,12 +149,16 @@ fun SaveableGridFeedState(
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun RenderFeed(
|
||||
fun RenderFeedState(
|
||||
viewModel: FeedViewModel,
|
||||
accountViewModel: AccountViewModel,
|
||||
listState: LazyListState,
|
||||
nav: (String) -> Unit,
|
||||
routeForLastRead: String?,
|
||||
onLoaded: @Composable (FeedState.Loaded) -> Unit = { FeedLoaded(it, listState, routeForLastRead, accountViewModel, nav) },
|
||||
onEmpty: @Composable () -> Unit = { FeedEmpty { viewModel.invalidateData() } },
|
||||
onError: @Composable (String) -> Unit = { FeedError(it) { viewModel.invalidateData() } },
|
||||
onLoading: @Composable () -> Unit = { LoadingFeed() },
|
||||
) {
|
||||
val feedState by viewModel.feedContent.collectAsStateWithLifecycle()
|
||||
|
||||
@ -172,24 +167,10 @@ private fun RenderFeed(
|
||||
animationSpec = tween(durationMillis = 100),
|
||||
) { state ->
|
||||
when (state) {
|
||||
is FeedState.Empty -> {
|
||||
FeedEmpty { viewModel.invalidateData() }
|
||||
}
|
||||
is FeedState.FeedError -> {
|
||||
FeedError(state.errorMessage) { viewModel.invalidateData() }
|
||||
}
|
||||
is FeedState.Loaded -> {
|
||||
FeedLoaded(
|
||||
state = state,
|
||||
listState = listState,
|
||||
routeForLastRead = routeForLastRead,
|
||||
accountViewModel = accountViewModel,
|
||||
nav = nav,
|
||||
)
|
||||
}
|
||||
is FeedState.Loading -> {
|
||||
LoadingFeed()
|
||||
}
|
||||
is FeedState.Empty -> onEmpty()
|
||||
is FeedState.FeedError -> onError(state.errorMessage)
|
||||
is FeedState.Loaded -> onLoaded(state)
|
||||
is FeedState.Loading -> onLoading()
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -277,6 +258,7 @@ fun FeedError(
|
||||
verticalArrangement = Arrangement.Center,
|
||||
) {
|
||||
Text("${stringResource(R.string.error_loading_replies)} $errorMessage")
|
||||
Spacer(modifier = StdVertSpacer)
|
||||
Button(
|
||||
modifier = Modifier.align(Alignment.CenterHorizontally),
|
||||
onClick = onRefresh,
|
||||
@ -294,6 +276,7 @@ fun FeedEmpty(onRefresh: () -> Unit) {
|
||||
verticalArrangement = Arrangement.Center,
|
||||
) {
|
||||
Text(stringResource(R.string.feed_is_empty))
|
||||
Spacer(modifier = StdVertSpacer)
|
||||
OutlinedButton(onClick = onRefresh) { Text(text = stringResource(R.string.refresh)) }
|
||||
}
|
||||
}
|
||||
|
@ -45,7 +45,7 @@ fun RefreshingFeedStringFeedView(
|
||||
enablePullRefresh: Boolean = true,
|
||||
inner: @Composable (String) -> Unit,
|
||||
) {
|
||||
RefresheableView(viewModel, enablePullRefresh) { StringFeedView(viewModel, inner = inner) }
|
||||
RefresheableBox(viewModel, enablePullRefresh) { StringFeedView(viewModel, inner = inner) }
|
||||
}
|
||||
|
||||
@Composable
|
||||
|
@ -39,7 +39,7 @@ fun RefreshingFeedUserFeedView(
|
||||
nav: (String) -> Unit,
|
||||
enablePullRefresh: Boolean = true,
|
||||
) {
|
||||
RefresheableView(viewModel, enablePullRefresh) { UserFeedView(viewModel, accountViewModel, nav) }
|
||||
RefresheableBox(viewModel, enablePullRefresh) { UserFeedView(viewModel, accountViewModel, nav) }
|
||||
}
|
||||
|
||||
@Composable
|
||||
|
@ -69,7 +69,7 @@ import com.vitorpamplona.amethyst.ui.screen.NostrDiscoverCommunityFeedViewModel
|
||||
import com.vitorpamplona.amethyst.ui.screen.NostrDiscoverLiveFeedViewModel
|
||||
import com.vitorpamplona.amethyst.ui.screen.NostrDiscoverMarketplaceFeedViewModel
|
||||
import com.vitorpamplona.amethyst.ui.screen.PagerStateKeys
|
||||
import com.vitorpamplona.amethyst.ui.screen.RefresheableView
|
||||
import com.vitorpamplona.amethyst.ui.screen.RefresheableBox
|
||||
import com.vitorpamplona.amethyst.ui.screen.SaveableFeedState
|
||||
import com.vitorpamplona.amethyst.ui.screen.SaveableGridFeedState
|
||||
import com.vitorpamplona.amethyst.ui.screen.ScrollStateKeys
|
||||
@ -196,7 +196,7 @@ private fun DiscoverPages(
|
||||
}
|
||||
|
||||
HorizontalPager(state = pagerState) { page ->
|
||||
RefresheableView(tabs[page].viewModel, true) {
|
||||
RefresheableBox(tabs[page].viewModel, true) {
|
||||
if (tabs[page].viewModel is NostrDiscoverMarketplaceFeedViewModel) {
|
||||
SaveableGridFeedState(tabs[page].viewModel, scrollStateKey = tabs[page].scrollStateKey) {
|
||||
listState ->
|
||||
|
@ -71,7 +71,7 @@ import com.vitorpamplona.amethyst.ui.elements.AddButton
|
||||
import com.vitorpamplona.amethyst.ui.screen.NostrHiddenAccountsFeedViewModel
|
||||
import com.vitorpamplona.amethyst.ui.screen.NostrHiddenWordsFeedViewModel
|
||||
import com.vitorpamplona.amethyst.ui.screen.NostrSpammerAccountsFeedViewModel
|
||||
import com.vitorpamplona.amethyst.ui.screen.RefresheableView
|
||||
import com.vitorpamplona.amethyst.ui.screen.RefresheableBox
|
||||
import com.vitorpamplona.amethyst.ui.screen.RefreshingFeedUserFeedView
|
||||
import com.vitorpamplona.amethyst.ui.screen.StringFeedView
|
||||
import com.vitorpamplona.amethyst.ui.screen.UserFeedViewModel
|
||||
@ -216,7 +216,7 @@ private fun HiddenWordsFeed(
|
||||
hiddenWordsViewModel: NostrHiddenWordsFeedViewModel,
|
||||
accountViewModel: AccountViewModel,
|
||||
) {
|
||||
RefresheableView(hiddenWordsViewModel, false) {
|
||||
RefresheableBox(hiddenWordsViewModel, false) {
|
||||
StringFeedView(
|
||||
hiddenWordsViewModel,
|
||||
post = { AddMuteWordTextField(accountViewModel) },
|
||||
|
@ -22,11 +22,15 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn
|
||||
|
||||
import androidx.compose.animation.Crossfade
|
||||
import androidx.compose.foundation.ExperimentalFoundationApi
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxHeight
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.pager.HorizontalPager
|
||||
import androidx.compose.foundation.pager.PagerState
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.OutlinedButton
|
||||
import androidx.compose.material3.Tab
|
||||
import androidx.compose.material3.TabRow
|
||||
import androidx.compose.material3.Text
|
||||
@ -39,9 +43,11 @@ import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalLifecycleOwner
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import androidx.lifecycle.LifecycleEventObserver
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
@ -54,10 +60,14 @@ import com.vitorpamplona.amethyst.ui.screen.FeedViewModel
|
||||
import com.vitorpamplona.amethyst.ui.screen.NostrHomeFeedViewModel
|
||||
import com.vitorpamplona.amethyst.ui.screen.NostrHomeRepliesFeedViewModel
|
||||
import com.vitorpamplona.amethyst.ui.screen.PagerStateKeys
|
||||
import com.vitorpamplona.amethyst.ui.screen.RefresheableFeedView
|
||||
import com.vitorpamplona.amethyst.ui.screen.RefresheableBox
|
||||
import com.vitorpamplona.amethyst.ui.screen.RenderFeedState
|
||||
import com.vitorpamplona.amethyst.ui.screen.SaveableFeedState
|
||||
import com.vitorpamplona.amethyst.ui.screen.ScrollStateKeys
|
||||
import com.vitorpamplona.amethyst.ui.screen.rememberForeverPagerState
|
||||
import com.vitorpamplona.amethyst.ui.theme.StdVertSpacer
|
||||
import com.vitorpamplona.amethyst.ui.theme.TabRowHeight
|
||||
import com.vitorpamplona.amethyst.ui.theme.ThemeComparisonRow
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.collections.immutable.toImmutableList
|
||||
import kotlinx.coroutines.launch
|
||||
@ -181,7 +191,7 @@ private fun HomePages(
|
||||
}
|
||||
|
||||
HorizontalPager(state = pagerState, userScrollEnabled = false) { page ->
|
||||
RefresheableFeedView(
|
||||
HomeFeeds(
|
||||
viewModel = tabs[page].viewModel,
|
||||
routeForLastRead = tabs[page].routeForLastRead,
|
||||
scrollStateKey = tabs[page].scrollStateKey,
|
||||
@ -191,6 +201,51 @@ private fun HomePages(
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun HomeFeeds(
|
||||
viewModel: FeedViewModel,
|
||||
routeForLastRead: String?,
|
||||
enablePullRefresh: Boolean = true,
|
||||
scrollStateKey: String? = null,
|
||||
accountViewModel: AccountViewModel,
|
||||
nav: (String) -> Unit,
|
||||
) {
|
||||
RefresheableBox(viewModel, enablePullRefresh) {
|
||||
SaveableFeedState(viewModel, scrollStateKey) { listState ->
|
||||
RenderFeedState(
|
||||
viewModel = viewModel,
|
||||
accountViewModel = accountViewModel,
|
||||
listState = listState,
|
||||
nav = nav,
|
||||
routeForLastRead = routeForLastRead,
|
||||
onEmpty = { HomeFeedEmpty { viewModel.invalidateData() } },
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
fun HomeFeedEmptyPreview() {
|
||||
ThemeComparisonRow(
|
||||
onDark = { HomeFeedEmpty {} },
|
||||
onLight = { HomeFeedEmpty {} },
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun HomeFeedEmpty(onRefresh: () -> Unit) {
|
||||
Column(
|
||||
Modifier.fillMaxSize(),
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
verticalArrangement = Arrangement.Center,
|
||||
) {
|
||||
Text(stringResource(R.string.feed_is_empty))
|
||||
Spacer(modifier = StdVertSpacer)
|
||||
OutlinedButton(onClick = onRefresh) { Text(text = stringResource(R.string.refresh)) }
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun CheckIfUrlIsOnline(
|
||||
url: String,
|
||||
|
@ -86,7 +86,7 @@ import com.vitorpamplona.amethyst.ui.screen.FeedState
|
||||
import com.vitorpamplona.amethyst.ui.screen.FeedViewModel
|
||||
import com.vitorpamplona.amethyst.ui.screen.LoadingFeed
|
||||
import com.vitorpamplona.amethyst.ui.screen.NostrVideoFeedViewModel
|
||||
import com.vitorpamplona.amethyst.ui.screen.RefresheableView
|
||||
import com.vitorpamplona.amethyst.ui.screen.RefresheableBox
|
||||
import com.vitorpamplona.amethyst.ui.screen.ScrollStateKeys
|
||||
import com.vitorpamplona.amethyst.ui.screen.rememberForeverPagerState
|
||||
import com.vitorpamplona.amethyst.ui.theme.Size35Modifier
|
||||
@ -214,7 +214,7 @@ private fun LoadedState(
|
||||
|
||||
WatchScrollToTop(videoFeedView, pagerState)
|
||||
|
||||
RefresheableView(viewModel = videoFeedView) {
|
||||
RefresheableBox(viewModel = videoFeedView) {
|
||||
SlidingCarousel(
|
||||
state.feed,
|
||||
pagerState,
|
||||
|
Loading…
x
Reference in New Issue
Block a user