This commit is contained in:
Horis
2023-12-27 09:58:07 +08:00
parent e895223638
commit cf40a32e3a
11 changed files with 102 additions and 25 deletions
@@ -1,5 +1,6 @@
package io.legado.app.constant package io.legado.app.constant
@Suppress("ConstPropertyName")
object IntentAction { object IntentAction {
const val start = "start" const val start = "start"
const val play = "play" const val play = "play"
@@ -3,6 +3,7 @@ package io.legado.app.constant
/** /**
* 通知ID不能重复,统一规划通知ID * 通知ID不能重复,统一规划通知ID
*/ */
@Suppress("ConstPropertyName")
object NotificationId { object NotificationId {
const val ReadAloudService = 101 const val ReadAloudService = 101
@@ -1,12 +1,22 @@
package io.legado.app.data.entities package io.legado.app.data.entities
import android.os.Parcelable import android.os.Parcelable
import androidx.room.* import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.Ignore
import androidx.room.Index
import androidx.room.PrimaryKey
import androidx.room.TypeConverter
import androidx.room.TypeConverters
import io.legado.app.constant.AppPattern import io.legado.app.constant.AppPattern
import io.legado.app.constant.BookType import io.legado.app.constant.BookType
import io.legado.app.constant.PageAnim import io.legado.app.constant.PageAnim
import io.legado.app.data.appDb import io.legado.app.data.appDb
import io.legado.app.help.book.* import io.legado.app.help.book.BookHelp
import io.legado.app.help.book.ContentProcessor
import io.legado.app.help.book.isEpub
import io.legado.app.help.book.isImage
import io.legado.app.help.book.isPdf
import io.legado.app.help.config.AppConfig import io.legado.app.help.config.AppConfig
import io.legado.app.help.config.ReadBookConfig import io.legado.app.help.config.ReadBookConfig
import io.legado.app.model.ReadBook import io.legado.app.model.ReadBook
@@ -144,6 +154,10 @@ data class Book(
@IgnoredOnParcel @IgnoredOnParcel
private var folderName: String? = null private var folderName: String? = null
@get:Ignore
@IgnoredOnParcel
val lastChapterIndex get() = totalChapterNum - 1
fun getRealAuthor() = author.replace(AppPattern.authorRegex, "") fun getRealAuthor() = author.replace(AppPattern.authorRegex, "")
fun getUnreadChapterNum() = max(totalChapterNum - durChapterIndex - 1, 0) fun getUnreadChapterNum() = max(totalChapterNum - durChapterIndex - 1, 0)
@@ -103,30 +103,34 @@ class CacheBookService : BaseService() {
execute { execute {
val cacheBook = CacheBook.getOrCreate(bookUrl) ?: return@execute val cacheBook = CacheBook.getOrCreate(bookUrl) ?: return@execute
val chapterCount = appDb.bookChapterDao.getChapterCount(bookUrl) val chapterCount = appDb.bookChapterDao.getChapterCount(bookUrl)
val book = cacheBook.book
if (chapterCount == 0) { if (chapterCount == 0) {
val name = cacheBook.book.name val name = book.name
if (cacheBook.book.tocUrl.isEmpty()) { if (book.tocUrl.isEmpty()) {
kotlin.runCatching { kotlin.runCatching {
WebBook.getBookInfoAwait(cacheBook.bookSource, cacheBook.book) WebBook.getBookInfoAwait(cacheBook.bookSource, book)
}.onFailure { }.onFailure {
val msg = "《$name》目录为空且加载详情页失败\n${it.localizedMessage}" val msg = "《$name》目录为空且加载详情页失败\n${it.localizedMessage}"
AppLog.put(msg, it, true) AppLog.put(msg, it, true)
return@execute return@execute
} }
} }
WebBook.getChapterListAwait(cacheBook.bookSource, cacheBook.book).onFailure { WebBook.getChapterListAwait(cacheBook.bookSource, book).onFailure {
cacheBook.book.totalChapterNum = 0 if (book.totalChapterNum > 0) {
book.totalChapterNum = 0
book.save()
}
AppLog.put("《$name》目录为空且加载目录失败\n${it.localizedMessage}", it, true) AppLog.put("《$name》目录为空且加载目录失败\n${it.localizedMessage}", it, true)
return@execute return@execute
}.getOrNull()?.let { toc -> }.getOrNull()?.let { toc ->
appDb.bookChapterDao.insert(*toc.toTypedArray()) appDb.bookChapterDao.insert(*toc.toTypedArray())
} }
cacheBook.book.save() book.save()
} }
val end2 = if (end == 0) { val end2 = if (end < 0) {
appDb.bookChapterDao.getChapterCount(bookUrl) book.lastChapterIndex
} else { } else {
end min(end, book.lastChapterIndex)
} }
cacheBook.addDownload(start, end2) cacheBook.addDownload(start, end2)
notificationContent = CacheBook.downloadSummary notificationContent = CacheBook.downloadSummary
@@ -29,8 +29,10 @@ import io.legado.app.help.AppWebDav
import io.legado.app.help.book.BookHelp import io.legado.app.help.book.BookHelp
import io.legado.app.help.book.ContentProcessor import io.legado.app.help.book.ContentProcessor
import io.legado.app.help.book.getExportFileName import io.legado.app.help.book.getExportFileName
import io.legado.app.help.book.isLocal
import io.legado.app.help.config.AppConfig import io.legado.app.help.config.AppConfig
import io.legado.app.help.coroutine.OrderCoroutine import io.legado.app.help.coroutine.OrderCoroutine
import io.legado.app.model.localBook.LocalBook
import io.legado.app.ui.book.cache.CacheActivity import io.legado.app.ui.book.cache.CacheActivity
import io.legado.app.utils.DocumentUtils import io.legado.app.utils.DocumentUtils
import io.legado.app.utils.FileUtils import io.legado.app.utils.FileUtils
@@ -177,6 +179,7 @@ class ExportBookService : BaseService() {
val book = appDb.bookDao.getBook(bookUrl) val book = appDb.bookDao.getBook(bookUrl)
try { try {
book ?: throw NoStackTraceException("获取${bookUrl}书籍出错") book ?: throw NoStackTraceException("获取${bookUrl}书籍出错")
refreshChapterList(book)
notificationContentText = getString( notificationContentText = getString(
R.string.export_book_notification_content, R.string.export_book_notification_content,
book.name, book.name,
@@ -207,6 +210,22 @@ class ExportBookService : BaseService() {
} }
} }
private fun refreshChapterList(book: Book) {
if (!book.isLocal) {
return
}
if (LocalBook.getLastModified(book).getOrDefault(0L) < book.latestChapterTime) {
return
}
kotlin.runCatching {
LocalBook.getChapterList(book)
}.onSuccess {
book.latestChapterTime = System.currentTimeMillis()
appDb.bookChapterDao.delByBook(book.bookUrl)
appDb.bookChapterDao.insert(*it.toTypedArray())
}
}
private data class SrcData( private data class SrcData(
val chapterTitle: String, val chapterTitle: String,
val index: Int, val index: Int,
@@ -34,13 +34,27 @@ import io.legado.app.model.CacheBook
import io.legado.app.service.ExportBookService import io.legado.app.service.ExportBookService
import io.legado.app.ui.about.AppLogDialog import io.legado.app.ui.about.AppLogDialog
import io.legado.app.ui.file.HandleFileContract import io.legado.app.ui.file.HandleFileContract
import io.legado.app.utils.* import io.legado.app.utils.ACache
import io.legado.app.utils.FileDoc
import io.legado.app.utils.applyTint
import io.legado.app.utils.checkWrite
import io.legado.app.utils.cnCompare
import io.legado.app.utils.enableCustomExport
import io.legado.app.utils.isContentScheme
import io.legado.app.utils.observeEvent
import io.legado.app.utils.parseToUri
import io.legado.app.utils.showDialogFragment
import io.legado.app.utils.startService
import io.legado.app.utils.toastOnUi
import io.legado.app.utils.verificationField
import io.legado.app.utils.viewbindingdelegate.viewBinding import io.legado.app.utils.viewbindingdelegate.viewBinding
import kotlinx.coroutines.Dispatchers.IO import kotlinx.coroutines.Dispatchers.IO
import kotlinx.coroutines.Job import kotlinx.coroutines.Job
import kotlinx.coroutines.flow.* import kotlinx.coroutines.flow.conflate
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import kotlin.math.max
/** /**
* cache/download 缓存界面 * cache/download 缓存界面
@@ -146,7 +160,7 @@ class CacheActivity : VMBaseActivity<ActivityCacheBookBinding, CacheViewModel>()
this@CacheActivity, this@CacheActivity,
book, book,
book.durChapterIndex, book.durChapterIndex,
book.totalChapterNum book.lastChapterIndex
) )
} }
} else { } else {
@@ -198,6 +212,10 @@ class CacheActivity : VMBaseActivity<ActivityCacheBookBinding, CacheViewModel>()
} }
3 -> booksDownload.sortedBy { it.order } 3 -> booksDownload.sortedBy { it.order }
4 -> booksDownload.sortedByDescending {
max(it.latestChapterTime, it.durChapterTime)
}
else -> booksDownload.sortedByDescending { it.durChapterTime } else -> booksDownload.sortedByDescending { it.durChapterTime }
} }
}.conflate().collect { books -> }.conflate().collect { books ->
@@ -71,10 +71,10 @@ class CacheAdapter(context: Context, private val callBack: CallBack) :
if (!it.isStop()) { if (!it.isStop()) {
CacheBook.remove(context, book.bookUrl) CacheBook.remove(context, book.bookUrl)
} else { } else {
CacheBook.start(context, book, 0, book.totalChapterNum) CacheBook.start(context, book, 0, book.lastChapterIndex)
} }
} ?: let { } ?: let {
CacheBook.start(context, book, 0, book.totalChapterNum) CacheBook.start(context, book, 0, book.lastChapterIndex)
} }
} }
} }
@@ -10,13 +10,6 @@ import io.legado.app.help.book.isLocal
import io.legado.app.help.coroutine.Coroutine import io.legado.app.help.coroutine.Coroutine
import io.legado.app.utils.sendValue import io.legado.app.utils.sendValue
import kotlinx.coroutines.ensureActive import kotlinx.coroutines.ensureActive
import kotlin.collections.HashSet
import kotlin.collections.List
import kotlin.collections.contains
import kotlin.collections.forEach
import kotlin.collections.hashMapOf
import kotlin.collections.hashSetOf
import kotlin.collections.isNotEmpty
import kotlin.collections.set import kotlin.collections.set
@@ -34,7 +27,9 @@ class CacheViewModel(application: Application) : BaseViewModel(application) {
val chapterCaches = hashSetOf<String>() val chapterCaches = hashSetOf<String>()
val cacheNames = BookHelp.getChapterFiles(book) val cacheNames = BookHelp.getChapterFiles(book)
if (cacheNames.isNotEmpty()) { if (cacheNames.isNotEmpty()) {
appDb.bookChapterDao.getChapterList(book.bookUrl).forEach { chapter -> appDb.bookChapterDao.getChapterList(book.bookUrl).also {
book.totalChapterNum = it.size
}.forEach { chapter ->
if (cacheNames.contains(chapter.getFileName()) || chapter.isVolume) { if (cacheNames.contains(chapter.getFileName()) || chapter.isVolume) {
chapterCaches.add(chapter.url) chapterCaches.add(chapter.url)
} }
@@ -39,7 +39,15 @@ import io.legado.app.ui.widget.dialog.WaitDialog
import io.legado.app.ui.widget.recycler.DragSelectTouchHelper import io.legado.app.ui.widget.recycler.DragSelectTouchHelper
import io.legado.app.ui.widget.recycler.ItemTouchCallback import io.legado.app.ui.widget.recycler.ItemTouchCallback
import io.legado.app.ui.widget.recycler.VerticalDivider import io.legado.app.ui.widget.recycler.VerticalDivider
import io.legado.app.utils.* import io.legado.app.utils.applyTint
import io.legado.app.utils.cnCompare
import io.legado.app.utils.dpToPx
import io.legado.app.utils.hideSoftInput
import io.legado.app.utils.isAbsUrl
import io.legado.app.utils.sendToClip
import io.legado.app.utils.setEdgeEffectColor
import io.legado.app.utils.showDialogFragment
import io.legado.app.utils.startActivity
import io.legado.app.utils.viewbindingdelegate.viewBinding import io.legado.app.utils.viewbindingdelegate.viewBinding
import kotlinx.coroutines.Dispatchers.IO import kotlinx.coroutines.Dispatchers.IO
import kotlinx.coroutines.Job import kotlinx.coroutines.Job
@@ -308,6 +316,7 @@ class BookshelfManageActivity :
R.id.menu_add_to_group -> selectGroup(addToGroupRequestCode, 0) R.id.menu_add_to_group -> selectGroup(addToGroupRequestCode, 0)
R.id.menu_change_source -> showDialogFragment<SourcePickerDialog>() R.id.menu_change_source -> showDialogFragment<SourcePickerDialog>()
R.id.menu_clear_cache -> viewModel.clearCache(adapter.selection)
R.id.menu_check_selected_interval -> adapter.checkSelectedInterval() R.id.menu_check_selected_interval -> adapter.checkSelectedInterval()
} }
return false return false
@@ -2,12 +2,14 @@ package io.legado.app.ui.book.manage
import android.app.Application import android.app.Application
import androidx.lifecycle.MutableLiveData import androidx.lifecycle.MutableLiveData
import io.legado.app.R
import io.legado.app.base.BaseViewModel import io.legado.app.base.BaseViewModel
import io.legado.app.constant.AppLog import io.legado.app.constant.AppLog
import io.legado.app.constant.BookType import io.legado.app.constant.BookType
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.BookSource import io.legado.app.data.entities.BookSource
import io.legado.app.help.book.BookHelp
import io.legado.app.help.book.isLocal 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
@@ -108,4 +110,14 @@ class BookshelfManageViewModel(application: Application) : BaseViewModel(applica
} }
} }
fun clearCache(books: List<Book>) {
execute {
books.forEach {
BookHelp.clearCache(it)
}
}.onSuccess {
context.toastOnUi(R.string.clear_cache_success)
}
}
} }
@@ -21,6 +21,10 @@
android:id="@+id/menu_change_source" android:id="@+id/menu_change_source"
android:title="@string/change_source_batch" /> android:title="@string/change_source_batch" />
<item
android:id="@+id/menu_clear_cache"
android:title="@string/clear_cache" />
<item <item
android:id="@+id/menu_check_selected_interval" android:id="@+id/menu_check_selected_interval"
android:title="@string/check_selected_interval" /> android:title="@string/check_selected_interval" />