优化
This commit is contained in:
@@ -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"""
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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 val searchBooks = CopyOnWriteArrayList<SearchBook>()
|
||||||
private var postTime = 0L
|
|
||||||
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() {
|
fun refresh() {
|
||||||
execute {
|
getDbSearchBooks().let {
|
||||||
searchBooks.clear()
|
searchBooks.clear()
|
||||||
upAdapter()
|
searchBooks.addAll(it)
|
||||||
val sbs = if (AppConfig.changeSourceCheckAuthor) {
|
searchCallback?.upAdapter()
|
||||||
appDb.searchBookDao.getChangeSourceSearch(name, author, searchGroup)
|
|
||||||
} else {
|
|
||||||
appDb.searchBookDao.getChangeSourceSearch(name, "", searchGroup)
|
|
||||||
}
|
|
||||||
searchBooks.addAll(sbs)
|
|
||||||
searchBooksLiveData.postValue(searchBooks.toList())
|
|
||||||
if (sbs.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 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 ?: ""
|
getDbSearchBooks().let {
|
||||||
if (key.isNullOrEmpty()) {
|
|
||||||
loadDbSearchBook()
|
|
||||||
} else {
|
|
||||||
val items =
|
|
||||||
appDb.searchBookDao.getChangeSourceSearch(name, author, screenKey, searchGroup)
|
|
||||||
searchBooks.clear()
|
searchBooks.clear()
|
||||||
searchBooks.addAll(items)
|
searchBooks.addAll(it)
|
||||||
upAdapter()
|
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()
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user