添加单章换源
This commit is contained in:
@@ -8,7 +8,6 @@ import androidx.appcompat.widget.SearchView
|
|||||||
import androidx.appcompat.widget.Toolbar
|
import androidx.appcompat.widget.Toolbar
|
||||||
import androidx.core.os.bundleOf
|
import androidx.core.os.bundleOf
|
||||||
import androidx.fragment.app.viewModels
|
import androidx.fragment.app.viewModels
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import io.legado.app.R
|
import io.legado.app.R
|
||||||
import io.legado.app.base.BaseDialogFragment
|
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.constant.PreferKey
|
||||||
import io.legado.app.data.appDb
|
import io.legado.app.data.appDb
|
||||||
import io.legado.app.data.entities.Book
|
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.BookSource
|
||||||
import io.legado.app.data.entities.SearchBook
|
import io.legado.app.data.entities.SearchBook
|
||||||
import io.legado.app.databinding.DialogChapterChangeSourceBinding
|
import io.legado.app.databinding.DialogChapterChangeSourceBinding
|
||||||
@@ -33,7 +33,8 @@ import kotlinx.coroutines.launch
|
|||||||
|
|
||||||
class ChangeChapterSourceDialog() : BaseDialogFragment(R.layout.dialog_chapter_change_source),
|
class ChangeChapterSourceDialog() : BaseDialogFragment(R.layout.dialog_chapter_change_source),
|
||||||
Toolbar.OnMenuItemClickListener,
|
Toolbar.OnMenuItemClickListener,
|
||||||
ChangeChapterSourceAdapter.CallBack {
|
ChangeChapterSourceAdapter.CallBack,
|
||||||
|
ChangeChapterTocAdapter.Callback {
|
||||||
|
|
||||||
constructor(name: String, author: String, chapterIndex: Int, chapterTitle: String) : this() {
|
constructor(name: String, author: String, chapterIndex: Int, chapterTitle: String) : this() {
|
||||||
arguments = Bundle().apply {
|
arguments = Bundle().apply {
|
||||||
@@ -48,11 +49,17 @@ class ChangeChapterSourceDialog() : BaseDialogFragment(R.layout.dialog_chapter_c
|
|||||||
private val groups = linkedSetOf<String>()
|
private val groups = linkedSetOf<String>()
|
||||||
private val callBack: CallBack? get() = activity as? CallBack
|
private val callBack: CallBack? get() = activity as? CallBack
|
||||||
private val viewModel: ChangeChapterSourceViewModel by viewModels()
|
private val viewModel: ChangeChapterSourceViewModel by viewModels()
|
||||||
private val adapter by lazy { ChangeChapterSourceAdapter(requireContext(), viewModel, this) }
|
|
||||||
private val editSourceResult =
|
private val editSourceResult =
|
||||||
registerForActivityResult(StartActivityContract(BookSourceEditActivity::class.java)) {
|
registerForActivityResult(StartActivityContract(BookSourceEditActivity::class.java)) {
|
||||||
viewModel.startSearch()
|
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() {
|
override fun onStart() {
|
||||||
super.onStart()
|
super.onStart()
|
||||||
@@ -64,14 +71,14 @@ class ChangeChapterSourceDialog() : BaseDialogFragment(R.layout.dialog_chapter_c
|
|||||||
viewModel.initData(arguments)
|
viewModel.initData(arguments)
|
||||||
showTitle()
|
showTitle()
|
||||||
initMenu()
|
initMenu()
|
||||||
|
initView()
|
||||||
initRecyclerView()
|
initRecyclerView()
|
||||||
initSearchView()
|
initSearchView()
|
||||||
initLiveData()
|
initLiveData()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun showTitle() {
|
private fun showTitle() {
|
||||||
binding.toolBar.title = viewModel.name
|
binding.toolBar.title = viewModel.chapterTitle
|
||||||
binding.toolBar.subtitle = viewModel.author
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun initMenu() {
|
private fun initMenu() {
|
||||||
@@ -86,11 +93,16 @@ class ChangeChapterSourceDialog() : BaseDialogFragment(R.layout.dialog_chapter_c
|
|||||||
?.isChecked = AppConfig.changeSourceLoadToc
|
?.isChecked = AppConfig.changeSourceLoadToc
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun initView() {
|
||||||
|
binding.ivHideToc.setOnClickListener {
|
||||||
|
binding.clToc.gone()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun initRecyclerView() {
|
private fun initRecyclerView() {
|
||||||
binding.recyclerView.layoutManager = LinearLayoutManager(context)
|
|
||||||
binding.recyclerView.addItemDecoration(VerticalDivider(requireContext()))
|
binding.recyclerView.addItemDecoration(VerticalDivider(requireContext()))
|
||||||
binding.recyclerView.adapter = adapter
|
binding.recyclerView.adapter = searchBookAdapter
|
||||||
adapter.registerAdapterDataObserver(object : RecyclerView.AdapterDataObserver() {
|
searchBookAdapter.registerAdapterDataObserver(object : RecyclerView.AdapterDataObserver() {
|
||||||
override fun onItemRangeInserted(positionStart: Int, itemCount: Int) {
|
override fun onItemRangeInserted(positionStart: Int, itemCount: Int) {
|
||||||
if (positionStart == 0) {
|
if (positionStart == 0) {
|
||||||
binding.recyclerView.scrollToPosition(0)
|
binding.recyclerView.scrollToPosition(0)
|
||||||
@@ -103,6 +115,7 @@ class ChangeChapterSourceDialog() : BaseDialogFragment(R.layout.dialog_chapter_c
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
binding.recyclerViewToc.adapter = tocAdapter
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun initSearchView() {
|
private fun initSearchView() {
|
||||||
@@ -147,7 +160,7 @@ class ChangeChapterSourceDialog() : BaseDialogFragment(R.layout.dialog_chapter_c
|
|||||||
launch {
|
launch {
|
||||||
viewModel.searchDataFlow
|
viewModel.searchDataFlow
|
||||||
.collect {
|
.collect {
|
||||||
adapter.setItems(it)
|
searchBookAdapter.setItems(it)
|
||||||
delay(1000)
|
delay(1000)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -198,8 +211,22 @@ class ChangeChapterSourceDialog() : BaseDialogFragment(R.layout.dialog_chapter_c
|
|||||||
return false
|
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) {
|
override fun openToc(searchBook: SearchBook) {
|
||||||
|
this.searchBook = searchBook
|
||||||
|
tocAdapter.setItems(null)
|
||||||
binding.clToc.visible()
|
binding.clToc.visible()
|
||||||
|
binding.loadingToc.show()
|
||||||
|
viewModel.getToc(searchBook, tocSuccess) {
|
||||||
|
binding.clToc.gone()
|
||||||
|
toastOnUi(it)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override val bookUrl: String?
|
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) {
|
private fun changeSource(searchBook: SearchBook) {
|
||||||
try {
|
try {
|
||||||
val book = searchBook.toBook()
|
val book = searchBook.toBook()
|
||||||
@@ -272,9 +303,9 @@ class ChangeChapterSourceDialog() : BaseDialogFragment(R.layout.dialog_chapter_c
|
|||||||
|
|
||||||
override fun observeLiveBus() {
|
override fun observeLiveBus() {
|
||||||
observeEvent<String>(EventBus.SOURCE_CHANGED) {
|
observeEvent<String>(EventBus.SOURCE_CHANGED) {
|
||||||
adapter.notifyItemRangeChanged(
|
searchBookAdapter.notifyItemRangeChanged(
|
||||||
0,
|
0,
|
||||||
adapter.itemCount,
|
searchBookAdapter.itemCount,
|
||||||
bundleOf(Pair("upCurSource", bookUrl))
|
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.data.entities.SearchBook
|
||||||
import io.legado.app.help.AppConfig
|
import io.legado.app.help.AppConfig
|
||||||
import io.legado.app.help.coroutine.CompositeCoroutine
|
import io.legado.app.help.coroutine.CompositeCoroutine
|
||||||
|
import io.legado.app.model.NoStackTraceException
|
||||||
import io.legado.app.model.webBook.WebBook
|
import io.legado.app.model.webBook.WebBook
|
||||||
import io.legado.app.utils.getPrefBoolean
|
import io.legado.app.utils.getPrefBoolean
|
||||||
import io.legado.app.utils.getPrefString
|
import io.legado.app.utils.getPrefString
|
||||||
@@ -270,6 +271,29 @@ class ChangeChapterSourceViewModel(application: Application) : BaseViewModel(app
|
|||||||
searchPool?.close()
|
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) {
|
fun disableSource(searchBook: SearchBook) {
|
||||||
execute {
|
execute {
|
||||||
appDb.bookSourceDao.getBookSource(searchBook.origin)?.let { source ->
|
appDb.bookSourceDao.getBookSource(searchBook.origin)?.let { source ->
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ import android.view.ViewGroup
|
|||||||
import io.legado.app.R
|
import io.legado.app.R
|
||||||
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.BookChapter
|
import io.legado.app.data.entities.BookChapter
|
||||||
import io.legado.app.databinding.ItemChapterListBinding
|
import io.legado.app.databinding.ItemChapterListBinding
|
||||||
import io.legado.app.lib.theme.ThemeUtils
|
import io.legado.app.lib.theme.ThemeUtils
|
||||||
@@ -17,6 +16,8 @@ import io.legado.app.utils.visible
|
|||||||
class ChangeChapterTocAdapter(context: Context, val callback: Callback) :
|
class ChangeChapterTocAdapter(context: Context, val callback: Callback) :
|
||||||
RecyclerAdapter<BookChapter, ItemChapterListBinding>(context) {
|
RecyclerAdapter<BookChapter, ItemChapterListBinding>(context) {
|
||||||
|
|
||||||
|
var durChapterIndex = 0
|
||||||
|
|
||||||
override fun getViewBinding(parent: ViewGroup): ItemChapterListBinding {
|
override fun getViewBinding(parent: ViewGroup): ItemChapterListBinding {
|
||||||
return ItemChapterListBinding.inflate(inflater, parent, false)
|
return ItemChapterListBinding.inflate(inflater, parent, false)
|
||||||
}
|
}
|
||||||
@@ -28,7 +29,7 @@ class ChangeChapterTocAdapter(context: Context, val callback: Callback) :
|
|||||||
payloads: MutableList<Any>
|
payloads: MutableList<Any>
|
||||||
) {
|
) {
|
||||||
binding.run {
|
binding.run {
|
||||||
val isDur = callback.durChapterIndex() == item.index
|
val isDur = durChapterIndex == item.index
|
||||||
if (isDur) {
|
if (isDur) {
|
||||||
tvChapterName.setTextColor(context.accentColor)
|
tvChapterName.setTextColor(context.accentColor)
|
||||||
} else {
|
} else {
|
||||||
@@ -58,14 +59,12 @@ class ChangeChapterTocAdapter(context: Context, val callback: Callback) :
|
|||||||
override fun registerListener(holder: ItemViewHolder, binding: ItemChapterListBinding) {
|
override fun registerListener(holder: ItemViewHolder, binding: ItemChapterListBinding) {
|
||||||
holder.itemView.setOnClickListener {
|
holder.itemView.setOnClickListener {
|
||||||
getItem(holder.layoutPosition)?.let {
|
getItem(holder.layoutPosition)?.let {
|
||||||
callback.openChapter(it)
|
callback.clickChapter(it)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
interface Callback {
|
interface Callback {
|
||||||
val book: Book?
|
fun clickChapter(bookChapter: BookChapter)
|
||||||
fun openChapter(bookChapter: BookChapter)
|
|
||||||
fun durChapterIndex(): Int
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -29,6 +29,7 @@
|
|||||||
android:id="@+id/recycler_view"
|
android:id="@+id/recycler_view"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="0dp"
|
android:layout_height="0dp"
|
||||||
|
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
app:layout_constraintTop_toBottomOf="@+id/refresh_progress_bar" />
|
app:layout_constraintTop_toBottomOf="@+id/refresh_progress_bar" />
|
||||||
|
|
||||||
@@ -53,10 +54,12 @@
|
|||||||
android:id="@+id/recycler_view_toc"
|
android:id="@+id/recycler_view_toc"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="0dp"
|
android:layout_height="0dp"
|
||||||
|
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
app:layout_constraintTop_toBottomOf="@+id/iv_hide_toc" />
|
app:layout_constraintTop_toBottomOf="@+id/iv_hide_toc" />
|
||||||
|
|
||||||
<io.legado.app.ui.widget.anima.RotateLoading
|
<io.legado.app.ui.widget.anima.RotateLoading
|
||||||
|
android:id="@+id/loading_toc"
|
||||||
android:layout_width="36dp"
|
android:layout_width="36dp"
|
||||||
android:layout_height="36dp"
|
android:layout_height="36dp"
|
||||||
android:visibility="gone"
|
android:visibility="gone"
|
||||||
|
|||||||
Reference in New Issue
Block a user