add and delete

add data class searchList
delete durchapterindex
pull/374/head
Jason Yao 4 years ago
parent 1e94325f80
commit ec9e554d0d
  1. 3
      app/src/main/java/io/legado/app/ui/book/searchContent/SearchListActivity.kt
  2. 39
      app/src/main/java/io/legado/app/ui/book/searchContent/SearchListAdapter.kt
  3. 118
      app/src/main/java/io/legado/app/ui/book/searchContent/SearchListFragment.kt
  4. 22
      app/src/main/java/io/legado/app/ui/book/searchContent/SearchResult.kt
  5. 16
      app/src/main/res/layout/item_search_list.xml

@ -45,6 +45,7 @@ class SearchListActivity : VMBaseActivity<SearchListViewModel>(R.layout.activity
searchView?.onActionViewCollapsed()
searchView?.setOnCloseListener {
tab_layout.visible()
//to do clean
false
}
searchView?.setOnSearchClickListener { tab_layout.gone() }
@ -62,7 +63,7 @@ class SearchListActivity : VMBaseActivity<SearchListViewModel>(R.layout.activity
return super.onCompatCreateOptionsMenu(menu)
}
private inner class TabFragmentPageAdapter internal constructor(fm: FragmentManager) :
private inner class TabFragmentPageAdapter(fm: FragmentManager) :
FragmentPagerAdapter(fm, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT) {
override fun getItem(position: Int): Fragment {
return SearchListFragment()

@ -1,7 +1,11 @@
package io.legado.app.ui.book.searchContent
import android.content.Context
import android.os.Build
import android.text.Html
import android.view.View
import androidx.annotation.RequiresApi
import androidx.core.text.HtmlCompat
import io.legado.app.R
import io.legado.app.base.adapter.ItemViewHolder
import io.legado.app.base.adapter.SimpleRecyclerAdapter
@ -10,32 +14,23 @@ 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.tv_chapter_name
import kotlinx.android.synthetic.main.item_chapter_list.view.*
import kotlinx.android.synthetic.main.item_search_list.view.*
import org.jetbrains.anko.sdk27.listeners.onClick
class SearchListAdapter(context: Context, val callback: Callback) :
SimpleRecyclerAdapter<BookChapter>(context, R.layout.item_search_list) {
SimpleRecyclerAdapter<SearchResult>(context, R.layout.item_search_list) {
val cacheFileNames = hashSetOf<String>()
override fun convert(holder: ItemViewHolder, item: BookChapter, payloads: MutableList<Any>) {
@RequiresApi(Build.VERSION_CODES.N)
override fun convert(holder: ItemViewHolder, item: SearchResult, payloads: MutableList<Any>) {
with(holder.itemView) {
val isDur = callback.durChapterIndex() == item.index
val cached = callback.isLocalBook
|| cacheFileNames.contains(BookHelp.formatChapterName(item))
if (payloads.isEmpty()) {
// set search result color here
if (isDur) {
tv_chapter_name.setTextColor(context.accentColor)
} else {
tv_chapter_name.setTextColor(context.getCompatColor(R.color.primaryText))
}
tv_chapter_name.text = item.title
upHasCache(this, isDur, cached)
tv_search_result.text = HtmlCompat.fromHtml(item.presentText, HtmlCompat.FROM_HTML_MODE_LEGACY)
} else {
upHasCache(this, isDur, cached)
//to do
}
}
}
@ -49,18 +44,10 @@ class SearchListAdapter(context: Context, val callback: Callback) :
}
private fun upHasCache(itemView: View, isDur: Boolean, cached: Boolean) = itemView.apply {
tv_chapter_name.paint.isFakeBoldText = cached
iv_checked.setImageResource(R.drawable.ic_outline_cloud_24)
iv_checked.visible(!cached)
if (isDur) {
iv_checked.setImageResource(R.drawable.ic_check)
iv_checked.visible()
}
tv_search_result.paint.isFakeBoldText = cached
}
interface Callback {
val isLocalBook: Boolean
fun openSearchResult(bookChapter: BookChapter)
fun durChapterIndex(): Int
fun openSearchResult(searchResult: SearchResult)
}
}

@ -32,10 +32,9 @@ class SearchListFragment : VMBaseFragment<SearchListViewModel>(R.layout.fragment
get() = getViewModelOfActivity(SearchListViewModel::class.java)
lateinit var adapter: SearchListAdapter
private var durChapterIndex = 0
private lateinit var mLayoutManager: UpLinearLayoutManager
private var tocLiveData: LiveData<List<BookChapter>>? = null
private var scrollToDurChapter = false
private var searchResultCounts = 0
override fun onFragmentCreated(view: View, savedInstanceState: Bundle?) {
viewModel.searchCallBack = this
@ -69,35 +68,28 @@ class SearchListFragment : VMBaseFragment<SearchListViewModel>(R.layout.fragment
mLayoutManager.scrollToPositionWithOffset(adapter.itemCount - 1, 0)
}
}
tv_current_search_info.onClick {
mLayoutManager.scrollToPositionWithOffset(durChapterIndex, 0)
}
}
@SuppressLint("SetTextI18n")
private fun initBook() {
launch {
initDoc()
viewModel.book?.let {
durChapterIndex = it.durChapterIndex
tv_current_search_info.text =
"${it.durChapterTitle}(${it.durChapterIndex + 1}/${it.totalChapterNum})"
"搜索结果:$searchResultCounts"
initCacheFileNames(it)
}
}
}
/*
private fun initDoc() {
tocLiveData?.removeObservers(this@SearchListFragment)
tocLiveData = App.db.bookChapterDao().observeByBook(viewModel.bookUrl)
tocLiveData?.observe(viewLifecycleOwner, {
adapter.setItems(it)
if (!scrollToDurChapter) {
mLayoutManager.scrollToPositionWithOffset(durChapterIndex, 0)
scrollToDurChapter = true
}
})
}
*/
private fun initCacheFileNames(book: Book) {
launch(IO) {
@ -120,46 +112,34 @@ class SearchListFragment : VMBaseFragment<SearchListViewModel>(R.layout.fragment
}
override fun startContentSearch(newText: String?) {
if (newText.isNullOrBlank()) {
initDoc()
} else {
var count: Int = 0
val beginTime = System.currentTimeMillis()
if (!newText.isNullOrBlank()) {
App.db.bookChapterDao().getChapterList(viewModel.bookUrl).map{
launch(IO) {
val beginTime = System.currentTimeMillis()
if (isLocalBook ||
adapter.cacheFileNames.contains(BookHelp.formatChapterName(it))
) {
val value = searchChapter(newText, it)
count += value
searchResultCounts += value
}
val finishedTime = System.currentTimeMillis() - beginTime
Log.d("Jason", "Search finished, the total time cost is $finishedTime")
Log.d("Jason", "Search finished, the total count is $searchResultCounts")
}
}
//adapter.setItems(list)
val finishedTime = System.currentTimeMillis() - beginTime
Log.d("Jason", "Search finished, the total time cost is $finishedTime")
Log.d("Jason", "Search finished, the total count is $count")
//tocLiveData?.removeObservers(this)
//tocLiveData = App.db.bookChapterDao().liveDataSearch(viewModel.bookUrl, newText)
//tocLiveData?.observe(viewLifecycleOwner, {
//adapter.setItems(it)
//})
}
}
}
private suspend fun searchChapter(query: String, chapter: BookChapter?): Int {
val startTime = System.currentTimeMillis()
val searchResult: MutableList<String> = mutableListOf()
var count = 0
val searchResult: MutableList<SearchResult> = mutableListOf()
var positions : List<Int>? = listOf()
if (chapter != null){
Log.d("Jason", "Search ${chapter.title}")
viewModel.book?.let { bookSource ->
val bookContent = BookHelp.getContent(bookSource, chapter)
if (bookContent != null){
/* replace content, let's focus on original content first
chapter.title = when (AppConfig.chineseConverterType) {
1 -> HanLP.convertToSimplifiedChinese(chapter.title)
@ -186,35 +166,73 @@ class SearchListFragment : VMBaseFragment<SearchListViewModel>(R.layout.fragment
}
}?.awaitAll()
*/
count = bookContent?.let { countMatches(it, query) }!!
Log.d("Jason", "Search ${chapter.title} finished, the appeared count is $count")
positions = countMatches(bookContent, query)
positions?.map{
searchResult.add(
SearchResult(index = 0,
text = constructText(bookContent, it),
chapterTitle = chapter.title,
query = query,
pageSize = 0, // to be finished
chapterIndex = chapter.index, // to be finished
pageIndex = 0, // to be finished
)
)
}
adapter.addItems(searchResult)
Log.d("Jason", "Search ${chapter.title} finished, the appeared count is ${positions!!.size}")
}
}
val endTime = System.currentTimeMillis() - startTime
Log.d("Jason", "Search ${chapter.title} finished, the time cost is $endTime")
}
return count
return positions!!.size
}
fun countMatches(string: String, pattern: String): Int {
val matcher = Pattern.compile(pattern).matcher(string)
private fun countMatches(content: String, pattern: String): List<Int> {
val position : MutableList<Int> = mutableListOf()
var count = 0
while (matcher.find()) {
count++
var index = content.indexOf(pattern)
while(index >= 0){
position.add(index)
index = content.indexOf(pattern, index + 1);
}
return count
return position
}
private fun constructText(content: String, position: Int): String{
override val isLocalBook: Boolean
get() = viewModel.book?.isLocalBook() == true
override fun durChapterIndex(): Int {
return durChapterIndex
val length = 10
var po1 = position - length
var po2 = position + length
if (po1 <0) {
po1 = 0
}
if (po2 > content.length){
po2 = content.length
}
return content.substring(po1, po2)
/*
if (position >= length && position <= content.length - length){
return content.substring(position - length, position + length)
}
else if (position <= length){
return content.substring(0, position + length)
}
else if (position >= content.length - length){
return content.substring(position - length, content.length)
}
*/
}
override fun openSearchResult(bookChapter: BookChapter) {
activity?.setResult(RESULT_OK, Intent().putExtra("index", bookChapter.index))
val isLocalBook: Boolean
get() = viewModel.book?.isLocalBook() == true
override fun openSearchResult(searchResult: SearchResult) {
val searchData = Intent()
searchData.putExtra("index", searchResult.chapterIndex)
searchData.putExtra("pageIndex", searchResult.pageIndex)
activity?.setResult(RESULT_OK, searchData)
activity?.finish()
}

@ -0,0 +1,22 @@
package io.legado.app.ui.book.searchContent
data class SearchResult(
var index: Int = 0,
var text: String = "",
var chapterTitle: String = "",
val query: String,
var pageSize: Int = 0,
var chapterIndex: Int = 0,
var pageIndex: Int = 0,
) {
val presentText: String
get(){
val sub1 = text.substring(0, text.indexOf(query))
val sub2 = text.substring(text.indexOf(query) + query.length, text.length)
return "<font color=#000000>$sub1</font> " +
"<font color=#ff0000>$query</font>" +
"<font color=#000000>$sub2</font> " +
"<font color=#0000ff>($chapterTitle)</font>"
}
}

@ -8,24 +8,12 @@
android:padding="12dp">
<TextView
android:id="@+id/tv_chapter_name"
android:id="@+id/tv_search_result"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:singleLine="true"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toLeftOf="@+id/iv_checked" />
<ImageView
android:id="@+id/iv_checked"
android:layout_width="16dp"
android:layout_height="16dp"
android:src="@drawable/ic_check"
android:visibility="invisible"
android:contentDescription="@string/success"
app:tint="@color/secondaryText"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintBottom_toBottomOf="parent" />
app:layout_constraintRight_toLeftOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
Loading…
Cancel
Save