Browse Source

Merge branch 'moreSearchResults' into 'master'

搜尋功能動態載入,移除筆數上限

See merge request kdanandroid/pdf/pdfreaderreadermodule!39
Wayne Huang 5 years ago
parent
commit
58cd880f56
1 changed files with 109 additions and 79 deletions
  1. 109 79
      src/main/java/com/kdanmobile/reader/screen/view/SearchView.kt

+ 109 - 79
src/main/java/com/kdanmobile/reader/screen/view/SearchView.kt

@@ -32,14 +32,21 @@ import java.lang.ref.WeakReference
 import kotlin.collections.ArrayList
 
 class SearchView: RelativeLayout, View.OnClickListener, LeftToolbarView {
+
+    companion object {
+        private const val SEARCH_RESULT_INIT_NUMBER = 200
+        private const val SEARCH_RESULT_ADD_NUMBER = 50
+        private const val SEARCH_RESULT_PRE_LOAD_BUFFER = 1
+    }
+
     private var pdfInfoHandler: PdfInfoHandler? = null
     private var searchHandler: SearchHandler? = null
     private lateinit var linearLayout: LinearLayout
-    private lateinit var tv_page: TextView
-    private lateinit var tv_text:TextView
-    private lateinit var et_search: EditText
-    private lateinit var lv: ListView
-    private lateinit var tv_tishi: TextView
+    private lateinit var tvPage: TextView
+    private lateinit var tvText:TextView
+    private lateinit var etSearch: EditText
+    private lateinit var listView: ListView
+    private lateinit var tvHint: TextView
     private lateinit var adapter: SearchAdapter
     private val list = ArrayList<SearchResultInfo>()
 
@@ -48,13 +55,15 @@ class SearchView: RelativeLayout, View.OnClickListener, LeftToolbarView {
 
     private var msgHandler: Handler? = null
 
-    private val MAX_SEARCH_RESULT = 200
-
     private var isDone = false
     private var deviceWidth: Int = 0
 
     private var disposable: Disposable? = null
 
+    private var lastSearchText = ""
+    private var searchStartPage: Int = 0
+    private var searchResultNum: Int = 0
+
     constructor(context: Context) : super(context) {
         initView()
     }
@@ -95,15 +104,15 @@ class SearchView: RelativeLayout, View.OnClickListener, LeftToolbarView {
                     when (msg.what) {
                         10 -> {
                             if (msg.obj is List<*>) {
-                                view.lv.visibility = View.VISIBLE
-                                view.tv_tishi.visibility = View.GONE
+                                view.listView.visibility = View.VISIBLE
+                                view.tvHint.visibility = View.GONE
                                 val item = (msg.obj as List<*>).filterIsInstance<SearchResultInfo>()
                                 view.list.addAll(item)
                                 view.adapter.add(item)
                                 view.adapter.notifyDataSetChanged()
                             }
                         }
-                        20 -> search()
+                        20 -> search(0)
                         30 -> {
                             val position = msg.arg1
                             val info = view.list[position]
@@ -120,15 +129,15 @@ class SearchView: RelativeLayout, View.OnClickListener, LeftToolbarView {
     private fun initLayout() {
 
         linearLayout = ll_fragmentPdfReaderSearch
-        tv_page = tv_fragmentPdfReaderSearch_page
-        tv_text = tv_fragmentPdfReaderSearch_text
-        et_search = et_fragmentPdfReaderSearch_
+        tvPage = tv_fragmentPdfReaderSearch_page
+        tvText = tv_fragmentPdfReaderSearch_text
+        etSearch = et_fragmentPdfReaderSearch_
 
-        et_search.setHint(R.string.fragment_search_enter_text)
-        et_search.inputType = InputType.TYPE_CLASS_TEXT
-        et_search.isLongClickable = false
-        lv = lv_fragmentPdfReaderSearch_
-        tv_tishi = tv_fragmentPdfReaderSearch_tishi
+        etSearch.setHint(R.string.fragment_search_enter_text)
+        etSearch.inputType = InputType.TYPE_CLASS_TEXT
+        etSearch.isLongClickable = false
+        listView = lv_fragmentPdfReaderSearch_
+        tvHint = tv_fragmentPdfReaderSearch_tishi
 
         var navigationHeight = 0
         val resourceId = resources.getIdentifier("navigation_bar_height", "dimen", "android")
@@ -156,37 +165,49 @@ class SearchView: RelativeLayout, View.OnClickListener, LeftToolbarView {
         params.rightMargin = 21 * deviceWidth / 800
         params.topMargin = 8 * deviceWidth / 800
         params.bottomMargin = 8 * deviceWidth / 800
-        et_search.layoutParams = params
+        etSearch.layoutParams = params
         val pad = (density * 4).toInt()
-        et_search.setPadding(pad, pad, pad, pad)
+        etSearch.setPadding(pad, pad, pad, pad)
 
         if (isPhone) {
-            tv_tishi.textSize = 18f
+            tvHint.textSize = 18f
         } else {
             val textSize = deviceWidth.toFloat() / 800f / density
-            tv_tishi.textSize = 24 * textSize
+            tvHint.textSize = 24 * textSize
         }
 
         adapter = SearchAdapter(deviceWidth)
-        lv.adapter = adapter
+        listView.adapter = adapter
     }
 
     private fun setListener() {
 
-        tv_page.setOnClickListener(this)
-        tv_text.setOnClickListener(this)
+        tvPage.setOnClickListener(this)
+        tvText.setOnClickListener(this)
 
-        lv.onItemClickListener = AdapterView.OnItemClickListener { parent, view, position, id ->
+        listView.setOnScrollListener(object : AbsListView.OnScrollListener {
+            override fun onScroll(view: AbsListView?, firstVisibleItem: Int, visibleItemCount: Int, totalItemCount: Int) {
+                val shouldLoadMore = firstVisibleItem + visibleItemCount >= totalItemCount - SEARCH_RESULT_PRE_LOAD_BUFFER
+                if (shouldLoadMore) {
+                    search(searchStartPage)
+                }
+            }
+
+            override fun onScrollStateChanged(view: AbsListView?, scrollState: Int) {
+            }
+        })
+
+        listView.onItemClickListener = AdapterView.OnItemClickListener { parent, view, position, id ->
             adapter.setSelected(position)
 
             msgHandler?.sendMessageDelayed(msgHandler?.obtainMessage(30, position, 0), 50)
         }
 
-        et_search.setOnEditorActionListener { _, actionId, _ ->
+        etSearch.setOnEditorActionListener { _, actionId, _ ->
             if (actionId == EditorInfo.IME_ACTION_SEARCH) {
-                if (!isPage && et_search.text.toString().length < 3) {
+                if (!isPage && etSearch.text.toString().length < 3) {
                     val la = IntArray(2)
-                    et_search.getLocationOnScreen(la)
+                    etSearch.getLocationOnScreen(la)
                     val y = la[1]
                     val toast = Toast.makeText(context, R.string.fileManager_thishi_search, Toast.LENGTH_SHORT)
                     toast.setGravity(Gravity.TOP or Gravity.LEFT, 11 * deviceWidth / 800, y + 30 * deviceWidth / 800)
@@ -200,7 +221,7 @@ class SearchView: RelativeLayout, View.OnClickListener, LeftToolbarView {
             return@setOnEditorActionListener false
         }
 
-        et_search.addTextChangedListener(object : SimpleTextWatcher() {
+        etSearch.addTextChangedListener(object : SimpleTextWatcher() {
             override fun onTextChanged(sequence: CharSequence, start: Int, before: Int, count: Int) {
                 super.onTextChanged(sequence, start, before, count)
                 try {
@@ -209,23 +230,23 @@ class SearchView: RelativeLayout, View.OnClickListener, LeftToolbarView {
                         val index = sequence[0]
                         if (c < '0' || c > '9' || index == '0') {
                             val text = sequence.subSequence(0, sequence.length - 1).toString()
-                            et_search.setText(text)
-                            et_search.setSelection(text.length)
+                            etSearch.setText(text)
+                            etSearch.setSelection(text.length)
                         }
-                        val searchText = et_search.text.toString()
+                        val searchText = etSearch.text.toString()
                         if (searchText.isNotEmpty()) {
                             val page = Integer.parseInt(searchText)
                             val pageCount = pdfInfoHandler?.getPdfPageCount() ?: 0
                             if (page > pageCount) {
                                 val text = searchText.subSequence(0, searchText.length - 1).toString()
-                                et_search.setText(text)
-                                et_search.setSelection(text.length)
+                                etSearch.setText(text)
+                                etSearch.setSelection(text.length)
                             }
                         }
                     }
                 } catch (e: Exception) {
                     e.printStackTrace()
-                    et_search.setText("")
+                    etSearch.setText("")
                 }
 
             }
@@ -237,16 +258,16 @@ class SearchView: RelativeLayout, View.OnClickListener, LeftToolbarView {
         when (v.id) {
             R.id.tv_fragmentPdfReaderSearch_page -> {
                 if (!isPage) {
-                    et_search.isLongClickable = false
-                    tv_page.setTextColor(ContextCompat.getColor(context, R.color.reader_search_title_selected))
-                    tv_text.setTextColor(ContextCompat.getColor(context, R.color.reader_search_title_normal))
-                    et_search.setText("")
-                    et_search.setHint(R.string.fragment_search_enter_page)
-                    et_search.inputType = InputType.TYPE_CLASS_NUMBER
-                    et_search.setSingleLine(true)
+                    etSearch.isLongClickable = false
+                    tvPage.setTextColor(ContextCompat.getColor(context, R.color.reader_search_title_selected))
+                    tvText.setTextColor(ContextCompat.getColor(context, R.color.reader_search_title_normal))
+                    etSearch.setText("")
+                    etSearch.setHint(R.string.fragment_search_enter_page)
+                    etSearch.inputType = InputType.TYPE_CLASS_NUMBER
+                    etSearch.setSingleLine(true)
 
-                    lv.visibility = View.GONE
-                    tv_tishi.visibility = View.GONE
+                    listView.visibility = View.GONE
+                    tvHint.visibility = View.GONE
 
                     showSoftKeyboard()
                 }
@@ -255,16 +276,16 @@ class SearchView: RelativeLayout, View.OnClickListener, LeftToolbarView {
             }
             R.id.tv_fragmentPdfReaderSearch_text -> {
                 if (isPage) {
-                    et_search.isLongClickable = true
-                    tv_page.setTextColor(ContextCompat.getColor(context, R.color.reader_search_title_normal))
-                    tv_text.setTextColor(ContextCompat.getColor(context, R.color.reader_search_title_selected))
-                    et_search.setText("")
-                    et_search.setHint(R.string.fragment_search_enter_text)
-                    et_search.inputType = InputType.TYPE_CLASS_TEXT
-                    et_search.setSingleLine(true)
+                    etSearch.isLongClickable = true
+                    tvPage.setTextColor(ContextCompat.getColor(context, R.color.reader_search_title_normal))
+                    tvText.setTextColor(ContextCompat.getColor(context, R.color.reader_search_title_selected))
+                    etSearch.setText("")
+                    etSearch.setHint(R.string.fragment_search_enter_text)
+                    etSearch.inputType = InputType.TYPE_CLASS_TEXT
+                    etSearch.setSingleLine(true)
 
-                    lv.visibility = View.VISIBLE
-                    tv_tishi.visibility = View.GONE
+                    listView.visibility = View.VISIBLE
+                    tvHint.visibility = View.GONE
 
                     showSoftKeyboard()
                 }
@@ -274,8 +295,8 @@ class SearchView: RelativeLayout, View.OnClickListener, LeftToolbarView {
         }
     }
 
-    private fun search() {
-        val searchText = et_search.text.toString()
+    private fun search(startPage: Int) {
+        val searchText = etSearch.text.toString()
         if (searchText.isNotEmpty()) {
             if (isPage) {
                 val page = Integer.parseInt(searchText)
@@ -283,27 +304,38 @@ class SearchView: RelativeLayout, View.OnClickListener, LeftToolbarView {
                     pdfInfoHandler?.goToCurrentPage(page - 1)
                 }
             } else if (searchText.length >= 3) {
-                if (list.size > 0) {
-                    adapter.setSelected(-1)
-                    adapter.clear()
-                    list.clear()
-                    adapter.notifyDataSetChanged()
+                if (!isDone) return
+                if (startPage == 0 || searchText != lastSearchText) {
+                    searchStartPage = 0
+                    searchResultNum = SEARCH_RESULT_INIT_NUMBER
+                    if (list.size > 0) {
+                        adapter.setSelected(-1)
+                        adapter.clear()
+                        list.clear()
+                        adapter.notifyDataSetChanged()
+                    }
+                    lastSearchText = searchText
+                } else {
+                    searchResultNum += SEARCH_RESULT_ADD_NUMBER
                 }
-
                 isDone = false
                 disposable = Completable.create {
                     if (null != pdfInfoHandler && null != searchHandler) {
                         val pageCount = pdfInfoHandler!!.getPdfPageCount()
-                        for (i in 0 until pageCount) {
+                        for (pageIndex in searchStartPage until pageCount) {
                             if (!isDone) {
-                                val results = searchHandler!!.searchPage(i, searchText)
+                                val results = searchHandler!!.searchPage(pageIndex, searchText)
                                 if (results.isNotEmpty()) {
-                                    val chars = pdfInfoHandler!!.getPageChars(i)
-                                    val list = dealData(chars, results, searchText, i)
+                                    val chars = pdfInfoHandler!!.getPageChars(pageIndex)
+                                    val list = dealData(chars, results, searchText, pageIndex)
                                     msgHandler?.sendMessage(msgHandler?.obtainMessage(10, list))
-                                    if (this.list.size + list.size >= MAX_SEARCH_RESULT) {
+                                    if (this.list.size + list.size >= searchResultNum) {
                                         isDone = true
+                                        searchStartPage = pageIndex + 1
+                                        break
                                     }
+                                } else if (pageIndex == pageCount - 1) {
+                                    searchStartPage = pageCount
                                 }
                             }
                         }
@@ -314,8 +346,8 @@ class SearchView: RelativeLayout, View.OnClickListener, LeftToolbarView {
                         .observeOn(AndroidSchedulers.mainThread())
                         .subscribe({
                             if (list.size < 1) {
-                                lv.visibility = View.GONE
-                                tv_tishi.visibility = View.VISIBLE
+                                listView.visibility = View.GONE
+                                tvHint.visibility = View.VISIBLE
                             }
                         }, {
                             it.printStackTrace()
@@ -385,9 +417,6 @@ class SearchView: RelativeLayout, View.OnClickListener, LeftToolbarView {
 
                                 lastResult = targetResult
                                 addSearchResult()
-                                if (this.list.size + list.size >= MAX_SEARCH_RESULT) {
-                                    return list
-                                }
                             }
                             if (currentWord.isEmpty) {
                                 resultBlockStartIndex = blockIndex
@@ -397,9 +426,6 @@ class SearchView: RelativeLayout, View.OnClickListener, LeftToolbarView {
                             rectList.add(char)
                         } else if (currentWord.w.contains(search, true)) {
                             addSearchResult()
-                            if (this.list.size + list.size >= MAX_SEARCH_RESULT) {
-                                return list
-                            }
                         }
                     }
                 }
@@ -410,17 +436,21 @@ class SearchView: RelativeLayout, View.OnClickListener, LeftToolbarView {
 
     private fun showSoftKeyboard() {
         val inputMethodManager = context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
-        et_search.requestFocus()
-        inputMethodManager.showSoftInput(et_search, InputMethodManager.RESULT_UNCHANGED_SHOWN)
+        etSearch.requestFocus()
+        inputMethodManager.showSoftInput(etSearch, InputMethodManager.RESULT_UNCHANGED_SHOWN)
     }
 
     fun hideSoftKeyboard() {
         val inputMethodManager = context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
-        inputMethodManager.hideSoftInputFromWindow(et_search.windowToken, InputMethodManager.HIDE_NOT_ALWAYS)
+        inputMethodManager.hideSoftInputFromWindow(etSearch.windowToken, InputMethodManager.HIDE_NOT_ALWAYS)
     }
 
     override fun updateContent() {
-        search()
+        val init = disposable == null
+        if (init) {
+            isDone = true
+            search(0)
+        }
     }
 
     override fun onScrollToContent(pageIndex: Int, notify: Boolean) {