|
@@ -153,9 +153,24 @@ fun BookInfoScreen(
|
|
|
canApplyCoverTheme = true
|
|
canApplyCoverTheme = true
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
- val bookColorTheme = rememberBookInfoColorTheme(state.book)
|
|
|
|
|
|
|
+ val initiallyUsesDefaultCover = state.book?.let { usesDefaultBookCover(it.coverPath) } ?: true
|
|
|
|
|
+ var usesDefaultCover by remember(
|
|
|
|
|
+ state.book?.bookUrl,
|
|
|
|
|
+ state.book?.coverPath,
|
|
|
|
|
+ initiallyUsesDefaultCover,
|
|
|
|
|
+ ) {
|
|
|
|
|
+ mutableStateOf(initiallyUsesDefaultCover)
|
|
|
|
|
+ }
|
|
|
|
|
+ val backdropStyle = state.book?.let { resolveBookInfoBackdropStyle(it, usesDefaultCover) }
|
|
|
|
|
+ val bookColorTheme = rememberBookInfoColorTheme(
|
|
|
|
|
+ book = state.book,
|
|
|
|
|
+ enabled = backdropStyle?.showCover == true,
|
|
|
|
|
+ usesDefaultCover = usesDefaultCover,
|
|
|
|
|
+ )
|
|
|
|
|
|
|
|
- BookInfoColorTheme(theme = bookColorTheme.takeIf { canApplyCoverTheme }) {
|
|
|
|
|
|
|
+ BookInfoColorTheme(theme = bookColorTheme.takeIf {
|
|
|
|
|
+ canApplyCoverTheme && backdropStyle?.showCover == true
|
|
|
|
|
+ }) {
|
|
|
BookInfoScreenContent(
|
|
BookInfoScreenContent(
|
|
|
state = state,
|
|
state = state,
|
|
|
onIntent = onIntent,
|
|
onIntent = onIntent,
|
|
@@ -163,6 +178,13 @@ fun BookInfoScreen(
|
|
|
sharedTransitionScope = sharedTransitionScope,
|
|
sharedTransitionScope = sharedTransitionScope,
|
|
|
animatedVisibilityScope = animatedVisibilityScope,
|
|
animatedVisibilityScope = animatedVisibilityScope,
|
|
|
sharedCoverKey = sharedCoverKey,
|
|
sharedCoverKey = sharedCoverKey,
|
|
|
|
|
+ backdropStyle = backdropStyle,
|
|
|
|
|
+ usesDefaultCover = usesDefaultCover,
|
|
|
|
|
+ onNetworkCoverLoadError = { failedCoverPath ->
|
|
|
|
|
+ if (failedCoverPath == state.book?.coverPath) {
|
|
|
|
|
+ usesDefaultCover = true
|
|
|
|
|
+ }
|
|
|
|
|
+ },
|
|
|
)
|
|
)
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
@@ -178,6 +200,9 @@ private fun BookInfoScreenContent(
|
|
|
sharedTransitionScope: SharedTransitionScope?,
|
|
sharedTransitionScope: SharedTransitionScope?,
|
|
|
animatedVisibilityScope: AnimatedVisibilityScope?,
|
|
animatedVisibilityScope: AnimatedVisibilityScope?,
|
|
|
sharedCoverKey: String?,
|
|
sharedCoverKey: String?,
|
|
|
|
|
+ backdropStyle: BookInfoBackdropStyle?,
|
|
|
|
|
+ usesDefaultCover: Boolean,
|
|
|
|
|
+ onNetworkCoverLoadError: (String?) -> Unit,
|
|
|
) {
|
|
) {
|
|
|
val isMiuix = ThemeResolver.isMiuixEngine(LegadoTheme.composeEngine)
|
|
val isMiuix = ThemeResolver.isMiuixEngine(LegadoTheme.composeEngine)
|
|
|
val scrollBehavior = if (isMiuix) {
|
|
val scrollBehavior = if (isMiuix) {
|
|
@@ -217,9 +242,13 @@ private fun BookInfoScreenContent(
|
|
|
if (book == null) {
|
|
if (book == null) {
|
|
|
Box(modifier = Modifier.fillMaxSize())
|
|
Box(modifier = Modifier.fillMaxSize())
|
|
|
} else {
|
|
} else {
|
|
|
|
|
+ val resolvedBackdropStyle = requireNotNull(backdropStyle)
|
|
|
Box(modifier = Modifier.fillMaxSize()) {
|
|
Box(modifier = Modifier.fillMaxSize()) {
|
|
|
BookInfoBackdrop(
|
|
BookInfoBackdrop(
|
|
|
book = book,
|
|
book = book,
|
|
|
|
|
+ style = resolvedBackdropStyle,
|
|
|
|
|
+ usesDefaultCover = usesDefaultCover,
|
|
|
|
|
+ onNetworkCoverLoadError = onNetworkCoverLoadError,
|
|
|
)
|
|
)
|
|
|
AppPullToRefresh(
|
|
AppPullToRefresh(
|
|
|
modifier = Modifier.fillMaxSize(),
|
|
modifier = Modifier.fillMaxSize(),
|
|
@@ -247,6 +276,11 @@ private fun BookInfoScreenContent(
|
|
|
onAuthorClick = { onIntent(BookInfoIntent.AuthorClick(it)) },
|
|
onAuthorClick = { onIntent(BookInfoIntent.AuthorClick(it)) },
|
|
|
onBookNameClick = { onIntent(BookInfoIntent.BookNameClick(it)) },
|
|
onBookNameClick = { onIntent(BookInfoIntent.BookNameClick(it)) },
|
|
|
onOriginClick = { onIntent(BookInfoIntent.OriginClick) },
|
|
onOriginClick = { onIntent(BookInfoIntent.OriginClick) },
|
|
|
|
|
+ onNetworkCoverLoadError = {
|
|
|
|
|
+ onNetworkCoverLoadError(book.coverPath)
|
|
|
|
|
+ },
|
|
|
|
|
+ usesDefaultCover = usesDefaultCover,
|
|
|
|
|
+ blurCover = resolvedBackdropStyle.blurCover,
|
|
|
sharedTransitionScope = sharedTransitionScope,
|
|
sharedTransitionScope = sharedTransitionScope,
|
|
|
animatedVisibilityScope = animatedVisibilityScope,
|
|
animatedVisibilityScope = animatedVisibilityScope,
|
|
|
sharedCoverKey = sharedCoverKey,
|
|
sharedCoverKey = sharedCoverKey,
|
|
@@ -482,9 +516,12 @@ private fun BookInfoTransparentTopAppBar(
|
|
|
@Composable
|
|
@Composable
|
|
|
private fun rememberBookInfoColorTheme(
|
|
private fun rememberBookInfoColorTheme(
|
|
|
book: BookInfoBookUi?,
|
|
book: BookInfoBookUi?,
|
|
|
|
|
+ enabled: Boolean,
|
|
|
|
|
+ usesDefaultCover: Boolean,
|
|
|
): ThemeOverrideState? {
|
|
): ThemeOverrideState? {
|
|
|
if (
|
|
if (
|
|
|
book == null ||
|
|
book == null ||
|
|
|
|
|
+ !enabled ||
|
|
|
!ThemeConfig.bookInfoFollowCoverColor
|
|
!ThemeConfig.bookInfoFollowCoverColor
|
|
|
) {
|
|
) {
|
|
|
return null
|
|
return null
|
|
@@ -492,18 +529,17 @@ private fun rememberBookInfoColorTheme(
|
|
|
|
|
|
|
|
val imageLoader = koinInject<ImageLoader>()
|
|
val imageLoader = koinInject<ImageLoader>()
|
|
|
val isNight = LegadoTheme.isDark
|
|
val isNight = LegadoTheme.isDark
|
|
|
- val useDefaultCover = usesDefaultBookCover(book.coverPath)
|
|
|
|
|
val defaultCoverPaths =
|
|
val defaultCoverPaths =
|
|
|
if (isNight) CoverConfig.defaultCoverDark else CoverConfig.defaultCover
|
|
if (isNight) CoverConfig.defaultCoverDark else CoverConfig.defaultCover
|
|
|
val coverPath = remember(
|
|
val coverPath = remember(
|
|
|
book.name,
|
|
book.name,
|
|
|
book.author,
|
|
book.author,
|
|
|
book.coverPath,
|
|
book.coverPath,
|
|
|
- useDefaultCover,
|
|
|
|
|
|
|
+ usesDefaultCover,
|
|
|
isNight,
|
|
isNight,
|
|
|
defaultCoverPaths,
|
|
defaultCoverPaths,
|
|
|
) {
|
|
) {
|
|
|
- if (useDefaultCover) {
|
|
|
|
|
|
|
+ if (usesDefaultCover) {
|
|
|
BookCoverModel.getRandomDefaultPath(
|
|
BookCoverModel.getRandomDefaultPath(
|
|
|
seed = book.name,
|
|
seed = book.name,
|
|
|
isNight = isNight,
|
|
isNight = isNight,
|
|
@@ -512,8 +548,8 @@ private fun rememberBookInfoColorTheme(
|
|
|
book.coverPath
|
|
book.coverPath
|
|
|
}
|
|
}
|
|
|
} ?: return null
|
|
} ?: return null
|
|
|
- val sourceOrigin = if (useDefaultCover) null else book.origin
|
|
|
|
|
- val loadOnlyWifi = !useDefaultCover && CoverConfig.loadCoverOnlyWifi
|
|
|
|
|
|
|
+ val sourceOrigin = if (usesDefaultCover) null else book.origin
|
|
|
|
|
+ val loadOnlyWifi = !usesDefaultCover && CoverConfig.loadCoverOnlyWifi
|
|
|
val requestKey = remember(coverPath, sourceOrigin, loadOnlyWifi) {
|
|
val requestKey = remember(coverPath, sourceOrigin, loadOnlyWifi) {
|
|
|
listOf(coverPath, sourceOrigin, loadOnlyWifi)
|
|
listOf(coverPath, sourceOrigin, loadOnlyWifi)
|
|
|
}
|
|
}
|
|
@@ -530,6 +566,18 @@ private fun rememberBookInfoColorTheme(
|
|
|
return rememberThemeOverride(seedColor)
|
|
return rememberThemeOverride(seedColor)
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+private fun resolveBookInfoBackdropStyle(
|
|
|
|
|
+ book: BookInfoBookUi,
|
|
|
|
|
+ usesDefaultCover: Boolean,
|
|
|
|
|
+): BookInfoBackdropStyle {
|
|
|
|
|
+ val backgroundMode = if (usesDefaultCover) {
|
|
|
|
|
+ ThemeConfig.bookInfoDefaultCoverBackground
|
|
|
|
|
+ } else {
|
|
|
|
|
+ ThemeConfig.bookInfoNetworkCoverBackground
|
|
|
|
|
+ }
|
|
|
|
|
+ return resolveBookInfoBackdropStyle(backgroundMode)
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
@Composable
|
|
@Composable
|
|
|
private fun BookInfoTopBarActions(
|
|
private fun BookInfoTopBarActions(
|
|
|
state: BookInfoUiState,
|
|
state: BookInfoUiState,
|
|
@@ -568,23 +616,22 @@ private fun BookInfoTopBarActions(
|
|
|
@Composable
|
|
@Composable
|
|
|
private fun BookInfoBackdrop(
|
|
private fun BookInfoBackdrop(
|
|
|
book: BookInfoBookUi,
|
|
book: BookInfoBookUi,
|
|
|
|
|
+ style: BookInfoBackdropStyle,
|
|
|
|
|
+ usesDefaultCover: Boolean,
|
|
|
|
|
+ onNetworkCoverLoadError: (String?) -> Unit,
|
|
|
) {
|
|
) {
|
|
|
- val backgroundMode = ThemeConfig.bookInfoBackgroundBlur
|
|
|
|
|
- val showBackgroundCover =
|
|
|
|
|
- backgroundMode != ThemeConfig.BOOK_INFO_BACKGROUND_COVER_HIDDEN
|
|
|
|
|
- val blurBackground = backgroundMode != ThemeConfig.BOOK_INFO_BACKGROUND_BLUR_OFF
|
|
|
|
|
-
|
|
|
|
|
val backdropState = remember(
|
|
val backdropState = remember(
|
|
|
book.name,
|
|
book.name,
|
|
|
book.author,
|
|
book.author,
|
|
|
book.coverPath,
|
|
book.coverPath,
|
|
|
book.origin,
|
|
book.origin,
|
|
|
|
|
+ usesDefaultCover,
|
|
|
) {
|
|
) {
|
|
|
BookInfoBackdropState(
|
|
BookInfoBackdropState(
|
|
|
name = book.name,
|
|
name = book.name,
|
|
|
author = book.author,
|
|
author = book.author,
|
|
|
- coverPath = book.coverPath,
|
|
|
|
|
- sourceOrigin = book.origin,
|
|
|
|
|
|
|
+ coverPath = if (usesDefaultCover) null else book.coverPath,
|
|
|
|
|
+ sourceOrigin = if (usesDefaultCover) null else book.origin,
|
|
|
)
|
|
)
|
|
|
}
|
|
}
|
|
|
val seedOverlay = lerp(
|
|
val seedOverlay = lerp(
|
|
@@ -597,7 +644,7 @@ private fun BookInfoBackdrop(
|
|
|
.fillMaxSize()
|
|
.fillMaxSize()
|
|
|
.clearAndSetSemantics { }
|
|
.clearAndSetSemantics { }
|
|
|
) {
|
|
) {
|
|
|
- if (showBackgroundCover) {
|
|
|
|
|
|
|
+ if (style.showCover) {
|
|
|
Crossfade(
|
|
Crossfade(
|
|
|
targetState = backdropState,
|
|
targetState = backdropState,
|
|
|
animationSpec = tween(800),
|
|
animationSpec = tween(800),
|
|
@@ -613,7 +660,7 @@ private fun BookInfoBackdrop(
|
|
|
.fillMaxWidth()
|
|
.fillMaxWidth()
|
|
|
.height(480.dp)
|
|
.height(480.dp)
|
|
|
.then(
|
|
.then(
|
|
|
- if (blurBackground) {
|
|
|
|
|
|
|
+ if (style.blurCover) {
|
|
|
Modifier.blur(24.dp)
|
|
Modifier.blur(24.dp)
|
|
|
} else {
|
|
} else {
|
|
|
Modifier
|
|
Modifier
|
|
@@ -621,17 +668,20 @@ private fun BookInfoBackdrop(
|
|
|
),
|
|
),
|
|
|
contentScale = ContentScale.Crop,
|
|
contentScale = ContentScale.Crop,
|
|
|
showLoadingPlaceholder = false,
|
|
showLoadingPlaceholder = false,
|
|
|
|
|
+ onError = { onNetworkCoverLoadError(currentBook.coverPath) },
|
|
|
requestBuilder = {
|
|
requestBuilder = {
|
|
|
size(Size(384, 384))
|
|
size(Size(384, 384))
|
|
|
}
|
|
}
|
|
|
)
|
|
)
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
- Box(
|
|
|
|
|
- modifier = Modifier
|
|
|
|
|
- .fillMaxSize()
|
|
|
|
|
- .background(seedOverlay.copy(alpha = 0.34f))
|
|
|
|
|
- )
|
|
|
|
|
|
|
+ if (style.blurCover) {
|
|
|
|
|
+ Box(
|
|
|
|
|
+ modifier = Modifier
|
|
|
|
|
+ .fillMaxSize()
|
|
|
|
|
+ .background(seedOverlay.copy(alpha = 0.34f))
|
|
|
|
|
+ )
|
|
|
|
|
+ }
|
|
|
Box(
|
|
Box(
|
|
|
modifier = Modifier
|
|
modifier = Modifier
|
|
|
.fillMaxSize()
|
|
.fillMaxSize()
|
|
@@ -639,8 +689,16 @@ private fun BookInfoBackdrop(
|
|
|
Brush.verticalGradient(
|
|
Brush.verticalGradient(
|
|
|
colorStops = arrayOf(
|
|
colorStops = arrayOf(
|
|
|
0f to Color.Transparent,
|
|
0f to Color.Transparent,
|
|
|
- 0.20f to seedOverlay.copy(alpha = 0.10f),
|
|
|
|
|
- 0.40f to seedOverlay.copy(alpha = 0.18f),
|
|
|
|
|
|
|
+ 0.20f to if (style.blurCover) {
|
|
|
|
|
+ seedOverlay.copy(alpha = 0.10f)
|
|
|
|
|
+ } else {
|
|
|
|
|
+ Color.Transparent
|
|
|
|
|
+ },
|
|
|
|
|
+ 0.40f to if (style.blurCover) {
|
|
|
|
|
+ seedOverlay.copy(alpha = 0.18f)
|
|
|
|
|
+ } else {
|
|
|
|
|
+ LegadoTheme.colorScheme.surface.copy(alpha = 0.35f)
|
|
|
|
|
+ },
|
|
|
0.60f to LegadoTheme.colorScheme.surface.copy(alpha = 0.85f),
|
|
0.60f to LegadoTheme.colorScheme.surface.copy(alpha = 0.85f),
|
|
|
0.80f to LegadoTheme.colorScheme.surface,
|
|
0.80f to LegadoTheme.colorScheme.surface,
|
|
|
1f to LegadoTheme.colorScheme.surface,
|
|
1f to LegadoTheme.colorScheme.surface,
|
|
@@ -760,6 +818,9 @@ private fun BookInfoHeader(
|
|
|
onAuthorClick: (Boolean) -> Unit,
|
|
onAuthorClick: (Boolean) -> Unit,
|
|
|
onBookNameClick: (Boolean) -> Unit,
|
|
onBookNameClick: (Boolean) -> Unit,
|
|
|
onOriginClick: () -> Unit,
|
|
onOriginClick: () -> Unit,
|
|
|
|
|
+ onNetworkCoverLoadError: () -> Unit,
|
|
|
|
|
+ usesDefaultCover: Boolean,
|
|
|
|
|
+ blurCover: Boolean,
|
|
|
sharedTransitionScope: SharedTransitionScope?,
|
|
sharedTransitionScope: SharedTransitionScope?,
|
|
|
animatedVisibilityScope: AnimatedVisibilityScope?,
|
|
animatedVisibilityScope: AnimatedVisibilityScope?,
|
|
|
sharedCoverKey: String?,
|
|
sharedCoverKey: String?,
|
|
@@ -772,8 +833,12 @@ private fun BookInfoHeader(
|
|
|
Brush.verticalGradient(
|
|
Brush.verticalGradient(
|
|
|
colors = listOf(
|
|
colors = listOf(
|
|
|
Color.Transparent,
|
|
Color.Transparent,
|
|
|
- lerp(LegadoTheme.colorScheme.surface, LegadoTheme.seedColor, 0.08f)
|
|
|
|
|
- .copy(alpha = 0.5f),
|
|
|
|
|
|
|
+ if (blurCover) {
|
|
|
|
|
+ lerp(LegadoTheme.colorScheme.surface, LegadoTheme.seedColor, 0.08f)
|
|
|
|
|
+ .copy(alpha = 0.5f)
|
|
|
|
|
+ } else {
|
|
|
|
|
+ LegadoTheme.colorScheme.surface.copy(alpha = 0.5f)
|
|
|
|
|
+ },
|
|
|
LegadoTheme.colorScheme.surface,
|
|
LegadoTheme.colorScheme.surface,
|
|
|
)
|
|
)
|
|
|
)
|
|
)
|
|
@@ -802,8 +867,9 @@ private fun BookInfoHeader(
|
|
|
CoilBookCover(
|
|
CoilBookCover(
|
|
|
name = book.name,
|
|
name = book.name,
|
|
|
author = book.author,
|
|
author = book.author,
|
|
|
- path = book.coverPath,
|
|
|
|
|
- sourceOrigin = book.origin,
|
|
|
|
|
|
|
+ path = if (usesDefaultCover) null else book.coverPath,
|
|
|
|
|
+ sourceOrigin = if (usesDefaultCover) null else book.origin,
|
|
|
|
|
+ onError = onNetworkCoverLoadError,
|
|
|
modifier = Modifier
|
|
modifier = Modifier
|
|
|
.width(112.dp)
|
|
.width(112.dp)
|
|
|
.aspectRatio(5f / 7f),
|
|
.aspectRatio(5f / 7f),
|