pull/1649/head
kunfei 3 years ago
parent 0373af42c8
commit 17aaae27a5
  1. 22
      app/src/main/java/io/legado/app/model/webBook/SearchModel.kt
  2. 2
      app/src/main/java/io/legado/app/ui/book/changesource/ChangeSourceDialog.kt
  3. 19
      app/src/main/java/io/legado/app/ui/book/search/SearchActivity.kt
  4. 83
      app/src/main/java/io/legado/app/ui/book/search/SearchViewModel.kt

@ -17,7 +17,7 @@ import splitties.init.appCtx
import java.util.concurrent.Executors import java.util.concurrent.Executors
import kotlin.math.min import kotlin.math.min
class SearchModel(private val scope: CoroutineScope, private val callBack: CallBack) { class SearchModel(private val scope: CoroutineScope) {
val threadCount = AppConfig.threadCount val threadCount = AppConfig.threadCount
private var searchPool: ExecutorCoroutineDispatcher? = null private var searchPool: ExecutorCoroutineDispatcher? = null
private var mSearchId = 0L private var mSearchId = 0L
@ -26,10 +26,19 @@ class SearchModel(private val scope: CoroutineScope, private val callBack: CallB
private var tasks = CompositeCoroutine() private var tasks = CompositeCoroutine()
private var bookSourceList = arrayListOf<BookSource>() private var bookSourceList = arrayListOf<BookSource>()
private var searchBooks = arrayListOf<SearchBook>() private var searchBooks = arrayListOf<SearchBook>()
private var callBack: CallBack? = null
@Volatile @Volatile
private var searchIndex = -1 private var searchIndex = -1
fun registerCallback(callBack: CallBack) {
this.callBack = callBack
}
fun unRegisterCallback() {
this.callBack = null
}
private fun initSearchPool() { private fun initSearchPool() {
searchPool?.close() searchPool?.close()
searchPool = Executors searchPool = Executors
@ -37,10 +46,10 @@ class SearchModel(private val scope: CoroutineScope, private val callBack: CallB
} }
fun search(searchId: Long, key: String) { fun search(searchId: Long, key: String) {
callBack.onSearchStart() callBack?.onSearchStart()
if (searchId != mSearchId) { if (searchId != mSearchId) {
if (key.isEmpty()) { if (key.isEmpty()) {
callBack.onSearchCancel() callBack?.onSearchCancel()
return return
} else { } else {
this.searchKey = key this.searchKey = key
@ -53,6 +62,7 @@ class SearchModel(private val scope: CoroutineScope, private val callBack: CallB
searchPage = 1 searchPage = 1
val searchGroup = appCtx.getPrefString("searchGroup") ?: "" val searchGroup = appCtx.getPrefString("searchGroup") ?: ""
bookSourceList.clear() bookSourceList.clear()
callBack?.onSearchSuccess(searchBooks)
if (searchGroup.isBlank()) { if (searchGroup.isBlank()) {
bookSourceList.addAll(appDb.bookSourceDao.allEnabled) bookSourceList.addAll(appDb.bookSourceDao.allEnabled)
} else { } else {
@ -103,7 +113,7 @@ class SearchModel(private val scope: CoroutineScope, private val callBack: CallB
appDb.searchBookDao.insert(*items.toTypedArray()) appDb.searchBookDao.insert(*items.toTypedArray())
val precision = appCtx.getPrefBoolean(PreferKey.precisionSearch) val precision = appCtx.getPrefBoolean(PreferKey.precisionSearch)
mergeItems(scope, items, precision) mergeItems(scope, items, precision)
callBack.onSearchSuccess(searchBooks) callBack?.onSearchSuccess(searchBooks)
} }
} }
@ -117,7 +127,7 @@ class SearchModel(private val scope: CoroutineScope, private val callBack: CallB
if (searchIndex >= bookSourceList.lastIndex if (searchIndex >= bookSourceList.lastIndex
+ min(bookSourceList.size, threadCount) + min(bookSourceList.size, threadCount)
) { ) {
callBack.onSearchFinish() callBack?.onSearchFinish()
} }
} }
@ -189,7 +199,7 @@ class SearchModel(private val scope: CoroutineScope, private val callBack: CallB
fun cancelSearch() { fun cancelSearch() {
close() close()
callBack.onSearchCancel() callBack?.onSearchCancel()
} }
fun close() { fun close() {

@ -148,6 +148,8 @@ class ChangeSourceDialog() : BaseDialogFragment(R.layout.dialog_change_source),
adapter.setItems(it) adapter.setItems(it)
delay(1000) delay(1000)
} }
}
launch {
appDb.bookSourceDao.flowGroupEnabled().collect { appDb.bookSourceDao.flowGroupEnabled().collect {
groups.clear() groups.clear()
it.map { group -> it.map { group ->

@ -19,7 +19,6 @@ import io.legado.app.constant.AppPattern
import io.legado.app.constant.PreferKey import io.legado.app.constant.PreferKey
import io.legado.app.data.appDb import io.legado.app.data.appDb
import io.legado.app.data.entities.Book import io.legado.app.data.entities.Book
import io.legado.app.data.entities.SearchBook
import io.legado.app.data.entities.SearchKeyword import io.legado.app.data.entities.SearchKeyword
import io.legado.app.databinding.ActivityBookSearchBinding import io.legado.app.databinding.ActivityBookSearchBinding
import io.legado.app.lib.theme.* import io.legado.app.lib.theme.*
@ -30,6 +29,7 @@ import io.legado.app.utils.*
import io.legado.app.utils.viewbindingdelegate.viewBinding import io.legado.app.utils.viewbindingdelegate.viewBinding
import kotlinx.coroutines.Dispatchers.IO import kotlinx.coroutines.Dispatchers.IO
import kotlinx.coroutines.Job import kotlinx.coroutines.Job
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
@ -195,6 +195,13 @@ class SearchActivity : VMBaseActivity<ActivityBookSearchBinding, SearchViewModel
} }
private fun initData() { private fun initData() {
launch {
viewModel.searchDataFlow
.collect {
adapter.setItems(it)
delay(1000)
}
}
launch { launch {
appDb.bookSourceDao.flowGroupEnabled().collect { appDb.bookSourceDao.flowGroupEnabled().collect {
groups.clear() groups.clear()
@ -204,9 +211,6 @@ class SearchActivity : VMBaseActivity<ActivityBookSearchBinding, SearchViewModel
upGroupMenu() upGroupMenu()
} }
} }
viewModel.searchBookLiveData.observe(this) {
upSearchItems(it)
}
viewModel.isSearchLiveData.observe(this) { viewModel.isSearchLiveData.observe(this) {
if (it) { if (it) {
startSearch() startSearch()
@ -310,13 +314,6 @@ class SearchActivity : VMBaseActivity<ActivityBookSearchBinding, SearchViewModel
} }
} }
/**
* 更新搜索结果
*/
private fun upSearchItems(items: List<SearchBook>) {
adapter.setItems(items)
}
/** /**
* 开始搜索 * 开始搜索
*/ */

@ -8,20 +8,47 @@ import io.legado.app.data.appDb
import io.legado.app.data.entities.SearchBook import io.legado.app.data.entities.SearchBook
import io.legado.app.data.entities.SearchKeyword import io.legado.app.data.entities.SearchKeyword
import io.legado.app.model.webBook.SearchModel import io.legado.app.model.webBook.SearchModel
import kotlinx.coroutines.Job import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.delay import kotlinx.coroutines.flow.callbackFlow
import kotlinx.coroutines.launch import kotlinx.coroutines.flow.conflate
class SearchViewModel(application: Application) : BaseViewModel(application), SearchModel.CallBack { class SearchViewModel(application: Application) : BaseViewModel(application) {
private val searchModel = SearchModel(viewModelScope, this) private val searchModel = SearchModel(viewModelScope)
private var upAdapterJob: Job? = null
var isSearchLiveData = MutableLiveData<Boolean>() var isSearchLiveData = MutableLiveData<Boolean>()
var searchBookLiveData = MutableLiveData<List<SearchBook>>()
var searchKey: String = "" var searchKey: String = ""
var isLoading = false var isLoading = false
private var searchBooks = arrayListOf<SearchBook>()
private var searchID = 0L private var searchID = 0L
private var postTime = 0L
val searchDataFlow = callbackFlow {
val callback = object : SearchModel.CallBack {
override fun onSearchStart() {
isSearchLiveData.postValue(true)
isLoading = true
}
@Synchronized
override fun onSearchSuccess(searchBooks: ArrayList<SearchBook>) {
trySend(ArrayList(searchBooks))
}
override fun onSearchFinish() {
isSearchLiveData.postValue(false)
isLoading = false
}
override fun onSearchCancel() {
isSearchLiveData.postValue(false)
isLoading = false
}
}
searchModel.registerCallback(callback)
awaitClose {
searchModel.unRegisterCallback()
}
}.conflate()
/** /**
* 开始搜索 * 开始搜索
@ -29,8 +56,6 @@ class SearchViewModel(application: Application) : BaseViewModel(application), Se
fun search(key: String) { fun search(key: String) {
if ((searchKey == key) || key.isNotEmpty()) { if ((searchKey == key) || key.isNotEmpty()) {
searchModel.cancelSearch() searchModel.cancelSearch()
searchBooks.clear()
searchBookLiveData.postValue(searchBooks)
searchID = System.currentTimeMillis() searchID = System.currentTimeMillis()
searchKey = key searchKey = key
} }
@ -40,42 +65,6 @@ class SearchViewModel(application: Application) : BaseViewModel(application), Se
searchModel.search(searchID, searchKey) searchModel.search(searchID, searchKey)
} }
@Synchronized
private fun upAdapter() {
upAdapterJob?.cancel()
if (System.currentTimeMillis() >= postTime + 1000) {
postTime = System.currentTimeMillis()
searchBookLiveData.postValue(searchBooks)
} else {
upAdapterJob = viewModelScope.launch {
delay(1000)
upAdapter()
}
}
}
override fun onSearchStart() {
isSearchLiveData.postValue(true)
isLoading = true
}
@Synchronized
override fun onSearchSuccess(searchBooks: ArrayList<SearchBook>) {
this.searchBooks = searchBooks
upAdapter()
}
override fun onSearchFinish() {
isSearchLiveData.postValue(false)
isLoading = false
}
override fun onSearchCancel() {
isSearchLiveData.postValue(false)
isLoading = false
}
/** /**
* 停止搜索 * 停止搜索
*/ */

Loading…
Cancel
Save