feat: 收藏页面状态
This commit is contained in:
parent
83a855b2d4
commit
e3199c1d8d
|
|
@ -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,
|
||||||
|
|
@ -189,6 +217,7 @@ fun ThreadStorePage(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@OptIn(ExperimentalTextApi::class)
|
@OptIn(ExperimentalTextApi::class)
|
||||||
@Composable
|
@Composable
|
||||||
|
|
|
||||||
|
|
@ -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 {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue