fix: 优化书籍详情内存占用
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
package io.legado.app.ui.book.info
|
||||
|
||||
import android.net.Uri
|
||||
import androidx.compose.runtime.Stable
|
||||
import io.legado.app.data.entities.Book
|
||||
import io.legado.app.data.entities.BookChapter
|
||||
import io.legado.app.data.entities.BookSource
|
||||
@@ -13,8 +14,8 @@ import kotlinx.collections.immutable.persistentListOf
|
||||
const val READER_RESULT_DELETED = 100
|
||||
|
||||
data class BookInfoUiState(
|
||||
val book: Book? = null,
|
||||
val chapterList: List<BookChapter> = emptyList(),
|
||||
val book: BookInfoBookUi? = null,
|
||||
val hasChapters: Boolean = false,
|
||||
val webFiles: List<BookInfoWebFile> = emptyList(),
|
||||
val kindLabels: List<String> = emptyList(),
|
||||
val groupNames: String? = null,
|
||||
@@ -22,7 +23,7 @@ data class BookInfoUiState(
|
||||
val readRecordTotalTime: Long = 0L,
|
||||
val readRecordTimelineDays: List<ReadRecordTimelineDay> = emptyList(),
|
||||
val inBookshelf: Boolean = false,
|
||||
val bookSource: BookSource? = null,
|
||||
val bookSource: BookInfoSourceUi? = null,
|
||||
val relatedBooks: ImmutableList<RelatedBooksUi> = persistentListOf(),
|
||||
val isTocLoading: Boolean = true,
|
||||
val isBusy: Boolean = false,
|
||||
@@ -33,11 +34,39 @@ data class BookInfoUiState(
|
||||
val dialog: BookInfoDialog? = null,
|
||||
)
|
||||
|
||||
@Stable
|
||||
data class BookInfoBookUi(
|
||||
val bookUrl: String,
|
||||
val name: String,
|
||||
val author: String,
|
||||
val realAuthor: String,
|
||||
val origin: String,
|
||||
val originName: String,
|
||||
val coverPath: String?,
|
||||
val group: Long,
|
||||
val isLocal: Boolean,
|
||||
val type: Int,
|
||||
val canUpdate: Boolean,
|
||||
val splitLongChapter: Boolean,
|
||||
val durChapterTitle: String?,
|
||||
val latestChapterTitle: String?,
|
||||
val totalChapterNum: Int,
|
||||
val durChapterIndex: Int,
|
||||
val remark: String?,
|
||||
val displayIntro: String?,
|
||||
)
|
||||
|
||||
@Stable
|
||||
data class BookInfoSourceUi(
|
||||
val sourceUrl: String,
|
||||
val hasLogin: Boolean,
|
||||
)
|
||||
|
||||
sealed interface BookInfoSheet {
|
||||
data object None : BookInfoSheet
|
||||
data object CoverPicker : BookInfoSheet
|
||||
data object GroupPicker : BookInfoSheet
|
||||
data object SourcePicker : BookInfoSheet
|
||||
data class SourcePicker(val oldBook: Book) : BookInfoSheet
|
||||
data object ReadRecord : BookInfoSheet
|
||||
data class WebFiles(val openAfterImport: Boolean) : BookInfoSheet
|
||||
data class ArchiveEntries(
|
||||
|
||||
@@ -64,12 +64,10 @@ import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import coil.ImageLoader
|
||||
import coil.size.Size
|
||||
import io.legado.app.R
|
||||
import io.legado.app.constant.BookType
|
||||
import io.legado.app.data.entities.Book
|
||||
import io.legado.app.data.entities.BookChapter
|
||||
import io.legado.app.data.entities.SearchBook
|
||||
import io.legado.app.help.book.isLocal
|
||||
import io.legado.app.help.config.AppConfig
|
||||
import io.legado.app.ui.config.coverConfig.CoverConfig
|
||||
import io.legado.app.ui.main.homepage.modules.BannerModule
|
||||
@@ -252,7 +250,7 @@ private fun BookInfoScreenContent(
|
||||
}
|
||||
BookInfoSummary(
|
||||
book = book,
|
||||
chapterList = state.chapterList,
|
||||
hasChapters = state.hasChapters,
|
||||
onRemarkClick = { onIntent(BookInfoIntent.RemarkClick) },
|
||||
)
|
||||
}
|
||||
@@ -294,10 +292,10 @@ private fun BookInfoScreenContent(
|
||||
onConfirm = { onIntent(BookInfoIntent.SelectGroup(it)) },
|
||||
)
|
||||
}
|
||||
BookInfoSheet.SourcePicker -> state.book?.let { book ->
|
||||
is BookInfoSheet.SourcePicker -> {
|
||||
ChangeSourceSheet(
|
||||
show = currentSheet == BookInfoSheet.SourcePicker,
|
||||
oldBook = book,
|
||||
show = currentSheet is BookInfoSheet.SourcePicker,
|
||||
oldBook = sheet.oldBook,
|
||||
onDismissRequest = { onIntent(BookInfoIntent.DismissSheet) },
|
||||
onReplace = { source, newBook, toc, options ->
|
||||
onIntent(BookInfoIntent.ReplaceWithSource(source, newBook, toc, options))
|
||||
@@ -419,12 +417,12 @@ private fun BookInfoTransparentTopAppBar(
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun rememberBookInfoColorTheme(book: Book?): ThemeOverrideState? {
|
||||
val useDefaultCover = AppConfig.useDefaultCover || book?.customCoverUrl == "use_default_cover"
|
||||
private fun rememberBookInfoColorTheme(book: BookInfoBookUi?): ThemeOverrideState? {
|
||||
val useDefaultCover = AppConfig.useDefaultCover || book?.coverPath == "use_default_cover"
|
||||
if (useDefaultCover) return null
|
||||
|
||||
val imageLoader = koinInject<ImageLoader>()
|
||||
val coverPath = book?.getDisplayCover()
|
||||
val coverPath = book?.coverPath
|
||||
val sourceOrigin = book?.origin
|
||||
val loadOnlyWifi = CoverConfig.loadCoverOnlyWifi
|
||||
val requestKey = remember(coverPath, sourceOrigin, loadOnlyWifi) {
|
||||
@@ -480,8 +478,21 @@ private fun BookInfoTopBarActions(
|
||||
|
||||
@Composable
|
||||
private fun BookInfoBackdrop(
|
||||
book: Book,
|
||||
book: BookInfoBookUi,
|
||||
) {
|
||||
val backdropState = remember(
|
||||
book.name,
|
||||
book.author,
|
||||
book.coverPath,
|
||||
book.origin,
|
||||
) {
|
||||
BookInfoBackdropState(
|
||||
name = book.name,
|
||||
author = book.author,
|
||||
coverPath = book.coverPath,
|
||||
sourceOrigin = book.origin,
|
||||
)
|
||||
}
|
||||
val seedOverlay = lerp(
|
||||
LegadoTheme.colorScheme.secondaryContainer,
|
||||
LegadoTheme.seedColor,
|
||||
@@ -489,21 +500,25 @@ private fun BookInfoBackdrop(
|
||||
)
|
||||
Box(modifier = Modifier.fillMaxSize()) {
|
||||
Crossfade(
|
||||
targetState = book,
|
||||
targetState = backdropState,
|
||||
animationSpec = tween(800),
|
||||
label = "BackdropCrossfade"
|
||||
) { currentBook ->
|
||||
BookCoverImage(
|
||||
name = currentBook.name,
|
||||
author = currentBook.author,
|
||||
path = currentBook.getDisplayCover(),
|
||||
sourceOrigin = currentBook.origin,
|
||||
path = currentBook.coverPath,
|
||||
sourceOrigin = currentBook.sourceOrigin,
|
||||
memoryCacheKey = currentBook.coverPath?.let { "$it#book-info-backdrop" },
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.height(480.dp)
|
||||
.blur(24.dp),
|
||||
contentScale = ContentScale.Crop,
|
||||
showLoadingPlaceholder = false,
|
||||
requestBuilder = {
|
||||
size(Size(384, 384))
|
||||
}
|
||||
)
|
||||
}
|
||||
Box(
|
||||
@@ -530,6 +545,13 @@ private fun BookInfoBackdrop(
|
||||
}
|
||||
}
|
||||
|
||||
private data class BookInfoBackdropState(
|
||||
val name: String,
|
||||
val author: String,
|
||||
val coverPath: String?,
|
||||
val sourceOrigin: String?,
|
||||
)
|
||||
|
||||
@Composable
|
||||
private fun BookInfoOverflowMenu(
|
||||
expanded: Boolean,
|
||||
@@ -563,7 +585,7 @@ private fun BookInfoOverflowMenu(
|
||||
onClick = { onMenuAction(BookInfoMenuAction.Upload) }
|
||||
)
|
||||
}
|
||||
if (!state.bookSource?.loginUrl.isNullOrBlank()) {
|
||||
if (state.bookSource?.hasLogin == true) {
|
||||
RoundDropdownMenuItem(
|
||||
text = stringResource(R.string.login),
|
||||
onClick = { onMenuAction(BookInfoMenuAction.Login) }
|
||||
@@ -602,7 +624,7 @@ private fun BookInfoOverflowMenu(
|
||||
RoundDropdownMenuItem(
|
||||
text = stringResource(R.string.split_long_chapter),
|
||||
onClick = { onMenuAction(BookInfoMenuAction.ToggleSplitLongChapter) },
|
||||
isSelected = book.getSplitLongChapter()
|
||||
isSelected = book.splitLongChapter
|
||||
)
|
||||
}
|
||||
RoundDropdownMenuItem(
|
||||
@@ -623,7 +645,7 @@ private fun BookInfoOverflowMenu(
|
||||
|
||||
@Composable
|
||||
private fun BookInfoHeader(
|
||||
book: Book,
|
||||
book: BookInfoBookUi,
|
||||
kindLabels: List<String>,
|
||||
groupNames: String?,
|
||||
onCoverClick: () -> Unit,
|
||||
@@ -668,7 +690,7 @@ private fun BookInfoHeader(
|
||||
CoilBookCover(
|
||||
name = book.name,
|
||||
author = book.author,
|
||||
path = book.getDisplayCover(),
|
||||
path = book.coverPath,
|
||||
sourceOrigin = book.origin,
|
||||
modifier = Modifier
|
||||
.width(112.dp)
|
||||
@@ -720,7 +742,7 @@ private fun BookInfoHeader(
|
||||
}
|
||||
}
|
||||
AnimatedTextLine(
|
||||
text = stringResource(R.string.author_show, book.getRealAuthor()),
|
||||
text = stringResource(R.string.author_show, book.realAuthor),
|
||||
style = LegadoTheme.typography.bodyLarge,
|
||||
color = LegadoTheme.colorScheme.onSurfaceVariant,
|
||||
modifier = Modifier.combinedClickable(
|
||||
@@ -886,8 +908,8 @@ private fun BookInfoActionCard(
|
||||
|
||||
@Composable
|
||||
private fun BookInfoSummary(
|
||||
book: Book,
|
||||
chapterList: List<BookChapter>,
|
||||
book: BookInfoBookUi,
|
||||
hasChapters: Boolean,
|
||||
onRemarkClick: () -> Unit,
|
||||
) {
|
||||
Column(
|
||||
@@ -928,7 +950,7 @@ private fun BookInfoSummary(
|
||||
color = LegadoTheme.colorScheme.secondary,
|
||||
)
|
||||
}
|
||||
if (chapterList.isEmpty()) {
|
||||
if (!hasChapters) {
|
||||
AnimatedTextLine(
|
||||
text = stringResource(R.string.error_load_toc),
|
||||
style = LegadoTheme.typography.bodySmall,
|
||||
@@ -952,7 +974,7 @@ private fun BookInfoSummary(
|
||||
}
|
||||
Spacer(modifier = Modifier.height(4.dp))
|
||||
AnimatedTextLine(
|
||||
text = book.getDisplayIntro().orEmpty().ifBlank { stringResource(R.string.intro_show_null) },
|
||||
text = book.displayIntro.orEmpty().ifBlank { stringResource(R.string.intro_show_null) },
|
||||
style = LegadoTheme.typography.bodyMedium,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -62,12 +62,14 @@ import io.legado.app.utils.postEvent
|
||||
import io.legado.app.utils.splitNotBlank
|
||||
import io.legado.app.utils.toastOnUi
|
||||
import kotlinx.collections.immutable.toImmutableList
|
||||
import kotlinx.coroutines.CancellationException
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers.IO
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.async
|
||||
import kotlinx.coroutines.awaitAll
|
||||
import kotlinx.coroutines.coroutineScope
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.asSharedFlow
|
||||
@@ -76,6 +78,7 @@ import kotlinx.coroutines.flow.collectLatest
|
||||
import kotlinx.coroutines.flow.combine
|
||||
import kotlinx.coroutines.flow.update
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import java.io.ByteArrayOutputStream
|
||||
|
||||
class BookInfoViewModel(
|
||||
@@ -119,6 +122,7 @@ class BookInfoViewModel(
|
||||
|
||||
private var changeSourceCoroutine: Coroutine<*>? = null
|
||||
private var readRecordObserveJob: Job? = null
|
||||
private var relatedBooksLoadJob: Job? = null
|
||||
|
||||
fun initData(intent: Intent) {
|
||||
initData(
|
||||
@@ -162,6 +166,7 @@ class BookInfoViewModel(
|
||||
bookSource = null
|
||||
chapterChanged = false
|
||||
clearReadRecordObserve()
|
||||
relatedBooksLoadJob?.cancel()
|
||||
syncUiState()
|
||||
execute {
|
||||
val dbBook = appDb.bookDao.getBook(bookUrl)
|
||||
@@ -214,7 +219,8 @@ class BookInfoViewModel(
|
||||
?.let { showDialog(BookInfoDialog.PhotoPreview(it)) }
|
||||
|
||||
BookInfoIntent.GroupClick -> setSheet(BookInfoSheet.GroupPicker)
|
||||
BookInfoIntent.ChangeSourceClick -> setSheet(BookInfoSheet.SourcePicker)
|
||||
BookInfoIntent.ChangeSourceClick -> currentBook?.uiCopy()
|
||||
?.let { setSheet(BookInfoSheet.SourcePicker(it)) }
|
||||
BookInfoIntent.ReadRecordClick -> setSheet(BookInfoSheet.ReadRecord)
|
||||
BookInfoIntent.RemarkClick -> showDialog(BookInfoDialog.EditRemark(currentBook?.remark))
|
||||
is BookInfoIntent.SaveCover -> {
|
||||
@@ -733,7 +739,7 @@ class BookInfoViewModel(
|
||||
} else {
|
||||
loadChapter(loadedBook, runPreUpdateJs)
|
||||
}
|
||||
loadRelatedBooks(loadedBook, source)
|
||||
scheduleRelatedBooksLoad(loadedBook, source)
|
||||
}.onError {
|
||||
AppLog.put("获取书籍信息失败\n${it.localizedMessage}", it)
|
||||
context.toastOnUi(R.string.error_get_book_info)
|
||||
@@ -792,7 +798,7 @@ class BookInfoViewModel(
|
||||
if (chapters.isNotEmpty()) {
|
||||
currentChapterList = chapters
|
||||
syncUiState(isTocLoading = false)
|
||||
source?.let { loadRelatedBooks(book, it) }
|
||||
source?.let { scheduleRelatedBooksLoad(book, it) }
|
||||
} else {
|
||||
loadChapter(book)
|
||||
}
|
||||
@@ -1291,8 +1297,8 @@ class BookInfoViewModel(
|
||||
private fun syncUiState(isTocLoading: Boolean = _uiState.value.isTocLoading) {
|
||||
_uiState.update {
|
||||
it.copy(
|
||||
book = currentBook?.uiCopy(),
|
||||
chapterList = currentChapterList,
|
||||
book = currentBook?.toBookInfoBookUi(),
|
||||
hasChapters = currentChapterList.isNotEmpty(),
|
||||
webFiles = currentWebFiles,
|
||||
relatedBooks = currentRelatedBooks.toImmutableList(),
|
||||
kindLabels = currentKindLabels,
|
||||
@@ -1301,7 +1307,7 @@ class BookInfoViewModel(
|
||||
readRecordTotalTime = currentReadRecordTotalTime,
|
||||
readRecordTimelineDays = currentReadRecordTimelineDays,
|
||||
inBookshelf = inBookshelf,
|
||||
bookSource = bookSource,
|
||||
bookSource = bookSource?.toBookInfoSourceUi(),
|
||||
isTocLoading = isTocLoading,
|
||||
deleteAlertEnabled = LocalConfig.bookInfoDeleteAlert,
|
||||
deleteOriginal = LocalConfig.deleteBookOriginal,
|
||||
@@ -1332,14 +1338,50 @@ class BookInfoViewModel(
|
||||
)
|
||||
}
|
||||
|
||||
private fun loadRelatedBooks(book: Book, source: BookSource) {
|
||||
private fun scheduleRelatedBooksLoad(
|
||||
book: Book,
|
||||
source: BookSource,
|
||||
delayMillis: Long = 350L,
|
||||
) {
|
||||
relatedBooksLoadJob?.cancel()
|
||||
relatedBooksLoadJob = viewModelScope.launch {
|
||||
delay(delayMillis)
|
||||
if (!isCurrentBookSource(book, source)) return@launch
|
||||
|
||||
val modules = parseRelatedBookModules(source)
|
||||
if (modules.isEmpty()) {
|
||||
currentRelatedBooks = emptyList()
|
||||
syncUiState()
|
||||
return@launch
|
||||
}
|
||||
|
||||
try {
|
||||
val result = withContext(IO) {
|
||||
loadRelatedBooks(book, source, modules)
|
||||
}
|
||||
if (!isCurrentBookSource(book, source)) return@launch
|
||||
currentRelatedBooks = result
|
||||
syncUiState()
|
||||
} catch (e: CancellationException) {
|
||||
throw e
|
||||
} catch (e: Throwable) {
|
||||
if (!isCurrentBookSource(book, source)) return@launch
|
||||
currentRelatedBooks = emptyList()
|
||||
syncUiState()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun isCurrentBookSource(book: Book, source: BookSource): Boolean {
|
||||
return currentBook?.bookUrl == book.bookUrl && bookSource?.bookSourceUrl == source.bookSourceUrl
|
||||
}
|
||||
|
||||
private fun parseRelatedBookModules(source: BookSource): List<RelatedBooksDef> {
|
||||
val modulesJson = source.ruleBookInfo?.relatedBooks
|
||||
if (modulesJson.isNullOrBlank()) {
|
||||
currentRelatedBooks = emptyList()
|
||||
syncUiState()
|
||||
return
|
||||
return emptyList()
|
||||
}
|
||||
val modules = try {
|
||||
return try {
|
||||
GSON.fromJsonArray<RelatedBooksDef>(modulesJson)
|
||||
.getOrNull()
|
||||
?.filter { !it.url.isNullOrBlank() }
|
||||
@@ -1348,36 +1390,33 @@ class BookInfoViewModel(
|
||||
} catch (e: Exception) {
|
||||
emptyList()
|
||||
}
|
||||
if (modules.isEmpty()) {
|
||||
currentRelatedBooks = emptyList()
|
||||
syncUiState()
|
||||
return
|
||||
}
|
||||
execute {
|
||||
coroutineScope {
|
||||
modules.map { def ->
|
||||
async {
|
||||
val (resolvedUrl, books) = try {
|
||||
resolveAndExplore(source, def.url!!, book)
|
||||
} catch (e: Exception) {
|
||||
def.url!! to emptyList()
|
||||
}
|
||||
RelatedBooksUi(
|
||||
key = def.key ?: def.title.orEmpty(),
|
||||
title = def.title.orEmpty(),
|
||||
url = def.url!!,
|
||||
resolvedUrl = resolvedUrl,
|
||||
books = books.filter { it.bookUrl != book.bookUrl }.toImmutableList(),
|
||||
)
|
||||
}
|
||||
|
||||
private suspend fun loadRelatedBooks(
|
||||
book: Book,
|
||||
source: BookSource,
|
||||
modules: List<RelatedBooksDef>,
|
||||
): List<RelatedBooksUi> {
|
||||
return coroutineScope {
|
||||
modules.map { def ->
|
||||
async {
|
||||
val url = def.url.orEmpty()
|
||||
val (resolvedUrl, books) = try {
|
||||
resolveAndExplore(source, url, book)
|
||||
} catch (e: CancellationException) {
|
||||
throw e
|
||||
} catch (e: Exception) {
|
||||
url to emptyList()
|
||||
}
|
||||
}.awaitAll().filter { it.books.isNotEmpty() }
|
||||
}
|
||||
}.onSuccess { result ->
|
||||
currentRelatedBooks = result
|
||||
syncUiState()
|
||||
}.onError {
|
||||
currentRelatedBooks = emptyList()
|
||||
syncUiState()
|
||||
RelatedBooksUi(
|
||||
key = def.key ?: def.title.orEmpty(),
|
||||
title = def.title.orEmpty(),
|
||||
url = url,
|
||||
resolvedUrl = resolvedUrl,
|
||||
books = books.filter { it.bookUrl != book.bookUrl }.toImmutableList(),
|
||||
)
|
||||
}
|
||||
}.awaitAll().filter { it.books.isNotEmpty() }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1393,6 +1432,36 @@ class BookInfoViewModel(
|
||||
_effects.tryEmit(effect)
|
||||
}
|
||||
|
||||
private fun Book.toBookInfoBookUi(): BookInfoBookUi {
|
||||
return BookInfoBookUi(
|
||||
bookUrl = bookUrl,
|
||||
name = name,
|
||||
author = author,
|
||||
realAuthor = getRealAuthor(),
|
||||
origin = origin,
|
||||
originName = originName,
|
||||
coverPath = getDisplayCover(),
|
||||
group = group,
|
||||
isLocal = isLocal,
|
||||
type = type,
|
||||
canUpdate = canUpdate,
|
||||
splitLongChapter = getSplitLongChapter(),
|
||||
durChapterTitle = durChapterTitle,
|
||||
latestChapterTitle = latestChapterTitle,
|
||||
totalChapterNum = totalChapterNum,
|
||||
durChapterIndex = durChapterIndex,
|
||||
remark = remark,
|
||||
displayIntro = getDisplayIntro(),
|
||||
)
|
||||
}
|
||||
|
||||
private fun BookSource.toBookInfoSourceUi(): BookInfoSourceUi {
|
||||
return BookInfoSourceUi(
|
||||
sourceUrl = bookSourceUrl,
|
||||
hasLogin = !loginUrl.isNullOrBlank(),
|
||||
)
|
||||
}
|
||||
|
||||
private fun Book.uiCopy(): Book {
|
||||
return copy().also { snapshot ->
|
||||
snapshot.infoHtml = infoHtml
|
||||
|
||||
@@ -43,6 +43,7 @@ import androidx.compose.ui.unit.Dp
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.core.graphics.withSave
|
||||
import coil.compose.AsyncImage
|
||||
import coil.request.ImageRequest
|
||||
import io.legado.app.ui.config.coverConfig.CoverConfig
|
||||
import io.legado.app.ui.theme.LegadoTheme
|
||||
import org.koin.compose.koinInject
|
||||
@@ -58,6 +59,7 @@ fun BookCoverImage(
|
||||
path: String?,
|
||||
modifier: Modifier = Modifier,
|
||||
sourceOrigin: String? = null,
|
||||
memoryCacheKey: String? = null,
|
||||
ignoreUseDefaultCover: Boolean = false,
|
||||
showLoadingPlaceholder: Boolean = true,
|
||||
contentScale: ContentScale = ContentScale.Crop,
|
||||
@@ -65,6 +67,7 @@ fun BookCoverImage(
|
||||
onSuccess: (() -> Unit)? = null,
|
||||
onError: (() -> Unit)? = null,
|
||||
sharedCoverKey: String? = null,
|
||||
requestBuilder: ImageRequest.Builder.() -> Unit = {},
|
||||
) {
|
||||
val context = LocalContext.current
|
||||
val isNight = LegadoTheme.isDark
|
||||
@@ -116,7 +119,8 @@ fun BookCoverImage(
|
||||
sourceOrigin = sourceOrigin,
|
||||
loadOnlyWifi = CoverConfig.loadCoverOnlyWifi,
|
||||
crossfade = showLoadingPlaceholder,
|
||||
memoryCacheKey = finalPath,
|
||||
memoryCacheKey = memoryCacheKey ?: finalPath,
|
||||
configure = requestBuilder,
|
||||
),
|
||||
contentDescription = null,
|
||||
imageLoader = koinInject(),
|
||||
|
||||
Reference in New Issue
Block a user