kunfei 4 лет назад
Родитель
Сommit
2df15c2f53

+ 1 - 1
app/src/main/java/io/legado/app/data/dao/SearchBookDao.kt

@@ -30,7 +30,7 @@ interface SearchBookDao {
         t1.wordCount, t2.customOrder as originOrder
         t1.wordCount, t2.customOrder as originOrder
         from searchBooks as t1 inner join book_sources as t2 
         from searchBooks as t1 inner join book_sources as t2 
         on t1.origin = t2.bookSourceUrl 
         on t1.origin = t2.bookSourceUrl 
-        where t1.name = :name and t1.author = :author 
+        where t1.name = :name and t1.author like '%'||:author||'%' 
         and originName like '%'||:key||'%' and t2.enabled = 1 
         and originName like '%'||:key||'%' and t2.enabled = 1 
         and t2.bookSourceGroup like '%'||:sourceGroup||'%'
         and t2.bookSourceGroup like '%'||:sourceGroup||'%'
         order by t2.customOrder"""
         order by t2.customOrder"""

+ 0 - 2
app/src/main/java/io/legado/app/ui/book/changecover/ChangeCoverDialog.kt

@@ -14,7 +14,6 @@ import io.legado.app.utils.applyTint
 import io.legado.app.utils.setLayout
 import io.legado.app.utils.setLayout
 import io.legado.app.utils.viewbindingdelegate.viewBinding
 import io.legado.app.utils.viewbindingdelegate.viewBinding
 import kotlinx.coroutines.delay
 import kotlinx.coroutines.delay
-import kotlinx.coroutines.flow.conflate
 import kotlinx.coroutines.launch
 import kotlinx.coroutines.launch
 
 
 /**
 /**
@@ -67,7 +66,6 @@ class ChangeCoverDialog() : BaseDialogFragment(R.layout.dialog_change_cover),
     private fun initData() {
     private fun initData() {
         launch {
         launch {
             viewModel.dataFlow
             viewModel.dataFlow
-                .conflate()
                 .collect {
                 .collect {
                     adapter.setItems(it)
                     adapter.setItems(it)
                     delay(1000)
                     delay(1000)

+ 3 - 1
app/src/main/java/io/legado/app/ui/book/changecover/ChangeCoverViewModel.kt

@@ -18,6 +18,7 @@ import kotlinx.coroutines.ExecutorCoroutineDispatcher
 import kotlinx.coroutines.asCoroutineDispatcher
 import kotlinx.coroutines.asCoroutineDispatcher
 import kotlinx.coroutines.channels.awaitClose
 import kotlinx.coroutines.channels.awaitClose
 import kotlinx.coroutines.flow.callbackFlow
 import kotlinx.coroutines.flow.callbackFlow
+import kotlinx.coroutines.flow.conflate
 import kotlinx.coroutines.flow.flowOn
 import kotlinx.coroutines.flow.flowOn
 import java.util.concurrent.Executors
 import java.util.concurrent.Executors
 import kotlin.math.min
 import kotlin.math.min
@@ -54,7 +55,8 @@ class ChangeCoverViewModel(application: Application) : BaseViewModel(application
             searchBooks.clear()
             searchBooks.clear()
             searchSuccess = null
             searchSuccess = null
         }
         }
-    }.flowOn(IO)
+    }.conflate()
+        .flowOn(IO)
 
 
     @Volatile
     @Volatile
     private var searchIndex = -1
     private var searchIndex = -1

+ 6 - 7
app/src/main/java/io/legado/app/ui/book/changesource/ChangeSourceDialog.kt

@@ -51,7 +51,6 @@ class ChangeSourceDialog() : BaseDialogFragment(R.layout.dialog_change_source),
             viewModel.startSearch()
             viewModel.startSearch()
         }
         }
 
 
-
     override fun onStart() {
     override fun onStart() {
         super.onStart()
         super.onStart()
         setLayout(0.9f, 0.9f)
         setLayout(0.9f, 0.9f)
@@ -65,7 +64,6 @@ class ChangeSourceDialog() : BaseDialogFragment(R.layout.dialog_change_source),
         initRecyclerView()
         initRecyclerView()
         initSearchView()
         initSearchView()
         initLiveData()
         initLiveData()
-        viewModel.loadDbSearchBook()
     }
     }
 
 
     private fun showTitle() {
     private fun showTitle() {
@@ -143,10 +141,11 @@ class ChangeSourceDialog() : BaseDialogFragment(R.layout.dialog_change_source),
             }
             }
             binding.toolBar.menu.applyTint(requireContext())
             binding.toolBar.menu.applyTint(requireContext())
         }
         }
-        viewModel.searchBooksLiveData.observe(viewLifecycleOwner) {
-            adapter.setItems(it)
-        }
         launch {
         launch {
+            viewModel.searchDataFlow
+                .collect {
+                    adapter.setItems(it)
+                }
             appDb.bookSourceDao.flowGroupEnabled().collect {
             appDb.bookSourceDao.flowGroupEnabled().collect {
                 groups.clear()
                 groups.clear()
                 it.map { group ->
                 it.map { group ->
@@ -165,7 +164,7 @@ class ChangeSourceDialog() : BaseDialogFragment(R.layout.dialog_change_source),
             R.id.menu_check_author -> {
             R.id.menu_check_author -> {
                 AppConfig.changeSourceCheckAuthor = !item.isChecked
                 AppConfig.changeSourceCheckAuthor = !item.isChecked
                 item.isChecked = !item.isChecked
                 item.isChecked = !item.isChecked
-                viewModel.loadDbSearchBook()
+                viewModel.refresh()
             }
             }
             R.id.menu_load_toc -> {
             R.id.menu_load_toc -> {
                 putPrefBoolean(PreferKey.changeSourceLoadToc, !item.isChecked)
                 putPrefBoolean(PreferKey.changeSourceLoadToc, !item.isChecked)
@@ -186,7 +185,7 @@ class ChangeSourceDialog() : BaseDialogFragment(R.layout.dialog_change_source),
                         putPrefString("searchGroup", item.title.toString())
                         putPrefString("searchGroup", item.title.toString())
                     }
                     }
                     viewModel.startOrStopSearch()
                     viewModel.startOrStopSearch()
-                    viewModel.loadDbSearchBook()
+                    viewModel.refresh()
                 }
                 }
             }
             }
         }
         }

+ 92 - 64
app/src/main/java/io/legado/app/ui/book/changesource/ChangeSourceViewModel.kt

@@ -17,12 +17,18 @@ import io.legado.app.help.coroutine.CompositeCoroutine
 import io.legado.app.model.webBook.WebBook
 import io.legado.app.model.webBook.WebBook
 import io.legado.app.utils.getPrefBoolean
 import io.legado.app.utils.getPrefBoolean
 import io.legado.app.utils.getPrefString
 import io.legado.app.utils.getPrefString
-
-import kotlinx.coroutines.*
 import kotlinx.coroutines.Dispatchers.IO
 import kotlinx.coroutines.Dispatchers.IO
+import kotlinx.coroutines.ExecutorCoroutineDispatcher
+import kotlinx.coroutines.asCoroutineDispatcher
+import kotlinx.coroutines.channels.awaitClose
+import kotlinx.coroutines.delay
+import kotlinx.coroutines.flow.callbackFlow
+import kotlinx.coroutines.flow.conflate
+import kotlinx.coroutines.flow.flowOn
+import kotlinx.coroutines.flow.map
 import splitties.init.appCtx
 import splitties.init.appCtx
 import timber.log.Timber
 import timber.log.Timber
-import java.util.concurrent.CopyOnWriteArraySet
+import java.util.concurrent.CopyOnWriteArrayList
 import java.util.concurrent.Executors
 import java.util.concurrent.Executors
 import kotlin.math.min
 import kotlin.math.min
 
 
@@ -30,17 +36,56 @@ import kotlin.math.min
 class ChangeSourceViewModel(application: Application) : BaseViewModel(application) {
 class ChangeSourceViewModel(application: Application) : BaseViewModel(application) {
     private val threadCount = AppConfig.threadCount
     private val threadCount = AppConfig.threadCount
     private var searchPool: ExecutorCoroutineDispatcher? = null
     private var searchPool: ExecutorCoroutineDispatcher? = null
-    private var upAdapterJob: Job? = null
     val searchStateData = MutableLiveData<Boolean>()
     val searchStateData = MutableLiveData<Boolean>()
-    val searchBooksLiveData = MutableLiveData<List<SearchBook>>()
     var name: String = ""
     var name: String = ""
     var author: String = ""
     var author: String = ""
     private var tasks = CompositeCoroutine()
     private var tasks = CompositeCoroutine()
     private var screenKey: String = ""
     private var screenKey: String = ""
     private var bookSourceList = arrayListOf<BookSource>()
     private var bookSourceList = arrayListOf<BookSource>()
-    private val searchBooks = CopyOnWriteArraySet<SearchBook>()
-    private var postTime = 0L
+    private val searchBooks = CopyOnWriteArrayList<SearchBook>()
     private val searchGroup get() = appCtx.getPrefString("searchGroup") ?: ""
     private val searchGroup get() = appCtx.getPrefString("searchGroup") ?: ""
+    private var searchCallback: SourceCallback? = null
+    val searchDataFlow = callbackFlow {
+
+        searchCallback = object : SourceCallback {
+
+            override fun searchSuccess(searchBook: SearchBook) {
+                appDb.searchBookDao.insert(searchBook)
+                val index = searchBooks.indexOf(searchBook)
+                when {
+                    index >= 0 -> searchBooks[index] = searchBook
+                    screenKey.isEmpty() -> searchBooks.add(searchBook)
+                    searchBook.name.contains(screenKey) -> searchBooks.add(searchBook)
+                    else -> return
+                }
+                trySend(searchBooks)
+            }
+
+            override fun upAdapter() {
+                trySend(searchBooks)
+            }
+
+        }
+
+        getDbSearchBooks().let {
+            searchBooks.clear()
+            searchBooks.addAll(it)
+            trySend(searchBooks)
+        }
+
+        if (searchBooks.size <= 1) {
+            startSearch()
+        }
+
+        awaitClose {
+            searchCallback = null
+        }
+    }.conflate()
+        .map {
+            val data = searchBooks.sortedBy { it.originOrder }
+            delay(1000)
+            data
+        }.flowOn(IO)
 
 
     @Volatile
     @Volatile
     private var searchIndex = -1
     private var searchIndex = -1
@@ -62,56 +107,19 @@ class ChangeSourceViewModel(application: Application) : BaseViewModel(applicatio
         searchIndex = -1
         searchIndex = -1
     }
     }
 
 
-    fun loadDbSearchBook() {
-        execute {
+    fun refresh() {
+        getDbSearchBooks().let {
             searchBooks.clear()
             searchBooks.clear()
-            upAdapter()
-            val sbs = if (AppConfig.changeSourceCheckAuthor) {
-                appDb.searchBookDao.getChangeSourceSearch(name, author, searchGroup)
-            } else {
-                appDb.searchBookDao.getChangeSourceSearch(name, "", searchGroup)
-            }
-            searchBooks.addAll(sbs)
-            searchBooksLiveData.postValue(searchBooks.toList())
-            if (sbs.size <= 1) {
-                startSearch()
-            }
+            searchBooks.addAll(it)
+            searchCallback?.upAdapter()
         }
         }
     }
     }
 
 
-    @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 searchFinish(searchBook: SearchBook) {
-        if (searchBooks.contains(searchBook)) return
-        appDb.searchBookDao.insert(searchBook)
-        if (screenKey.isEmpty()) {
-            searchBooks.add(searchBook)
-        } else if (searchBook.name.contains(screenKey)) {
-            searchBooks.add(searchBook)
-        }
-        upAdapter()
-    }
-
     fun startSearch() {
     fun startSearch() {
         execute {
         execute {
             stopSearch()
             stopSearch()
             appDb.searchBookDao.clear(name, author)
             appDb.searchBookDao.clear(name, author)
             searchBooks.clear()
             searchBooks.clear()
-            upAdapter()
             bookSourceList.clear()
             bookSourceList.clear()
             if (searchGroup.isBlank()) {
             if (searchGroup.isBlank()) {
                 bookSourceList.addAll(appDb.bookSourceDao.allEnabled)
                 bookSourceList.addAll(appDb.bookSourceDao.allEnabled)
@@ -152,10 +160,10 @@ class ChangeSourceViewModel(application: Application) : BaseViewModel(applicatio
                                 if (AppConfig.changeSourceLoadInfo || AppConfig.changeSourceLoadToc) {
                                 if (AppConfig.changeSourceLoadInfo || AppConfig.changeSourceLoadToc) {
                                     loadBookInfo(source, searchBook.toBook())
                                     loadBookInfo(source, searchBook.toBook())
                                 } else {
                                 } else {
-                                    searchFinish(searchBook)
+                                    searchCallback?.searchSuccess(searchBook)
                                 }
                                 }
                             } else {
                             } else {
-                                searchFinish(searchBook)
+                                searchCallback?.searchSuccess(searchBook)
                             }
                             }
                         }
                         }
                     }
                     }
@@ -190,7 +198,7 @@ class ChangeSourceViewModel(application: Application) : BaseViewModel(applicatio
                     //从详情页里获取最新章节
                     //从详情页里获取最新章节
                     book.latestChapterTitle = it.latestChapterTitle
                     book.latestChapterTitle = it.latestChapterTitle
                     val searchBook = book.toSearchBook()
                     val searchBook = book.toSearchBook()
-                    searchFinish(searchBook)
+                    searchCallback?.searchSuccess(searchBook)
                 }
                 }
             }.onError {
             }.onError {
                 Timber.e(it)
                 Timber.e(it)
@@ -202,26 +210,38 @@ class ChangeSourceViewModel(application: Application) : BaseViewModel(applicatio
             .onSuccess(IO) { chapters ->
             .onSuccess(IO) { chapters ->
                 book.latestChapterTitle = chapters.last().title
                 book.latestChapterTitle = chapters.last().title
                 val searchBook: SearchBook = book.toSearchBook()
                 val searchBook: SearchBook = book.toSearchBook()
-                searchFinish(searchBook)
+                searchCallback?.searchSuccess(searchBook)
             }.onError {
             }.onError {
                 Timber.e(it)
                 Timber.e(it)
             }
             }
     }
     }
 
 
+    private fun getDbSearchBooks(): List<SearchBook> {
+        return if (screenKey.isEmpty()) {
+            if (AppConfig.changeSourceCheckAuthor) {
+                appDb.searchBookDao.getChangeSourceSearch(name, author, searchGroup)
+            } else {
+                appDb.searchBookDao.getChangeSourceSearch(name, "", searchGroup)
+            }
+        } else {
+            if (AppConfig.changeSourceCheckAuthor) {
+                appDb.searchBookDao.getChangeSourceSearch(name, author, screenKey, searchGroup)
+            } else {
+                appDb.searchBookDao.getChangeSourceSearch(name, "", screenKey, searchGroup)
+            }
+        }
+    }
+
     /**
     /**
      * 筛选
      * 筛选
      */
      */
     fun screen(key: String?) {
     fun screen(key: String?) {
+        screenKey = key?.trim() ?: ""
         execute {
         execute {
-            screenKey = key ?: ""
-            if (key.isNullOrEmpty()) {
-                loadDbSearchBook()
-            } else {
-                val items =
-                    appDb.searchBookDao.getChangeSourceSearch(name, author, screenKey, searchGroup)
+            getDbSearchBooks().let {
                 searchBooks.clear()
                 searchBooks.clear()
-                searchBooks.addAll(items)
-                upAdapter()
+                searchBooks.addAll(it)
+                searchCallback?.upAdapter()
             }
             }
         }
         }
     }
     }
@@ -252,7 +272,7 @@ class ChangeSourceViewModel(application: Application) : BaseViewModel(applicatio
                 appDb.bookSourceDao.update(source)
                 appDb.bookSourceDao.update(source)
             }
             }
             searchBooks.remove(searchBook)
             searchBooks.remove(searchBook)
-            upAdapter()
+            searchCallback?.upAdapter()
         }
         }
     }
     }
 
 
@@ -265,7 +285,7 @@ class ChangeSourceViewModel(application: Application) : BaseViewModel(applicatio
                 appDb.bookSourceDao.update(source)
                 appDb.bookSourceDao.update(source)
                 updateSource(searchBook)
                 updateSource(searchBook)
             }
             }
-            upAdapter()
+            searchCallback?.upAdapter()
         }
         }
     }
     }
 
 
@@ -278,7 +298,7 @@ class ChangeSourceViewModel(application: Application) : BaseViewModel(applicatio
                 appDb.bookSourceDao.update(source)
                 appDb.bookSourceDao.update(source)
                 updateSource(searchBook)
                 updateSource(searchBook)
             }
             }
-            upAdapter()
+            searchCallback?.upAdapter()
         }
         }
     }
     }
 
 
@@ -294,11 +314,19 @@ class ChangeSourceViewModel(application: Application) : BaseViewModel(applicatio
             }
             }
         }
         }
         searchBooks.remove(searchBook)
         searchBooks.remove(searchBook)
-        upAdapter()
+        searchCallback?.upAdapter()
     }
     }
 
 
     fun firstSourceOrNull(searchBook: SearchBook): SearchBook? {
     fun firstSourceOrNull(searchBook: SearchBook): SearchBook? {
         return searchBooks.firstOrNull { it.bookUrl != searchBook.bookUrl }
         return searchBooks.firstOrNull { it.bookUrl != searchBook.bookUrl }
     }
     }
 
 
+    interface SourceCallback {
+
+        fun searchSuccess(searchBook: SearchBook)
+
+        fun upAdapter()
+
+    }
+
 }
 }