Persist book status and add recent catalog section

This commit is contained in:
sergeych committed 2026-05-18 14:40:56 +03:00
1 parent 6422f814d1
commit 44cc0bbaf3
8 files changed
+136 -2

No files matched your search

@@ -131,6 +131,13 @@ actual suspend fun loadLibraryItemsPage(limit: Int, offset: Int): List<LibraryIt
}
}
actual suspend fun loadRecentlyAddedLibraryItems(sinceImportedAt: Long, limit: Int): List<LibraryItem> = withContext(Dispatchers.IO) {
appendLibraryLog("load recently added library items since=$sinceImportedAt limit=$limit")
openLibraryDatabase().useLibrary { db ->
db.files.listRecentlyAddedLibraryFiles(sinceImportedAt, limit).map { it.toLibraryItem() }
}
}
actual suspend fun searchLibraryItems(query: String, limit: Int): List<LibraryItem> = withContext(Dispatchers.IO) {
val prefixes = query.toSearchPrefixes()
if (prefixes.isEmpty()) return@withContext emptyList()
@@ -140,6 +147,8 @@ actual suspend fun searchLibraryItems(query: String, limit: Int): List<LibraryIt
}
}
actual fun currentLibraryTimeMillis(): Long = System.currentTimeMillis()
actual suspend fun loadLibraryItem(fileId: String): LibraryItem? = withContext(Dispatchers.IO) {
openLibraryDatabase().useLibrary { db ->
db.files.getLibraryFile(fileId)?.toLibraryItem()
@@ -96,8 +96,12 @@ expect suspend fun loadLibraryItems(): List<LibraryItem>
expect suspend fun loadLibraryItemsPage(limit: Int, offset: Int): List<LibraryItem>
expect suspend fun loadRecentlyAddedLibraryItems(sinceImportedAt: Long, limit: Int = 50): List<LibraryItem>
expect suspend fun searchLibraryItems(query: String, limit: Int = 100): List<LibraryItem>
expect fun currentLibraryTimeMillis(): Long
expect suspend fun loadLibraryItem(fileId: String): LibraryItem?
expect suspend fun loadLibraryItemCover(fileId: String): LibraryCover?
@@ -86,6 +86,7 @@ internal fun LibraryScreen(
var nextOffset by remember(state.items) { mutableStateOf(state.items.size) }
var loadingPage by remember(state.items) { mutableStateOf(false) }
var endReached by remember(state.items) { mutableStateOf(false) }
var recentlyAddedItems by remember(state.items) { mutableStateOf<List<LibraryItem>>(emptyList()) }
var wasScanning by remember { mutableStateOf(false) }
var settingsMenuOpen by remember { mutableStateOf(false) }
var autoScanDownloads by remember { mutableStateOf(true) }
@@ -94,6 +95,7 @@ internal fun LibraryScreen(
var searchResults by remember { mutableStateOf<List<LibraryItem>>(emptyList()) }
var searching by remember { mutableStateOf(false) }
var readingNowCollapsed by remember { mutableStateOf(false) }
var recentlyAddedCollapsed by remember { mutableStateOf(false) }
var myLibraryCollapsed by remember { mutableStateOf(false) }
var notInterestedCollapsed by remember { mutableStateOf(false) }
val coverCache = remember { mutableStateMapOf<String, LibraryCover?>() }
@@ -133,6 +135,11 @@ internal fun LibraryScreen(
}
}
suspend fun loadRecentlyAdded() {
val since = currentLibraryTimeMillis() - RecentlyAddedWindowMillis
recentlyAddedItems = loadRecentlyAddedLibraryItems(since, RecentlyAddedLimit)
}
fun refresh(nextMessage: String? = message) {
message = nextMessage
scope.launch {
@@ -142,6 +149,7 @@ internal fun LibraryScreen(
searching = false
} else {
loadPage(reset = true)
loadRecentlyAdded()
}
}
}
@@ -162,6 +170,7 @@ internal fun LibraryScreen(
searching = false
} else {
loadPage(reset = true)
loadRecentlyAdded()
}
} else {
message = "Could not update ${item.title}."
@@ -193,7 +202,10 @@ internal fun LibraryScreen(
}
LaunchedEffect(state.scanPath, state.message) {
if (items.isEmpty() && !endReached) loadPage(reset = true)
if (items.isEmpty() && !endReached) {
loadPage(reset = true)
loadRecentlyAdded()
}
}
LaunchedEffect(searchText) {
@@ -242,10 +254,12 @@ internal fun LibraryScreen(
while (true) {
delay(5_000)
loadPage(reset = true)
loadRecentlyAdded()
}
} else if (wasScanning) {
wasScanning = false
loadPage(reset = true)
loadRecentlyAdded()
}
}
@@ -440,7 +454,13 @@ internal fun LibraryScreen(
libraryRows("search", visibleItems)
} else {
val readingNow = visibleItems.filter { it.readingStatus == BookReadingStatus.READING }
val myLibrary = visibleItems.filter { it.readingStatus != BookReadingStatus.READING && it.readingStatus != BookReadingStatus.NOT_INTERESTED }
val recentlyAdded = recentlyAddedItems.filter { it.readingStatus == BookReadingStatus.NEW }
val recentlyAddedIds = recentlyAdded.mapTo(mutableSetOf()) { it.fileId }
val myLibrary = visibleItems.filter {
it.fileId !in recentlyAddedIds &&
it.readingStatus != BookReadingStatus.READING &&
it.readingStatus != BookReadingStatus.NOT_INTERESTED
}
val notInterested = visibleItems.filter { it.readingStatus == BookReadingStatus.NOT_INTERESTED }
librarySection(
@@ -453,6 +473,16 @@ internal fun LibraryScreen(
) {
libraryRows("reading", readingNow)
}
librarySection(
key = "recently-added",
title = "recently added",
itemCount = recentlyAdded.size,
displayCount = null,
collapsed = recentlyAddedCollapsed,
onCollapsedChange = { recentlyAddedCollapsed = it },
) {
libraryRows("recently-added", recentlyAdded)
}
librarySection(
key = "library",
title = "my library",
@@ -858,3 +888,5 @@ private fun LibraryScanProgress.toCatalogScanMessage(): String {
private const val LibraryPageSize: Int = 50
private const val SearchResultLimit: Int = 100
private const val RecentlyAddedLimit: Int = 50
private const val RecentlyAddedWindowMillis: Long = 30L * 60L * 60L * 1000L
@@ -94,6 +94,13 @@ actual suspend fun loadLibraryItemsPage(limit: Int, offset: Int): List<LibraryIt
}
}
actual suspend fun loadRecentlyAddedLibraryItems(sinceImportedAt: Long, limit: Int): List<LibraryItem> = withContext(Dispatchers.IO) {
appendLibraryLog("load recently added library items since=$sinceImportedAt limit=$limit")
openLibraryDatabase().useLibrary { db ->
db.files.listRecentlyAddedLibraryFiles(sinceImportedAt, limit).map { it.toLibraryItem() }
}
}
actual suspend fun searchLibraryItems(query: String, limit: Int): List<LibraryItem> = withContext(Dispatchers.IO) {
val prefixes = query.toSearchPrefixes()
if (prefixes.isEmpty()) return@withContext emptyList()
@@ -103,6 +110,8 @@ actual suspend fun searchLibraryItems(query: String, limit: Int): List<LibraryIt
}
}
actual fun currentLibraryTimeMillis(): Long = System.currentTimeMillis()
actual suspend fun loadLibraryItem(fileId: String): LibraryItem? = withContext(Dispatchers.IO) {
openLibraryDatabase().useLibrary { db ->
db.files.getLibraryFile(fileId)?.toLibraryItem()
@@ -24,8 +24,12 @@ actual suspend fun loadLibraryItems(): List<LibraryItem> = emptyList()
actual suspend fun loadLibraryItemsPage(limit: Int, offset: Int): List<LibraryItem> = emptyList()
actual suspend fun loadRecentlyAddedLibraryItems(sinceImportedAt: Long, limit: Int): List<LibraryItem> = emptyList()
actual suspend fun searchLibraryItems(query: String, limit: Int): List<LibraryItem> = emptyList()
actual fun currentLibraryTimeMillis(): Long = 0L
actual suspend fun loadLibraryItem(fileId: String): LibraryItem? = null
actual suspend fun loadLibraryItemCover(fileId: String): LibraryCover? = null