搜索替换后正文
粗体当前章节搜索结果
跳转搜索结果对应页面
pull/374/head
Jason Yao 4 years ago
parent 435c63f732
commit 04088a5dc1
  1. 22
      app/src/main/java/io/legado/app/service/help/ReadBook.kt
  2. 37
      app/src/main/java/io/legado/app/ui/book/read/ReadBookActivity.kt
  3. 8
      app/src/main/java/io/legado/app/ui/book/searchContent/SearchListAdapter.kt
  4. 67
      app/src/main/java/io/legado/app/ui/book/searchContent/SearchListFragment.kt
  5. 22
      app/src/main/java/io/legado/app/ui/book/searchContent/SearchResult.kt

@ -326,9 +326,21 @@ object ReadBook {
}
}
fun searchResultPositions(pages: List<TextPage>, contentPosition: Int): Array<Int>{
fun searchResultPositions(pages: List<TextPage>, indexWithinChapter: Int, query: String): Array<Int>{
//
// 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)
}

@ -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<ReadBookViewModel>(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<ReadBookViewModel>(R.layout.activity_boo
intent.removeExtra("readAloud")
ReadBook.readAloud()
}
loadStates = true
}
/**
@ -547,6 +552,7 @@ class ReadBookActivity : VMBaseActivity<ReadBookViewModel>(R.layout.activity_boo
page_view.upContent(relativePosition, resetPageOffset)
seek_read_page.progress = ReadBook.durPageIndex
}
loadStates = false
}
/**
@ -770,20 +776,29 @@ class ReadBookActivity : VMBaseActivity<ReadBookViewModel>(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()

@ -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<Any>) {
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
}
}

@ -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<SearchListViewModel>(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<SearchResult> = mutableListOf()
override fun onFragmentCreated(view: View, savedInstanceState: Bundle?) {
@ -76,9 +78,11 @@ class SearchListFragment : VMBaseFragment<SearchListViewModel>(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<SearchListViewModel>(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<SearchResult>()
}
@ -134,55 +138,51 @@ class SearchListFragment : VMBaseFragment<SearchListViewModel>(R.layout.fragment
}
}
private fun searchChapter(query: String, chapter: BookChapter?): List<SearchResult> {
private suspend fun searchChapter(query: String, chapter: BookChapter?): List<SearchResult> {
val searchResults: MutableList<SearchResult> = mutableListOf()
var positions : List<Int>? = listOf()
var positions : List<Int> = listOf()
var replaceContents: List<String>? = 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<String>? = 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<SearchListViewModel>(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<SearchListViewModel>(R.layout.fragment
}
override fun durChapterIndex(): Int {
return durChapterIndex
}
}

@ -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 "<font color=#000000>$sub1</font>" +
"<font color=#ff0000>$query</font>" +
"<font color=#000000>$sub2</font>" +
return colorPresentText(newPosition, query, text) +
"<font color=#0000ff>($chapterTitle)</font>"
}
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 "<font color=#000000>$sub1</font>" +
"<font color=#ff0000>$center</font>" +
"<font color=#000000>$sub2</font>"
}
fun parseText(targetText: String): Spanned {
return HtmlCompat.fromHtml(targetText, HtmlCompat.FROM_HTML_MODE_LEGACY)
}
}
Loading…
Cancel
Save