diff --git a/app/src/main/java/io/legado/app/ui/book/read/ReadBookActivity.kt b/app/src/main/java/io/legado/app/ui/book/read/ReadBookActivity.kt index cac23296c..d93bb840d 100644 --- a/app/src/main/java/io/legado/app/ui/book/read/ReadBookActivity.kt +++ b/app/src/main/java/io/legado/app/ui/book/read/ReadBookActivity.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$key") val searchResultList = IntentData.get>("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(PreferKey.showBrightnessView) { readMenu.upBrightnessState() } + observeEvent>(EventBus.SEARCH_RESULT) { + viewModel.searchResultList = it + } } private fun upScreenTimeOut() { diff --git a/app/src/main/java/io/legado/app/ui/book/read/ReadBookViewModel.kt b/app/src/main/java/io/legado/app/ui/book/read/ReadBookViewModel.kt index ec86f9cfd..7ae2a1589 100644 --- a/app/src/main/java/io/legado/app/ui/book/read/ReadBookViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/book/read/ReadBookViewModel.kt @@ -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() var isInitFinish = false var searchContentQuery = "" + var searchResultList: List? = 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) } diff --git a/app/src/main/java/io/legado/app/ui/book/read/SearchMenu.kt b/app/src/main/java/io/legado/app/ui/book/read/SearchMenu.kt index b429b18a3..88a33f08d 100644 --- a/app/src/main/java/io/legado/app/ui/book/read/SearchMenu.kt +++ b/app/src/main/java/io/legado/app/ui/book/read/SearchMenu.kt @@ -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) } } diff --git a/app/src/main/java/io/legado/app/ui/book/read/page/ContentTextView.kt b/app/src/main/java/io/legado/app/ui/book/read/page/ContentTextView.kt index a9fdb979a..a0cdb0f34 100644 --- a/app/src/main/java/io/legado/app/ui/book/read/page/ContentTextView.kt +++ b/app/src/main/java/io/legado/app/ui/book/read/page/ContentTextView.kt @@ -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 } } } diff --git a/app/src/main/java/io/legado/app/ui/book/read/page/PageView.kt b/app/src/main/java/io/legado/app/ui/book/read/page/PageView.kt index 13bc4c849..8f7e85619 100644 --- a/app/src/main/java/io/legado/app/ui/book/read/page/PageView.kt +++ b/app/src/main/java/io/legado/app/ui/book/read/page/PageView.kt @@ -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? { diff --git a/app/src/main/java/io/legado/app/ui/book/searchContent/SearchContentActivity.kt b/app/src/main/java/io/legado/app/ui/book/searchContent/SearchContentActivity.kt index a44132933..9869497ed 100644 --- a/app/src/main/java/io/legado/app/ui/book/searchContent/SearchContentActivity.kt +++ b/app/src/main/java/io/legado/app/ui/book/searchContent/SearchContentActivity.kt @@ -56,9 +56,18 @@ class SearchContentActivity : initSearchView() initRecyclerView() initView() - intent.getStringExtra("bookUrl")?.let { - viewModel.initBook(it) { - initBook() + val searchResultList = IntentData.get>("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) 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() } diff --git a/app/src/main/java/io/legado/app/ui/book/searchContent/SearchContentAdapter.kt b/app/src/main/java/io/legado/app/ui/book/searchContent/SearchContentAdapter.kt index c70ff63b0..b072291de 100644 --- a/app/src/main/java/io/legado/app/ui/book/searchContent/SearchContentAdapter.kt +++ b/app/src/main/java/io/legado/app/ui/book/searchContent/SearchContentAdapter.kt @@ -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 } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/book/searchContent/SearchContentViewModel.kt b/app/src/main/java/io/legado/app/ui/book/searchContent/SearchContentViewModel.kt index c529145ff..ef6e87b17 100644 --- a/app/src/main/java/io/legado/app/ui/book/searchContent/SearchContentViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/book/searchContent/SearchContentViewModel.kt @@ -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 diff --git a/app/src/main/java/io/legado/app/ui/book/searchContent/SearchResult.kt b/app/src/main/java/io/legado/app/ui/book/searchContent/SearchResult.kt index 8def7cb5d..6da724e3c 100644 --- a/app/src/main/java/io/legado/app/ui/book/searchContent/SearchResult.kt +++ b/app/src/main/java/io/legado/app/ui/book/searchContent/SearchResult.kt @@ -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("
") + append(leftString.colorTextForHtml(textColor)) + append(query.colorTextForHtml(accentColor)) + append(rightString.colorTextForHtml(textColor)) + } HtmlCompat.fromHtml(html, HtmlCompat.FROM_HTML_MODE_LEGACY) } else { HtmlCompat.fromHtml(