添加单章换源

pull/1649/head
kunfei 3 years ago
parent 4347ff7c78
commit c9cf9b5336
  1. 53
      app/src/main/java/io/legado/app/ui/book/changesource/ChangeChapterSourceDialog.kt
  2. 24
      app/src/main/java/io/legado/app/ui/book/changesource/ChangeChapterSourceViewModel.kt
  3. 11
      app/src/main/java/io/legado/app/ui/book/changesource/ChangeChapterTocAdapter.kt
  4. 3
      app/src/main/res/layout/dialog_chapter_change_source.xml

@ -8,7 +8,6 @@ import androidx.appcompat.widget.SearchView
import androidx.appcompat.widget.Toolbar
import androidx.core.os.bundleOf
import androidx.fragment.app.viewModels
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import io.legado.app.R
import io.legado.app.base.BaseDialogFragment
@ -17,6 +16,7 @@ import io.legado.app.constant.EventBus
import io.legado.app.constant.PreferKey
import io.legado.app.data.appDb
import io.legado.app.data.entities.Book
import io.legado.app.data.entities.BookChapter
import io.legado.app.data.entities.BookSource
import io.legado.app.data.entities.SearchBook
import io.legado.app.databinding.DialogChapterChangeSourceBinding
@ -33,7 +33,8 @@ import kotlinx.coroutines.launch
class ChangeChapterSourceDialog() : BaseDialogFragment(R.layout.dialog_chapter_change_source),
Toolbar.OnMenuItemClickListener,
ChangeChapterSourceAdapter.CallBack {
ChangeChapterSourceAdapter.CallBack,
ChangeChapterTocAdapter.Callback {
constructor(name: String, author: String, chapterIndex: Int, chapterTitle: String) : this() {
arguments = Bundle().apply {
@ -48,11 +49,17 @@ class ChangeChapterSourceDialog() : BaseDialogFragment(R.layout.dialog_chapter_c
private val groups = linkedSetOf<String>()
private val callBack: CallBack? get() = activity as? CallBack
private val viewModel: ChangeChapterSourceViewModel by viewModels()
private val adapter by lazy { ChangeChapterSourceAdapter(requireContext(), viewModel, this) }
private val editSourceResult =
registerForActivityResult(StartActivityContract(BookSourceEditActivity::class.java)) {
viewModel.startSearch()
}
private val searchBookAdapter by lazy {
ChangeChapterSourceAdapter(requireContext(), viewModel, this)
}
private val tocAdapter by lazy {
ChangeChapterTocAdapter(requireContext(), this)
}
private var searchBook: SearchBook? = null
override fun onStart() {
super.onStart()
@ -64,14 +71,14 @@ class ChangeChapterSourceDialog() : BaseDialogFragment(R.layout.dialog_chapter_c
viewModel.initData(arguments)
showTitle()
initMenu()
initView()
initRecyclerView()
initSearchView()
initLiveData()
}
private fun showTitle() {
binding.toolBar.title = viewModel.name
binding.toolBar.subtitle = viewModel.author
binding.toolBar.title = viewModel.chapterTitle
}
private fun initMenu() {
@ -86,11 +93,16 @@ class ChangeChapterSourceDialog() : BaseDialogFragment(R.layout.dialog_chapter_c
?.isChecked = AppConfig.changeSourceLoadToc
}
private fun initView() {
binding.ivHideToc.setOnClickListener {
binding.clToc.gone()
}
}
private fun initRecyclerView() {
binding.recyclerView.layoutManager = LinearLayoutManager(context)
binding.recyclerView.addItemDecoration(VerticalDivider(requireContext()))
binding.recyclerView.adapter = adapter
adapter.registerAdapterDataObserver(object : RecyclerView.AdapterDataObserver() {
binding.recyclerView.adapter = searchBookAdapter
searchBookAdapter.registerAdapterDataObserver(object : RecyclerView.AdapterDataObserver() {
override fun onItemRangeInserted(positionStart: Int, itemCount: Int) {
if (positionStart == 0) {
binding.recyclerView.scrollToPosition(0)
@ -103,6 +115,7 @@ class ChangeChapterSourceDialog() : BaseDialogFragment(R.layout.dialog_chapter_c
}
}
})
binding.recyclerViewToc.adapter = tocAdapter
}
private fun initSearchView() {
@ -147,7 +160,7 @@ class ChangeChapterSourceDialog() : BaseDialogFragment(R.layout.dialog_chapter_c
launch {
viewModel.searchDataFlow
.collect {
adapter.setItems(it)
searchBookAdapter.setItems(it)
delay(1000)
}
}
@ -198,8 +211,22 @@ class ChangeChapterSourceDialog() : BaseDialogFragment(R.layout.dialog_chapter_c
return false
}
private val tocSuccess: (toc: List<BookChapter>) -> Unit = {
tocAdapter.durChapterIndex = viewModel.chapterIndex
binding.loadingToc.hide()
tocAdapter.setItems(it)
binding.recyclerViewToc.scrollToPosition(tocAdapter.durChapterIndex - 5)
}
override fun openToc(searchBook: SearchBook) {
this.searchBook = searchBook
tocAdapter.setItems(null)
binding.clToc.visible()
binding.loadingToc.show()
viewModel.getToc(searchBook, tocSuccess) {
binding.clToc.gone()
toastOnUi(it)
}
}
override val bookUrl: String?
@ -232,6 +259,10 @@ class ChangeChapterSourceDialog() : BaseDialogFragment(R.layout.dialog_chapter_c
}
}
override fun clickChapter(bookChapter: BookChapter) {
TODO("Not yet implemented")
}
private fun changeSource(searchBook: SearchBook) {
try {
val book = searchBook.toBook()
@ -272,9 +303,9 @@ class ChangeChapterSourceDialog() : BaseDialogFragment(R.layout.dialog_chapter_c
override fun observeLiveBus() {
observeEvent<String>(EventBus.SOURCE_CHANGED) {
adapter.notifyItemRangeChanged(
searchBookAdapter.notifyItemRangeChanged(
0,
adapter.itemCount,
searchBookAdapter.itemCount,
bundleOf(Pair("upCurSource", bookUrl))
)
}

@ -16,6 +16,7 @@ import io.legado.app.data.entities.BookSource
import io.legado.app.data.entities.SearchBook
import io.legado.app.help.AppConfig
import io.legado.app.help.coroutine.CompositeCoroutine
import io.legado.app.model.NoStackTraceException
import io.legado.app.model.webBook.WebBook
import io.legado.app.utils.getPrefBoolean
import io.legado.app.utils.getPrefString
@ -270,6 +271,29 @@ class ChangeChapterSourceViewModel(application: Application) : BaseViewModel(app
searchPool?.close()
}
fun getToc(
searchBook: SearchBook,
success: (toc: List<BookChapter>) -> Unit,
error: (msg: String) -> Unit
) {
execute {
return@execute tocMap[searchBook.bookUrl]
?: let {
val book = searchBook.toBook()
val source = appDb.bookSourceDao.getBookSource(book.origin)
?: throw NoStackTraceException("书源不存在")
if (book.tocUrl.isEmpty()) {
WebBook.getBookInfoAwait(this, source, book)
}
WebBook.getChapterListAwait(this, source, book)
}
}.onSuccess {
success(it)
}.onError {
error(it.localizedMessage ?: "获取目录出错")
}
}
fun disableSource(searchBook: SearchBook) {
execute {
appDb.bookSourceDao.getBookSource(searchBook.origin)?.let { source ->

@ -5,7 +5,6 @@ import android.view.ViewGroup
import io.legado.app.R
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.data.entities.BookChapter
import io.legado.app.databinding.ItemChapterListBinding
import io.legado.app.lib.theme.ThemeUtils
@ -17,6 +16,8 @@ import io.legado.app.utils.visible
class ChangeChapterTocAdapter(context: Context, val callback: Callback) :
RecyclerAdapter<BookChapter, ItemChapterListBinding>(context) {
var durChapterIndex = 0
override fun getViewBinding(parent: ViewGroup): ItemChapterListBinding {
return ItemChapterListBinding.inflate(inflater, parent, false)
}
@ -28,7 +29,7 @@ class ChangeChapterTocAdapter(context: Context, val callback: Callback) :
payloads: MutableList<Any>
) {
binding.run {
val isDur = callback.durChapterIndex() == item.index
val isDur = durChapterIndex == item.index
if (isDur) {
tvChapterName.setTextColor(context.accentColor)
} else {
@ -58,14 +59,12 @@ class ChangeChapterTocAdapter(context: Context, val callback: Callback) :
override fun registerListener(holder: ItemViewHolder, binding: ItemChapterListBinding) {
holder.itemView.setOnClickListener {
getItem(holder.layoutPosition)?.let {
callback.openChapter(it)
callback.clickChapter(it)
}
}
}
interface Callback {
val book: Book?
fun openChapter(bookChapter: BookChapter)
fun durChapterIndex(): Int
fun clickChapter(bookChapter: BookChapter)
}
}

@ -29,6 +29,7 @@
android:id="@+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="0dp"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toBottomOf="@+id/refresh_progress_bar" />
@ -53,10 +54,12 @@
android:id="@+id/recycler_view_toc"
android:layout_width="match_parent"
android:layout_height="0dp"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toBottomOf="@+id/iv_hide_toc" />
<io.legado.app.ui.widget.anima.RotateLoading
android:id="@+id/loading_toc"
android:layout_width="36dp"
android:layout_height="36dp"
android:visibility="gone"

Loading…
Cancel
Save