优化
This commit is contained in:
@@ -12,6 +12,11 @@
|
|||||||
* 正文出现缺字漏字、内容缺失、排版错乱等情况,有可能是净化规则或简繁转换出现问题。
|
* 正文出现缺字漏字、内容缺失、排版错乱等情况,有可能是净化规则或简繁转换出现问题。
|
||||||
* 漫画源看书显示乱码,**阅读与其他软件的源并不通用**,请导入阅读的支持的漫画源!
|
* 漫画源看书显示乱码,**阅读与其他软件的源并不通用**,请导入阅读的支持的漫画源!
|
||||||
|
|
||||||
|
**2023/06/07**
|
||||||
|
|
||||||
|
* 修复长按菜单全文搜索结果不全或无结果问题
|
||||||
|
* 优化全文搜索速度
|
||||||
|
|
||||||
**2023/06/06**
|
**2023/06/06**
|
||||||
|
|
||||||
* 更新cronet: 114.0.5735.57
|
* 更新cronet: 114.0.5735.57
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ object AppPattern {
|
|||||||
val authorRegex = Regex("^\\s*作\\s*者[::\\s]+|\\s+著")
|
val authorRegex = Regex("^\\s*作\\s*者[::\\s]+|\\s+著")
|
||||||
val fileNameRegex = Regex("[\\\\/:*?\"<>|.]")
|
val fileNameRegex = Regex("[\\\\/:*?\"<>|.]")
|
||||||
val splitGroupRegex = Regex("[,;,;]")
|
val splitGroupRegex = Regex("[,;,;]")
|
||||||
val titleNumPattern = Pattern.compile("(第)(.+?)(章)")
|
val titleNumPattern: Pattern = Pattern.compile("(第)(.+?)(章)")
|
||||||
|
|
||||||
//书源调试信息中的各种符号
|
//书源调试信息中的各种符号
|
||||||
val debugMessageSymbolRegex = Regex("[⇒◇┌└≡]")
|
val debugMessageSymbolRegex = Regex("[⇒◇┌└≡]")
|
||||||
@@ -48,4 +48,8 @@ object AppPattern {
|
|||||||
val semicolonRegex = ";".toRegex()
|
val semicolonRegex = ";".toRegex()
|
||||||
|
|
||||||
val equalsRegex = "=".toRegex()
|
val equalsRegex = "=".toRegex()
|
||||||
|
|
||||||
|
val spaceRegex = "\\s+".toRegex()
|
||||||
|
|
||||||
|
val regexCharRegex = "[{}()\\[\\].+*?^$\\\\|]".toRegex()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -68,6 +68,9 @@ interface BookDao {
|
|||||||
@Query("SELECT * FROM books WHERE name = :name and author = :author")
|
@Query("SELECT * FROM books WHERE name = :name and author = :author")
|
||||||
fun getBook(name: String, author: String): Book?
|
fun getBook(name: String, author: String): Book?
|
||||||
|
|
||||||
|
@Query("SELECT * FROM books WHERE name = :name and origin = :origin")
|
||||||
|
fun getBookByOrigin(name: String, origin: String): Book?
|
||||||
|
|
||||||
@get:Query("select count(bookUrl) from books where (SELECT sum(groupId) FROM book_groups)")
|
@get:Query("select count(bookUrl) from books where (SELECT sum(groupId) FROM book_groups)")
|
||||||
val noGroupSize: Int
|
val noGroupSize: Int
|
||||||
|
|
||||||
|
|||||||
@@ -135,6 +135,10 @@ data class Book(
|
|||||||
@IgnoredOnParcel
|
@IgnoredOnParcel
|
||||||
var downloadUrls: List<String>? = null
|
var downloadUrls: List<String>? = null
|
||||||
|
|
||||||
|
@Ignore
|
||||||
|
@IgnoredOnParcel
|
||||||
|
private var folderName: String? = null
|
||||||
|
|
||||||
fun getRealAuthor() = author.replace(AppPattern.authorRegex, "")
|
fun getRealAuthor() = author.replace(AppPattern.authorRegex, "")
|
||||||
|
|
||||||
fun getUnreadChapterNum() = max(totalChapterNum - durChapterIndex - 1, 0)
|
fun getUnreadChapterNum() = max(totalChapterNum - durChapterIndex - 1, 0)
|
||||||
@@ -237,10 +241,18 @@ data class Book(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun getFolderName(): String {
|
fun getFolderName(): String {
|
||||||
|
folderName?.let {
|
||||||
|
return it
|
||||||
|
}
|
||||||
//防止书名过长,只取9位
|
//防止书名过长,只取9位
|
||||||
var folderName = name.replace(AppPattern.fileNameRegex, "")
|
folderName = getFolderNameNoCache()
|
||||||
folderName = folderName.substring(0, min(9, folderName.length))
|
return folderName!!
|
||||||
return folderName + MD5Utils.md5Encode16(bookUrl)
|
}
|
||||||
|
|
||||||
|
fun getFolderNameNoCache(): String {
|
||||||
|
return name.replace(AppPattern.fileNameRegex, "").let {
|
||||||
|
it.substring(0, min(9, it.length)) + MD5Utils.md5Encode16(bookUrl)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun toSearchBook() = SearchBook(
|
fun toSearchBook() = SearchBook(
|
||||||
|
|||||||
@@ -59,6 +59,12 @@ data class BookChapter(
|
|||||||
GSON.fromJsonObject<HashMap<String, String>>(variable).getOrNull() ?: hashMapOf()
|
GSON.fromJsonObject<HashMap<String, String>>(variable).getOrNull() ?: hashMapOf()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@delegate:Ignore
|
||||||
|
@IgnoredOnParcel
|
||||||
|
private val titleMD5: String by lazy {
|
||||||
|
MD5Utils.md5Encode16(title)
|
||||||
|
}
|
||||||
|
|
||||||
override fun putVariable(key: String, value: String?): Boolean {
|
override fun putVariable(key: String, value: String?): Boolean {
|
||||||
if (super.putVariable(key, value)) {
|
if (super.putVariable(key, value)) {
|
||||||
variable = GSON.toJson(variableMap)
|
variable = GSON.toJson(variableMap)
|
||||||
@@ -145,9 +151,10 @@ data class BookChapter(
|
|||||||
|
|
||||||
@Suppress("unused")
|
@Suppress("unused")
|
||||||
fun getFileName(suffix: String = "nb"): String =
|
fun getFileName(suffix: String = "nb"): String =
|
||||||
String.format("%05d-%s.%s", index, MD5Utils.md5Encode16(title), suffix)
|
String.format("%05d-%s.%s", index, titleMD5, suffix)
|
||||||
|
|
||||||
|
|
||||||
@Suppress("unused")
|
@Suppress("unused")
|
||||||
fun getFontName(): String = String.format("%05d-%s.ttf", index, MD5Utils.md5Encode16(title))
|
fun getFontName(): String = String.format("%05d-%s.ttf", index, titleMD5)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -51,8 +51,19 @@ object BookHelp {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun updateCacheFolder(oldBook: Book, newBook: Book) {
|
fun updateCacheFolder(oldBook: Book, newBook: Book) {
|
||||||
val oldFolderPath = FileUtils.getPath(downloadDir, cacheFolderName, oldBook.getFolderName())
|
val oldFolderName = oldBook.getFolderNameNoCache()
|
||||||
val newFolderPath = FileUtils.getPath(downloadDir, cacheFolderName, newBook.getFolderName())
|
val newFolderName = newBook.getFolderNameNoCache()
|
||||||
|
if (oldFolderName == newFolderName) return
|
||||||
|
val oldFolderPath = FileUtils.getPath(
|
||||||
|
downloadDir,
|
||||||
|
cacheFolderName,
|
||||||
|
oldFolderName
|
||||||
|
)
|
||||||
|
val newFolderPath = FileUtils.getPath(
|
||||||
|
downloadDir,
|
||||||
|
cacheFolderName,
|
||||||
|
newFolderName
|
||||||
|
)
|
||||||
FileUtils.move(oldFolderPath, newFolderPath)
|
FileUtils.move(oldFolderPath, newFolderPath)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -331,21 +342,25 @@ object BookHelp {
|
|||||||
* 设置是否禁用正文的去除重复标题,针对单个章节
|
* 设置是否禁用正文的去除重复标题,针对单个章节
|
||||||
*/
|
*/
|
||||||
fun setRemoveSameTitle(book: Book, bookChapter: BookChapter, removeSameTitle: Boolean) {
|
fun setRemoveSameTitle(book: Book, bookChapter: BookChapter, removeSameTitle: Boolean) {
|
||||||
|
val fileName = bookChapter.getFileName("nr")
|
||||||
|
val contentProcessor = ContentProcessor.get(book)
|
||||||
if (removeSameTitle) {
|
if (removeSameTitle) {
|
||||||
val path = FileUtils.getPath(
|
val path = FileUtils.getPath(
|
||||||
downloadDir,
|
downloadDir,
|
||||||
cacheFolderName,
|
cacheFolderName,
|
||||||
book.getFolderName(),
|
book.getFolderName(),
|
||||||
bookChapter.getFileName(".nr")
|
fileName
|
||||||
)
|
)
|
||||||
|
contentProcessor.removeSameTitleCache.remove(fileName)
|
||||||
File(path).delete()
|
File(path).delete()
|
||||||
} else {
|
} else {
|
||||||
FileUtils.createFileIfNotExist(
|
FileUtils.createFileIfNotExist(
|
||||||
downloadDir,
|
downloadDir,
|
||||||
cacheFolderName,
|
cacheFolderName,
|
||||||
book.getFolderName(),
|
book.getFolderName(),
|
||||||
bookChapter.getFileName(".nr")
|
fileName
|
||||||
)
|
)
|
||||||
|
contentProcessor.removeSameTitleCache.add(fileName)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -357,7 +372,7 @@ object BookHelp {
|
|||||||
downloadDir,
|
downloadDir,
|
||||||
cacheFolderName,
|
cacheFolderName,
|
||||||
book.getFolderName(),
|
book.getFolderName(),
|
||||||
bookChapter.getFileName(".nr")
|
bookChapter.getFileName("nr")
|
||||||
)
|
)
|
||||||
return !File(path).exists()
|
return !File(path).exists()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package io.legado.app.help.book
|
|||||||
|
|
||||||
import com.github.liuyueyi.quick.transfer.ChineseUtils
|
import com.github.liuyueyi.quick.transfer.ChineseUtils
|
||||||
import io.legado.app.constant.AppLog
|
import io.legado.app.constant.AppLog
|
||||||
|
import io.legado.app.constant.AppPattern.spaceRegex
|
||||||
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.BookChapter
|
import io.legado.app.data.entities.BookChapter
|
||||||
@@ -9,6 +10,7 @@ import io.legado.app.data.entities.ReplaceRule
|
|||||||
import io.legado.app.exception.RegexTimeoutException
|
import io.legado.app.exception.RegexTimeoutException
|
||||||
import io.legado.app.help.config.AppConfig
|
import io.legado.app.help.config.AppConfig
|
||||||
import io.legado.app.help.config.ReadBookConfig
|
import io.legado.app.help.config.ReadBookConfig
|
||||||
|
import io.legado.app.utils.escapeRegex
|
||||||
import io.legado.app.utils.replace
|
import io.legado.app.utils.replace
|
||||||
import io.legado.app.utils.stackTraceStr
|
import io.legado.app.utils.stackTraceStr
|
||||||
import io.legado.app.utils.toastOnUi
|
import io.legado.app.utils.toastOnUi
|
||||||
@@ -25,7 +27,8 @@ class ContentProcessor private constructor(
|
|||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private val processors = hashMapOf<String, WeakReference<ContentProcessor>>()
|
private val processors = hashMapOf<String, WeakReference<ContentProcessor>>()
|
||||||
var enableRemoveSameTitle = true
|
|
||||||
|
fun get(book: Book) = get(book.name, book.origin)
|
||||||
|
|
||||||
fun get(bookName: String, bookOrigin: String): ContentProcessor {
|
fun get(bookName: String, bookOrigin: String): ContentProcessor {
|
||||||
val processorWr = processors[bookName + bookOrigin]
|
val processorWr = processors[bookName + bookOrigin]
|
||||||
@@ -47,9 +50,11 @@ class ContentProcessor private constructor(
|
|||||||
|
|
||||||
private val titleReplaceRules = CopyOnWriteArrayList<ReplaceRule>()
|
private val titleReplaceRules = CopyOnWriteArrayList<ReplaceRule>()
|
||||||
private val contentReplaceRules = CopyOnWriteArrayList<ReplaceRule>()
|
private val contentReplaceRules = CopyOnWriteArrayList<ReplaceRule>()
|
||||||
|
val removeSameTitleCache = hashSetOf<String>()
|
||||||
|
|
||||||
init {
|
init {
|
||||||
upReplaceRules()
|
upReplaceRules()
|
||||||
|
upRemoveSameTitle()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun upReplaceRules() {
|
fun upReplaceRules() {
|
||||||
@@ -63,6 +68,15 @@ class ContentProcessor private constructor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun upRemoveSameTitle() {
|
||||||
|
val book = appDb.bookDao.getBookByOrigin(bookName, bookOrigin) ?: return
|
||||||
|
removeSameTitleCache.clear()
|
||||||
|
val files = BookHelp.getChapterFiles(book).filter {
|
||||||
|
it.endsWith("nr")
|
||||||
|
}
|
||||||
|
removeSameTitleCache.addAll(files)
|
||||||
|
}
|
||||||
|
|
||||||
fun getTitleReplaceRules(): List<ReplaceRule> {
|
fun getTitleReplaceRules(): List<ReplaceRule> {
|
||||||
return titleReplaceRules
|
return titleReplaceRules
|
||||||
}
|
}
|
||||||
@@ -85,9 +99,10 @@ class ContentProcessor private constructor(
|
|||||||
var sameTitleRemoved = false
|
var sameTitleRemoved = false
|
||||||
if (content != "null") {
|
if (content != "null") {
|
||||||
//去除重复标题
|
//去除重复标题
|
||||||
if (enableRemoveSameTitle && BookHelp.removeSameTitle(book, chapter)) try {
|
val fileName = chapter.getFileName("nr")
|
||||||
|
if (!removeSameTitleCache.contains(fileName)) try {
|
||||||
val name = Pattern.quote(book.name)
|
val name = Pattern.quote(book.name)
|
||||||
var title = Pattern.quote(chapter.title)
|
var title = chapter.title.escapeRegex().replace(spaceRegex, "\\\\s*")
|
||||||
var matcher = Pattern.compile("^(\\s|\\p{P}|${name})*${title}(\\s)*")
|
var matcher = Pattern.compile("^(\\s|\\p{P}|${name})*${title}(\\s)*")
|
||||||
.matcher(mContent)
|
.matcher(mContent)
|
||||||
if (matcher.find()) {
|
if (matcher.find()) {
|
||||||
|
|||||||
@@ -54,6 +54,7 @@ object ReadBook : CoroutineScope by MainScope() {
|
|||||||
|
|
||||||
var preDownloadTask: Coroutine<*>? = null
|
var preDownloadTask: Coroutine<*>? = null
|
||||||
val downloadedChapters = hashSetOf<Int>()
|
val downloadedChapters = hashSetOf<Int>()
|
||||||
|
var contentProcessor: ContentProcessor? = null
|
||||||
|
|
||||||
//暂时保存跳转前进度
|
//暂时保存跳转前进度
|
||||||
fun saveCurrentBookProcess() {
|
fun saveCurrentBookProcess() {
|
||||||
@@ -74,6 +75,7 @@ object ReadBook : CoroutineScope by MainScope() {
|
|||||||
readRecord.bookName = book.name
|
readRecord.bookName = book.name
|
||||||
readRecord.readTime = appDb.readRecordDao.getReadTime(book.name) ?: 0
|
readRecord.readTime = appDb.readRecordDao.getReadTime(book.name) ?: 0
|
||||||
chapterSize = appDb.bookChapterDao.getChapterCount(book.bookUrl)
|
chapterSize = appDb.bookChapterDao.getChapterCount(book.bookUrl)
|
||||||
|
contentProcessor = ContentProcessor.get(book)
|
||||||
durChapterIndex = book.durChapterIndex
|
durChapterIndex = book.durChapterIndex
|
||||||
durChapterPos = book.durChapterPos
|
durChapterPos = book.durChapterPos
|
||||||
isLocalBook = book.isLocal
|
isLocalBook = book.isLocal
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import io.legado.app.base.VMBaseActivity
|
|||||||
import io.legado.app.constant.BookType
|
import io.legado.app.constant.BookType
|
||||||
import io.legado.app.data.entities.Book
|
import io.legado.app.data.entities.Book
|
||||||
import io.legado.app.databinding.ActivityBookInfoEditBinding
|
import io.legado.app.databinding.ActivityBookInfoEditBinding
|
||||||
|
import io.legado.app.help.book.BookHelp
|
||||||
import io.legado.app.help.book.isAudio
|
import io.legado.app.help.book.isAudio
|
||||||
import io.legado.app.help.book.isImage
|
import io.legado.app.help.book.isImage
|
||||||
import io.legado.app.help.book.isLocal
|
import io.legado.app.help.book.isLocal
|
||||||
@@ -94,22 +95,23 @@ class BookInfoEditActivity :
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun saveData() = binding.run {
|
private fun saveData() = binding.run {
|
||||||
viewModel.book?.let { book ->
|
val book = viewModel.book ?: return@run
|
||||||
book.name = tieBookName.text?.toString() ?: ""
|
val oldBook = book.copy()
|
||||||
book.author = tieBookAuthor.text?.toString() ?: ""
|
book.name = tieBookName.text?.toString() ?: ""
|
||||||
val local = if (book.isLocal) BookType.local else 0
|
book.author = tieBookAuthor.text?.toString() ?: ""
|
||||||
book.type = when (spType.selectedItemPosition) {
|
val local = if (book.isLocal) BookType.local else 0
|
||||||
2 -> BookType.image or local
|
book.type = when (spType.selectedItemPosition) {
|
||||||
1 -> BookType.audio or local
|
2 -> BookType.image or local
|
||||||
else -> BookType.text or local
|
1 -> BookType.audio or local
|
||||||
}
|
else -> BookType.text or local
|
||||||
val customCoverUrl = tieCoverUrl.text?.toString()
|
}
|
||||||
book.customCoverUrl = if (customCoverUrl == book.coverUrl) null else customCoverUrl
|
val customCoverUrl = tieCoverUrl.text?.toString()
|
||||||
book.customIntro = tieBookIntro.text?.toString()
|
book.customCoverUrl = if (customCoverUrl == book.coverUrl) null else customCoverUrl
|
||||||
viewModel.saveBook(book) {
|
book.customIntro = tieBookIntro.text?.toString()
|
||||||
setResult(Activity.RESULT_OK)
|
BookHelp.updateCacheFolder(oldBook, book)
|
||||||
finish()
|
viewModel.saveBook(book) {
|
||||||
}
|
setResult(Activity.RESULT_OK)
|
||||||
|
finish()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -121,7 +121,6 @@ class ReadBookActivity : BaseReadBookActivity(),
|
|||||||
val searchResult = IntentData.get<SearchResult>("searchResult$key")
|
val searchResult = IntentData.get<SearchResult>("searchResult$key")
|
||||||
val searchResultList = IntentData.get<List<SearchResult>>("searchResultList$key")
|
val searchResultList = IntentData.get<List<SearchResult>>("searchResultList$key")
|
||||||
if (searchResult != null && searchResultList != null) {
|
if (searchResult != null && searchResultList != null) {
|
||||||
ContentProcessor.enableRemoveSameTitle = false
|
|
||||||
viewModel.searchContentQuery = searchResult.query
|
viewModel.searchContentQuery = searchResult.query
|
||||||
binding.searchMenu.upSearchResultList(searchResultList)
|
binding.searchMenu.upSearchResultList(searchResultList)
|
||||||
isShowingSearchResult = true
|
isShowingSearchResult = true
|
||||||
@@ -294,6 +293,7 @@ class ReadBookActivity : BaseReadBookActivity(),
|
|||||||
item.isVisible = BuildConfig.DEBUG
|
item.isVisible = BuildConfig.DEBUG
|
||||||
item.isChecked = AppConfig.enableReview
|
item.isChecked = AppConfig.enableReview
|
||||||
}
|
}
|
||||||
|
|
||||||
R.id.menu_reverse_content -> item.isVisible = onLine
|
R.id.menu_reverse_content -> item.isVisible = onLine
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -318,6 +318,7 @@ class ReadBookActivity : BaseReadBookActivity(),
|
|||||||
showDialogFragment(ChangeBookSourceDialog(it.name, it.author))
|
showDialogFragment(ChangeBookSourceDialog(it.name, it.author))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
R.id.menu_chapter_change_source -> launch {
|
R.id.menu_chapter_change_source -> launch {
|
||||||
val book = ReadBook.book ?: return@launch
|
val book = ReadBook.book ?: return@launch
|
||||||
val chapter =
|
val chapter =
|
||||||
@@ -328,6 +329,7 @@ class ReadBookActivity : BaseReadBookActivity(),
|
|||||||
ChangeChapterSourceDialog(book.name, book.author, chapter.index, chapter.title)
|
ChangeChapterSourceDialog(book.name, book.author, chapter.index, chapter.title)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
R.id.menu_refresh,
|
R.id.menu_refresh,
|
||||||
R.id.menu_refresh_dur -> {
|
R.id.menu_refresh_dur -> {
|
||||||
if (ReadBook.bookSource == null) {
|
if (ReadBook.bookSource == null) {
|
||||||
@@ -340,6 +342,7 @@ class ReadBookActivity : BaseReadBookActivity(),
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
R.id.menu_refresh_after -> {
|
R.id.menu_refresh_after -> {
|
||||||
if (ReadBook.bookSource == null) {
|
if (ReadBook.bookSource == null) {
|
||||||
upContent()
|
upContent()
|
||||||
@@ -351,6 +354,7 @@ class ReadBookActivity : BaseReadBookActivity(),
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
R.id.menu_refresh_all -> {
|
R.id.menu_refresh_all -> {
|
||||||
if (ReadBook.bookSource == null) {
|
if (ReadBook.bookSource == null) {
|
||||||
upContent()
|
upContent()
|
||||||
@@ -362,6 +366,7 @@ class ReadBookActivity : BaseReadBookActivity(),
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
R.id.menu_download -> showDownloadDialog()
|
R.id.menu_download -> showDownloadDialog()
|
||||||
R.id.menu_add_bookmark -> addBookmark()
|
R.id.menu_add_bookmark -> addBookmark()
|
||||||
R.id.menu_edit_content -> showDialogFragment(ContentEditDialog())
|
R.id.menu_edit_content -> showDialogFragment(ContentEditDialog())
|
||||||
@@ -371,28 +376,34 @@ class ReadBookActivity : BaseReadBookActivity(),
|
|||||||
}
|
}
|
||||||
loadChapterList(it)
|
loadChapterList(it)
|
||||||
}
|
}
|
||||||
|
|
||||||
R.id.menu_enable_replace -> changeReplaceRuleState()
|
R.id.menu_enable_replace -> changeReplaceRuleState()
|
||||||
R.id.menu_re_segment -> ReadBook.book?.let {
|
R.id.menu_re_segment -> ReadBook.book?.let {
|
||||||
it.setReSegment(!it.getReSegment())
|
it.setReSegment(!it.getReSegment())
|
||||||
menu?.findItem(R.id.menu_re_segment)?.isChecked = it.getReSegment()
|
menu?.findItem(R.id.menu_re_segment)?.isChecked = it.getReSegment()
|
||||||
ReadBook.loadContent(false)
|
ReadBook.loadContent(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
R.id.menu_enable_review -> {
|
R.id.menu_enable_review -> {
|
||||||
AppConfig.enableReview = !AppConfig.enableReview
|
AppConfig.enableReview = !AppConfig.enableReview
|
||||||
menu?.findItem(R.id.menu_enable_review)?.isChecked = AppConfig.enableReview
|
menu?.findItem(R.id.menu_enable_review)?.isChecked = AppConfig.enableReview
|
||||||
ReadBook.loadContent(false)
|
ReadBook.loadContent(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
R.id.menu_page_anim -> showPageAnimConfig {
|
R.id.menu_page_anim -> showPageAnimConfig {
|
||||||
binding.readView.upPageAnim()
|
binding.readView.upPageAnim()
|
||||||
ReadBook.loadContent(false)
|
ReadBook.loadContent(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
R.id.menu_log -> showDialogFragment<AppLogDialog>()
|
R.id.menu_log -> showDialogFragment<AppLogDialog>()
|
||||||
R.id.menu_toc_regex -> showDialogFragment(
|
R.id.menu_toc_regex -> showDialogFragment(
|
||||||
TxtTocRuleDialog(ReadBook.book?.tocUrl)
|
TxtTocRuleDialog(ReadBook.book?.tocUrl)
|
||||||
)
|
)
|
||||||
|
|
||||||
R.id.menu_reverse_content -> ReadBook.book?.let {
|
R.id.menu_reverse_content -> ReadBook.book?.let {
|
||||||
viewModel.reverseContent(it)
|
viewModel.reverseContent(it)
|
||||||
}
|
}
|
||||||
|
|
||||||
R.id.menu_set_charset -> showCharsetConfig()
|
R.id.menu_set_charset -> showCharsetConfig()
|
||||||
R.id.menu_image_style -> {
|
R.id.menu_image_style -> {
|
||||||
val imgStyles =
|
val imgStyles =
|
||||||
@@ -405,12 +416,29 @@ class ReadBookActivity : BaseReadBookActivity(),
|
|||||||
ReadBook.loadContent(false)
|
ReadBook.loadContent(false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
R.id.menu_get_progress -> ReadBook.book?.let {
|
R.id.menu_get_progress -> ReadBook.book?.let {
|
||||||
viewModel.syncBookProgress(it) { progress ->
|
viewModel.syncBookProgress(it) { progress ->
|
||||||
sureSyncProgress(progress)
|
sureSyncProgress(progress)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
R.id.menu_same_title_removed -> viewModel.reverseRemoveSameTitle()
|
|
||||||
|
R.id.menu_same_title_removed -> {
|
||||||
|
ReadBook.book?.let {
|
||||||
|
val contentProcessor = ContentProcessor.get(it)
|
||||||
|
val textChapter = ReadBook.curTextChapter
|
||||||
|
if (textChapter != null
|
||||||
|
&& !textChapter.sameTitleRemoved
|
||||||
|
&& !contentProcessor.removeSameTitleCache.contains(
|
||||||
|
textChapter.chapter.getFileName("nr")
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
toastOnUi("未找到可移除的重复标题")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
viewModel.reverseRemoveSameTitle()
|
||||||
|
}
|
||||||
|
|
||||||
R.id.menu_help -> showReadMenuHelp()
|
R.id.menu_help -> showReadMenuHelp()
|
||||||
}
|
}
|
||||||
return super.onCompatOptionsItemSelected(item)
|
return super.onCompatOptionsItemSelected(item)
|
||||||
@@ -477,34 +505,41 @@ class ReadBookActivity : BaseReadBookActivity(),
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
isNextKey(keyCode) -> {
|
isNextKey(keyCode) -> {
|
||||||
if (keyCode != KeyEvent.KEYCODE_UNKNOWN) {
|
if (keyCode != KeyEvent.KEYCODE_UNKNOWN) {
|
||||||
binding.readView.pageDelegate?.keyTurnPage(PageDirection.NEXT)
|
binding.readView.pageDelegate?.keyTurnPage(PageDirection.NEXT)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
keyCode == KeyEvent.KEYCODE_VOLUME_UP -> {
|
keyCode == KeyEvent.KEYCODE_VOLUME_UP -> {
|
||||||
if (volumeKeyPage(PageDirection.PREV)) {
|
if (volumeKeyPage(PageDirection.PREV)) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
keyCode == KeyEvent.KEYCODE_VOLUME_DOWN -> {
|
keyCode == KeyEvent.KEYCODE_VOLUME_DOWN -> {
|
||||||
if (volumeKeyPage(PageDirection.NEXT)) {
|
if (volumeKeyPage(PageDirection.NEXT)) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
keyCode == KeyEvent.KEYCODE_PAGE_UP -> {
|
keyCode == KeyEvent.KEYCODE_PAGE_UP -> {
|
||||||
binding.readView.pageDelegate?.keyTurnPage(PageDirection.PREV)
|
binding.readView.pageDelegate?.keyTurnPage(PageDirection.PREV)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
keyCode == KeyEvent.KEYCODE_PAGE_DOWN -> {
|
keyCode == KeyEvent.KEYCODE_PAGE_DOWN -> {
|
||||||
binding.readView.pageDelegate?.keyTurnPage(PageDirection.NEXT)
|
binding.readView.pageDelegate?.keyTurnPage(PageDirection.NEXT)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
keyCode == KeyEvent.KEYCODE_SPACE -> {
|
keyCode == KeyEvent.KEYCODE_SPACE -> {
|
||||||
binding.readView.pageDelegate?.keyTurnPage(PageDirection.NEXT)
|
binding.readView.pageDelegate?.keyTurnPage(PageDirection.NEXT)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
keyCode == KeyEvent.KEYCODE_BACK -> {
|
keyCode == KeyEvent.KEYCODE_BACK -> {
|
||||||
if (isShowingSearchResult) {
|
if (isShowingSearchResult) {
|
||||||
exitSearchMenu()
|
exitSearchMenu()
|
||||||
@@ -544,6 +579,7 @@ class ReadBookActivity : BaseReadBookActivity(),
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
KeyEvent.KEYCODE_BACK -> {
|
KeyEvent.KEYCODE_BACK -> {
|
||||||
event?.let {
|
event?.let {
|
||||||
if ((event.flags and KeyEvent.FLAG_CANCELED_LONG_PRESS == 0)
|
if ((event.flags and KeyEvent.FLAG_CANCELED_LONG_PRESS == 0)
|
||||||
@@ -585,12 +621,14 @@ class ReadBookActivity : BaseReadBookActivity(),
|
|||||||
event.rawX + cursorLeft.width,
|
event.rawX + cursorLeft.width,
|
||||||
event.rawY - cursorLeft.height
|
event.rawY - cursorLeft.height
|
||||||
)
|
)
|
||||||
|
|
||||||
R.id.cursor_right -> readView.curPage.selectEndMove(
|
R.id.cursor_right -> readView.curPage.selectEndMove(
|
||||||
event.rawX - cursorRight.width,
|
event.rawX - cursorRight.width,
|
||||||
event.rawY - cursorRight.height
|
event.rawY - cursorRight.height
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
MotionEvent.ACTION_UP -> showTextActionMenu()
|
MotionEvent.ACTION_UP -> showTextActionMenu()
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
@@ -657,6 +695,7 @@ class ReadBookActivity : BaseReadBookActivity(),
|
|||||||
1 -> binding.readView.aloudStartSelect()
|
1 -> binding.readView.aloudStartSelect()
|
||||||
else -> speak(binding.readView.getSelectText())
|
else -> speak(binding.readView.getSelectText())
|
||||||
}
|
}
|
||||||
|
|
||||||
R.id.menu_bookmark -> binding.readView.curPage.let {
|
R.id.menu_bookmark -> binding.readView.curPage.let {
|
||||||
val bookmark = it.createBookmark()
|
val bookmark = it.createBookmark()
|
||||||
if (bookmark == null) {
|
if (bookmark == null) {
|
||||||
@@ -666,6 +705,7 @@ class ReadBookActivity : BaseReadBookActivity(),
|
|||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
R.id.menu_replace -> {
|
R.id.menu_replace -> {
|
||||||
val scopes = arrayListOf<String>()
|
val scopes = arrayListOf<String>()
|
||||||
ReadBook.book?.name?.let {
|
ReadBook.book?.name?.let {
|
||||||
@@ -683,11 +723,13 @@ class ReadBookActivity : BaseReadBookActivity(),
|
|||||||
)
|
)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
R.id.menu_search_content -> {
|
R.id.menu_search_content -> {
|
||||||
viewModel.searchContentQuery = selectedText
|
viewModel.searchContentQuery = selectedText
|
||||||
openSearchActivity(selectedText)
|
openSearchActivity(selectedText)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
R.id.menu_dict -> {
|
R.id.menu_dict -> {
|
||||||
showDialogFragment(DictDialog(selectedText))
|
showDialogFragment(DictDialog(selectedText))
|
||||||
return true
|
return true
|
||||||
@@ -1010,7 +1052,6 @@ class ReadBookActivity : BaseReadBookActivity(),
|
|||||||
override fun exitSearchMenu() {
|
override fun exitSearchMenu() {
|
||||||
if (isShowingSearchResult) {
|
if (isShowingSearchResult) {
|
||||||
isShowingSearchResult = false
|
isShowingSearchResult = false
|
||||||
ContentProcessor.enableRemoveSameTitle = true
|
|
||||||
binding.searchMenu.invalidate()
|
binding.searchMenu.invalidate()
|
||||||
binding.searchMenu.invisible()
|
binding.searchMenu.invisible()
|
||||||
binding.readView.isTextSelected = false
|
binding.readView.isTextSelected = false
|
||||||
@@ -1110,6 +1151,7 @@ class ReadBookActivity : BaseReadBookActivity(),
|
|||||||
ReadAloud.upReadAloudClass()
|
ReadAloud.upReadAloudClass()
|
||||||
ReadBook.readAloud()
|
ReadBook.readAloud()
|
||||||
}
|
}
|
||||||
|
|
||||||
BaseReadAloudService.pause -> ReadAloud.resume(this)
|
BaseReadAloudService.pause -> ReadAloud.resume(this)
|
||||||
else -> ReadAloud.pause(this)
|
else -> ReadAloud.pause(this)
|
||||||
}
|
}
|
||||||
@@ -1142,6 +1184,7 @@ class ReadBookActivity : BaseReadBookActivity(),
|
|||||||
viewModel.saveImage(src, Uri.parse(path))
|
viewModel.saveImage(src, Uri.parse(path))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
"selectFolder" -> selectImageDir.launch()
|
"selectFolder" -> selectImageDir.launch()
|
||||||
}
|
}
|
||||||
popupAction.dismiss()
|
popupAction.dismiss()
|
||||||
@@ -1164,15 +1207,18 @@ class ReadBookActivity : BaseReadBookActivity(),
|
|||||||
setCurTextColor(color)
|
setCurTextColor(color)
|
||||||
postEvent(EventBus.UP_CONFIG, false)
|
postEvent(EventBus.UP_CONFIG, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
BG_COLOR -> {
|
BG_COLOR -> {
|
||||||
setCurBg(0, "#${color.hexString}")
|
setCurBg(0, "#${color.hexString}")
|
||||||
postEvent(EventBus.UP_CONFIG, false)
|
postEvent(EventBus.UP_CONFIG, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
TIP_COLOR -> {
|
TIP_COLOR -> {
|
||||||
ReadTipConfig.tipColor = color
|
ReadTipConfig.tipColor = color
|
||||||
postEvent(EventBus.TIP_COLOR, "")
|
postEvent(EventBus.TIP_COLOR, "")
|
||||||
postEvent(EventBus.UP_CONFIG, true)
|
postEvent(EventBus.UP_CONFIG, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
TIP_DIVIDER_COLOR -> {
|
TIP_DIVIDER_COLOR -> {
|
||||||
ReadTipConfig.tipDividerColor = color
|
ReadTipConfig.tipDividerColor = color
|
||||||
postEvent(EventBus.TIP_COLOR, "")
|
postEvent(EventBus.TIP_COLOR, "")
|
||||||
@@ -1233,6 +1279,7 @@ class ReadBookActivity : BaseReadBookActivity(),
|
|||||||
lineIndex,
|
lineIndex,
|
||||||
charIndex + viewModel.searchContentQuery.length - 1
|
charIndex + viewModel.searchContentQuery.length - 1
|
||||||
)
|
)
|
||||||
|
|
||||||
1 -> binding.readView.curPage.selectEndMoveIndex(
|
1 -> binding.readView.curPage.selectEndMoveIndex(
|
||||||
0, lineIndex + 1, charIndex2
|
0, lineIndex + 1, charIndex2
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -155,6 +155,7 @@ class ReadBookViewModel(application: Application) : BaseViewModel(application) {
|
|||||||
is SecurityException, is FileNotFoundException -> {
|
is SecurityException, is FileNotFoundException -> {
|
||||||
permissionDenialLiveData.postValue(1)
|
permissionDenialLiveData.postValue(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
else -> {
|
else -> {
|
||||||
AppLog.put("LoadTocError:${it.localizedMessage}", it)
|
AppLog.put("LoadTocError:${it.localizedMessage}", it)
|
||||||
ReadBook.upMsg("LoadTocError:${it.localizedMessage}")
|
ReadBook.upMsg("LoadTocError:${it.localizedMessage}")
|
||||||
@@ -434,14 +435,12 @@ class ReadBookViewModel(application: Application) : BaseViewModel(application) {
|
|||||||
*/
|
*/
|
||||||
fun reverseRemoveSameTitle() {
|
fun reverseRemoveSameTitle() {
|
||||||
execute {
|
execute {
|
||||||
val book = ReadBook.book
|
val book = ReadBook.book ?: return@execute
|
||||||
val textChapter = ReadBook.curTextChapter
|
val textChapter = ReadBook.curTextChapter ?: return@execute
|
||||||
if (book != null && textChapter != null) {
|
BookHelp.setRemoveSameTitle(
|
||||||
BookHelp.setRemoveSameTitle(
|
book, textChapter.chapter, !textChapter.sameTitleRemoved
|
||||||
book, textChapter.chapter, !textChapter.sameTitleRemoved
|
)
|
||||||
)
|
ReadBook.loadContent(ReadBook.durChapterIndex)
|
||||||
ReadBook.loadContent(ReadBook.durChapterIndex)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -27,8 +27,10 @@ import io.legado.app.ui.widget.recycler.UpLinearLayoutManager
|
|||||||
import io.legado.app.ui.widget.recycler.VerticalDivider
|
import io.legado.app.ui.widget.recycler.VerticalDivider
|
||||||
import io.legado.app.utils.*
|
import io.legado.app.utils.*
|
||||||
import io.legado.app.utils.viewbindingdelegate.viewBinding
|
import io.legado.app.utils.viewbindingdelegate.viewBinding
|
||||||
|
import kotlinx.coroutines.Deferred
|
||||||
import kotlinx.coroutines.Dispatchers.IO
|
import kotlinx.coroutines.Dispatchers.IO
|
||||||
import kotlinx.coroutines.Job
|
import kotlinx.coroutines.Job
|
||||||
|
import kotlinx.coroutines.async
|
||||||
import kotlinx.coroutines.ensureActive
|
import kotlinx.coroutines.ensureActive
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
@@ -47,6 +49,7 @@ class SearchContentActivity :
|
|||||||
}
|
}
|
||||||
private var durChapterIndex = 0
|
private var durChapterIndex = 0
|
||||||
private var searchJob: Job? = null
|
private var searchJob: Job? = null
|
||||||
|
private var initJob: Deferred<*>? = null
|
||||||
|
|
||||||
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
||||||
val bbg = bottomBackground
|
val bbg = bottomBackground
|
||||||
@@ -56,38 +59,37 @@ class SearchContentActivity :
|
|||||||
binding.ivSearchContentTop.setColorFilter(btc)
|
binding.ivSearchContentTop.setColorFilter(btc)
|
||||||
binding.ivSearchContentBottom.setColorFilter(btc)
|
binding.ivSearchContentBottom.setColorFilter(btc)
|
||||||
val searchResultList = IntentData.get<List<SearchResult>>("searchResultList")
|
val searchResultList = IntentData.get<List<SearchResult>>("searchResultList")
|
||||||
|
val position = intent.getIntExtra("searchResultIndex", 0)
|
||||||
val noSearchResult = searchResultList == null
|
val noSearchResult = searchResultList == null
|
||||||
initSearchView(!noSearchResult)
|
initSearchView(!noSearchResult)
|
||||||
initRecyclerView()
|
initRecyclerView()
|
||||||
initView()
|
initView()
|
||||||
intent.getStringExtra("bookUrl")?.let { bookUrl ->
|
val bookUrl = intent.getStringExtra("bookUrl") ?: return
|
||||||
viewModel.initBook(bookUrl) {
|
viewModel.initBook(bookUrl) {
|
||||||
searchResultList?.let {
|
initSearchResultList(searchResultList, position)
|
||||||
viewModel.searchResultList.addAll(it)
|
initBook(noSearchResult)
|
||||||
viewModel.searchResultCounts = it.size
|
|
||||||
adapter.setItems(it)
|
|
||||||
val position = intent.getIntExtra("searchResultIndex", 0)
|
|
||||||
binding.recyclerView.scrollToPosition(position)
|
|
||||||
}
|
|
||||||
initBook(noSearchResult)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun dispatchTouchEvent(ev: MotionEvent): Boolean {
|
override fun dispatchTouchEvent(ev: MotionEvent): Boolean {
|
||||||
if (ev.action == MotionEvent.ACTION_DOWN) {
|
if (ev.action == MotionEvent.ACTION_DOWN) {
|
||||||
searchView.post {
|
currentFocus?.let {
|
||||||
currentFocus?.let {
|
if (it.shouldHideSoftInput(ev)) {
|
||||||
if (it is EditText) {
|
it.hideSoftInput()
|
||||||
it.clearFocus()
|
|
||||||
it.hideSoftInput()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return super.dispatchTouchEvent(ev)
|
return super.dispatchTouchEvent(ev)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun initSearchResultList(list: List<SearchResult>?, position: Int) {
|
||||||
|
list ?: return
|
||||||
|
viewModel.searchResultList.addAll(list)
|
||||||
|
viewModel.searchResultCounts = list.size
|
||||||
|
adapter.setItems(list)
|
||||||
|
binding.recyclerView.scrollToPosition(position)
|
||||||
|
}
|
||||||
|
|
||||||
private fun initSearchView(clearFocus: Boolean) {
|
private fun initSearchView(clearFocus: Boolean) {
|
||||||
searchView.applyTint(primaryTextColor)
|
searchView.applyTint(primaryTextColor)
|
||||||
searchView.onActionViewExpanded()
|
searchView.onActionViewExpanded()
|
||||||
@@ -149,7 +151,7 @@ class SearchContentActivity :
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun initCacheFileNames(book: Book) {
|
private fun initCacheFileNames(book: Book) {
|
||||||
launch {
|
initJob = async {
|
||||||
withContext(IO) {
|
withContext(IO) {
|
||||||
viewModel.cacheChapterNames.addAll(BookHelp.getChapterFiles(book))
|
viewModel.cacheChapterNames.addAll(BookHelp.getChapterFiles(book))
|
||||||
}
|
}
|
||||||
@@ -179,8 +181,8 @@ class SearchContentActivity :
|
|||||||
viewModel.lastQuery = query
|
viewModel.lastQuery = query
|
||||||
binding.refreshProgressBar.isAutoLoading = true
|
binding.refreshProgressBar.isAutoLoading = true
|
||||||
binding.fbStop.visible()
|
binding.fbStop.visible()
|
||||||
ContentProcessor.enableRemoveSameTitle = false
|
|
||||||
searchJob = launch(IO) {
|
searchJob = launch(IO) {
|
||||||
|
initJob?.await()
|
||||||
kotlin.runCatching {
|
kotlin.runCatching {
|
||||||
appDb.bookChapterDao.getChapterList(viewModel.bookUrl).forEach { bookChapter ->
|
appDb.bookChapterDao.getChapterList(viewModel.bookUrl).forEach { bookChapter ->
|
||||||
ensureActive()
|
ensureActive()
|
||||||
@@ -211,7 +213,6 @@ class SearchContentActivity :
|
|||||||
}.onFailure {
|
}.onFailure {
|
||||||
AppLog.put("全文搜索出错\n${it.localizedMessage}", it)
|
AppLog.put("全文搜索出错\n${it.localizedMessage}", it)
|
||||||
}
|
}
|
||||||
ContentProcessor.enableRemoveSameTitle = true
|
|
||||||
binding.tvCurrentSearchInfo.post {
|
binding.tvCurrentSearchInfo.post {
|
||||||
binding.fbStop.invisible()
|
binding.fbStop.invisible()
|
||||||
binding.refreshProgressBar.isAutoLoading = false
|
binding.refreshProgressBar.isAutoLoading = false
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ import kotlin.coroutines.coroutineContext
|
|||||||
class SearchContentViewModel(application: Application) : BaseViewModel(application) {
|
class SearchContentViewModel(application: Application) : BaseViewModel(application) {
|
||||||
var bookUrl: String = ""
|
var bookUrl: String = ""
|
||||||
var book: Book? = null
|
var book: Book? = null
|
||||||
private var contentProcessor: ContentProcessor? = null
|
var contentProcessor: ContentProcessor? = null
|
||||||
var lastQuery: String = ""
|
var lastQuery: String = ""
|
||||||
var searchResultCounts = 0
|
var searchResultCounts = 0
|
||||||
val cacheChapterNames = hashSetOf<String>()
|
val cacheChapterNames = hashSetOf<String>()
|
||||||
@@ -38,10 +38,9 @@ class SearchContentViewModel(application: Application) : BaseViewModel(applicati
|
|||||||
|
|
||||||
suspend fun searchChapter(
|
suspend fun searchChapter(
|
||||||
query: String,
|
query: String,
|
||||||
chapter: BookChapter?
|
chapter: BookChapter
|
||||||
): List<SearchResult> {
|
): List<SearchResult> {
|
||||||
val searchResultsWithinChapter: MutableList<SearchResult> = mutableListOf()
|
val searchResultsWithinChapter: MutableList<SearchResult> = mutableListOf()
|
||||||
chapter ?: return searchResultsWithinChapter
|
|
||||||
val book = book ?: return searchResultsWithinChapter
|
val book = book ?: return searchResultsWithinChapter
|
||||||
val chapterContent = BookHelp.getContent(book, chapter) ?: return searchResultsWithinChapter
|
val chapterContent = BookHelp.getContent(book, chapter) ?: return searchResultsWithinChapter
|
||||||
coroutineContext.ensureActive()
|
coroutineContext.ensureActive()
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import android.icu.text.Collator
|
|||||||
import android.icu.util.ULocale
|
import android.icu.util.ULocale
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import android.text.Editable
|
import android.text.Editable
|
||||||
|
import io.legado.app.constant.AppPattern
|
||||||
import io.legado.app.constant.AppPattern.dataUriRegex
|
import io.legado.app.constant.AppPattern.dataUriRegex
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.lang.Character.codePointCount
|
import java.lang.Character.codePointCount
|
||||||
@@ -127,3 +128,7 @@ fun CharSequence.toStringArray(): Array<String> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun String.escapeRegex(): String {
|
||||||
|
return replace(AppPattern.regexCharRegex, "\\\\$0")
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import android.graphics.Bitmap
|
|||||||
import android.graphics.Canvas
|
import android.graphics.Canvas
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.text.Html
|
import android.text.Html
|
||||||
|
import android.view.MotionEvent
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.View.*
|
import android.view.View.*
|
||||||
import android.view.inputmethod.InputMethodManager
|
import android.view.inputmethod.InputMethodManager
|
||||||
@@ -195,4 +196,17 @@ fun PopupMenu.show(x: Int, y: Int) {
|
|||||||
}.onFailure {
|
}.onFailure {
|
||||||
it.printOnDebug()
|
it.printOnDebug()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun View.shouldHideSoftInput(event: MotionEvent): Boolean {
|
||||||
|
if (this is EditText) {
|
||||||
|
val l = intArrayOf(0, 0)
|
||||||
|
getLocationInWindow(l)
|
||||||
|
val left = l[0]
|
||||||
|
val top = l[1]
|
||||||
|
val bottom = top + getHeight()
|
||||||
|
val right = left + getWidth()
|
||||||
|
return !(event.x > left && event.x < right && event.y > top && event.y < bottom)
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user