|
|
@ -13,23 +13,48 @@ import io.legado.app.data.entities.SearchBook |
|
|
|
import io.legado.app.help.AppConfig |
|
|
|
import io.legado.app.help.AppConfig |
|
|
|
import io.legado.app.help.coroutine.CompositeCoroutine |
|
|
|
import io.legado.app.help.coroutine.CompositeCoroutine |
|
|
|
import io.legado.app.model.webBook.WebBook |
|
|
|
import io.legado.app.model.webBook.WebBook |
|
|
|
import kotlinx.coroutines.* |
|
|
|
import kotlinx.coroutines.Dispatchers.IO |
|
|
|
import java.util.concurrent.CopyOnWriteArraySet |
|
|
|
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 java.util.concurrent.Executors |
|
|
|
import kotlin.math.min |
|
|
|
import kotlin.math.min |
|
|
|
|
|
|
|
|
|
|
|
class ChangeCoverViewModel(application: Application) : BaseViewModel(application) { |
|
|
|
class ChangeCoverViewModel(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 |
|
|
|
private val tasks = CompositeCoroutine() |
|
|
|
var name: String = "" |
|
|
|
private var searchSuccess: ((SearchBook) -> Unit)? = null |
|
|
|
var author: String = "" |
|
|
|
|
|
|
|
private var tasks = CompositeCoroutine() |
|
|
|
|
|
|
|
private var bookSourceList = arrayListOf<BookSource>() |
|
|
|
private var bookSourceList = arrayListOf<BookSource>() |
|
|
|
val searchStateData = MutableLiveData<Boolean>() |
|
|
|
val searchStateData = MutableLiveData<Boolean>() |
|
|
|
val searchBooksLiveData = MutableLiveData<List<SearchBook>>() |
|
|
|
var name: String = "" |
|
|
|
private val searchBooks = CopyOnWriteArraySet<SearchBook>() |
|
|
|
var author: String = "" |
|
|
|
private var postTime = 0L |
|
|
|
val dataFlow = callbackFlow<List<SearchBook>> { |
|
|
|
|
|
|
|
val searchBooks = arrayListOf<SearchBook>() |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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 |
|
|
|
@Volatile |
|
|
|
private var searchIndex = -1 |
|
|
|
private var searchIndex = -1 |
|
|
@ -51,34 +76,6 @@ class ChangeCoverViewModel(application: Application) : BaseViewModel(application |
|
|
|
searchIndex = -1 |
|
|
|
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() { |
|
|
|
private fun startSearch() { |
|
|
|
execute { |
|
|
|
execute { |
|
|
|
stopSearch() |
|
|
|
stopSearch() |
|
|
@ -106,17 +103,13 @@ class ChangeCoverViewModel(application: Application) : BaseViewModel(application |
|
|
|
val task = WebBook |
|
|
|
val task = WebBook |
|
|
|
.searchBook(viewModelScope, source, name, context = searchPool!!) |
|
|
|
.searchBook(viewModelScope, source, name, context = searchPool!!) |
|
|
|
.timeout(60000L) |
|
|
|
.timeout(60000L) |
|
|
|
.onSuccess(searchPool) { |
|
|
|
.onSuccess(IO) { |
|
|
|
if (it.isNotEmpty()) { |
|
|
|
it.firstOrNull()?.let { searchBook -> |
|
|
|
val searchBook = it[0] |
|
|
|
|
|
|
|
if (searchBook.name == name && searchBook.author == author |
|
|
|
if (searchBook.name == name && searchBook.author == author |
|
|
|
&& !searchBook.coverUrl.isNullOrEmpty() |
|
|
|
&& !searchBook.coverUrl.isNullOrEmpty() |
|
|
|
) { |
|
|
|
) { |
|
|
|
appDb.searchBookDao.insert(searchBook) |
|
|
|
appDb.searchBookDao.insert(searchBook) |
|
|
|
if (!searchBooks.contains(searchBook)) { |
|
|
|
searchSuccess?.invoke(searchBook) |
|
|
|
searchBooks.add(searchBook) |
|
|
|
|
|
|
|
upAdapter() |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
@ -151,7 +144,7 @@ class ChangeCoverViewModel(application: Application) : BaseViewModel(application |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
fun stopSearch() { |
|
|
|
private fun stopSearch() { |
|
|
|
tasks.clear() |
|
|
|
tasks.clear() |
|
|
|
searchPool?.close() |
|
|
|
searchPool?.close() |
|
|
|
searchStateData.postValue(false) |
|
|
|
searchStateData.postValue(false) |
|
|
|