fix: 修复上传以及下载的部分BUG,功能已经基本可用
This commit is contained in:
@@ -1,5 +1,6 @@
|
|||||||
package io.legado.app.ui.book.remote
|
package io.legado.app.ui.book.remote
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import androidx.activity.viewModels
|
import androidx.activity.viewModels
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
@@ -46,8 +47,8 @@ class RemoteBookActivity : VMBaseActivity<ActivityRemoteBookBinding,RemoteBookVi
|
|||||||
// viewModel.getRemoteBooks().observe(this, {
|
// viewModel.getRemoteBooks().observe(this, {
|
||||||
// adapter.submitList(it)
|
// adapter.submitList(it)
|
||||||
// })
|
// })
|
||||||
// viewModel.loadRemoteBookList()
|
binding.refreshProgressBar.isAutoLoading = true
|
||||||
|
viewModel.loadRemoteBookList()
|
||||||
launch {
|
launch {
|
||||||
viewModel.dataFlow.collect { remoteBooks ->
|
viewModel.dataFlow.collect { remoteBooks ->
|
||||||
adapter.setItems(remoteBooks)
|
adapter.setItems(remoteBooks)
|
||||||
@@ -60,7 +61,10 @@ class RemoteBookActivity : VMBaseActivity<ActivityRemoteBookBinding,RemoteBookVi
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
override fun download(remoteBook: RemoteBook) {
|
@SuppressLint("NotifyDataSetChanged")
|
||||||
viewModel.downloadRemoteBook(remoteBook.urlName)
|
override fun addToBookshelf(remoteBook: RemoteBook) {
|
||||||
|
viewModel.addToBookshelf(remoteBook){
|
||||||
|
adapter.notifyDataSetChanged()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -38,7 +38,7 @@ class RemoteBookAdapter (context: Context, val callBack: CallBack) :
|
|||||||
payloads: MutableList<Any>
|
payloads: MutableList<Any>
|
||||||
) {
|
) {
|
||||||
binding.run {
|
binding.run {
|
||||||
tvName.text = item.filename
|
tvName.text = item.filename.substringBeforeLast(".")
|
||||||
tvContentType.text = item.contentType
|
tvContentType.text = item.contentType
|
||||||
tvSize.text = ConvertUtils.formatFileSize(item.size)
|
tvSize.text = ConvertUtils.formatFileSize(item.size)
|
||||||
tvDate.text = LocalDateTimeUtil.format(LocalDateTimeUtil.of(item.lastModify), "yyyy-MM-dd")
|
tvDate.text = LocalDateTimeUtil.format(LocalDateTimeUtil.of(item.lastModify), "yyyy-MM-dd")
|
||||||
@@ -48,8 +48,9 @@ class RemoteBookAdapter (context: Context, val callBack: CallBack) :
|
|||||||
override fun registerListener(holder: ItemViewHolder, binding: ItemRemoteBookBinding) {
|
override fun registerListener(holder: ItemViewHolder, binding: ItemRemoteBookBinding) {
|
||||||
binding.btnDownload.setOnClickListener {
|
binding.btnDownload.setOnClickListener {
|
||||||
getItem(holder.layoutPosition)?.let {
|
getItem(holder.layoutPosition)?.let {
|
||||||
context.toastOnUi("开始下载")
|
context.toastOnUi("开始加入")
|
||||||
callBack.download(it)
|
callBack.addToBookshelf(it)
|
||||||
|
context.toastOnUi("加入成功")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -57,6 +58,6 @@ class RemoteBookAdapter (context: Context, val callBack: CallBack) :
|
|||||||
}
|
}
|
||||||
|
|
||||||
interface CallBack {
|
interface CallBack {
|
||||||
fun download(remoteBook: RemoteBook)
|
fun addToBookshelf(remoteBook: RemoteBook)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,13 +1,7 @@
|
|||||||
package io.legado.app.ui.book.remote
|
package io.legado.app.ui.book.remote
|
||||||
|
|
||||||
import android.content.ContentResolver
|
|
||||||
import android.database.Cursor
|
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import android.provider.MediaStore
|
|
||||||
import android.provider.OpenableColumns
|
|
||||||
import android.webkit.MimeTypeMap
|
|
||||||
import java.io.File
|
|
||||||
import kotlin.random.Random
|
|
||||||
|
|
||||||
|
|
||||||
abstract class RemoteBookManager {
|
abstract class RemoteBookManager {
|
||||||
@@ -17,5 +11,9 @@ abstract class RemoteBookManager {
|
|||||||
abstract suspend fun getRemoteBookList(): MutableList<RemoteBook>
|
abstract suspend fun getRemoteBookList(): MutableList<RemoteBook>
|
||||||
abstract suspend fun upload(localBookUri: Uri): Boolean
|
abstract suspend fun upload(localBookUri: Uri): Boolean
|
||||||
abstract suspend fun delete(remoteBookUrl: String): Boolean
|
abstract suspend fun delete(remoteBookUrl: String): Boolean
|
||||||
abstract suspend fun getRemoteBook(remoteBookUrl: String): RemoteBook
|
|
||||||
|
/**
|
||||||
|
* @return String:下载到本地的路径
|
||||||
|
*/
|
||||||
|
abstract suspend fun getRemoteBook(remoteBook: RemoteBook): String?
|
||||||
}
|
}
|
||||||
@@ -55,53 +55,20 @@ class RemoteBookViewModel(application: Application): BaseViewModel(application){
|
|||||||
// }
|
// }
|
||||||
|
|
||||||
awaitClose {
|
awaitClose {
|
||||||
// dataCallback = null
|
dataCallback = null
|
||||||
}
|
}
|
||||||
}.flowOn(Dispatchers.IO)
|
}.flowOn(Dispatchers.IO)
|
||||||
|
|
||||||
fun loadRemoteBookList() {
|
fun loadRemoteBookList() {
|
||||||
execute {
|
execute {
|
||||||
dataCallback?.clear()
|
dataCallback?.clear()
|
||||||
RemoteBookWebDav.getRemoteBookList()
|
val bookList = RemoteBookWebDav.getRemoteBookList()
|
||||||
|
dataCallback?.setItems(bookList)
|
||||||
}
|
}
|
||||||
// dataCallback?.setItems()
|
|
||||||
}
|
|
||||||
// dataCallback?.setItems(listOf("1", "2", "3"))
|
|
||||||
|
|
||||||
|
|
||||||
fun downloadRemoteBook(urlName: String) {
|
|
||||||
val saveFolder = "${appCtx.externalFiles.absolutePath}${File.separator}${remoteBookFolderName}"
|
|
||||||
val trueCodeURLName = String(urlName.toByteArray(Charset.forName("GBK")), Charset.forName("UTF-8"))
|
|
||||||
val saveFilePath = "${saveFolder}${trueCodeURLName}"
|
|
||||||
execute {
|
|
||||||
kotlin.runCatching {
|
|
||||||
authorization = null
|
|
||||||
val account = appCtx.getPrefString(PreferKey.webDavAccount)
|
|
||||||
val password = appCtx.getPrefString(PreferKey.webDavPassword)
|
|
||||||
if (!account.isNullOrBlank() && !password.isNullOrBlank()) {
|
|
||||||
val mAuthorization = Authorization(account, password)
|
|
||||||
authorization = mAuthorization
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
authorization?.let { it ->
|
|
||||||
FileUtils.createFolderIfNotExist(saveFolder).run{
|
|
||||||
withTimeout(15000L) {
|
|
||||||
val webdav = WebDav(
|
|
||||||
"http://txc.qianfanguojin.top${trueCodeURLName}",
|
|
||||||
it
|
|
||||||
)
|
|
||||||
webdav.downloadTo(saveFilePath, true)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}.onFinally {
|
|
||||||
addToBookshelf(hashSetOf("${saveFolder}${trueCodeURLName}")){
|
|
||||||
Log.e("TAG", "downloadRemoteBook: add", )
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
fun addToBookshelf(uriList: HashSet<String>, finally: () -> Unit) {
|
fun addToBookshelf(uriList: HashSet<String>, finally: () -> Unit) {
|
||||||
execute {
|
execute {
|
||||||
uriList.forEach {
|
uriList.forEach {
|
||||||
@@ -111,6 +78,20 @@ class RemoteBookViewModel(application: Application): BaseViewModel(application){
|
|||||||
finally.invoke()
|
finally.invoke()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 添加书籍到本地书架
|
||||||
|
*/
|
||||||
|
fun addToBookshelf(remoteBook: RemoteBook, finally: () -> Unit) {
|
||||||
|
execute {
|
||||||
|
val downloadBookPath = RemoteBookWebDav.getRemoteBook(remoteBook)
|
||||||
|
downloadBookPath?.let {
|
||||||
|
LocalBook.importFile(Uri.parse(it))
|
||||||
|
}
|
||||||
|
}.onFinally {
|
||||||
|
finally.invoke()
|
||||||
|
}
|
||||||
|
}
|
||||||
interface DataCallback {
|
interface DataCallback {
|
||||||
|
|
||||||
fun setItems(remoteFiles: List<RemoteBook>)
|
fun setItems(remoteFiles: List<RemoteBook>)
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import io.legado.app.help.config.AppConfig
|
|||||||
|
|
||||||
import io.legado.app.lib.webdav.Authorization
|
import io.legado.app.lib.webdav.Authorization
|
||||||
import io.legado.app.lib.webdav.WebDav
|
import io.legado.app.lib.webdav.WebDav
|
||||||
|
import io.legado.app.lib.webdav.WebDavException
|
||||||
import io.legado.app.lib.webdav.WebDavFile
|
import io.legado.app.lib.webdav.WebDavFile
|
||||||
import io.legado.app.ui.book.info.BookInfoActivity
|
import io.legado.app.ui.book.info.BookInfoActivity
|
||||||
|
|
||||||
@@ -16,6 +17,7 @@ import io.legado.app.ui.book.remote.RemoteBook
|
|||||||
import io.legado.app.ui.book.remote.RemoteBookManager
|
import io.legado.app.ui.book.remote.RemoteBookManager
|
||||||
import io.legado.app.utils.*
|
import io.legado.app.utils.*
|
||||||
import kotlinx.coroutines.runBlocking
|
import kotlinx.coroutines.runBlocking
|
||||||
|
import kotlinx.coroutines.withTimeout
|
||||||
import splitties.init.appCtx
|
import splitties.init.appCtx
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.nio.charset.Charset
|
import java.nio.charset.Charset
|
||||||
@@ -24,7 +26,7 @@ object RemoteBookWebDav : RemoteBookManager() {
|
|||||||
private const val defaultWebDavUrl = "https://dav.jianguoyun.com/dav/"
|
private const val defaultWebDavUrl = "https://dav.jianguoyun.com/dav/"
|
||||||
private var authorization: Authorization? = null
|
private var authorization: Authorization? = null
|
||||||
private val remoteBookUrl get() = "${rootWebDavUrl}${remoteBookFolder}"
|
private val remoteBookUrl get() = "${rootWebDavUrl}${remoteBookFolder}"
|
||||||
|
private val localSaveFolder get() = "${appCtx.externalFiles.absolutePath}${File.separator}${remoteBookFolder}"
|
||||||
init {
|
init {
|
||||||
runBlocking {
|
runBlocking {
|
||||||
initRemoteContext()
|
initRemoteContext()
|
||||||
@@ -63,38 +65,52 @@ object RemoteBookWebDav : RemoteBookManager() {
|
|||||||
@Throws(Exception::class)
|
@Throws(Exception::class)
|
||||||
override suspend fun getRemoteBookList(): MutableList<RemoteBook> {
|
override suspend fun getRemoteBookList(): MutableList<RemoteBook> {
|
||||||
val remoteBooks = mutableListOf<RemoteBook>()
|
val remoteBooks = mutableListOf<RemoteBook>()
|
||||||
|
|
||||||
authorization?.let {
|
authorization?.let {
|
||||||
|
//读取文件列表
|
||||||
var remoteWebDavFileList : List<WebDavFile>? = null
|
var remoteWebDavFileList : List<WebDavFile>? = null
|
||||||
kotlin.runCatching {
|
kotlin.runCatching {
|
||||||
remoteWebDavFileList = WebDav(remoteBookUrl, it).listFiles()
|
remoteWebDavFileList = WebDav(remoteBookUrl, it).listFiles()
|
||||||
}
|
}
|
||||||
|
//逆序文件排序
|
||||||
|
|
||||||
remoteWebDavFileList = remoteWebDavFileList!!.reversed()
|
remoteWebDavFileList = remoteWebDavFileList!!.reversed()
|
||||||
|
//转化远程文件信息到本地对象
|
||||||
remoteWebDavFileList!!.forEach { webDavFile ->
|
remoteWebDavFileList!!.forEach { webDavFile ->
|
||||||
val webDavFileName = webDavFile.displayName
|
val webDavFileName = webDavFile.displayName
|
||||||
val webDavUrlName = webDavFile.urlName
|
val webDavUrlName = "${remoteBookUrl}${File.separator}${webDavFile.displayName}"
|
||||||
|
|
||||||
// 转码
|
// 转码
|
||||||
val trueFileName = String(webDavFileName.toByteArray(Charset.forName("GBK")), Charset.forName("UTF-8"))
|
//val trueFileName = String(webDavFileName.toByteArray(Charset.forName("GBK")), Charset.forName("UTF-8"))
|
||||||
val trueUrlName = String(webDavUrlName.toByteArray(Charset.forName("GBK")), Charset.forName("UTF-8"))
|
//val trueUrlName = String(webDavUrlName.toByteArray(Charset.forName("GBK")), Charset.forName("UTF-8"))
|
||||||
|
|
||||||
//分割文件名和后缀
|
//分割后缀
|
||||||
val filename = trueFileName.substringBeforeLast(".")
|
val fileExtension = webDavFileName.substringAfterLast(".")
|
||||||
val fileExtension = trueFileName.substringAfterLast(".")
|
|
||||||
|
|
||||||
//扩展名符合阅读的格式则认为是书籍
|
//扩展名符合阅读的格式则认为是书籍
|
||||||
if (contentTypeList.contains(fileExtension)) {
|
if (contentTypeList.contains(fileExtension)) {
|
||||||
remoteBooks.add(RemoteBook(filename,trueUrlName,webDavFile.size,fileExtension,webDavFile.lastModify))
|
remoteBooks.add(RemoteBook(webDavFileName,webDavUrlName,webDavFile.size,fileExtension,webDavFile.lastModify))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} ?: throw NoStackTraceException("webDav没有配置")
|
} ?: throw NoStackTraceException("webDav没有配置")
|
||||||
return remoteBooks
|
return remoteBooks
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun getRemoteBook(remoteBookUrl: String): RemoteBook {
|
override suspend fun getRemoteBook(remoteBook: RemoteBook): String? {
|
||||||
TODO("Not yet implemented")
|
val saveFilePath= "${localSaveFolder}${File.separator}${remoteBook.filename}"
|
||||||
|
kotlin.runCatching {
|
||||||
|
authorization?.let {
|
||||||
|
FileUtils.createFolderIfNotExist(localSaveFolder).run{
|
||||||
|
val webdav = WebDav(
|
||||||
|
remoteBook.urlName,
|
||||||
|
it
|
||||||
|
)
|
||||||
|
webdav.downloadTo(saveFilePath, true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}.onFailure {
|
||||||
|
it.printStackTrace()
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
return saveFilePath
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -97,12 +97,12 @@
|
|||||||
app:layout_constraintTop_toTopOf="parent"
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
android:layout_marginTop="3dp"
|
android:layout_marginTop="3dp"
|
||||||
>
|
>
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
android:id="@+id/btn_download"
|
android:id="@+id/btn_download"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="下载"
|
android:text="加入书架">
|
||||||
>
|
|
||||||
|
|
||||||
</Button>
|
</Button>
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|||||||
Reference in New Issue
Block a user