feat: 下载功能初步完成

pull/1894/head
谢意帆 3 years ago
parent b84db00367
commit 3f1c95b7be
  1. 16
      app/src/main/java/io/legado/app/ui/book/remote/RemoteBookActivity.kt
  2. 27
      app/src/main/java/io/legado/app/ui/book/remote/RemoteBookAdapter.kt
  3. 107
      app/src/main/java/io/legado/app/ui/book/remote/RemoteBookViewModel.kt
  4. 12
      app/src/main/res/layout/activity_remote_book.xml
  5. 5
      app/src/main/res/layout/item_remote_book.xml

@ -29,10 +29,13 @@ class RemoteBookActivity : VMBaseActivity<ActivityRemoteBookBinding,RemoteBookVi
override fun onActivityCreated(savedInstanceState: Bundle?) {
initView()
// initEvent()
initData()
// toastOnUi("远程书籍")
}
private fun initView() {
binding.recyclerView.layoutManager = LinearLayoutManager(this)
binding.recyclerView.adapter = adapter
@ -48,20 +51,21 @@ class RemoteBookActivity : VMBaseActivity<ActivityRemoteBookBinding,RemoteBookVi
// viewModel.getRemoteBooks().observe(this, {
// adapter.submitList(it)
// })
viewModel.loadRemoteBookList()
launch {
Log.e("TAG", "2")
viewModel.dataFlow.conflate().collect { remoteBooks ->
viewModel.dataFlow.collect { remoteBooks ->
adapter.setItems(remoteBooks)
}
}
// 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.view.ViewGroup
import cn.hutool.core.date.LocalDateTimeUtil
import io.legado.app.base.adapter.ItemViewHolder
import io.legado.app.base.adapter.RecyclerAdapter
import io.legado.app.data.entities.Book
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) :
RecyclerAdapter<String, ItemRemoteBookBinding>(context){
RecyclerAdapter<RemoteBook, ItemRemoteBookBinding>(context){
override fun getViewBinding(parent: ViewGroup): ItemRemoteBookBinding {
return ItemRemoteBookBinding.inflate(inflater, parent, false)
@ -25,19 +34,29 @@ class RemoteBookAdapter (context: Context, val callBack: CallBack) :
override fun convert(
holder: ItemViewHolder,
binding: ItemRemoteBookBinding,
item: String,
item: RemoteBook,
payloads: MutableList<Any>
) {
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) {
binding.btnDownload.setOnClickListener {
getItem(holder.layoutPosition)?.let {
context.toastOnUi("开始下载")
callBack.download(it)
}
}
}
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.util.Log
import android.widget.Toast
import io.legado.app.base.BaseViewModel
import io.legado.app.utils.FileDoc
import kotlinx.coroutines.Dispatchers
import io.legado.app.constant.PreferKey
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.flow.callbackFlow
import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.withContext
import splitties.init.appCtx
import java.io.File
import java.nio.charset.Charset
import java.util.*
import kotlin.reflect.typeOf
class RemoteBookViewModel(application: Application): BaseViewModel(application){
private val remoteBookFolderName = "book_remote"
private var dataCallback : DataCallback? = null
var dataFlowStart: (() -> Unit)? = null
val dataFlow = callbackFlow<List<String>> {
private var authorization: Authorization? = null
val dataFlow = callbackFlow<List<RemoteBook>> {
val list = Collections.synchronizedList(ArrayList<String>())
val list = Collections.synchronizedList(ArrayList<RemoteBook>())
dataCallback = object : DataCallback {
override fun setItems(remoteFiles: List<String>) {
override fun setItems(remoteFiles: List<RemoteBook>) {
list.clear()
list.addAll(remoteFiles)
Log.e("TAG", ": 1", )
trySend(list)
}
override fun addItems(remoteFiles: List<String>) {
override fun addItems(remoteFiles: List<RemoteBook>) {
list.addAll(remoteFiles)
trySend(list)
}
@ -41,28 +48,88 @@ class RemoteBookViewModel(application: Application): BaseViewModel(application){
trySend(emptyList())
}
}
// withContext(Dispatchers.Main) {
// dataFlowStart?.invoke()
// }
awaitClose {
dataCallback = null
// dataCallback = null
}
}.flowOn(Dispatchers.Main)
}.flowOn(Dispatchers.IO)
fun loadRemoteBookList() {
Log.e("TAG", dataCallback.toString(), )
dataCallback?.setItems(listOf("1", "2", "3"))
execute {
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 {
fun setItems(remoteFiles: List<String>)
fun setItems(remoteFiles: List<RemoteBook>)
fun addItems(remoteFiles: List<String>)
fun addItems(remoteFiles: List<RemoteBook>)
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.SelectActionBar
android:id="@+id/select_action_bar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent" />
<!-- <io.legado.app.ui.widget.SelectActionBar-->
<!-- android:id="@+id/select_action_bar"-->
<!-- android:layout_width="match_parent"-->
<!-- android:layout_height="wrap_content"-->
<!-- app:layout_constraintBottom_toBottomOf="parent"-->
<!-- app:layout_constraintTop_toBottomOf="@id/content_view"-->
<!-- />-->
</androidx.constraintlayout.widget.ConstraintLayout>

@ -55,7 +55,7 @@
android:layout_height="wrap_content"
android:ellipsize="end"
android:lines="1"
tools:text="\u4e28"
android:text="\u4e28"
android:textColor="@color/tv_text_summary"
android:textSize="11sp" />
@ -96,10 +96,9 @@
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:layout_marginTop="3dp"
android:id="@+id/tv_download"
>
<Button
android:id="@+id/tv_download1"
android:id="@+id/btn_download"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="下载"

Loading…
Cancel
Save