优化
This commit is contained in:
@@ -41,8 +41,6 @@ class ImportBookActivity : VMBaseActivity<ActivityImportBookBinding, ImportBookV
|
||||
|
||||
override val binding by viewBinding(ActivityImportBookBinding::inflate)
|
||||
override val viewModel by viewModels<ImportBookViewModel>()
|
||||
private var rootDoc: FileDoc? = null
|
||||
private val subDocs = arrayListOf<FileDoc>()
|
||||
private val adapter by lazy { ImportBookAdapter(this, this) }
|
||||
private var scanDocJob: Job? = null
|
||||
|
||||
@@ -59,6 +57,7 @@ class ImportBookActivity : VMBaseActivity<ActivityImportBookBinding, ImportBookV
|
||||
}
|
||||
|
||||
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
||||
binding.titleBar.setTitle(R.string.book_local)
|
||||
initView()
|
||||
initEvent()
|
||||
initData()
|
||||
@@ -148,6 +147,7 @@ class ImportBookActivity : VMBaseActivity<ActivityImportBookBinding, ImportBookV
|
||||
private fun initRootDoc() {
|
||||
val lastPath = AppConfig.importBookPath
|
||||
when {
|
||||
viewModel.rootDoc != null -> upPath()
|
||||
lastPath.isNullOrEmpty() -> {
|
||||
binding.tvEmptyMsg.visible()
|
||||
selectFolder.launch()
|
||||
@@ -160,9 +160,9 @@ class ImportBookActivity : VMBaseActivity<ActivityImportBookBinding, ImportBookV
|
||||
binding.tvEmptyMsg.visible()
|
||||
selectFolder.launch()
|
||||
} else {
|
||||
subDocs.clear()
|
||||
rootDoc = FileDoc.fromDocumentFile(doc)
|
||||
upDocs(rootDoc!!)
|
||||
viewModel.subDocs.clear()
|
||||
viewModel.rootDoc = FileDoc.fromDocumentFile(doc)
|
||||
upDocs(viewModel.rootDoc!!)
|
||||
}
|
||||
}.onFailure {
|
||||
binding.tvEmptyMsg.visible()
|
||||
@@ -184,8 +184,8 @@ class ImportBookActivity : VMBaseActivity<ActivityImportBookBinding, ImportBookV
|
||||
.rationale(R.string.tip_perm_request_storage)
|
||||
.onGranted {
|
||||
kotlin.runCatching {
|
||||
rootDoc = FileDoc.fromFile(File(path))
|
||||
subDocs.clear()
|
||||
viewModel.rootDoc = FileDoc.fromFile(File(path))
|
||||
viewModel.subDocs.clear()
|
||||
upPath()
|
||||
}.onFailure {
|
||||
binding.tvEmptyMsg.visible()
|
||||
@@ -205,7 +205,7 @@ class ImportBookActivity : VMBaseActivity<ActivityImportBookBinding, ImportBookV
|
||||
|
||||
@Synchronized
|
||||
private fun upPath() {
|
||||
rootDoc?.let {
|
||||
viewModel.rootDoc?.let {
|
||||
scanDocJob?.cancel()
|
||||
upDocs(it)
|
||||
}
|
||||
@@ -215,7 +215,7 @@ class ImportBookActivity : VMBaseActivity<ActivityImportBookBinding, ImportBookV
|
||||
binding.tvEmptyMsg.gone()
|
||||
var path = rootDoc.name + File.separator
|
||||
var lastDoc = rootDoc
|
||||
for (doc in subDocs) {
|
||||
for (doc in viewModel.subDocs) {
|
||||
lastDoc = doc
|
||||
path = path + doc.name + File.separator
|
||||
}
|
||||
@@ -229,9 +229,9 @@ class ImportBookActivity : VMBaseActivity<ActivityImportBookBinding, ImportBookV
|
||||
* 扫描当前文件夹及所有子文件夹
|
||||
*/
|
||||
private fun scanFolder() {
|
||||
rootDoc?.let { doc ->
|
||||
viewModel.rootDoc?.let { doc ->
|
||||
adapter.clearItems()
|
||||
val lastDoc = subDocs.lastOrNull() ?: doc
|
||||
val lastDoc = viewModel.subDocs.lastOrNull() ?: doc
|
||||
binding.refreshProgressBar.isAutoLoading = true
|
||||
scanDocJob?.cancel()
|
||||
scanDocJob = launch(IO) {
|
||||
@@ -261,14 +261,14 @@ class ImportBookActivity : VMBaseActivity<ActivityImportBookBinding, ImportBookV
|
||||
|
||||
@Synchronized
|
||||
override fun nextDoc(fileDoc: FileDoc) {
|
||||
subDocs.add(fileDoc)
|
||||
viewModel.subDocs.add(fileDoc)
|
||||
upPath()
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
private fun goBackDir(): Boolean {
|
||||
return if (subDocs.isNotEmpty()) {
|
||||
subDocs.removeAt(subDocs.lastIndex)
|
||||
return if (viewModel.subDocs.isNotEmpty()) {
|
||||
viewModel.subDocs.removeAt(viewModel.subDocs.lastIndex)
|
||||
upPath()
|
||||
true
|
||||
} else {
|
||||
|
||||
@@ -14,9 +14,9 @@ import io.legado.app.utils.*
|
||||
|
||||
class ImportBookAdapter(context: Context, val callBack: CallBack) :
|
||||
RecyclerAdapter<FileDoc, ItemImportBookBinding>(context) {
|
||||
var selectedUris = hashSetOf<String>()
|
||||
val selectedUris = hashSetOf<String>()
|
||||
var checkableCount = 0
|
||||
private var bookFileNames = arrayListOf<String>()
|
||||
private val bookFileNames = arrayListOf<String>()
|
||||
|
||||
override fun getViewBinding(parent: ViewGroup): ItemImportBookBinding {
|
||||
return ItemImportBookBinding.inflate(inflater, parent, false)
|
||||
|
||||
@@ -21,6 +21,8 @@ import java.io.File
|
||||
import java.util.*
|
||||
|
||||
class ImportBookViewModel(application: Application) : BaseViewModel(application) {
|
||||
var rootDoc: FileDoc? = null
|
||||
val subDocs = arrayListOf<FileDoc>()
|
||||
var sort = context.getPrefInt(PreferKey.localBookImportSort)
|
||||
var dataCallback: DataCallback? = null
|
||||
var dataFlowStart: (() -> Unit)? = null
|
||||
|
||||
@@ -6,7 +6,7 @@ data class RemoteBook(
|
||||
val size: Long,
|
||||
val contentType: String,
|
||||
val lastModify: Long,
|
||||
val isOnBookShelf: Boolean
|
||||
var isOnBookShelf: Boolean
|
||||
) {
|
||||
|
||||
val isDir by lazy {
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
package io.legado.app.ui.book.remote
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.os.Bundle
|
||||
import android.view.Menu
|
||||
import android.view.MenuItem
|
||||
@@ -9,37 +8,42 @@ import androidx.core.view.isGone
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import io.legado.app.R
|
||||
import io.legado.app.base.VMBaseActivity
|
||||
|
||||
|
||||
import io.legado.app.databinding.ActivityRemoteBookBinding
|
||||
import io.legado.app.databinding.ActivityImportBookBinding
|
||||
import io.legado.app.lib.theme.backgroundColor
|
||||
import io.legado.app.ui.book.remote.manager.RemoteBookWebDav
|
||||
import io.legado.app.ui.widget.SelectActionBar
|
||||
import io.legado.app.ui.widget.dialog.WaitDialog
|
||||
import io.legado.app.utils.toastOnUi
|
||||
|
||||
import io.legado.app.utils.viewbindingdelegate.viewBinding
|
||||
import kotlinx.coroutines.flow.conflate
|
||||
import kotlinx.coroutines.launch
|
||||
import java.io.File
|
||||
|
||||
/**
|
||||
* 展示远程书籍
|
||||
* @author qianfanguojin
|
||||
* @time 2022/05/12
|
||||
*/
|
||||
class RemoteBookActivity : VMBaseActivity<ActivityRemoteBookBinding, RemoteBookViewModel>(),
|
||||
RemoteBookAdapter.CallBack {
|
||||
override val binding by viewBinding(ActivityRemoteBookBinding::inflate)
|
||||
class RemoteBookActivity : VMBaseActivity<ActivityImportBookBinding, RemoteBookViewModel>(),
|
||||
RemoteBookAdapter.CallBack,
|
||||
SelectActionBar.CallBack {
|
||||
override val binding by viewBinding(ActivityImportBookBinding::inflate)
|
||||
override val viewModel by viewModels<RemoteBookViewModel>()
|
||||
private val adapter by lazy { RemoteBookAdapter(this, this) }
|
||||
private val waitDialog by lazy { WaitDialog(this) }
|
||||
|
||||
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
||||
binding.titleBar.setTitle(R.string.remote_book)
|
||||
initView()
|
||||
initData()
|
||||
initEvent()
|
||||
}
|
||||
|
||||
private fun initView() {
|
||||
binding.layTop.setBackgroundColor(backgroundColor)
|
||||
binding.recyclerView.layoutManager = LinearLayoutManager(this)
|
||||
binding.recyclerView.adapter = adapter
|
||||
binding.selectActionBar.setMainActionText(R.string.add_to_shelf)
|
||||
binding.selectActionBar.setCallBack(this)
|
||||
}
|
||||
|
||||
private fun initData() {
|
||||
@@ -51,7 +55,14 @@ class RemoteBookActivity : VMBaseActivity<ActivityRemoteBookBinding, RemoteBookV
|
||||
adapter.setItems(remoteBooks)
|
||||
}
|
||||
}
|
||||
viewModel.loadRemoteBookList(RemoteBookWebDav.rootBookUrl)
|
||||
upPath()
|
||||
}
|
||||
|
||||
private fun initEvent() {
|
||||
binding.tvGoBack.setOnClickListener {
|
||||
viewModel.dirList.removeLastOrNull()
|
||||
upPath()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCompatCreateOptionsMenu(menu: Menu): Boolean {
|
||||
@@ -62,46 +73,47 @@ class RemoteBookActivity : VMBaseActivity<ActivityRemoteBookBinding, RemoteBookV
|
||||
override fun onCompatOptionsItemSelected(item: MenuItem): Boolean {
|
||||
when (item.itemId) {
|
||||
R.id.menu_refresh -> {
|
||||
viewModel.loadRemoteBookList(
|
||||
viewModel.dirList.lastOrNull()?.path ?: RemoteBookWebDav.rootBookUrl
|
||||
)
|
||||
upPath()
|
||||
}
|
||||
}
|
||||
return super.onCompatOptionsItemSelected(item)
|
||||
}
|
||||
|
||||
override fun finish() {
|
||||
if (viewModel.dirList.isEmpty()) {
|
||||
super.finish()
|
||||
} else {
|
||||
viewModel.dirList.removeLastOrNull()
|
||||
val remoteBook = viewModel.dirList.lastOrNull()
|
||||
viewModel.dataCallback?.clear()
|
||||
if (remoteBook != null) {
|
||||
binding.titleBar.title = remoteBook.filename
|
||||
viewModel.loadRemoteBookList(remoteBook.path)
|
||||
} else {
|
||||
binding.titleBar.setTitle(R.string.remote_book)
|
||||
viewModel.loadRemoteBookList(RemoteBookWebDav.rootBookUrl)
|
||||
}
|
||||
override fun revertSelection() {
|
||||
adapter.revertSelection()
|
||||
}
|
||||
|
||||
override fun selectAll(selectAll: Boolean) {
|
||||
adapter.selectAll(selectAll)
|
||||
}
|
||||
|
||||
override fun onClickSelectBarMainAction() {
|
||||
waitDialog.show()
|
||||
viewModel.addToBookshelf(adapter.selected) {
|
||||
adapter.notifyDataSetChanged()
|
||||
waitDialog.dismiss()
|
||||
}
|
||||
}
|
||||
|
||||
private fun upPath() {
|
||||
var path = "books" + File.separator
|
||||
viewModel.dirList.forEach {
|
||||
path = path + it.filename + File.separator
|
||||
}
|
||||
binding.tvPath.text = path
|
||||
viewModel.dataCallback?.clear()
|
||||
adapter.selected.clear()
|
||||
viewModel.loadRemoteBookList(
|
||||
viewModel.dirList.lastOrNull()?.path ?: RemoteBookWebDav.rootBookUrl
|
||||
)
|
||||
}
|
||||
|
||||
override fun openDir(remoteBook: RemoteBook) {
|
||||
viewModel.dirList.add(remoteBook)
|
||||
binding.titleBar.title = remoteBook.filename
|
||||
viewModel.dataCallback?.clear()
|
||||
viewModel.loadRemoteBookList(remoteBook.path)
|
||||
upPath()
|
||||
}
|
||||
|
||||
@SuppressLint("NotifyDataSetChanged")
|
||||
override fun addToBookshelf(remoteBook: RemoteBook) {
|
||||
waitDialog.show()
|
||||
viewModel.addToBookshelf(remoteBook, success = {
|
||||
toastOnUi(getString(R.string.download_book_success))
|
||||
adapter.notifyDataSetChanged()
|
||||
}) {
|
||||
waitDialog.dismiss()
|
||||
}
|
||||
override fun upCountView() {
|
||||
binding.selectActionBar.upCountView(adapter.selected.size, adapter.checkableCount)
|
||||
}
|
||||
}
|
||||
@@ -1,13 +1,17 @@
|
||||
package io.legado.app.ui.book.remote
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.Context
|
||||
import android.view.ViewGroup
|
||||
import androidx.core.view.isGone
|
||||
import cn.hutool.core.date.LocalDateTimeUtil
|
||||
import io.legado.app.R
|
||||
import io.legado.app.base.adapter.ItemViewHolder
|
||||
import io.legado.app.base.adapter.RecyclerAdapter
|
||||
import io.legado.app.databinding.ItemRemoteBookBinding
|
||||
import io.legado.app.constant.AppConst
|
||||
import io.legado.app.databinding.ItemImportBookBinding
|
||||
import io.legado.app.utils.ConvertUtils
|
||||
import io.legado.app.utils.gone
|
||||
import io.legado.app.utils.invisible
|
||||
import io.legado.app.utils.visible
|
||||
|
||||
|
||||
/**
|
||||
@@ -15,14 +19,16 @@ import io.legado.app.utils.ConvertUtils
|
||||
* @author qianfanguojin
|
||||
*/
|
||||
class RemoteBookAdapter(context: Context, val callBack: CallBack) :
|
||||
RecyclerAdapter<RemoteBook, ItemRemoteBookBinding>(context) {
|
||||
RecyclerAdapter<RemoteBook, ItemImportBookBinding>(context) {
|
||||
var selected = hashSetOf<RemoteBook>()
|
||||
var checkableCount = 0
|
||||
|
||||
override fun getViewBinding(parent: ViewGroup): ItemRemoteBookBinding {
|
||||
return ItemRemoteBookBinding.inflate(inflater, parent, false)
|
||||
override fun getViewBinding(parent: ViewGroup): ItemImportBookBinding {
|
||||
return ItemImportBookBinding.inflate(inflater, parent, false)
|
||||
}
|
||||
|
||||
override fun onCurrentListChanged() {
|
||||
|
||||
upCheckableCount()
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -30,39 +36,107 @@ class RemoteBookAdapter(context: Context, val callBack: CallBack) :
|
||||
*/
|
||||
override fun convert(
|
||||
holder: ItemViewHolder,
|
||||
binding: ItemRemoteBookBinding,
|
||||
binding: ItemImportBookBinding,
|
||||
item: RemoteBook,
|
||||
payloads: MutableList<Any>
|
||||
) {
|
||||
binding.run {
|
||||
tvName.text = item.filename.substringBeforeLast(".")
|
||||
tvContentType.text = item.contentType
|
||||
tvSize.text = ConvertUtils.formatFileSize(item.size)
|
||||
tvDate.text =
|
||||
LocalDateTimeUtil.format(LocalDateTimeUtil.of(item.lastModify), "yyyy-MM-dd")
|
||||
llInfo.isGone = item.isDir
|
||||
tvContentType.isGone = item.isDir
|
||||
btnDownload.isGone = item.isDir
|
||||
if (payloads.isEmpty()) {
|
||||
if (item.isDir) {
|
||||
ivIcon.setImageResource(R.drawable.ic_folder)
|
||||
ivIcon.visible()
|
||||
cbSelect.invisible()
|
||||
llBrief.gone()
|
||||
cbSelect.isChecked = false
|
||||
} else {
|
||||
if (item.isOnBookShelf) {
|
||||
ivIcon.setImageResource(R.drawable.ic_book_has)
|
||||
ivIcon.visible()
|
||||
cbSelect.invisible()
|
||||
} else {
|
||||
ivIcon.invisible()
|
||||
cbSelect.visible()
|
||||
}
|
||||
llBrief.visible()
|
||||
tvTag.text = item.contentType
|
||||
tvSize.text = ConvertUtils.formatFileSize(item.size)
|
||||
tvDate.text = AppConst.dateFormat.format(item.lastModify)
|
||||
cbSelect.isChecked = selected.contains(item)
|
||||
}
|
||||
tvName.text = item.filename
|
||||
} else {
|
||||
cbSelect.isChecked = selected.contains(item)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun registerListener(holder: ItemViewHolder, binding: ItemRemoteBookBinding) {
|
||||
binding.root.setOnClickListener {
|
||||
override fun registerListener(holder: ItemViewHolder, binding: ItemImportBookBinding) {
|
||||
holder.itemView.setOnClickListener {
|
||||
getItem(holder.layoutPosition)?.let {
|
||||
if (it.isDir) {
|
||||
callBack.openDir(it)
|
||||
} else if (!it.isOnBookShelf) {
|
||||
if (!selected.contains(it)) {
|
||||
selected.add(it)
|
||||
} else {
|
||||
selected.remove(it)
|
||||
}
|
||||
notifyItemChanged(holder.layoutPosition, true)
|
||||
callBack.upCountView()
|
||||
}
|
||||
}
|
||||
}
|
||||
binding.btnDownload.setOnClickListener {
|
||||
getItem(holder.layoutPosition)?.let {
|
||||
callBack.addToBookshelf(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun upCheckableCount() {
|
||||
checkableCount = 0
|
||||
getItems().forEach {
|
||||
if (!it.isDir && !it.isOnBookShelf) {
|
||||
checkableCount++
|
||||
}
|
||||
}
|
||||
callBack.upCountView()
|
||||
}
|
||||
|
||||
@SuppressLint("NotifyDataSetChanged")
|
||||
fun selectAll(selectAll: Boolean) {
|
||||
if (selectAll) {
|
||||
getItems().forEach {
|
||||
if (!it.isDir && !it.isOnBookShelf) {
|
||||
selected.add(it)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
selected.clear()
|
||||
}
|
||||
notifyDataSetChanged()
|
||||
callBack.upCountView()
|
||||
}
|
||||
|
||||
fun revertSelection() {
|
||||
getItems().forEach {
|
||||
if (!it.isDir) {
|
||||
if (selected.contains(it)) {
|
||||
selected.remove(it)
|
||||
} else {
|
||||
selected.add(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
callBack.upCountView()
|
||||
}
|
||||
|
||||
fun removeSelection() {
|
||||
for (i in getItems().lastIndex downTo 0) {
|
||||
if (getItem(i) in selected) {
|
||||
removeItem(i)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
interface CallBack {
|
||||
fun openDir(remoteBook: RemoteBook)
|
||||
fun addToBookshelf(remoteBook: RemoteBook)
|
||||
fun upCountView()
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,8 @@
|
||||
package io.legado.app.ui.book.remote
|
||||
|
||||
import android.app.Application
|
||||
import android.net.Uri
|
||||
import io.legado.app.base.BaseViewModel
|
||||
import io.legado.app.constant.AppLog
|
||||
import io.legado.app.model.localBook.LocalBook
|
||||
import io.legado.app.ui.book.remote.manager.RemoteBookWebDav
|
||||
import io.legado.app.utils.toastOnUi
|
||||
@@ -62,33 +62,23 @@ class RemoteBookViewModel(application: Application): BaseViewModel(application){
|
||||
}
|
||||
}
|
||||
|
||||
fun addToBookshelf(uriList: HashSet<String>, finally: () -> Unit) {
|
||||
fun addToBookshelf(remoteBooks: HashSet<RemoteBook>, finally: () -> Unit) {
|
||||
execute {
|
||||
uriList.forEach {
|
||||
LocalBook.importFile(Uri.parse(it))
|
||||
remoteBooks.forEach { remoteBook ->
|
||||
val downloadBookPath = RemoteBookWebDav.getRemoteBook(remoteBook)
|
||||
downloadBookPath?.let {
|
||||
LocalBook.importFile(it)
|
||||
remoteBook.isOnBookShelf = true
|
||||
}
|
||||
}
|
||||
}.onError {
|
||||
AppLog.put("导入出错\n${it.localizedMessage}", it)
|
||||
context.toastOnUi("导入出错\n${it.localizedMessage}")
|
||||
}.onFinally {
|
||||
finally.invoke()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加书籍到本地书架
|
||||
*/
|
||||
fun addToBookshelf(remoteBook: RemoteBook, success: () -> Unit, finally: () -> Unit) {
|
||||
execute {
|
||||
val downloadBookPath = RemoteBookWebDav.getRemoteBook(remoteBook)
|
||||
downloadBookPath?.let {
|
||||
LocalBook.importFile(it)
|
||||
}
|
||||
}.onSuccess {
|
||||
success.invoke()
|
||||
}.onError {
|
||||
context.toastOnUi(it.localizedMessage)
|
||||
}.onFinally {
|
||||
finally.invoke()
|
||||
}
|
||||
}
|
||||
interface DataCallback {
|
||||
|
||||
fun setItems(remoteFiles: List<RemoteBook>)
|
||||
|
||||
@@ -108,7 +108,10 @@ object RemoteBookWebDav : RemoteBookManager() {
|
||||
}
|
||||
|
||||
override suspend fun delete(remoteBookUrl: String): Boolean {
|
||||
TODO("Not yet implemented")
|
||||
AppWebDav.authorization?.let {
|
||||
return WebDav(remoteBookUrl, it).delete()
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user