diff --git a/app/src/main/java/io/legado/app/ui/book/changecover/ChangeCoverDialog.kt b/app/src/main/java/io/legado/app/ui/book/changecover/ChangeCoverDialog.kt index ae578fb62..e3cb8fe3c 100644 --- a/app/src/main/java/io/legado/app/ui/book/changecover/ChangeCoverDialog.kt +++ b/app/src/main/java/io/legado/app/ui/book/changecover/ChangeCoverDialog.kt @@ -13,6 +13,9 @@ import io.legado.app.lib.theme.primaryColor import io.legado.app.utils.applyTint import io.legado.app.utils.setLayout import io.legado.app.utils.viewbindingdelegate.viewBinding +import kotlinx.coroutines.delay +import kotlinx.coroutines.flow.conflate +import kotlinx.coroutines.launch class ChangeCoverDialog() : BaseDialogFragment(R.layout.dialog_change_cover), @@ -45,6 +48,7 @@ class ChangeCoverDialog() : BaseDialogFragment(R.layout.dialog_change_cover), viewModel.initData(arguments) initMenu() initView() + initData() } private fun initMenu() { @@ -56,7 +60,17 @@ class ChangeCoverDialog() : BaseDialogFragment(R.layout.dialog_change_cover), private fun initView() { binding.recyclerView.layoutManager = GridLayoutManager(requireContext(), 3) binding.recyclerView.adapter = adapter - viewModel.loadDbSearchBook() + } + + private fun initData() { + launch { + viewModel.dataFlow + .conflate() + .collect { + adapter.setItems(it) + delay(1000) + } + } } override fun observeLiveBus() { @@ -76,9 +90,7 @@ class ChangeCoverDialog() : BaseDialogFragment(R.layout.dialog_change_cover), } binding.toolBar.menu.applyTint(requireContext()) } - viewModel.searchBooksLiveData.observe(viewLifecycleOwner) { - adapter.setItems(it) - } + } override fun onMenuItemClick(item: MenuItem?): Boolean { diff --git a/app/src/main/java/io/legado/app/ui/book/changecover/ChangeCoverViewModel.kt b/app/src/main/java/io/legado/app/ui/book/changecover/ChangeCoverViewModel.kt index 9c39f7375..dc14072d1 100644 --- a/app/src/main/java/io/legado/app/ui/book/changecover/ChangeCoverViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/book/changecover/ChangeCoverViewModel.kt @@ -13,23 +13,48 @@ import io.legado.app.data.entities.SearchBook import io.legado.app.help.AppConfig import io.legado.app.help.coroutine.CompositeCoroutine import io.legado.app.model.webBook.WebBook -import kotlinx.coroutines.* -import java.util.concurrent.CopyOnWriteArraySet +import kotlinx.coroutines.Dispatchers.IO +import kotlinx.coroutines.ExecutorCoroutineDispatcher +import kotlinx.coroutines.asCoroutineDispatcher +import kotlinx.coroutines.channels.awaitClose +import kotlinx.coroutines.channels.trySendBlocking +import kotlinx.coroutines.flow.callbackFlow import java.util.concurrent.Executors import kotlin.math.min class ChangeCoverViewModel(application: Application) : BaseViewModel(application) { private val threadCount = AppConfig.threadCount private var searchPool: ExecutorCoroutineDispatcher? = null - private var upAdapterJob: Job? = null - var name: String = "" - var author: String = "" - private var tasks = CompositeCoroutine() + private val tasks = CompositeCoroutine() + private var searchSuccess: ((SearchBook) -> Unit)? = null private var bookSourceList = arrayListOf() val searchStateData = MutableLiveData() - val searchBooksLiveData = MutableLiveData>() - private val searchBooks = CopyOnWriteArraySet() - private var postTime = 0L + var name: String = "" + var author: String = "" + val dataFlow = callbackFlow> { + val searchBooks = arrayListOf() + + searchSuccess = { + if (!searchBooks.contains(it)) { + searchBooks.add(it) + trySendBlocking(searchBooks) + } + } + + appDb.searchBookDao.getEnableHasCover(name, author).let { + searchBooks.addAll(it) + trySendBlocking(searchBooks) + } + + if (searchBooks.size <= 1) { + startSearch() + } + + awaitClose { + searchBooks.clear() + searchSuccess = null + } + } @Volatile private var searchIndex = -1 @@ -51,34 +76,6 @@ class ChangeCoverViewModel(application: Application) : BaseViewModel(application searchIndex = -1 } - fun loadDbSearchBook() { - execute { - appDb.searchBookDao.getEnableHasCover(name, author).let { - searchBooks.addAll(it) - searchBooksLiveData.postValue(searchBooks.toList()) - if (it.size <= 1) { - startSearch() - } - } - } - } - - @Synchronized - private fun upAdapter() { - if (System.currentTimeMillis() >= postTime + 500) { - upAdapterJob?.cancel() - postTime = System.currentTimeMillis() - val books = searchBooks.toList() - searchBooksLiveData.postValue(books.sortedBy { it.originOrder }) - } else { - upAdapterJob?.cancel() - upAdapterJob = viewModelScope.launch { - delay(500) - upAdapter() - } - } - } - private fun startSearch() { execute { stopSearch() @@ -106,17 +103,13 @@ class ChangeCoverViewModel(application: Application) : BaseViewModel(application val task = WebBook .searchBook(viewModelScope, source, name, context = searchPool!!) .timeout(60000L) - .onSuccess(searchPool) { - if (it.isNotEmpty()) { - val searchBook = it[0] + .onSuccess(IO) { + it.firstOrNull()?.let { searchBook -> if (searchBook.name == name && searchBook.author == author && !searchBook.coverUrl.isNullOrEmpty() ) { appDb.searchBookDao.insert(searchBook) - if (!searchBooks.contains(searchBook)) { - searchBooks.add(searchBook) - upAdapter() - } + searchSuccess?.invoke(searchBook) } } } @@ -151,7 +144,7 @@ class ChangeCoverViewModel(application: Application) : BaseViewModel(application } } - fun stopSearch() { + private fun stopSearch() { tasks.clear() searchPool?.close() searchStateData.postValue(false)