mirror of
https://github.com/gedoor/legado.git
synced 2024-09-01 09:34:25 +08:00
优化
This commit is contained in:
parent
bb3c475d19
commit
536577b869
@ -25,10 +25,9 @@ import io.legado.app.ui.widget.SelectActionBar
|
||||
import io.legado.app.utils.*
|
||||
import io.legado.app.utils.viewbindingdelegate.viewBinding
|
||||
import kotlinx.coroutines.Dispatchers.IO
|
||||
import kotlinx.coroutines.Dispatchers.Main
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.flow.conflate
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import java.io.File
|
||||
|
||||
/**
|
||||
@ -41,10 +40,10 @@ class ImportBookActivity : VMBaseActivity<ActivityImportBookBinding, ImportBookV
|
||||
|
||||
override val binding by viewBinding(ActivityImportBookBinding::inflate)
|
||||
override val viewModel by viewModels<ImportBookViewModel>()
|
||||
private val bookFileRegex = Regex("(?i).*\\.(txt|epub|umd)")
|
||||
private var rootDoc: FileDoc? = null
|
||||
private val subDocs = arrayListOf<FileDoc>()
|
||||
private val adapter by lazy { ImportBookAdapter(this, this) }
|
||||
private var scanDocJob: Job? = null
|
||||
|
||||
private val selectFolder = registerForActivityResult(HandleFileContract()) {
|
||||
it.uri?.let { uri ->
|
||||
@ -62,7 +61,6 @@ class ImportBookActivity : VMBaseActivity<ActivityImportBookBinding, ImportBookV
|
||||
initView()
|
||||
initEvent()
|
||||
initData()
|
||||
initRootDoc()
|
||||
}
|
||||
|
||||
override fun onCompatCreateOptionsMenu(menu: Menu): Boolean {
|
||||
@ -84,15 +82,15 @@ class ImportBookActivity : VMBaseActivity<ActivityImportBookBinding, ImportBookV
|
||||
R.id.menu_import_file_name -> alertImportFileName()
|
||||
R.id.menu_sort_name -> {
|
||||
viewModel.sort = 0
|
||||
upPath()
|
||||
upSort()
|
||||
}
|
||||
R.id.menu_sort_size -> {
|
||||
viewModel.sort = 1
|
||||
upPath()
|
||||
upSort()
|
||||
}
|
||||
R.id.menu_sort_time -> {
|
||||
viewModel.sort = 2
|
||||
upPath()
|
||||
upSort()
|
||||
}
|
||||
}
|
||||
return super.onCompatOptionsItemSelected(item)
|
||||
@ -140,11 +138,19 @@ class ImportBookActivity : VMBaseActivity<ActivityImportBookBinding, ImportBookV
|
||||
}
|
||||
|
||||
private fun initData() {
|
||||
viewModel.dataFlowStart = {
|
||||
initRootDoc()
|
||||
}
|
||||
launch {
|
||||
appDb.bookDao.flowLocalUri().conflate().collect {
|
||||
adapter.upBookHas(it)
|
||||
}
|
||||
}
|
||||
launch {
|
||||
viewModel.dataFlow.conflate().collect { docs ->
|
||||
adapter.setItems(docs)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun initRootDoc() {
|
||||
@ -197,9 +203,16 @@ class ImportBookActivity : VMBaseActivity<ActivityImportBookBinding, ImportBookV
|
||||
.request()
|
||||
}
|
||||
|
||||
private fun upSort() {
|
||||
if (scanDocJob?.isCancelled == true || scanDocJob?.isCompleted == true) {
|
||||
viewModel.dataCallback?.setItems(adapter.getItems())
|
||||
}
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
private fun upPath() {
|
||||
rootDoc?.let {
|
||||
scanDocJob?.cancel()
|
||||
upDocs(it)
|
||||
}
|
||||
}
|
||||
@ -215,44 +228,7 @@ class ImportBookActivity : VMBaseActivity<ActivityImportBookBinding, ImportBookV
|
||||
binding.tvPath.text = path
|
||||
adapter.selectedUris.clear()
|
||||
adapter.clearItems()
|
||||
launch(IO) {
|
||||
runCatching {
|
||||
val docList = DocumentUtils.listFiles(lastDoc.uri) { item ->
|
||||
when {
|
||||
item.name.startsWith(".") -> false
|
||||
item.isDir -> true
|
||||
else -> item.name.matches(bookFileRegex)
|
||||
}
|
||||
}
|
||||
when (viewModel.sort) {
|
||||
2 -> docList.sortWith(
|
||||
compareBy(
|
||||
{ !it.isDir },
|
||||
{ it.date },
|
||||
{ it.name }
|
||||
)
|
||||
)
|
||||
1 -> docList.sortWith(
|
||||
compareBy(
|
||||
{ !it.isDir },
|
||||
{ it.size },
|
||||
{ it.name }
|
||||
)
|
||||
)
|
||||
else -> docList.sortWith(
|
||||
compareBy(
|
||||
{ !it.isDir },
|
||||
{ it.name }
|
||||
)
|
||||
)
|
||||
}
|
||||
withContext(Main) {
|
||||
adapter.setItems(docList)
|
||||
}
|
||||
}.onFailure {
|
||||
toastOnUi("获取文件列表出错\n${it.localizedMessage}")
|
||||
}
|
||||
}
|
||||
viewModel.loadDoc(lastDoc.uri)
|
||||
}
|
||||
|
||||
/**
|
||||
@ -263,8 +239,9 @@ class ImportBookActivity : VMBaseActivity<ActivityImportBookBinding, ImportBookV
|
||||
adapter.clearItems()
|
||||
val lastDoc = subDocs.lastOrNull() ?: doc
|
||||
binding.refreshProgressBar.isAutoLoading = true
|
||||
launch(IO) {
|
||||
viewModel.scanDoc(lastDoc, true, find) {
|
||||
scanDocJob?.cancel()
|
||||
scanDocJob = launch(IO) {
|
||||
viewModel.scanDoc(lastDoc, true, this) {
|
||||
launch {
|
||||
binding.refreshProgressBar.isAutoLoading = false
|
||||
}
|
||||
@ -288,12 +265,6 @@ class ImportBookActivity : VMBaseActivity<ActivityImportBookBinding, ImportBookV
|
||||
}
|
||||
}
|
||||
|
||||
private val find: (docItem: FileDoc) -> Unit = {
|
||||
launch {
|
||||
adapter.addItem(it)
|
||||
}
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
override fun nextDoc(fileDoc: FileDoc) {
|
||||
subDocs.add(fileDoc)
|
||||
|
@ -9,12 +9,79 @@ import io.legado.app.utils.DocumentUtils
|
||||
import io.legado.app.utils.FileDoc
|
||||
import io.legado.app.utils.isContentScheme
|
||||
import io.legado.app.utils.toastOnUi
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers.IO
|
||||
import kotlinx.coroutines.Dispatchers.Main
|
||||
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.*
|
||||
|
||||
|
||||
class ImportBookViewModel(application: Application) : BaseViewModel(application) {
|
||||
|
||||
private val bookFileRegex = Regex("(?i).*\\.(txt|epub|umd)")
|
||||
var sort = 0
|
||||
var dataCallback: DataCallback? = null
|
||||
var dataFlowStart: (() -> Unit)? = null
|
||||
val dataFlow = callbackFlow<List<FileDoc>> {
|
||||
|
||||
val list = Collections.synchronizedList(ArrayList<FileDoc>())
|
||||
|
||||
dataCallback = object : DataCallback {
|
||||
|
||||
override fun setItems(fileDocs: List<FileDoc>) {
|
||||
list.clear()
|
||||
list.addAll(fileDocs)
|
||||
trySend(list)
|
||||
}
|
||||
|
||||
override fun addItems(fileDocs: List<FileDoc>) {
|
||||
list.addAll(fileDocs)
|
||||
trySend(list)
|
||||
}
|
||||
|
||||
override fun clear() {
|
||||
list.clear()
|
||||
trySend(emptyList())
|
||||
}
|
||||
}
|
||||
|
||||
withContext(Main) {
|
||||
dataFlowStart?.invoke()
|
||||
}
|
||||
|
||||
awaitClose {
|
||||
dataCallback = null
|
||||
}
|
||||
|
||||
}.map { docList ->
|
||||
when (sort) {
|
||||
2 -> docList.sortedWith(
|
||||
compareBy(
|
||||
{ !it.isDir },
|
||||
{ it.date },
|
||||
{ it.name }
|
||||
)
|
||||
)
|
||||
1 -> docList.sortedWith(
|
||||
compareBy(
|
||||
{ !it.isDir },
|
||||
{ it.size },
|
||||
{ it.name }
|
||||
)
|
||||
)
|
||||
else -> docList.sortedWith(
|
||||
compareBy(
|
||||
{ !it.isDir },
|
||||
{ it.name }
|
||||
)
|
||||
)
|
||||
}
|
||||
}.flowOn(IO)
|
||||
|
||||
fun addToBookshelf(uriList: HashSet<String>, finally: () -> Unit) {
|
||||
execute {
|
||||
@ -43,22 +110,56 @@ class ImportBookViewModel(application: Application) : BaseViewModel(application)
|
||||
}
|
||||
}
|
||||
|
||||
fun loadDoc(uri: Uri) {
|
||||
execute {
|
||||
val docList = DocumentUtils.listFiles(uri) { item ->
|
||||
when {
|
||||
item.name.startsWith(".") -> false
|
||||
item.isDir -> true
|
||||
else -> item.name.matches(bookFileRegex)
|
||||
}
|
||||
}
|
||||
dataCallback?.setItems(docList)
|
||||
}.onError {
|
||||
context.toastOnUi("获取文件列表出错\n${it.localizedMessage}")
|
||||
}
|
||||
}
|
||||
|
||||
fun scanDoc(
|
||||
fileDoc: FileDoc,
|
||||
isRoot: Boolean,
|
||||
find: (docItem: FileDoc) -> Unit,
|
||||
scope: CoroutineScope,
|
||||
finally: (() -> Unit)? = null
|
||||
) {
|
||||
if (isRoot) {
|
||||
dataCallback?.clear()
|
||||
}
|
||||
if (!scope.isActive) {
|
||||
finally?.invoke()
|
||||
return
|
||||
}
|
||||
kotlin.runCatching {
|
||||
val list = ArrayList<FileDoc>()
|
||||
DocumentUtils.listFiles(fileDoc.uri).forEach { docItem ->
|
||||
if (!scope.isActive) {
|
||||
finally?.invoke()
|
||||
return
|
||||
}
|
||||
if (docItem.isDir) {
|
||||
scanDoc(docItem, false, find)
|
||||
scanDoc(docItem, false, scope)
|
||||
} else if (docItem.name.endsWith(".txt", true)
|
||||
|| docItem.name.endsWith(".epub", true)
|
||||
) {
|
||||
find(docItem)
|
||||
list.add(docItem)
|
||||
}
|
||||
}
|
||||
if (!scope.isActive) {
|
||||
finally?.invoke()
|
||||
return
|
||||
}
|
||||
if (list.isNotEmpty()) {
|
||||
dataCallback?.addItems(list)
|
||||
}
|
||||
}.onFailure {
|
||||
context.toastOnUi("扫描文件夹出错\n${it.localizedMessage}")
|
||||
}
|
||||
@ -67,4 +168,14 @@ class ImportBookViewModel(application: Application) : BaseViewModel(application)
|
||||
}
|
||||
}
|
||||
|
||||
interface DataCallback {
|
||||
|
||||
fun setItems(fileDocs: List<FileDoc>)
|
||||
|
||||
fun addItems(fileDocs: List<FileDoc>)
|
||||
|
||||
fun clear()
|
||||
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue
Block a user