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