Fix import book slow
This commit is contained in:
@@ -132,8 +132,11 @@ interface BookDao {
|
||||
@Query("select 1 from books where bookUrl = :bookUrl")
|
||||
fun has(bookUrl: String): Boolean?
|
||||
|
||||
@Query("select 1 from books where originName = :fileName or origin like '%' || :fileName")
|
||||
fun hasFile(fileName: String): Boolean?
|
||||
@Query(
|
||||
"""select exists(select 1 from books where type & ${BookType.local} > 0
|
||||
and (originName = :fileName or (origin != '${BookType.localTag}' and origin like '%' || :fileName)))"""
|
||||
)
|
||||
fun hasFile(fileName: String): Boolean
|
||||
|
||||
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||
fun insert(vararg book: Book)
|
||||
|
||||
@@ -16,7 +16,6 @@ import io.legado.app.help.book.BookHelp
|
||||
import io.legado.app.help.book.ContentProcessor
|
||||
import io.legado.app.help.book.isEpub
|
||||
import io.legado.app.help.book.isImage
|
||||
import io.legado.app.help.book.isPdf
|
||||
import io.legado.app.help.book.simulatedTotalChapterNum
|
||||
import io.legado.app.help.config.AppConfig
|
||||
import io.legado.app.help.config.ReadBookConfig
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
package io.legado.app.ui.book.import.local
|
||||
|
||||
import io.legado.app.model.localBook.LocalBook
|
||||
import io.legado.app.utils.FileDoc
|
||||
|
||||
data class ImportBook(
|
||||
val file: FileDoc,
|
||||
var isOnBookShelf: Boolean = LocalBook.isOnBookShelf(file.name)
|
||||
) {
|
||||
val name get() = file.name
|
||||
val isDir get() = file.isDir
|
||||
val size get() = file.size
|
||||
val lastModified get() = file.lastModified
|
||||
}
|
||||
@@ -101,7 +101,7 @@ class ImportBookActivity : BaseImportBookActivity<ImportBookViewModel>(),
|
||||
|
||||
override fun onMenuItemClick(item: MenuItem?): Boolean {
|
||||
when (item?.itemId) {
|
||||
R.id.menu_del_selection -> viewModel.deleteDoc(adapter.selectedUris) {
|
||||
R.id.menu_del_selection -> viewModel.deleteDoc(adapter.selected) {
|
||||
adapter.removeSelection()
|
||||
}
|
||||
}
|
||||
@@ -118,8 +118,11 @@ class ImportBookActivity : BaseImportBookActivity<ImportBookViewModel>(),
|
||||
|
||||
@SuppressLint("NotifyDataSetChanged")
|
||||
override fun onClickSelectBarMainAction() {
|
||||
viewModel.addToBookshelf(adapter.selectedUris) {
|
||||
adapter.selectedUris.clear()
|
||||
viewModel.addToBookshelf(adapter.selected) {
|
||||
adapter.selected.forEach {
|
||||
it.isOnBookShelf = true
|
||||
}
|
||||
adapter.selected.clear()
|
||||
adapter.notifyDataSetChanged()
|
||||
}
|
||||
}
|
||||
@@ -129,6 +132,7 @@ class ImportBookActivity : BaseImportBookActivity<ImportBookViewModel>(),
|
||||
binding.tvEmptyMsg.setText(R.string.empty_msg_import_book)
|
||||
binding.recyclerView.layoutManager = LinearLayoutManager(this)
|
||||
binding.recyclerView.adapter = adapter
|
||||
binding.recyclerView.recycledViewPool.setMaxRecycledViews(0, 15)
|
||||
binding.selectActionBar.setMainActionText(R.string.add_to_bookshelf)
|
||||
binding.selectActionBar.inflateMenu(R.menu.import_book_sel)
|
||||
binding.selectActionBar.setOnMenuItemClickListener(this)
|
||||
@@ -212,7 +216,7 @@ class ImportBookActivity : BaseImportBookActivity<ImportBookViewModel>(),
|
||||
viewModel.sort = sort
|
||||
putPrefInt(PreferKey.localBookImportSort, sort)
|
||||
if (scanDocJob?.isActive != true) {
|
||||
viewModel.dataCallback?.setItems(adapter.getItems())
|
||||
viewModel.dataCallback?.upAdapter()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -234,7 +238,7 @@ class ImportBookActivity : BaseImportBookActivity<ImportBookViewModel>(),
|
||||
path = path + doc.name + File.separator
|
||||
}
|
||||
binding.tvPath.text = path
|
||||
adapter.selectedUris.clear()
|
||||
adapter.selected.clear()
|
||||
adapter.clearItems()
|
||||
viewModel.loadDoc(lastDoc)
|
||||
}
|
||||
@@ -295,7 +299,7 @@ class ImportBookActivity : BaseImportBookActivity<ImportBookViewModel>(),
|
||||
}
|
||||
|
||||
override fun upCountView() {
|
||||
binding.selectActionBar.upCountView(adapter.selectedUris.size, adapter.checkableCount)
|
||||
binding.selectActionBar.upCountView(adapter.selected.size, adapter.checkableCount)
|
||||
}
|
||||
|
||||
override fun startRead(fileDoc: FileDoc) {
|
||||
|
||||
@@ -9,12 +9,18 @@ import io.legado.app.base.adapter.RecyclerAdapter
|
||||
import io.legado.app.constant.AppConst
|
||||
import io.legado.app.databinding.ItemImportBookBinding
|
||||
import io.legado.app.model.localBook.LocalBook
|
||||
import io.legado.app.utils.*
|
||||
import io.legado.app.utils.ConvertUtils
|
||||
import io.legado.app.utils.FileDoc
|
||||
import io.legado.app.utils.gone
|
||||
import io.legado.app.utils.invisible
|
||||
import io.legado.app.utils.visible
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Job
|
||||
|
||||
|
||||
class ImportBookAdapter(context: Context, val callBack: CallBack) :
|
||||
RecyclerAdapter<FileDoc, ItemImportBookBinding>(context) {
|
||||
val selectedUris = hashSetOf<String>()
|
||||
RecyclerAdapter<ImportBook, ItemImportBookBinding>(context) {
|
||||
val selected = hashSetOf<ImportBook>()
|
||||
var checkableCount = 0
|
||||
|
||||
override fun getViewBinding(parent: ViewGroup): ItemImportBookBinding {
|
||||
@@ -28,7 +34,7 @@ class ImportBookAdapter(context: Context, val callBack: CallBack) :
|
||||
override fun convert(
|
||||
holder: ItemViewHolder,
|
||||
binding: ItemImportBookBinding,
|
||||
item: FileDoc,
|
||||
item: ImportBook,
|
||||
payloads: MutableList<Any>
|
||||
) {
|
||||
binding.run {
|
||||
@@ -40,7 +46,7 @@ class ImportBookAdapter(context: Context, val callBack: CallBack) :
|
||||
llBrief.gone()
|
||||
cbSelect.isChecked = false
|
||||
} else {
|
||||
if (isOnBookShelf(item)) {
|
||||
if (item.isOnBookShelf) {
|
||||
ivIcon.setImageResource(R.drawable.ic_book_has)
|
||||
ivIcon.visible()
|
||||
cbSelect.invisible()
|
||||
@@ -52,11 +58,11 @@ class ImportBookAdapter(context: Context, val callBack: CallBack) :
|
||||
tvTag.text = item.name.substringAfterLast(".")
|
||||
tvSize.text = ConvertUtils.formatFileSize(item.size)
|
||||
tvDate.text = AppConst.dateFormat.format(item.lastModified)
|
||||
cbSelect.isChecked = selectedUris.contains(item.toString())
|
||||
cbSelect.isChecked = selected.contains(item)
|
||||
}
|
||||
tvName.text = item.name
|
||||
} else {
|
||||
cbSelect.isChecked = selectedUris.contains(item.toString())
|
||||
cbSelect.isChecked = selected.contains(item)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -65,18 +71,18 @@ class ImportBookAdapter(context: Context, val callBack: CallBack) :
|
||||
holder.itemView.setOnClickListener {
|
||||
getItem(holder.layoutPosition)?.let {
|
||||
if (it.isDir) {
|
||||
callBack.nextDoc(it)
|
||||
} else if (!isOnBookShelf(it)) {
|
||||
if (!selectedUris.contains(it.toString())) {
|
||||
selectedUris.add(it.toString())
|
||||
callBack.nextDoc(it.file)
|
||||
} else if (!it.isOnBookShelf) {
|
||||
if (!selected.contains(it)) {
|
||||
selected.add(it)
|
||||
} else {
|
||||
selectedUris.remove(it.toString())
|
||||
selected.remove(it)
|
||||
}
|
||||
notifyItemChanged(holder.layoutPosition, true)
|
||||
callBack.upCountView()
|
||||
} else {
|
||||
/* 点击开始阅读 */
|
||||
callBack.startRead(it)
|
||||
callBack.startRead(it.file)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -89,7 +95,7 @@ class ImportBookAdapter(context: Context, val callBack: CallBack) :
|
||||
private fun upCheckableCount() {
|
||||
checkableCount = 0
|
||||
getItems().forEach {
|
||||
if (!it.isDir && !isOnBookShelf(it)) {
|
||||
if (!it.isDir && !it.isOnBookShelf) {
|
||||
checkableCount++
|
||||
}
|
||||
}
|
||||
@@ -100,12 +106,12 @@ class ImportBookAdapter(context: Context, val callBack: CallBack) :
|
||||
fun selectAll(selectAll: Boolean) {
|
||||
if (selectAll) {
|
||||
getItems().forEach {
|
||||
if (!it.isDir && !isOnBookShelf(it)) {
|
||||
selectedUris.add(it.toString())
|
||||
if (!it.isDir && !it.isOnBookShelf) {
|
||||
selected.add(it)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
selectedUris.clear()
|
||||
selected.clear()
|
||||
}
|
||||
notifyDataSetChanged()
|
||||
callBack.upCountView()
|
||||
@@ -113,11 +119,11 @@ class ImportBookAdapter(context: Context, val callBack: CallBack) :
|
||||
|
||||
fun revertSelection() {
|
||||
getItems().forEach {
|
||||
if (!it.isDir && !isOnBookShelf(it)) {
|
||||
if (selectedUris.contains(it.toString())) {
|
||||
selectedUris.remove(it.toString())
|
||||
if (!it.isDir && !it.isOnBookShelf) {
|
||||
if (selected.contains(it)) {
|
||||
selected.remove(it)
|
||||
} else {
|
||||
selectedUris.add(it.toString())
|
||||
selected.add(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -127,7 +133,7 @@ class ImportBookAdapter(context: Context, val callBack: CallBack) :
|
||||
|
||||
fun removeSelection() {
|
||||
for (i in getItems().lastIndex downTo 0) {
|
||||
if (getItem(i)?.toString() in selectedUris) {
|
||||
if (getItem(i) in selected) {
|
||||
removeItem(i)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
package io.legado.app.ui.book.import.local
|
||||
|
||||
import android.app.Application
|
||||
import android.net.Uri
|
||||
import androidx.documentfile.provider.DocumentFile
|
||||
import io.legado.app.base.BaseViewModel
|
||||
import io.legado.app.constant.AppLog
|
||||
import io.legado.app.constant.AppPattern.archiveFileRegex
|
||||
@@ -11,19 +9,19 @@ import io.legado.app.constant.PreferKey
|
||||
import io.legado.app.model.localBook.LocalBook
|
||||
import io.legado.app.utils.AlphanumComparator
|
||||
import io.legado.app.utils.FileDoc
|
||||
import io.legado.app.utils.delete
|
||||
import io.legado.app.utils.getPrefInt
|
||||
import io.legado.app.utils.isContentScheme
|
||||
import io.legado.app.utils.list
|
||||
import io.legado.app.utils.toastOnUi
|
||||
import kotlinx.coroutines.Dispatchers.IO
|
||||
import kotlinx.coroutines.Dispatchers.Main
|
||||
import kotlinx.coroutines.FlowPreview
|
||||
import kotlinx.coroutines.channels.awaitClose
|
||||
import kotlinx.coroutines.flow.callbackFlow
|
||||
import kotlinx.coroutines.flow.flowOn
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.isActive
|
||||
import kotlinx.coroutines.withContext
|
||||
import java.io.File
|
||||
import java.util.Collections
|
||||
import kotlin.coroutines.coroutineContext
|
||||
|
||||
@@ -33,20 +31,24 @@ class ImportBookViewModel(application: Application) : BaseViewModel(application)
|
||||
var sort = context.getPrefInt(PreferKey.localBookImportSort)
|
||||
var dataCallback: DataCallback? = null
|
||||
var dataFlowStart: (() -> Unit)? = null
|
||||
val dataFlow = callbackFlow<List<FileDoc>> {
|
||||
val dataFlow = callbackFlow<List<ImportBook>> {
|
||||
|
||||
val list = Collections.synchronizedList(ArrayList<FileDoc>())
|
||||
val list = Collections.synchronizedList(ArrayList<ImportBook>())
|
||||
|
||||
dataCallback = object : DataCallback {
|
||||
|
||||
override fun setItems(fileDocs: List<FileDoc>) {
|
||||
list.clear()
|
||||
list.addAll(fileDocs)
|
||||
fileDocs.mapTo(list) {
|
||||
ImportBook(it)
|
||||
}
|
||||
trySend(list)
|
||||
}
|
||||
|
||||
override fun addItems(fileDocs: List<FileDoc>) {
|
||||
list.addAll(fileDocs)
|
||||
fileDocs.mapTo(list) {
|
||||
ImportBook(it)
|
||||
}
|
||||
trySend(list)
|
||||
}
|
||||
|
||||
@@ -64,6 +66,10 @@ class ImportBookViewModel(application: Application) : BaseViewModel(application)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
override fun upAdapter() {
|
||||
trySend(list)
|
||||
}
|
||||
}
|
||||
|
||||
withContext(Main) {
|
||||
@@ -76,21 +82,17 @@ class ImportBookViewModel(application: Application) : BaseViewModel(application)
|
||||
|
||||
}.map { docList ->
|
||||
val comparator = when (sort) {
|
||||
2 -> compareBy<FileDoc>({ !it.isDir }, { -it.lastModified })
|
||||
2 -> compareBy<ImportBook>({ !it.isDir }, { -it.lastModified })
|
||||
1 -> compareBy({ !it.isDir }, { -it.size })
|
||||
else -> compareBy { !it.isDir }
|
||||
} then compareBy(AlphanumComparator) { it.name }
|
||||
docList.sortedWith(comparator)
|
||||
}.flowOn(IO)
|
||||
|
||||
fun addToBookshelf(uriList: HashSet<String>, finally: () -> Unit) {
|
||||
fun addToBookshelf(bookList: HashSet<ImportBook>, finally: () -> Unit) {
|
||||
execute {
|
||||
val fileUris = uriList.map {
|
||||
if (it.isContentScheme()) {
|
||||
Uri.parse(it)
|
||||
} else {
|
||||
Uri.fromFile(File(it))
|
||||
}
|
||||
val fileUris = bookList.map {
|
||||
it.file.uri
|
||||
}
|
||||
LocalBook.importFiles(fileUris)
|
||||
}.onError {
|
||||
@@ -101,17 +103,10 @@ class ImportBookViewModel(application: Application) : BaseViewModel(application)
|
||||
}
|
||||
}
|
||||
|
||||
fun deleteDoc(uriList: HashSet<String>, finally: () -> Unit) {
|
||||
fun deleteDoc(bookList: HashSet<ImportBook>, finally: () -> Unit) {
|
||||
execute {
|
||||
uriList.forEach {
|
||||
val uri = Uri.parse(it)
|
||||
if (uri.isContentScheme()) {
|
||||
DocumentFile.fromSingleUri(context, uri)?.delete()
|
||||
} else {
|
||||
uri.path?.let { path ->
|
||||
File(path).delete()
|
||||
}
|
||||
}
|
||||
bookList.forEach {
|
||||
it.file.delete()
|
||||
}
|
||||
}.onFinally {
|
||||
finally.invoke()
|
||||
@@ -190,6 +185,8 @@ class ImportBookViewModel(application: Application) : BaseViewModel(application)
|
||||
|
||||
fun screen(key: String?)
|
||||
|
||||
fun upAdapter()
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user