Add library categories and favorites
This commit is contained in:
1 parent
d749352333
commit
02bde7e644
9 files changed
+263
-21
No files matched your search
@@ -337,6 +337,12 @@ actual suspend fun markLibraryReadingStatus(fileId: String, status: BookReadingS
|
||||
}
|
||||
}
|
||||
|
||||
actual suspend fun markLibraryFavorite(fileId: String, favorite: Boolean): Boolean = withContext(Dispatchers.IO) {
|
||||
openLibraryDatabase().useLibrary { db ->
|
||||
db.files.updateFavorite(fileId, favorite)
|
||||
}
|
||||
}
|
||||
|
||||
actual suspend fun shareLibraryBookFile(fileId: String): Boolean = withContext(Dispatchers.IO) {
|
||||
runCatching {
|
||||
val shareFile = openLibraryDatabase().useLibrary { db ->
|
||||
@@ -698,6 +704,7 @@ private fun LibraryFileRecord.toLibraryItem(): LibraryItem =
|
||||
storageUri = storageUri,
|
||||
lastSeenAt = lastSeenAt,
|
||||
readingStatus = readingStatus,
|
||||
favorite = favorite,
|
||||
lastReadAt = lastReadAt,
|
||||
importedAt = importedAt,
|
||||
)
|
||||
|
||||
@@ -16,6 +16,7 @@ data class LibraryItem(
|
||||
val storageUri: String?,
|
||||
val lastSeenAt: Long?,
|
||||
val readingStatus: BookReadingStatus = BookReadingStatus.NEW,
|
||||
val favorite: Boolean = false,
|
||||
val lastReadAt: Long? = null,
|
||||
val importedAt: Long? = null,
|
||||
val coverImage: ByteArray? = null,
|
||||
@@ -124,6 +125,8 @@ expect suspend fun clearLibraryReadingPosition(fileId: String)
|
||||
|
||||
expect suspend fun markLibraryReadingStatus(fileId: String, status: BookReadingStatus): Boolean
|
||||
|
||||
expect suspend fun markLibraryFavorite(fileId: String, favorite: Boolean): Boolean
|
||||
|
||||
expect suspend fun shareLibraryBookFile(fileId: String): Boolean
|
||||
|
||||
expect suspend fun viewLibraryBookFile(fileId: String): Boolean
|
||||
|
||||
@@ -25,6 +25,7 @@ import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.automirrored.filled.KeyboardArrowRight
|
||||
import androidx.compose.material.icons.filled.Add
|
||||
import androidx.compose.material.icons.filled.Close
|
||||
import androidx.compose.material.icons.filled.Favorite
|
||||
import androidx.compose.material.icons.filled.KeyboardArrowDown
|
||||
import androidx.compose.material.icons.filled.MoreVert
|
||||
import androidx.compose.material.icons.filled.Search
|
||||
@@ -53,6 +54,7 @@ import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.SolidColor
|
||||
import androidx.compose.ui.input.key.Key
|
||||
import androidx.compose.ui.input.key.KeyEventType
|
||||
@@ -60,6 +62,7 @@ import androidx.compose.ui.input.key.key
|
||||
import androidx.compose.ui.input.key.onPreviewKeyEvent
|
||||
import androidx.compose.ui.input.key.type
|
||||
import androidx.compose.ui.layout.ContentScale
|
||||
import androidx.compose.ui.platform.LocalDensity
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
@@ -97,10 +100,14 @@ internal fun LibraryScreen(
|
||||
var settingsMenuOpen by remember { mutableStateOf(false) }
|
||||
var autoScanDownloads by remember { mutableStateOf(true) }
|
||||
var autoScanSettingLoaded by remember { mutableStateOf(false) }
|
||||
var backgroundDownloadsRescanStarted by remember { mutableStateOf(false) }
|
||||
var searchText by remember { mutableStateOf("") }
|
||||
var searchResults by remember { mutableStateOf<List<LibraryItem>>(emptyList()) }
|
||||
var searching by remember { mutableStateOf(false) }
|
||||
var readingNowCollapsed by remember { mutableStateOf(false) }
|
||||
var favoritesCollapsed by remember { mutableStateOf(false) }
|
||||
var toReadCollapsed by remember { mutableStateOf(false) }
|
||||
var readCollapsed by remember { mutableStateOf(false) }
|
||||
var recentlyAddedCollapsed by remember { mutableStateOf(false) }
|
||||
var myLibraryCollapsed by remember { mutableStateOf(false) }
|
||||
var notInterestedCollapsed by remember { mutableStateOf(false) }
|
||||
@@ -171,6 +178,31 @@ internal fun LibraryScreen(
|
||||
val updatedItem = loadLibraryItem(item.fileId) ?: item.copy(readingStatus = status)
|
||||
items = items.replaceLibraryItem(updatedItem)
|
||||
searchResults = searchResults.replaceLibraryItem(updatedItem)
|
||||
recentlyAddedItems = recentlyAddedItems.replaceLibraryItem(updatedItem)
|
||||
message = successMessage
|
||||
if (searchActive) {
|
||||
searching = true
|
||||
searchResults = searchLibraryItems(searchText, SearchResultLimit)
|
||||
searching = false
|
||||
} else {
|
||||
loadPage(reset = true)
|
||||
loadRecentlyAdded()
|
||||
}
|
||||
} else {
|
||||
message = "Could not update ${item.title}."
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun applyFavorite(
|
||||
item: LibraryItem,
|
||||
favorite: Boolean,
|
||||
successMessage: String,
|
||||
) {
|
||||
if (markLibraryFavorite(item.fileId, favorite)) {
|
||||
val updatedItem = loadLibraryItem(item.fileId) ?: item.copy(favorite = favorite)
|
||||
items = items.replaceLibraryItem(updatedItem)
|
||||
searchResults = searchResults.replaceLibraryItem(updatedItem)
|
||||
recentlyAddedItems = recentlyAddedItems.replaceLibraryItem(updatedItem)
|
||||
message = successMessage
|
||||
if (searchActive) {
|
||||
searching = true
|
||||
@@ -246,10 +278,18 @@ internal fun LibraryScreen(
|
||||
autoScanSettingLoaded = true
|
||||
}
|
||||
|
||||
LaunchedEffect(autoScanSettingLoaded, autoScanDownloads) {
|
||||
if (!autoScanSettingLoaded || !autoScanDownloads || activeScan != null) return@LaunchedEffect
|
||||
LaunchedEffect(autoScanSettingLoaded, autoScanDownloads, activeScan == null) {
|
||||
if (
|
||||
!autoScanSettingLoaded ||
|
||||
!autoScanDownloads ||
|
||||
backgroundDownloadsRescanStarted ||
|
||||
activeScan != null
|
||||
) {
|
||||
return@LaunchedEffect
|
||||
}
|
||||
if (loadDownloadsWasScanned()) {
|
||||
downloadsScanPath()?.let { path ->
|
||||
backgroundDownloadsRescanStarted = true
|
||||
message = "Scanning Downloads..."
|
||||
onStartScan(path)
|
||||
}
|
||||
@@ -260,7 +300,7 @@ internal fun LibraryScreen(
|
||||
if (activeScan != null) {
|
||||
wasScanning = true
|
||||
while (true) {
|
||||
delay(5_000)
|
||||
delay(2_000)
|
||||
loadPage(reset = true)
|
||||
loadRecentlyAdded()
|
||||
}
|
||||
@@ -364,7 +404,9 @@ internal fun LibraryScreen(
|
||||
readerLibraryItems = readerLibraryItems.replaceLibraryItem(updatedItem)
|
||||
coverCache[updatedItem.fileId] = loadLibraryItemCover(updatedItem.fileId)
|
||||
}
|
||||
if (markLibraryReadingStatus(item.fileId, BookReadingStatus.READING)) {
|
||||
if (item.readingStatus == BookReadingStatus.NEW &&
|
||||
markLibraryReadingStatus(item.fileId, BookReadingStatus.READING)
|
||||
) {
|
||||
val readingItem = loadLibraryItem(item.fileId)
|
||||
?: item.copy(readingStatus = BookReadingStatus.READING)
|
||||
items = items.replaceLibraryItem(readingItem)
|
||||
@@ -418,6 +460,16 @@ internal fun LibraryScreen(
|
||||
}
|
||||
}
|
||||
},
|
||||
onMarkToRead = {
|
||||
scope.launch {
|
||||
busy = true
|
||||
try {
|
||||
applyReadingStatus(item, BookReadingStatus.TO_READ, "Marked ${item.title} to read.")
|
||||
} finally {
|
||||
busy = false
|
||||
}
|
||||
}
|
||||
},
|
||||
onNotInterested = {
|
||||
scope.launch {
|
||||
busy = true
|
||||
@@ -428,6 +480,17 @@ internal fun LibraryScreen(
|
||||
}
|
||||
}
|
||||
},
|
||||
onFavoriteChange = { favorite ->
|
||||
scope.launch {
|
||||
busy = true
|
||||
try {
|
||||
val label = if (favorite) "Added ${item.title} to favorites." else "Removed ${item.title} from favorites."
|
||||
applyFavorite(item, favorite, label)
|
||||
} finally {
|
||||
busy = false
|
||||
}
|
||||
}
|
||||
},
|
||||
onDelete = {
|
||||
val previousItems = items
|
||||
val previousSearchResults = searchResults
|
||||
@@ -473,6 +536,9 @@ internal fun LibraryScreen(
|
||||
libraryRows("search", visibleItems)
|
||||
} else {
|
||||
val readingNow = visibleItems.filter { it.readingStatus == BookReadingStatus.READING }
|
||||
val favorites = visibleItems.filter { it.favorite }
|
||||
val toRead = visibleItems.filter { it.readingStatus == BookReadingStatus.TO_READ }
|
||||
val read = visibleItems.filter { it.readingStatus == BookReadingStatus.READ }
|
||||
val recentlyAdded = recentlyAddedItems.filter {
|
||||
it.fileId !in hiddenFileIds && it.readingStatus == BookReadingStatus.NEW
|
||||
}
|
||||
@@ -480,6 +546,8 @@ internal fun LibraryScreen(
|
||||
val myLibrary = visibleItems.filter {
|
||||
it.fileId !in recentlyAddedIds &&
|
||||
it.readingStatus != BookReadingStatus.READING &&
|
||||
it.readingStatus != BookReadingStatus.TO_READ &&
|
||||
it.readingStatus != BookReadingStatus.READ &&
|
||||
it.readingStatus != BookReadingStatus.NOT_INTERESTED
|
||||
}
|
||||
val notInterested = visibleItems.filter { it.readingStatus == BookReadingStatus.NOT_INTERESTED }
|
||||
@@ -494,6 +562,26 @@ internal fun LibraryScreen(
|
||||
) {
|
||||
libraryRows("reading", readingNow)
|
||||
}
|
||||
librarySection(
|
||||
key = "favorites",
|
||||
title = "favorites",
|
||||
itemCount = favorites.size,
|
||||
displayCount = favorites.size.takeIf { endReached },
|
||||
collapsed = favoritesCollapsed,
|
||||
onCollapsedChange = { favoritesCollapsed = it },
|
||||
) {
|
||||
libraryRows("favorites", favorites)
|
||||
}
|
||||
librarySection(
|
||||
key = "to-read",
|
||||
title = "to read",
|
||||
itemCount = toRead.size,
|
||||
displayCount = toRead.size.takeIf { endReached },
|
||||
collapsed = toReadCollapsed,
|
||||
onCollapsedChange = { toReadCollapsed = it },
|
||||
) {
|
||||
libraryRows("to-read", toRead)
|
||||
}
|
||||
librarySection(
|
||||
key = "recently-added",
|
||||
title = "recently added",
|
||||
@@ -514,6 +602,16 @@ internal fun LibraryScreen(
|
||||
) {
|
||||
libraryRows("library", myLibrary)
|
||||
}
|
||||
librarySection(
|
||||
key = "read",
|
||||
title = "read",
|
||||
itemCount = read.size,
|
||||
displayCount = read.size.takeIf { endReached },
|
||||
collapsed = readCollapsed,
|
||||
onCollapsedChange = { readCollapsed = it },
|
||||
) {
|
||||
libraryRows("read", read)
|
||||
}
|
||||
librarySection(
|
||||
key = "not-interested",
|
||||
title = "not interested",
|
||||
@@ -723,6 +821,8 @@ private fun LibraryRow(
|
||||
actions: LibraryItemActions,
|
||||
) {
|
||||
var menuOpen by remember { mutableStateOf(false) }
|
||||
val titleStyle = MaterialTheme.typography.titleMedium
|
||||
val favoriteIconSize = with(LocalDensity.current) { titleStyle.lineHeight.toDp() - 2.dp }
|
||||
|
||||
Card(shape = RoundedCornerShape(6.dp), colors = quietCardColors(), modifier = Modifier.fillMaxWidth()) {
|
||||
Row(
|
||||
@@ -735,13 +835,27 @@ private fun LibraryRow(
|
||||
) {
|
||||
LibraryCover(item, coverCache, modifier = Modifier.width(46.dp).aspectRatio(0.68f))
|
||||
Column(modifier = Modifier.weight(1f), verticalArrangement = Arrangement.spacedBy(2.dp)) {
|
||||
Text(
|
||||
item.title,
|
||||
style = MaterialTheme.typography.titleMedium,
|
||||
fontWeight = FontWeight.SemiBold,
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
)
|
||||
Row(
|
||||
horizontalArrangement = Arrangement.spacedBy(4.dp),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
Text(
|
||||
item.title,
|
||||
style = titleStyle,
|
||||
fontWeight = FontWeight.SemiBold,
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
modifier = Modifier.weight(1f, fill = false),
|
||||
)
|
||||
if (item.favorite) {
|
||||
Icon(
|
||||
Icons.Filled.Favorite,
|
||||
contentDescription = "Favorite",
|
||||
tint = Color(0xFFD32F2F),
|
||||
modifier = Modifier.size(favoriteIconSize),
|
||||
)
|
||||
}
|
||||
}
|
||||
Text(
|
||||
item.authors.joinToString().ifBlank { "Unknown author" },
|
||||
style = MaterialTheme.typography.bodyMedium,
|
||||
@@ -787,15 +901,31 @@ private fun LibraryRow(
|
||||
},
|
||||
)
|
||||
}
|
||||
if (item.readingStatus != BookReadingStatus.TO_READ) {
|
||||
DropdownMenuItem(
|
||||
text = { Text("Mark to read") },
|
||||
onClick = {
|
||||
menuOpen = false
|
||||
actions.onMarkToRead()
|
||||
},
|
||||
)
|
||||
}
|
||||
if (item.readingStatus != BookReadingStatus.NEW) {
|
||||
DropdownMenuItem(
|
||||
text = { Text("Remove marks") },
|
||||
text = { Text(if (item.readingStatus == BookReadingStatus.TO_READ) "Remove to read" else "Remove marks") },
|
||||
onClick = {
|
||||
menuOpen = false
|
||||
actions.onRemoveMarks()
|
||||
},
|
||||
)
|
||||
}
|
||||
DropdownMenuItem(
|
||||
text = { Text(if (item.favorite) "Remove favorite" else "Add favorite") },
|
||||
onClick = {
|
||||
menuOpen = false
|
||||
actions.onFavoriteChange(!item.favorite)
|
||||
},
|
||||
)
|
||||
DropdownMenuItem(
|
||||
text = { Text("Not interested") },
|
||||
onClick = {
|
||||
@@ -822,7 +952,9 @@ private data class LibraryItemActions(
|
||||
val onMarkAsRead: () -> Unit,
|
||||
val onMarkAsUnread: () -> Unit,
|
||||
val onRemoveMarks: () -> Unit,
|
||||
val onMarkToRead: () -> Unit,
|
||||
val onNotInterested: () -> Unit,
|
||||
val onFavoriteChange: (Boolean) -> Unit,
|
||||
val onDelete: () -> Unit,
|
||||
)
|
||||
|
||||
@@ -866,6 +998,7 @@ private fun LibraryCover(
|
||||
|
||||
private fun LibraryItem.libraryMetadataLine(): String =
|
||||
listOfNotNull(
|
||||
"Favorite".takeIf { favorite },
|
||||
readingStatus.displayLabel,
|
||||
lastReadAt?.formatLastRead(),
|
||||
date?.yearOrRaw(),
|
||||
@@ -877,6 +1010,7 @@ private fun LibraryItem.libraryMetadataLine(): String =
|
||||
private val BookReadingStatus.displayLabel: String
|
||||
get() = when (this) {
|
||||
BookReadingStatus.NEW -> "New"
|
||||
BookReadingStatus.TO_READ -> "To read"
|
||||
BookReadingStatus.READING -> "Reading"
|
||||
BookReadingStatus.READ -> "Read"
|
||||
BookReadingStatus.NOT_INTERESTED -> "Not interested"
|
||||
|
||||
@@ -81,6 +81,7 @@ internal fun BookView(
|
||||
val snackbarHostState = remember { SnackbarHostState() }
|
||||
var restored by remember(fileId) { mutableStateOf(false) }
|
||||
var markedRead by remember(fileId) { mutableStateOf(false) }
|
||||
var libraryItem by remember(fileId) { mutableStateOf<LibraryItem?>(null) }
|
||||
var readAloudPanelVisible by remember(fileId) { mutableStateOf(false) }
|
||||
var readAloudSettingsVisible by remember(fileId) { mutableStateOf(false) }
|
||||
val readAloudState by ReadAloudPlatform.state.collectAsState()
|
||||
@@ -102,6 +103,7 @@ internal fun BookView(
|
||||
fun setReadingStatus(status: BookReadingStatus, successMessage: String) {
|
||||
scope.launch {
|
||||
if (markLibraryReadingStatus(fileId, status)) {
|
||||
libraryItem = loadLibraryItem(fileId) ?: libraryItem?.copy(readingStatus = status)
|
||||
if (status == BookReadingStatus.READ) markedRead = true
|
||||
if (status == BookReadingStatus.NEW) markedRead = false
|
||||
showMessage(successMessage)
|
||||
@@ -112,7 +114,12 @@ internal fun BookView(
|
||||
}
|
||||
|
||||
LaunchedEffect(fileId) {
|
||||
markLibraryReadingStatus(fileId, BookReadingStatus.READING)
|
||||
val item = loadLibraryItem(fileId)
|
||||
libraryItem = item
|
||||
markedRead = item?.readingStatus == BookReadingStatus.READ
|
||||
if (item?.readingStatus == BookReadingStatus.NEW && markLibraryReadingStatus(fileId, BookReadingStatus.READING)) {
|
||||
libraryItem = loadLibraryItem(fileId) ?: item.copy(readingStatus = BookReadingStatus.READING)
|
||||
}
|
||||
}
|
||||
|
||||
DisposableEffect(fileId) {
|
||||
@@ -144,10 +151,12 @@ internal fun BookView(
|
||||
val lastVisible = layoutInfo.visibleItemsInfo.lastOrNull()?.index ?: -1
|
||||
layoutInfo.totalItemsCount > 0 && lastVisible >= layoutInfo.totalItemsCount - 1
|
||||
}
|
||||
.filter { restored && it && !markedRead }
|
||||
.filter { restored && it && !markedRead && libraryItem?.readingStatus != BookReadingStatus.TO_READ }
|
||||
.collect {
|
||||
markedRead = true
|
||||
markLibraryReadingStatus(fileId, BookReadingStatus.READ)
|
||||
if (markLibraryReadingStatus(fileId, BookReadingStatus.READ)) {
|
||||
libraryItem = loadLibraryItem(fileId) ?: libraryItem?.copy(readingStatus = BookReadingStatus.READ)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -179,12 +188,27 @@ internal fun BookView(
|
||||
onMarkAsRead = {
|
||||
setReadingStatus(BookReadingStatus.READ, "Marked as read.")
|
||||
},
|
||||
onMarkToRead = {
|
||||
setReadingStatus(BookReadingStatus.TO_READ, "Marked to read.")
|
||||
},
|
||||
onNotInterested = {
|
||||
setReadingStatus(BookReadingStatus.NOT_INTERESTED, "Marked as not interested.")
|
||||
},
|
||||
onClearMarks = {
|
||||
setReadingStatus(BookReadingStatus.NEW, "Cleared marks.")
|
||||
},
|
||||
readingStatus = libraryItem?.readingStatus,
|
||||
favorite = libraryItem?.favorite == true,
|
||||
onFavoriteChange = { favorite ->
|
||||
scope.launch {
|
||||
if (markLibraryFavorite(fileId, favorite)) {
|
||||
libraryItem = loadLibraryItem(fileId) ?: libraryItem?.copy(favorite = favorite)
|
||||
showMessage(if (favorite) "Added to favorites." else "Removed from favorites.")
|
||||
} else {
|
||||
showMessage("Could not update book.")
|
||||
}
|
||||
}
|
||||
},
|
||||
showShareAction = showShareAction,
|
||||
onShare = {
|
||||
scope.launch {
|
||||
@@ -290,8 +314,12 @@ private fun CompactReaderTopBar(
|
||||
onThemeToggle: () -> Unit,
|
||||
onBookInfo: () -> Unit,
|
||||
onMarkAsRead: () -> Unit,
|
||||
onMarkToRead: () -> Unit,
|
||||
onNotInterested: () -> Unit,
|
||||
onClearMarks: () -> Unit,
|
||||
readingStatus: BookReadingStatus?,
|
||||
favorite: Boolean,
|
||||
onFavoriteChange: (Boolean) -> Unit,
|
||||
showShareAction: Boolean,
|
||||
onShare: () -> Unit,
|
||||
showViewFileAction: Boolean,
|
||||
@@ -345,6 +373,23 @@ private fun CompactReaderTopBar(
|
||||
onMarkAsRead()
|
||||
},
|
||||
)
|
||||
if (readingStatus == BookReadingStatus.TO_READ) {
|
||||
DropdownMenuItem(
|
||||
text = { Text("Remove to read") },
|
||||
onClick = {
|
||||
menuOpen = false
|
||||
onClearMarks()
|
||||
},
|
||||
)
|
||||
} else {
|
||||
DropdownMenuItem(
|
||||
text = { Text("Mark to read") },
|
||||
onClick = {
|
||||
menuOpen = false
|
||||
onMarkToRead()
|
||||
},
|
||||
)
|
||||
}
|
||||
DropdownMenuItem(
|
||||
text = { Text("Not interested") },
|
||||
onClick = {
|
||||
@@ -359,6 +404,13 @@ private fun CompactReaderTopBar(
|
||||
onClearMarks()
|
||||
},
|
||||
)
|
||||
DropdownMenuItem(
|
||||
text = { Text(if (favorite) "Remove favorite" else "Add favorite") },
|
||||
onClick = {
|
||||
menuOpen = false
|
||||
onFavoriteChange(!favorite)
|
||||
},
|
||||
)
|
||||
if (showShareAction || showViewFileAction) {
|
||||
HorizontalDivider()
|
||||
}
|
||||
|
||||
@@ -285,6 +285,12 @@ actual suspend fun markLibraryReadingStatus(fileId: String, status: BookReadingS
|
||||
}
|
||||
}
|
||||
|
||||
actual suspend fun markLibraryFavorite(fileId: String, favorite: Boolean): Boolean = withContext(Dispatchers.IO) {
|
||||
openLibraryDatabase().useLibrary { db ->
|
||||
db.files.updateFavorite(fileId, favorite)
|
||||
}
|
||||
}
|
||||
|
||||
actual suspend fun shareLibraryBookFile(fileId: String): Boolean = false
|
||||
|
||||
actual suspend fun viewLibraryBookFile(fileId: String): Boolean = withContext(Dispatchers.IO) {
|
||||
@@ -495,6 +501,7 @@ private fun LibraryFileRecord.toLibraryItem(): LibraryItem =
|
||||
storageUri = storageUri,
|
||||
lastSeenAt = lastSeenAt,
|
||||
readingStatus = readingStatus,
|
||||
favorite = favorite,
|
||||
lastReadAt = lastReadAt,
|
||||
importedAt = importedAt,
|
||||
)
|
||||
|
||||
@@ -57,6 +57,8 @@ actual suspend fun clearLibraryReadingPosition(fileId: String) = Unit
|
||||
|
||||
actual suspend fun markLibraryReadingStatus(fileId: String, status: BookReadingStatus): Boolean = false
|
||||
|
||||
actual suspend fun markLibraryFavorite(fileId: String, favorite: Boolean): Boolean = false
|
||||
|
||||
actual suspend fun shareLibraryBookFile(fileId: String): Boolean = false
|
||||
|
||||
actual suspend fun viewLibraryBookFile(fileId: String): Boolean = false
|
||||
|
||||
Reference in new issue
Block a user