书架性能优化

This commit is contained in:
HapeLee
2026-05-15 03:00:31 +08:00
parent 0c1ad67526
commit 5338313583
6 changed files with 2223 additions and 29 deletions
@@ -69,7 +69,7 @@ val appDb by lazy {
}
@Database(
version = 86,
version = 87,
exportSchema = true,
entities = [Book::class, BookGroup::class, BookSource::class, BookChapter::class,
ReplaceRule::class, SearchBook::class, SearchKeyword::class, Cookie::class,
@@ -122,7 +122,8 @@ val appDb by lazy {
AutoMigration(from = 82, to = 83),
AutoMigration(from = 83, to = 84),
AutoMigration(from = 84, to = 85),
AutoMigration(from = 85, to = 86)
AutoMigration(from = 85, to = 86),
AutoMigration(from = 86, to = 87)
]
)
abstract class AppDatabase : RoomDatabase() {
@@ -33,7 +33,10 @@ import kotlin.math.max
@TypeConverters(Book.Converters::class)
@Entity(
tableName = "books",
indices = [Index(value = ["name", "author"], unique = false)]
indices = [
Index(value = ["name", "author"], unique = false),
Index(value = ["durChapterTime"], unique = false)
]
)
data class Book(
// 详情页Url(本地书源存储完整文件路径)
@@ -262,15 +262,17 @@ fun BookshelfScreen(
)
}
) { paddingValues ->
EmptyMessage(
modifier = Modifier
.fillMaxSize()
.padding(
top = paddingValues.calculateTopPadding(),
bottom = 120.dp
),
messageResId = R.string.bookshelf_empty
)
if (!uiState.isInitialLoading) {
EmptyMessage(
modifier = Modifier
.fillMaxSize()
.padding(
top = paddingValues.calculateTopPadding(),
bottom = 120.dp
),
messageResId = R.string.bookshelf_empty
)
}
}
return
}
@@ -1250,7 +1252,7 @@ fun BookshelfPage(
buttonText = stringResource(R.string.global_search),
onButtonClick = onGlobalSearch
)
} else {
} else if (!uiState.isInitialLoading) {
EmptyMessage(
modifier = Modifier
.fillMaxSize()
@@ -12,6 +12,7 @@ import kotlinx.collections.immutable.persistentSetOf
@Stable
data class BookshelfGroupSelectorState(
val isInitialLoading: Boolean = true,
val groups: ImmutableList<BookGroupUi> = persistentListOf(),
val selectedGroupIndex: Int = 0,
val selectedGroupId: Long = BookGroup.IdAll
@@ -37,6 +38,7 @@ data class BookshelfUiState(
override val searchKey: String = "",
override val isSearch: Boolean = false,
override val isLoading: Boolean = false,
val isInitialLoading: Boolean = true,
val groups: ImmutableList<BookGroupUi> = persistentListOf(),
val allGroups: ImmutableList<BookGroupUi> = persistentListOf(),
val groupPreviews: ImmutableMap<Long, ImmutableList<BookShelfItem>> = persistentMapOf(),
@@ -77,10 +77,13 @@ import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.flow.receiveAsFlow
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.isActive
@@ -117,6 +120,7 @@ class BookshelfViewModel(
private val bookGroupStyleFlow = MutableStateFlow(BookshelfConfig.bookGroupStyle)
private val draggingBooksFlow = MutableStateFlow<List<BookShelfItem>?>(null)
private val pendingSavedBooksFlow = MutableStateFlow<List<BookShelfItem>?>(null)
private val isInitialLoadingFlow = MutableStateFlow(true)
private data class BookshelfSortConfig(
val sort: Int,
@@ -156,6 +160,7 @@ class BookshelfViewModel(
val events = _eventChannel.receiveAsFlow()
val groupsFlow: StateFlow<List<BookGroup>> = bookGroupRepository.flowShow()
.onEach { isInitialLoadingFlow.value = false }
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(5000), emptyList())
val allGroupsFlow: StateFlow<List<BookGroup>> = bookGroupRepository.flowAll()
@@ -363,18 +368,23 @@ class BookshelfViewModel(
)
}
private val groupPreviewsStateFlow = MutableStateFlow(
GroupPreviewState(persistentMapOf(), persistentMapOf(), 0)
)
private val allGroupBooksStateFlow = MutableStateFlow<ImmutableMap<Long, ImmutableList<BookShelfItem>>>(
persistentMapOf()
)
private val dataStateFlow = combine(
combine(
booksFlow,
groupsFlow,
allGroupsFlow,
groupPreviewsFlow,
internalStateFlow
) { books, groups, allGroups, previews, internal ->
BookshelfDataCore(books, groups, allGroups, previews, internal)
},
allGroupBooksImmutableFlow
) { core, allGroupBooks ->
booksFlow,
groupsFlow,
allGroupsFlow,
groupPreviewsStateFlow,
internalStateFlow
) { books, groups, allGroups, previews, internal ->
BookshelfDataCore(books, groups, allGroups, previews, internal)
}.combine(allGroupBooksStateFlow) { core, allGroupBooks ->
BookshelfDataState(
books = core.books,
groups = core.groups.map { it.toBookGroupUi() },
@@ -405,8 +415,9 @@ class BookshelfViewModel(
val uiState: StateFlow<BookshelfUiState> = combine(
dataStateFlow,
interactionStateFlow,
visibleBooksFlow
) { data, interaction, filteredBooks ->
visibleBooksFlow,
isInitialLoadingFlow
) { data, interaction, filteredBooks, isInitialLoading ->
val books = data.books
val groups = data.groups
val allGroups = data.allGroups
@@ -429,6 +440,7 @@ class BookshelfViewModel(
BookshelfUiState(
items = filteredBooks.toImmutableList(),
selectedIds = selectedIds.toImmutableSet(),
isInitialLoading = isInitialLoading,
groups = groups.toImmutableList(),
allGroups = allGroups.toImmutableList(),
groupPreviews = previews.previews,
@@ -485,8 +497,19 @@ class BookshelfViewModel(
}
}
if (BookshelfConfig.autoRefreshBook) {
upAllBookToc()
viewModelScope.launch {
groupPreviewsFlow.collect { groupPreviewsStateFlow.value = it }
}
viewModelScope.launch {
allGroupBooksImmutableFlow.collect { allGroupBooksStateFlow.value = it }
}
viewModelScope.launch {
isInitialLoadingFlow.filter { !it }.collect {
if (BookshelfConfig.autoRefreshBook) {
upAllBookToc()
}
}
}
}