From e3199c1d8d6de39f14cc42c1bb12742eeccac04a Mon Sep 17 00:00:00 2001 From: HuanCheng65 <22636177+HuanCheng65@users.noreply.github.com> Date: Sun, 12 Mar 2023 15:44:55 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=94=B6=E8=97=8F=E9=A1=B5=E9=9D=A2?= =?UTF-8?q?=E7=8A=B6=E6=80=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ui/page/threadstore/ThreadStorePage.kt | 133 +++++++++++------- .../page/threadstore/ThreadStoreViewModel.kt | 10 +- 2 files changed, 88 insertions(+), 55 deletions(-) diff --git a/app/src/main/java/com/huanchengfly/tieba/post/ui/page/threadstore/ThreadStorePage.kt b/app/src/main/java/com/huanchengfly/tieba/post/ui/page/threadstore/ThreadStorePage.kt index bb1f740e..cc281829 100644 --- a/app/src/main/java/com/huanchengfly/tieba/post/ui/page/threadstore/ThreadStorePage.kt +++ b/app/src/main/java/com/huanchengfly/tieba/post/ui/page/threadstore/ThreadStorePage.kt @@ -20,7 +20,9 @@ import androidx.compose.material.pullrefresh.pullRefresh import androidx.compose.material.pullrefresh.rememberPullRefreshState import androidx.compose.material.rememberScaffoldState import androidx.compose.runtime.Composable +import androidx.compose.runtime.derivedStateOf import androidx.compose.runtime.getValue +import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color @@ -49,6 +51,7 @@ import com.huanchengfly.tieba.post.pxToSp import com.huanchengfly.tieba.post.ui.common.theme.compose.ExtendedTheme import com.huanchengfly.tieba.post.ui.widgets.compose.Avatar import com.huanchengfly.tieba.post.ui.widgets.compose.BackNavigationIcon +import com.huanchengfly.tieba.post.ui.widgets.compose.ErrorScreen 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.LongClickMenu @@ -56,6 +59,7 @@ import com.huanchengfly.tieba.post.ui.widgets.compose.MyScaffold import com.huanchengfly.tieba.post.ui.widgets.compose.Sizes import com.huanchengfly.tieba.post.ui.widgets.compose.TitleCentredToolbar import com.huanchengfly.tieba.post.ui.widgets.compose.UserHeader +import com.huanchengfly.tieba.post.ui.widgets.compose.states.StateScreen import com.huanchengfly.tieba.post.utils.StringUtil import com.huanchengfly.tieba.post.utils.StringUtil.getUsernameAnnotatedString import com.huanchengfly.tieba.post.utils.appPreferences @@ -100,12 +104,14 @@ fun ThreadStorePage( prop1 = ThreadStoreUiState::data, initial = emptyList() ) + val error by viewModel.uiState.collectPartialAsState( + prop1 = ThreadStoreUiState::error, + initial = null + ) + val isError by remember { derivedStateOf { error != null } } val context = LocalContext.current val scaffoldState = rememberScaffoldState() - val pullRefreshState = rememberPullRefreshState( - refreshing = isRefreshing, - onRefresh = { viewModel.send(ThreadStoreUiIntent.Refresh) }) viewModel.onEvent { scaffoldState.snackbarHostState.showSnackbar( context.getString( @@ -128,64 +134,87 @@ fun ThreadStorePage( } ) } - ) { paddingValues -> + ) { contentPaddings -> val textMeasurer = rememberTextMeasurer() - Box(modifier = Modifier.pullRefresh(pullRefreshState)) { - LoadMoreLayout( - isLoading = isLoadingMore, - onLoadMore = { viewModel.send(ThreadStoreUiIntent.LoadMore(currentPage + 1)) }, - loadEnd = !hasMore - ) { - LazyColumn(contentPadding = paddingValues) { - items( - items = data, - key = { it.threadId } - ) { info -> - LongClickMenu( - menuContent = { - DropdownMenuItem(onClick = { - viewModel.send( - ThreadStoreUiIntent.Delete( - info.threadId - ) - ) - }) { - Text(text = stringResource(id = R.string.title_collect_on)) - } - }, - onClick = { - ThreadActivity.launch( - context, - info.threadId, - info.markPid, - context.appPreferences.collectThreadSeeLz, - "collect", - info.maxPid - ) - } - ) { - StoreItem( - info = info, - onUserClick = { - info.author.lzUid?.let { - UserActivity.launch( - context, - it, StringUtil.getAvatarUrl(info.author.userPortrait) + StateScreen( + isEmpty = data.isEmpty(), + isError = isError, + isLoading = isRefreshing, + modifier = Modifier.padding(contentPaddings), + onReload = { + viewModel.send(ThreadStoreUiIntent.Refresh) + }, + errorScreen = { + error?.let { + val (e) = it + ErrorScreen(error = e) + } + } + ) { + val pullRefreshState = rememberPullRefreshState( + refreshing = isRefreshing, + onRefresh = { viewModel.send(ThreadStoreUiIntent.Refresh) } + ) + + Box(modifier = Modifier.pullRefresh(pullRefreshState)) { + LoadMoreLayout( + isLoading = isLoadingMore, + onLoadMore = { viewModel.send(ThreadStoreUiIntent.LoadMore(currentPage + 1)) }, + loadEnd = !hasMore + ) { + LazyColumn { + items( + items = data, + key = { it.threadId } + ) { info -> + LongClickMenu( + menuContent = { + DropdownMenuItem(onClick = { + viewModel.send( + ThreadStoreUiIntent.Delete( + info.threadId + ) ) + }) { + Text(text = stringResource(id = R.string.title_collect_on)) } }, - textMeasurer = textMeasurer - ) + onClick = { + ThreadActivity.launch( + context, + info.threadId, + info.markPid, + context.appPreferences.collectThreadSeeLz, + "collect", + info.maxPid + ) + } + ) { + StoreItem( + info = info, + onUserClick = { + info.author.lzUid?.let { + UserActivity.launch( + context, + it, + StringUtil.getAvatarUrl(info.author.userPortrait) + ) + } + }, + textMeasurer = textMeasurer + ) + } } } } + + PullRefreshIndicator( + refreshing = isRefreshing, + state = pullRefreshState, + modifier = Modifier.align(Alignment.TopCenter) + ) } - PullRefreshIndicator( - refreshing = isRefreshing, - state = pullRefreshState, - modifier = Modifier.align(Alignment.TopCenter) - ) } } } diff --git a/app/src/main/java/com/huanchengfly/tieba/post/ui/page/threadstore/ThreadStoreViewModel.kt b/app/src/main/java/com/huanchengfly/tieba/post/ui/page/threadstore/ThreadStoreViewModel.kt index d0b31970..c164b00b 100644 --- a/app/src/main/java/com/huanchengfly/tieba/post/ui/page/threadstore/ThreadStoreViewModel.kt +++ b/app/src/main/java/com/huanchengfly/tieba/post/ui/page/threadstore/ThreadStoreViewModel.kt @@ -6,11 +6,13 @@ import com.huanchengfly.tieba.post.api.models.ThreadStoreBean import com.huanchengfly.tieba.post.api.retrofit.exception.getErrorCode import com.huanchengfly.tieba.post.api.retrofit.exception.getErrorMessage import com.huanchengfly.tieba.post.arch.BaseViewModel +import com.huanchengfly.tieba.post.arch.ImmutableHolder 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 com.huanchengfly.tieba.post.arch.wrapImmutable import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.FlowPreview import kotlinx.coroutines.flow.Flow @@ -103,13 +105,14 @@ sealed interface ThreadStoreUiIntent : UiIntent { sealed interface ThreadStorePartialChange : PartialChange { sealed class Refresh : ThreadStorePartialChange { override fun reduce(oldState: ThreadStoreUiState): ThreadStoreUiState = when (this) { - is Failure -> oldState.copy(isRefreshing = false) + is Failure -> oldState.copy(isRefreshing = false, error = wrapImmutable(error)) Start -> oldState.copy(isRefreshing = true) is Success -> oldState.copy( isRefreshing = false, data = data, currentPage = 0, - hasMore = hasMore + hasMore = hasMore, + error = null ) } @@ -171,7 +174,8 @@ data class ThreadStoreUiState( val isLoadingMore: Boolean = false, val hasMore: Boolean = true, val currentPage: Int = 1, - val data: List = emptyList() + val data: List = emptyList(), + val error: ImmutableHolder? = null ) : UiState sealed interface ThreadStoreUiEvent : UiEvent {