Merge pull request #1506 from lalala-12138/feature/text-select-menu-filter

Feature/text select menu filter
This commit is contained in:
Kudomaga
2026-06-21 00:35:36 +08:00
committed by GitHub
15 changed files with 349 additions and 11 deletions
@@ -132,6 +132,8 @@ object PreferKey {
const val brightness = "brightness" const val brightness = "brightness"
const val nightBrightness = "nightBrightness" const val nightBrightness = "nightBrightness"
const val expandTextMenu = "expandTextMenu" const val expandTextMenu = "expandTextMenu"
const val showSelectMenuIcon = "showSelectMenuIcon"
const val textSelectMenuFilter = "textSelectMenuFilter"
const val doublePageHorizontal = "doubleHorizontalPage" const val doublePageHorizontal = "doubleHorizontalPage"
const val readUrlOpenInBrowser = "readUrlInBrowser" const val readUrlOpenInBrowser = "readUrlInBrowser"
const val defaultBookTreeUri = "defaultBookTreeUri" const val defaultBookTreeUri = "defaultBookTreeUri"
@@ -51,6 +51,8 @@ data class ReadPreferences(
val optimizeRender: Boolean = false, val optimizeRender: Boolean = false,
val disableReturnKey: Boolean = false, val disableReturnKey: Boolean = false,
val expandTextMenu: Boolean = false, val expandTextMenu: Boolean = false,
val showSelectMenuIcon: Boolean = true,
val textSelectMenuFilter: String = "",
val showReadTitleAddition: Boolean = true, val showReadTitleAddition: Boolean = true,
val autoReadSpeed: Int = 10, val autoReadSpeed: Int = 10,
val prevKeys: String = "", val prevKeys: String = "",
@@ -230,6 +232,12 @@ class ReadSettingsRepository(
suspend fun setExpandTextMenu(value: Boolean) = suspend fun setExpandTextMenu(value: Boolean) =
settingsRepository.putBoolean(PreferKey.expandTextMenu, value) settingsRepository.putBoolean(PreferKey.expandTextMenu, value)
suspend fun setShowSelectMenuIcon(value: Boolean) =
settingsRepository.putBoolean(PreferKey.showSelectMenuIcon, value)
suspend fun setTextSelectMenuFilter(value: String) =
settingsRepository.putString(PreferKey.textSelectMenuFilter, value)
suspend fun setShowReadTitleAddition(value: Boolean) = suspend fun setShowReadTitleAddition(value: Boolean) =
settingsRepository.putBoolean(PreferKey.showReadTitleAddition, value) settingsRepository.putBoolean(PreferKey.showReadTitleAddition, value)
@@ -420,6 +428,8 @@ class ReadSettingsRepository(
optimizeRender = this[Keys.OptimizeRender] ?: false, optimizeRender = this[Keys.OptimizeRender] ?: false,
disableReturnKey = this[Keys.DisableReturnKey] ?: false, disableReturnKey = this[Keys.DisableReturnKey] ?: false,
expandTextMenu = this[Keys.ExpandTextMenu] ?: false, expandTextMenu = this[Keys.ExpandTextMenu] ?: false,
showSelectMenuIcon = this[Keys.ShowSelectMenuIcon] ?: true,
textSelectMenuFilter = this[Keys.TextSelectMenuFilter] ?: "",
showReadTitleAddition = this[Keys.ShowReadTitleAddition] ?: true, showReadTitleAddition = this[Keys.ShowReadTitleAddition] ?: true,
autoReadSpeed = this[Keys.AutoReadSpeed] ?: 10, autoReadSpeed = this[Keys.AutoReadSpeed] ?: 10,
prevKeys = this[Keys.PrevKeys] ?: "", prevKeys = this[Keys.PrevKeys] ?: "",
@@ -518,6 +528,8 @@ class ReadSettingsRepository(
val OptimizeRender = booleanPreferencesKey(PreferKey.optimizeRender) val OptimizeRender = booleanPreferencesKey(PreferKey.optimizeRender)
val DisableReturnKey = booleanPreferencesKey(PreferKey.disableReturnKey) val DisableReturnKey = booleanPreferencesKey(PreferKey.disableReturnKey)
val ExpandTextMenu = booleanPreferencesKey(PreferKey.expandTextMenu) val ExpandTextMenu = booleanPreferencesKey(PreferKey.expandTextMenu)
val ShowSelectMenuIcon = booleanPreferencesKey(PreferKey.showSelectMenuIcon)
val TextSelectMenuFilter = stringPreferencesKey(PreferKey.textSelectMenuFilter)
val ShowReadTitleAddition = booleanPreferencesKey(PreferKey.showReadTitleAddition) val ShowReadTitleAddition = booleanPreferencesKey(PreferKey.showReadTitleAddition)
val AutoReadSpeed = intPreferencesKey(PreferKey.autoReadSpeed) val AutoReadSpeed = intPreferencesKey(PreferKey.autoReadSpeed)
val PrevKeys = stringPreferencesKey(PreferKey.prevKeys) val PrevKeys = stringPreferencesKey(PreferKey.prevKeys)
@@ -684,6 +684,7 @@ sealed interface ReadBookSheet {
data object AudioCacheCleanConfig : ReadBookSheet data object AudioCacheCleanConfig : ReadBookSheet
data object ClickActionConfig : ReadBookSheet data object ClickActionConfig : ReadBookSheet
data object PageKeyConfig : ReadBookSheet data object PageKeyConfig : ReadBookSheet
data object TextSelectMenuFilterConfig : ReadBookSheet
data object InfoConfig : ReadBookSheet data object InfoConfig : ReadBookSheet
data class Dict(val word: String) : ReadBookSheet data class Dict(val word: String) : ReadBookSheet
data class Bookmark( data class Bookmark(
@@ -1197,6 +1198,12 @@ sealed interface ConfigUpdate {
data class ExpandTextMenu(val value: Boolean) : ConfigUpdate { data class ExpandTextMenu(val value: Boolean) : ConfigUpdate {
override val actions = emptySet<ConfigUpdateAction>() override val actions = emptySet<ConfigUpdateAction>()
} }
data class ShowSelectMenuIcon(val value: Boolean) : ConfigUpdate {
override val actions = emptySet<ConfigUpdateAction>()
}
data class TextSelectMenuFilter(val value: String) : ConfigUpdate {
override val actions = emptySet<ConfigUpdateAction>()
}
data class ShowReadTitleAddition(val value: Boolean) : ConfigUpdate { data class ShowReadTitleAddition(val value: Boolean) : ConfigUpdate {
override val actions = emptySet<ConfigUpdateAction>() override val actions = emptySet<ConfigUpdateAction>()
} }
@@ -41,6 +41,7 @@ import io.legado.app.ui.widget.components.FontSelectSheet
import io.legado.app.ui.widget.components.alert.AppAlertDialog import io.legado.app.ui.widget.components.alert.AppAlertDialog
import io.legado.app.ui.widget.components.changeSource.ChangeSourceSheet import io.legado.app.ui.widget.components.changeSource.ChangeSourceSheet
import io.legado.app.ui.widget.components.log.AppLogSheet import io.legado.app.ui.widget.components.log.AppLogSheet
import io.legado.app.ui.config.readConfig.TextSelectMenuFilterSheet
import io.legado.app.utils.toastOnUi import io.legado.app.utils.toastOnUi
import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.flow.collectLatest
@@ -243,6 +244,10 @@ fun ReadBookScreen(
onIntent(ReadBookIntent.DismissSheet) onIntent(ReadBookIntent.DismissSheet)
onIntent(ReadBookIntent.ShowSheet(ReadBookSheet.PageKeyConfig)) onIntent(ReadBookIntent.ShowSheet(ReadBookSheet.PageKeyConfig))
}, },
onOpenTextSelectMenuFilterConfig = {
onIntent(ReadBookIntent.DismissSheet)
onIntent(ReadBookIntent.ShowSheet(ReadBookSheet.TextSelectMenuFilterConfig))
},
) )
ReadAloudConfigSheet( ReadAloudConfigSheet(
show = state.activeSheet is ReadBookSheet.ReadAloudConfig, show = state.activeSheet is ReadBookSheet.ReadAloudConfig,
@@ -337,6 +342,16 @@ fun ReadBookScreen(
) )
} }
is ReadBookSheet.TextSelectMenuFilterConfig -> {
TextSelectMenuFilterSheet(
show = true,
onDismissRequest = dismissSheet,
onFilterChanged = {
onIntent(ReadBookIntent.UpdateConfig(ConfigUpdate.TextSelectMenuFilter(it)))
}
)
}
is ReadBookSheet.PageAnim -> { is ReadBookSheet.PageAnim -> {
PageAnimConfigSheet( PageAnimConfigSheet(
onDismissRequest = dismissSheet, onDismissRequest = dismissSheet,
@@ -3479,6 +3479,18 @@ class ReadBookViewModel(
readSettingsRepository.setExpandTextMenu(update.value) readSettingsRepository.setExpandTextMenu(update.value)
} }
} }
is ConfigUpdate.ShowSelectMenuIcon -> {
ReadConfig.showSelectMenuIcon = update.value
viewModelScope.launch {
readSettingsRepository.setShowSelectMenuIcon(update.value)
}
}
is ConfigUpdate.TextSelectMenuFilter -> {
ReadConfig.textSelectMenuFilter = update.value
viewModelScope.launch {
readSettingsRepository.setTextSelectMenuFilter(update.value)
}
}
is ConfigUpdate.ShowReadTitleAddition -> { is ConfigUpdate.ShowReadTitleAddition -> {
ReadConfig.showReadTitleAddition = update.value ReadConfig.showReadTitleAddition = update.value
viewModelScope.launch { viewModelScope.launch {
@@ -23,6 +23,7 @@ import io.legado.app.constant.AppLog
import io.legado.app.databinding.ItemTextBinding import io.legado.app.databinding.ItemTextBinding
import io.legado.app.databinding.PopupActionMenuBinding import io.legado.app.databinding.PopupActionMenuBinding
import io.legado.app.ui.config.readConfig.ReadConfig import io.legado.app.ui.config.readConfig.ReadConfig
import io.legado.app.utils.dpToPx
import io.legado.app.utils.gone import io.legado.app.utils.gone
import io.legado.app.utils.isAbsUrl import io.legado.app.utils.isAbsUrl
import io.legado.app.utils.printOnDebug import io.legado.app.utils.printOnDebug
@@ -44,9 +45,10 @@ class TextActionMenu(
setHasStableIds(true) setHasStableIds(true)
} }
private val menuItems: List<MenuItemImpl> private var menuItems: List<MenuItemImpl> = emptyList()
private val visibleMenuItems = arrayListOf<MenuItemImpl>() private val visibleMenuItems = arrayListOf<MenuItemImpl>()
private val moreMenuItems = arrayListOf<MenuItemImpl>() private val moreMenuItems = arrayListOf<MenuItemImpl>()
private val myMenu = MenuBuilder(context)
init { init {
@SuppressLint("InflateParams") @SuppressLint("InflateParams")
@@ -57,13 +59,7 @@ class TextActionMenu(
isFocusable = false isFocusable = false
animationStyle = R.style.TextActionMenuAnimation animationStyle = R.style.TextActionMenuAnimation
val myMenu = MenuBuilder(context)
val otherMenu = MenuBuilder(context)
SupportMenuInflater(context).inflate(R.menu.content_select_action, myMenu) SupportMenuInflater(context).inflate(R.menu.content_select_action, myMenu)
onInitializeMenu(otherMenu)
menuItems = myMenu.visibleItems + otherMenu.visibleItems
visibleMenuItems.addAll(menuItems.subList(0, 6))
moreMenuItems.addAll(menuItems.subList(6, menuItems.size))
binding.recyclerView.adapter = adapter binding.recyclerView.adapter = adapter
binding.recyclerViewMore.adapter = adapter binding.recyclerViewMore.adapter = adapter
setOnDismissListener { setOnDismissListener {
@@ -91,6 +87,18 @@ class TextActionMenu(
} }
fun upMenu() { fun upMenu() {
val otherMenu = MenuBuilder(context)
onInitializeMenu(otherMenu)
menuItems = myMenu.visibleItems + otherMenu.visibleItems
visibleMenuItems.clear()
moreMenuItems.clear()
if (menuItems.size > 6) {
visibleMenuItems.addAll(menuItems.subList(0, 6))
moreMenuItems.addAll(menuItems.subList(6, menuItems.size))
} else {
visibleMenuItems.addAll(menuItems)
}
if (expandTextMenu()) { if (expandTextMenu()) {
adapter.setItems(menuItems) adapter.setItems(menuItems)
binding.ivMenuMore.gone() binding.ivMenuMore.gone()
@@ -172,6 +180,15 @@ class TextActionMenu(
) { ) {
with(binding) { with(binding) {
textView.text = item.title textView.text = item.title
val icon = item.icon
if (icon != null && ReadConfig.showSelectMenuIcon) {
val size = 18.dpToPx()
icon.setBounds(0, 0, size, size)
textView.setCompoundDrawables(icon, null, null, null)
textView.compoundDrawablePadding = 6.dpToPx()
} else {
textView.setCompoundDrawables(null, null, null, null)
}
} }
} }
@@ -255,11 +272,23 @@ class TextActionMenu(
private fun onInitializeMenu(menu: Menu) { private fun onInitializeMenu(menu: Menu) {
kotlin.runCatching { kotlin.runCatching {
var menuItemOrder = 100 var menuItemOrder = 100
val pm = context.packageManager
val filterSet = ReadConfig.textSelectMenuFilter.split(",").filter { it.isNotEmpty() }.toSet()
for (resolveInfo in getSupportedActivities()) { for (resolveInfo in getSupportedActivities()) {
menu.add( val componentName = "${resolveInfo.activityInfo.packageName}/${resolveInfo.activityInfo.name}"
if (filterSet.contains(componentName)) {
continue
}
val menuItem = menu.add(
Menu.NONE, Menu.NONE, Menu.NONE, Menu.NONE,
menuItemOrder++, resolveInfo.loadLabel(context.packageManager) menuItemOrder++, resolveInfo.loadLabel(pm)
).intent = createProcessTextIntentForResolveInfo(resolveInfo) )
menuItem.intent = createProcessTextIntentForResolveInfo(resolveInfo)
if (ReadConfig.showSelectMenuIcon) {
menuItem.icon = kotlin.runCatching {
resolveInfo.loadIcon(pm)
}.getOrNull()
}
} }
}.onFailure { }.onFailure {
context.toastOnUi("获取文字操作菜单出错:${it.localizedMessage}") context.toastOnUi("获取文字操作菜单出错:${it.localizedMessage}")
@@ -31,6 +31,7 @@ fun MoreConfigSheet(
onIntent: (ReadBookIntent) -> Unit, onIntent: (ReadBookIntent) -> Unit,
onOpenClickRegionalConfig: () -> Unit, onOpenClickRegionalConfig: () -> Unit,
onOpenPageKeyConfig: () -> Unit, onOpenPageKeyConfig: () -> Unit,
onOpenTextSelectMenuFilterConfig: () -> Unit,
) { ) {
val readSettingsRepository: ReadSettingsRepository = koinInject() val readSettingsRepository: ReadSettingsRepository = koinInject()
val preferences by readSettingsRepository.preferences.collectAsStateWithLifecycle( val preferences by readSettingsRepository.preferences.collectAsStateWithLifecycle(
@@ -137,13 +138,17 @@ fun MoreConfigSheet(
onIntent(ReadBookIntent.UpdateConfig(ConfigUpdate.ClickImgWay(it))) onIntent(ReadBookIntent.UpdateConfig(ConfigUpdate.ClickImgWay(it)))
}, },
onOpenClickRegionalConfig = onOpenClickRegionalConfig, onOpenClickRegionalConfig = onOpenClickRegionalConfig,
onOpenPageKeyConfig = onOpenPageKeyConfig,
onOpenTextSelectMenuFilterConfig = onOpenTextSelectMenuFilterConfig,
onDisableReturnKeyChange = { onDisableReturnKeyChange = {
onIntent(ReadBookIntent.UpdateConfig(ConfigUpdate.DisableReturnKey(it))) onIntent(ReadBookIntent.UpdateConfig(ConfigUpdate.DisableReturnKey(it)))
}, },
onOpenPageKeyConfig = onOpenPageKeyConfig,
onExpandTextMenuChange = { onExpandTextMenuChange = {
onIntent(ReadBookIntent.UpdateConfig(ConfigUpdate.ExpandTextMenu(it))) onIntent(ReadBookIntent.UpdateConfig(ConfigUpdate.ExpandTextMenu(it)))
}, },
onShowSelectMenuIconChange = {
onIntent(ReadBookIntent.UpdateConfig(ConfigUpdate.ShowSelectMenuIcon(it)))
},
onShowReadTitleAdditionChange = { onShowReadTitleAdditionChange = {
onIntent(ReadBookIntent.UpdateConfig(ConfigUpdate.ShowReadTitleAddition(it))) onIntent(ReadBookIntent.UpdateConfig(ConfigUpdate.ShowReadTitleAddition(it)))
}, },
@@ -300,7 +305,9 @@ private fun OtherSettings(
onOpenClickRegionalConfig: () -> Unit, onOpenClickRegionalConfig: () -> Unit,
onDisableReturnKeyChange: (Boolean) -> Unit, onDisableReturnKeyChange: (Boolean) -> Unit,
onOpenPageKeyConfig: () -> Unit, onOpenPageKeyConfig: () -> Unit,
onOpenTextSelectMenuFilterConfig: () -> Unit,
onExpandTextMenuChange: (Boolean) -> Unit, onExpandTextMenuChange: (Boolean) -> Unit,
onShowSelectMenuIconChange: (Boolean) -> Unit,
onShowReadTitleAdditionChange: (Boolean) -> Unit, onShowReadTitleAdditionChange: (Boolean) -> Unit,
onShowMenuIconChange: (Boolean) -> Unit, onShowMenuIconChange: (Boolean) -> Unit,
) { ) {
@@ -357,11 +364,20 @@ private fun OtherSettings(
title = stringResource(R.string.custom_page_key), title = stringResource(R.string.custom_page_key),
onClick = onOpenPageKeyConfig, onClick = onOpenPageKeyConfig,
) )
TinyClickableSettingItem(
title = stringResource(R.string.text_select_menu_filter),
onClick = onOpenTextSelectMenuFilterConfig,
)
TinySwitchSettingItem( TinySwitchSettingItem(
title = stringResource(R.string.expand_text_menu), title = stringResource(R.string.expand_text_menu),
checked = preferences.expandTextMenu, checked = preferences.expandTextMenu,
onCheckedChange = onExpandTextMenuChange, onCheckedChange = onExpandTextMenuChange,
) )
TinySwitchSettingItem(
title = stringResource(R.string.show_select_menu_icon),
checked = preferences.showSelectMenuIcon,
onCheckedChange = onShowSelectMenuIconChange,
)
TinySwitchSettingItem( TinySwitchSettingItem(
title = stringResource(R.string.show_read_title_addition), title = stringResource(R.string.show_read_title_addition),
checked = preferences.showReadTitleAddition, checked = preferences.showReadTitleAddition,
@@ -84,6 +84,12 @@ object ReadConfig {
var expandTextMenu var expandTextMenu
get() = ReadMenuConfig.expandTextMenu get() = ReadMenuConfig.expandTextMenu
set(value) { ReadMenuConfig.expandTextMenu = value } set(value) { ReadMenuConfig.expandTextMenu = value }
var showSelectMenuIcon
get() = ReadMenuConfig.showSelectMenuIcon
set(value) { ReadMenuConfig.showSelectMenuIcon = value }
var textSelectMenuFilter
get() = ReadMenuConfig.textSelectMenuFilter
set(value) { ReadMenuConfig.textSelectMenuFilter = value }
var showReadTitleAddition var showReadTitleAddition
get() = ReadMenuConfig.showReadTitleAddition get() = ReadMenuConfig.showReadTitleAddition
set(value) { ReadMenuConfig.showReadTitleAddition = value } set(value) { ReadMenuConfig.showReadTitleAddition = value }
@@ -264,6 +270,8 @@ object ReadConfig {
readBarStyle = preferences.readBarStyle readBarStyle = preferences.readBarStyle
progressBarBehavior = preferences.progressBarBehavior progressBarBehavior = preferences.progressBarBehavior
expandTextMenu = preferences.expandTextMenu expandTextMenu = preferences.expandTextMenu
showSelectMenuIcon = preferences.showSelectMenuIcon
textSelectMenuFilter = preferences.textSelectMenuFilter
showReadTitleAddition = preferences.showReadTitleAddition showReadTitleAddition = preferences.showReadTitleAddition
showMenuIcon = preferences.showMenuIcon showMenuIcon = preferences.showMenuIcon
clickActionTL = preferences.clickActionTL clickActionTL = preferences.clickActionTL
@@ -35,6 +35,8 @@ data class ReadConfigUiState(
val optimizeRender: Boolean = false, val optimizeRender: Boolean = false,
val disableReturnKey: Boolean = false, val disableReturnKey: Boolean = false,
val expandTextMenu: Boolean = false, val expandTextMenu: Boolean = false,
val showSelectMenuIcon: Boolean = true,
val textSelectMenuFilter: String = "",
val showReadTitleAddition: Boolean = true, val showReadTitleAddition: Boolean = true,
val autoReadSpeed: Int = 10, val autoReadSpeed: Int = 10,
val prevKeys: String = "", val prevKeys: String = "",
@@ -76,6 +78,8 @@ sealed interface ReadConfigIntent {
data class OptimizeRenderChanged(val value: Boolean) : ReadConfigIntent data class OptimizeRenderChanged(val value: Boolean) : ReadConfigIntent
data class DisableReturnKeyChanged(val value: Boolean) : ReadConfigIntent data class DisableReturnKeyChanged(val value: Boolean) : ReadConfigIntent
data class ExpandTextMenuChanged(val value: Boolean) : ReadConfigIntent data class ExpandTextMenuChanged(val value: Boolean) : ReadConfigIntent
data class ShowSelectMenuIconChanged(val value: Boolean) : ReadConfigIntent
data class TextSelectMenuFilterChanged(val value: String) : ReadConfigIntent
data class ShowReadTitleAdditionChanged(val value: Boolean) : ReadConfigIntent data class ShowReadTitleAdditionChanged(val value: Boolean) : ReadConfigIntent
data class ShowMenuIconChanged(val value: Boolean) : ReadConfigIntent data class ShowMenuIconChanged(val value: Boolean) : ReadConfigIntent
data class PageKeysChanged(val prevKeys: String, val nextKeys: String) : ReadConfigIntent data class PageKeysChanged(val prevKeys: String, val nextKeys: String) : ReadConfigIntent
@@ -369,6 +369,30 @@ fun ReadConfigScreen(
} }
) )
SwitchSettingItem(
title = stringResource(R.string.show_select_menu_icon),
checked = state.showSelectMenuIcon,
onCheckedChange = {
viewModel.onIntent(ReadConfigIntent.ShowSelectMenuIconChanged(it))
}
)
var showSelectMenuFilterSheet by remember { mutableStateOf(false) }
ClickableSettingItem(
title = stringResource(R.string.text_select_menu_filter),
description = stringResource(R.string.text_select_menu_filter_desc),
onClick = { showSelectMenuFilterSheet = true }
)
TextSelectMenuFilterSheet(
show = showSelectMenuFilterSheet,
onDismissRequest = { showSelectMenuFilterSheet = false },
onFilterChanged = {
viewModel.onIntent(ReadConfigIntent.TextSelectMenuFilterChanged(it))
}
)
SwitchSettingItem( SwitchSettingItem(
title = stringResource(R.string.show_read_title_addition), title = stringResource(R.string.show_read_title_addition),
checked = state.showReadTitleAddition, checked = state.showReadTitleAddition,
@@ -197,6 +197,16 @@ class ReadConfigViewModel(
readSettingsRepository.setExpandTextMenu(intent.value) readSettingsRepository.setExpandTextMenu(intent.value)
} }
is ReadConfigIntent.ShowSelectMenuIconChanged -> {
ReadConfig.showSelectMenuIcon = intent.value
readSettingsRepository.setShowSelectMenuIcon(intent.value)
}
is ReadConfigIntent.TextSelectMenuFilterChanged -> {
ReadConfig.textSelectMenuFilter = intent.value
readSettingsRepository.setTextSelectMenuFilter(intent.value)
}
is ReadConfigIntent.ShowReadTitleAdditionChanged -> { is ReadConfigIntent.ShowReadTitleAdditionChanged -> {
ReadConfig.showReadTitleAddition = intent.value ReadConfig.showReadTitleAddition = intent.value
readSettingsRepository.setShowReadTitleAddition(intent.value) readSettingsRepository.setShowReadTitleAddition(intent.value)
@@ -263,6 +273,8 @@ class ReadConfigViewModel(
optimizeRender = optimizeRender, optimizeRender = optimizeRender,
disableReturnKey = disableReturnKey, disableReturnKey = disableReturnKey,
expandTextMenu = expandTextMenu, expandTextMenu = expandTextMenu,
showSelectMenuIcon = showSelectMenuIcon,
textSelectMenuFilter = textSelectMenuFilter,
showReadTitleAddition = showReadTitleAddition, showReadTitleAddition = showReadTitleAddition,
autoReadSpeed = autoReadSpeed, autoReadSpeed = autoReadSpeed,
prevKeys = prevKeys, prevKeys = prevKeys,
@@ -40,6 +40,16 @@ object ReadMenuConfig {
false false
) )
var showSelectMenuIcon by prefDelegate(
PreferKey.showSelectMenuIcon,
true
)
var textSelectMenuFilter by prefDelegate(
PreferKey.textSelectMenuFilter,
""
)
var showReadTitleAddition by prefDelegate( var showReadTitleAddition by prefDelegate(
PreferKey.showReadTitleAddition, PreferKey.showReadTitleAddition,
true true
@@ -0,0 +1,175 @@
package io.legado.app.ui.config.readConfig
import android.content.Intent
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Check
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import coil.compose.AsyncImage
import io.legado.app.R
import io.legado.app.ui.theme.LegadoTheme
import io.legado.app.ui.widget.components.AdaptiveSwitch
import io.legado.app.ui.widget.components.button.series.SmallPlainButton
import io.legado.app.ui.widget.components.card.NormalCard
import io.legado.app.ui.widget.components.modalBottomSheet.AppModalBottomSheet
import io.legado.app.ui.widget.components.text.AppText
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun TextSelectMenuFilterSheet(
show: Boolean,
onDismissRequest: () -> Unit,
onFilterChanged: (String) -> Unit
) {
val context = LocalContext.current
val pm = context.packageManager
// 查询所有注册了 ACTION_PROCESS_TEXT 的第三方 Activity
var apps by remember { mutableStateOf<List<TextSelectMenuAppInfo>>(emptyList()) }
LaunchedEffect(show) {
if (show) {
val list = kotlinx.coroutines.withContext(kotlinx.coroutines.Dispatchers.IO) {
val intent = Intent().setAction(Intent.ACTION_PROCESS_TEXT).setType("text/plain")
pm.queryIntentActivities(intent, 0).map { resolveInfo ->
val title = resolveInfo.loadLabel(pm).toString()
val componentName = "${resolveInfo.activityInfo.packageName}/${resolveInfo.activityInfo.name}"
val icon = kotlin.runCatching { resolveInfo.loadIcon(pm) }.getOrNull()
TextSelectMenuAppInfo(title, componentName, icon)
}
}
apps = list
} else {
apps = emptyList()
}
}
var pendingFilterString by remember(show) {
mutableStateOf(ReadConfig.textSelectMenuFilter)
}
val disabledSet = remember(pendingFilterString) {
pendingFilterString.split(",").filter { it.isNotEmpty() }.toSet()
}
AppModalBottomSheet(
show = show,
onDismissRequest = onDismissRequest,
title = stringResource(R.string.text_select_menu_filter),
endAction = {
SmallPlainButton(
icon = Icons.Default.Check,
onClick = {
onFilterChanged(pendingFilterString)
onDismissRequest()
}
)
},
) {
Column(
modifier = Modifier
.fillMaxWidth()
.fillMaxHeight(0.8f)
.padding(horizontal = 16.dp, vertical = 8.dp)
) {
if (apps.isEmpty()) {
Box(
modifier = Modifier
.fillMaxWidth()
.weight(1f),
contentAlignment = Alignment.Center
) {
AppText(text = stringResource(R.string.no_apps_found))
}
} else {
LazyColumn(
modifier = Modifier.weight(1f),
verticalArrangement = Arrangement.spacedBy(8.dp)
) {
items(apps) { app ->
val isEnabled = !disabledSet.contains(app.componentName)
NormalCard(
onClick = {
val nextSet = if (isEnabled) {
disabledSet + app.componentName
} else {
disabledSet - app.componentName
}
pendingFilterString = nextSet.joinToString(",")
},
cornerRadius = 12.dp,
containerColor = LegadoTheme.colorScheme.surfaceContainerHigh,
) {
Row(
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = 8.dp, vertical = 12.dp),
verticalAlignment = Alignment.CenterVertically
) {
Box(
modifier = Modifier
.size(40.dp)
.padding(4.dp),
contentAlignment = Alignment.Center
) {
AsyncImage(
model = app.icon,
contentDescription = null,
modifier = Modifier.fillMaxSize()
)
}
Column(
modifier = Modifier
.weight(1f)
.padding(horizontal = 8.dp)
) {
AppText(
text = app.title,
style = LegadoTheme.typography.titleMedium
)
}
AdaptiveSwitch(
checked = isEnabled,
onCheckedChange = { checked ->
val nextSet = if (checked) {
disabledSet - app.componentName
} else {
disabledSet + app.componentName
}
pendingFilterString = nextSet.joinToString(",")
}
)
}
}
}
}
}
}
}
}
data class TextSelectMenuAppInfo(
val title: String,
val componentName: String,
val icon: android.graphics.drawable.Drawable?
)
@@ -1098,6 +1098,12 @@
<string name="open_sys_dir_picker_error">打开系统文件夹选择器出错,将自动打开应用文件夹选择器</string> <string name="open_sys_dir_picker_error">打开系统文件夹选择器出错,将自动打开应用文件夹选择器</string>
<string name="open_sys_doc_picker_error">打开系统文件选择器出错,将自动打开应用文件选择器</string> <string name="open_sys_doc_picker_error">打开系统文件选择器出错,将自动打开应用文件选择器</string>
<string name="expand_text_menu">展开文本选择菜单</string> <string name="expand_text_menu">展开文本选择菜单</string>
<string name="show_select_menu_icon">展示选择菜单图标</string>
<string name="text_select_menu_filter">选择菜单应用过滤</string>
<string name="text_select_menu_filter_desc">过滤文字选择操作菜单中显示的第三方应用</string>
<string name="show_all">全部显示</string>
<string name="hide_all">全不显示</string>
<string name="no_apps_found">未找到支持文字处理的第三方应用</string>
<string name="book_tree_uri_t">书籍保存位置</string> <string name="book_tree_uri_t">书籍保存位置</string>
<string name="book_tree_uri_s">从其它应用打开的书籍保存位置</string> <string name="book_tree_uri_s">从其它应用打开的书籍保存位置</string>
<string name="select_book_folder">选择保存书籍的文件夹</string> <string name="select_book_folder">选择保存书籍的文件夹</string>
+6
View File
@@ -1130,6 +1130,12 @@
<string name="open_sys_dir_picker_error">Error opening system folder selector, automatically open application folder selector</string> <string name="open_sys_dir_picker_error">Error opening system folder selector, automatically open application folder selector</string>
<string name="open_sys_doc_picker_error">Error opening system file selector, automatically open application file selector</string> <string name="open_sys_doc_picker_error">Error opening system file selector, automatically open application file selector</string>
<string name="expand_text_menu">Expand Text Selection Menu</string> <string name="expand_text_menu">Expand Text Selection Menu</string>
<string name="show_select_menu_icon">Show Text Selection Menu Icons</string>
<string name="text_select_menu_filter">Text Selection Menu Filter</string>
<string name="text_select_menu_filter_desc">Filter the third-party apps displayed in the selection menu</string>
<string name="show_all">Show All</string>
<string name="hide_all">Hide All</string>
<string name="no_apps_found">No third-party apps supporting text actions found</string>
<string name="book_tree_uri_t">Book Save Location</string> <string name="book_tree_uri_t">Book Save Location</string>
<string name="book_tree_uri_s">Save location for books opened from other apps</string> <string name="book_tree_uri_s">Save location for books opened from other apps</string>
<string name="select_book_folder">Select the folder where the books are saved</string> <string name="select_book_folder">Select the folder where the books are saved</string>