[优化] 漫画功能扩展 #496

This commit is contained in:
HapeLee
2025-12-24 00:41:01 +08:00
parent 8e1c1d6518
commit cf5f9c6674
3 changed files with 154 additions and 1 deletions
@@ -11,6 +11,7 @@ import android.view.MenuItem
import android.view.WindowManager import android.view.WindowManager
import android.view.animation.LinearInterpolator import android.view.animation.LinearInterpolator
import androidx.activity.addCallback import androidx.activity.addCallback
import androidx.activity.result.contract.ActivityResultContracts
import androidx.activity.viewModels import androidx.activity.viewModels
import androidx.appcompat.app.AlertDialog import androidx.appcompat.app.AlertDialog
import androidx.core.view.doOnLayout import androidx.core.view.doOnLayout
@@ -29,22 +30,33 @@ import com.jaredrummler.android.colorpicker.ColorPickerDialogListener
import io.legado.app.BuildConfig import io.legado.app.BuildConfig
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.constant.AppLog
import io.legado.app.constant.BookType import io.legado.app.constant.BookType
import io.legado.app.constant.EventBus import io.legado.app.constant.EventBus
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.BookChapter
import io.legado.app.data.entities.BookProgress import io.legado.app.data.entities.BookProgress
import io.legado.app.data.entities.BookSource import io.legado.app.data.entities.BookSource
import io.legado.app.databinding.ActivityMangaBinding import io.legado.app.databinding.ActivityMangaBinding
import io.legado.app.databinding.ViewLoadMoreBinding import io.legado.app.databinding.ViewLoadMoreBinding
import io.legado.app.exception.NoStackTraceException
import io.legado.app.help.AppFreezeMonitor.handler
import io.legado.app.help.book.BookHelp
import io.legado.app.help.book.isImage import io.legado.app.help.book.isImage
import io.legado.app.help.book.isLocal
import io.legado.app.help.book.removeType import io.legado.app.help.book.removeType
import io.legado.app.help.config.AppConfig import io.legado.app.help.config.AppConfig
import io.legado.app.help.coroutine.Coroutine
import io.legado.app.help.source.getSourceType
import io.legado.app.help.storage.Backup import io.legado.app.help.storage.Backup
import io.legado.app.lib.dialogs.SelectItem import io.legado.app.lib.dialogs.SelectItem
import io.legado.app.lib.dialogs.alert import io.legado.app.lib.dialogs.alert
import io.legado.app.lib.dialogs.selector import io.legado.app.lib.dialogs.selector
import io.legado.app.model.ReadManga import io.legado.app.model.ReadManga
import io.legado.app.model.analyzeRule.AnalyzeRule
import io.legado.app.model.analyzeRule.AnalyzeRule.Companion.setChapter
import io.legado.app.model.analyzeRule.AnalyzeRule.Companion.setCoroutineContext
import io.legado.app.receiver.NetworkChangedListener import io.legado.app.receiver.NetworkChangedListener
import io.legado.app.ui.book.changesource.ChangeBookSourceDialog import io.legado.app.ui.book.changesource.ChangeBookSourceDialog
import io.legado.app.ui.book.info.BookInfoActivity import io.legado.app.ui.book.info.BookInfoActivity
@@ -64,7 +76,10 @@ import io.legado.app.ui.book.manga.recyclerview.ScrollTimer
import io.legado.app.ui.book.manga.recyclerview.WebtoonFrame import io.legado.app.ui.book.manga.recyclerview.WebtoonFrame
import io.legado.app.ui.book.read.MangaMenu import io.legado.app.ui.book.read.MangaMenu
import io.legado.app.ui.book.read.ReadBookActivity.Companion.RESULT_DELETED import io.legado.app.ui.book.read.ReadBookActivity.Companion.RESULT_DELETED
import io.legado.app.ui.book.source.edit.BookSourceEditActivity
import io.legado.app.ui.book.toc.TocActivityResult import io.legado.app.ui.book.toc.TocActivityResult
import io.legado.app.ui.browser.WebViewActivity
import io.legado.app.ui.login.SourceLoginActivity
import io.legado.app.ui.widget.number.NumberPickerDialog import io.legado.app.ui.widget.number.NumberPickerDialog
import io.legado.app.ui.widget.recycler.LoadMoreView import io.legado.app.ui.widget.recycler.LoadMoreView
import io.legado.app.utils.GSON import io.legado.app.utils.GSON
@@ -75,8 +90,11 @@ import io.legado.app.utils.fastBinarySearch
import io.legado.app.utils.findCenterViewPosition import io.legado.app.utils.findCenterViewPosition
import io.legado.app.utils.fromJsonObject import io.legado.app.utils.fromJsonObject
import io.legado.app.utils.gone import io.legado.app.utils.gone
import io.legado.app.utils.isAbsUrl
import io.legado.app.utils.isTrue
import io.legado.app.utils.observeEvent import io.legado.app.utils.observeEvent
import io.legado.app.utils.showDialogFragment import io.legado.app.utils.showDialogFragment
import io.legado.app.utils.startActivity
import io.legado.app.utils.toastOnUi import io.legado.app.utils.toastOnUi
import io.legado.app.utils.toggleSystemBar import io.legado.app.utils.toggleSystemBar
import io.legado.app.utils.viewbindingdelegate.viewBinding import io.legado.app.utils.viewbindingdelegate.viewBinding
@@ -135,6 +153,17 @@ class ReadMangaActivity : VMBaseActivity<ActivityMangaBinding, ReadMangaViewMode
LinearInterpolator() LinearInterpolator()
} }
private val sourceEditActivity =
registerForActivityResult(StartActivityContract(BookSourceEditActivity::class.java)) {
if (it.resultCode == RESULT_OK) {
viewModel.upBookSource {
handler.post {
binding.mangaMenu.upBookView()
}
}
}
}
private val loadMoreView by lazy { private val loadMoreView by lazy {
LoadMoreView(this).apply { LoadMoreView(this).apply {
// setBackgroundColor(getCompatColor(R.color.book_ant_10)) // setBackgroundColor(getCompatColor(R.color.book_ant_10))
@@ -565,6 +594,77 @@ class ReadMangaActivity : VMBaseActivity<ActivityMangaBinding, ReadMangaViewMode
return super.onCompatCreateOptionsMenu(menu) return super.onCompatCreateOptionsMenu(menu)
} }
override fun showLogin() {
ReadManga.bookSource?.let {
startActivity<SourceLoginActivity> {
putExtra("type", "bookSource")
putExtra("key", it.bookSourceUrl)
}
}
}
override fun payAction() {
val book = ReadManga.book ?: return
if (book.isLocal) return
val chapter = appDb.bookChapterDao.getChapter(book.bookUrl, ReadManga.durChapterIndex)
if (chapter == null) {
toastOnUi("no chapter")
return
}
alert(R.string.chapter_pay) {
setMessage(chapter.title)
yesButton {
Coroutine.async(lifecycleScope) {
val source =
ReadManga.bookSource ?: throw NoStackTraceException("no book source")
val payAction = source.getContentRule().payAction
if (payAction.isNullOrBlank()) {
throw NoStackTraceException("no pay action")
}
val analyzeRule = AnalyzeRule(book, source)
analyzeRule.setCoroutineContext(coroutineContext)
analyzeRule.setBaseUrl(chapter.url)
analyzeRule.setChapter(chapter)
analyzeRule.evalJS(payAction).toString()
}.onSuccess(IO) {
if (it.isAbsUrl()) {
startActivity<WebViewActivity> {
val bookSource = ReadManga.bookSource
putExtra("title", getString(R.string.chapter_pay))
putExtra("url", it)
putExtra("sourceOrigin", bookSource?.bookSourceUrl)
putExtra("sourceName", bookSource?.bookSourceName)
putExtra("sourceType", bookSource?.getSourceType())
}
} else if (it.isTrue()) {
//购买成功后刷新目录
ReadManga.book?.let {
ReadManga.curMangaChapter = null
BookHelp.delContent(book, chapter)
viewModel.loadChapterList(book)
}
}
}.onError {
AppLog.put("执行购买操作出错\n${it.localizedMessage}", it, true)
}
}
noButton()
}
}
override fun disableSource() {
viewModel.disableSource()
}
override fun openSourceEditActivity() {
ReadManga.bookSource?.let {
sourceEditActivity.launch {
putExtra("sourceUrl", it.bookSourceUrl)
}
}
}
/** /**
* 菜单 * 菜单
*/ */
@@ -24,6 +24,7 @@ import io.legado.app.help.book.removeType
import io.legado.app.help.book.simulatedTotalChapterNum import io.legado.app.help.book.simulatedTotalChapterNum
import io.legado.app.help.config.AppConfig import io.legado.app.help.config.AppConfig
import io.legado.app.help.coroutine.Coroutine import io.legado.app.help.coroutine.Coroutine
import io.legado.app.model.ReadBook
import io.legado.app.model.ReadManga import io.legado.app.model.ReadManga
import io.legado.app.model.localBook.LocalBook import io.legado.app.model.localBook.LocalBook
import io.legado.app.model.webBook.WebBook import io.legado.app.model.webBook.WebBook
@@ -120,6 +121,31 @@ class ReadMangaViewModel(application: Application) : BaseViewModel(application)
} }
} }
fun upBookSource(success: (() -> Unit)?) {
execute {
ReadManga.book?.let { book ->
ReadManga.bookSource = appDb.bookSourceDao.getBookSource(book.origin)
}
}.onSuccess {
success?.invoke()
}
}
fun loadChapterList(book: Book) {
execute {
loadChapterListAwait(book)
}
}
fun disableSource() {
execute {
ReadManga.bookSource?.let {
it.enabled = false
appDb.bookSourceDao.update(it)
}
}
}
private suspend fun loadChapterListAwait(book: Book): Boolean { private suspend fun loadChapterListAwait(book: Book): Boolean {
ReadManga.bookSource?.let { ReadManga.bookSource?.let {
val oldBook = book.copy() val oldBook = book.copy()
@@ -7,6 +7,7 @@ import android.util.AttributeSet
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.animation.Animation import android.view.animation.Animation
import android.widget.FrameLayout import android.widget.FrameLayout
import androidx.appcompat.widget.PopupMenu
import androidx.core.view.isGone import androidx.core.view.isGone
import androidx.core.view.isVisible import androidx.core.view.isVisible
import com.google.android.material.slider.Slider import com.google.android.material.slider.Slider
@@ -37,6 +38,22 @@ class MangaMenu @JvmOverloads constructor(
private val binding = ViewMangaMenuBinding.inflate(LayoutInflater.from(context), this, true) private val binding = ViewMangaMenuBinding.inflate(LayoutInflater.from(context), this, true)
private val callBack: CallBack get() = activity as CallBack private val callBack: CallBack get() = activity as CallBack
var canShowMenu: Boolean = false var canShowMenu: Boolean = false
private val sourceMenu by lazy {
PopupMenu(context, binding.tvSourceAction).apply {
inflate(R.menu.book_read_source)
setOnMenuItemClickListener {
when (it.itemId) {
R.id.menu_login -> callBack.showLogin()
R.id.menu_chapter_pay -> callBack.payAction()
R.id.menu_edit_source -> callBack.openSourceEditActivity()
R.id.menu_disable_source -> callBack.disableSource()
}
true
}
}
}
private val menuTopIn: Animation by lazy { private val menuTopIn: Animation by lazy {
loadAnimation(context, R.anim.anim_readbook_top_in) loadAnimation(context, R.anim.anim_readbook_top_in)
} }
@@ -207,11 +224,17 @@ class MangaMenu @JvmOverloads constructor(
} }
true true
} }
tvBookName.setOnClickListener{
callBack.openBookInfoActivity()
}
tvChapterName.setOnClickListener(chapterViewClickListener) tvChapterName.setOnClickListener(chapterViewClickListener)
tvChapterName.setOnLongClickListener(chapterViewLongClickListener) tvChapterName.setOnLongClickListener(chapterViewLongClickListener)
tvChapterUrl.setOnClickListener(chapterViewClickListener) tvChapterUrl.setOnClickListener(chapterViewClickListener)
tvChapterUrl.setOnLongClickListener(chapterViewLongClickListener) tvChapterUrl.setOnLongClickListener(chapterViewLongClickListener)
tvSourceAction.setOnLongClickListener {
sourceMenu.show()
true
}
tvNext.setOnClickListener { tvNext.setOnClickListener {
ReadManga.moveToNextChapter(true) ReadManga.moveToNextChapter(true)
} }
@@ -282,6 +305,10 @@ class MangaMenu @JvmOverloads constructor(
fun showFooterConfig() fun showFooterConfig()
fun showScrollModeDialog() fun showScrollModeDialog()
fun onAutoPageToggle2() fun onAutoPageToggle2()
fun showLogin()
fun payAction()
fun openSourceEditActivity()
fun disableSource()
} }
} }