fix: 阅读菜单模糊着色、调色板样式、标题胶囊布局及主题覆盖修复
This commit is contained in:
21 files changed
+402
-44
No files matched your search
@@ -308,6 +308,8 @@ object PreferKey {
|
|||||||
const val readMenuBottomBarBlurStyle = "readMenuBottomBarBlurStyle"
|
const val readMenuBottomBarBlurStyle = "readMenuBottomBarBlurStyle"
|
||||||
const val readMenuBlurRadius = "readMenuBlurRadius"
|
const val readMenuBlurRadius = "readMenuBlurRadius"
|
||||||
const val readMenuBlurAlpha = "readMenuBlurAlpha"
|
const val readMenuBlurAlpha = "readMenuBlurAlpha"
|
||||||
|
const val readMenuBlurColor = "readMenuBlurColor"
|
||||||
|
const val readMenuPaletteStyle = "readMenuPaletteStyle"
|
||||||
const val readMenuLensRadius = "readMenuLensRadius"
|
const val readMenuLensRadius = "readMenuLensRadius"
|
||||||
const val readMenuBorderWidth = "readMenuBorderWidth"
|
const val readMenuBorderWidth = "readMenuBorderWidth"
|
||||||
const val readMenuBorderColor = "readMenuBorderColor"
|
const val readMenuBorderColor = "readMenuBorderColor"
|
||||||
|
|||||||
@@ -94,6 +94,8 @@ data class ReadPreferences(
|
|||||||
val readMenuBottomBarBlurStyle: Int = ReadMenuBlurStyle.Solid,
|
val readMenuBottomBarBlurStyle: Int = ReadMenuBlurStyle.Solid,
|
||||||
val readMenuBlurRadius: Int = 24,
|
val readMenuBlurRadius: Int = 24,
|
||||||
val readMenuBlurAlpha: Int = 60,
|
val readMenuBlurAlpha: Int = 60,
|
||||||
|
val readMenuBlurColor: Int = 0,
|
||||||
|
val readMenuPaletteStyle: String = "",
|
||||||
val readMenuLensRadius: Float = 24f,
|
val readMenuLensRadius: Float = 24f,
|
||||||
val readMenuBorderWidth: Int = 0,
|
val readMenuBorderWidth: Int = 0,
|
||||||
val readMenuBorderColor: Int = 0,
|
val readMenuBorderColor: Int = 0,
|
||||||
@@ -335,6 +337,12 @@ class ReadSettingsRepository(
|
|||||||
suspend fun setReadMenuBlurAlpha(value: Int) =
|
suspend fun setReadMenuBlurAlpha(value: Int) =
|
||||||
settingsRepository.putInt(PreferKey.readMenuBlurAlpha, value.coerceIn(0, 100))
|
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) =
|
suspend fun setReadMenuLensRadius(value: Float) =
|
||||||
settingsRepository.putFloat(PreferKey.readMenuLensRadius, value.coerceIn(0f, 48f))
|
settingsRepository.putFloat(PreferKey.readMenuLensRadius, value.coerceIn(0f, 48f))
|
||||||
|
|
||||||
@@ -446,6 +454,7 @@ class ReadSettingsRepository(
|
|||||||
readMenuBottomBarBlurMode = this[Keys.ReadMenuBottomBarBlurMode]
|
readMenuBottomBarBlurMode = this[Keys.ReadMenuBottomBarBlurMode]
|
||||||
?: ReadMenuBlurMode.None,
|
?: ReadMenuBlurMode.None,
|
||||||
readMenuTopBarLiquidGlassButtons = this[Keys.ReadMenuTopBarLiquidGlassButtons] ?: false,
|
readMenuTopBarLiquidGlassButtons = this[Keys.ReadMenuTopBarLiquidGlassButtons] ?: false,
|
||||||
|
readMenuTopBarTitleCapsule = this[Keys.ReadMenuTopBarTitleCapsule] ?: false,
|
||||||
readMenuBottomBarLiquidGlassButtons = this[Keys.ReadMenuBottomBarLiquidGlassButtons]
|
readMenuBottomBarLiquidGlassButtons = this[Keys.ReadMenuBottomBarLiquidGlassButtons]
|
||||||
?: false,
|
?: false,
|
||||||
readMenuTopBarBlurStyle = this[Keys.ReadMenuTopBarBlurStyle]
|
readMenuTopBarBlurStyle = this[Keys.ReadMenuTopBarBlurStyle]
|
||||||
@@ -454,6 +463,8 @@ class ReadSettingsRepository(
|
|||||||
?: ReadMenuBlurStyle.Solid,
|
?: ReadMenuBlurStyle.Solid,
|
||||||
readMenuBlurRadius = this[Keys.ReadMenuBlurRadius] ?: 24,
|
readMenuBlurRadius = this[Keys.ReadMenuBlurRadius] ?: 24,
|
||||||
readMenuBlurAlpha = this[Keys.ReadMenuBlurAlpha] ?: 60,
|
readMenuBlurAlpha = this[Keys.ReadMenuBlurAlpha] ?: 60,
|
||||||
|
readMenuBlurColor = this[Keys.ReadMenuBlurColor] ?: 0,
|
||||||
|
readMenuPaletteStyle = this[Keys.ReadMenuPaletteStyle] ?: "",
|
||||||
readMenuLensRadius = this[Keys.ReadMenuLensRadius] ?: 24f,
|
readMenuLensRadius = this[Keys.ReadMenuLensRadius] ?: 24f,
|
||||||
readMenuBorderWidth = this[Keys.ReadMenuBorderWidth] ?: 0,
|
readMenuBorderWidth = this[Keys.ReadMenuBorderWidth] ?: 0,
|
||||||
readMenuBorderColor = this[Keys.ReadMenuBorderColor] ?: 0,
|
readMenuBorderColor = this[Keys.ReadMenuBorderColor] ?: 0,
|
||||||
@@ -540,12 +551,16 @@ class ReadSettingsRepository(
|
|||||||
val ReadMenuBottomBarBlurMode = intPreferencesKey(PreferKey.readMenuBottomBarBlurMode)
|
val ReadMenuBottomBarBlurMode = intPreferencesKey(PreferKey.readMenuBottomBarBlurMode)
|
||||||
val ReadMenuTopBarLiquidGlassButtons =
|
val ReadMenuTopBarLiquidGlassButtons =
|
||||||
booleanPreferencesKey(PreferKey.readMenuTopBarLiquidGlassButtons)
|
booleanPreferencesKey(PreferKey.readMenuTopBarLiquidGlassButtons)
|
||||||
|
val ReadMenuTopBarTitleCapsule =
|
||||||
|
booleanPreferencesKey(PreferKey.readMenuTopBarTitleCapsule)
|
||||||
val ReadMenuBottomBarLiquidGlassButtons =
|
val ReadMenuBottomBarLiquidGlassButtons =
|
||||||
booleanPreferencesKey(PreferKey.readMenuBottomBarLiquidGlassButtons)
|
booleanPreferencesKey(PreferKey.readMenuBottomBarLiquidGlassButtons)
|
||||||
val ReadMenuTopBarBlurStyle = intPreferencesKey(PreferKey.readMenuTopBarBlurStyle)
|
val ReadMenuTopBarBlurStyle = intPreferencesKey(PreferKey.readMenuTopBarBlurStyle)
|
||||||
val ReadMenuBottomBarBlurStyle = intPreferencesKey(PreferKey.readMenuBottomBarBlurStyle)
|
val ReadMenuBottomBarBlurStyle = intPreferencesKey(PreferKey.readMenuBottomBarBlurStyle)
|
||||||
val ReadMenuBlurRadius = intPreferencesKey(PreferKey.readMenuBlurRadius)
|
val ReadMenuBlurRadius = intPreferencesKey(PreferKey.readMenuBlurRadius)
|
||||||
val ReadMenuBlurAlpha = intPreferencesKey(PreferKey.readMenuBlurAlpha)
|
val ReadMenuBlurAlpha = intPreferencesKey(PreferKey.readMenuBlurAlpha)
|
||||||
|
val ReadMenuBlurColor = intPreferencesKey(PreferKey.readMenuBlurColor)
|
||||||
|
val ReadMenuPaletteStyle = stringPreferencesKey(PreferKey.readMenuPaletteStyle)
|
||||||
val ReadMenuLensRadius = floatPreferencesKey(PreferKey.readMenuLensRadius)
|
val ReadMenuLensRadius = floatPreferencesKey(PreferKey.readMenuLensRadius)
|
||||||
val ReadMenuBorderWidth = intPreferencesKey(PreferKey.readMenuBorderWidth)
|
val ReadMenuBorderWidth = intPreferencesKey(PreferKey.readMenuBorderWidth)
|
||||||
val ReadMenuBorderColor = intPreferencesKey(PreferKey.readMenuBorderColor)
|
val ReadMenuBorderColor = intPreferencesKey(PreferKey.readMenuBorderColor)
|
||||||
|
|||||||
@@ -25,12 +25,13 @@ import kotlinx.coroutines.flow.asFlow
|
|||||||
import kotlinx.coroutines.flow.flatMapMerge
|
import kotlinx.coroutines.flow.flatMapMerge
|
||||||
import kotlinx.coroutines.flow.flow
|
import kotlinx.coroutines.flow.flow
|
||||||
import kotlinx.coroutines.flow.flowOn
|
import kotlinx.coroutines.flow.flowOn
|
||||||
|
import kotlinx.coroutines.flow.mapNotNull
|
||||||
import kotlinx.coroutines.withTimeout
|
import kotlinx.coroutines.withTimeout
|
||||||
import java.util.concurrent.ConcurrentHashMap
|
import java.util.concurrent.ConcurrentHashMap
|
||||||
import java.util.concurrent.atomic.AtomicInteger
|
import java.util.concurrent.atomic.AtomicInteger
|
||||||
|
|
||||||
sealed interface ChangeSourceSearchEvent {
|
sealed interface ChangeSourceSearchEvent {
|
||||||
data object Started : ChangeSourceSearchEvent
|
data class Started(val totalSources: Int) : ChangeSourceSearchEvent
|
||||||
data class Progress(
|
data class Progress(
|
||||||
val processedSources: Int,
|
val processedSources: Int,
|
||||||
val totalSources: Int,
|
val totalSources: Int,
|
||||||
@@ -69,23 +70,20 @@ class ChangeSourceSearchUseCase(
|
|||||||
if (bookSourceParts.isEmpty()) {
|
if (bookSourceParts.isEmpty()) {
|
||||||
throw io.legado.app.exception.NoStackTraceException("启用书源为空")
|
throw io.legado.app.exception.NoStackTraceException("启用书源为空")
|
||||||
}
|
}
|
||||||
val sources = bookSourceParts.mapNotNull { it.getBookSource() }
|
|
||||||
if (sources.isEmpty()) {
|
|
||||||
throw io.legado.app.exception.NoStackTraceException("启用书源为空")
|
|
||||||
}
|
|
||||||
|
|
||||||
tocMap.clear()
|
tocMap.clear()
|
||||||
bookMap.clear()
|
bookMap.clear()
|
||||||
tocMapChapterCount.set(0)
|
tocMapChapterCount.set(0)
|
||||||
|
|
||||||
emit(ChangeSourceSearchEvent.Started)
|
val totalSources = bookSourceParts.size
|
||||||
|
emit(ChangeSourceSearchEvent.Started(totalSources))
|
||||||
|
|
||||||
var processedSources = 0
|
var processedSources = 0
|
||||||
var resultCount = 0
|
var resultCount = 0
|
||||||
val totalSources = sources.size
|
|
||||||
val concurrency = threadCount.coerceAtLeast(1)
|
val concurrency = threadCount.coerceAtLeast(1)
|
||||||
|
|
||||||
sources.asFlow()
|
bookSourceParts.asFlow()
|
||||||
|
.mapNotNull { it.getBookSource() }
|
||||||
.flatMapMerge(concurrency) { source ->
|
.flatMapMerge(concurrency) { source ->
|
||||||
flow {
|
flow {
|
||||||
val books = try {
|
val books = try {
|
||||||
@@ -231,7 +229,7 @@ class ChangeSourceSearchUseCase(
|
|||||||
contentProcessor
|
contentProcessor
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
return null
|
return book.toSearchBook()
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun loadBookWordCount(
|
private suspend fun loadBookWordCount(
|
||||||
|
|||||||
@@ -236,6 +236,8 @@ object ReadBookConfig {
|
|||||||
var readMenuBottomBarBlurStyle by clampedPrefDelegate(PreferKey.readMenuBottomBarBlurStyle, ReadMenuBlurStyle.Solid, 0..1)
|
var readMenuBottomBarBlurStyle by clampedPrefDelegate(PreferKey.readMenuBottomBarBlurStyle, ReadMenuBlurStyle.Solid, 0..1)
|
||||||
var readMenuBlurRadius by clampedPrefDelegate(PreferKey.readMenuBlurRadius, 24, 0..32)
|
var readMenuBlurRadius by clampedPrefDelegate(PreferKey.readMenuBlurRadius, 24, 0..32)
|
||||||
var readMenuBlurAlpha by clampedPrefDelegate(PreferKey.readMenuBlurAlpha, 60, 0..100)
|
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 readMenuLensRadius by clampedPrefDelegate(PreferKey.readMenuLensRadius, 24f, 0f..48f)
|
||||||
var readMenuBorderWidth by clampedPrefDelegate(PreferKey.readMenuBorderWidth, 0, 0..4)
|
var readMenuBorderWidth by clampedPrefDelegate(PreferKey.readMenuBorderWidth, 0, 0..4)
|
||||||
var titleBarIconPosition by clampedPrefDelegate(PreferKey.titleBarIconPosition, 0, 0..3)
|
var titleBarIconPosition by clampedPrefDelegate(PreferKey.titleBarIconPosition, 0, 0..3)
|
||||||
|
|||||||
+72
-3
@@ -70,8 +70,11 @@ class ChangeBookSourceComposeViewModel(
|
|||||||
val loadWordCount: Boolean get() = ChangeSourceConfig.loadWordCount
|
val loadWordCount: Boolean get() = ChangeSourceConfig.loadWordCount
|
||||||
|
|
||||||
// Internal state
|
// Internal state
|
||||||
|
private val chapterNumRegex = "^\\[(\\d+)]".toRegex()
|
||||||
private var searchJob: Job? = null
|
private var searchJob: Job? = null
|
||||||
private var oldBook: Book? = null
|
private var oldBook: Book? = null
|
||||||
|
private var bookName: String = ""
|
||||||
|
private var bookAuthor: String = ""
|
||||||
private var fromReadBookActivity: Boolean = false
|
private var fromReadBookActivity: Boolean = false
|
||||||
private var screenKey: String = ""
|
private var screenKey: String = ""
|
||||||
private val searchResults = mutableListOf<SearchBook>()
|
private val searchResults = mutableListOf<SearchBook>()
|
||||||
@@ -86,15 +89,42 @@ class ChangeBookSourceComposeViewModel(
|
|||||||
|
|
||||||
fun initData(name: String, author: String, book: Book, fromReadBookActivity: Boolean) {
|
fun initData(name: String, author: String, book: Book, fromReadBookActivity: Boolean) {
|
||||||
this.oldBook = book
|
this.oldBook = book
|
||||||
|
this.bookName = name
|
||||||
|
this.bookAuthor = author
|
||||||
this.fromReadBookActivity = fromReadBookActivity
|
this.fromReadBookActivity = fromReadBookActivity
|
||||||
if (searchJob?.isActive != true) {
|
if (searchJob?.isActive != true) {
|
||||||
|
viewModelScope.launch {
|
||||||
|
val dbBooks = getDbSearchBooks()
|
||||||
|
if (dbBooks.isNotEmpty()) {
|
||||||
|
searchResults.clear()
|
||||||
|
searchResults.addAll(dbBooks)
|
||||||
|
searchResults.forEach { bookMap[it.primaryStr()] = it }
|
||||||
|
filterResults()
|
||||||
|
} else {
|
||||||
startSearch()
|
startSearch()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getDbSearchBooks(): List<SearchBook> {
|
||||||
|
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() {
|
fun startSearch() {
|
||||||
val book = oldBook ?: return
|
val book = oldBook ?: return
|
||||||
stopSearch()
|
stopSearch()
|
||||||
|
// 清除 DB 中的旧记录
|
||||||
|
io.legado.app.data.appDb.searchBookDao.clear(bookName, bookAuthor)
|
||||||
searchResults.clear()
|
searchResults.clear()
|
||||||
bookMap.clear()
|
bookMap.clear()
|
||||||
tocMap.clear()
|
tocMap.clear()
|
||||||
@@ -113,6 +143,7 @@ class ChangeBookSourceComposeViewModel(
|
|||||||
when (event) {
|
when (event) {
|
||||||
is ChangeSourceSearchEvent.Started -> {
|
is ChangeSourceSearchEvent.Started -> {
|
||||||
_isSearching.value = true
|
_isSearching.value = true
|
||||||
|
totalSourceCount = event.totalSources
|
||||||
}
|
}
|
||||||
|
|
||||||
is ChangeSourceSearchEvent.Progress -> {
|
is ChangeSourceSearchEvent.Progress -> {
|
||||||
@@ -123,6 +154,8 @@ class ChangeBookSourceComposeViewModel(
|
|||||||
is ChangeSourceSearchEvent.Result -> {
|
is ChangeSourceSearchEvent.Result -> {
|
||||||
searchResults.add(event.searchBook)
|
searchResults.add(event.searchBook)
|
||||||
bookMap[event.searchBook.primaryStr()] = event.searchBook
|
bookMap[event.searchBook.primaryStr()] = event.searchBook
|
||||||
|
// 持久化到 DB
|
||||||
|
io.legado.app.data.appDb.searchBookDao.insert(event.searchBook)
|
||||||
filterResults()
|
filterResults()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -179,12 +212,24 @@ class ChangeBookSourceComposeViewModel(
|
|||||||
it.name.contains(screenKey) || it.originName.contains(screenKey)
|
it.name.contains(screenKey) || it.originName.contains(screenKey)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
val sorted = filtered.sortedWith(
|
val comparator = if (ChangeSourceConfig.loadWordCount) {
|
||||||
|
compareByDescending<SearchBook> { 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<SearchBook> { ObservableSourceConfig.getBookScore(it) }
|
compareByDescending<SearchBook> { ObservableSourceConfig.getBookScore(it) }
|
||||||
.thenByDescending { io.legado.app.help.config.SourceConfig.getSourceScore(it.origin) }
|
.thenByDescending { io.legado.app.help.config.SourceConfig.getSourceScore(it.origin) }
|
||||||
.thenBy { it.originOrder }
|
.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(
|
fun getToc(
|
||||||
@@ -247,8 +292,15 @@ class ChangeBookSourceComposeViewModel(
|
|||||||
fun refresh() {
|
fun refresh() {
|
||||||
searchResults.clear()
|
searchResults.clear()
|
||||||
bookMap.clear()
|
bookMap.clear()
|
||||||
|
val dbBooks = getDbSearchBooks()
|
||||||
|
if (dbBooks.isNotEmpty()) {
|
||||||
|
searchResults.addAll(dbBooks)
|
||||||
|
searchResults.forEach { bookMap[it.primaryStr()] = it }
|
||||||
|
filterResults()
|
||||||
|
} else {
|
||||||
startSearch()
|
startSearch()
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Source actions
|
// Source actions
|
||||||
fun topSource(searchBook: SearchBook) {
|
fun topSource(searchBook: SearchBook) {
|
||||||
@@ -340,6 +392,23 @@ class ChangeBookSourceComposeViewModel(
|
|||||||
saveScope()
|
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() {
|
private fun saveScope() {
|
||||||
ChangeSourceConfig.searchScope = searchScope.toString()
|
ChangeSourceConfig.searchScope = searchScope.toString()
|
||||||
_scopeUiState.value = ScopeUiState(
|
_scopeUiState.value = ScopeUiState(
|
||||||
|
|||||||
@@ -46,12 +46,14 @@ private fun rememberReadBookColorTheme(
|
|||||||
preferences: ReadPreferences,
|
preferences: ReadPreferences,
|
||||||
): ThemeOverrideState? {
|
): ThemeOverrideState? {
|
||||||
val isAppDark = LegadoTheme.isDark
|
val isAppDark = LegadoTheme.isDark
|
||||||
|
val paletteStyle = preferences.readMenuPaletteStyle
|
||||||
return when (preferences.readBarStyle) {
|
return when (preferences.readBarStyle) {
|
||||||
1 -> rememberReadBackgroundTheme(styleConfig, isAppDark)
|
1 -> rememberReadBackgroundTheme(styleConfig, isAppDark, paletteStyle)
|
||||||
2 -> rememberCustomReadMenuTheme(
|
2 -> rememberCustomReadMenuTheme(
|
||||||
styleConfig = styleConfig,
|
styleConfig = styleConfig,
|
||||||
preferences = preferences,
|
preferences = preferences,
|
||||||
isAppDark = isAppDark,
|
isAppDark = isAppDark,
|
||||||
|
paletteStyle = paletteStyle,
|
||||||
)
|
)
|
||||||
else -> null
|
else -> null
|
||||||
}
|
}
|
||||||
@@ -61,6 +63,7 @@ private fun rememberReadBookColorTheme(
|
|||||||
private fun rememberReadBackgroundTheme(
|
private fun rememberReadBackgroundTheme(
|
||||||
styleConfig: ReadBookStyleConfig,
|
styleConfig: ReadBookStyleConfig,
|
||||||
isAppDark: Boolean,
|
isAppDark: Boolean,
|
||||||
|
paletteStyle: String,
|
||||||
): ThemeOverrideState? {
|
): ThemeOverrideState? {
|
||||||
val background = remember(styleConfig, isAppDark) {
|
val background = remember(styleConfig, isAppDark) {
|
||||||
runCatching { ReadStyleResolver.currentBackground(ReadBookConfig.durConfig) }.getOrNull()
|
runCatching { ReadStyleResolver.currentBackground(ReadBookConfig.durConfig) }.getOrNull()
|
||||||
@@ -85,6 +88,7 @@ private fun rememberReadBackgroundTheme(
|
|||||||
backgroundColor = surfaceColor,
|
backgroundColor = surfaceColor,
|
||||||
containerColor = null,
|
containerColor = null,
|
||||||
fallbackDark = isAppDark,
|
fallbackDark = isAppDark,
|
||||||
|
paletteStyle = paletteStyle,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -93,6 +97,7 @@ private fun rememberCustomReadMenuTheme(
|
|||||||
styleConfig: ReadBookStyleConfig,
|
styleConfig: ReadBookStyleConfig,
|
||||||
preferences: ReadPreferences,
|
preferences: ReadPreferences,
|
||||||
isAppDark: Boolean,
|
isAppDark: Boolean,
|
||||||
|
paletteStyle: String,
|
||||||
): ThemeOverrideState {
|
): ThemeOverrideState {
|
||||||
val menuBackgroundColor = remember(
|
val menuBackgroundColor = remember(
|
||||||
styleConfig,
|
styleConfig,
|
||||||
@@ -127,6 +132,7 @@ private fun rememberCustomReadMenuTheme(
|
|||||||
menuBackgroundColor = menuBackgroundColor,
|
menuBackgroundColor = menuBackgroundColor,
|
||||||
menuContainerColor = menuContainerColor,
|
menuContainerColor = menuContainerColor,
|
||||||
isDark = isAppDark,
|
isDark = isAppDark,
|
||||||
|
paletteStyle = paletteStyle,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -136,11 +142,13 @@ private fun rememberCustomReadMenuTheme(
|
|||||||
containerColor = null,
|
containerColor = null,
|
||||||
fallbackDark = isAppDark,
|
fallbackDark = isAppDark,
|
||||||
deriveDarkFromColor = false,
|
deriveDarkFromColor = false,
|
||||||
|
paletteStyle = paletteStyle,
|
||||||
) ?: buildReadThemeOverride(
|
) ?: buildReadThemeOverride(
|
||||||
seedColor = accentColor,
|
seedColor = accentColor,
|
||||||
backgroundColor = null,
|
backgroundColor = null,
|
||||||
containerColor = null,
|
containerColor = null,
|
||||||
isDark = isAppDark,
|
isDark = isAppDark,
|
||||||
|
paletteStyle = paletteStyle,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -150,13 +158,15 @@ private fun rememberCustomReadMenuThemeOverride(
|
|||||||
menuBackgroundColor: Color,
|
menuBackgroundColor: Color,
|
||||||
menuContainerColor: Color,
|
menuContainerColor: Color,
|
||||||
isDark: Boolean,
|
isDark: Boolean,
|
||||||
|
paletteStyle: String,
|
||||||
): ThemeOverrideState {
|
): ThemeOverrideState {
|
||||||
return remember(accentColor, menuBackgroundColor, menuContainerColor, isDark) {
|
return remember(accentColor, menuBackgroundColor, menuContainerColor, isDark, paletteStyle) {
|
||||||
buildReadThemeOverride(
|
buildReadThemeOverride(
|
||||||
seedColor = accentColor,
|
seedColor = accentColor,
|
||||||
backgroundColor = null,
|
backgroundColor = null,
|
||||||
containerColor = null,
|
containerColor = null,
|
||||||
isDark = isDark,
|
isDark = isDark,
|
||||||
|
paletteStyle = paletteStyle,
|
||||||
).let { base ->
|
).let { base ->
|
||||||
base.copy(
|
base.copy(
|
||||||
colorScheme = base.colorScheme.withCustomReadMenuColors(
|
colorScheme = base.colorScheme.withCustomReadMenuColors(
|
||||||
@@ -176,6 +186,7 @@ private fun rememberReadThemeOverride(
|
|||||||
containerColor: Color?,
|
containerColor: Color?,
|
||||||
fallbackDark: Boolean = LegadoTheme.isDark,
|
fallbackDark: Boolean = LegadoTheme.isDark,
|
||||||
deriveDarkFromColor: Boolean = true,
|
deriveDarkFromColor: Boolean = true,
|
||||||
|
paletteStyle: String = "",
|
||||||
): ThemeOverrideState? {
|
): ThemeOverrideState? {
|
||||||
val isDark = remember(backgroundColor, containerColor, fallbackDark, deriveDarkFromColor) {
|
val isDark = remember(backgroundColor, containerColor, fallbackDark, deriveDarkFromColor) {
|
||||||
if (deriveDarkFromColor) {
|
if (deriveDarkFromColor) {
|
||||||
@@ -184,12 +195,13 @@ private fun rememberReadThemeOverride(
|
|||||||
fallbackDark
|
fallbackDark
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return remember(seedColor, backgroundColor, containerColor, isDark) {
|
return remember(seedColor, backgroundColor, containerColor, isDark, paletteStyle) {
|
||||||
buildReadThemeOverride(
|
buildReadThemeOverride(
|
||||||
seedColor = seedColor,
|
seedColor = seedColor,
|
||||||
backgroundColor = backgroundColor,
|
backgroundColor = backgroundColor,
|
||||||
containerColor = containerColor,
|
containerColor = containerColor,
|
||||||
isDark = isDark,
|
isDark = isDark,
|
||||||
|
paletteStyle = paletteStyle,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -199,12 +211,17 @@ private fun buildReadThemeOverride(
|
|||||||
backgroundColor: Color?,
|
backgroundColor: Color?,
|
||||||
containerColor: Color?,
|
containerColor: Color?,
|
||||||
isDark: Boolean,
|
isDark: Boolean,
|
||||||
|
paletteStyle: String = "",
|
||||||
): ThemeOverrideState {
|
): ThemeOverrideState {
|
||||||
val colorSpec = ThemeResolver.resolveColorSpecFromMaterialVersion(ThemeConfig.materialVersion)
|
val colorSpec = ThemeResolver.resolveColorSpecFromMaterialVersion(ThemeConfig.materialVersion)
|
||||||
|
val resolvedPaletteStyle = paletteStyle
|
||||||
|
.takeIf { it.isNotBlank() }
|
||||||
|
?.let { ThemeResolver.resolvePaletteStyle(it) }
|
||||||
|
?: ThemeResolver.resolvePaletteStyle(ThemeConfig.paletteStyle)
|
||||||
val base = buildThemeOverrideState(
|
val base = buildThemeOverrideState(
|
||||||
seedColor = seedColor,
|
seedColor = seedColor,
|
||||||
isDark = isDark,
|
isDark = isDark,
|
||||||
paletteStyle = ThemeResolver.resolvePaletteStyle(ThemeConfig.paletteStyle),
|
paletteStyle = resolvedPaletteStyle,
|
||||||
colorSpec = colorSpec,
|
colorSpec = colorSpec,
|
||||||
usePureBlack = false,
|
usePureBlack = false,
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -182,6 +182,8 @@ data class ReadMenuConfig(
|
|||||||
val readMenuBorderColor: Int = 0,
|
val readMenuBorderColor: Int = 0,
|
||||||
val readMenuBorderColorNight: Int = 0,
|
val readMenuBorderColorNight: Int = 0,
|
||||||
val readMenuBlurAlpha: Int = 60,
|
val readMenuBlurAlpha: Int = 60,
|
||||||
|
val readMenuBlurColor: Int = 0,
|
||||||
|
val readMenuPaletteStyle: String = "",
|
||||||
val readMenuBlurRadius: Int = 24,
|
val readMenuBlurRadius: Int = 24,
|
||||||
val readMenuLensRadius: Float = 24f,
|
val readMenuLensRadius: Float = 24f,
|
||||||
val readMenuTopBarBlurMode: Int = ReadMenuBlurMode.None,
|
val readMenuTopBarBlurMode: Int = ReadMenuBlurMode.None,
|
||||||
@@ -482,6 +484,8 @@ sealed interface ReadBookIntent {
|
|||||||
data object OpenSystemTtsSettings : ReadBookIntent
|
data object OpenSystemTtsSettings : ReadBookIntent
|
||||||
data object ClearTtsCache : ReadBookIntent
|
data object ClearTtsCache : ReadBookIntent
|
||||||
data class SelectFont(val path: String) : 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 SelectSystemTypeface(val index: Int) : ReadBookIntent
|
||||||
data class ColorSelected(val dialogId: Int, val color: 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 ShadowSet : ReadBookSheet
|
||||||
data object UnderlineConfig : ReadBookSheet
|
data object UnderlineConfig : ReadBookSheet
|
||||||
data object FontSelect : ReadBookSheet
|
data object FontSelect : ReadBookSheet
|
||||||
|
data object TitleFontSelect : ReadBookSheet
|
||||||
data object HighlightRuleConfig : ReadBookSheet
|
data object HighlightRuleConfig : ReadBookSheet
|
||||||
data object MoreConfig : ReadBookSheet
|
data object MoreConfig : ReadBookSheet
|
||||||
data object BgTextConfig : ReadBookSheet
|
data object BgTextConfig : ReadBookSheet
|
||||||
@@ -769,6 +774,18 @@ sealed interface ConfigUpdate {
|
|||||||
data class TitleColor(val color: Int) : ConfigUpdate {
|
data class TitleColor(val color: Int) : ConfigUpdate {
|
||||||
override val actions = setOf(ConfigUpdateAction.UpdateStyle, ConfigUpdateAction.ReloadContent, ConfigUpdateAction.InvalidateTextPage)
|
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 ---
|
// --- Header / footer tips ---
|
||||||
data class HeaderMode(val value: Int) : ConfigUpdate {
|
data class HeaderMode(val value: Int) : ConfigUpdate {
|
||||||
@@ -1023,6 +1040,12 @@ sealed interface ConfigUpdate {
|
|||||||
data class MenuBlurAlpha(val value: Int) : ConfigUpdate {
|
data class MenuBlurAlpha(val value: Int) : ConfigUpdate {
|
||||||
override val actions = emptySet<ConfigUpdateAction>()
|
override val actions = emptySet<ConfigUpdateAction>()
|
||||||
}
|
}
|
||||||
|
data class MenuBlurColor(val color: Int) : ConfigUpdate {
|
||||||
|
override val actions = emptySet<ConfigUpdateAction>()
|
||||||
|
}
|
||||||
|
data class MenuPaletteStyle(val value: String) : ConfigUpdate {
|
||||||
|
override val actions = emptySet<ConfigUpdateAction>()
|
||||||
|
}
|
||||||
data class MenuLensRadius(val value: Float) : ConfigUpdate {
|
data class MenuLensRadius(val value: Float) : ConfigUpdate {
|
||||||
override val actions = emptySet<ConfigUpdateAction>()
|
override val actions = emptySet<ConfigUpdateAction>()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -195,7 +195,7 @@ fun ReadBookMenuBar(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
val hideTopBar = dialogLikeRoute ||
|
val hideTopBar = dialogLikeRoute ||
|
||||||
currentRoute == ReadBookMenuRoute.ReadStyle && readStylePage >= 1
|
currentRoute == ReadBookMenuRoute.TextTitle
|
||||||
val menuColors = readMenuColors()
|
val menuColors = readMenuColors()
|
||||||
|
|
||||||
Box(Modifier.fillMaxSize()) {
|
Box(Modifier.fillMaxSize()) {
|
||||||
@@ -683,6 +683,9 @@ private fun ReadBookMenuSurface(
|
|||||||
onOpenFontSelect = {
|
onOpenFontSelect = {
|
||||||
onIntent(ReadBookIntent.ShowSheet(ReadBookSheet.FontSelect))
|
onIntent(ReadBookIntent.ShowSheet(ReadBookSheet.FontSelect))
|
||||||
},
|
},
|
||||||
|
onOpenTitleFontSelect = {
|
||||||
|
onIntent(ReadBookIntent.ShowSheet(ReadBookSheet.TitleFontSelect))
|
||||||
|
},
|
||||||
modifier = Modifier.padding(horizontal = 16.dp),
|
modifier = Modifier.padding(horizontal = 16.dp),
|
||||||
onIntent = onIntent,
|
onIntent = onIntent,
|
||||||
)
|
)
|
||||||
@@ -902,15 +905,22 @@ private fun MenuTitleBar(
|
|||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
val useTitleCapsule = readMenuTopBarTitleCapsuleEnabled(backdrop, state.menuConfig)
|
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(
|
Row(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.padding(horizontal = 16.dp, vertical = 4.dp),
|
.padding(horizontal = 16.dp, vertical = 4.dp),
|
||||||
verticalAlignment = Alignment.CenterVertically,
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
|
horizontalArrangement = Arrangement.spacedBy(16.dp),
|
||||||
|
) {
|
||||||
|
// Left group: back + capsule/title — fills remaining space
|
||||||
|
Row(
|
||||||
|
modifier = Modifier.weight(1f),
|
||||||
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
) {
|
) {
|
||||||
// Back button
|
|
||||||
MenuTitleGlassButton(
|
MenuTitleGlassButton(
|
||||||
onClick = { onIntent(ReadBookIntent.CloseReadBook) },
|
onClick = { onIntent(ReadBookIntent.CloseReadBook) },
|
||||||
icon = Icons.AutoMirrored.Filled.ArrowBack,
|
icon = Icons.AutoMirrored.Filled.ArrowBack,
|
||||||
@@ -921,13 +931,12 @@ private fun MenuTitleBar(
|
|||||||
)
|
)
|
||||||
|
|
||||||
if (useTitleCapsule) {
|
if (useTitleCapsule) {
|
||||||
// Title capsule layout: title + chapter in a glass pill
|
|
||||||
TitleCapsuleGlassLayout(
|
TitleCapsuleGlassLayout(
|
||||||
state = state,
|
state = state,
|
||||||
colors = colors,
|
colors = colors,
|
||||||
onIntent = onIntent,
|
onIntent = onIntent,
|
||||||
backdrop = backdrop,
|
backdrop = backdrop,
|
||||||
titleTextColor = titleTextColor,
|
titleTextColor = capsuleIconColor,
|
||||||
)
|
)
|
||||||
} else if (titleBarMode != "1" && titleBarMode != "3") {
|
} else if (titleBarMode != "1" && titleBarMode != "3") {
|
||||||
AppText(
|
AppText(
|
||||||
@@ -947,10 +956,10 @@ private fun MenuTitleBar(
|
|||||||
maxLines = 2,
|
maxLines = 2,
|
||||||
overflow = TextOverflow.Ellipsis,
|
overflow = TextOverflow.Ellipsis,
|
||||||
)
|
)
|
||||||
} else {
|
}
|
||||||
Spacer(Modifier.weight(1f))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Right group: actions
|
||||||
if (readMenuTopBarButtonLiquidGlassEnabled(backdrop, state.menuConfig)) {
|
if (readMenuTopBarButtonLiquidGlassEnabled(backdrop, state.menuConfig)) {
|
||||||
MenuTitleBarMergedGlassButton(
|
MenuTitleBarMergedGlassButton(
|
||||||
state = state,
|
state = state,
|
||||||
@@ -963,7 +972,6 @@ private fun MenuTitleBar(
|
|||||||
horizontalArrangement = Arrangement.spacedBy(6.dp),
|
horizontalArrangement = Arrangement.spacedBy(6.dp),
|
||||||
verticalAlignment = Alignment.CenterVertically,
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
) {
|
) {
|
||||||
// Source action button (non-local books only)
|
|
||||||
if (!state.isLocalBook) {
|
if (!state.isLocalBook) {
|
||||||
SourceActionButton(
|
SourceActionButton(
|
||||||
state = state,
|
state = state,
|
||||||
@@ -1252,7 +1260,7 @@ private fun RowScope.TitleCapsuleGlassLayout(
|
|||||||
Row(
|
Row(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.weight(1f)
|
.weight(1f)
|
||||||
.padding(horizontal = 8.dp)
|
.padding(start = 12.dp)
|
||||||
.height(40.dp)
|
.height(40.dp)
|
||||||
.readMenuLiquidGlass(
|
.readMenuLiquidGlass(
|
||||||
backdrop = backdrop,
|
backdrop = backdrop,
|
||||||
@@ -1320,10 +1328,6 @@ private fun MenuTitleBarMergedGlassButton(
|
|||||||
val tint = LegadoTheme.colorScheme.onSurfaceVariant
|
val tint = LegadoTheme.colorScheme.onSurfaceVariant
|
||||||
|
|
||||||
Box {
|
Box {
|
||||||
Box(
|
|
||||||
contentAlignment = Alignment.Center,
|
|
||||||
modifier = Modifier.size(48.dp),
|
|
||||||
) {
|
|
||||||
Row(
|
Row(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.height(40.dp)
|
.height(40.dp)
|
||||||
@@ -1418,7 +1422,6 @@ private fun MenuTitleBarMergedGlassButton(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Dropdown menus
|
// Dropdown menus
|
||||||
if (!state.isLocalBook) {
|
if (!state.isLocalBook) {
|
||||||
@@ -2827,8 +2830,9 @@ private fun Modifier.readMenuHazeEffect(
|
|||||||
progressiveBottomToTop: Boolean = false,
|
progressiveBottomToTop: Boolean = false,
|
||||||
): Modifier {
|
): Modifier {
|
||||||
val surfaceAlpha = menuConfig.readMenuBlurAlpha.coerceIn(0, 100) / 100f
|
val surfaceAlpha = menuConfig.readMenuBlurAlpha.coerceIn(0, 100) / 100f
|
||||||
|
val blurTintColor = menuConfig.readMenuBlurColor.takeIf { it != 0 }?.let { Color(it) }
|
||||||
val hazeContainerColor = if (progressive) {
|
val hazeContainerColor = if (progressive) {
|
||||||
Color.Black.copy(alpha = surfaceAlpha)
|
(blurTintColor ?: Color.Black).copy(alpha = surfaceAlpha)
|
||||||
} else {
|
} else {
|
||||||
colors.background.copy(alpha = surfaceAlpha)
|
colors.background.copy(alpha = surfaceAlpha)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -174,6 +174,17 @@ fun ReadBookScreen(
|
|||||||
onOpenFolderPicker = { onIntent(ReadBookIntent.OpenFontFolderPicker) },
|
onOpenFolderPicker = { onIntent(ReadBookIntent.OpenFontFolderPicker) },
|
||||||
systemTypefaces = fontSelectSystemTypefaces,
|
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(
|
ToolButtonConfigSheet(
|
||||||
show = state.activeSheet is ReadBookSheet.ToolButtonConfig,
|
show = state.activeSheet is ReadBookSheet.ToolButtonConfig,
|
||||||
items = state.menuConfig.bottomBarButtons,
|
items = state.menuConfig.bottomBarButtons,
|
||||||
|
|||||||
@@ -896,6 +896,14 @@ class ReadBookViewModel(
|
|||||||
}
|
}
|
||||||
|
|
||||||
is ReadBookIntent.SelectFont -> selectFont(intent.path)
|
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 -> {
|
is ReadBookIntent.SelectSystemTypeface -> {
|
||||||
ReadConfig.systemTypefaces = intent.index
|
ReadConfig.systemTypefaces = intent.index
|
||||||
ReadBookConfig.textFont = ""
|
ReadBookConfig.textFont = ""
|
||||||
@@ -1448,6 +1456,7 @@ class ReadBookViewModel(
|
|||||||
val old = previous
|
val old = previous
|
||||||
previous = preferences
|
previous = preferences
|
||||||
ReadConfig.syncReadPreferences(preferences)
|
ReadConfig.syncReadPreferences(preferences)
|
||||||
|
ReadBookConfig.readMenuPaletteStyle = preferences.readMenuPaletteStyle
|
||||||
_readPreferences.value = preferences
|
_readPreferences.value = preferences
|
||||||
if (!preferences.hasMenuClickArea()) {
|
if (!preferences.hasMenuClickArea()) {
|
||||||
ReadConfig.detectClickArea()
|
ReadConfig.detectClickArea()
|
||||||
@@ -1599,6 +1608,8 @@ class ReadBookViewModel(
|
|||||||
readMenuBorderColor = ReadBookConfig.readMenuBorderColor,
|
readMenuBorderColor = ReadBookConfig.readMenuBorderColor,
|
||||||
readMenuBorderColorNight = ReadBookConfig.readMenuBorderColorNight,
|
readMenuBorderColorNight = ReadBookConfig.readMenuBorderColorNight,
|
||||||
readMenuBlurAlpha = ReadBookConfig.readMenuBlurAlpha,
|
readMenuBlurAlpha = ReadBookConfig.readMenuBlurAlpha,
|
||||||
|
readMenuBlurColor = ReadBookConfig.readMenuBlurColor,
|
||||||
|
readMenuPaletteStyle = ReadBookConfig.readMenuPaletteStyle,
|
||||||
readMenuBlurRadius = ReadBookConfig.readMenuBlurRadius,
|
readMenuBlurRadius = ReadBookConfig.readMenuBlurRadius,
|
||||||
readMenuLensRadius = ReadBookConfig.readMenuLensRadius,
|
readMenuLensRadius = ReadBookConfig.readMenuLensRadius,
|
||||||
readMenuTopBarBlurMode = ReadBookConfig.readMenuTopBarBlurMode,
|
readMenuTopBarBlurMode = ReadBookConfig.readMenuTopBarBlurMode,
|
||||||
@@ -2507,6 +2518,10 @@ class ReadBookViewModel(
|
|||||||
is ConfigUpdate.TitleTopSpacing -> ReadBookConfig.titleTopSpacing = update.value
|
is ConfigUpdate.TitleTopSpacing -> ReadBookConfig.titleTopSpacing = update.value
|
||||||
is ConfigUpdate.TitleBottomSpacing -> ReadBookConfig.titleBottomSpacing = update.value
|
is ConfigUpdate.TitleBottomSpacing -> ReadBookConfig.titleBottomSpacing = update.value
|
||||||
is ConfigUpdate.TitleColor -> ReadBookConfig.titleColor = update.color
|
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 ---
|
// --- Header / footer tips ---
|
||||||
is ConfigUpdate.HeaderMode -> ReadBookConfig.headerMode = update.value
|
is ConfigUpdate.HeaderMode -> ReadBookConfig.headerMode = update.value
|
||||||
@@ -2829,6 +2844,20 @@ class ReadBookViewModel(
|
|||||||
}
|
}
|
||||||
_uiState.update { it.copy(menuConfig = it.menuConfig.copy(readMenuBlurAlpha = update.value)) }
|
_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 -> {
|
is ConfigUpdate.MenuLensRadius -> {
|
||||||
ReadBookConfig.readMenuLensRadius = update.value
|
ReadBookConfig.readMenuLensRadius = update.value
|
||||||
viewModelScope.launch {
|
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() {
|
private fun toggleDayNight() {
|
||||||
val nextMode = if (ReadConfig.isNightTheme) "1" else "2"
|
val nextMode = if (ReadConfig.isNightTheme) "1" else "2"
|
||||||
ThemeConfig.themeMode = nextMode
|
ThemeConfig.themeMode = nextMode
|
||||||
|
|||||||
@@ -26,7 +26,11 @@ import androidx.compose.material.icons.filled.Settings
|
|||||||
import androidx.compose.material.icons.filled.SkipNext
|
import androidx.compose.material.icons.filled.SkipNext
|
||||||
import androidx.compose.material.icons.filled.SkipPrevious
|
import androidx.compose.material.icons.filled.SkipPrevious
|
||||||
import androidx.compose.material.icons.filled.Translate
|
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.Box
|
||||||
|
import androidx.compose.foundation.layout.size
|
||||||
|
import androidx.compose.foundation.shape.CircleShape
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.LaunchedEffect
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
import androidx.compose.runtime.derivedStateOf
|
import androidx.compose.runtime.derivedStateOf
|
||||||
@@ -40,13 +44,16 @@ import androidx.compose.runtime.setValue
|
|||||||
import androidx.compose.runtime.snapshotFlow
|
import androidx.compose.runtime.snapshotFlow
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.draw.clip
|
||||||
import androidx.compose.ui.draw.clipToBounds
|
import androidx.compose.ui.draw.clipToBounds
|
||||||
|
import androidx.compose.ui.graphics.Color
|
||||||
import androidx.compose.ui.graphics.vector.ImageVector
|
import androidx.compose.ui.graphics.vector.ImageVector
|
||||||
import androidx.compose.ui.layout.onSizeChanged
|
import androidx.compose.ui.layout.onSizeChanged
|
||||||
import androidx.compose.ui.platform.LocalDensity
|
import androidx.compose.ui.platform.LocalDensity
|
||||||
import androidx.compose.ui.platform.LocalContext
|
import androidx.compose.ui.platform.LocalContext
|
||||||
import androidx.compose.ui.res.stringArrayResource
|
import androidx.compose.ui.res.stringArrayResource
|
||||||
import androidx.compose.ui.res.stringResource
|
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.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
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.ReadBookButtonConfigItem
|
||||||
import io.legado.app.ui.book.read.ReadBookIntent
|
import io.legado.app.ui.book.read.ReadBookIntent
|
||||||
import io.legado.app.ui.book.read.ReadBookSheet
|
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.SectionTitle
|
||||||
import io.legado.app.ui.widget.components.dialog.ColorPickerSheet
|
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.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.TinyClickableSettingItem
|
||||||
import io.legado.app.ui.widget.components.settingItem.TinyColorModeSettingItem
|
import io.legado.app.ui.widget.components.settingItem.TinyColorModeSettingItem
|
||||||
import io.legado.app.ui.widget.components.settingItem.TinyDropdownSettingItem
|
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_MENU_CONTAINER_NIGHT = 10
|
||||||
private const val COLOR_BORDER = 11
|
private const val COLOR_BORDER = 11
|
||||||
private const val COLOR_BORDER_NIGHT = 12
|
private const val COLOR_BORDER_NIGHT = 12
|
||||||
|
private const val COLOR_BLUR_TINT = 13
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
internal fun SystemMenuPage(
|
internal fun SystemMenuPage(
|
||||||
@@ -196,6 +206,7 @@ internal fun SystemMenuPage(
|
|||||||
COLOR_MENU_CONTAINER_NIGHT -> onIntent(ReadBookIntent.UpdateConfig(ConfigUpdate.MenuContainerColorNight(color)))
|
COLOR_MENU_CONTAINER_NIGHT -> onIntent(ReadBookIntent.UpdateConfig(ConfigUpdate.MenuContainerColorNight(color)))
|
||||||
COLOR_BORDER -> onIntent(ReadBookIntent.UpdateConfig(ConfigUpdate.BorderColor(color)))
|
COLOR_BORDER -> onIntent(ReadBookIntent.UpdateConfig(ConfigUpdate.BorderColor(color)))
|
||||||
COLOR_BORDER_NIGHT -> onIntent(ReadBookIntent.UpdateConfig(ConfigUpdate.BorderColorNight(color)))
|
COLOR_BORDER_NIGHT -> onIntent(ReadBookIntent.UpdateConfig(ConfigUpdate.BorderColorNight(color)))
|
||||||
|
COLOR_BLUR_TINT -> onIntent(ReadBookIntent.UpdateConfig(ConfigUpdate.MenuBlurColor(color)))
|
||||||
}
|
}
|
||||||
showColorPicker = false
|
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) {
|
AnimatedVisibility(visible = bottomMode == 2) {
|
||||||
Column {
|
Column {
|
||||||
TinyDropdownSettingItem(
|
TinyDropdownSettingItem(
|
||||||
@@ -461,6 +489,18 @@ private fun GlobalMenuTab(
|
|||||||
onIntent(ReadBookIntent.UpdateConfig(ConfigUpdate.MenuBlurAlpha(it.toInt())))
|
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<ReadMenuButtonInfo> = l
|
|||||||
ReadMenuButtonInfo("replace_badge", Icons.Default.AutoAwesome, context.getString(R.string.replace_purify_badge)),
|
ReadMenuButtonInfo("replace_badge", Icons.Default.AutoAwesome, context.getString(R.string.replace_purify_badge)),
|
||||||
ReadMenuButtonInfo("translate", Icons.Default.Translate, context.getString(R.string.translate)),
|
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,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -60,6 +60,7 @@ fun ReadStyleTextTitleContent(
|
|||||||
onOpenUnderlineConfig: () -> Unit,
|
onOpenUnderlineConfig: () -> Unit,
|
||||||
onOpenHighlightRule: () -> Unit,
|
onOpenHighlightRule: () -> Unit,
|
||||||
onOpenFontSelect: () -> Unit,
|
onOpenFontSelect: () -> Unit,
|
||||||
|
onOpenTitleFontSelect: () -> Unit,
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
onIntent: (ReadBookIntent) -> Unit,
|
onIntent: (ReadBookIntent) -> Unit,
|
||||||
) {
|
) {
|
||||||
@@ -85,6 +86,7 @@ fun ReadStyleTextTitleContent(
|
|||||||
onOpenUnderlineConfig = onOpenUnderlineConfig,
|
onOpenUnderlineConfig = onOpenUnderlineConfig,
|
||||||
onOpenHighlightRule = onOpenHighlightRule,
|
onOpenHighlightRule = onOpenHighlightRule,
|
||||||
onOpenFontSelect = onOpenFontSelect,
|
onOpenFontSelect = onOpenFontSelect,
|
||||||
|
onOpenTitleFontSelect = onOpenTitleFontSelect,
|
||||||
animateToPage = { page -> scope.launch { pagerState.animateScrollToPage(page) } },
|
animateToPage = { page -> scope.launch { pagerState.animateScrollToPage(page) } },
|
||||||
modifier = modifier,
|
modifier = modifier,
|
||||||
onIntent = onIntent,
|
onIntent = onIntent,
|
||||||
@@ -101,6 +103,7 @@ internal fun ReadStyleTextTitleContent(
|
|||||||
onOpenUnderlineConfig: () -> Unit,
|
onOpenUnderlineConfig: () -> Unit,
|
||||||
onOpenHighlightRule: () -> Unit,
|
onOpenHighlightRule: () -> Unit,
|
||||||
onOpenFontSelect: () -> Unit,
|
onOpenFontSelect: () -> Unit,
|
||||||
|
onOpenTitleFontSelect: () -> Unit,
|
||||||
animateToPage: (Int) -> Unit,
|
animateToPage: (Int) -> Unit,
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
onIntent: (ReadBookIntent) -> Unit,
|
onIntent: (ReadBookIntent) -> Unit,
|
||||||
@@ -132,7 +135,10 @@ internal fun ReadStyleTextTitleContent(
|
|||||||
)
|
)
|
||||||
|
|
||||||
1 -> LayoutSpacingPage(onIntent = onIntent)
|
1 -> LayoutSpacingPage(onIntent = onIntent)
|
||||||
2 -> TitleSettingsPage(onIntent = onIntent)
|
2 -> TitleSettingsPage(
|
||||||
|
onOpenTitleFontSelect = onOpenTitleFontSelect,
|
||||||
|
onIntent = onIntent,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -358,10 +364,14 @@ internal fun TextEffectsPage(
|
|||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
internal fun TitleSettingsPage(
|
internal fun TitleSettingsPage(
|
||||||
|
onOpenTitleFontSelect: () -> Unit,
|
||||||
onIntent: (ReadBookIntent) -> Unit,
|
onIntent: (ReadBookIntent) -> Unit,
|
||||||
) {
|
) {
|
||||||
var titleMode by remember(ReadBookConfig.titleMode) { mutableIntStateOf(ReadBookConfig.titleMode) }
|
var titleMode by remember(ReadBookConfig.titleMode) { mutableIntStateOf(ReadBookConfig.titleMode) }
|
||||||
var titleBold by remember(ReadBookConfig.titleBold) { mutableIntStateOf(ReadBookConfig.titleBold) }
|
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 titleSegScaling by remember(ReadBookConfig.titleSegScaling) { mutableFloatStateOf(ReadBookConfig.titleSegScaling) }
|
||||||
var titleLineSpacingExtra by remember(ReadBookConfig.titleLineSpacingExtra) { mutableIntStateOf(ReadBookConfig.titleLineSpacingExtra) }
|
var titleLineSpacingExtra by remember(ReadBookConfig.titleLineSpacingExtra) { mutableIntStateOf(ReadBookConfig.titleLineSpacingExtra) }
|
||||||
var titleLineSpacingSub by remember(ReadBookConfig.titleLineSpacingSub) { mutableIntStateOf(ReadBookConfig.titleLineSpacingSub) }
|
var titleLineSpacingSub by remember(ReadBookConfig.titleLineSpacingSub) { mutableIntStateOf(ReadBookConfig.titleLineSpacingSub) }
|
||||||
@@ -432,6 +442,85 @@ internal fun TitleSettingsPage(
|
|||||||
|
|
||||||
Spacer(Modifier.height(8.dp))
|
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
|
// Title spacing sliders
|
||||||
TinySliderSettingItem(
|
TinySliderSettingItem(
|
||||||
title = stringResource(R.string.subtitle_scale),
|
title = stringResource(R.string.subtitle_scale),
|
||||||
|
|||||||
@@ -104,7 +104,7 @@ fun ScopeSelectSheet(
|
|||||||
applyDraftSelection()
|
applyDraftSelection()
|
||||||
onDismissRequest()
|
onDismissRequest()
|
||||||
},
|
},
|
||||||
text = stringResource(R.string.confirm),
|
icon = AppIcons.Check,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -92,6 +92,7 @@ fun ColorScheme.toLegadoColorScheme(): LegadoColorScheme {
|
|||||||
fun ProvideColorSchemeOverride(
|
fun ProvideColorSchemeOverride(
|
||||||
colorScheme: ColorScheme,
|
colorScheme: ColorScheme,
|
||||||
seedColor: Color = colorScheme.primary,
|
seedColor: Color = colorScheme.primary,
|
||||||
|
overrideIsDark: Boolean? = null,
|
||||||
content: @Composable () -> Unit,
|
content: @Composable () -> Unit,
|
||||||
) {
|
) {
|
||||||
val themeAnimationSpec = tween<Color>(
|
val themeAnimationSpec = tween<Color>(
|
||||||
@@ -106,10 +107,12 @@ fun ProvideColorSchemeOverride(
|
|||||||
label = "theme_seed_animation"
|
label = "theme_seed_animation"
|
||||||
).value
|
).value
|
||||||
val legadoColorScheme = remember(animatedColorScheme) { animatedColorScheme.toLegadoColorScheme() }
|
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(
|
baseThemeMode.copy(
|
||||||
colorScheme = animatedColorScheme,
|
colorScheme = animatedColorScheme,
|
||||||
seedColor = animatedSeedColor,
|
seedColor = animatedSeedColor,
|
||||||
|
isDark = resolvedIsDark,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
val materialTypography = MaterialTheme.typography
|
val materialTypography = MaterialTheme.typography
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ import io.legado.app.ui.config.themeConfig.ThemeConfig
|
|||||||
data class ThemeOverrideState(
|
data class ThemeOverrideState(
|
||||||
val seedColor: Color,
|
val seedColor: Color,
|
||||||
val colorScheme: ColorScheme,
|
val colorScheme: ColorScheme,
|
||||||
|
val isDark: Boolean = false,
|
||||||
)
|
)
|
||||||
|
|
||||||
fun buildThemeOverrideState(
|
fun buildThemeOverrideState(
|
||||||
@@ -45,7 +46,8 @@ fun buildThemeOverrideState(
|
|||||||
|
|
||||||
return ThemeOverrideState(
|
return ThemeOverrideState(
|
||||||
seedColor = seedColor,
|
seedColor = seedColor,
|
||||||
colorScheme = colorScheme
|
colorScheme = colorScheme,
|
||||||
|
isDark = isDark,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -72,6 +74,7 @@ fun ProvideThemeOverride(
|
|||||||
ProvideColorSchemeOverride(
|
ProvideColorSchemeOverride(
|
||||||
colorScheme = currentTheme.colorScheme,
|
colorScheme = currentTheme.colorScheme,
|
||||||
seedColor = currentTheme.seedColor,
|
seedColor = currentTheme.seedColor,
|
||||||
|
overrideIsDark = currentTheme.isDark,
|
||||||
content = content
|
content = content
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
+2
-2
@@ -438,8 +438,8 @@ fun ChangeSourceSheet(
|
|||||||
selectedSources = scopeState.sourceUrls,
|
selectedSources = scopeState.sourceUrls,
|
||||||
onToggleSource = { viewModel.toggleScopeSource(it) },
|
onToggleSource = { viewModel.toggleScopeSource(it) },
|
||||||
isSourceScope = scopeState.isSource,
|
isSourceScope = scopeState.isSource,
|
||||||
onConfirm = {
|
onApplyScope = { selection ->
|
||||||
viewModel.startSearch()
|
viewModel.applyScopeSelection(selection)
|
||||||
showFilterSheet = false
|
showFilterSheet = false
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -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.filled.LibraryBooks
|
||||||
import androidx.compose.material.icons.automirrored.outlined.LibraryBooks
|
import androidx.compose.material.icons.automirrored.outlined.LibraryBooks
|
||||||
import androidx.compose.material.icons.filled.BugReport
|
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.Clear
|
||||||
import androidx.compose.material.icons.filled.Delete
|
import androidx.compose.material.icons.filled.Delete
|
||||||
import androidx.compose.material.icons.filled.Edit
|
import androidx.compose.material.icons.filled.Edit
|
||||||
@@ -111,6 +112,10 @@ object AppIcons {
|
|||||||
@Composable
|
@Composable
|
||||||
get() = if (isMiuix) MiuixIcons.MoreCircle else Icons.Default.MoreHoriz
|
get() = if (isMiuix) MiuixIcons.MoreCircle else Icons.Default.MoreHoriz
|
||||||
|
|
||||||
|
val Check: ImageVector
|
||||||
|
@Composable
|
||||||
|
get() = Icons.Default.Check
|
||||||
|
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun mainDestination(destination: MainDestination, selected: Boolean): ImageVector {
|
fun mainDestination(destination: MainDestination, selected: Boolean): ImageVector {
|
||||||
|
|||||||
@@ -65,6 +65,7 @@ fun RoundDropdownMenu(
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
val colorScheme = rememberOpaqueColorScheme()
|
val colorScheme = rememberOpaqueColorScheme()
|
||||||
|
val popupContainerColor = LegadoTheme.colorScheme.surfaceContainerLow
|
||||||
|
|
||||||
DropdownMenu(
|
DropdownMenu(
|
||||||
expanded = expanded,
|
expanded = expanded,
|
||||||
@@ -72,7 +73,7 @@ fun RoundDropdownMenu(
|
|||||||
modifier = modifier,
|
modifier = modifier,
|
||||||
shape = shape,
|
shape = shape,
|
||||||
shadowElevation = shadowElevation,
|
shadowElevation = shadowElevation,
|
||||||
containerColor = colorScheme.surfaceContainerLow
|
containerColor = popupContainerColor
|
||||||
) {
|
) {
|
||||||
MaterialExpressiveTheme(
|
MaterialExpressiveTheme(
|
||||||
colorScheme = colorScheme,
|
colorScheme = colorScheme,
|
||||||
@@ -129,6 +130,7 @@ fun RoundDropdownMenuLazy(
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
val colorScheme = rememberOpaqueColorScheme()
|
val colorScheme = rememberOpaqueColorScheme()
|
||||||
|
val popupContainerColor = LegadoTheme.colorScheme.surfaceContainerLow
|
||||||
|
|
||||||
DropdownMenu(
|
DropdownMenu(
|
||||||
expanded = expanded,
|
expanded = expanded,
|
||||||
@@ -136,7 +138,7 @@ fun RoundDropdownMenuLazy(
|
|||||||
modifier = modifier,
|
modifier = modifier,
|
||||||
shape = shape,
|
shape = shape,
|
||||||
shadowElevation = shadowElevation,
|
shadowElevation = shadowElevation,
|
||||||
containerColor = colorScheme.surfaceContainerLow
|
containerColor = popupContainerColor
|
||||||
) {
|
) {
|
||||||
MaterialExpressiveTheme(
|
MaterialExpressiveTheme(
|
||||||
colorScheme = colorScheme,
|
colorScheme = colorScheme,
|
||||||
|
|||||||
+4
-5
@@ -35,7 +35,6 @@ import androidx.compose.ui.text.font.FontWeight
|
|||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import io.legado.app.ui.theme.LegadoTheme
|
import io.legado.app.ui.theme.LegadoTheme
|
||||||
import io.legado.app.ui.theme.ThemeResolver
|
import io.legado.app.ui.theme.ThemeResolver
|
||||||
import io.legado.app.ui.theme.rememberOpaqueColorScheme
|
|
||||||
import io.legado.app.ui.widget.components.icon.AppIcon
|
import io.legado.app.ui.widget.components.icon.AppIcon
|
||||||
import top.yukonga.miuix.kmp.basic.DropdownDefaults
|
import top.yukonga.miuix.kmp.basic.DropdownDefaults
|
||||||
import top.yukonga.miuix.kmp.icon.MiuixIcons
|
import top.yukonga.miuix.kmp.icon.MiuixIcons
|
||||||
@@ -121,9 +120,9 @@ fun RoundDropdownMenuItem(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
val colorScheme = rememberOpaqueColorScheme()
|
val legadoColorScheme = LegadoTheme.colorScheme
|
||||||
val selectedContentColor = colorScheme.primary
|
val selectedContentColor = legadoColorScheme.primary
|
||||||
val defaultContentColor = colorScheme.onSurface
|
val defaultContentColor = legadoColorScheme.onSurface
|
||||||
val contentColor = if (enabled) {
|
val contentColor = if (enabled) {
|
||||||
when {
|
when {
|
||||||
hasCustomContentColor -> color
|
hasCustomContentColor -> color
|
||||||
@@ -137,7 +136,7 @@ fun RoundDropdownMenuItem(
|
|||||||
else -> defaultContentColor.copy(alpha = 0.38f)
|
else -> defaultContentColor.copy(alpha = 0.38f)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
val containerColor = colorScheme.surface
|
val containerColor = legadoColorScheme.surface
|
||||||
|
|
||||||
Surface(
|
Surface(
|
||||||
onClick = onClick,
|
onClick = onClick,
|
||||||
|
|||||||
@@ -1711,6 +1711,10 @@
|
|||||||
<string name="tool_bar_style">工具栏样式</string>
|
<string name="tool_bar_style">工具栏样式</string>
|
||||||
<string name="split_title">标题分段</string>
|
<string name="split_title">标题分段</string>
|
||||||
<string name="split_title_mode">分段模式</string>
|
<string name="split_title_mode">分段模式</string>
|
||||||
|
<string name="split_title_by_position">按位置分段</string>
|
||||||
|
<string name="split_title_by_flag">按标记分段</string>
|
||||||
|
<string name="split_title_by_regex">正则分段</string>
|
||||||
|
<string name="split_title_position">分段位置</string>
|
||||||
<string name="subtitle_scale">次行缩放</string>
|
<string name="subtitle_scale">次行缩放</string>
|
||||||
<string name="subtitle_margin">次行距离</string>
|
<string name="subtitle_margin">次行距离</string>
|
||||||
<string name="heading_spacing">标题段距</string>
|
<string name="heading_spacing">标题段距</string>
|
||||||
@@ -1903,6 +1907,7 @@
|
|||||||
<string name="read_menu_blur_radius">模糊半径</string>
|
<string name="read_menu_blur_radius">模糊半径</string>
|
||||||
<string name="read_menu_blur_radius_summary">模糊半径越大,系统运行越卡顿</string>
|
<string name="read_menu_blur_radius_summary">模糊半径越大,系统运行越卡顿</string>
|
||||||
<string name="read_menu_blur_alpha">菜单不透明度</string>
|
<string name="read_menu_blur_alpha">菜单不透明度</string>
|
||||||
|
<string name="read_menu_blur_color">模糊着色</string>
|
||||||
<string name="read_menu_border">边框</string>
|
<string name="read_menu_border">边框</string>
|
||||||
<string name="read_menu_border_width">宽度</string>
|
<string name="read_menu_border_width">宽度</string>
|
||||||
<string name="read_menu_border_color">颜色</string>
|
<string name="read_menu_border_color">颜色</string>
|
||||||
|
|||||||
@@ -1748,6 +1748,10 @@
|
|||||||
<string name="rule_segment">Rule</string>
|
<string name="rule_segment">Rule</string>
|
||||||
<string name="split_title">Split title</string>
|
<string name="split_title">Split title</string>
|
||||||
<string name="split_title_mode">Split mode</string>
|
<string name="split_title_mode">Split mode</string>
|
||||||
|
<string name="split_title_by_position">By position</string>
|
||||||
|
<string name="split_title_by_flag">By flag</string>
|
||||||
|
<string name="split_title_by_regex">By regex</string>
|
||||||
|
<string name="split_title_position">Split position</string>
|
||||||
<string name="subtitle_margin">Subtitle margin</string>
|
<string name="subtitle_margin">Subtitle margin</string>
|
||||||
<string name="subtitle_scale">Subtitle scale</string>
|
<string name="subtitle_scale">Subtitle scale</string>
|
||||||
<string name="tool_bar_style">Tool bar style</string>
|
<string name="tool_bar_style">Tool bar style</string>
|
||||||
@@ -1912,6 +1916,7 @@
|
|||||||
<string name="read_menu_blur_radius">Blur radius</string>
|
<string name="read_menu_blur_radius">Blur radius</string>
|
||||||
<string name="read_menu_blur_radius_summary">Higher radius may reduce performance</string>
|
<string name="read_menu_blur_radius_summary">Higher radius may reduce performance</string>
|
||||||
<string name="read_menu_blur_alpha">Menu opacity</string>
|
<string name="read_menu_blur_alpha">Menu opacity</string>
|
||||||
|
<string name="read_menu_blur_color">Blur tint color</string>
|
||||||
<string name="read_menu_border">Border</string>
|
<string name="read_menu_border">Border</string>
|
||||||
<string name="read_menu_border_width">Width</string>
|
<string name="read_menu_border_width">Width</string>
|
||||||
<string name="read_menu_border_color">Color</string>
|
<string name="read_menu_border_color">Color</string>
|
||||||
|
|||||||
Reference in new issue
Block a user