feat: 收藏页面状态

This commit is contained in:
HuanCheng65 2023-03-12 15:44:55 +08:00
parent 83a855b2d4
commit e3199c1d8d
No known key found for this signature in database
GPG Key ID: E9031EF91A805148
2 changed files with 88 additions and 55 deletions

View File

@ -20,7 +20,9 @@ import androidx.compose.material.pullrefresh.pullRefresh
import androidx.compose.material.pullrefresh.rememberPullRefreshState import androidx.compose.material.pullrefresh.rememberPullRefreshState
import androidx.compose.material.rememberScaffoldState import androidx.compose.material.rememberScaffoldState
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.derivedStateOf
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color 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.common.theme.compose.ExtendedTheme
import com.huanchengfly.tieba.post.ui.widgets.compose.Avatar 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.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.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.LongClickMenu 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.Sizes
import com.huanchengfly.tieba.post.ui.widgets.compose.TitleCentredToolbar 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.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
import com.huanchengfly.tieba.post.utils.StringUtil.getUsernameAnnotatedString import com.huanchengfly.tieba.post.utils.StringUtil.getUsernameAnnotatedString
import com.huanchengfly.tieba.post.utils.appPreferences import com.huanchengfly.tieba.post.utils.appPreferences
@ -100,12 +104,14 @@ fun ThreadStorePage(
prop1 = ThreadStoreUiState::data, prop1 = ThreadStoreUiState::data,
initial = emptyList() 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 context = LocalContext.current
val scaffoldState = rememberScaffoldState() val scaffoldState = rememberScaffoldState()
val pullRefreshState = rememberPullRefreshState(
refreshing = isRefreshing,
onRefresh = { viewModel.send(ThreadStoreUiIntent.Refresh) })
viewModel.onEvent<ThreadStoreUiEvent.Delete.Failure> { viewModel.onEvent<ThreadStoreUiEvent.Delete.Failure> {
scaffoldState.snackbarHostState.showSnackbar( scaffoldState.snackbarHostState.showSnackbar(
context.getString( context.getString(
@ -128,16 +134,36 @@ fun ThreadStorePage(
} }
) )
} }
) { paddingValues -> ) { contentPaddings ->
val textMeasurer = rememberTextMeasurer() val textMeasurer = rememberTextMeasurer()
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)) { Box(modifier = Modifier.pullRefresh(pullRefreshState)) {
LoadMoreLayout( LoadMoreLayout(
isLoading = isLoadingMore, isLoading = isLoadingMore,
onLoadMore = { viewModel.send(ThreadStoreUiIntent.LoadMore(currentPage + 1)) }, onLoadMore = { viewModel.send(ThreadStoreUiIntent.LoadMore(currentPage + 1)) },
loadEnd = !hasMore loadEnd = !hasMore
) { ) {
LazyColumn(contentPadding = paddingValues) { LazyColumn {
items( items(
items = data, items = data,
key = { it.threadId } key = { it.threadId }
@ -171,7 +197,8 @@ fun ThreadStorePage(
info.author.lzUid?.let { info.author.lzUid?.let {
UserActivity.launch( UserActivity.launch(
context, context,
it, StringUtil.getAvatarUrl(info.author.userPortrait) it,
StringUtil.getAvatarUrl(info.author.userPortrait)
) )
} }
}, },
@ -181,6 +208,7 @@ fun ThreadStorePage(
} }
} }
} }
PullRefreshIndicator( PullRefreshIndicator(
refreshing = isRefreshing, refreshing = isRefreshing,
state = pullRefreshState, state = pullRefreshState,
@ -188,6 +216,7 @@ fun ThreadStorePage(
) )
} }
} }
}
} }
@OptIn(ExperimentalTextApi::class) @OptIn(ExperimentalTextApi::class)

View File

@ -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.getErrorCode
import com.huanchengfly.tieba.post.api.retrofit.exception.getErrorMessage import com.huanchengfly.tieba.post.api.retrofit.exception.getErrorMessage
import com.huanchengfly.tieba.post.arch.BaseViewModel 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.PartialChange
import com.huanchengfly.tieba.post.arch.PartialChangeProducer import com.huanchengfly.tieba.post.arch.PartialChangeProducer
import com.huanchengfly.tieba.post.arch.UiEvent import com.huanchengfly.tieba.post.arch.UiEvent
import com.huanchengfly.tieba.post.arch.UiIntent import com.huanchengfly.tieba.post.arch.UiIntent
import com.huanchengfly.tieba.post.arch.UiState import com.huanchengfly.tieba.post.arch.UiState
import com.huanchengfly.tieba.post.arch.wrapImmutable
import dagger.hilt.android.lifecycle.HiltViewModel import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.FlowPreview import kotlinx.coroutines.FlowPreview
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
@ -103,13 +105,14 @@ sealed interface ThreadStoreUiIntent : UiIntent {
sealed interface ThreadStorePartialChange : PartialChange<ThreadStoreUiState> { sealed interface ThreadStorePartialChange : PartialChange<ThreadStoreUiState> {
sealed class Refresh : ThreadStorePartialChange { sealed class Refresh : ThreadStorePartialChange {
override fun reduce(oldState: ThreadStoreUiState): ThreadStoreUiState = when (this) { 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) Start -> oldState.copy(isRefreshing = true)
is Success -> oldState.copy( is Success -> oldState.copy(
isRefreshing = false, isRefreshing = false,
data = data, data = data,
currentPage = 0, currentPage = 0,
hasMore = hasMore hasMore = hasMore,
error = null
) )
} }
@ -171,7 +174,8 @@ data class ThreadStoreUiState(
val isLoadingMore: Boolean = false, val isLoadingMore: Boolean = false,
val hasMore: Boolean = true, val hasMore: Boolean = true,
val currentPage: Int = 1, val currentPage: Int = 1,
val data: List<ThreadStoreBean.ThreadStoreInfo> = emptyList() val data: List<ThreadStoreBean.ThreadStoreInfo> = emptyList(),
val error: ImmutableHolder<Throwable>? = null
) : UiState ) : UiState
sealed interface ThreadStoreUiEvent : UiEvent { sealed interface ThreadStoreUiEvent : UiEvent {