From 9bb8571cc74286d51a58beece9c4a136624cf965 Mon Sep 17 00:00:00 2001 From: HapeLee <63206378+HapeLee@users.noreply.github.com> Date: Mon, 15 Jun 2026 01:33:28 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E9=98=85=E8=AF=BB=E8=8F=9C=E5=8D=95?= =?UTF-8?q?=E6=A8=A1=E7=B3=8A=E7=9D=80=E8=89=B2=E3=80=81=E8=B0=83=E8=89=B2?= =?UTF-8?q?=E6=9D=BF=E6=A0=B7=E5=BC=8F=E3=80=81=E6=A0=87=E9=A2=98=E8=83=B6?= =?UTF-8?q?=E5=9B=8A=E5=B8=83=E5=B1=80=E5=8F=8A=E4=B8=BB=E9=A2=98=E8=A6=86?= =?UTF-8?q?=E7=9B=96=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/io/legado/app/constant/PreferKey.kt | 2 + .../data/repository/ReadSettingsRepository.kt | 15 +++ .../usecase/ChangeSourceSearchUseCase.kt | 16 +-- .../legado/app/help/config/ReadBookConfig.kt | 2 + .../ChangeBookSourceComposeViewModel.kt | 79 +++++++++++- .../app/ui/book/read/ReadBookColorTheme.kt | 25 +++- .../app/ui/book/read/ReadBookContract.kt | 23 ++++ .../app/ui/book/read/ReadBookMenuBar.kt | 122 +++++++++--------- .../legado/app/ui/book/read/ReadBookScreen.kt | 11 ++ .../app/ui/book/read/ReadBookViewModel.kt | 36 ++++++ .../app/ui/book/read/sheet/SystemMenuPage.kt | 70 ++++++++++ .../app/ui/book/read/sheet/TextTitleSheet.kt | 91 ++++++++++++- .../app/ui/book/search/ScopeSelectSheet.kt | 2 +- .../app/ui/theme/ThemeColorSchemeOverride.kt | 5 +- .../io/legado/app/ui/theme/ThemeOverride.kt | 5 +- .../changeSource/ChangeSourceSheet.kt | 4 +- .../app/ui/widget/components/icon/AppIcons.kt | 5 + .../components/menuItem/RoundDropdownMenu.kt | 6 +- .../menuItem/RoundDropdownMenuItem.kt | 9 +- app/src/main/res/values-zh-rCN/strings.xml | 5 + app/src/main/res/values/strings.xml | 5 + 21 files changed, 448 insertions(+), 90 deletions(-) diff --git a/app/src/main/java/io/legado/app/constant/PreferKey.kt b/app/src/main/java/io/legado/app/constant/PreferKey.kt index 60257c268..b0cac807d 100644 --- a/app/src/main/java/io/legado/app/constant/PreferKey.kt +++ b/app/src/main/java/io/legado/app/constant/PreferKey.kt @@ -308,6 +308,8 @@ object PreferKey { const val readMenuBottomBarBlurStyle = "readMenuBottomBarBlurStyle" const val readMenuBlurRadius = "readMenuBlurRadius" const val readMenuBlurAlpha = "readMenuBlurAlpha" + const val readMenuBlurColor = "readMenuBlurColor" + const val readMenuPaletteStyle = "readMenuPaletteStyle" const val readMenuLensRadius = "readMenuLensRadius" const val readMenuBorderWidth = "readMenuBorderWidth" const val readMenuBorderColor = "readMenuBorderColor" diff --git a/app/src/main/java/io/legado/app/data/repository/ReadSettingsRepository.kt b/app/src/main/java/io/legado/app/data/repository/ReadSettingsRepository.kt index 82c1012df..ab9ab93cd 100644 --- a/app/src/main/java/io/legado/app/data/repository/ReadSettingsRepository.kt +++ b/app/src/main/java/io/legado/app/data/repository/ReadSettingsRepository.kt @@ -94,6 +94,8 @@ data class ReadPreferences( val readMenuBottomBarBlurStyle: Int = ReadMenuBlurStyle.Solid, val readMenuBlurRadius: Int = 24, val readMenuBlurAlpha: Int = 60, + val readMenuBlurColor: Int = 0, + val readMenuPaletteStyle: String = "", val readMenuLensRadius: Float = 24f, val readMenuBorderWidth: Int = 0, val readMenuBorderColor: Int = 0, @@ -335,6 +337,12 @@ class ReadSettingsRepository( suspend fun setReadMenuBlurAlpha(value: Int) = settingsRepository.putInt(PreferKey.readMenuBlurAlpha, value.coerceIn(0, 100)) + suspend fun setReadMenuBlurColor(value: Int) = + settingsRepository.putInt(PreferKey.readMenuBlurColor, value) + + suspend fun setReadMenuPaletteStyle(value: String) = + settingsRepository.putString(PreferKey.readMenuPaletteStyle, value) + suspend fun setReadMenuLensRadius(value: Float) = settingsRepository.putFloat(PreferKey.readMenuLensRadius, value.coerceIn(0f, 48f)) @@ -446,6 +454,7 @@ class ReadSettingsRepository( readMenuBottomBarBlurMode = this[Keys.ReadMenuBottomBarBlurMode] ?: ReadMenuBlurMode.None, readMenuTopBarLiquidGlassButtons = this[Keys.ReadMenuTopBarLiquidGlassButtons] ?: false, + readMenuTopBarTitleCapsule = this[Keys.ReadMenuTopBarTitleCapsule] ?: false, readMenuBottomBarLiquidGlassButtons = this[Keys.ReadMenuBottomBarLiquidGlassButtons] ?: false, readMenuTopBarBlurStyle = this[Keys.ReadMenuTopBarBlurStyle] @@ -454,6 +463,8 @@ class ReadSettingsRepository( ?: ReadMenuBlurStyle.Solid, readMenuBlurRadius = this[Keys.ReadMenuBlurRadius] ?: 24, readMenuBlurAlpha = this[Keys.ReadMenuBlurAlpha] ?: 60, + readMenuBlurColor = this[Keys.ReadMenuBlurColor] ?: 0, + readMenuPaletteStyle = this[Keys.ReadMenuPaletteStyle] ?: "", readMenuLensRadius = this[Keys.ReadMenuLensRadius] ?: 24f, readMenuBorderWidth = this[Keys.ReadMenuBorderWidth] ?: 0, readMenuBorderColor = this[Keys.ReadMenuBorderColor] ?: 0, @@ -540,12 +551,16 @@ class ReadSettingsRepository( val ReadMenuBottomBarBlurMode = intPreferencesKey(PreferKey.readMenuBottomBarBlurMode) val ReadMenuTopBarLiquidGlassButtons = booleanPreferencesKey(PreferKey.readMenuTopBarLiquidGlassButtons) + val ReadMenuTopBarTitleCapsule = + booleanPreferencesKey(PreferKey.readMenuTopBarTitleCapsule) val ReadMenuBottomBarLiquidGlassButtons = booleanPreferencesKey(PreferKey.readMenuBottomBarLiquidGlassButtons) val ReadMenuTopBarBlurStyle = intPreferencesKey(PreferKey.readMenuTopBarBlurStyle) val ReadMenuBottomBarBlurStyle = intPreferencesKey(PreferKey.readMenuBottomBarBlurStyle) val ReadMenuBlurRadius = intPreferencesKey(PreferKey.readMenuBlurRadius) val ReadMenuBlurAlpha = intPreferencesKey(PreferKey.readMenuBlurAlpha) + val ReadMenuBlurColor = intPreferencesKey(PreferKey.readMenuBlurColor) + val ReadMenuPaletteStyle = stringPreferencesKey(PreferKey.readMenuPaletteStyle) val ReadMenuLensRadius = floatPreferencesKey(PreferKey.readMenuLensRadius) val ReadMenuBorderWidth = intPreferencesKey(PreferKey.readMenuBorderWidth) val ReadMenuBorderColor = intPreferencesKey(PreferKey.readMenuBorderColor) diff --git a/app/src/main/java/io/legado/app/domain/usecase/ChangeSourceSearchUseCase.kt b/app/src/main/java/io/legado/app/domain/usecase/ChangeSourceSearchUseCase.kt index 48c94ce31..cc5dd155d 100644 --- a/app/src/main/java/io/legado/app/domain/usecase/ChangeSourceSearchUseCase.kt +++ b/app/src/main/java/io/legado/app/domain/usecase/ChangeSourceSearchUseCase.kt @@ -25,12 +25,13 @@ import kotlinx.coroutines.flow.asFlow import kotlinx.coroutines.flow.flatMapMerge import kotlinx.coroutines.flow.flow import kotlinx.coroutines.flow.flowOn +import kotlinx.coroutines.flow.mapNotNull import kotlinx.coroutines.withTimeout import java.util.concurrent.ConcurrentHashMap import java.util.concurrent.atomic.AtomicInteger sealed interface ChangeSourceSearchEvent { - data object Started : ChangeSourceSearchEvent + data class Started(val totalSources: Int) : ChangeSourceSearchEvent data class Progress( val processedSources: Int, val totalSources: Int, @@ -69,23 +70,20 @@ class ChangeSourceSearchUseCase( if (bookSourceParts.isEmpty()) { throw io.legado.app.exception.NoStackTraceException("启用书源为空") } - val sources = bookSourceParts.mapNotNull { it.getBookSource() } - if (sources.isEmpty()) { - throw io.legado.app.exception.NoStackTraceException("启用书源为空") - } tocMap.clear() bookMap.clear() tocMapChapterCount.set(0) - emit(ChangeSourceSearchEvent.Started) + val totalSources = bookSourceParts.size + emit(ChangeSourceSearchEvent.Started(totalSources)) var processedSources = 0 var resultCount = 0 - val totalSources = sources.size val concurrency = threadCount.coerceAtLeast(1) - sources.asFlow() + bookSourceParts.asFlow() + .mapNotNull { it.getBookSource() } .flatMapMerge(concurrency) { source -> flow { val books = try { @@ -231,7 +229,7 @@ class ChangeSourceSearchUseCase( contentProcessor ) } - return null + return book.toSearchBook() } private suspend fun loadBookWordCount( diff --git a/app/src/main/java/io/legado/app/help/config/ReadBookConfig.kt b/app/src/main/java/io/legado/app/help/config/ReadBookConfig.kt index 1f760048b..7307d22a8 100644 --- a/app/src/main/java/io/legado/app/help/config/ReadBookConfig.kt +++ b/app/src/main/java/io/legado/app/help/config/ReadBookConfig.kt @@ -236,6 +236,8 @@ object ReadBookConfig { var readMenuBottomBarBlurStyle by clampedPrefDelegate(PreferKey.readMenuBottomBarBlurStyle, ReadMenuBlurStyle.Solid, 0..1) var readMenuBlurRadius by clampedPrefDelegate(PreferKey.readMenuBlurRadius, 24, 0..32) var readMenuBlurAlpha by clampedPrefDelegate(PreferKey.readMenuBlurAlpha, 60, 0..100) + var readMenuBlurColor by prefDelegate(PreferKey.readMenuBlurColor, 0) + var readMenuPaletteStyle: String = "" var readMenuLensRadius by clampedPrefDelegate(PreferKey.readMenuLensRadius, 24f, 0f..48f) var readMenuBorderWidth by clampedPrefDelegate(PreferKey.readMenuBorderWidth, 0, 0..4) var titleBarIconPosition by clampedPrefDelegate(PreferKey.titleBarIconPosition, 0, 0..3) diff --git a/app/src/main/java/io/legado/app/ui/book/changesource/ChangeBookSourceComposeViewModel.kt b/app/src/main/java/io/legado/app/ui/book/changesource/ChangeBookSourceComposeViewModel.kt index 9a29f0569..b67762e1c 100644 --- a/app/src/main/java/io/legado/app/ui/book/changesource/ChangeBookSourceComposeViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/book/changesource/ChangeBookSourceComposeViewModel.kt @@ -70,8 +70,11 @@ class ChangeBookSourceComposeViewModel( val loadWordCount: Boolean get() = ChangeSourceConfig.loadWordCount // Internal state + private val chapterNumRegex = "^\\[(\\d+)]".toRegex() private var searchJob: Job? = null private var oldBook: Book? = null + private var bookName: String = "" + private var bookAuthor: String = "" private var fromReadBookActivity: Boolean = false private var screenKey: String = "" private val searchResults = mutableListOf() @@ -86,15 +89,42 @@ class ChangeBookSourceComposeViewModel( fun initData(name: String, author: String, book: Book, fromReadBookActivity: Boolean) { this.oldBook = book + this.bookName = name + this.bookAuthor = author this.fromReadBookActivity = fromReadBookActivity if (searchJob?.isActive != true) { - startSearch() + viewModelScope.launch { + val dbBooks = getDbSearchBooks() + if (dbBooks.isNotEmpty()) { + searchResults.clear() + searchResults.addAll(dbBooks) + searchResults.forEach { bookMap[it.primaryStr()] = it } + filterResults() + } else { + startSearch() + } + } + } + } + + private fun getDbSearchBooks(): List { + val scopeRaw = ChangeSourceConfig.searchScope + return if (screenKey.isEmpty()) { + io.legado.app.data.appDb.searchBookDao.changeSourceByGroup( + bookName, bookAuthor, scopeRaw + ) + } else { + io.legado.app.data.appDb.searchBookDao.changeSourceSearch( + bookName, bookAuthor, screenKey, scopeRaw + ) } } fun startSearch() { val book = oldBook ?: return stopSearch() + // 清除 DB 中的旧记录 + io.legado.app.data.appDb.searchBookDao.clear(bookName, bookAuthor) searchResults.clear() bookMap.clear() tocMap.clear() @@ -113,6 +143,7 @@ class ChangeBookSourceComposeViewModel( when (event) { is ChangeSourceSearchEvent.Started -> { _isSearching.value = true + totalSourceCount = event.totalSources } is ChangeSourceSearchEvent.Progress -> { @@ -123,6 +154,8 @@ class ChangeBookSourceComposeViewModel( is ChangeSourceSearchEvent.Result -> { searchResults.add(event.searchBook) bookMap[event.searchBook.primaryStr()] = event.searchBook + // 持久化到 DB + io.legado.app.data.appDb.searchBookDao.insert(event.searchBook) filterResults() } @@ -179,12 +212,24 @@ class ChangeBookSourceComposeViewModel( it.name.contains(screenKey) || it.originName.contains(screenKey) } } - val sorted = filtered.sortedWith( + val comparator = if (ChangeSourceConfig.loadWordCount) { + compareByDescending { ObservableSourceConfig.getBookScore(it) } + .thenByDescending { io.legado.app.help.config.SourceConfig.getSourceScore(it.origin) } + .thenByDescending { it.chapterWordCount > 1000 } + .thenByDescending { getChapterNum(it.chapterWordCountText) } + .thenByDescending { it.chapterWordCount } + .thenBy { it.originOrder } + } else { compareByDescending { ObservableSourceConfig.getBookScore(it) } .thenByDescending { io.legado.app.help.config.SourceConfig.getSourceScore(it.origin) } .thenBy { it.originOrder } - ) - _searchDataFlow.value = sorted + } + _searchDataFlow.value = filtered.sortedWith(comparator) + } + + private fun getChapterNum(text: String?): Int { + if (text.isNullOrBlank()) return 0 + return chapterNumRegex.find(text)?.groupValues?.get(1)?.toIntOrNull() ?: 0 } fun getToc( @@ -247,7 +292,14 @@ class ChangeBookSourceComposeViewModel( fun refresh() { searchResults.clear() bookMap.clear() - startSearch() + val dbBooks = getDbSearchBooks() + if (dbBooks.isNotEmpty()) { + searchResults.addAll(dbBooks) + searchResults.forEach { bookMap[it.primaryStr()] = it } + filterResults() + } else { + startSearch() + } } // Source actions @@ -340,6 +392,23 @@ class ChangeBookSourceComposeViewModel( saveScope() } + fun applyScopeSelection(selection: io.legado.app.ui.book.search.ScopeSelection) { + if (selection.isSourceScope) { + if (selection.sources.isEmpty()) { + searchScope.update("") + } else { + searchScope.updateSources(selection.sources) + } + } else { + if (selection.groupNames.isEmpty()) { + searchScope.update("") + } else { + searchScope.update(selection.groupNames) + } + } + saveScope() + } + private fun saveScope() { ChangeSourceConfig.searchScope = searchScope.toString() _scopeUiState.value = ScopeUiState( diff --git a/app/src/main/java/io/legado/app/ui/book/read/ReadBookColorTheme.kt b/app/src/main/java/io/legado/app/ui/book/read/ReadBookColorTheme.kt index 182abe8a7..1f0a57a80 100644 --- a/app/src/main/java/io/legado/app/ui/book/read/ReadBookColorTheme.kt +++ b/app/src/main/java/io/legado/app/ui/book/read/ReadBookColorTheme.kt @@ -46,12 +46,14 @@ private fun rememberReadBookColorTheme( preferences: ReadPreferences, ): ThemeOverrideState? { val isAppDark = LegadoTheme.isDark + val paletteStyle = preferences.readMenuPaletteStyle return when (preferences.readBarStyle) { - 1 -> rememberReadBackgroundTheme(styleConfig, isAppDark) + 1 -> rememberReadBackgroundTheme(styleConfig, isAppDark, paletteStyle) 2 -> rememberCustomReadMenuTheme( styleConfig = styleConfig, preferences = preferences, isAppDark = isAppDark, + paletteStyle = paletteStyle, ) else -> null } @@ -61,6 +63,7 @@ private fun rememberReadBookColorTheme( private fun rememberReadBackgroundTheme( styleConfig: ReadBookStyleConfig, isAppDark: Boolean, + paletteStyle: String, ): ThemeOverrideState? { val background = remember(styleConfig, isAppDark) { runCatching { ReadStyleResolver.currentBackground(ReadBookConfig.durConfig) }.getOrNull() @@ -85,6 +88,7 @@ private fun rememberReadBackgroundTheme( backgroundColor = surfaceColor, containerColor = null, fallbackDark = isAppDark, + paletteStyle = paletteStyle, ) } @@ -93,6 +97,7 @@ private fun rememberCustomReadMenuTheme( styleConfig: ReadBookStyleConfig, preferences: ReadPreferences, isAppDark: Boolean, + paletteStyle: String, ): ThemeOverrideState { val menuBackgroundColor = remember( styleConfig, @@ -127,6 +132,7 @@ private fun rememberCustomReadMenuTheme( menuBackgroundColor = menuBackgroundColor, menuContainerColor = menuContainerColor, isDark = isAppDark, + paletteStyle = paletteStyle, ) } @@ -136,11 +142,13 @@ private fun rememberCustomReadMenuTheme( containerColor = null, fallbackDark = isAppDark, deriveDarkFromColor = false, + paletteStyle = paletteStyle, ) ?: buildReadThemeOverride( seedColor = accentColor, backgroundColor = null, containerColor = null, isDark = isAppDark, + paletteStyle = paletteStyle, ) } @@ -150,13 +158,15 @@ private fun rememberCustomReadMenuThemeOverride( menuBackgroundColor: Color, menuContainerColor: Color, isDark: Boolean, + paletteStyle: String, ): ThemeOverrideState { - return remember(accentColor, menuBackgroundColor, menuContainerColor, isDark) { + return remember(accentColor, menuBackgroundColor, menuContainerColor, isDark, paletteStyle) { buildReadThemeOverride( seedColor = accentColor, backgroundColor = null, containerColor = null, isDark = isDark, + paletteStyle = paletteStyle, ).let { base -> base.copy( colorScheme = base.colorScheme.withCustomReadMenuColors( @@ -176,6 +186,7 @@ private fun rememberReadThemeOverride( containerColor: Color?, fallbackDark: Boolean = LegadoTheme.isDark, deriveDarkFromColor: Boolean = true, + paletteStyle: String = "", ): ThemeOverrideState? { val isDark = remember(backgroundColor, containerColor, fallbackDark, deriveDarkFromColor) { if (deriveDarkFromColor) { @@ -184,12 +195,13 @@ private fun rememberReadThemeOverride( fallbackDark } } - return remember(seedColor, backgroundColor, containerColor, isDark) { + return remember(seedColor, backgroundColor, containerColor, isDark, paletteStyle) { buildReadThemeOverride( seedColor = seedColor, backgroundColor = backgroundColor, containerColor = containerColor, isDark = isDark, + paletteStyle = paletteStyle, ) } } @@ -199,12 +211,17 @@ private fun buildReadThemeOverride( backgroundColor: Color?, containerColor: Color?, isDark: Boolean, + paletteStyle: String = "", ): ThemeOverrideState { val colorSpec = ThemeResolver.resolveColorSpecFromMaterialVersion(ThemeConfig.materialVersion) + val resolvedPaletteStyle = paletteStyle + .takeIf { it.isNotBlank() } + ?.let { ThemeResolver.resolvePaletteStyle(it) } + ?: ThemeResolver.resolvePaletteStyle(ThemeConfig.paletteStyle) val base = buildThemeOverrideState( seedColor = seedColor, isDark = isDark, - paletteStyle = ThemeResolver.resolvePaletteStyle(ThemeConfig.paletteStyle), + paletteStyle = resolvedPaletteStyle, colorSpec = colorSpec, usePureBlack = false, ) diff --git a/app/src/main/java/io/legado/app/ui/book/read/ReadBookContract.kt b/app/src/main/java/io/legado/app/ui/book/read/ReadBookContract.kt index 9bdadd3e5..1da24e8f4 100644 --- a/app/src/main/java/io/legado/app/ui/book/read/ReadBookContract.kt +++ b/app/src/main/java/io/legado/app/ui/book/read/ReadBookContract.kt @@ -182,6 +182,8 @@ data class ReadMenuConfig( val readMenuBorderColor: Int = 0, val readMenuBorderColorNight: Int = 0, val readMenuBlurAlpha: Int = 60, + val readMenuBlurColor: Int = 0, + val readMenuPaletteStyle: String = "", val readMenuBlurRadius: Int = 24, val readMenuLensRadius: Float = 24f, val readMenuTopBarBlurMode: Int = ReadMenuBlurMode.None, @@ -482,6 +484,8 @@ sealed interface ReadBookIntent { data object OpenSystemTtsSettings : ReadBookIntent data object ClearTtsCache : ReadBookIntent data class SelectFont(val path: String) : ReadBookIntent + data class SelectTitleFont(val path: String) : ReadBookIntent + data class SelectTitleSystemTypeface(val index: Int) : ReadBookIntent data class SelectSystemTypeface(val index: Int) : ReadBookIntent data class ColorSelected(val dialogId: Int, val color: Int) : ReadBookIntent @@ -653,6 +657,7 @@ sealed interface ReadBookSheet { data object ShadowSet : ReadBookSheet data object UnderlineConfig : ReadBookSheet data object FontSelect : ReadBookSheet + data object TitleFontSelect : ReadBookSheet data object HighlightRuleConfig : ReadBookSheet data object MoreConfig : ReadBookSheet data object BgTextConfig : ReadBookSheet @@ -769,6 +774,18 @@ sealed interface ConfigUpdate { data class TitleColor(val color: Int) : ConfigUpdate { override val actions = setOf(ConfigUpdateAction.UpdateStyle, ConfigUpdateAction.ReloadContent, ConfigUpdateAction.InvalidateTextPage) } + data class TitleFont(val path: String) : ConfigUpdate { + override val actions = setOf(ConfigUpdateAction.UpdateChapterStyle, ConfigUpdateAction.ReloadContent) + } + data class TitleSegType(val value: Int) : ConfigUpdate { + override val actions = setOf(ConfigUpdateAction.UpdateChapterStyle, ConfigUpdateAction.ReloadContent) + } + data class TitleSegDistance(val value: Int) : ConfigUpdate { + override val actions = setOf(ConfigUpdateAction.UpdateChapterStyle, ConfigUpdateAction.ReloadContent) + } + data class TitleSegFlag(val value: String) : ConfigUpdate { + override val actions = setOf(ConfigUpdateAction.UpdateChapterStyle, ConfigUpdateAction.ReloadContent) + } // --- Header / footer tips --- data class HeaderMode(val value: Int) : ConfigUpdate { @@ -1023,6 +1040,12 @@ sealed interface ConfigUpdate { data class MenuBlurAlpha(val value: Int) : ConfigUpdate { override val actions = emptySet() } + data class MenuBlurColor(val color: Int) : ConfigUpdate { + override val actions = emptySet() + } + data class MenuPaletteStyle(val value: String) : ConfigUpdate { + override val actions = emptySet() + } data class MenuLensRadius(val value: Float) : ConfigUpdate { override val actions = emptySet() } diff --git a/app/src/main/java/io/legado/app/ui/book/read/ReadBookMenuBar.kt b/app/src/main/java/io/legado/app/ui/book/read/ReadBookMenuBar.kt index b714fd08e..c9fb983c7 100644 --- a/app/src/main/java/io/legado/app/ui/book/read/ReadBookMenuBar.kt +++ b/app/src/main/java/io/legado/app/ui/book/read/ReadBookMenuBar.kt @@ -195,7 +195,7 @@ fun ReadBookMenuBar( } } val hideTopBar = dialogLikeRoute || - currentRoute == ReadBookMenuRoute.ReadStyle && readStylePage >= 1 + currentRoute == ReadBookMenuRoute.TextTitle val menuColors = readMenuColors() Box(Modifier.fillMaxSize()) { @@ -683,6 +683,9 @@ private fun ReadBookMenuSurface( onOpenFontSelect = { onIntent(ReadBookIntent.ShowSheet(ReadBookSheet.FontSelect)) }, + onOpenTitleFontSelect = { + onIntent(ReadBookIntent.ShowSheet(ReadBookSheet.TitleFontSelect)) + }, modifier = Modifier.padding(horizontal = 16.dp), onIntent = onIntent, ) @@ -902,55 +905,61 @@ private fun MenuTitleBar( ) ) { val useTitleCapsule = readMenuTopBarTitleCapsuleEnabled(backdrop, state.menuConfig) + && progressiveBlurActive + val capsuleIconColor = LegadoTheme.colorScheme.onSurfaceVariant - // Title row: back + title + actions + overflow + // Title row: left group (back + capsule/title) + right group (actions) Row( modifier = Modifier .fillMaxWidth() .padding(horizontal = 16.dp, vertical = 4.dp), verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.spacedBy(16.dp), ) { - // Back button - MenuTitleGlassButton( - onClick = { onIntent(ReadBookIntent.CloseReadBook) }, - icon = Icons.AutoMirrored.Filled.ArrowBack, - contentDescription = "Back", - state = state, - colors = colors, - backdrop = backdrop, - ) - - if (useTitleCapsule) { - // Title capsule layout: title + chapter in a glass pill - TitleCapsuleGlassLayout( + // Left group: back + capsule/title — fills remaining space + Row( + modifier = Modifier.weight(1f), + verticalAlignment = Alignment.CenterVertically, + ) { + MenuTitleGlassButton( + onClick = { onIntent(ReadBookIntent.CloseReadBook) }, + icon = Icons.AutoMirrored.Filled.ArrowBack, + contentDescription = "Back", state = state, colors = colors, - onIntent = onIntent, backdrop = backdrop, - titleTextColor = titleTextColor, ) - } else if (titleBarMode != "1" && titleBarMode != "3") { - AppText( - text = state.bookName, - modifier = Modifier - .weight(1f) - .clickable { onIntent(ReadBookIntent.OpenBookInfo) } - .padding(horizontal = 8.dp, vertical = 4.dp), - style = LegadoTheme.typography.titleMedium.copy( - shadow = androidx.compose.ui.graphics.Shadow( - color = Color.Black.copy(alpha = 0.12f), - offset = Offset.Zero, - blurRadius = 12f - ) - ), - color = titleTextColor, - maxLines = 2, - overflow = TextOverflow.Ellipsis, - ) - } else { - Spacer(Modifier.weight(1f)) + + if (useTitleCapsule) { + TitleCapsuleGlassLayout( + state = state, + colors = colors, + onIntent = onIntent, + backdrop = backdrop, + titleTextColor = capsuleIconColor, + ) + } else if (titleBarMode != "1" && titleBarMode != "3") { + AppText( + text = state.bookName, + modifier = Modifier + .weight(1f) + .clickable { onIntent(ReadBookIntent.OpenBookInfo) } + .padding(horizontal = 8.dp, vertical = 4.dp), + style = LegadoTheme.typography.titleMedium.copy( + shadow = androidx.compose.ui.graphics.Shadow( + color = Color.Black.copy(alpha = 0.12f), + offset = Offset.Zero, + blurRadius = 12f + ) + ), + color = titleTextColor, + maxLines = 2, + overflow = TextOverflow.Ellipsis, + ) + } } + // Right group: actions if (readMenuTopBarButtonLiquidGlassEnabled(backdrop, state.menuConfig)) { MenuTitleBarMergedGlassButton( state = state, @@ -963,7 +972,6 @@ private fun MenuTitleBar( horizontalArrangement = Arrangement.spacedBy(6.dp), verticalAlignment = Alignment.CenterVertically, ) { - // Source action button (non-local books only) if (!state.isLocalBook) { SourceActionButton( state = state, @@ -1252,7 +1260,7 @@ private fun RowScope.TitleCapsuleGlassLayout( Row( modifier = Modifier .weight(1f) - .padding(horizontal = 8.dp) + .padding(start = 12.dp) .height(40.dp) .readMenuLiquidGlass( backdrop = backdrop, @@ -1320,24 +1328,20 @@ private fun MenuTitleBarMergedGlassButton( val tint = LegadoTheme.colorScheme.onSurfaceVariant Box { - Box( - contentAlignment = Alignment.Center, - modifier = Modifier.size(48.dp), - ) { - Row( - modifier = Modifier - .height(40.dp) - .readMenuLiquidGlass( - backdrop = backdrop, - colors = colors, - shape = pillShape, - useTopBarStyle = true, - useLens = true, - blurRadius = 32.dp, - interactive = true, - menuConfig = state.menuConfig, - ) - .padding(horizontal = 4.dp), + Row( + modifier = Modifier + .height(40.dp) + .readMenuLiquidGlass( + backdrop = backdrop, + colors = colors, + shape = pillShape, + useTopBarStyle = true, + useLens = true, + blurRadius = 32.dp, + interactive = true, + menuConfig = state.menuConfig, + ) + .padding(horizontal = 4.dp), verticalAlignment = Alignment.CenterVertically, ) { // SwapHoriz - change source @@ -1418,7 +1422,6 @@ private fun MenuTitleBarMergedGlassButton( ) } } - } // Dropdown menus if (!state.isLocalBook) { @@ -2827,8 +2830,9 @@ private fun Modifier.readMenuHazeEffect( progressiveBottomToTop: Boolean = false, ): Modifier { val surfaceAlpha = menuConfig.readMenuBlurAlpha.coerceIn(0, 100) / 100f + val blurTintColor = menuConfig.readMenuBlurColor.takeIf { it != 0 }?.let { Color(it) } val hazeContainerColor = if (progressive) { - Color.Black.copy(alpha = surfaceAlpha) + (blurTintColor ?: Color.Black).copy(alpha = surfaceAlpha) } else { colors.background.copy(alpha = surfaceAlpha) } diff --git a/app/src/main/java/io/legado/app/ui/book/read/ReadBookScreen.kt b/app/src/main/java/io/legado/app/ui/book/read/ReadBookScreen.kt index 79730986f..3658b0d6a 100644 --- a/app/src/main/java/io/legado/app/ui/book/read/ReadBookScreen.kt +++ b/app/src/main/java/io/legado/app/ui/book/read/ReadBookScreen.kt @@ -174,6 +174,17 @@ fun ReadBookScreen( onOpenFolderPicker = { onIntent(ReadBookIntent.OpenFontFolderPicker) }, systemTypefaces = fontSelectSystemTypefaces, ) + FontSelectSheet( + show = state.activeSheet is ReadBookSheet.TitleFontSelect, + title = stringResource(R.string.read_config_title_settings), + fontFolderUri = fontSelectFolderUri, + selectedFontPath = ReadBookConfig.titleFont, + onDismissRequest = dismissSheet, + onSelectFont = { onIntent(ReadBookIntent.SelectTitleFont(it.uri.toString())) }, + onSelectSystemTypeface = { onIntent(ReadBookIntent.SelectTitleSystemTypeface(it)) }, + onOpenFolderPicker = { onIntent(ReadBookIntent.OpenFontFolderPicker) }, + systemTypefaces = fontSelectSystemTypefaces, + ) ToolButtonConfigSheet( show = state.activeSheet is ReadBookSheet.ToolButtonConfig, items = state.menuConfig.bottomBarButtons, diff --git a/app/src/main/java/io/legado/app/ui/book/read/ReadBookViewModel.kt b/app/src/main/java/io/legado/app/ui/book/read/ReadBookViewModel.kt index cbe67333a..aedec5ef6 100644 --- a/app/src/main/java/io/legado/app/ui/book/read/ReadBookViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/book/read/ReadBookViewModel.kt @@ -896,6 +896,14 @@ class ReadBookViewModel( } is ReadBookIntent.SelectFont -> selectFont(intent.path) + is ReadBookIntent.SelectTitleFont -> selectTitleFont(intent.path) + is ReadBookIntent.SelectTitleSystemTypeface -> { + ReadConfig.systemTypefaces = intent.index + ReadBookConfig.titleFont = "" + _effects.tryEmit(ReadBookEffect.UpdateReadViewConfig( + setOf(ConfigUpdateAction.UpdateStyle, ConfigUpdateAction.ReloadContent) + )) + } is ReadBookIntent.SelectSystemTypeface -> { ReadConfig.systemTypefaces = intent.index ReadBookConfig.textFont = "" @@ -1448,6 +1456,7 @@ class ReadBookViewModel( val old = previous previous = preferences ReadConfig.syncReadPreferences(preferences) + ReadBookConfig.readMenuPaletteStyle = preferences.readMenuPaletteStyle _readPreferences.value = preferences if (!preferences.hasMenuClickArea()) { ReadConfig.detectClickArea() @@ -1599,6 +1608,8 @@ class ReadBookViewModel( readMenuBorderColor = ReadBookConfig.readMenuBorderColor, readMenuBorderColorNight = ReadBookConfig.readMenuBorderColorNight, readMenuBlurAlpha = ReadBookConfig.readMenuBlurAlpha, + readMenuBlurColor = ReadBookConfig.readMenuBlurColor, + readMenuPaletteStyle = ReadBookConfig.readMenuPaletteStyle, readMenuBlurRadius = ReadBookConfig.readMenuBlurRadius, readMenuLensRadius = ReadBookConfig.readMenuLensRadius, readMenuTopBarBlurMode = ReadBookConfig.readMenuTopBarBlurMode, @@ -2507,6 +2518,10 @@ class ReadBookViewModel( is ConfigUpdate.TitleTopSpacing -> ReadBookConfig.titleTopSpacing = update.value is ConfigUpdate.TitleBottomSpacing -> ReadBookConfig.titleBottomSpacing = update.value is ConfigUpdate.TitleColor -> ReadBookConfig.titleColor = update.color + is ConfigUpdate.TitleFont -> ReadBookConfig.titleFont = update.path + is ConfigUpdate.TitleSegType -> ReadBookConfig.titleSegType = update.value + is ConfigUpdate.TitleSegDistance -> ReadBookConfig.titleSegDistance = update.value + is ConfigUpdate.TitleSegFlag -> ReadBookConfig.titleSegFlag = update.value // --- Header / footer tips --- is ConfigUpdate.HeaderMode -> ReadBookConfig.headerMode = update.value @@ -2829,6 +2844,20 @@ class ReadBookViewModel( } _uiState.update { it.copy(menuConfig = it.menuConfig.copy(readMenuBlurAlpha = update.value)) } } + is ConfigUpdate.MenuBlurColor -> { + ReadBookConfig.readMenuBlurColor = update.color + viewModelScope.launch { + readSettingsRepository.setReadMenuBlurColor(update.color) + } + _uiState.update { it.copy(menuConfig = it.menuConfig.copy(readMenuBlurColor = update.color)) } + } + is ConfigUpdate.MenuPaletteStyle -> { + ReadBookConfig.readMenuPaletteStyle = update.value + viewModelScope.launch { + readSettingsRepository.setReadMenuPaletteStyle(update.value) + } + _uiState.update { it.copy(menuConfig = it.menuConfig.copy(readMenuPaletteStyle = update.value)) } + } is ConfigUpdate.MenuLensRadius -> { ReadBookConfig.readMenuLensRadius = update.value viewModelScope.launch { @@ -3207,6 +3236,13 @@ class ReadBookViewModel( )) } + private fun selectTitleFont(path: String) { + ReadBookConfig.titleFont = path + _effects.tryEmit(ReadBookEffect.UpdateReadViewConfig( + setOf(ConfigUpdateAction.UpdateChapterStyle, ConfigUpdateAction.ReloadContent, ConfigUpdateAction.UpdateStyle) + )) + } + private fun toggleDayNight() { val nextMode = if (ReadConfig.isNightTheme) "1" else "2" ThemeConfig.themeMode = nextMode diff --git a/app/src/main/java/io/legado/app/ui/book/read/sheet/SystemMenuPage.kt b/app/src/main/java/io/legado/app/ui/book/read/sheet/SystemMenuPage.kt index 1ea982678..080c231a1 100644 --- a/app/src/main/java/io/legado/app/ui/book/read/sheet/SystemMenuPage.kt +++ b/app/src/main/java/io/legado/app/ui/book/read/sheet/SystemMenuPage.kt @@ -26,7 +26,11 @@ import androidx.compose.material.icons.filled.Settings import androidx.compose.material.icons.filled.SkipNext import androidx.compose.material.icons.filled.SkipPrevious import androidx.compose.material.icons.filled.Translate +import androidx.compose.foundation.background +import androidx.compose.foundation.border import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.shape.CircleShape import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.derivedStateOf @@ -40,13 +44,16 @@ import androidx.compose.runtime.setValue import androidx.compose.runtime.snapshotFlow import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip import androidx.compose.ui.draw.clipToBounds +import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.layout.onSizeChanged import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.stringArrayResource import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp import androidx.lifecycle.compose.collectAsStateWithLifecycle @@ -60,9 +67,11 @@ import io.legado.app.ui.book.read.ConfigUpdate import io.legado.app.ui.book.read.ReadBookButtonConfigItem import io.legado.app.ui.book.read.ReadBookIntent import io.legado.app.ui.book.read.ReadBookSheet +import io.legado.app.ui.theme.LegadoTheme import io.legado.app.ui.widget.components.SectionTitle import io.legado.app.ui.widget.components.dialog.ColorPickerSheet import io.legado.app.ui.widget.components.settingItem.TinyClearColorModeSettingItem +import io.legado.app.ui.widget.components.text.AppText import io.legado.app.ui.widget.components.settingItem.TinyClickableSettingItem import io.legado.app.ui.widget.components.settingItem.TinyColorModeSettingItem import io.legado.app.ui.widget.components.settingItem.TinyDropdownSettingItem @@ -82,6 +91,7 @@ private const val COLOR_MENU_ACCENT_NIGHT = 9 private const val COLOR_MENU_CONTAINER_NIGHT = 10 private const val COLOR_BORDER = 11 private const val COLOR_BORDER_NIGHT = 12 +private const val COLOR_BLUR_TINT = 13 @Composable internal fun SystemMenuPage( @@ -196,6 +206,7 @@ internal fun SystemMenuPage( COLOR_MENU_CONTAINER_NIGHT -> onIntent(ReadBookIntent.UpdateConfig(ConfigUpdate.MenuContainerColorNight(color))) COLOR_BORDER -> onIntent(ReadBookIntent.UpdateConfig(ConfigUpdate.BorderColor(color))) COLOR_BORDER_NIGHT -> onIntent(ReadBookIntent.UpdateConfig(ConfigUpdate.BorderColorNight(color))) + COLOR_BLUR_TINT -> onIntent(ReadBookIntent.UpdateConfig(ConfigUpdate.MenuBlurColor(color))) } showColorPicker = false }, @@ -264,6 +275,23 @@ private fun GlobalMenuTab( }, ) + val showPaletteStyle = bottomMode == 1 || (bottomMode == 2 && colorMode == 0) + AnimatedVisibility(visible = showPaletteStyle) { + val paletteEntries = stringArrayResource(R.array.paletteStyle) + val paletteValues = stringArrayResource(R.array.paletteStyle_value) + val allEntries = arrayOf(stringResource(R.string.flow_sys)) + paletteEntries + val allValues = arrayOf("") + paletteValues + TinyDropdownSettingItem( + title = stringResource(R.string.palette_style), + selectedValue = preferences.readMenuPaletteStyle, + displayEntries = allEntries, + entryValues = allValues, + onValueChange = { + onIntent(ReadBookIntent.UpdateConfig(ConfigUpdate.MenuPaletteStyle(it))) + }, + ) + } + AnimatedVisibility(visible = bottomMode == 2) { Column { TinyDropdownSettingItem( @@ -461,6 +489,18 @@ private fun GlobalMenuTab( onIntent(ReadBookIntent.UpdateConfig(ConfigUpdate.MenuBlurAlpha(it.toInt()))) }, ) + TinyClickableSettingItem( + title = stringResource(R.string.read_menu_blur_color), + onClick = { + onShowColorPicker(COLOR_BLUR_TINT, preferences.readMenuBlurColor) + }, + onLongClick = { + onIntent(ReadBookIntent.UpdateConfig(ConfigUpdate.MenuBlurColor(0))) + }, + trailingContent = { + TinyColorSwatch(color = preferences.readMenuBlurColor) + }, + ) } } @@ -794,3 +834,33 @@ internal fun readMenuButtonInfos(context: Context): List = l ReadMenuButtonInfo("replace_badge", Icons.Default.AutoAwesome, context.getString(R.string.replace_purify_badge)), ReadMenuButtonInfo("translate", Icons.Default.Translate, context.getString(R.string.translate)), ) + +// ========== Color Swatch ========== + +@Composable +private fun TinyColorSwatch( + color: Int, +) { + val swatchColor = if (color != 0) Color(color) else LegadoTheme.colorScheme.onSurfaceVariant + val borderColor = LegadoTheme.colorScheme.outline + Box( + modifier = Modifier + .size(28.dp) + .clip(CircleShape) + .background(swatchColor) + .then( + if (color == 0) Modifier.border(1.5.dp, borderColor, CircleShape) + else Modifier + ), + contentAlignment = Alignment.Center, + ) { + if (color == 0) { + AppText( + text = "A", + style = LegadoTheme.typography.labelSmall, + color = LegadoTheme.colorScheme.surfaceContainerLow, + textAlign = TextAlign.Center, + ) + } + } +} diff --git a/app/src/main/java/io/legado/app/ui/book/read/sheet/TextTitleSheet.kt b/app/src/main/java/io/legado/app/ui/book/read/sheet/TextTitleSheet.kt index 5ca6ceb9a..bb3291c25 100644 --- a/app/src/main/java/io/legado/app/ui/book/read/sheet/TextTitleSheet.kt +++ b/app/src/main/java/io/legado/app/ui/book/read/sheet/TextTitleSheet.kt @@ -60,6 +60,7 @@ fun ReadStyleTextTitleContent( onOpenUnderlineConfig: () -> Unit, onOpenHighlightRule: () -> Unit, onOpenFontSelect: () -> Unit, + onOpenTitleFontSelect: () -> Unit, modifier: Modifier = Modifier, onIntent: (ReadBookIntent) -> Unit, ) { @@ -85,6 +86,7 @@ fun ReadStyleTextTitleContent( onOpenUnderlineConfig = onOpenUnderlineConfig, onOpenHighlightRule = onOpenHighlightRule, onOpenFontSelect = onOpenFontSelect, + onOpenTitleFontSelect = onOpenTitleFontSelect, animateToPage = { page -> scope.launch { pagerState.animateScrollToPage(page) } }, modifier = modifier, onIntent = onIntent, @@ -101,6 +103,7 @@ internal fun ReadStyleTextTitleContent( onOpenUnderlineConfig: () -> Unit, onOpenHighlightRule: () -> Unit, onOpenFontSelect: () -> Unit, + onOpenTitleFontSelect: () -> Unit, animateToPage: (Int) -> Unit, modifier: Modifier = Modifier, onIntent: (ReadBookIntent) -> Unit, @@ -132,7 +135,10 @@ internal fun ReadStyleTextTitleContent( ) 1 -> LayoutSpacingPage(onIntent = onIntent) - 2 -> TitleSettingsPage(onIntent = onIntent) + 2 -> TitleSettingsPage( + onOpenTitleFontSelect = onOpenTitleFontSelect, + onIntent = onIntent, + ) } } } @@ -358,10 +364,14 @@ internal fun TextEffectsPage( @Composable internal fun TitleSettingsPage( + onOpenTitleFontSelect: () -> Unit, onIntent: (ReadBookIntent) -> Unit, ) { var titleMode by remember(ReadBookConfig.titleMode) { mutableIntStateOf(ReadBookConfig.titleMode) } var titleBold by remember(ReadBookConfig.titleBold) { mutableIntStateOf(ReadBookConfig.titleBold) } + var titleSegType by remember(ReadBookConfig.titleSegType) { mutableIntStateOf(ReadBookConfig.titleSegType) } + var titleSegDistance by remember(ReadBookConfig.titleSegDistance) { mutableIntStateOf(ReadBookConfig.titleSegDistance) } + var titleSegFlag by remember(ReadBookConfig.titleSegFlag) { mutableStateOf(ReadBookConfig.titleSegFlag) } var titleSegScaling by remember(ReadBookConfig.titleSegScaling) { mutableFloatStateOf(ReadBookConfig.titleSegScaling) } var titleLineSpacingExtra by remember(ReadBookConfig.titleLineSpacingExtra) { mutableIntStateOf(ReadBookConfig.titleLineSpacingExtra) } var titleLineSpacingSub by remember(ReadBookConfig.titleLineSpacingSub) { mutableIntStateOf(ReadBookConfig.titleLineSpacingSub) } @@ -432,6 +442,85 @@ internal fun TitleSettingsPage( Spacer(Modifier.height(8.dp)) + // Title font + TinyClickableSettingItem( + title = stringResource(R.string.read_config_title_settings), + imageVector = Icons.Default.TextFields, + onClick = onOpenTitleFontSelect, + ) + + Spacer(Modifier.height(8.dp)) + + // Title segmentation + TinyDropdownSettingItem( + title = stringResource(R.string.split_title_mode), + selectedValue = titleSegType.toString(), + displayEntries = arrayOf( + stringResource(R.string.close), + stringResource(R.string.split_title_by_position), + stringResource(R.string.split_title_by_flag), + stringResource(R.string.split_title_by_regex), + ), + entryValues = arrayOf("0", "1", "2", "3"), + onValueChange = { + titleSegType = it.toInt() + onIntent(ReadBookIntent.UpdateConfig(ConfigUpdate.TitleSegType(titleSegType))) + }, + ) + if (titleSegType == 1) { + TinySliderSettingItem( + title = stringResource(R.string.split_title_position), + value = titleSegDistance.toFloat(), + valueRange = 1f..20f, + steps = 18, + onValueChange = { value -> + titleSegDistance = value.toInt() + onIntent(ReadBookIntent.UpdateConfig(ConfigUpdate.TitleSegDistance(titleSegDistance))) + }, + ) + } + if (titleSegType == 2 || titleSegType == 3) { + var showFlagDialog by remember { mutableStateOf(false) } + + TinyClickableSettingItem( + title = stringResource(R.string.rule_segment), + description = titleSegFlag.ifBlank { stringResource(R.string.split_title_mode) }, + onClick = { showFlagDialog = true }, + ) + + if (showFlagDialog) { + var flagText by remember { mutableStateOf(titleSegFlag) } + androidx.compose.material3.AlertDialog( + onDismissRequest = { showFlagDialog = false }, + title = { Text(stringResource(R.string.rule_segment)) }, + text = { + androidx.compose.material3.OutlinedTextField( + value = flagText, + onValueChange = { flagText = it }, + singleLine = false, + modifier = Modifier.fillMaxWidth(), + ) + }, + confirmButton = { + androidx.compose.material3.TextButton(onClick = { + titleSegFlag = flagText + onIntent(ReadBookIntent.UpdateConfig(ConfigUpdate.TitleSegFlag(titleSegFlag))) + showFlagDialog = false + }) { + Text(stringResource(android.R.string.ok)) + } + }, + dismissButton = { + androidx.compose.material3.TextButton(onClick = { showFlagDialog = false }) { + Text(stringResource(android.R.string.cancel)) + } + }, + ) + } + } + + Spacer(Modifier.height(8.dp)) + // Title spacing sliders TinySliderSettingItem( title = stringResource(R.string.subtitle_scale), diff --git a/app/src/main/java/io/legado/app/ui/book/search/ScopeSelectSheet.kt b/app/src/main/java/io/legado/app/ui/book/search/ScopeSelectSheet.kt index 238764e43..2add39b08 100644 --- a/app/src/main/java/io/legado/app/ui/book/search/ScopeSelectSheet.kt +++ b/app/src/main/java/io/legado/app/ui/book/search/ScopeSelectSheet.kt @@ -104,7 +104,7 @@ fun ScopeSelectSheet( applyDraftSelection() onDismissRequest() }, - text = stringResource(R.string.confirm), + icon = AppIcons.Check, ) } }, diff --git a/app/src/main/java/io/legado/app/ui/theme/ThemeColorSchemeOverride.kt b/app/src/main/java/io/legado/app/ui/theme/ThemeColorSchemeOverride.kt index b164d5175..7e9f637fa 100644 --- a/app/src/main/java/io/legado/app/ui/theme/ThemeColorSchemeOverride.kt +++ b/app/src/main/java/io/legado/app/ui/theme/ThemeColorSchemeOverride.kt @@ -92,6 +92,7 @@ fun ColorScheme.toLegadoColorScheme(): LegadoColorScheme { fun ProvideColorSchemeOverride( colorScheme: ColorScheme, seedColor: Color = colorScheme.primary, + overrideIsDark: Boolean? = null, content: @Composable () -> Unit, ) { val themeAnimationSpec = tween( @@ -106,10 +107,12 @@ fun ProvideColorSchemeOverride( label = "theme_seed_animation" ).value val legadoColorScheme = remember(animatedColorScheme) { animatedColorScheme.toLegadoColorScheme() } - val overrideThemeMode = remember(baseThemeMode, animatedColorScheme, animatedSeedColor) { + val resolvedIsDark = overrideIsDark ?: baseThemeMode.isDark + val overrideThemeMode = remember(baseThemeMode, animatedColorScheme, animatedSeedColor, resolvedIsDark) { baseThemeMode.copy( colorScheme = animatedColorScheme, seedColor = animatedSeedColor, + isDark = resolvedIsDark, ) } val materialTypography = MaterialTheme.typography diff --git a/app/src/main/java/io/legado/app/ui/theme/ThemeOverride.kt b/app/src/main/java/io/legado/app/ui/theme/ThemeOverride.kt index fecdec48c..b3260e195 100644 --- a/app/src/main/java/io/legado/app/ui/theme/ThemeOverride.kt +++ b/app/src/main/java/io/legado/app/ui/theme/ThemeOverride.kt @@ -16,6 +16,7 @@ import io.legado.app.ui.config.themeConfig.ThemeConfig data class ThemeOverrideState( val seedColor: Color, val colorScheme: ColorScheme, + val isDark: Boolean = false, ) fun buildThemeOverrideState( @@ -45,7 +46,8 @@ fun buildThemeOverrideState( return ThemeOverrideState( seedColor = seedColor, - colorScheme = colorScheme + colorScheme = colorScheme, + isDark = isDark, ) } @@ -72,6 +74,7 @@ fun ProvideThemeOverride( ProvideColorSchemeOverride( colorScheme = currentTheme.colorScheme, seedColor = currentTheme.seedColor, + overrideIsDark = currentTheme.isDark, content = content ) } else { diff --git a/app/src/main/java/io/legado/app/ui/widget/components/changeSource/ChangeSourceSheet.kt b/app/src/main/java/io/legado/app/ui/widget/components/changeSource/ChangeSourceSheet.kt index 284cec8a6..82ea20c6f 100644 --- a/app/src/main/java/io/legado/app/ui/widget/components/changeSource/ChangeSourceSheet.kt +++ b/app/src/main/java/io/legado/app/ui/widget/components/changeSource/ChangeSourceSheet.kt @@ -438,8 +438,8 @@ fun ChangeSourceSheet( selectedSources = scopeState.sourceUrls, onToggleSource = { viewModel.toggleScopeSource(it) }, isSourceScope = scopeState.isSource, - onConfirm = { - viewModel.startSearch() + onApplyScope = { selection -> + viewModel.applyScopeSelection(selection) showFilterSheet = false } ) diff --git a/app/src/main/java/io/legado/app/ui/widget/components/icon/AppIcons.kt b/app/src/main/java/io/legado/app/ui/widget/components/icon/AppIcons.kt index e5b9b059c..93b704f1a 100644 --- a/app/src/main/java/io/legado/app/ui/widget/components/icon/AppIcons.kt +++ b/app/src/main/java/io/legado/app/ui/widget/components/icon/AppIcons.kt @@ -5,6 +5,7 @@ import androidx.compose.material.icons.automirrored.filled.ArrowBack import androidx.compose.material.icons.automirrored.filled.LibraryBooks import androidx.compose.material.icons.automirrored.outlined.LibraryBooks import androidx.compose.material.icons.filled.BugReport +import androidx.compose.material.icons.filled.Check import androidx.compose.material.icons.filled.Clear import androidx.compose.material.icons.filled.Delete import androidx.compose.material.icons.filled.Edit @@ -111,6 +112,10 @@ object AppIcons { @Composable get() = if (isMiuix) MiuixIcons.MoreCircle else Icons.Default.MoreHoriz + val Check: ImageVector + @Composable + get() = Icons.Default.Check + @Composable fun mainDestination(destination: MainDestination, selected: Boolean): ImageVector { diff --git a/app/src/main/java/io/legado/app/ui/widget/components/menuItem/RoundDropdownMenu.kt b/app/src/main/java/io/legado/app/ui/widget/components/menuItem/RoundDropdownMenu.kt index e6c46ce79..ea4950289 100644 --- a/app/src/main/java/io/legado/app/ui/widget/components/menuItem/RoundDropdownMenu.kt +++ b/app/src/main/java/io/legado/app/ui/widget/components/menuItem/RoundDropdownMenu.kt @@ -65,6 +65,7 @@ fun RoundDropdownMenu( } } else { val colorScheme = rememberOpaqueColorScheme() + val popupContainerColor = LegadoTheme.colorScheme.surfaceContainerLow DropdownMenu( expanded = expanded, @@ -72,7 +73,7 @@ fun RoundDropdownMenu( modifier = modifier, shape = shape, shadowElevation = shadowElevation, - containerColor = colorScheme.surfaceContainerLow + containerColor = popupContainerColor ) { MaterialExpressiveTheme( colorScheme = colorScheme, @@ -129,6 +130,7 @@ fun RoundDropdownMenuLazy( } } else { val colorScheme = rememberOpaqueColorScheme() + val popupContainerColor = LegadoTheme.colorScheme.surfaceContainerLow DropdownMenu( expanded = expanded, @@ -136,7 +138,7 @@ fun RoundDropdownMenuLazy( modifier = modifier, shape = shape, shadowElevation = shadowElevation, - containerColor = colorScheme.surfaceContainerLow + containerColor = popupContainerColor ) { MaterialExpressiveTheme( colorScheme = colorScheme, diff --git a/app/src/main/java/io/legado/app/ui/widget/components/menuItem/RoundDropdownMenuItem.kt b/app/src/main/java/io/legado/app/ui/widget/components/menuItem/RoundDropdownMenuItem.kt index 56741183e..0b4af41d2 100644 --- a/app/src/main/java/io/legado/app/ui/widget/components/menuItem/RoundDropdownMenuItem.kt +++ b/app/src/main/java/io/legado/app/ui/widget/components/menuItem/RoundDropdownMenuItem.kt @@ -35,7 +35,6 @@ import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.dp import io.legado.app.ui.theme.LegadoTheme import io.legado.app.ui.theme.ThemeResolver -import io.legado.app.ui.theme.rememberOpaqueColorScheme import io.legado.app.ui.widget.components.icon.AppIcon import top.yukonga.miuix.kmp.basic.DropdownDefaults import top.yukonga.miuix.kmp.icon.MiuixIcons @@ -121,9 +120,9 @@ fun RoundDropdownMenuItem( } } } else { - val colorScheme = rememberOpaqueColorScheme() - val selectedContentColor = colorScheme.primary - val defaultContentColor = colorScheme.onSurface + val legadoColorScheme = LegadoTheme.colorScheme + val selectedContentColor = legadoColorScheme.primary + val defaultContentColor = legadoColorScheme.onSurface val contentColor = if (enabled) { when { hasCustomContentColor -> color @@ -137,7 +136,7 @@ fun RoundDropdownMenuItem( else -> defaultContentColor.copy(alpha = 0.38f) } } - val containerColor = colorScheme.surface + val containerColor = legadoColorScheme.surface Surface( onClick = onClick, diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml index d31876f37..bbcdea12f 100644 --- a/app/src/main/res/values-zh-rCN/strings.xml +++ b/app/src/main/res/values-zh-rCN/strings.xml @@ -1711,6 +1711,10 @@ 工具栏样式 标题分段 分段模式 + 按位置分段 + 按标记分段 + 正则分段 + 分段位置 次行缩放 次行距离 标题段距 @@ -1903,6 +1907,7 @@ 模糊半径 模糊半径越大,系统运行越卡顿 菜单不透明度 + 模糊着色 边框 宽度 颜色 diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index dd219fe71..de1a7e0f3 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1748,6 +1748,10 @@ Rule Split title Split mode + By position + By flag + By regex + Split position Subtitle margin Subtitle scale Tool bar style @@ -1912,6 +1916,7 @@ Blur radius Higher radius may reduce performance Menu opacity + Blur tint color Border Width Color