更加强劲的替换管理 #179
This commit is contained in:
@@ -8,6 +8,7 @@ import android.os.Bundle
|
|||||||
import android.view.Menu
|
import android.view.Menu
|
||||||
import android.view.MenuItem
|
import android.view.MenuItem
|
||||||
import android.view.MotionEvent
|
import android.view.MotionEvent
|
||||||
|
import androidx.activity.result.contract.ActivityResultContracts
|
||||||
import androidx.activity.viewModels
|
import androidx.activity.viewModels
|
||||||
import androidx.appcompat.widget.SearchView
|
import androidx.appcompat.widget.SearchView
|
||||||
import androidx.fragment.app.Fragment
|
import androidx.fragment.app.Fragment
|
||||||
@@ -22,12 +23,12 @@ import io.legado.app.help.book.isLocalTxt
|
|||||||
import io.legado.app.help.config.AppConfig
|
import io.legado.app.help.config.AppConfig
|
||||||
import io.legado.app.lib.dialogs.alert
|
import io.legado.app.lib.dialogs.alert
|
||||||
import io.legado.app.model.CacheBook
|
import io.legado.app.model.CacheBook
|
||||||
//import io.legado.app.lib.theme.accentColor
|
|
||||||
//import io.legado.app.lib.theme.primaryTextColor
|
|
||||||
import io.legado.app.model.ReadBook
|
import io.legado.app.model.ReadBook
|
||||||
import io.legado.app.ui.about.AppLogDialog
|
import io.legado.app.ui.about.AppLogDialog
|
||||||
import io.legado.app.ui.book.toc.rule.TxtTocRuleDialog
|
import io.legado.app.ui.book.toc.rule.TxtTocRuleDialog
|
||||||
import io.legado.app.ui.file.HandleFileContract
|
import io.legado.app.ui.file.HandleFileContract
|
||||||
|
import io.legado.app.ui.replace.ReplaceRuleActivity
|
||||||
|
import io.legado.app.ui.replace.edit.ReplaceEditActivity
|
||||||
import io.legado.app.ui.widget.dialog.WaitDialog
|
import io.legado.app.ui.widget.dialog.WaitDialog
|
||||||
import io.legado.app.utils.gone
|
import io.legado.app.utils.gone
|
||||||
import io.legado.app.utils.hideSoftInput
|
import io.legado.app.utils.hideSoftInput
|
||||||
@@ -57,6 +58,12 @@ class TocActivity : VMBaseActivity<ActivityChapterListBinding, TocViewModel>(),
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
private val replaceActivity =
|
||||||
|
registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
|
||||||
|
if (it.resultCode == RESULT_OK) {
|
||||||
|
viewModel.replaceRuleChanged()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
@@ -143,6 +150,25 @@ class TocActivity : VMBaseActivity<ActivityChapterListBinding, TocViewModel>(),
|
|||||||
|
|
||||||
override fun onCompatOptionsItemSelected(item: MenuItem): Boolean {
|
override fun onCompatOptionsItemSelected(item: MenuItem): Boolean {
|
||||||
when (item.itemId) {
|
when (item.itemId) {
|
||||||
|
R.id.menu_replace -> {
|
||||||
|
val scopes = arrayListOf<String>()
|
||||||
|
viewModel.bookData.value?.name?.let { scopes.add(it) }
|
||||||
|
viewModel.bookSource?.bookSourceUrl?.let { scopes.add(it) }
|
||||||
|
replaceActivity.launch(
|
||||||
|
ReplaceEditActivity.startIntent(
|
||||||
|
this,
|
||||||
|
pattern = "text",
|
||||||
|
scope = scopes.joinToString(";"),
|
||||||
|
isScopeTitle = true,
|
||||||
|
isScopeContent = false
|
||||||
|
)
|
||||||
|
)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
R.id.menu_replace_show -> {
|
||||||
|
replaceActivity.launch(Intent(this, ReplaceRuleActivity::class.java))
|
||||||
|
return true
|
||||||
|
}
|
||||||
R.id.menu_toc_regex -> showDialogFragment(
|
R.id.menu_toc_regex -> showDialogFragment(
|
||||||
TxtTocRuleDialog(viewModel.bookData.value?.tocUrl)
|
TxtTocRuleDialog(viewModel.bookData.value?.tocUrl)
|
||||||
)
|
)
|
||||||
@@ -210,6 +236,7 @@ class TocActivity : VMBaseActivity<ActivityChapterListBinding, TocViewModel>(),
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fun locateToChapter(index: Int) {
|
fun locateToChapter(index: Int) {
|
||||||
val tag = "android:switcher:${binding.viewPager.id}:0"
|
val tag = "android:switcher:${binding.viewPager.id}:0"
|
||||||
val chapterFragment = supportFragmentManager.findFragmentByTag(tag) as? ChapterListFragment
|
val chapterFragment = supportFragmentManager.findFragmentByTag(tag) as? ChapterListFragment
|
||||||
|
|||||||
@@ -9,7 +9,9 @@ import io.legado.app.base.BaseViewModel
|
|||||||
import io.legado.app.constant.AppLog
|
import io.legado.app.constant.AppLog
|
||||||
import io.legado.app.data.appDb
|
import io.legado.app.data.appDb
|
||||||
import io.legado.app.data.entities.Book
|
import io.legado.app.data.entities.Book
|
||||||
|
import io.legado.app.data.entities.BookSource
|
||||||
import io.legado.app.exception.NoStackTraceException
|
import io.legado.app.exception.NoStackTraceException
|
||||||
|
import io.legado.app.help.book.ContentProcessor
|
||||||
import io.legado.app.model.ReadBook
|
import io.legado.app.model.ReadBook
|
||||||
import io.legado.app.model.localBook.LocalBook
|
import io.legado.app.model.localBook.LocalBook
|
||||||
import io.legado.app.utils.FileDoc
|
import io.legado.app.utils.FileDoc
|
||||||
@@ -21,15 +23,25 @@ import io.legado.app.utils.writeText
|
|||||||
|
|
||||||
class TocViewModel(application: Application) : BaseViewModel(application) {
|
class TocViewModel(application: Application) : BaseViewModel(application) {
|
||||||
var bookUrl: String = ""
|
var bookUrl: String = ""
|
||||||
|
var bookSource: BookSource? = null
|
||||||
var bookData = MutableLiveData<Book>()
|
var bookData = MutableLiveData<Book>()
|
||||||
var chapterListCallBack: ChapterListCallBack? = null
|
var chapterListCallBack: ChapterListCallBack? = null
|
||||||
var bookMarkCallBack: BookmarkCallBack? = null
|
var bookMarkCallBack: BookmarkCallBack? = null
|
||||||
var searchKey: String? = null
|
var searchKey: String? = null
|
||||||
|
fun replaceRuleChanged() {
|
||||||
|
execute {
|
||||||
|
ReadBook.book?.let {
|
||||||
|
ContentProcessor.get(it.name, it.origin).upReplaceRules()
|
||||||
|
ReadBook.loadContent(resetPageOffset = false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fun initBook(bookUrl: String) {
|
fun initBook(bookUrl: String) {
|
||||||
this.bookUrl = bookUrl
|
this.bookUrl = bookUrl
|
||||||
execute {
|
execute {
|
||||||
appDb.bookDao.getBook(bookUrl)?.let {
|
appDb.bookDao.getBook(bookUrl)?.let {
|
||||||
|
bookSource = appDb.bookSourceDao.getBookSource(it.origin)
|
||||||
bookData.postValue(it)
|
bookData.postValue(it)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import android.content.Intent
|
|||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.view.Menu
|
import android.view.Menu
|
||||||
import android.view.MenuItem
|
import android.view.MenuItem
|
||||||
|
import android.widget.ArrayAdapter
|
||||||
import android.widget.EditText
|
import android.widget.EditText
|
||||||
import androidx.activity.viewModels
|
import androidx.activity.viewModels
|
||||||
import androidx.lifecycle.lifecycleScope
|
import androidx.lifecycle.lifecycleScope
|
||||||
@@ -20,6 +21,9 @@ import io.legado.app.utils.sendToClip
|
|||||||
import io.legado.app.utils.setOnApplyWindowInsetsListenerCompat
|
import io.legado.app.utils.setOnApplyWindowInsetsListenerCompat
|
||||||
import io.legado.app.utils.showHelp
|
import io.legado.app.utils.showHelp
|
||||||
import io.legado.app.utils.viewbindingdelegate.viewBinding
|
import io.legado.app.utils.viewbindingdelegate.viewBinding
|
||||||
|
import androidx.core.content.edit
|
||||||
|
import io.legado.app.lib.dialogs.alert
|
||||||
|
import io.legado.app.utils.toastOnUi
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 编辑替换规则
|
* 编辑替换规则
|
||||||
@@ -28,28 +32,74 @@ class ReplaceEditActivity :
|
|||||||
VMBaseActivity<ActivityReplaceEditBinding, ReplaceEditViewModel>(),
|
VMBaseActivity<ActivityReplaceEditBinding, ReplaceEditViewModel>(),
|
||||||
KeyboardToolPop.CallBack {
|
KeyboardToolPop.CallBack {
|
||||||
|
|
||||||
companion object {
|
object GroupManager {
|
||||||
|
private const val PREF_NAME = "replace_groups"
|
||||||
|
private const val KEY_CUSTOM_GROUPS = "custom_groups"
|
||||||
|
private const val KEY_LAST_SELECTED = "last_selected_group"
|
||||||
|
|
||||||
|
private val presetGroups = listOf(
|
||||||
|
"默认", "地名", "国家", "企业", "人名", "敏感词", "生僻字", "乱码或广告"
|
||||||
|
)
|
||||||
|
|
||||||
|
private fun prefs(context: Context) =
|
||||||
|
context.getSharedPreferences(PREF_NAME, MODE_PRIVATE)
|
||||||
|
|
||||||
|
fun getAllGroups(context: Context): List<String> =
|
||||||
|
(getCustomGroups(context) + presetGroups).distinct()
|
||||||
|
|
||||||
|
fun getCustomGroups(context: Context): List<String> {
|
||||||
|
val json = prefs(context).getString(KEY_CUSTOM_GROUPS, "[]") ?: "[]"
|
||||||
|
return GSON.fromJson(json, Array<String>::class.java).toList()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun saveCustomGroups(context: Context, groups: List<String>) {
|
||||||
|
prefs(context).edit { putString(KEY_CUSTOM_GROUPS, GSON.toJson(groups)) }
|
||||||
|
}
|
||||||
|
|
||||||
|
fun addCustomGroup(context: Context, group: String) {
|
||||||
|
if (group.isBlank() || presetGroups.contains(group)) return
|
||||||
|
val custom = getCustomGroups(context).toMutableList()
|
||||||
|
if (group !in custom) {
|
||||||
|
custom += group
|
||||||
|
saveCustomGroups(context, custom)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun removeCustomGroups(context: Context, groupsToRemove: List<String>) {
|
||||||
|
if (groupsToRemove.isEmpty()) return
|
||||||
|
val updated = getCustomGroups(context).filterNot { it in groupsToRemove }
|
||||||
|
saveCustomGroups(context, updated)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getLastSelectedGroup(context: Context): String =
|
||||||
|
prefs(context).getString(KEY_LAST_SELECTED, "默认") ?: "默认"
|
||||||
|
|
||||||
|
fun setLastSelectedGroup(context: Context, group: String) {
|
||||||
|
prefs(context).edit { putString(KEY_LAST_SELECTED, group) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
fun startIntent(
|
fun startIntent(
|
||||||
context: Context,
|
context: Context,
|
||||||
id: Long = -1,
|
id: Long = -1,
|
||||||
pattern: String? = null,
|
pattern: String? = null,
|
||||||
isRegex: Boolean = false,
|
isRegex: Boolean = false,
|
||||||
scope: String? = null
|
scope: String? = null,
|
||||||
): Intent {
|
isScopeTitle: Boolean = false,
|
||||||
val intent = Intent(context, ReplaceEditActivity::class.java)
|
isScopeContent: Boolean = false
|
||||||
intent.putExtra("id", id)
|
): Intent = Intent(context, ReplaceEditActivity::class.java).apply {
|
||||||
intent.putExtra("pattern", pattern)
|
putExtra("id", id)
|
||||||
intent.putExtra("isRegex", isRegex)
|
putExtra("pattern", pattern)
|
||||||
intent.putExtra("scope", scope)
|
putExtra("isRegex", isRegex)
|
||||||
return intent
|
putExtra("scope", scope)
|
||||||
|
putExtra("isScopeTitle", isScopeTitle)
|
||||||
|
putExtra("isScopeContent", isScopeContent)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override val binding by viewBinding(ActivityReplaceEditBinding::inflate)
|
override val binding by viewBinding(ActivityReplaceEditBinding::inflate)
|
||||||
override val viewModel by viewModels<ReplaceEditViewModel>()
|
override val viewModel by viewModels<ReplaceEditViewModel>()
|
||||||
|
|
||||||
private val softKeyboardTool by lazy {
|
private val softKeyboardTool by lazy {
|
||||||
KeyboardToolPop(this, lifecycleScope, binding.root, this)
|
KeyboardToolPop(this, lifecycleScope, binding.root, this)
|
||||||
}
|
}
|
||||||
@@ -58,9 +108,12 @@ class ReplaceEditActivity :
|
|||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
softKeyboardTool.attachToWindow(window)
|
softKeyboardTool.attachToWindow(window)
|
||||||
initView()
|
initView()
|
||||||
viewModel.initData(intent) {
|
viewModel.initData(intent, ::upReplaceView)
|
||||||
upReplaceView(it)
|
}
|
||||||
}
|
|
||||||
|
override fun onDestroy() {
|
||||||
|
super.onDestroy()
|
||||||
|
softKeyboardTool.dismiss()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCompatCreateOptionsMenu(menu: Menu): Boolean {
|
override fun onCompatCreateOptionsMenu(menu: Menu): Boolean {
|
||||||
@@ -76,66 +129,126 @@ class ReplaceEditActivity :
|
|||||||
}
|
}
|
||||||
|
|
||||||
R.id.menu_copy_rule -> sendToClip(GSON.toJson(getReplaceRule()))
|
R.id.menu_copy_rule -> sendToClip(GSON.toJson(getReplaceRule()))
|
||||||
R.id.menu_paste_rule -> viewModel.pasteRule {
|
R.id.menu_paste_rule -> viewModel.pasteRule(::upReplaceView)
|
||||||
upReplaceView(it)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onDestroy() {
|
private fun initView() = binding.run {
|
||||||
super.onDestroy()
|
ivHelp.setOnClickListener { showHelp("regexHelp") }
|
||||||
softKeyboardTool.dismiss()
|
ivManageGroups.setOnClickListener { showGroupManageDialog() }
|
||||||
|
|
||||||
|
root.setOnApplyWindowInsetsListenerCompat { _, insets ->
|
||||||
|
softKeyboardTool.initialPadding = insets.imeHeight
|
||||||
|
insets
|
||||||
|
}
|
||||||
|
|
||||||
|
setupGroupAutoComplete()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun initView() {
|
private fun setupGroupAutoComplete() = binding.run {
|
||||||
binding.ivHelp.setOnClickListener {
|
val allGroups = GroupManager.getAllGroups(this@ReplaceEditActivity)
|
||||||
showHelp("regexHelp")
|
val adapter = ArrayAdapter(
|
||||||
|
this@ReplaceEditActivity,
|
||||||
|
android.R.layout.simple_dropdown_item_1line,
|
||||||
|
allGroups
|
||||||
|
)
|
||||||
|
etGroup.setAdapter(adapter)
|
||||||
|
|
||||||
|
etGroup.setText(GroupManager.getLastSelectedGroup(this@ReplaceEditActivity), false)
|
||||||
|
|
||||||
|
etGroup.setOnFocusChangeListener { _, hasFocus ->
|
||||||
|
if (!hasFocus) saveCurrentGroup()
|
||||||
}
|
}
|
||||||
binding.root.setOnApplyWindowInsetsListenerCompat { _, windowInsets ->
|
|
||||||
softKeyboardTool.initialPadding = windowInsets.imeHeight
|
etGroup.setOnItemClickListener { parent, _, position, _ ->
|
||||||
windowInsets
|
val selected = parent.getItemAtPosition(position) as String
|
||||||
|
GroupManager.setLastSelectedGroup(this@ReplaceEditActivity, selected)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun upReplaceView(replaceRule: ReplaceRule) = binding.run {
|
private fun refreshGroupList() {
|
||||||
etName.setText(replaceRule.name)
|
val allGroups = GroupManager.getAllGroups(this)
|
||||||
etGroup.setText(replaceRule.group)
|
val adapter = ArrayAdapter(
|
||||||
etReplaceRule.setText(replaceRule.pattern)
|
this,
|
||||||
cbUseRegex.isChecked = replaceRule.isRegex
|
android.R.layout.simple_dropdown_item_1line,
|
||||||
etReplaceTo.setText(replaceRule.replacement)
|
allGroups
|
||||||
cbScopeTitle.isChecked = replaceRule.scopeTitle
|
)
|
||||||
cbScopeContent.isChecked = replaceRule.scopeContent
|
binding.etGroup.setAdapter(adapter)
|
||||||
etScope.setText(replaceRule.scope)
|
}
|
||||||
etExcludeScope.setText(replaceRule.excludeScope)
|
|
||||||
etTimeout.setText(replaceRule.timeoutMillisecond.toString())
|
private fun saveCurrentGroup() {
|
||||||
|
val current = binding.etGroup.text.toString().trim()
|
||||||
|
if (current.isNotBlank()) {
|
||||||
|
GroupManager.addCustomGroup(this, current)
|
||||||
|
GroupManager.setLastSelectedGroup(this, current)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun showGroupManageDialog() {
|
||||||
|
val allGroups = GroupManager.getCustomGroups(this).toMutableList()
|
||||||
|
if (allGroups.isEmpty()) {
|
||||||
|
toastOnUi("暂无自定义分组")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
val checked = BooleanArray(allGroups.size)
|
||||||
|
alert(title = getString(R.string.group_manage)) {
|
||||||
|
multiChoiceItems(allGroups.toTypedArray(), checked) { _, _, _ -> }
|
||||||
|
negativeButton("关闭")
|
||||||
|
neutralButton("删除所选") {
|
||||||
|
val toDelete = allGroups.filterIndexed { i, _ -> checked[i] }
|
||||||
|
if (toDelete.isNotEmpty()) {
|
||||||
|
GroupManager.removeCustomGroups(this@ReplaceEditActivity, toDelete)
|
||||||
|
refreshGroupList()
|
||||||
|
toastOnUi("已删除 ${toDelete.size} 个分组")
|
||||||
|
} else {
|
||||||
|
toastOnUi("未选择任何分组")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun upReplaceView(rule: ReplaceRule) = binding.run {
|
||||||
|
etName.setText(rule.name)
|
||||||
|
val group = rule.group.takeUnless { it.isNullOrBlank() }
|
||||||
|
?: GroupManager.getLastSelectedGroup(this@ReplaceEditActivity)
|
||||||
|
etGroup.setText(group, false)
|
||||||
|
etReplaceRule.setText(rule.pattern)
|
||||||
|
cbUseRegex.isChecked = rule.isRegex
|
||||||
|
etReplaceTo.setText(rule.replacement)
|
||||||
|
cbScopeTitle.isChecked = rule.scopeTitle
|
||||||
|
cbScopeContent.isChecked = rule.scopeContent
|
||||||
|
etScope.setText(rule.scope)
|
||||||
|
etExcludeScope.setText(rule.excludeScope)
|
||||||
|
etTimeout.setText(rule.timeoutMillisecond.toString())
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getReplaceRule(): ReplaceRule = binding.run {
|
private fun getReplaceRule(): ReplaceRule = binding.run {
|
||||||
val replaceRule: ReplaceRule = viewModel.replaceRule ?: ReplaceRule()
|
saveCurrentGroup()
|
||||||
replaceRule.name = etName.text.toString()
|
val rule = viewModel.replaceRule ?: ReplaceRule()
|
||||||
replaceRule.group = etGroup.text.toString()
|
|
||||||
replaceRule.pattern = etReplaceRule.text.toString()
|
rule.name = etName.text.toString()
|
||||||
replaceRule.isRegex = cbUseRegex.isChecked
|
rule.group = etGroup.text.toString().trim().ifBlank {
|
||||||
replaceRule.replacement = etReplaceTo.text.toString()
|
GroupManager.getLastSelectedGroup(this@ReplaceEditActivity)
|
||||||
replaceRule.scopeTitle = cbScopeTitle.isChecked
|
}
|
||||||
replaceRule.scopeContent = cbScopeContent.isChecked
|
rule.pattern = etReplaceRule.text.toString()
|
||||||
replaceRule.scope = etScope.text.toString()
|
rule.isRegex = cbUseRegex.isChecked
|
||||||
replaceRule.excludeScope = etExcludeScope.text.toString()
|
rule.replacement = etReplaceTo.text.toString()
|
||||||
replaceRule.timeoutMillisecond = etTimeout.text.toString().ifEmpty { "3000" }.toLong()
|
rule.scopeTitle = cbScopeTitle.isChecked
|
||||||
return replaceRule
|
rule.scopeContent = cbScopeContent.isChecked
|
||||||
|
rule.scope = etScope.text.toString()
|
||||||
|
rule.excludeScope = etExcludeScope.text.toString()
|
||||||
|
rule.timeoutMillisecond = etTimeout.text.toString().ifEmpty { "3000" }.toLong()
|
||||||
|
|
||||||
|
rule
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun helpActions(): List<SelectItem<String>> {
|
override fun helpActions(): List<SelectItem<String>> =
|
||||||
return arrayListOf(
|
listOf(SelectItem("正则教程", "regexHelp"))
|
||||||
SelectItem("正则教程", "regexHelp")
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onHelpActionSelect(action: String) {
|
override fun onHelpActionSelect(action: String) {
|
||||||
when (action) {
|
if (action == "regexHelp") showHelp("regexHelp")
|
||||||
"regexHelp" -> showHelp("regexHelp")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun sendText(text: String) {
|
override fun sendText(text: String) {
|
||||||
@@ -144,15 +257,12 @@ class ReplaceEditActivity :
|
|||||||
if (view is EditText) {
|
if (view is EditText) {
|
||||||
val start = view.selectionStart
|
val start = view.selectionStart
|
||||||
val end = view.selectionEnd
|
val end = view.selectionEnd
|
||||||
//获取EditText的文字
|
|
||||||
val edit = view.editableText
|
val edit = view.editableText
|
||||||
if (start < 0 || start >= edit.length) {
|
if (start < 0 || start >= edit.length) {
|
||||||
edit.append(text)
|
edit.append(text)
|
||||||
} else {
|
} else {
|
||||||
//光标所在位置插入文字
|
|
||||||
edit.replace(start, end, text)
|
edit.replace(start, end, text)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,11 +22,15 @@ class ReplaceEditViewModel(application: Application) : BaseViewModel(application
|
|||||||
val pattern = intent.getStringExtra("pattern") ?: ""
|
val pattern = intent.getStringExtra("pattern") ?: ""
|
||||||
val isRegex = intent.getBooleanExtra("isRegex", false)
|
val isRegex = intent.getBooleanExtra("isRegex", false)
|
||||||
val scope = intent.getStringExtra("scope")
|
val scope = intent.getStringExtra("scope")
|
||||||
|
val isScopeTitle = intent.getBooleanExtra("isScopeTitle", false)
|
||||||
|
val isScopeContent = intent.getBooleanExtra("isScopeContent", false)
|
||||||
ReplaceRule(
|
ReplaceRule(
|
||||||
name = pattern,
|
name = pattern,
|
||||||
pattern = pattern,
|
pattern = pattern,
|
||||||
isRegex = isRegex,
|
isRegex = isRegex,
|
||||||
scope = scope
|
scope = scope,
|
||||||
|
scopeTitle = isScopeTitle,
|
||||||
|
scopeContent = isScopeContent
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}.onFinally {
|
}.onFinally {
|
||||||
|
|||||||
@@ -43,15 +43,23 @@
|
|||||||
android:id="@+id/til_group"
|
android:id="@+id/til_group"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
style="@style/Widget.Material3.TextInputLayout.OutlinedBox.ExposedDropdownMenu"
|
||||||
android:hint="@string/group">
|
android:hint="@string/group">
|
||||||
|
|
||||||
<com.google.android.material.textfield.TextInputEditText
|
<com.google.android.material.textfield.MaterialAutoCompleteTextView
|
||||||
android:id="@+id/et_group"
|
android:id="@+id/et_group"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/text_default"
|
||||||
tools:ignore="SpeakableTextPresentCheck,TouchTargetSizeCheck" />
|
tools:ignore="SpeakableTextPresentCheck,TouchTargetSizeCheck" />
|
||||||
</com.google.android.material.textfield.TextInputLayout>
|
</com.google.android.material.textfield.TextInputLayout>
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/iv_manage_groups"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/group_manage"/>
|
||||||
|
|
||||||
<com.google.android.material.textfield.TextInputLayout
|
<com.google.android.material.textfield.TextInputLayout
|
||||||
android:id="@+id/til_replace_rule"
|
android:id="@+id/til_replace_rule"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
|
|||||||
@@ -42,6 +42,14 @@
|
|||||||
android:title="@string/reverse_toc"
|
android:title="@string/reverse_toc"
|
||||||
app:showAsAction="never" />
|
app:showAsAction="never" />
|
||||||
|
|
||||||
|
<item
|
||||||
|
android:id="@+id/menu_replace"
|
||||||
|
android:title="@string/replace" />
|
||||||
|
|
||||||
|
<item
|
||||||
|
android:id="@+id/menu_replace_show"
|
||||||
|
android:title="@string/replace_rule" />
|
||||||
|
|
||||||
<item
|
<item
|
||||||
android:id="@+id/menu_use_replace"
|
android:id="@+id/menu_use_replace"
|
||||||
android:checkable="true"
|
android:checkable="true"
|
||||||
|
|||||||
Reference in New Issue
Block a user