diff --git a/app/src/main/java/io/legado/app/ui/book/info/BookInfoScreen.kt b/app/src/main/java/io/legado/app/ui/book/info/BookInfoScreen.kt index f3159140d..937b6dd07 100644 --- a/app/src/main/java/io/legado/app/ui/book/info/BookInfoScreen.kt +++ b/app/src/main/java/io/legado/app/ui/book/info/BookInfoScreen.kt @@ -59,13 +59,11 @@ import androidx.compose.ui.graphics.lerp import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.input.nestedscroll.nestedScroll import androidx.compose.ui.layout.ContentScale -import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.dp import androidx.lifecycle.compose.collectAsStateWithLifecycle import coil.ImageLoader -import coil.compose.AsyncImage import io.legado.app.R import io.legado.app.constant.BookType import io.legado.app.data.entities.Book @@ -73,7 +71,6 @@ 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.model.BookCover import io.legado.app.ui.config.coverConfig.CoverConfig import io.legado.app.ui.main.homepage.modules.BannerModule import io.legado.app.ui.theme.LegadoTheme @@ -93,8 +90,8 @@ import io.legado.app.ui.widget.components.button.series.SmallTonalButton import io.legado.app.ui.widget.components.card.GlassCard import io.legado.app.ui.widget.components.card.TextCard import io.legado.app.ui.widget.components.icon.AppIcon +import io.legado.app.ui.widget.components.image.cover.BookCoverImage import io.legado.app.ui.widget.components.image.cover.CoilBookCover -import io.legado.app.ui.widget.components.image.cover.buildCoverImageRequest import io.legado.app.ui.widget.components.log.AppLogSheet import io.legado.app.ui.widget.components.menuItem.RoundDropdownMenu import io.legado.app.ui.widget.components.menuItem.RoundDropdownMenuItem @@ -192,10 +189,7 @@ private fun BookInfoScreenContent( } else { Box(modifier = Modifier.fillMaxSize()) { BookInfoBackdrop( - bookUrl = book.bookUrl, - coverUrl = book.coverUrl, - customCoverUrl = book.customCoverUrl, - origin = book.origin, + book = book, ) AppPullToRefresh( modifier = Modifier.fillMaxSize(), @@ -479,26 +473,8 @@ private fun BookInfoTopBarActions( @Composable private fun BookInfoBackdrop( - bookUrl: String, - coverUrl: String?, - customCoverUrl: String?, - origin: String, + book: Book, ) { - val useDefaultCover = AppConfig.useDefaultCover || customCoverUrl == "use_default_cover" - val isNight = AppConfig.isNightTheme - - val cover = remember(bookUrl, customCoverUrl, coverUrl, isNight) { - if (useDefaultCover) { - BookCover.getRandomDefaultPath(bookUrl, isNight) - } else { - if (customCoverUrl.isNullOrEmpty()) coverUrl else customCoverUrl - } - } - val sourceOrigin = if (!useDefaultCover) origin else null - val loadOnlyWifi = CoverConfig.loadCoverOnlyWifi - val context = LocalContext.current - val imageLoader = koinInject() - val seedOverlay = lerp( LegadoTheme.colorScheme.secondaryContainer, LegadoTheme.seedColor, @@ -506,32 +482,22 @@ private fun BookInfoBackdrop( ) Box(modifier = Modifier.fillMaxSize()) { Crossfade( - targetState = cover, + targetState = book, animationSpec = tween(800), label = "BackdropCrossfade" - ) { currentCover -> - if (!currentCover.isNullOrBlank()) { - val backdropRequest = remember(currentCover, sourceOrigin, loadOnlyWifi, context) { - buildCoverImageRequest( - context = context, - data = currentCover, - sourceOrigin = sourceOrigin, - loadOnlyWifi = loadOnlyWifi, - crossfade = true, - memoryCacheKey = currentCover, - ) - } - AsyncImage( - model = backdropRequest, - imageLoader = imageLoader, - contentDescription = null, - modifier = Modifier - .fillMaxWidth() - .height(480.dp) - .blur(24.dp), - contentScale = ContentScale.Crop, - ) - } + ) { currentBook -> + BookCoverImage( + name = currentBook.name, + author = currentBook.author, + path = currentBook.getDisplayCover(), + sourceOrigin = currentBook.origin, + modifier = Modifier + .fillMaxWidth() + .height(480.dp) + .blur(24.dp), + contentScale = ContentScale.Crop, + showLoadingPlaceholder = false, + ) } Box( modifier = Modifier diff --git a/app/src/main/java/io/legado/app/ui/widget/components/image/cover/CoilBookCover.kt b/app/src/main/java/io/legado/app/ui/widget/components/image/cover/CoilBookCover.kt index a75d427c2..01644ddd0 100644 --- a/app/src/main/java/io/legado/app/ui/widget/components/image/cover/CoilBookCover.kt +++ b/app/src/main/java/io/legado/app/ui/widget/components/image/cover/CoilBookCover.kt @@ -52,6 +52,97 @@ import io.legado.app.model.BookCover as BookCoverModel private const val SharedCoverRadiusCacheMaxSize = 256 private val sharedCoverRadiusCache = mutableStateMapOf() +@Composable +fun BookCoverImage( + name: String?, + author: String?, + path: String?, + modifier: Modifier = Modifier, + sourceOrigin: String? = null, + ignoreUseDefaultCover: Boolean = false, + showLoadingPlaceholder: Boolean = true, + contentScale: ContentScale = ContentScale.Crop, + onLoadFinish: (() -> Unit)? = null, + onSuccess: (() -> Unit)? = null, + onError: (() -> Unit)? = null, + sharedCoverKey: String? = null, +) { + val context = LocalContext.current + val isNight = isSystemInDarkTheme() + + val useDefault = !ignoreUseDefaultCover && CoverConfig.useDefaultCover + val finalPath = if (useDefault) null else path + + val randomPath = remember(name, author, path, isNight) { + BookCoverModel.getRandomDefaultPath( + seed = name ?: author ?: path ?: "", + isNight = isNight + ) + } + + val hasCustomDefault = !randomPath.isNullOrBlank() + var isOnlineCoverLoaded by remember(finalPath) { + mutableStateOf(sharedCoverKey != null && finalPath != null) + } + + LaunchedEffect(finalPath) { + if (finalPath == null) { + isOnlineCoverLoaded = false + } + } + + Box(modifier = modifier) { + if (hasCustomDefault && !isOnlineCoverLoaded) { + AsyncImage( + model = buildCoverImageRequest( + context = context, + data = randomPath, + sourceOrigin = null, + loadOnlyWifi = false, + crossfade = showLoadingPlaceholder, + memoryCacheKey = randomPath, + ), + contentDescription = null, + imageLoader = koinInject(), + contentScale = contentScale, + modifier = Modifier.fillMaxSize() + ) + } + + if (finalPath != null) { + AsyncImage( + model = buildCoverImageRequest( + context = context, + data = finalPath, + sourceOrigin = sourceOrigin, + loadOnlyWifi = CoverConfig.loadCoverOnlyWifi, + crossfade = showLoadingPlaceholder, + memoryCacheKey = finalPath, + ), + contentDescription = null, + imageLoader = koinInject(), + contentScale = contentScale, + modifier = Modifier.fillMaxSize(), + onSuccess = { + isOnlineCoverLoaded = true + onSuccess?.invoke() + onLoadFinish?.invoke() + }, + onError = { + isOnlineCoverLoaded = false + onError?.invoke() + onLoadFinish?.invoke() + } + ) + } else { + LaunchedEffect(Unit) { + onLoadFinish?.invoke() + } + } + } +} + +// 改成BookCover @OptIn(ExperimentalSharedTransitionApi::class) @Composable fun CoilBookCover( @@ -68,7 +159,6 @@ fun CoilBookCover( animatedVisibilityScope: AnimatedVisibilityScope? = null, sharedCoverKey: String? = null, ) { - val context = LocalContext.current val isNight = isSystemInDarkTheme() val useDefault = !ignoreUseDefaultCover && CoverConfig.useDefaultCover @@ -126,54 +216,24 @@ fun CoilBookCover( ) .clip(shape) ) { - Box(modifier = Modifier.fillMaxSize()) { - if (hasCustomDefault && !isOnlineCoverLoaded) { - AsyncImage( - model = buildCoverImageRequest( - context = context, - data = randomPath, - sourceOrigin = null, - loadOnlyWifi = false, - crossfade = showLoadingPlaceholder, - memoryCacheKey = randomPath, - ), - contentDescription = null, - imageLoader = koinInject(), - contentScale = ContentScale.Crop, - modifier = Modifier - .fillMaxSize() - ) - } - - if (finalPath != null) { - AsyncImage( - model = buildCoverImageRequest( - context = context, - data = finalPath, - sourceOrigin = sourceOrigin, - loadOnlyWifi = CoverConfig.loadCoverOnlyWifi, - crossfade = showLoadingPlaceholder, - memoryCacheKey = finalPath, - ), - contentDescription = null, - imageLoader = koinInject(), - contentScale = ContentScale.Crop, - modifier = Modifier.fillMaxSize(), - onSuccess = { - isOnlineCoverLoaded = true - onLoadFinish?.invoke() - }, - onError = { - isOnlineCoverLoaded = false - onLoadFinish?.invoke() - } - ) - } else { - LaunchedEffect(Unit) { - onLoadFinish?.invoke() - } - } - } + BookCoverImage( + name = name, + author = author, + path = path, + modifier = Modifier.fillMaxSize(), + sourceOrigin = sourceOrigin, + ignoreUseDefaultCover = ignoreUseDefaultCover, + showLoadingPlaceholder = showLoadingPlaceholder, + onSuccess = { + isOnlineCoverLoaded = true + onLoadFinish?.invoke() + }, + onError = { + isOnlineCoverLoaded = false + onLoadFinish?.invoke() + }, + sharedCoverKey = sharedCoverKey + ) if (showLoadingPlaceholder && !isOnlineCoverLoaded) { if (!hasCustomDefault) {