feat: 动态页面状态屏
This commit is contained in:
parent
71a11f3496
commit
a24d22e3f3
|
|
@ -33,6 +33,7 @@ import androidx.compose.material.pullrefresh.pullRefresh
|
||||||
import androidx.compose.material.pullrefresh.rememberPullRefreshState
|
import androidx.compose.material.pullrefresh.rememberPullRefreshState
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.LaunchedEffect
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
|
import androidx.compose.runtime.derivedStateOf
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.runtime.mutableIntStateOf
|
import androidx.compose.runtime.mutableIntStateOf
|
||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableStateOf
|
||||||
|
|
@ -62,11 +63,13 @@ import com.huanchengfly.tieba.post.ui.page.destinations.ThreadPageDestination
|
||||||
import com.huanchengfly.tieba.post.ui.widgets.compose.BlockTip
|
import com.huanchengfly.tieba.post.ui.widgets.compose.BlockTip
|
||||||
import com.huanchengfly.tieba.post.ui.widgets.compose.BlockableContent
|
import com.huanchengfly.tieba.post.ui.widgets.compose.BlockableContent
|
||||||
import com.huanchengfly.tieba.post.ui.widgets.compose.Container
|
import com.huanchengfly.tieba.post.ui.widgets.compose.Container
|
||||||
|
import com.huanchengfly.tieba.post.ui.widgets.compose.ErrorScreen
|
||||||
import com.huanchengfly.tieba.post.ui.widgets.compose.FeedCard
|
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.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.MyLazyColumn
|
import com.huanchengfly.tieba.post.ui.widgets.compose.MyLazyColumn
|
||||||
import com.huanchengfly.tieba.post.ui.widgets.compose.VerticalDivider
|
import com.huanchengfly.tieba.post.ui.widgets.compose.VerticalDivider
|
||||||
|
import com.huanchengfly.tieba.post.ui.widgets.compose.states.StateScreen
|
||||||
import kotlinx.collections.immutable.ImmutableList
|
import kotlinx.collections.immutable.ImmutableList
|
||||||
import kotlinx.collections.immutable.persistentListOf
|
import kotlinx.collections.immutable.persistentListOf
|
||||||
import kotlinx.coroutines.delay
|
import kotlinx.coroutines.delay
|
||||||
|
|
@ -98,6 +101,10 @@ fun PersonalizedPage(
|
||||||
prop1 = PersonalizedUiState::data,
|
prop1 = PersonalizedUiState::data,
|
||||||
initial = persistentListOf()
|
initial = persistentListOf()
|
||||||
)
|
)
|
||||||
|
val error by viewModel.uiState.collectPartialAsState(
|
||||||
|
prop1 = PersonalizedUiState::error,
|
||||||
|
initial = null
|
||||||
|
)
|
||||||
val refreshPosition by viewModel.uiState.collectPartialAsState(
|
val refreshPosition by viewModel.uiState.collectPartialAsState(
|
||||||
prop1 = PersonalizedUiState::refreshPosition,
|
prop1 = PersonalizedUiState::refreshPosition,
|
||||||
initial = 0
|
initial = 0
|
||||||
|
|
@ -112,6 +119,16 @@ fun PersonalizedPage(
|
||||||
)
|
)
|
||||||
val lazyListState = rememberLazyListState()
|
val lazyListState = rememberLazyListState()
|
||||||
viewModel.bindScrollToTopEvent(lazyListState = lazyListState)
|
viewModel.bindScrollToTopEvent(lazyListState = lazyListState)
|
||||||
|
val isEmpty by remember {
|
||||||
|
derivedStateOf {
|
||||||
|
data.isEmpty()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val isError by remember {
|
||||||
|
derivedStateOf {
|
||||||
|
error != null
|
||||||
|
}
|
||||||
|
}
|
||||||
var refreshCount by remember {
|
var refreshCount by remember {
|
||||||
mutableIntStateOf(0)
|
mutableIntStateOf(0)
|
||||||
}
|
}
|
||||||
|
|
@ -147,6 +164,19 @@ fun PersonalizedPage(
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
|
StateScreen(
|
||||||
|
isEmpty = isEmpty,
|
||||||
|
isError = isError,
|
||||||
|
isLoading = isRefreshing,
|
||||||
|
onReload = { viewModel.send(PersonalizedUiIntent.Refresh) },
|
||||||
|
errorScreen = {
|
||||||
|
error?.let {
|
||||||
|
ErrorScreen(
|
||||||
|
error = it.get()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
) {
|
||||||
Box(modifier = Modifier.pullRefresh(pullRefreshState)) {
|
Box(modifier = Modifier.pullRefresh(pullRefreshState)) {
|
||||||
LoadMoreLayout(
|
LoadMoreLayout(
|
||||||
isLoading = isLoadingMore,
|
isLoading = isLoadingMore,
|
||||||
|
|
@ -221,6 +251,7 @@ fun PersonalizedPage(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun BoxScope.RefreshTip(refreshCount: Int) {
|
private fun BoxScope.RefreshTip(refreshCount: Int) {
|
||||||
|
|
|
||||||
|
|
@ -145,7 +145,7 @@ class PersonalizedViewModel @Inject constructor() :
|
||||||
}
|
}
|
||||||
|
|
||||||
sealed interface PersonalizedUiIntent : UiIntent {
|
sealed interface PersonalizedUiIntent : UiIntent {
|
||||||
object Refresh : PersonalizedUiIntent
|
data object Refresh : PersonalizedUiIntent
|
||||||
|
|
||||||
data class LoadMore(val page: Int) : PersonalizedUiIntent
|
data class LoadMore(val page: Int) : PersonalizedUiIntent
|
||||||
|
|
||||||
|
|
@ -282,10 +282,14 @@ sealed interface PersonalizedPartialChange : PartialChange<PersonalizedUiState>
|
||||||
data = (data + oldState.data).toImmutableList(),
|
data = (data + oldState.data).toImmutableList(),
|
||||||
refreshPosition = if (oldState.data.isEmpty()) 0 else data.size
|
refreshPosition = if (oldState.data.isEmpty()) 0 else data.size
|
||||||
)
|
)
|
||||||
is Failure -> oldState.copy(isRefreshing = false)
|
|
||||||
|
is Failure -> oldState.copy(
|
||||||
|
isRefreshing = false,
|
||||||
|
error = error.wrapImmutable()
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
object Start: Refresh()
|
data object Start : Refresh()
|
||||||
|
|
||||||
data class Success(
|
data class Success(
|
||||||
val data: List<ThreadItemData>,
|
val data: List<ThreadItemData>,
|
||||||
|
|
@ -305,10 +309,14 @@ sealed interface PersonalizedPartialChange : PartialChange<PersonalizedUiState>
|
||||||
currentPage = currentPage,
|
currentPage = currentPage,
|
||||||
data = (oldState.data + data).toImmutableList(),
|
data = (oldState.data + data).toImmutableList(),
|
||||||
)
|
)
|
||||||
is Failure -> oldState.copy(isLoadingMore = false)
|
|
||||||
|
is Failure -> oldState.copy(
|
||||||
|
isLoadingMore = false,
|
||||||
|
error = error.wrapImmutable()
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
object Start: LoadMore()
|
data object Start : LoadMore()
|
||||||
|
|
||||||
data class Success(
|
data class Success(
|
||||||
val currentPage: Int,
|
val currentPage: Int,
|
||||||
|
|
@ -325,6 +333,7 @@ sealed interface PersonalizedPartialChange : PartialChange<PersonalizedUiState>
|
||||||
data class PersonalizedUiState(
|
data class PersonalizedUiState(
|
||||||
val isRefreshing: Boolean = true,
|
val isRefreshing: Boolean = true,
|
||||||
val isLoadingMore: Boolean = false,
|
val isLoadingMore: Boolean = false,
|
||||||
|
val error: ImmutableHolder<Throwable>? = null,
|
||||||
val currentPage: Int = 1,
|
val currentPage: Int = 1,
|
||||||
val data: ImmutableList<ThreadItemData> = persistentListOf(),
|
val data: ImmutableList<ThreadItemData> = persistentListOf(),
|
||||||
val hiddenThreadIds: ImmutableList<Long> = persistentListOf(),
|
val hiddenThreadIds: ImmutableList<Long> = persistentListOf(),
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue