优化
This commit is contained in:
@@ -73,6 +73,7 @@ class SearchModel(private val scope: CoroutineScope, private val callBack: CallB
|
|||||||
|
|
||||||
private fun startSearch() {
|
private fun startSearch() {
|
||||||
val precision = appCtx.getPrefBoolean(PreferKey.precisionSearch)
|
val precision = appCtx.getPrefBoolean(PreferKey.precisionSearch)
|
||||||
|
var hasMore = false
|
||||||
searchJob = scope.launch(searchPool!!) {
|
searchJob = scope.launch(searchPool!!) {
|
||||||
flow {
|
flow {
|
||||||
for (bs in bookSourceParts) {
|
for (bs in bookSourceParts) {
|
||||||
@@ -90,12 +91,13 @@ class SearchModel(private val scope: CoroutineScope, private val callBack: CallB
|
|||||||
for (book in items) {
|
for (book in items) {
|
||||||
book.releaseHtmlData()
|
book.releaseHtmlData()
|
||||||
}
|
}
|
||||||
|
hasMore = hasMore || items.isNotEmpty()
|
||||||
appDb.searchBookDao.insert(*items.toTypedArray())
|
appDb.searchBookDao.insert(*items.toTypedArray())
|
||||||
mergeItems(items, precision)
|
mergeItems(items, precision)
|
||||||
currentCoroutineContext().ensureActive()
|
currentCoroutineContext().ensureActive()
|
||||||
callBack.onSearchSuccess(searchBooks)
|
callBack.onSearchSuccess(searchBooks)
|
||||||
}.onCompletion {
|
}.onCompletion {
|
||||||
if (it == null) callBack.onSearchFinish(searchBooks.isEmpty())
|
if (it == null) callBack.onSearchFinish(searchBooks.isEmpty(), hasMore)
|
||||||
}.catch {
|
}.catch {
|
||||||
AppLog.put("书源搜索出错\n${it.localizedMessage}", it)
|
AppLog.put("书源搜索出错\n${it.localizedMessage}", it)
|
||||||
}.collect()
|
}.collect()
|
||||||
@@ -185,7 +187,7 @@ class SearchModel(private val scope: CoroutineScope, private val callBack: CallB
|
|||||||
fun getSearchScope(): SearchScope
|
fun getSearchScope(): SearchScope
|
||||||
fun onSearchStart()
|
fun onSearchStart()
|
||||||
fun onSearchSuccess(searchBooks: List<SearchBook>)
|
fun onSearchSuccess(searchBooks: List<SearchBook>)
|
||||||
fun onSearchFinish(isEmpty: Boolean)
|
fun onSearchFinish(isEmpty: Boolean, hasMore: Boolean)
|
||||||
fun onSearchCancel(exception: Throwable? = null)
|
fun onSearchCancel(exception: Throwable? = null)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -54,7 +54,6 @@ import kotlinx.coroutines.flow.flowOn
|
|||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
import splitties.init.appCtx
|
import splitties.init.appCtx
|
||||||
import kotlin.math.abs
|
|
||||||
|
|
||||||
class SearchActivity : VMBaseActivity<ActivityBookSearchBinding, SearchViewModel>(),
|
class SearchActivity : VMBaseActivity<ActivityBookSearchBinding, SearchViewModel>(),
|
||||||
BookAdapter.CallBack,
|
BookAdapter.CallBack,
|
||||||
@@ -240,20 +239,7 @@ class SearchActivity : VMBaseActivity<ActivityBookSearchBinding, SearchViewModel
|
|||||||
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
|
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
|
||||||
super.onScrolled(recyclerView, dx, dy)
|
super.onScrolled(recyclerView, dx, dy)
|
||||||
if (!recyclerView.canScrollVertically(1)) {
|
if (!recyclerView.canScrollVertically(1)) {
|
||||||
val layoutManager = recyclerView.layoutManager as LinearLayoutManager
|
scrollToBottom()
|
||||||
val lastPosition = layoutManager.findLastCompletelyVisibleItemPosition()
|
|
||||||
if (lastPosition == RecyclerView.NO_POSITION) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
val lastView = layoutManager.findViewByPosition(lastPosition)
|
|
||||||
if (lastView == null) {
|
|
||||||
scrollToBottom()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
val bottom = abs(lastView.bottom - recyclerView.height)
|
|
||||||
if (bottom <= 1) {
|
|
||||||
scrollToBottom()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@@ -324,6 +310,7 @@ class SearchActivity : VMBaseActivity<ActivityBookSearchBinding, SearchViewModel
|
|||||||
}
|
}
|
||||||
if (viewModel.isSearchLiveData.value == false
|
if (viewModel.isSearchLiveData.value == false
|
||||||
&& viewModel.searchKey.isNotEmpty()
|
&& viewModel.searchKey.isNotEmpty()
|
||||||
|
&& viewModel.hasMore
|
||||||
) {
|
) {
|
||||||
viewModel.search("")
|
viewModel.search("")
|
||||||
}
|
}
|
||||||
@@ -407,8 +394,9 @@ class SearchActivity : VMBaseActivity<ActivityBookSearchBinding, SearchViewModel
|
|||||||
if (!isEmpty || viewModel.searchScope.isAll()) return@observe
|
if (!isEmpty || viewModel.searchScope.isAll()) return@observe
|
||||||
alert("搜索结果为空") {
|
alert("搜索结果为空") {
|
||||||
val precisionSearch = appCtx.getPrefBoolean(PreferKey.precisionSearch)
|
val precisionSearch = appCtx.getPrefBoolean(PreferKey.precisionSearch)
|
||||||
|
val displayScope = viewModel.searchScope.display
|
||||||
if (precisionSearch) {
|
if (precisionSearch) {
|
||||||
setMessage("${viewModel.searchScope.display}分组搜索结果为空,是否关闭精准搜索?")
|
setMessage("${displayScope}分组搜索结果为空,是否关闭精准搜索?")
|
||||||
yesButton {
|
yesButton {
|
||||||
appCtx.putPrefBoolean(PreferKey.precisionSearch, false)
|
appCtx.putPrefBoolean(PreferKey.precisionSearch, false)
|
||||||
precisionSearchMenuItem?.isChecked = false
|
precisionSearchMenuItem?.isChecked = false
|
||||||
@@ -416,7 +404,7 @@ class SearchActivity : VMBaseActivity<ActivityBookSearchBinding, SearchViewModel
|
|||||||
viewModel.search(searchView.query.toString())
|
viewModel.search(searchView.query.toString())
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
setMessage("${viewModel.searchScope.display}分组搜索结果为空,是否切换到全部分组?")
|
setMessage("${displayScope}分组搜索结果为空,是否切换到全部分组?")
|
||||||
yesButton {
|
yesButton {
|
||||||
viewModel.searchScope.update("")
|
viewModel.searchScope.update("")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ class SearchViewModel(application: Application) : BaseViewModel(application) {
|
|||||||
var searchFinishLiveData = MutableLiveData<Boolean>()
|
var searchFinishLiveData = MutableLiveData<Boolean>()
|
||||||
var isSearchLiveData = MutableLiveData<Boolean>()
|
var isSearchLiveData = MutableLiveData<Boolean>()
|
||||||
var searchKey: String = ""
|
var searchKey: String = ""
|
||||||
|
var hasMore = true
|
||||||
private var searchID = 0L
|
private var searchID = 0L
|
||||||
private val searchModel = SearchModel(viewModelScope, object : SearchModel.CallBack {
|
private val searchModel = SearchModel(viewModelScope, object : SearchModel.CallBack {
|
||||||
|
|
||||||
@@ -45,9 +46,10 @@ class SearchViewModel(application: Application) : BaseViewModel(application) {
|
|||||||
searchBookLiveData.postValue(searchBooks)
|
searchBookLiveData.postValue(searchBooks)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onSearchFinish(isEmpty: Boolean) {
|
override fun onSearchFinish(isEmpty: Boolean, hasMore: Boolean) {
|
||||||
isSearchLiveData.postValue(false)
|
isSearchLiveData.postValue(false)
|
||||||
searchFinishLiveData.postValue(isEmpty)
|
searchFinishLiveData.postValue(isEmpty)
|
||||||
|
this@SearchViewModel.hasMore = hasMore
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onSearchCancel(exception: Throwable?) {
|
override fun onSearchCancel(exception: Throwable?) {
|
||||||
@@ -99,6 +101,7 @@ class SearchViewModel(application: Application) : BaseViewModel(application) {
|
|||||||
searchID = System.currentTimeMillis()
|
searchID = System.currentTimeMillis()
|
||||||
searchBookLiveData.postValue(emptyList())
|
searchBookLiveData.postValue(emptyList())
|
||||||
searchKey = key
|
searchKey = key
|
||||||
|
hasMore = true
|
||||||
}
|
}
|
||||||
if (searchKey.isEmpty()) {
|
if (searchKey.isEmpty()) {
|
||||||
return@execute
|
return@execute
|
||||||
|
|||||||
@@ -1,12 +1,19 @@
|
|||||||
package io.legado.app.ui.widget.text
|
package io.legado.app.ui.widget.text
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
|
import android.os.Build
|
||||||
import android.util.AttributeSet
|
import android.util.AttributeSet
|
||||||
import androidx.appcompat.widget.AppCompatTextView
|
import androidx.appcompat.widget.AppCompatTextView
|
||||||
|
|
||||||
class MultilineTextView(context: Context, attrs: AttributeSet?) :
|
class MultilineTextView(context: Context, attrs: AttributeSet?) :
|
||||||
AppCompatTextView(context, attrs) {
|
AppCompatTextView(context, attrs) {
|
||||||
|
|
||||||
|
init {
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||||
|
isFallbackLineSpacing = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
|
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
|
||||||
val heightSize = MeasureSpec.getSize(heightMeasureSpec)
|
val heightSize = MeasureSpec.getSize(heightMeasureSpec)
|
||||||
calculateLines(heightSize)
|
calculateLines(heightSize)
|
||||||
|
|||||||
@@ -90,7 +90,7 @@ class BookSearchWebSocket(handshakeRequest: NanoHTTPD.IHTTPSession) :
|
|||||||
send(GSON.toJson(searchBooks))
|
send(GSON.toJson(searchBooks))
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onSearchFinish(isEmpty: Boolean) = close(normalClosure, SEARCH_FINISH, false)
|
override fun onSearchFinish(isEmpty: Boolean, hasMore: Boolean) = close(normalClosure, SEARCH_FINISH, false)
|
||||||
|
|
||||||
override fun onSearchCancel(exception: Throwable?) = close(normalClosure, exception?.toString() ?: SEARCH_FINISH, false)
|
override fun onSearchCancel(exception: Throwable?) = close(normalClosure, exception?.toString() ?: SEARCH_FINISH, false)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user