pull/1994/head
kunfei 2 years ago
parent 6f4bb0f387
commit d62c757cc4
  1. 28
      app/src/main/java/io/legado/app/ui/book/local/ImportBookActivity.kt
  2. 4
      app/src/main/java/io/legado/app/ui/book/local/ImportBookAdapter.kt
  3. 2
      app/src/main/java/io/legado/app/ui/book/local/ImportBookViewModel.kt
  4. 2
      app/src/main/java/io/legado/app/ui/book/remote/RemoteBook.kt
  5. 88
      app/src/main/java/io/legado/app/ui/book/remote/RemoteBookActivity.kt
  6. 116
      app/src/main/java/io/legado/app/ui/book/remote/RemoteBookAdapter.kt
  7. 26
      app/src/main/java/io/legado/app/ui/book/remote/RemoteBookViewModel.kt
  8. 5
      app/src/main/java/io/legado/app/ui/book/remote/manager/RemoteBookWebDav.kt
  9. 3
      app/src/main/res/layout/activity_import_book.xml
  10. 67
      app/src/main/res/layout/activity_remote_book.xml
  11. 108
      app/src/main/res/layout/item_remote_book.xml

@ -41,8 +41,6 @@ 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 var rootDoc: FileDoc? = null
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 var scanDocJob: Job? = null
@ -59,6 +57,7 @@ class ImportBookActivity : VMBaseActivity<ActivityImportBookBinding, ImportBookV
} }
override fun onActivityCreated(savedInstanceState: Bundle?) { override fun onActivityCreated(savedInstanceState: Bundle?) {
binding.titleBar.setTitle(R.string.book_local)
initView() initView()
initEvent() initEvent()
initData() initData()
@ -148,6 +147,7 @@ class ImportBookActivity : VMBaseActivity<ActivityImportBookBinding, ImportBookV
private fun initRootDoc() { private fun initRootDoc() {
val lastPath = AppConfig.importBookPath val lastPath = AppConfig.importBookPath
when { when {
viewModel.rootDoc != null -> upPath()
lastPath.isNullOrEmpty() -> { lastPath.isNullOrEmpty() -> {
binding.tvEmptyMsg.visible() binding.tvEmptyMsg.visible()
selectFolder.launch() selectFolder.launch()
@ -160,9 +160,9 @@ class ImportBookActivity : VMBaseActivity<ActivityImportBookBinding, ImportBookV
binding.tvEmptyMsg.visible() binding.tvEmptyMsg.visible()
selectFolder.launch() selectFolder.launch()
} else { } else {
subDocs.clear() viewModel.subDocs.clear()
rootDoc = FileDoc.fromDocumentFile(doc) viewModel.rootDoc = FileDoc.fromDocumentFile(doc)
upDocs(rootDoc!!) upDocs(viewModel.rootDoc!!)
} }
}.onFailure { }.onFailure {
binding.tvEmptyMsg.visible() binding.tvEmptyMsg.visible()
@ -184,8 +184,8 @@ class ImportBookActivity : VMBaseActivity<ActivityImportBookBinding, ImportBookV
.rationale(R.string.tip_perm_request_storage) .rationale(R.string.tip_perm_request_storage)
.onGranted { .onGranted {
kotlin.runCatching { kotlin.runCatching {
rootDoc = FileDoc.fromFile(File(path)) viewModel.rootDoc = FileDoc.fromFile(File(path))
subDocs.clear() viewModel.subDocs.clear()
upPath() upPath()
}.onFailure { }.onFailure {
binding.tvEmptyMsg.visible() binding.tvEmptyMsg.visible()
@ -205,7 +205,7 @@ class ImportBookActivity : VMBaseActivity<ActivityImportBookBinding, ImportBookV
@Synchronized @Synchronized
private fun upPath() { private fun upPath() {
rootDoc?.let { viewModel.rootDoc?.let {
scanDocJob?.cancel() scanDocJob?.cancel()
upDocs(it) upDocs(it)
} }
@ -215,7 +215,7 @@ class ImportBookActivity : VMBaseActivity<ActivityImportBookBinding, ImportBookV
binding.tvEmptyMsg.gone() binding.tvEmptyMsg.gone()
var path = rootDoc.name + File.separator var path = rootDoc.name + File.separator
var lastDoc = rootDoc var lastDoc = rootDoc
for (doc in subDocs) { for (doc in viewModel.subDocs) {
lastDoc = doc lastDoc = doc
path = path + doc.name + File.separator path = path + doc.name + File.separator
} }
@ -229,9 +229,9 @@ class ImportBookActivity : VMBaseActivity<ActivityImportBookBinding, ImportBookV
* 扫描当前文件夹及所有子文件夹 * 扫描当前文件夹及所有子文件夹
*/ */
private fun scanFolder() { private fun scanFolder() {
rootDoc?.let { doc -> viewModel.rootDoc?.let { doc ->
adapter.clearItems() adapter.clearItems()
val lastDoc = subDocs.lastOrNull() ?: doc val lastDoc = viewModel.subDocs.lastOrNull() ?: doc
binding.refreshProgressBar.isAutoLoading = true binding.refreshProgressBar.isAutoLoading = true
scanDocJob?.cancel() scanDocJob?.cancel()
scanDocJob = launch(IO) { scanDocJob = launch(IO) {
@ -261,14 +261,14 @@ class ImportBookActivity : VMBaseActivity<ActivityImportBookBinding, ImportBookV
@Synchronized @Synchronized
override fun nextDoc(fileDoc: FileDoc) { override fun nextDoc(fileDoc: FileDoc) {
subDocs.add(fileDoc) viewModel.subDocs.add(fileDoc)
upPath() upPath()
} }
@Synchronized @Synchronized
private fun goBackDir(): Boolean { private fun goBackDir(): Boolean {
return if (subDocs.isNotEmpty()) { return if (viewModel.subDocs.isNotEmpty()) {
subDocs.removeAt(subDocs.lastIndex) viewModel.subDocs.removeAt(viewModel.subDocs.lastIndex)
upPath() upPath()
true true
} else { } else {

@ -14,9 +14,9 @@ import io.legado.app.utils.*
class ImportBookAdapter(context: Context, val callBack: CallBack) : class ImportBookAdapter(context: Context, val callBack: CallBack) :
RecyclerAdapter<FileDoc, ItemImportBookBinding>(context) { RecyclerAdapter<FileDoc, ItemImportBookBinding>(context) {
var selectedUris = hashSetOf<String>() val selectedUris = hashSetOf<String>()
var checkableCount = 0 var checkableCount = 0
private var bookFileNames = arrayListOf<String>() private val bookFileNames = arrayListOf<String>()
override fun getViewBinding(parent: ViewGroup): ItemImportBookBinding { override fun getViewBinding(parent: ViewGroup): ItemImportBookBinding {
return ItemImportBookBinding.inflate(inflater, parent, false) return ItemImportBookBinding.inflate(inflater, parent, false)

@ -21,6 +21,8 @@ import java.io.File
import java.util.* import java.util.*
class ImportBookViewModel(application: Application) : BaseViewModel(application) { class ImportBookViewModel(application: Application) : BaseViewModel(application) {
var rootDoc: FileDoc? = null
val subDocs = arrayListOf<FileDoc>()
var sort = context.getPrefInt(PreferKey.localBookImportSort) var sort = context.getPrefInt(PreferKey.localBookImportSort)
var dataCallback: DataCallback? = null var dataCallback: DataCallback? = null
var dataFlowStart: (() -> Unit)? = null var dataFlowStart: (() -> Unit)? = null

@ -6,7 +6,7 @@ data class RemoteBook(
val size: Long, val size: Long,
val contentType: String, val contentType: String,
val lastModify: Long, val lastModify: Long,
val isOnBookShelf: Boolean var isOnBookShelf: Boolean
) { ) {
val isDir by lazy { val isDir by lazy {

@ -1,6 +1,5 @@
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 android.view.Menu import android.view.Menu
import android.view.MenuItem import android.view.MenuItem
@ -9,37 +8,42 @@ import androidx.core.view.isGone
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
import io.legado.app.R import io.legado.app.R
import io.legado.app.base.VMBaseActivity import io.legado.app.base.VMBaseActivity
import io.legado.app.databinding.ActivityImportBookBinding
import io.legado.app.lib.theme.backgroundColor
import io.legado.app.databinding.ActivityRemoteBookBinding
import io.legado.app.ui.book.remote.manager.RemoteBookWebDav 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.ui.widget.dialog.WaitDialog
import io.legado.app.utils.toastOnUi
import io.legado.app.utils.viewbindingdelegate.viewBinding import io.legado.app.utils.viewbindingdelegate.viewBinding
import kotlinx.coroutines.flow.conflate import kotlinx.coroutines.flow.conflate
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import java.io.File
/** /**
* 展示远程书籍 * 展示远程书籍
* @author qianfanguojin * @author qianfanguojin
* @time 2022/05/12 * @time 2022/05/12
*/ */
class RemoteBookActivity : VMBaseActivity<ActivityRemoteBookBinding, RemoteBookViewModel>(), class RemoteBookActivity : VMBaseActivity<ActivityImportBookBinding, RemoteBookViewModel>(),
RemoteBookAdapter.CallBack { RemoteBookAdapter.CallBack,
override val binding by viewBinding(ActivityRemoteBookBinding::inflate) SelectActionBar.CallBack {
override val binding by viewBinding(ActivityImportBookBinding::inflate)
override val viewModel by viewModels<RemoteBookViewModel>() override val viewModel by viewModels<RemoteBookViewModel>()
private val adapter by lazy { RemoteBookAdapter(this, this) } private val adapter by lazy { RemoteBookAdapter(this, this) }
private val waitDialog by lazy { WaitDialog(this) } private val waitDialog by lazy { WaitDialog(this) }
override fun onActivityCreated(savedInstanceState: Bundle?) { override fun onActivityCreated(savedInstanceState: Bundle?) {
binding.titleBar.setTitle(R.string.remote_book)
initView() initView()
initData() initData()
initEvent()
} }
private fun initView() { private fun initView() {
binding.layTop.setBackgroundColor(backgroundColor)
binding.recyclerView.layoutManager = LinearLayoutManager(this) binding.recyclerView.layoutManager = LinearLayoutManager(this)
binding.recyclerView.adapter = adapter binding.recyclerView.adapter = adapter
binding.selectActionBar.setMainActionText(R.string.add_to_shelf)
binding.selectActionBar.setCallBack(this)
} }
private fun initData() { private fun initData() {
@ -51,7 +55,14 @@ class RemoteBookActivity : VMBaseActivity<ActivityRemoteBookBinding, RemoteBookV
adapter.setItems(remoteBooks) adapter.setItems(remoteBooks)
} }
} }
viewModel.loadRemoteBookList(RemoteBookWebDav.rootBookUrl) upPath()
}
private fun initEvent() {
binding.tvGoBack.setOnClickListener {
viewModel.dirList.removeLastOrNull()
upPath()
}
} }
override fun onCompatCreateOptionsMenu(menu: Menu): Boolean { override fun onCompatCreateOptionsMenu(menu: Menu): Boolean {
@ -62,46 +73,47 @@ class RemoteBookActivity : VMBaseActivity<ActivityRemoteBookBinding, RemoteBookV
override fun onCompatOptionsItemSelected(item: MenuItem): Boolean { override fun onCompatOptionsItemSelected(item: MenuItem): Boolean {
when (item.itemId) { when (item.itemId) {
R.id.menu_refresh -> { R.id.menu_refresh -> {
viewModel.loadRemoteBookList( upPath()
viewModel.dirList.lastOrNull()?.path ?: RemoteBookWebDav.rootBookUrl
)
} }
} }
return super.onCompatOptionsItemSelected(item) return super.onCompatOptionsItemSelected(item)
} }
override fun finish() { override fun revertSelection() {
if (viewModel.dirList.isEmpty()) { adapter.revertSelection()
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 openDir(remoteBook: RemoteBook) { override fun selectAll(selectAll: Boolean) {
viewModel.dirList.add(remoteBook) adapter.selectAll(selectAll)
binding.titleBar.title = remoteBook.filename
viewModel.dataCallback?.clear()
viewModel.loadRemoteBookList(remoteBook.path)
} }
@SuppressLint("NotifyDataSetChanged") override fun onClickSelectBarMainAction() {
override fun addToBookshelf(remoteBook: RemoteBook) {
waitDialog.show() waitDialog.show()
viewModel.addToBookshelf(remoteBook, success = { viewModel.addToBookshelf(adapter.selected) {
toastOnUi(getString(R.string.download_book_success))
adapter.notifyDataSetChanged() adapter.notifyDataSetChanged()
}) {
waitDialog.dismiss() 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)
upPath()
}
override fun upCountView() {
binding.selectActionBar.upCountView(adapter.selected.size, adapter.checkableCount)
}
} }

@ -1,13 +1,17 @@
package io.legado.app.ui.book.remote package io.legado.app.ui.book.remote
import android.annotation.SuppressLint
import android.content.Context import android.content.Context
import android.view.ViewGroup import android.view.ViewGroup
import androidx.core.view.isGone import io.legado.app.R
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.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.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 * @author qianfanguojin
*/ */
class RemoteBookAdapter(context: Context, val callBack: CallBack) : 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 { override fun getViewBinding(parent: ViewGroup): ItemImportBookBinding {
return ItemRemoteBookBinding.inflate(inflater, parent, false) return ItemImportBookBinding.inflate(inflater, parent, false)
} }
override fun onCurrentListChanged() { override fun onCurrentListChanged() {
upCheckableCount()
} }
/** /**
@ -30,39 +36,107 @@ class RemoteBookAdapter(context: Context, val callBack: CallBack) :
*/ */
override fun convert( override fun convert(
holder: ItemViewHolder, holder: ItemViewHolder,
binding: ItemRemoteBookBinding, binding: ItemImportBookBinding,
item: RemoteBook, item: RemoteBook,
payloads: MutableList<Any> payloads: MutableList<Any>
) { ) {
binding.run { binding.run {
tvName.text = item.filename.substringBeforeLast(".") if (payloads.isEmpty()) {
tvContentType.text = item.contentType 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) tvSize.text = ConvertUtils.formatFileSize(item.size)
tvDate.text = tvDate.text = AppConst.dateFormat.format(item.lastModify)
LocalDateTimeUtil.format(LocalDateTimeUtil.of(item.lastModify), "yyyy-MM-dd") cbSelect.isChecked = selected.contains(item)
llInfo.isGone = item.isDir }
tvContentType.isGone = item.isDir tvName.text = item.filename
btnDownload.isGone = item.isDir } else {
cbSelect.isChecked = selected.contains(item)
}
} }
} }
override fun registerListener(holder: ItemViewHolder, binding: ItemRemoteBookBinding) { override fun registerListener(holder: ItemViewHolder, binding: ItemImportBookBinding) {
binding.root.setOnClickListener { holder.itemView.setOnClickListener {
getItem(holder.layoutPosition)?.let { getItem(holder.layoutPosition)?.let {
if (it.isDir) { if (it.isDir) {
callBack.openDir(it) 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 { interface CallBack {
fun openDir(remoteBook: RemoteBook) fun openDir(remoteBook: RemoteBook)
fun addToBookshelf(remoteBook: RemoteBook) fun upCountView()
} }
} }

@ -1,8 +1,8 @@
package io.legado.app.ui.book.remote package io.legado.app.ui.book.remote
import android.app.Application import android.app.Application
import android.net.Uri
import io.legado.app.base.BaseViewModel import io.legado.app.base.BaseViewModel
import io.legado.app.constant.AppLog
import io.legado.app.model.localBook.LocalBook import io.legado.app.model.localBook.LocalBook
import io.legado.app.ui.book.remote.manager.RemoteBookWebDav import io.legado.app.ui.book.remote.manager.RemoteBookWebDav
import io.legado.app.utils.toastOnUi 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))
}
}.onFinally {
finally.invoke()
}
}
/**
* 添加书籍到本地书架
*/
fun addToBookshelf(remoteBook: RemoteBook, success: () -> Unit, finally: () -> Unit) {
execute { execute {
remoteBooks.forEach { remoteBook ->
val downloadBookPath = RemoteBookWebDav.getRemoteBook(remoteBook) val downloadBookPath = RemoteBookWebDav.getRemoteBook(remoteBook)
downloadBookPath?.let { downloadBookPath?.let {
LocalBook.importFile(it) LocalBook.importFile(it)
remoteBook.isOnBookShelf = true
}
} }
}.onSuccess {
success.invoke()
}.onError { }.onError {
context.toastOnUi(it.localizedMessage) AppLog.put("导入出错\n${it.localizedMessage}", it)
context.toastOnUi("导入出错\n${it.localizedMessage}")
}.onFinally { }.onFinally {
finally.invoke() finally.invoke()
} }
} }
interface DataCallback { interface DataCallback {
fun setItems(remoteFiles: List<RemoteBook>) fun setItems(remoteFiles: List<RemoteBook>)

@ -108,7 +108,10 @@ object RemoteBookWebDav : RemoteBookManager() {
} }
override suspend fun delete(remoteBookUrl: String): Boolean { override suspend fun delete(remoteBookUrl: String): Boolean {
TODO("Not yet implemented") AppWebDav.authorization?.let {
return WebDav(remoteBookUrl, it).delete()
}
return false
} }
} }

@ -9,8 +9,7 @@
android:id="@+id/titleBar" android:id="@+id/titleBar"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
app:layout_constraintTop_toTopOf="parent" app:layout_constraintTop_toTopOf="parent" />
app:title="@string/book_local" />
<!--path--> <!--path-->
<LinearLayout <LinearLayout

@ -1,67 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:tools="http://schemas.android.com/tools">
<io.legado.app.ui.widget.TitleBar
android:id="@+id/title_bar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintTop_toTopOf="parent"
app:title="@string/remote_book" />
<io.legado.app.ui.widget.anima.RefreshProgressBar
android:id="@+id/refresh_progress_bar"
android:layout_width="match_parent"
android:layout_height="2dp"
app:layout_constraintTop_toBottomOf="@id/title_bar" />
<io.legado.app.ui.widget.dynamiclayout.DynamicFrameLayout
android:id="@+id/content_view"
android:layout_width="match_parent"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toBottomOf="@id/refresh_progress_bar">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<io.legado.app.ui.widget.anima.RotateLoading
android:id="@+id/rotate_loading"
android:layout_width="36dp"
android:layout_height="36dp"
android:layout_margin="6dp"
android:visibility="gone"
android:layout_gravity="center"
app:loading_width="2dp" />
</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"-->
<!-- app:layout_constraintTop_toBottomOf="@id/content_view"-->
<!-- />-->
<TextView
android:id="@+id/tv_empty_msg"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="16dp"
android:gravity="center"
android:visibility="gone"
android:text="webDav books文件夹为空"
app:layout_constraintTop_toBottomOf="@+id/title_bar"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
tools:text="Empty" />
</androidx.constraintlayout.widget.ConstraintLayout>

@ -1,108 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<io.legado.app.ui.widget.image.CoverImageView
android:id="@+id/iv_cover"
android:layout_width="66dp"
android:layout_height="90dp"
android:layout_margin="8dp"
android:contentDescription="@string/img_cover"
android:scaleType="centerCrop"
android:src="@drawable/image_cover_default"
android:transitionName="img_cover"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:ignore="UnusedAttribute" />
<TextView
android:id="@+id/tv_name"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_margin="8dp"
android:text="@string/app_name"
android:textColor="@color/primaryText"
android:textSize="16sp"
app:layout_constraintBottom_toTopOf="@+id/ll_info"
app:layout_constraintStart_toEndOf="@+id/iv_cover"
app:layout_constraintTop_toTopOf="parent" />
<LinearLayout
android:id="@+id/ll_info"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_margin="8dp"
android:gravity="top"
android:orientation="horizontal"
app:layout_constraintBottom_toTopOf="@+id/tv_content_type"
app:layout_constraintLeft_toRightOf="@+id/iv_cover"
app:layout_constraintTop_toBottomOf="@+id/tv_name"
app:layout_constraintRight_toLeftOf="@+id/btn_download">
<TextView
android:id="@+id/tv_size"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ellipsize="end"
android:lines="1"
android:textColor="@color/tv_text_summary"
android:textSize="13sp"
tools:ignore="TextContrastCheck"
tools:text="128kb" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ellipsize="end"
android:lines="1"
android:text="@string/separator"
android:textColor="@color/tv_text_summary"
android:textSize="11sp"
tools:ignore="TextContrastCheck" />
<TextView
android:id="@+id/tv_date"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ellipsize="end"
android:lines="1"
android:textColor="@color/tv_text_summary"
android:textSize="13sp"
tools:ignore="TextContrastCheck"
tools:text="2022-12-7" />
</LinearLayout>
<io.legado.app.ui.widget.text.AccentBgTextView
android:id="@+id/tv_content_type"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="8dp"
android:maxWidth="50dp"
android:singleLine="true"
android:paddingStart="5dp"
android:paddingEnd="5dp"
android:text="TXT"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toRightOf="@+id/iv_cover"
app:layout_constraintTop_toBottomOf="@id/ll_info"
app:radius="2dp"
tools:ignore="HardcodedText,RtlHardcoded" />
<io.legado.app.ui.widget.text.AccentStrokeTextView
android:id="@+id/btn_download"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="8dp"
android:padding="6dp"
android:text="@string/nb_file_add_shelf"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@+id/tv_name"
tools:text="加入书架" />
</androidx.constraintlayout.widget.ConstraintLayout>
Loading…
Cancel
Save