diff --git a/app/src/main/java/io/legado/app/service/help/ReadBook.kt b/app/src/main/java/io/legado/app/service/help/ReadBook.kt index 5bdcaa25e..dfa337ae7 100644 --- a/app/src/main/java/io/legado/app/service/help/ReadBook.kt +++ b/app/src/main/java/io/legado/app/service/help/ReadBook.kt @@ -326,9 +326,21 @@ object ReadBook { } } - fun searchResultPositions(pages: List, contentPosition: Int): Array{ + fun searchResultPositions(pages: List, indexWithinChapter: Int, query: String): Array{ // // calculate search result's pageIndex + var content = "" + pages.map{ + content+= it.text + } + var count = 1 + var index = content.indexOf(query) + while(count != indexWithinChapter){ + index = content.indexOf(query, index + 1); + count += 1 + } + Log.d("h11128", "new index $index") + val contentPosition = index var pageIndex = 0 var length = pages[pageIndex].text.length Log.d("h11128", "page size ${pages.size}") @@ -348,6 +360,7 @@ object ReadBook { val currentPage = pages[pageIndex] var lineIndex = 0 length = length - currentPage.text.length + currentPage.textLines[lineIndex].text.length + Log.d("h11128", "currentLine ${currentPage.textLines[lineIndex].text}") while (length < contentPosition){ lineIndex += 1 if (lineIndex >currentPage.textLines.size){ @@ -355,14 +368,17 @@ object ReadBook { break } length += currentPage.textLines[lineIndex].text.length - + Log.d("h11128", "currentLine ${currentPage.textLines[lineIndex].text}") } // charIndex + Log.d("h11128", "currentLine ${currentPage.textLines[lineIndex].text}") + Log.d("h11128", "currentLength $length") val currentLine = currentPage.textLines[lineIndex] length -= currentLine.text.length + Log.d("h11128", "currentLength $length") val charIndex = contentPosition - length - + Log.d("h11128", "contentLength $contentPosition") return arrayOf(pageIndex, lineIndex, charIndex) } 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 5b4991c37..fc7e262af 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 @@ -60,6 +60,9 @@ import kotlinx.android.synthetic.main.activity_book_read.* import kotlinx.android.synthetic.main.view_read_menu.* import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers.IO +import kotlinx.coroutines.Dispatchers.Main +import kotlinx.coroutines.async +import kotlinx.coroutines.delay import kotlinx.coroutines.launch import org.jetbrains.anko.sdk27.listeners.onClick import org.jetbrains.anko.startActivity @@ -100,6 +103,7 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_boo override var isAutoPage = false private var screenTimeOut: Long = 0 private var timeBatteryReceiver: TimeBatteryReceiver? = null + private var loadStates: Boolean = false override val pageFactory: TextPageFactory get() = page_view.pageFactory override val headerHeight: Int get() = page_view.curPage.headerHeight @@ -536,6 +540,7 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_boo intent.removeExtra("readAloud") ReadBook.readAloud() } + loadStates = true } /** @@ -547,6 +552,7 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_boo page_view.upContent(relativePosition, resetPageOffset) seek_read_page.progress = ReadBook.durPageIndex } + loadStates = false } /** @@ -770,20 +776,29 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_boo } requestCodeSearchResult -> data?.getIntExtra("index", ReadBook.durChapterIndex)?.let { index -> - val contentPosition = data.getIntExtra("contentPosition", 0) - val query = data.getStringExtra("query") - ReadBook.durChapterIndex = index - ReadBook.saveRead() - ReadBook.loadContent(resetPageOffset = true) - val pages = ReadBook.curTextChapter?.pages - if (pages != null){ - val positions = ReadBook.searchResultPositions(pages, contentPosition) - viewModel.openChapter(index, positions[0]) + launch(IO){ + val indexWithinChapter = data.getIntExtra("indexWithinChapter", 0) + val query = data.getStringExtra("query") + viewModel.openChapter(index) + + // block until load correct chapter and pages + while (ReadBook.durChapterIndex != index || ReadBook.curTextChapter?.pages == null ){ + delay(100L) + } + val pages = ReadBook.curTextChapter?.pages + Log.d("Jason", "Current chapter pages ${pages!!.size}") + val positions = ReadBook.searchResultPositions(pages, indexWithinChapter, query!!) Log.d("h11128", positions[0].toString()) Log.d("h11128", positions[1].toString()) Log.d("h11128", positions[2].toString()) - //page_view.curPage.selectStartMoveIndex(positions[0], positions[1], 0) - //page_view.curPage.selectEndMoveIndex(positions[0], positions[1], 0 + query!!.length ) + //todo: show selected text + val job1 = async(Main){ + ReadBook.skipToPage(positions[0]) + page_view.curPage.selectStartMoveIndex(positions[0], positions[1], 0) + page_view.curPage.selectEndMoveIndex(positions[0], positions[1], 0 + query.length ) + page_view.isTextSelected = true + } + job1.await() } } requestCodeReplace -> onReplaceRuleSave() diff --git a/app/src/main/java/io/legado/app/ui/book/searchContent/SearchListAdapter.kt b/app/src/main/java/io/legado/app/ui/book/searchContent/SearchListAdapter.kt index 8f8a83a88..d2c98b955 100644 --- a/app/src/main/java/io/legado/app/ui/book/searchContent/SearchListAdapter.kt +++ b/app/src/main/java/io/legado/app/ui/book/searchContent/SearchListAdapter.kt @@ -15,6 +15,7 @@ import io.legado.app.help.BookHelp import io.legado.app.lib.theme.accentColor import io.legado.app.utils.getCompatColor import io.legado.app.utils.visible +import kotlinx.android.synthetic.main.item_bookmark.view.* import kotlinx.android.synthetic.main.item_search_list.view.* import org.jetbrains.anko.sdk27.listeners.onClick @@ -25,8 +26,12 @@ class SearchListAdapter(context: Context, val callback: Callback) : override fun convert(holder: ItemViewHolder, item: SearchResult, payloads: MutableList) { with(holder.itemView) { + val isDur = callback.durChapterIndex() == item.chapterIndex if (payloads.isEmpty()) { - tv_search_result.text = HtmlCompat.fromHtml(item.presentText, HtmlCompat.FROM_HTML_MODE_LEGACY) + tv_search_result.text = item.parseText(item.presentText) + if (isDur){ + tv_search_result.paint.isFakeBoldText = true + } } } } @@ -41,5 +46,6 @@ class SearchListAdapter(context: Context, val callback: Callback) : interface Callback { fun openSearchResult(searchResult: SearchResult) + fun durChapterIndex(): Int } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/book/searchContent/SearchListFragment.kt b/app/src/main/java/io/legado/app/ui/book/searchContent/SearchListFragment.kt index a52cfac6a..646153b6c 100644 --- a/app/src/main/java/io/legado/app/ui/book/searchContent/SearchListFragment.kt +++ b/app/src/main/java/io/legado/app/ui/book/searchContent/SearchListFragment.kt @@ -7,12 +7,14 @@ import android.os.Bundle import android.util.Log import android.view.View import androidx.lifecycle.LiveData +import com.hankcs.hanlp.HanLP import io.legado.app.App import io.legado.app.R import io.legado.app.base.VMBaseFragment import io.legado.app.constant.EventBus import io.legado.app.data.entities.Book import io.legado.app.data.entities.BookChapter +import io.legado.app.help.AppConfig import io.legado.app.help.BookHelp import io.legado.app.lib.theme.bottomBackground import io.legado.app.lib.theme.getPrimaryTextColor @@ -40,7 +42,7 @@ class SearchListFragment : VMBaseFragment(R.layout.fragment lateinit var adapter: SearchListAdapter private lateinit var mLayoutManager: UpLinearLayoutManager private var searchResultCounts = 0 - private var pageSize = 0 + private var durChapterIndex = 0 private var searchResultList: MutableList = mutableListOf() override fun onFragmentCreated(view: View, savedInstanceState: Bundle?) { @@ -76,9 +78,11 @@ class SearchListFragment : VMBaseFragment(R.layout.fragment @SuppressLint("SetTextI18n") private fun initBook() { launch { + tv_current_search_info.text = "搜索结果:$searchResultCounts" viewModel.book?.let { initCacheFileNames(it) + durChapterIndex = it.durChapterIndex } } } @@ -117,15 +121,15 @@ class SearchListFragment : VMBaseFragment(R.layout.fragment val job = async(IO){ if (isLocalBook || adapter.cacheFileNames.contains(BookHelp.formatChapterName(chapter))) { searchResults = searchChapter(newText, chapter) - Log.d("h11128", "find ${searchResults.size} results in chapter ${chapter.title}") + //Log.d("h11128", "find ${searchResults.size} results in chapter ${chapter.title}") } } job.await() if (searchResults.isNotEmpty()){ - Log.d("h11128", "load ${searchResults.size} results in chapter ${chapter.title}") + //Log.d("h11128", "load ${searchResults.size} results in chapter ${chapter.title}") searchResultList.addAll(searchResults) tv_current_search_info.text = "搜索结果:$searchResultCounts" - Log.d("h11128", "searchResultList size ${searchResultList.size}") + //Log.d("h11128", "searchResultList size ${searchResultList.size}") adapter.addItems(searchResults) searchResults = listOf() } @@ -134,55 +138,51 @@ class SearchListFragment : VMBaseFragment(R.layout.fragment } } - private fun searchChapter(query: String, chapter: BookChapter?): List { + private suspend fun searchChapter(query: String, chapter: BookChapter?): List { val searchResults: MutableList = mutableListOf() - var positions : List? = listOf() + var positions : List = listOf() + var replaceContents: List? = null + var totalContents = "" if (chapter != null){ viewModel.book?.let { bookSource -> val bookContent = BookHelp.getContent(bookSource, chapter) if (bookContent != null){ - //todo: 搜索替换后的正文句子列表 - /* - chapter.title = when (AppConfig.chineseConverterType) { - 1 -> HanLP.convertToSimplifiedChinese(chapter.title) - 2 -> HanLP.convertToTraditionalChinese(chapter.title) - else -> chapter.title - } - var replaceContents: List? = null - bookContent?.let { + //搜索替换后的正文 + val job = async(IO) { + chapter.title = when (AppConfig.chineseConverterType) { + 1 -> HanLP.convertToSimplifiedChinese(chapter.title) + 2 -> HanLP.convertToTraditionalChinese(chapter.title) + else -> chapter.title + } replaceContents = BookHelp.disposeContent( chapter.title, bookSource.name, bookSource.bookUrl, - it, + bookContent, bookSource.useReplaceRule ) } - - replaceContents?.map { - async(IO) { - if (it.contains(query)) { - Log.d("targetd contents", it) - searchResult.add(it) - } - } - }?.awaitAll() - */ - positions = searchPosition(bookContent, query) - positions?.map{ - val construct = constructText(bookContent, it, query) + job.await() + while (replaceContents == null){ + delay(100L) + } + totalContents = replaceContents!!.joinToString("") + positions = searchPosition(totalContents, query) + var count = 1 + positions.map{ + val construct = constructText(totalContents, it, query) val result = SearchResult(index = searchResultCounts, + indexWithinChapter = count, text = construct[1] as String, chapterTitle = chapter.title, query = query, - pageIndex = 0, //todo: 计算搜索结果所在的pageIndex直接跳转 chapterIndex = chapter.index, newPosition = construct[0] as Int, contentPosition = it ) + count += 1 searchResultCounts += 1 searchResults.add(result) - // Log.d("h11128", result.presentText) } } } @@ -228,6 +228,7 @@ class SearchListFragment : VMBaseFragment(R.layout.fragment searchData.putExtra("index", searchResult.chapterIndex) searchData.putExtra("contentPosition", searchResult.contentPosition) searchData.putExtra("query", searchResult.query) + searchData.putExtra("indexWithinChapter", searchResult.indexWithinChapter) Log.d("h11128","current chapter index ${searchResult.chapterIndex}") activity?.setResult(RESULT_OK, searchData) activity?.finish() @@ -235,4 +236,8 @@ class SearchListFragment : VMBaseFragment(R.layout.fragment } + override fun durChapterIndex(): Int { + return durChapterIndex + } + } \ No newline at end of file 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 fd1873464..6b0d9df5b 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 @@ -1,10 +1,13 @@ package io.legado.app.ui.book.searchContent +import android.text.Spanned import android.util.Log +import androidx.core.text.HtmlCompat import io.legado.app.ui.book.read.page.entities.TextPage data class SearchResult( var index: Int = 0, + var indexWithinChapter: Int = 0, var text: String = "", var chapterTitle: String = "", val query: String, @@ -16,13 +19,22 @@ data class SearchResult( ) { val presentText: String get(){ - val sub1 = text.substring(0, newPosition) - val sub2 = text.substring(newPosition + query.length, text.length) - return "$sub1" + - "$query" + - "$sub2" + + return colorPresentText(newPosition, query, text) + "($chapterTitle)" } + fun colorPresentText(position: Int, center: String, targetText: String): String{ + val sub1 = text.substring(0, position) + val sub2 = text.substring(position + center.length, targetText.length) + return "$sub1" + + "$center" + + "$sub2" + } + + fun parseText(targetText: String): Spanned { + return HtmlCompat.fromHtml(targetText, HtmlCompat.FROM_HTML_MODE_LEGACY) + } + + } \ No newline at end of file