feat: 保留ExpandedSourceSheet的浏览进度

合并 PR #1279 by woruteyqi
This commit is contained in:
aoi
2026-06-02 18:32:04 +08:00
committed by GitHub
parent aa9e5a4458
commit 5da2e85395
3 changed files with 69 additions and 22 deletions
@@ -51,6 +51,9 @@ data class SearchUiState(
val expandedSourceEnd: Boolean = false, val expandedSourceEnd: Boolean = false,
val expandedSourceError: String? = null, val expandedSourceError: String? = null,
val expandedSourcePage: Int = 1, val expandedSourcePage: Int = 1,
val showExpandedSource: Boolean = false,
val expandedSourceSavedScrollIndex: Int = 0,
val expandedSourceSavedScrollOffset: Int = 0,
) )
data class SearchEmptyScopeAction( data class SearchEmptyScopeAction(
@@ -90,6 +93,7 @@ sealed interface SearchIntent {
data object DismissEmptyScopeAction : SearchIntent data object DismissEmptyScopeAction : SearchIntent
data object OpenSourceManage : SearchIntent data object OpenSourceManage : SearchIntent
data class SaveScrollState(val index: Int, val offset: Int) : SearchIntent data class SaveScrollState(val index: Int, val offset: Int) : SearchIntent
data class SaveExpandedSourceScrollState(val index: Int, val offset: Int) : SearchIntent
} }
sealed interface SearchEffect { sealed interface SearchEffect {
@@ -698,14 +698,19 @@ fun SearchScreen(
) )
ExpandedSourceSheet( ExpandedSourceSheet(
show = state.expandedSourceUrl != null, show = state.showExpandedSource,
sourceName = state.expandedSourceName ?: "", sourceName = state.expandedSourceName ?: "",
books = state.expandedSourceBooks, books = state.expandedSourceBooks,
isLoading = state.expandedSourceLoading, isLoading = state.expandedSourceLoading,
isEnd = state.expandedSourceEnd, isEnd = state.expandedSourceEnd,
errorMsg = state.expandedSourceError, errorMsg = state.expandedSourceError,
savedScrollIndex = state.expandedSourceSavedScrollIndex,
savedScrollOffset = state.expandedSourceSavedScrollOffset,
onDismiss = { viewModel.onIntent(SearchIntent.DismissExpandedSource) }, onDismiss = { viewModel.onIntent(SearchIntent.DismissExpandedSource) },
onLoadMore = { viewModel.onIntent(SearchIntent.LoadMoreExpandedSource) }, onLoadMore = { viewModel.onIntent(SearchIntent.LoadMoreExpandedSource) },
onSaveScrollState = { index, offset ->
viewModel.onIntent(SearchIntent.SaveExpandedSourceScrollState(index, offset))
},
onBookClick = { book, coverKey -> onBookClick = { book, coverKey ->
viewModel.onIntent(SearchIntent.OpenExpandedSourceBook(book, coverKey)) viewModel.onIntent(SearchIntent.OpenExpandedSourceBook(book, coverKey))
}, },
@@ -888,8 +893,11 @@ private fun ExpandedSourceSheet(
isLoading: Boolean, isLoading: Boolean,
isEnd: Boolean, isEnd: Boolean,
errorMsg: String?, errorMsg: String?,
savedScrollIndex: Int,
savedScrollOffset: Int,
onDismiss: () -> Unit, onDismiss: () -> Unit,
onLoadMore: () -> Unit, onLoadMore: () -> Unit,
onSaveScrollState: (Int, Int) -> Unit,
onBookClick: (SearchBook, String?) -> Unit, onBookClick: (SearchBook, String?) -> Unit,
onBookLongClick: ((SearchBook, String?) -> Unit)? = null, onBookLongClick: ((SearchBook, String?) -> Unit)? = null,
) { ) {
@@ -900,7 +908,7 @@ private fun ExpandedSourceSheet(
) { ) {
val listState = rememberLazyListState() val listState = rememberLazyListState()
val showLoadMoreFooter = isLoading || errorMsg != null || isEnd val showLoadMoreFooter = isLoading || errorMsg != null || isEnd
val currentOnSaveScrollState by rememberUpdatedState(onSaveScrollState)
val shouldLoadMore by remember { val shouldLoadMore by remember {
derivedStateOf { derivedStateOf {
val total = listState.layoutInfo.totalItemsCount val total = listState.layoutInfo.totalItemsCount
@@ -915,6 +923,23 @@ private fun ExpandedSourceSheet(
} }
} }
LaunchedEffect(savedScrollIndex, savedScrollOffset) {
if (savedScrollIndex > 0 || savedScrollOffset > 0) {
listState.scrollToItem(savedScrollIndex, savedScrollOffset)
onSaveScrollState(0, 0)
}
}
DisposableEffect(listState) {
onDispose {
val first = listState.firstVisibleItemIndex
val offset = listState.firstVisibleItemScrollOffset
if (first > 0 || offset > 0) {
currentOnSaveScrollState(first, offset)
}
}
}
LazyColumn( LazyColumn(
state = listState, state = listState,
modifier = Modifier.fillMaxSize(), modifier = Modifier.fillMaxSize(),
@@ -225,6 +225,11 @@ class SearchViewModel(
SearchIntent.OpenSourceManage -> emitEffect(SearchEffect.OpenSourceManage) SearchIntent.OpenSourceManage -> emitEffect(SearchEffect.OpenSourceManage)
is SearchIntent.ExpandSource -> { is SearchIntent.ExpandSource -> {
val state = _uiState.value
if (state.expandedSourceUrl == intent.sourceUrl) {
_uiState.update { it.copy(showExpandedSource = true) }
return
}
_uiState.update { _uiState.update {
it.copy( it.copy(
expandedSourceUrl = intent.sourceUrl, expandedSourceUrl = intent.sourceUrl,
@@ -234,6 +239,9 @@ class SearchViewModel(
expandedSourceEnd = false, expandedSourceEnd = false,
expandedSourceError = null, expandedSourceError = null,
expandedSourcePage = 1, expandedSourcePage = 1,
showExpandedSource = true,
expandedSourceSavedScrollIndex = 0,
expandedSourceSavedScrollOffset = 0,
) )
} }
loadExpandedSourcePage(intent.sourceUrl, page = 1) loadExpandedSourcePage(intent.sourceUrl, page = 1)
@@ -241,15 +249,7 @@ class SearchViewModel(
SearchIntent.DismissExpandedSource -> { SearchIntent.DismissExpandedSource -> {
_uiState.update { _uiState.update {
it.copy( it.copy(showExpandedSource = false)
expandedSourceUrl = null,
expandedSourceName = null,
expandedSourceBooks = persistentListOf(),
expandedSourceLoading = false,
expandedSourceEnd = false,
expandedSourceError = null,
expandedSourcePage = 1,
)
} }
} }
@@ -267,17 +267,6 @@ class SearchViewModel(
} }
is SearchIntent.OpenExpandedSourceBook -> { is SearchIntent.OpenExpandedSourceBook -> {
_uiState.update {
it.copy(
expandedSourceUrl = null,
expandedSourceName = null,
expandedSourceBooks = persistentListOf(),
expandedSourceLoading = false,
expandedSourceEnd = false,
expandedSourceError = null,
expandedSourcePage = 1,
)
}
emitEffect( emitEffect(
SearchEffect.OpenBookInfo( SearchEffect.OpenBookInfo(
name = intent.book.name, name = intent.book.name,
@@ -298,6 +287,15 @@ class SearchViewModel(
) )
} }
} }
is SearchIntent.SaveExpandedSourceScrollState -> {
_uiState.update {
it.copy(
expandedSourceSavedScrollIndex = intent.index,
expandedSourceSavedScrollOffset = intent.offset,
)
}
}
} }
} }
@@ -426,6 +424,16 @@ class SearchViewModel(
processedSources = 0, processedSources = 0,
totalSources = 0, totalSources = 0,
emptyScopeAction = null, emptyScopeAction = null,
expandedSourceUrl = null,
expandedSourceName = null,
expandedSourceBooks = persistentListOf(),
expandedSourceLoading = false,
expandedSourceEnd = false,
expandedSourceError = null,
expandedSourcePage = 1,
showExpandedSource = false,
expandedSourceSavedScrollIndex = 0,
expandedSourceSavedScrollOffset = 0,
) )
} }
@@ -550,6 +558,16 @@ class SearchViewModel(
hasMore = true, hasMore = true,
showSuggestions = true, showSuggestions = true,
emptyScopeAction = null, emptyScopeAction = null,
expandedSourceUrl = null,
expandedSourceName = null,
expandedSourceBooks = persistentListOf(),
expandedSourceLoading = false,
expandedSourceEnd = false,
expandedSourceError = null,
expandedSourcePage = 1,
showExpandedSource = false,
expandedSourceSavedScrollIndex = 0,
expandedSourceSavedScrollOffset = 0,
) )
} }
} }