优化
This commit is contained in:
@@ -25,10 +25,9 @@ import io.legado.app.ui.widget.SelectActionBar
|
|||||||
import io.legado.app.utils.*
|
import io.legado.app.utils.*
|
||||||
import io.legado.app.utils.viewbindingdelegate.viewBinding
|
import io.legado.app.utils.viewbindingdelegate.viewBinding
|
||||||
import kotlinx.coroutines.Dispatchers.IO
|
import kotlinx.coroutines.Dispatchers.IO
|
||||||
import kotlinx.coroutines.Dispatchers.Main
|
import kotlinx.coroutines.Job
|
||||||
import kotlinx.coroutines.flow.conflate
|
import kotlinx.coroutines.flow.conflate
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.withContext
|
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -41,10 +40,10 @@ class ImportBookActivity : VMBaseActivity<ActivityImportBookBinding, ImportBookV
|
|||||||
|
|
||||||
override val binding by viewBinding(ActivityImportBookBinding::inflate)
|
override val binding by viewBinding(ActivityImportBookBinding::inflate)
|
||||||
override val viewModel by viewModels<ImportBookViewModel>()
|
override val viewModel by viewModels<ImportBookViewModel>()
|
||||||
private val bookFileRegex = Regex("(?i).*\\.(txt|epub|umd)")
|
|
||||||
private var rootDoc: FileDoc? = null
|
private var rootDoc: FileDoc? = null
|
||||||
private val subDocs = arrayListOf<FileDoc>()
|
private val subDocs = arrayListOf<FileDoc>()
|
||||||
private val adapter by lazy { ImportBookAdapter(this, this) }
|
private val adapter by lazy { ImportBookAdapter(this, this) }
|
||||||
|
private var scanDocJob: Job? = null
|
||||||
|
|
||||||
private val selectFolder = registerForActivityResult(HandleFileContract()) {
|
private val selectFolder = registerForActivityResult(HandleFileContract()) {
|
||||||
it.uri?.let { uri ->
|
it.uri?.let { uri ->
|
||||||
@@ -62,7 +61,6 @@ class ImportBookActivity : VMBaseActivity<ActivityImportBookBinding, ImportBookV
|
|||||||
initView()
|
initView()
|
||||||
initEvent()
|
initEvent()
|
||||||
initData()
|
initData()
|
||||||
initRootDoc()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCompatCreateOptionsMenu(menu: Menu): Boolean {
|
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_import_file_name -> alertImportFileName()
|
||||||
R.id.menu_sort_name -> {
|
R.id.menu_sort_name -> {
|
||||||
viewModel.sort = 0
|
viewModel.sort = 0
|
||||||
upPath()
|
upSort()
|
||||||
}
|
}
|
||||||
R.id.menu_sort_size -> {
|
R.id.menu_sort_size -> {
|
||||||
viewModel.sort = 1
|
viewModel.sort = 1
|
||||||
upPath()
|
upSort()
|
||||||
}
|
}
|
||||||
R.id.menu_sort_time -> {
|
R.id.menu_sort_time -> {
|
||||||
viewModel.sort = 2
|
viewModel.sort = 2
|
||||||
upPath()
|
upSort()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return super.onCompatOptionsItemSelected(item)
|
return super.onCompatOptionsItemSelected(item)
|
||||||
@@ -140,11 +138,19 @@ class ImportBookActivity : VMBaseActivity<ActivityImportBookBinding, ImportBookV
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun initData() {
|
private fun initData() {
|
||||||
|
viewModel.dataFlowStart = {
|
||||||
|
initRootDoc()
|
||||||
|
}
|
||||||
launch {
|
launch {
|
||||||
appDb.bookDao.flowLocalUri().conflate().collect {
|
appDb.bookDao.flowLocalUri().conflate().collect {
|
||||||
adapter.upBookHas(it)
|
adapter.upBookHas(it)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
launch {
|
||||||
|
viewModel.dataFlow.conflate().collect { docs ->
|
||||||
|
adapter.setItems(docs)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun initRootDoc() {
|
private fun initRootDoc() {
|
||||||
@@ -197,9 +203,16 @@ class ImportBookActivity : VMBaseActivity<ActivityImportBookBinding, ImportBookV
|
|||||||
.request()
|
.request()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun upSort() {
|
||||||
|
if (scanDocJob?.isCancelled == true || scanDocJob?.isCompleted == true) {
|
||||||
|
viewModel.dataCallback?.setItems(adapter.getItems())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Synchronized
|
@Synchronized
|
||||||
private fun upPath() {
|
private fun upPath() {
|
||||||
rootDoc?.let {
|
rootDoc?.let {
|
||||||
|
scanDocJob?.cancel()
|
||||||
upDocs(it)
|
upDocs(it)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -215,44 +228,7 @@ class ImportBookActivity : VMBaseActivity<ActivityImportBookBinding, ImportBookV
|
|||||||
binding.tvPath.text = path
|
binding.tvPath.text = path
|
||||||
adapter.selectedUris.clear()
|
adapter.selectedUris.clear()
|
||||||
adapter.clearItems()
|
adapter.clearItems()
|
||||||
launch(IO) {
|
viewModel.loadDoc(lastDoc.uri)
|
||||||
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}")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -263,8 +239,9 @@ class ImportBookActivity : VMBaseActivity<ActivityImportBookBinding, ImportBookV
|
|||||||
adapter.clearItems()
|
adapter.clearItems()
|
||||||
val lastDoc = subDocs.lastOrNull() ?: doc
|
val lastDoc = subDocs.lastOrNull() ?: doc
|
||||||
binding.refreshProgressBar.isAutoLoading = true
|
binding.refreshProgressBar.isAutoLoading = true
|
||||||
launch(IO) {
|
scanDocJob?.cancel()
|
||||||
viewModel.scanDoc(lastDoc, true, find) {
|
scanDocJob = launch(IO) {
|
||||||
|
viewModel.scanDoc(lastDoc, true, this) {
|
||||||
launch {
|
launch {
|
||||||
binding.refreshProgressBar.isAutoLoading = false
|
binding.refreshProgressBar.isAutoLoading = false
|
||||||
}
|
}
|
||||||
@@ -288,12 +265,6 @@ class ImportBookActivity : VMBaseActivity<ActivityImportBookBinding, ImportBookV
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private val find: (docItem: FileDoc) -> Unit = {
|
|
||||||
launch {
|
|
||||||
adapter.addItem(it)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Synchronized
|
@Synchronized
|
||||||
override fun nextDoc(fileDoc: FileDoc) {
|
override fun nextDoc(fileDoc: FileDoc) {
|
||||||
subDocs.add(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.FileDoc
|
||||||
import io.legado.app.utils.isContentScheme
|
import io.legado.app.utils.isContentScheme
|
||||||
import io.legado.app.utils.toastOnUi
|
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.io.File
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
|
|
||||||
class ImportBookViewModel(application: Application) : BaseViewModel(application) {
|
class ImportBookViewModel(application: Application) : BaseViewModel(application) {
|
||||||
|
private val bookFileRegex = Regex("(?i).*\\.(txt|epub|umd)")
|
||||||
var sort = 0
|
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) {
|
fun addToBookshelf(uriList: HashSet<String>, finally: () -> Unit) {
|
||||||
execute {
|
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(
|
fun scanDoc(
|
||||||
fileDoc: FileDoc,
|
fileDoc: FileDoc,
|
||||||
isRoot: Boolean,
|
isRoot: Boolean,
|
||||||
find: (docItem: FileDoc) -> Unit,
|
scope: CoroutineScope,
|
||||||
finally: (() -> Unit)? = null
|
finally: (() -> Unit)? = null
|
||||||
) {
|
) {
|
||||||
|
if (isRoot) {
|
||||||
|
dataCallback?.clear()
|
||||||
|
}
|
||||||
|
if (!scope.isActive) {
|
||||||
|
finally?.invoke()
|
||||||
|
return
|
||||||
|
}
|
||||||
kotlin.runCatching {
|
kotlin.runCatching {
|
||||||
|
val list = ArrayList<FileDoc>()
|
||||||
DocumentUtils.listFiles(fileDoc.uri).forEach { docItem ->
|
DocumentUtils.listFiles(fileDoc.uri).forEach { docItem ->
|
||||||
|
if (!scope.isActive) {
|
||||||
|
finally?.invoke()
|
||||||
|
return
|
||||||
|
}
|
||||||
if (docItem.isDir) {
|
if (docItem.isDir) {
|
||||||
scanDoc(docItem, false, find)
|
scanDoc(docItem, false, scope)
|
||||||
} else if (docItem.name.endsWith(".txt", true)
|
} else if (docItem.name.endsWith(".txt", true)
|
||||||
|| docItem.name.endsWith(".epub", true)
|
|| docItem.name.endsWith(".epub", true)
|
||||||
) {
|
) {
|
||||||
find(docItem)
|
list.add(docItem)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (!scope.isActive) {
|
||||||
|
finally?.invoke()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (list.isNotEmpty()) {
|
||||||
|
dataCallback?.addItems(list)
|
||||||
|
}
|
||||||
}.onFailure {
|
}.onFailure {
|
||||||
context.toastOnUi("扫描文件夹出错\n${it.localizedMessage}")
|
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()
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user