优化全文搜索

pull/2072/head
821938089 2 years ago
parent 316cd246e2
commit ea59082186
  1. 35
      app/src/main/java/io/legado/app/ui/book/read/ReadBookActivity.kt
  2. 38
      app/src/main/java/io/legado/app/ui/book/read/ReadBookViewModel.kt
  3. 22
      app/src/main/java/io/legado/app/ui/book/read/SearchMenu.kt
  4. 3
      app/src/main/java/io/legado/app/ui/book/read/page/ContentTextView.kt
  5. 4
      app/src/main/java/io/legado/app/ui/book/read/page/PageView.kt
  6. 22
      app/src/main/java/io/legado/app/ui/book/searchContent/SearchContentActivity.kt
  7. 4
      app/src/main/java/io/legado/app/ui/book/searchContent/SearchContentAdapter.kt
  8. 2
      app/src/main/java/io/legado/app/ui/book/searchContent/SearchContentViewModel.kt
  9. 11
      app/src/main/java/io/legado/app/ui/book/searchContent/SearchResult.kt

@ -113,13 +113,15 @@ class ReadBookActivity : BaseReadBookActivity(),
it ?: return@registerForActivityResult
it.data?.let { data ->
val key = data.getLongExtra("key", System.currentTimeMillis())
val index = data.getIntExtra("index", 0)
val searchResult = IntentData.get<SearchResult>("searchResult$key")
val searchResultList = IntentData.get<List<SearchResult>>("searchResultList$key")
if (searchResult != null && searchResultList != null) {
viewModel.searchContentQuery = searchResult.query
binding.searchMenu.upSearchResultList(searchResultList)
isShowingSearchResult = true
binding.searchMenu.updateSearchResultIndex(searchResultList.indexOf(searchResult))
viewModel.searchResultIndex = index
binding.searchMenu.updateSearchResultIndex(index)
binding.searchMenu.selectedSearchResult?.let { currentResult ->
skipToSearch(currentResult)
showActionMenu()
@ -888,6 +890,12 @@ class ReadBookActivity : BaseReadBookActivity(),
searchContentActivity.launch(Intent(this, SearchContentActivity::class.java).apply {
putExtra("bookUrl", it.bookUrl)
putExtra("searchWord", searchWord ?: viewModel.searchContentQuery)
putExtra("searchResultIndex", viewModel.searchResultIndex)
viewModel.searchResultList?.first()?.let {
if (it.query == viewModel.searchContentQuery) {
IntentData.put("searchResultList", viewModel.searchResultList)
}
}
})
}
}
@ -930,6 +938,8 @@ class ReadBookActivity : BaseReadBookActivity(),
isShowingSearchResult = false
binding.searchMenu.invalidate()
binding.searchMenu.invisible()
binding.readView.isTextSelected = false
binding.readView.curPage.cancelSelect(true)
}
}
@ -1052,7 +1062,8 @@ class ReadBookActivity : BaseReadBookActivity(),
}
}
override fun navigateToSearch(searchResult: SearchResult) {
override fun navigateToSearch(searchResult: SearchResult, index: Int) {
viewModel.searchResultIndex = index
skipToSearch(searchResult)
}
@ -1062,22 +1073,23 @@ class ReadBookActivity : BaseReadBookActivity(),
fun jumpToPosition() {
ReadBook.curTextChapter?.let {
binding.searchMenu.updateSearchInfo()
val positions = viewModel.searchResultPositions(it, searchResult)
ReadBook.skipToPage(positions[0]) {
val (pageIndex, lineIndex, charIndex, addLine, charIndex2) =
viewModel.searchResultPositions(it, searchResult)
ReadBook.skipToPage(pageIndex) {
launch {
isSelectingSearchResult = true
binding.readView.curPage.selectStartMoveIndex(0, positions[1], positions[2])
when (positions[3]) {
binding.readView.curPage.selectStartMoveIndex(0, lineIndex, charIndex)
when (addLine) {
0 -> binding.readView.curPage.selectEndMoveIndex(
0,
positions[1],
positions[2] + viewModel.searchContentQuery.length - 1
lineIndex,
charIndex + viewModel.searchContentQuery.length - 1
)
1 -> binding.readView.curPage.selectEndMoveIndex(
0, positions[1] + 1, positions[4]
0, lineIndex + 1, charIndex2
)
//consider change page, jump to scroll position
-1 -> binding.readView.curPage.selectEndMoveIndex(1, 0, positions[4])
-1 -> binding.readView.curPage.selectEndMoveIndex(1, 0, charIndex2)
}
binding.readView.isTextSelected = true
isSelectingSearchResult = false
@ -1196,6 +1208,9 @@ class ReadBookActivity : BaseReadBookActivity(),
observeEvent<String>(PreferKey.showBrightnessView) {
readMenu.upBrightnessState()
}
observeEvent<List<SearchResult>>(EventBus.SEARCH_RESULT) {
viewModel.searchResultList = it
}
}
private fun upScreenTimeOut() {

@ -34,7 +34,6 @@ import io.legado.app.utils.toStringArray
import io.legado.app.utils.toastOnUi
import kotlinx.coroutines.Dispatchers.IO
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
/**
* 阅读界面数据处理
@ -43,6 +42,8 @@ class ReadBookViewModel(application: Application) : BaseViewModel(application) {
val permissionDenialLiveData = MutableLiveData<Int>()
var isInitFinish = false
var searchContentQuery = ""
var searchResultList: List<SearchResult>? = null
var searchResultIndex: Int = 0
private var changeSourceCoroutine: Coroutine<*>? = null
/**
@ -360,53 +361,54 @@ class ReadBookViewModel(application: Application) : BaseViewModel(application) {
// calculate search result's pageIndex
val pages = textChapter.pages
val content = textChapter.getContent()
val queryLength = searchContentQuery.length
var count = 0
var index = content.indexOf(searchContentQuery)
while (count != searchResult.resultCountWithinChapter) {
index = content.indexOf(searchContentQuery, index + 1)
index = content.indexOf(searchContentQuery, index + queryLength)
count += 1
}
val contentPosition = index
var pageIndex = 0
var length = pages[pageIndex].text.length
while (length < contentPosition) {
while (length < contentPosition && pageIndex + 1 < pages.size) {
pageIndex += 1
if (pageIndex > pages.size) {
pageIndex = pages.size
break
}
length += pages[pageIndex].text.length
}
// calculate search result's lineIndex
val currentPage = pages[pageIndex]
val curTextLines = currentPage.textLines
var lineIndex = 0
length = length - currentPage.text.length + currentPage.textLines[lineIndex].text.length
while (length < contentPosition) {
var curLine = curTextLines[lineIndex]
length = length - currentPage.text.length + curLine.text.length
if (curLine.isParagraphEnd) length++
while (length < contentPosition && lineIndex + 1 < curTextLines.size) {
lineIndex += 1
if (lineIndex > currentPage.textLines.size) {
lineIndex = currentPage.textLines.size
break
}
length += currentPage.textLines[lineIndex].text.length
curLine = curTextLines[lineIndex]
length += curLine.text.length
if (curLine.isParagraphEnd) length++
}
// charIndex
val currentLine = currentPage.textLines[lineIndex]
length -= currentLine.text.length
var curLineLength = currentLine.text.length
if (currentLine.isParagraphEnd) curLineLength++
length -= curLineLength
val charIndex = contentPosition - length
var addLine = 0
var charIndex2 = 0
// change line
if ((charIndex + searchContentQuery.length) > currentLine.text.length) {
if ((charIndex + queryLength) > curLineLength) {
addLine = 1
charIndex2 = charIndex + searchContentQuery.length - currentLine.text.length - 1
charIndex2 = charIndex + queryLength - curLineLength - 1
}
// changePage
if ((lineIndex + addLine + 1) > currentPage.textLines.size) {
addLine = -1
charIndex2 = charIndex + searchContentQuery.length - currentLine.text.length - 1
charIndex2 = charIndex + queryLength - curLineLength - 1
}
return arrayOf(pageIndex, lineIndex, charIndex, addLine, charIndex2)
}

@ -148,22 +148,34 @@ class SearchMenu @JvmOverloads constructor(
fabLeft.setOnClickListener {
updateSearchResultIndex(currentSearchResultIndex - 1)
callBack.navigateToSearch(searchResultList[currentSearchResultIndex])
callBack.navigateToSearch(
searchResultList[currentSearchResultIndex],
currentSearchResultIndex
)
}
ivSearchContentUp.setOnClickListener {
updateSearchResultIndex(currentSearchResultIndex - 1)
callBack.navigateToSearch(searchResultList[currentSearchResultIndex])
callBack.navigateToSearch(
searchResultList[currentSearchResultIndex],
currentSearchResultIndex
)
}
ivSearchContentDown.setOnClickListener {
updateSearchResultIndex(currentSearchResultIndex + 1)
callBack.navigateToSearch(searchResultList[currentSearchResultIndex])
callBack.navigateToSearch(
searchResultList[currentSearchResultIndex],
currentSearchResultIndex
)
}
fabRight.setOnClickListener {
updateSearchResultIndex(currentSearchResultIndex + 1)
callBack.navigateToSearch(searchResultList[currentSearchResultIndex])
callBack.navigateToSearch(
searchResultList[currentSearchResultIndex],
currentSearchResultIndex
)
}
}
@ -225,7 +237,7 @@ class SearchMenu @JvmOverloads constructor(
fun upSystemUiVisibility()
fun exitSearchMenu()
fun showMenuBar()
fun navigateToSearch(searchResult: SearchResult)
fun navigateToSearch(searchResult: SearchResult, index: Int)
}
}

@ -397,12 +397,13 @@ class ContentTextView(context: Context, attrs: AttributeSet?) : View(context, at
upSelectedEnd(x, y + headerHeight)
}
fun cancelSelect() {
fun cancelSelect(fromSearchExit: Boolean = false) {
val last = if (callBack.isScroll) 2 else 0
for (relativePos in 0..last) {
relativePage(relativePos).textLines.forEach { textLine ->
textLine.textChars.forEach {
it.selected = false
if (fromSearchExit) it.isSearchResult = false
}
}
}

@ -294,8 +294,8 @@ class PageView(context: Context) : FrameLayout(context) {
binding.contentTextView.selectEndMoveIndex(relativePagePos, lineIndex, charIndex)
}
fun cancelSelect() {
binding.contentTextView.cancelSelect()
fun cancelSelect(fromSearchExit: Boolean = false) {
binding.contentTextView.cancelSelect(fromSearchExit)
}
fun createBookmark(): Bookmark? {

@ -56,9 +56,18 @@ class SearchContentActivity :
initSearchView()
initRecyclerView()
initView()
intent.getStringExtra("bookUrl")?.let {
viewModel.initBook(it) {
initBook()
val searchResultList = IntentData.get<List<SearchResult>>("searchResultList")
val submit = searchResultList == null
intent.getStringExtra("bookUrl")?.let { bookUrl ->
viewModel.initBook(bookUrl) {
searchResultList?.let {
viewModel.searchResultList.addAll(it)
viewModel.searchResultCounts = it.size
adapter.setItems(it)
val position = intent.getIntExtra("searchResultIndex", 0)
binding.recyclerView.scrollToPosition(position)
}
initBook(submit)
}
}
}
@ -101,14 +110,14 @@ class SearchContentActivity :
}
@SuppressLint("SetTextI18n")
private fun initBook() {
private fun initBook(submit: Boolean = true) {
binding.tvCurrentSearchInfo.text =
this.getString(R.string.search_content_size) + ": ${viewModel.searchResultCounts}"
viewModel.book?.let {
initCacheFileNames(it)
durChapterIndex = it.durChapterIndex
intent.getStringExtra("searchWord")?.let { searchWord ->
searchView.setQuery(searchWord, true)
searchView.setQuery(searchWord, submit)
}
}
}
@ -182,13 +191,14 @@ class SearchContentActivity :
val isLocalBook: Boolean
get() = viewModel.book?.isLocalBook() == true
override fun openSearchResult(searchResult: SearchResult) {
override fun openSearchResult(searchResult: SearchResult, index: Int) {
postEvent(EventBus.SEARCH_RESULT, viewModel.searchResultList as List<SearchResult>)
val searchData = Intent()
val key = System.currentTimeMillis()
IntentData.put("searchResult$key", searchResult)
IntentData.put("searchResultList$key", viewModel.searchResultList)
searchData.putExtra("key", key)
searchData.putExtra("index", index)
setResult(RESULT_OK, searchData)
finish()
}

@ -39,13 +39,13 @@ class SearchContentAdapter(context: Context, val callback: Callback) :
override fun registerListener(holder: ItemViewHolder, binding: ItemSearchListBinding) {
holder.itemView.setOnClickListener {
getItem(holder.layoutPosition)?.let {
if (it.query.isNotBlank()) callback.openSearchResult(it)
if (it.query.isNotBlank()) callback.openSearchResult(it, holder.layoutPosition)
}
}
}
interface Callback {
fun openSearchResult(searchResult: SearchResult)
fun openSearchResult(searchResult: SearchResult, index: Int)
fun durChapterIndex(): Int
}
}

@ -97,7 +97,7 @@ class SearchContentViewModel(application: Application) : BaseViewModel(applicati
while (index >= 0) {
scope.ensureActive()
position.add(index)
index = mContent.indexOf(pattern, index + 1)
index = mContent.indexOf(pattern, index + pattern.length)
}
}
return position

@ -22,10 +22,13 @@ data class SearchResult(
val leftString = resultText.substring(0, queryIndexInSurrounding)
val rightString =
resultText.substring(queryIndexInSurrounding + query.length, resultText.length)
val html = leftString.colorTextForHtml(textColor) +
query.colorTextForHtml(accentColor) +
rightString.colorTextForHtml(textColor) +
chapterTitle.colorTextForHtml(accentColor)
val html = buildString {
append(chapterTitle.colorTextForHtml(accentColor))
append("<br>")
append(leftString.colorTextForHtml(textColor))
append(query.colorTextForHtml(accentColor))
append(rightString.colorTextForHtml(textColor))
}
HtmlCompat.fromHtml(html, HtmlCompat.FROM_HTML_MODE_LEGACY)
} else {
HtmlCompat.fromHtml(

Loading…
Cancel
Save