feat: 下载功能初步完成
This commit is contained in:
@@ -29,10 +29,13 @@ class RemoteBookActivity : VMBaseActivity<ActivityRemoteBookBinding,RemoteBookVi
|
|||||||
|
|
||||||
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
||||||
initView()
|
initView()
|
||||||
|
// initEvent()
|
||||||
initData()
|
initData()
|
||||||
// toastOnUi("远程书籍")
|
// toastOnUi("远程书籍")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
private fun initView() {
|
private fun initView() {
|
||||||
binding.recyclerView.layoutManager = LinearLayoutManager(this)
|
binding.recyclerView.layoutManager = LinearLayoutManager(this)
|
||||||
binding.recyclerView.adapter = adapter
|
binding.recyclerView.adapter = adapter
|
||||||
@@ -48,20 +51,21 @@ class RemoteBookActivity : VMBaseActivity<ActivityRemoteBookBinding,RemoteBookVi
|
|||||||
// viewModel.getRemoteBooks().observe(this, {
|
// viewModel.getRemoteBooks().observe(this, {
|
||||||
// adapter.submitList(it)
|
// adapter.submitList(it)
|
||||||
// })
|
// })
|
||||||
|
viewModel.loadRemoteBookList()
|
||||||
|
|
||||||
launch {
|
launch {
|
||||||
Log.e("TAG", "2")
|
viewModel.dataFlow.collect { remoteBooks ->
|
||||||
viewModel.dataFlow.conflate().collect { remoteBooks ->
|
|
||||||
adapter.setItems(remoteBooks)
|
adapter.setItems(remoteBooks)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// toastOnUi("1")
|
// toastOnUi("1")
|
||||||
viewModel.loadRemoteBookList()
|
|
||||||
}
|
}
|
||||||
override fun showRemoteBookInfo(book: Book) {
|
|
||||||
TODO("Not yet implemented")
|
|
||||||
|
override fun download(remoteBook: RemoteBook) {
|
||||||
|
viewModel.downloadRemoteBook(remoteBook.url)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2,14 +2,23 @@ package io.legado.app.ui.book.remote
|
|||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
|
import cn.hutool.core.date.LocalDateTimeUtil
|
||||||
import io.legado.app.base.adapter.ItemViewHolder
|
import io.legado.app.base.adapter.ItemViewHolder
|
||||||
import io.legado.app.base.adapter.RecyclerAdapter
|
import io.legado.app.base.adapter.RecyclerAdapter
|
||||||
import io.legado.app.data.entities.Book
|
import io.legado.app.data.entities.Book
|
||||||
import io.legado.app.databinding.ItemRemoteBookBinding
|
import io.legado.app.databinding.ItemRemoteBookBinding
|
||||||
|
import io.legado.app.utils.ConvertUtils
|
||||||
|
import io.legado.app.utils.FileUtils
|
||||||
|
import io.legado.app.utils.toastOnUi
|
||||||
|
import splitties.init.appCtx
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 适配器
|
||||||
|
* @author qianfanguojin
|
||||||
|
*/
|
||||||
class RemoteBookAdapter (context: Context, val callBack: CallBack) :
|
class RemoteBookAdapter (context: Context, val callBack: CallBack) :
|
||||||
RecyclerAdapter<String, ItemRemoteBookBinding>(context){
|
RecyclerAdapter<RemoteBook, ItemRemoteBookBinding>(context){
|
||||||
|
|
||||||
override fun getViewBinding(parent: ViewGroup): ItemRemoteBookBinding {
|
override fun getViewBinding(parent: ViewGroup): ItemRemoteBookBinding {
|
||||||
return ItemRemoteBookBinding.inflate(inflater, parent, false)
|
return ItemRemoteBookBinding.inflate(inflater, parent, false)
|
||||||
@@ -25,19 +34,29 @@ class RemoteBookAdapter (context: Context, val callBack: CallBack) :
|
|||||||
override fun convert(
|
override fun convert(
|
||||||
holder: ItemViewHolder,
|
holder: ItemViewHolder,
|
||||||
binding: ItemRemoteBookBinding,
|
binding: ItemRemoteBookBinding,
|
||||||
item: String,
|
item: RemoteBook,
|
||||||
payloads: MutableList<Any>
|
payloads: MutableList<Any>
|
||||||
) {
|
) {
|
||||||
binding.run {
|
binding.run {
|
||||||
tvName.text = item
|
tvName.text = item.name.substringBeforeLast(".")
|
||||||
|
tvContentType.text = item.name.substringAfterLast(".")
|
||||||
|
tvSize.text = ConvertUtils.formatFileSize(item.size)
|
||||||
|
tvDate.text = LocalDateTimeUtil.format(LocalDateTimeUtil.of(item.lastModify), "yyyy-MM-dd")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun registerListener(holder: ItemViewHolder, binding: ItemRemoteBookBinding) {
|
override fun registerListener(holder: ItemViewHolder, binding: ItemRemoteBookBinding) {
|
||||||
|
binding.btnDownload.setOnClickListener {
|
||||||
|
getItem(holder.layoutPosition)?.let {
|
||||||
|
context.toastOnUi("开始下载")
|
||||||
|
callBack.download(it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
interface CallBack {
|
interface CallBack {
|
||||||
fun showRemoteBookInfo(book: Book)
|
fun download(remoteBook: RemoteBook)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2,36 +2,43 @@ package io.legado.app.ui.book.remote
|
|||||||
|
|
||||||
import android.app.Application
|
import android.app.Application
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import android.widget.Toast
|
|
||||||
import io.legado.app.base.BaseViewModel
|
import io.legado.app.base.BaseViewModel
|
||||||
import io.legado.app.utils.FileDoc
|
import io.legado.app.constant.PreferKey
|
||||||
import kotlinx.coroutines.Dispatchers
|
import io.legado.app.lib.webdav.Authorization
|
||||||
|
import io.legado.app.lib.webdav.WebDav
|
||||||
|
import io.legado.app.utils.FileUtils
|
||||||
|
import io.legado.app.utils.exists
|
||||||
|
import io.legado.app.utils.externalFiles
|
||||||
|
import io.legado.app.utils.getPrefString
|
||||||
|
import kotlinx.coroutines.*
|
||||||
import kotlinx.coroutines.channels.awaitClose
|
import kotlinx.coroutines.channels.awaitClose
|
||||||
import kotlinx.coroutines.flow.callbackFlow
|
import kotlinx.coroutines.flow.callbackFlow
|
||||||
import kotlinx.coroutines.flow.flowOn
|
import kotlinx.coroutines.flow.flowOn
|
||||||
import kotlinx.coroutines.flow.map
|
import splitties.init.appCtx
|
||||||
import kotlinx.coroutines.withContext
|
import java.io.File
|
||||||
|
import java.nio.charset.Charset
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import kotlin.reflect.typeOf
|
|
||||||
|
|
||||||
class RemoteBookViewModel(application: Application): BaseViewModel(application){
|
class RemoteBookViewModel(application: Application): BaseViewModel(application){
|
||||||
|
private val remoteBookFolderName = "book_remote"
|
||||||
private var dataCallback : DataCallback? = null
|
private var dataCallback : DataCallback? = null
|
||||||
var dataFlowStart: (() -> Unit)? = null
|
var dataFlowStart: (() -> Unit)? = null
|
||||||
val dataFlow = callbackFlow<List<String>> {
|
private var authorization: Authorization? = null
|
||||||
|
|
||||||
val list = Collections.synchronizedList(ArrayList<String>())
|
|
||||||
|
val dataFlow = callbackFlow<List<RemoteBook>> {
|
||||||
|
|
||||||
|
val list = Collections.synchronizedList(ArrayList<RemoteBook>())
|
||||||
|
|
||||||
dataCallback = object : DataCallback {
|
dataCallback = object : DataCallback {
|
||||||
|
|
||||||
override fun setItems(remoteFiles: List<String>) {
|
override fun setItems(remoteFiles: List<RemoteBook>) {
|
||||||
list.clear()
|
list.clear()
|
||||||
list.addAll(remoteFiles)
|
list.addAll(remoteFiles)
|
||||||
Log.e("TAG", ": 1", )
|
|
||||||
trySend(list)
|
trySend(list)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun addItems(remoteFiles: List<String>) {
|
override fun addItems(remoteFiles: List<RemoteBook>) {
|
||||||
list.addAll(remoteFiles)
|
list.addAll(remoteFiles)
|
||||||
trySend(list)
|
trySend(list)
|
||||||
}
|
}
|
||||||
@@ -41,28 +48,88 @@ class RemoteBookViewModel(application: Application): BaseViewModel(application){
|
|||||||
trySend(emptyList())
|
trySend(emptyList())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// withContext(Dispatchers.Main) {
|
// withContext(Dispatchers.Main) {
|
||||||
// dataFlowStart?.invoke()
|
// dataFlowStart?.invoke()
|
||||||
// }
|
// }
|
||||||
|
|
||||||
awaitClose {
|
awaitClose {
|
||||||
dataCallback = null
|
// dataCallback = null
|
||||||
}
|
}
|
||||||
}.flowOn(Dispatchers.Main)
|
}.flowOn(Dispatchers.IO)
|
||||||
|
|
||||||
fun loadRemoteBookList() {
|
fun loadRemoteBookList() {
|
||||||
Log.e("TAG", dataCallback.toString(), )
|
execute {
|
||||||
dataCallback?.setItems(listOf("1", "2", "3"))
|
dataCallback?.clear()
|
||||||
|
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 ->
|
||||||
|
val remoteWebDavFileList = WebDav("http://txc.qianfanguojin.top/",it).listFiles()
|
||||||
|
val remoteList = remoteWebDavFileList.map {
|
||||||
|
RemoteBook(it.displayName,it.urlName,it.size,"epub",it.lastModify)
|
||||||
|
}
|
||||||
|
dataCallback?.setItems(remoteList)
|
||||||
|
}
|
||||||
|
// dataCallback?.setItems()
|
||||||
|
}
|
||||||
|
// dataCallback?.setItems(listOf("1", "2", "3"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun downloadRemoteBook(urlName: String) {
|
||||||
|
execute {
|
||||||
|
// kotlin.runCatching {
|
||||||
|
// val remoteWebDavFile = WebDav("http://txc.qianfanguojin.top/",authorization!!).getFile(url)
|
||||||
|
// val remoteBook = RemoteBook(remoteWebDavFile.displayName,remoteWebDavFile.urlName,remoteWebDavFile.size,"epub",remoteWebDavFile.lastModify)
|
||||||
|
// dataCallback?.addItems(listOf(remoteBook))
|
||||||
|
// }
|
||||||
|
|
||||||
|
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 ->
|
||||||
|
Log.e("TAG", "downloadRemoteBook: 1", )
|
||||||
|
val saveFolder = "${appCtx.externalFiles.absolutePath}${File.separator}${remoteBookFolderName}"
|
||||||
|
FileUtils.createFolderIfNotExist(saveFolder).run{
|
||||||
|
|
||||||
|
// Log.e("TAG", "downloadRemoteBook: 2 ${appCtx.externalFiles.absoluteFile}", )
|
||||||
|
val trueCodeURLName = String(urlName.toByteArray(Charset.forName("GBK")), Charset.forName("UTF-8"))
|
||||||
|
withTimeout(15000L) {
|
||||||
|
val webdav = WebDav("http://txc.qianfanguojin.top${trueCodeURLName}", it)
|
||||||
|
webdav.downloadTo("${saveFolder}${trueCodeURLName}", true).apply {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
interface DataCallback {
|
interface DataCallback {
|
||||||
|
|
||||||
fun setItems(remoteFiles: List<String>)
|
fun setItems(remoteFiles: List<RemoteBook>)
|
||||||
|
|
||||||
fun addItems(remoteFiles: List<String>)
|
fun addItems(remoteFiles: List<RemoteBook>)
|
||||||
|
|
||||||
fun clear()
|
fun clear()
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
data class RemoteBook(
|
||||||
|
val name: String,
|
||||||
|
val url: String,
|
||||||
|
val size: Long,
|
||||||
|
val contentType: String,
|
||||||
|
val lastModify: Long
|
||||||
|
)
|
||||||
@@ -36,9 +36,11 @@
|
|||||||
|
|
||||||
</io.legado.app.ui.widget.dynamiclayout.DynamicFrameLayout>
|
</io.legado.app.ui.widget.dynamiclayout.DynamicFrameLayout>
|
||||||
|
|
||||||
<io.legado.app.ui.widget.SelectActionBar
|
<!-- <io.legado.app.ui.widget.SelectActionBar-->
|
||||||
android:id="@+id/select_action_bar"
|
<!-- android:id="@+id/select_action_bar"-->
|
||||||
android:layout_width="match_parent"
|
<!-- android:layout_width="match_parent"-->
|
||||||
android:layout_height="wrap_content"
|
<!-- android:layout_height="wrap_content"-->
|
||||||
app:layout_constraintBottom_toBottomOf="parent" />
|
<!-- app:layout_constraintBottom_toBottomOf="parent"-->
|
||||||
|
<!-- app:layout_constraintTop_toBottomOf="@id/content_view"-->
|
||||||
|
<!-- />-->
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
@@ -55,7 +55,7 @@
|
|||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:ellipsize="end"
|
android:ellipsize="end"
|
||||||
android:lines="1"
|
android:lines="1"
|
||||||
tools:text="\u4e28"
|
android:text="\u4e28"
|
||||||
android:textColor="@color/tv_text_summary"
|
android:textColor="@color/tv_text_summary"
|
||||||
android:textSize="11sp" />
|
android:textSize="11sp" />
|
||||||
|
|
||||||
@@ -96,10 +96,9 @@
|
|||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
android:layout_marginTop="3dp"
|
android:layout_marginTop="3dp"
|
||||||
android:id="@+id/tv_download"
|
|
||||||
>
|
>
|
||||||
<Button
|
<Button
|
||||||
android:id="@+id/tv_download1"
|
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="下载"
|
||||||
|
|||||||
Reference in New Issue
Block a user