Przeglądaj źródła

Merge branch 'gedoor:master' into master

Xwite 4 lat temu
rodzic
commit
abf17370ca

+ 3 - 2
app/build.gradle

@@ -192,8 +192,9 @@ dependencies {
     implementation(fileTree(dir: 'cronetlib', include: ['*.jar', '*.aar']))
 
     //Glide
-    implementation('com.github.bumptech.glide:glide:4.12.0')
-    kapt('com.github.bumptech.glide:compiler:4.12.0')
+    def glideVersion = "4.13.0"
+    implementation("com.github.bumptech.glide:glide:$glideVersion")
+    kapt("com.github.bumptech.glide:compiler:$glideVersion")
 
     //webServer
     def nanoHttpdVersion = "2.3.1"

+ 2 - 1
app/src/main/assets/updateLog.md

@@ -11,13 +11,14 @@
 * 正文出现缺字漏字、内容缺失、排版错乱等情况,有可能是净化规则或简繁转换出现问题。
 * 漫画源看书显示乱码,**阅读与其他软件的源并不通用**,请导入阅读的支持的漫画源!
 
-**2022/02/08**
+**2022/02/09**
 
 * 校验失效分组具体到搜索发现目录正文 by Xwite
 * txt文件初次解析目录不选择禁用的正则
 * txt单章字数超102400均分txt,添加开关 by Xwite
 * 修复tts被回收后无法继续朗读的bug,重新初始化tts
 * webDav备份支持自定义文件夹
+* 其它一些优化
 
 **2022/02/03**
 

+ 19 - 5
app/src/main/java/io/legado/app/data/entities/Book.kt

@@ -6,6 +6,7 @@ import io.legado.app.constant.AppPattern
 import io.legado.app.constant.BookType
 import io.legado.app.data.appDb
 import io.legado.app.help.AppConfig
+import io.legado.app.help.ReadBookConfig
 import io.legado.app.model.ReadBook
 import io.legado.app.utils.GSON
 import io.legado.app.utils.MD5Utils
@@ -149,7 +150,7 @@ data class Book(
     }
 
     fun getUseReplaceRule(): Boolean {
-        return config().useReplaceRule
+        return config().useReplaceRule ?: AppConfig.replaceEnableDefault
     }
 
     fun getReSegment(): Boolean {
@@ -169,10 +170,14 @@ data class Book(
     }
 
     fun getPageAnim(): Int {
-        return config().pageAnim
+        var pageAnim = config().pageAnim ?: ReadBookConfig.pageAnim
+        if (pageAnim < 0) {
+            pageAnim = ReadBookConfig.pageAnim
+        }
+        return pageAnim
     }
 
-    fun setPageAnim(pageAnim: Int) {
+    fun setPageAnim(pageAnim: Int?) {
         config().pageAnim = pageAnim
     }
 
@@ -184,6 +189,14 @@ data class Book(
         config().imageStyle = imageStyle
     }
 
+    fun setTtsEngine(ttsEngine: String?) {
+        config().ttsEngine = ttsEngine
+    }
+
+    fun getTtsEngine(): String? {
+        return config().ttsEngine
+    }
+
     fun getDelTag(tag: Long): Boolean {
         return config().delTag and tag == tag
     }
@@ -276,12 +289,13 @@ data class Book(
     @Parcelize
     data class ReadConfig(
         var reverseToc: Boolean = false,
-        var pageAnim: Int = -1,
+        var pageAnim: Int? = null,
         var reSegment: Boolean = false,
         var limitContentLength: Boolean = true, //txt规则解析目录时超过规定的最大字数时均分txt
         var imageStyle: String? = null,
-        var useReplaceRule: Boolean = AppConfig.replaceEnableDefault,// 正文使用净化替换规则
+        var useReplaceRule: Boolean? = null,// 正文使用净化替换规则
         var delTag: Long = 0L,//去除标签
+        var ttsEngine: String? = null,
     ) : Parcelable
 
     class Converters {

+ 2 - 1
app/src/main/java/io/legado/app/data/entities/BookChapter.kt

@@ -16,7 +16,6 @@ import kotlinx.parcelize.IgnoredOnParcel
 import kotlinx.parcelize.Parcelize
 import splitties.init.appCtx
 
-@Suppress("unused")
 @Parcelize
 @Entity(
     tableName = "chapters",
@@ -124,8 +123,10 @@ data class BookChapter(
         }
     }
 
+    @Suppress("unused")
     fun getFileName(): String = String.format("%05d-%s.nb", index, MD5Utils.md5Encode16(title))
 
+    @Suppress("unused")
     fun getFontName(): String = String.format("%05d-%s.ttf", index, MD5Utils.md5Encode16(title))
 }
 

+ 2 - 1
app/src/main/java/io/legado/app/model/ReadAloud.kt

@@ -14,10 +14,11 @@ import splitties.init.appCtx
 
 object ReadAloud {
     private var aloudClass: Class<*> = getReadAloudClass()
+    val ttsEngine get() = ReadBook.book?.getTtsEngine() ?: AppConfig.ttsEngine
     var httpTTS: HttpTTS? = null
 
     private fun getReadAloudClass(): Class<*> {
-        val ttsEngine = AppConfig.ttsEngine
+        val ttsEngine = ttsEngine
         if (ttsEngine.isNullOrBlank()) {
             return TTSReadAloudService::class.java
         }

+ 1 - 7
app/src/main/java/io/legado/app/model/ReadBook.kt

@@ -402,13 +402,7 @@ object ReadBook : CoroutineScope by MainScope() {
     }
 
     fun pageAnim(): Int {
-        book?.let {
-            return if (it.getPageAnim() < 0)
-                ReadBookConfig.pageAnim
-            else
-                it.getPageAnim()
-        }
-        return ReadBookConfig.pageAnim
+        return book?.getPageAnim() ?: ReadBookConfig.pageAnim
     }
 
     fun setCharset(charset: String) {

+ 2 - 1
app/src/main/java/io/legado/app/service/TTSReadAloudService.kt

@@ -12,6 +12,7 @@ import io.legado.app.help.AppConfig
 import io.legado.app.help.MediaHelp
 import io.legado.app.lib.dialogs.SelectItem
 import io.legado.app.model.NoStackTraceException
+import io.legado.app.model.ReadAloud
 import io.legado.app.model.ReadBook
 import io.legado.app.utils.*
 import java.util.*
@@ -36,7 +37,7 @@ class TTSReadAloudService : BaseReadAloudService(), TextToSpeech.OnInitListener
     @Synchronized
     private fun initTts() {
         ttsInitFinish = false
-        val engine = GSON.fromJsonObject<SelectItem<String>>(AppConfig.ttsEngine)?.value
+        val engine = GSON.fromJsonObject<SelectItem<String>>(ReadAloud.ttsEngine)?.value
         textToSpeech = if (engine.isNullOrBlank()) {
             TextToSpeech(this, this)
         } else {

+ 1 - 1
app/src/main/java/io/legado/app/ui/book/read/config/ReadStyleDialog.kt

@@ -126,7 +126,7 @@ class ReadStyleDialog : BaseDialogFragment(R.layout.dialog_read_book_style),
             TipConfigDialog().show(childFragmentManager, "tipConfigDialog")
         }
         rgPageAnim.setOnCheckedChangeListener { _, checkedId ->
-            ReadBook.book?.setPageAnim(-1)
+            ReadBook.book?.setPageAnim(null)
             ReadBookConfig.pageAnim = binding.rgPageAnim.getIndexById(checkedId)
             callBack?.upPageAnim()
             ReadBook.loadContent(false)

+ 0 - 1
app/src/main/java/io/legado/app/ui/book/toc/BookmarkFragment.kt

@@ -17,7 +17,6 @@ import io.legado.app.utils.setEdgeEffectColor
 import io.legado.app.utils.showDialogFragment
 import io.legado.app.utils.viewbindingdelegate.viewBinding
 import kotlinx.coroutines.Job
-import kotlinx.coroutines.flow.collect
 import kotlinx.coroutines.launch
 
 

+ 32 - 29
app/src/main/java/io/legado/app/ui/book/toc/ChapterListAdapter.kt

@@ -6,39 +6,41 @@ import androidx.recyclerview.widget.DiffUtil
 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.help.ContentProcessor
 import io.legado.app.lib.theme.ThemeUtils
 import io.legado.app.lib.theme.accentColor
 import io.legado.app.utils.getCompatColor
 import io.legado.app.utils.gone
 import io.legado.app.utils.visible
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Deferred
+import kotlinx.coroutines.launch
 
-class ChapterListAdapter(context: Context, val callback: Callback) :
-    RecyclerAdapter<BookChapter, ItemChapterListBinding>(context) {
+class ChapterListAdapter(context: Context, val callback: Callback, private val scope: CoroutineScope) :
+    RecyclerAdapter<Pair<BookChapter, Deferred<String>>, ItemChapterListBinding>(context) {
 
-    val replaceRules
-        get() = callback.book?.let {
-            ContentProcessor.get(it.name, it.origin).getReplaceRules()
-        }
-    val useReplace get() = callback.book?.getUseReplaceRule() == true
     val cacheFileNames = hashSetOf<String>()
-    val diffCallBack = object : DiffUtil.ItemCallback<BookChapter>() {
+    val diffCallBack = object : DiffUtil.ItemCallback<Pair<BookChapter, Deferred<String>>>() {
 
-        override fun areItemsTheSame(oldItem: BookChapter, newItem: BookChapter): Boolean {
-            return oldItem.index == newItem.index
+        override fun areItemsTheSame(
+            oldItem: Pair<BookChapter, Deferred<String>>,
+            newItem: Pair<BookChapter, Deferred<String>>
+        ): Boolean {
+            return oldItem.first.index == newItem.first.index
         }
 
-        override fun areContentsTheSame(oldItem: BookChapter, newItem: BookChapter): Boolean {
-            return oldItem.bookUrl == newItem.bookUrl
-                && oldItem.url == newItem.url
-                && oldItem.isVip == newItem.isVip
-                && oldItem.isPay == newItem.isPay
-                && oldItem.title == newItem.title
-                && oldItem.tag == newItem.tag
-                && oldItem.isVolume == newItem.isVolume
+        override fun areContentsTheSame(
+            oldItem: Pair<BookChapter, Deferred<String>>,
+            newItem: Pair<BookChapter, Deferred<String>>
+        ): Boolean {
+            return oldItem.first.bookUrl == newItem.first.bookUrl
+                && oldItem.first.url == newItem.first.url
+                && oldItem.first.isVip == newItem.first.isVip
+                && oldItem.first.isPay == newItem.first.isPay
+                && oldItem.first.title == newItem.first.title
+                && oldItem.first.tag == newItem.first.tag
+                && oldItem.first.isVolume == newItem.first.isVolume
         }
 
     }
@@ -50,20 +52,22 @@ class ChapterListAdapter(context: Context, val callback: Callback) :
     override fun convert(
         holder: ItemViewHolder,
         binding: ItemChapterListBinding,
-        item: BookChapter,
+        item: Pair<BookChapter, Deferred<String>>,
         payloads: MutableList<Any>
     ) {
         binding.run {
-            val isDur = callback.durChapterIndex() == item.index
-            val cached = callback.isLocalBook || cacheFileNames.contains(item.getFileName())
+            val isDur = callback.durChapterIndex() == item.first.index
+            val cached = callback.isLocalBook || cacheFileNames.contains(item.first.getFileName())
             if (payloads.isEmpty()) {
                 if (isDur) {
                     tvChapterName.setTextColor(context.accentColor)
                 } else {
                     tvChapterName.setTextColor(context.getCompatColor(R.color.primaryText))
                 }
-                tvChapterName.text = item.getDisplayTitle(replaceRules, useReplace)
-                if (item.isVolume) {
+                scope.launch {
+                    tvChapterName.text = item.second.await()
+                }
+                if (item.first.isVolume) {
                     //卷名,如第一卷 突出显示
                     tvChapterItem.setBackgroundColor(context.getCompatColor(R.color.btn_bg_press))
                 } else {
@@ -71,9 +75,9 @@ class ChapterListAdapter(context: Context, val callback: Callback) :
                     tvChapterItem.background =
                         ThemeUtils.resolveDrawable(context, android.R.attr.selectableItemBackground)
                 }
-                if (!item.tag.isNullOrEmpty() && !item.isVolume) {
+                if (!item.first.tag.isNullOrEmpty() && !item.first.isVolume) {
                     //卷名不显示tag(更新时间规则)
-                    tvTag.text = item.tag
+                    tvTag.text = item.first.tag
                     tvTag.visible()
                 } else {
                     tvTag.gone()
@@ -88,7 +92,7 @@ class ChapterListAdapter(context: Context, val callback: Callback) :
     override fun registerListener(holder: ItemViewHolder, binding: ItemChapterListBinding) {
         holder.itemView.setOnClickListener {
             getItem(holder.layoutPosition)?.let {
-                callback.openChapter(it)
+                callback.openChapter(it.first)
             }
         }
     }
@@ -104,7 +108,6 @@ class ChapterListAdapter(context: Context, val callback: Callback) :
         }
 
     interface Callback {
-        val book: Book?
         val isLocalBook: Boolean
         fun openChapter(bookChapter: BookChapter)
         fun durChapterIndex(): Int

+ 19 - 9
app/src/main/java/io/legado/app/ui/book/toc/ChapterListFragment.kt

@@ -14,6 +14,7 @@ import io.legado.app.data.entities.Book
 import io.legado.app.data.entities.BookChapter
 import io.legado.app.databinding.FragmentChapterListBinding
 import io.legado.app.help.BookHelp
+import io.legado.app.help.ContentProcessor
 import io.legado.app.lib.theme.bottomBackground
 import io.legado.app.lib.theme.getPrimaryTextColor
 import io.legado.app.ui.widget.recycler.UpLinearLayoutManager
@@ -21,12 +22,9 @@ import io.legado.app.ui.widget.recycler.VerticalDivider
 import io.legado.app.utils.ColorUtils
 import io.legado.app.utils.observeEvent
 import io.legado.app.utils.viewbindingdelegate.viewBinding
+import kotlinx.coroutines.*
 import kotlinx.coroutines.Dispatchers.IO
 import kotlinx.coroutines.Dispatchers.Main
-import kotlinx.coroutines.Job
-import kotlinx.coroutines.flow.collect
-import kotlinx.coroutines.launch
-import kotlinx.coroutines.withContext
 
 class ChapterListFragment : VMBaseFragment<TocViewModel>(R.layout.fragment_chapter_list),
     ChapterListAdapter.Callback,
@@ -34,7 +32,7 @@ class ChapterListFragment : VMBaseFragment<TocViewModel>(R.layout.fragment_chapt
     override val viewModel by activityViewModels<TocViewModel>()
     private val binding by viewBinding(FragmentChapterListBinding::bind)
     private val mLayoutManager by lazy { UpLinearLayoutManager(requireContext()) }
-    private val adapter by lazy { ChapterListAdapter(requireContext(), this) }
+    private val adapter by lazy { ChapterListAdapter(requireContext(), this, this) }
     private var durChapterIndex = 0
     private var tocFlowJob: Job? = null
 
@@ -112,7 +110,22 @@ class ChapterListFragment : VMBaseFragment<TocViewModel>(R.layout.fragment_chapt
                 else -> appDb.bookChapterDao.flowSearch(viewModel.bookUrl, searchKey)
             }.collect {
                 if (!(searchKey.isNullOrBlank() && it.isEmpty())) {
-                    adapter.setItems(it, adapter.diffCallBack)
+                    binding.rotateLoading.show()
+                    val data = withContext(IO) {
+                        val replaces = viewModel.bookData.value?.let { book ->
+                            ContentProcessor.get(book.name, book.origin).getReplaceRules()
+                        }
+                        val useReplace = viewModel.bookData.value?.getUseReplaceRule() == true
+                        it.map { chapter ->
+                            Pair(
+                                chapter,
+                                async(IO) {
+                                    chapter.getDisplayTitle(replaces, useReplace)
+                                })
+                        }
+                    }
+                    binding.rotateLoading.hide()
+                    adapter.setItems(data, adapter.diffCallBack)
                     if (searchKey.isNullOrBlank() && mLayoutManager.findFirstVisibleItemPosition() < 0) {
                         mLayoutManager.scrollToPositionWithOffset(durChapterIndex, 0)
                     }
@@ -121,9 +134,6 @@ class ChapterListFragment : VMBaseFragment<TocViewModel>(R.layout.fragment_chapt
         }
     }
 
-    override val book: Book?
-        get() = viewModel.bookData.value
-
     override val isLocalBook: Boolean
         get() = viewModel.bookData.value?.isLocalBook() == true
 

+ 10 - 0
app/src/main/res/layout/fragment_chapter_list.xml

@@ -14,6 +14,16 @@
         app:layout_constraintTop_toTopOf="parent"
         app:layout_constraintBottom_toTopOf="@+id/ll_chapter_base_info" />
 
+    <io.legado.app.ui.widget.anima.RotateLoading
+        android:id="@+id/rotate_loading"
+        android:layout_width="60dp"
+        android:layout_height="60dp"
+        android:visibility="gone"
+        app:layout_constraintTop_toTopOf="@id/recycler_view"
+        app:layout_constraintBottom_toBottomOf="@+id/recycler_view"
+        app:layout_constraintLeft_toLeftOf="parent"
+        app:layout_constraintRight_toRightOf="parent" />
+
     <LinearLayout
         android:id="@+id/ll_chapter_base_info"
         android:layout_width="match_parent"