[优化] 漫画功能扩展 #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.animation.LinearInterpolator
import androidx.activity.addCallback
import androidx.activity.result.contract.ActivityResultContracts
import androidx.activity.viewModels
import androidx.appcompat.app.AlertDialog
import androidx.core.view.doOnLayout
@@ -29,22 +30,33 @@ import com.jaredrummler.android.colorpicker.ColorPickerDialogListener
import io.legado.app.BuildConfig
import io.legado.app.R
import io.legado.app.base.VMBaseActivity
import io.legado.app.constant.AppLog
import io.legado.app.constant.BookType
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.BookChapter
import io.legado.app.data.entities.BookProgress
import io.legado.app.data.entities.BookSource
import io.legado.app.databinding.ActivityMangaBinding
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.isLocal
import io.legado.app.help.book.removeType
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.lib.dialogs.SelectItem
import io.legado.app.lib.dialogs.alert
import io.legado.app.lib.dialogs.selector
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.ui.book.changesource.ChangeBookSourceDialog
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.read.MangaMenu
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.browser.WebViewActivity
import io.legado.app.ui.login.SourceLoginActivity
import io.legado.app.ui.widget.number.NumberPickerDialog
import io.legado.app.ui.widget.recycler.LoadMoreView
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.fromJsonObject
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.showDialogFragment
import io.legado.app.utils.startActivity
import io.legado.app.utils.toastOnUi
import io.legado.app.utils.toggleSystemBar
import io.legado.app.utils.viewbindingdelegate.viewBinding
@@ -135,6 +153,17 @@ class ReadMangaActivity : VMBaseActivity<ActivityMangaBinding, ReadMangaViewMode
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 {
LoadMoreView(this).apply {
// setBackgroundColor(getCompatColor(R.color.book_ant_10))
@@ -565,6 +594,77 @@ class ReadMangaActivity : VMBaseActivity<ActivityMangaBinding, ReadMangaViewMode
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.config.AppConfig
import io.legado.app.help.coroutine.Coroutine
import io.legado.app.model.ReadBook
import io.legado.app.model.ReadManga
import io.legado.app.model.localBook.LocalBook
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 {
ReadManga.bookSource?.let {
val oldBook = book.copy()
@@ -7,6 +7,7 @@ import android.util.AttributeSet
import android.view.LayoutInflater
import android.view.animation.Animation
import android.widget.FrameLayout
import androidx.appcompat.widget.PopupMenu
import androidx.core.view.isGone
import androidx.core.view.isVisible
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 callBack: CallBack get() = activity as CallBack
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 {
loadAnimation(context, R.anim.anim_readbook_top_in)
}
@@ -207,11 +224,17 @@ class MangaMenu @JvmOverloads constructor(
}
true
}
tvBookName.setOnClickListener{
callBack.openBookInfoActivity()
}
tvChapterName.setOnClickListener(chapterViewClickListener)
tvChapterName.setOnLongClickListener(chapterViewLongClickListener)
tvChapterUrl.setOnClickListener(chapterViewClickListener)
tvChapterUrl.setOnLongClickListener(chapterViewLongClickListener)
tvSourceAction.setOnLongClickListener {
sourceMenu.show()
true
}
tvNext.setOnClickListener {
ReadManga.moveToNextChapter(true)
}
@@ -282,6 +305,10 @@ class MangaMenu @JvmOverloads constructor(
fun showFooterConfig()
fun showScrollModeDialog()
fun onAutoPageToggle2()
fun showLogin()
fun payAction()
fun openSourceEditActivity()
fun disableSource()
}
}