Merge pull request #1506 from lalala-12138/feature/text-select-menu-filter
Feature/text select menu filter
This commit is contained in:
@@ -132,6 +132,8 @@ object PreferKey {
|
||||
const val brightness = "brightness"
|
||||
const val nightBrightness = "nightBrightness"
|
||||
const val expandTextMenu = "expandTextMenu"
|
||||
const val showSelectMenuIcon = "showSelectMenuIcon"
|
||||
const val textSelectMenuFilter = "textSelectMenuFilter"
|
||||
const val doublePageHorizontal = "doubleHorizontalPage"
|
||||
const val readUrlOpenInBrowser = "readUrlInBrowser"
|
||||
const val defaultBookTreeUri = "defaultBookTreeUri"
|
||||
|
||||
@@ -51,6 +51,8 @@ data class ReadPreferences(
|
||||
val optimizeRender: Boolean = false,
|
||||
val disableReturnKey: Boolean = false,
|
||||
val expandTextMenu: Boolean = false,
|
||||
val showSelectMenuIcon: Boolean = true,
|
||||
val textSelectMenuFilter: String = "",
|
||||
val showReadTitleAddition: Boolean = true,
|
||||
val autoReadSpeed: Int = 10,
|
||||
val prevKeys: String = "",
|
||||
@@ -230,6 +232,12 @@ class ReadSettingsRepository(
|
||||
suspend fun setExpandTextMenu(value: Boolean) =
|
||||
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) =
|
||||
settingsRepository.putBoolean(PreferKey.showReadTitleAddition, value)
|
||||
|
||||
@@ -420,6 +428,8 @@ class ReadSettingsRepository(
|
||||
optimizeRender = this[Keys.OptimizeRender] ?: false,
|
||||
disableReturnKey = this[Keys.DisableReturnKey] ?: false,
|
||||
expandTextMenu = this[Keys.ExpandTextMenu] ?: false,
|
||||
showSelectMenuIcon = this[Keys.ShowSelectMenuIcon] ?: true,
|
||||
textSelectMenuFilter = this[Keys.TextSelectMenuFilter] ?: "",
|
||||
showReadTitleAddition = this[Keys.ShowReadTitleAddition] ?: true,
|
||||
autoReadSpeed = this[Keys.AutoReadSpeed] ?: 10,
|
||||
prevKeys = this[Keys.PrevKeys] ?: "",
|
||||
@@ -518,6 +528,8 @@ class ReadSettingsRepository(
|
||||
val OptimizeRender = booleanPreferencesKey(PreferKey.optimizeRender)
|
||||
val DisableReturnKey = booleanPreferencesKey(PreferKey.disableReturnKey)
|
||||
val ExpandTextMenu = booleanPreferencesKey(PreferKey.expandTextMenu)
|
||||
val ShowSelectMenuIcon = booleanPreferencesKey(PreferKey.showSelectMenuIcon)
|
||||
val TextSelectMenuFilter = stringPreferencesKey(PreferKey.textSelectMenuFilter)
|
||||
val ShowReadTitleAddition = booleanPreferencesKey(PreferKey.showReadTitleAddition)
|
||||
val AutoReadSpeed = intPreferencesKey(PreferKey.autoReadSpeed)
|
||||
val PrevKeys = stringPreferencesKey(PreferKey.prevKeys)
|
||||
|
||||
@@ -684,6 +684,7 @@ sealed interface ReadBookSheet {
|
||||
data object AudioCacheCleanConfig : ReadBookSheet
|
||||
data object ClickActionConfig : ReadBookSheet
|
||||
data object PageKeyConfig : ReadBookSheet
|
||||
data object TextSelectMenuFilterConfig : ReadBookSheet
|
||||
data object InfoConfig : ReadBookSheet
|
||||
data class Dict(val word: String) : ReadBookSheet
|
||||
data class Bookmark(
|
||||
@@ -1197,6 +1198,12 @@ sealed interface ConfigUpdate {
|
||||
data class ExpandTextMenu(val value: Boolean) : ConfigUpdate {
|
||||
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 {
|
||||
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.changeSource.ChangeSourceSheet
|
||||
import io.legado.app.ui.widget.components.log.AppLogSheet
|
||||
import io.legado.app.ui.config.readConfig.TextSelectMenuFilterSheet
|
||||
import io.legado.app.utils.toastOnUi
|
||||
import kotlinx.coroutines.flow.collectLatest
|
||||
|
||||
@@ -243,6 +244,10 @@ fun ReadBookScreen(
|
||||
onIntent(ReadBookIntent.DismissSheet)
|
||||
onIntent(ReadBookIntent.ShowSheet(ReadBookSheet.PageKeyConfig))
|
||||
},
|
||||
onOpenTextSelectMenuFilterConfig = {
|
||||
onIntent(ReadBookIntent.DismissSheet)
|
||||
onIntent(ReadBookIntent.ShowSheet(ReadBookSheet.TextSelectMenuFilterConfig))
|
||||
},
|
||||
)
|
||||
ReadAloudConfigSheet(
|
||||
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 -> {
|
||||
PageAnimConfigSheet(
|
||||
onDismissRequest = dismissSheet,
|
||||
|
||||
@@ -3479,6 +3479,18 @@ class ReadBookViewModel(
|
||||
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 -> {
|
||||
ReadConfig.showReadTitleAddition = update.value
|
||||
viewModelScope.launch {
|
||||
|
||||
@@ -23,6 +23,7 @@ import io.legado.app.constant.AppLog
|
||||
import io.legado.app.databinding.ItemTextBinding
|
||||
import io.legado.app.databinding.PopupActionMenuBinding
|
||||
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.isAbsUrl
|
||||
import io.legado.app.utils.printOnDebug
|
||||
@@ -44,9 +45,10 @@ class TextActionMenu(
|
||||
setHasStableIds(true)
|
||||
}
|
||||
|
||||
private val menuItems: List<MenuItemImpl>
|
||||
private var menuItems: List<MenuItemImpl> = emptyList()
|
||||
private val visibleMenuItems = arrayListOf<MenuItemImpl>()
|
||||
private val moreMenuItems = arrayListOf<MenuItemImpl>()
|
||||
private val myMenu = MenuBuilder(context)
|
||||
|
||||
init {
|
||||
@SuppressLint("InflateParams")
|
||||
@@ -57,13 +59,7 @@ class TextActionMenu(
|
||||
isFocusable = false
|
||||
animationStyle = R.style.TextActionMenuAnimation
|
||||
|
||||
val myMenu = MenuBuilder(context)
|
||||
val otherMenu = MenuBuilder(context)
|
||||
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.recyclerViewMore.adapter = adapter
|
||||
setOnDismissListener {
|
||||
@@ -91,6 +87,18 @@ class TextActionMenu(
|
||||
}
|
||||
|
||||
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()) {
|
||||
adapter.setItems(menuItems)
|
||||
binding.ivMenuMore.gone()
|
||||
@@ -172,6 +180,15 @@ class TextActionMenu(
|
||||
) {
|
||||
with(binding) {
|
||||
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) {
|
||||
kotlin.runCatching {
|
||||
var menuItemOrder = 100
|
||||
val pm = context.packageManager
|
||||
val filterSet = ReadConfig.textSelectMenuFilter.split(",").filter { it.isNotEmpty() }.toSet()
|
||||
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,
|
||||
menuItemOrder++, resolveInfo.loadLabel(context.packageManager)
|
||||
).intent = createProcessTextIntentForResolveInfo(resolveInfo)
|
||||
menuItemOrder++, resolveInfo.loadLabel(pm)
|
||||
)
|
||||
menuItem.intent = createProcessTextIntentForResolveInfo(resolveInfo)
|
||||
if (ReadConfig.showSelectMenuIcon) {
|
||||
menuItem.icon = kotlin.runCatching {
|
||||
resolveInfo.loadIcon(pm)
|
||||
}.getOrNull()
|
||||
}
|
||||
}
|
||||
}.onFailure {
|
||||
context.toastOnUi("获取文字操作菜单出错:${it.localizedMessage}")
|
||||
|
||||
@@ -31,6 +31,7 @@ fun MoreConfigSheet(
|
||||
onIntent: (ReadBookIntent) -> Unit,
|
||||
onOpenClickRegionalConfig: () -> Unit,
|
||||
onOpenPageKeyConfig: () -> Unit,
|
||||
onOpenTextSelectMenuFilterConfig: () -> Unit,
|
||||
) {
|
||||
val readSettingsRepository: ReadSettingsRepository = koinInject()
|
||||
val preferences by readSettingsRepository.preferences.collectAsStateWithLifecycle(
|
||||
@@ -137,13 +138,17 @@ fun MoreConfigSheet(
|
||||
onIntent(ReadBookIntent.UpdateConfig(ConfigUpdate.ClickImgWay(it)))
|
||||
},
|
||||
onOpenClickRegionalConfig = onOpenClickRegionalConfig,
|
||||
onOpenPageKeyConfig = onOpenPageKeyConfig,
|
||||
onOpenTextSelectMenuFilterConfig = onOpenTextSelectMenuFilterConfig,
|
||||
onDisableReturnKeyChange = {
|
||||
onIntent(ReadBookIntent.UpdateConfig(ConfigUpdate.DisableReturnKey(it)))
|
||||
},
|
||||
onOpenPageKeyConfig = onOpenPageKeyConfig,
|
||||
onExpandTextMenuChange = {
|
||||
onIntent(ReadBookIntent.UpdateConfig(ConfigUpdate.ExpandTextMenu(it)))
|
||||
},
|
||||
onShowSelectMenuIconChange = {
|
||||
onIntent(ReadBookIntent.UpdateConfig(ConfigUpdate.ShowSelectMenuIcon(it)))
|
||||
},
|
||||
onShowReadTitleAdditionChange = {
|
||||
onIntent(ReadBookIntent.UpdateConfig(ConfigUpdate.ShowReadTitleAddition(it)))
|
||||
},
|
||||
@@ -300,7 +305,9 @@ private fun OtherSettings(
|
||||
onOpenClickRegionalConfig: () -> Unit,
|
||||
onDisableReturnKeyChange: (Boolean) -> Unit,
|
||||
onOpenPageKeyConfig: () -> Unit,
|
||||
onOpenTextSelectMenuFilterConfig: () -> Unit,
|
||||
onExpandTextMenuChange: (Boolean) -> Unit,
|
||||
onShowSelectMenuIconChange: (Boolean) -> Unit,
|
||||
onShowReadTitleAdditionChange: (Boolean) -> Unit,
|
||||
onShowMenuIconChange: (Boolean) -> Unit,
|
||||
) {
|
||||
@@ -357,11 +364,20 @@ private fun OtherSettings(
|
||||
title = stringResource(R.string.custom_page_key),
|
||||
onClick = onOpenPageKeyConfig,
|
||||
)
|
||||
TinyClickableSettingItem(
|
||||
title = stringResource(R.string.text_select_menu_filter),
|
||||
onClick = onOpenTextSelectMenuFilterConfig,
|
||||
)
|
||||
TinySwitchSettingItem(
|
||||
title = stringResource(R.string.expand_text_menu),
|
||||
checked = preferences.expandTextMenu,
|
||||
onCheckedChange = onExpandTextMenuChange,
|
||||
)
|
||||
TinySwitchSettingItem(
|
||||
title = stringResource(R.string.show_select_menu_icon),
|
||||
checked = preferences.showSelectMenuIcon,
|
||||
onCheckedChange = onShowSelectMenuIconChange,
|
||||
)
|
||||
TinySwitchSettingItem(
|
||||
title = stringResource(R.string.show_read_title_addition),
|
||||
checked = preferences.showReadTitleAddition,
|
||||
|
||||
@@ -84,6 +84,12 @@ object ReadConfig {
|
||||
var expandTextMenu
|
||||
get() = ReadMenuConfig.expandTextMenu
|
||||
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
|
||||
get() = ReadMenuConfig.showReadTitleAddition
|
||||
set(value) { ReadMenuConfig.showReadTitleAddition = value }
|
||||
@@ -264,6 +270,8 @@ object ReadConfig {
|
||||
readBarStyle = preferences.readBarStyle
|
||||
progressBarBehavior = preferences.progressBarBehavior
|
||||
expandTextMenu = preferences.expandTextMenu
|
||||
showSelectMenuIcon = preferences.showSelectMenuIcon
|
||||
textSelectMenuFilter = preferences.textSelectMenuFilter
|
||||
showReadTitleAddition = preferences.showReadTitleAddition
|
||||
showMenuIcon = preferences.showMenuIcon
|
||||
clickActionTL = preferences.clickActionTL
|
||||
|
||||
@@ -35,6 +35,8 @@ data class ReadConfigUiState(
|
||||
val optimizeRender: Boolean = false,
|
||||
val disableReturnKey: Boolean = false,
|
||||
val expandTextMenu: Boolean = false,
|
||||
val showSelectMenuIcon: Boolean = true,
|
||||
val textSelectMenuFilter: String = "",
|
||||
val showReadTitleAddition: Boolean = true,
|
||||
val autoReadSpeed: Int = 10,
|
||||
val prevKeys: String = "",
|
||||
@@ -76,6 +78,8 @@ sealed interface ReadConfigIntent {
|
||||
data class OptimizeRenderChanged(val value: Boolean) : ReadConfigIntent
|
||||
data class DisableReturnKeyChanged(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 ShowMenuIconChanged(val value: Boolean) : 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(
|
||||
title = stringResource(R.string.show_read_title_addition),
|
||||
checked = state.showReadTitleAddition,
|
||||
|
||||
@@ -197,6 +197,16 @@ class ReadConfigViewModel(
|
||||
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 -> {
|
||||
ReadConfig.showReadTitleAddition = intent.value
|
||||
readSettingsRepository.setShowReadTitleAddition(intent.value)
|
||||
@@ -263,6 +273,8 @@ class ReadConfigViewModel(
|
||||
optimizeRender = optimizeRender,
|
||||
disableReturnKey = disableReturnKey,
|
||||
expandTextMenu = expandTextMenu,
|
||||
showSelectMenuIcon = showSelectMenuIcon,
|
||||
textSelectMenuFilter = textSelectMenuFilter,
|
||||
showReadTitleAddition = showReadTitleAddition,
|
||||
autoReadSpeed = autoReadSpeed,
|
||||
prevKeys = prevKeys,
|
||||
|
||||
@@ -40,6 +40,16 @@ object ReadMenuConfig {
|
||||
false
|
||||
)
|
||||
|
||||
var showSelectMenuIcon by prefDelegate(
|
||||
PreferKey.showSelectMenuIcon,
|
||||
true
|
||||
)
|
||||
|
||||
var textSelectMenuFilter by prefDelegate(
|
||||
PreferKey.textSelectMenuFilter,
|
||||
""
|
||||
)
|
||||
|
||||
var showReadTitleAddition by prefDelegate(
|
||||
PreferKey.showReadTitleAddition,
|
||||
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_doc_picker_error">打开系统文件选择器出错,将自动打开应用文件选择器</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_s">从其它应用打开的书籍保存位置</string>
|
||||
<string name="select_book_folder">选择保存书籍的文件夹</string>
|
||||
|
||||
@@ -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_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="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_s">Save location for books opened from other apps</string>
|
||||
<string name="select_book_folder">Select the folder where the books are saved</string>
|
||||
|
||||
Reference in New Issue
Block a user