Explorar el Código

Merge branch 'gedoor:master' into master

Xwite hace 4 años
padre
commit
0b84889345

+ 5 - 0
app/src/main/assets/updateLog.md

@@ -11,6 +11,11 @@
 * 正文出现缺字漏字、内容缺失、排版错乱等情况,有可能是净化规则或简繁转换出现问题。
 * 漫画源看书显示乱码,**阅读与其他软件的源并不通用**,请导入阅读的支持的漫画源!
 
+**2022/02/10**
+
+* 可以单独给书籍设置朗读tts
+* 目录界面菜单添加替换开关,开启替换加载时间会长一些
+
 **2022/02/09**
 
 * 校验失效分组具体到搜索发现目录正文 by Xwite

+ 1 - 0
app/src/main/java/io/legado/app/constant/PreferKey.kt

@@ -93,6 +93,7 @@ object PreferKey {
     const val defaultBookTreeUri = "defaultBookTreeUri"
     const val checkSource = "checkSource"
     const val uploadRule = "uploadRule"
+    const val tocUiUseReplace = "tocUiUseReplace"
 
     const val cPrimary = "colorPrimary"
     const val cAccent = "colorAccent"

+ 6 - 0
app/src/main/java/io/legado/app/help/AppConfig.kt

@@ -250,6 +250,12 @@ object AppConfig : SharedPreferences.OnSharedPreferenceChangeListener {
             appCtx.putPrefInt(PreferKey.webPort, value)
         }
 
+    var tocUiUseReplace: Boolean
+        get() = appCtx.getPrefBoolean(PreferKey.tocUiUseReplace)
+        set(value) {
+            appCtx.putPrefBoolean(PreferKey.tocUiUseReplace, value)
+        }
+
     val autoChangeSource: Boolean
         get() = appCtx.getPrefBoolean(PreferKey.autoChangeSource, true)
 

+ 1 - 0
app/src/main/java/io/legado/app/help/DirectLinkUpload.kt

@@ -15,6 +15,7 @@ object DirectLinkUpload {
     private const val downloadUrlRuleKey = "directLinkDownloadUrlRule"
     private const val summaryKey = "directSummary"
 
+    @Throws(NoStackTraceException::class)
     suspend fun upLoad(fileName: String, file: Any, contentType: String): String {
         val url = getUploadUrl()
         if (url.isNullOrBlank()) {

+ 3 - 1
app/src/main/java/io/legado/app/service/CheckSourceService.kt

@@ -19,6 +19,7 @@ import io.legado.app.utils.activityPendingIntent
 import io.legado.app.utils.postEvent
 import io.legado.app.utils.servicePendingIntent
 import io.legado.app.utils.toastOnUi
+import kotlinx.coroutines.Dispatchers.IO
 import kotlinx.coroutines.asCoroutineDispatcher
 import java.util.concurrent.Executors
 import kotlin.math.min
@@ -204,8 +205,9 @@ class CheckSourceService : BaseService() {
                         "" else "\n\n${source.bookSourceComment}"
                 Debug.updateFinalMessage(source.bookSourceUrl, "校验失败:${it.localizedMessage}")
             }.onSuccess(searchCoroutine) {
+                source.removeGroup("失效")
                 Debug.updateFinalMessage(source.bookSourceUrl, "校验成功")
-            }.onFinally(searchCoroutine) {
+            }.onFinally(IO) {
                 source.respondTime = Debug.getRespondTime(source.bookSourceUrl)
                 appDb.bookSourceDao.update(source)
                 onNext(source.bookSourceUrl, source.bookSourceName)

+ 38 - 20
app/src/main/java/io/legado/app/ui/book/read/config/SpeakEngineDialog.kt

@@ -5,6 +5,7 @@ import android.os.Bundle
 import android.view.MenuItem
 import android.view.View
 import android.view.ViewGroup
+import android.widget.RadioButton
 import androidx.appcompat.widget.Toolbar
 import androidx.fragment.app.viewModels
 import androidx.recyclerview.widget.LinearLayoutManager
@@ -21,15 +22,17 @@ import io.legado.app.help.AppConfig
 import io.legado.app.help.DirectLinkUpload
 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.lib.theme.primaryColor
+import io.legado.app.model.ReadAloud
+import io.legado.app.model.ReadBook
 import io.legado.app.ui.document.HandleFileContract
 import io.legado.app.utils.*
 import io.legado.app.utils.viewbindingdelegate.viewBinding
-import kotlinx.coroutines.flow.collect
 import kotlinx.coroutines.launch
 
-
+/**
+ * tts引擎管理
+ */
 class SpeakEngineDialog : BaseDialogFragment(R.layout.dialog_recycler_view),
     Toolbar.OnMenuItemClickListener {
 
@@ -37,7 +40,8 @@ class SpeakEngineDialog : BaseDialogFragment(R.layout.dialog_recycler_view),
     private val viewModel: SpeakEngineViewModel by viewModels()
     private val ttsUrlKey = "ttsUrlKey"
     private val adapter by lazy { Adapter(requireContext()) }
-    private var ttsEngine: String? = AppConfig.ttsEngine
+    private var ttsEngine: String? = ReadAloud.ttsEngine
+    private val sysTtsViews = arrayListOf<RadioButton>()
     private val importDocResult = registerForActivityResult(HandleFileContract()) {
         it.uri?.let { uri ->
             viewModel.importLocal(uri)
@@ -80,13 +84,32 @@ class SpeakEngineDialog : BaseDialogFragment(R.layout.dialog_recycler_view),
         recyclerView.setEdgeEffectColor(primaryColor)
         recyclerView.layoutManager = LinearLayoutManager(requireContext())
         recyclerView.adapter = adapter
-        tvFooterLeft.setText(R.string.system_tts)
+        viewModel.sysEngines.forEach { engine ->
+            adapter.addHeaderView {
+                ItemHttpTtsBinding.inflate(layoutInflater, recyclerView, false).apply {
+                    sysTtsViews.add(cbName)
+                    ivEdit.gone()
+                    ivMenuDelete.gone()
+                    cbName.text = engine.label
+                    cbName.tag = engine.name
+                    cbName.isChecked =
+                        GSON.fromJsonObject<SelectItem<String>>(ttsEngine)?.value == cbName.tag
+                    cbName.setOnClickListener {
+                        upTts(GSON.toJson(SelectItem(engine.label, engine.name)))
+                    }
+                }
+            }
+        }
+        tvFooterLeft.setText(R.string.book)
         tvFooterLeft.visible()
         tvFooterLeft.setOnClickListener {
-            selectSysTts()
+            ReadBook.book?.setTtsEngine(ttsEngine)
+            dismissAllowingStateLoss()
         }
+        tvOk.setText(R.string.general)
         tvOk.visible()
         tvOk.setOnClickListener {
+            ReadBook.book?.setTtsEngine(null)
             AppConfig.ttsEngine = ttsEngine
             dismissAllowingStateLoss()
         }
@@ -131,18 +154,6 @@ class SpeakEngineDialog : BaseDialogFragment(R.layout.dialog_recycler_view),
         return true
     }
 
-    private fun selectSysTts() {
-        val ttsItems = viewModel.tts.engines.map {
-            SelectItem(it.label, it.name)
-        }
-        context?.selector(R.string.system_tts, ttsItems) { _, item, _ ->
-            AppConfig.ttsEngine = GSON.toJson(item)
-            ttsEngine = null
-            adapter.notifyItemRangeChanged(0, adapter.itemCount)
-            dismissAllowingStateLoss()
-        }
-    }
-
     private fun importAlert() {
         val aCache = ACache.get(requireContext(), cacheDir = false)
         val cacheUrls: MutableList<String> = aCache
@@ -171,6 +182,14 @@ class SpeakEngineDialog : BaseDialogFragment(R.layout.dialog_recycler_view),
         }
     }
 
+    private fun upTts(tts: String) {
+        ttsEngine = tts
+        sysTtsViews.forEach {
+            it.isChecked = GSON.fromJsonObject<SelectItem<String>>(ttsEngine)?.value == it.tag
+        }
+        adapter.notifyItemRangeChanged(adapter.getHeaderCount(), adapter.itemCount)
+    }
+
     inner class Adapter(context: Context) :
         RecyclerAdapter<HttpTTS, ItemHttpTtsBinding>(context) {
 
@@ -194,8 +213,7 @@ class SpeakEngineDialog : BaseDialogFragment(R.layout.dialog_recycler_view),
             binding.run {
                 cbName.setOnClickListener {
                     getItemByLayoutPosition(holder.layoutPosition)?.let { httpTTS ->
-                        ttsEngine = httpTTS.id.toString()
-                        notifyItemRangeChanged(getHeaderCount(), itemCount)
+                        upTts(httpTTS.id.toString())
                     }
                 }
                 ivEdit.setOnClickListener {

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

@@ -18,7 +18,7 @@ import io.legado.app.utils.toastOnUi
 
 class SpeakEngineViewModel(application: Application) : BaseViewModel(application) {
 
-    val tts = TextToSpeech(context, null)
+    val sysEngines = TextToSpeech(context, null).engines
 
     fun importDefault() {
         execute {

+ 3 - 2
app/src/main/java/io/legado/app/ui/book/toc/ChapterListAdapter.kt

@@ -17,7 +17,7 @@ import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.Deferred
 import kotlinx.coroutines.launch
 
-class ChapterListAdapter(context: Context, val callback: Callback, private val scope: CoroutineScope) :
+class ChapterListAdapter(context: Context, val callback: Callback) :
     RecyclerAdapter<Pair<BookChapter, Deferred<String>>, ItemChapterListBinding>(context) {
 
     val cacheFileNames = hashSetOf<String>()
@@ -64,7 +64,7 @@ class ChapterListAdapter(context: Context, val callback: Callback, private val s
                 } else {
                     tvChapterName.setTextColor(context.getCompatColor(R.color.primaryText))
                 }
-                scope.launch {
+                callback.scope.launch {
                     tvChapterName.text = item.second.await()
                 }
                 if (item.first.isVolume) {
@@ -108,6 +108,7 @@ class ChapterListAdapter(context: Context, val callback: Callback, private val s
         }
 
     interface Callback {
+        val scope: CoroutineScope
         val isLocalBook: Boolean
         fun openChapter(bookChapter: BookChapter)
         fun durChapterIndex(): Int

+ 7 - 2
app/src/main/java/io/legado/app/ui/book/toc/ChapterListFragment.kt

@@ -13,6 +13,7 @@ import io.legado.app.data.appDb
 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.AppConfig
 import io.legado.app.help.BookHelp
 import io.legado.app.help.ContentProcessor
 import io.legado.app.lib.theme.bottomBackground
@@ -32,7 +33,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, this) }
+    private val adapter by lazy { ChapterListAdapter(requireContext(), this) }
     private var durChapterIndex = 0
     private var tocFlowJob: Job? = null
 
@@ -115,7 +116,8 @@ class ChapterListFragment : VMBaseFragment<TocViewModel>(R.layout.fragment_chapt
                         val replaces = viewModel.bookData.value?.let { book ->
                             ContentProcessor.get(book.name, book.origin).getReplaceRules()
                         }
-                        val useReplace = viewModel.bookData.value?.getUseReplaceRule() == true
+                        val useReplace =
+                            AppConfig.tocUiUseReplace && viewModel.bookData.value?.getUseReplaceRule() == true
                         it.map { chapter ->
                             Pair(
                                 chapter,
@@ -134,6 +136,9 @@ class ChapterListFragment : VMBaseFragment<TocViewModel>(R.layout.fragment_chapt
         }
     }
 
+    override val scope: CoroutineScope
+        get() = this
+
     override val isLocalBook: Boolean
         get() = viewModel.bookData.value?.isLocalBook() == true
 

+ 10 - 0
app/src/main/java/io/legado/app/ui/book/toc/TocActivity.kt

@@ -15,6 +15,7 @@ import com.google.android.material.tabs.TabLayout
 import io.legado.app.R
 import io.legado.app.base.VMBaseActivity
 import io.legado.app.databinding.ActivityChapterListBinding
+import io.legado.app.help.AppConfig
 import io.legado.app.lib.theme.accentColor
 import io.legado.app.lib.theme.primaryTextColor
 import io.legado.app.ui.about.AppLogDialog
@@ -74,6 +75,11 @@ class TocActivity : VMBaseActivity<ActivityChapterListBinding, TocViewModel>() {
         return super.onCompatCreateOptionsMenu(menu)
     }
 
+    override fun onMenuOpened(featureId: Int, menu: Menu): Boolean {
+        menu.findItem(R.id.menu_use_replace)?.isChecked = AppConfig.tocUiUseReplace
+        return super.onMenuOpened(featureId, menu)
+    }
+
     override fun onCompatOptionsItemSelected(item: MenuItem): Boolean {
         when (item.itemId) {
             R.id.menu_reverse_toc -> viewModel.reverseToc {
@@ -82,6 +88,10 @@ class TocActivity : VMBaseActivity<ActivityChapterListBinding, TocViewModel>() {
                     putExtra("chapterPos", it.durChapterPos)
                 })
             }
+            R.id.menu_use_replace -> {
+                AppConfig.tocUiUseReplace = !item.isChecked
+                viewModel.chapterCallBack?.upChapterList(null)
+            }
             R.id.menu_log -> showDialogFragment<AppLogDialog>()
         }
         return super.onCompatOptionsItemSelected(item)

+ 5 - 4
app/src/main/java/io/legado/app/ui/main/explore/ExploreAdapter.kt

@@ -23,7 +23,7 @@ import io.legado.app.utils.*
 import kotlinx.coroutines.CoroutineScope
 import splitties.views.onLongClick
 
-class ExploreAdapter(context: Context, private val scope: CoroutineScope, val callBack: CallBack) :
+class ExploreAdapter(context: Context, val callBack: CallBack) :
     RecyclerAdapter<BookSource, ItemFindBookBinding>(context) {
 
     private val recycler = arrayListOf<View>()
@@ -56,7 +56,7 @@ class ExploreAdapter(context: Context, private val scope: CoroutineScope, val ca
                 if (scrollTo >= 0) {
                     callBack.scrollTo(scrollTo)
                 }
-                Coroutine.async(scope) {
+                Coroutine.async(callBack.scope) {
                     item.exploreKinds
                 }.onSuccess { kindList ->
                     upKindList(flexbox, item.bookSourceUrl, kindList)
@@ -167,12 +167,12 @@ class ExploreAdapter(context: Context, private val scope: CoroutineScope, val ca
                     putExtra("type", "bookSource")
                     putExtra("key", source.bookSourceUrl)
                 }
-                R.id.menu_refresh -> Coroutine.async(scope) {
+                R.id.menu_refresh -> Coroutine.async(callBack.scope) {
                     ACache.get(context, "explore").remove(source.bookSourceUrl)
                 }.onSuccess {
                     callBack.refreshData()
                 }
-                R.id.menu_del -> Coroutine.async(scope) {
+                R.id.menu_del -> Coroutine.async(callBack.scope) {
                     appDb.bookSourceDao.delete(source)
                 }
             }
@@ -183,6 +183,7 @@ class ExploreAdapter(context: Context, private val scope: CoroutineScope, val ca
     }
 
     interface CallBack {
+        val scope: CoroutineScope
         fun refreshData()
         fun scrollTo(pos: Int)
         fun openExplore(sourceUrl: String, title: String, exploreUrl: String?)

+ 5 - 1
app/src/main/java/io/legado/app/ui/main/explore/ExploreFragment.kt

@@ -24,6 +24,7 @@ import io.legado.app.ui.book.explore.ExploreShowActivity
 import io.legado.app.ui.book.source.edit.BookSourceEditActivity
 import io.legado.app.utils.*
 import io.legado.app.utils.viewbindingdelegate.viewBinding
+import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.Job
 import kotlinx.coroutines.flow.collect
 import kotlinx.coroutines.launch
@@ -35,7 +36,7 @@ class ExploreFragment : VMBaseFragment<ExploreViewModel>(R.layout.fragment_explo
     ExploreAdapter.CallBack {
     override val viewModel by viewModels<ExploreViewModel>()
     private val binding by viewBinding(FragmentExploreBinding::bind)
-    private val adapter by lazy { ExploreAdapter(requireContext(), lifecycleScope, this) }
+    private val adapter by lazy { ExploreAdapter(requireContext(), this) }
     private val linearLayoutManager by lazy { LinearLayoutManager(context) }
     private val searchView: SearchView by lazy {
         binding.titleBar.findViewById(R.id.search_view)
@@ -142,6 +143,9 @@ class ExploreFragment : VMBaseFragment<ExploreViewModel>(R.layout.fragment_explo
         }
     }
 
+    override val scope: CoroutineScope
+        get() = lifecycleScope
+
     override fun onCompatOptionsItemSelected(item: MenuItem) {
         super.onCompatOptionsItemSelected(item)
         if (item.groupId == R.id.menu_group_text) {

+ 8 - 2
app/src/main/res/menu/book_toc.xml

@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="utf-8"?>
-<menu xmlns:tools="http://schemas.android.com/tools"
-    xmlns:android="http://schemas.android.com/apk/res/android"
+<menu xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:app="http://schemas.android.com/apk/res-auto"
+    xmlns:tools="http://schemas.android.com/tools"
     tools:ignore="AlwaysShowAction">
 
     <item
@@ -15,6 +15,12 @@
         android:title="@string/reverse_toc"
         app:showAsAction="never" />
 
+    <item
+        android:id="@+id/menu_use_replace"
+        android:checkable="true"
+        android:title="@string/use_replace"
+        app:showAsAction="never" />
+
     <item
         android:id="@+id/menu_log"
         android:title="@string/log"

+ 2 - 0
app/src/main/res/values-es-rES/strings.xml

@@ -928,5 +928,7 @@
     <string name="check_source_config_summary">校验超时: %1$s秒\n校验项目:%2$s</string>
     <string name="record_debug_log">记录调试日志</string>
     <string name="sub_dir">子文件夹</string>
+    <string name="general">全局</string>
+    <string name="use_replace">使用替换</string>
     <!-- string end -->
 </resources>

+ 2 - 0
app/src/main/res/values-ja-rJP/strings.xml

@@ -931,5 +931,7 @@
     <string name="check_source_config_summary">校验超时: %1$s秒\n校验项目:%2$s</string>
     <string name="record_debug_log">记录调试日志</string>
     <string name="sub_dir">子文件夹</string>
+    <string name="general">全局</string>
+    <string name="use_replace">使用替换</string>
     <!-- string end -->
 </resources>

+ 4 - 0
app/src/main/res/values-pt-rBR/strings.xml

@@ -918,6 +918,8 @@
     <string name="select_book_folder">选择保存书籍的文件夹</string>
     <string name="user_agent">用户代理</string>
     <string name="bg_alpha">背景透明度</string>
+    <string name="limit_content_length">限制正文长度</string>
+    <string name="need_more_time_load_content">正文长度过长时,加载正文可能会花费更多时间</string>
 
     <!-- check source config string -->
     <string name="check_source_config">校验设置</string>
@@ -929,5 +931,7 @@
     <string name="check_source_config_summary">校验超时: %1$s秒\n校验项目:%2$s</string>
     <string name="record_debug_log">记录调试日志</string>
     <string name="sub_dir">子文件夹</string>
+    <string name="general">全局</string>
+    <string name="use_replace">使用替换</string>
     <!-- string end -->
 </resources>

+ 2 - 0
app/src/main/res/values-zh-rHK/strings.xml

@@ -928,5 +928,7 @@
     <string name="check_source_config_summary">校验超时: %1$s秒\n校验项目:%2$s</string>
     <string name="record_debug_log">记录调试日志</string>
     <string name="sub_dir">子文件夹</string>
+    <string name="general">全局</string>
+    <string name="use_replace">使用替换</string>
     <!-- string end -->
 </resources>

+ 2 - 0
app/src/main/res/values-zh-rTW/strings.xml

@@ -930,5 +930,7 @@
     <string name="check_source_config_summary">校验超时: %1$s秒\n校验项目:%2$s</string>
     <string name="record_debug_log">记录调试日志</string>
     <string name="sub_dir">子文件夹</string>
+    <string name="general">全局</string>
+    <string name="use_replace">使用替换</string>
     <!-- string end -->
 </resources>

+ 2 - 0
app/src/main/res/values-zh/strings.xml

@@ -930,5 +930,7 @@
     <string name="check_source_config_summary">校验超时: %1$s秒\n校验项目:%2$s</string>
     <string name="record_debug_log">记录调试日志</string>
     <string name="sub_dir">子文件夹</string>
+    <string name="general">全局</string>
+    <string name="use_replace">使用替换</string>
     <!-- string end -->
 </resources>

+ 4 - 2
app/src/main/res/values/strings.xml

@@ -918,8 +918,8 @@
     <string name="book_tree_uri_t">书籍保存位置</string>
     <string name="book_tree_uri_s">从其它应用打开的书籍保存位置</string>
     <string name="select_book_folder">选择保存书籍的文件夹</string>
-    <string name="user_agent">用户代理</string>
-    <string name="bg_alpha">背景透明度</string>
+    <string name="user_agent">User agent</string>
+    <string name="bg_alpha">Background alpha</string>
 
     <!-- check source config string -->
     <string name="check_source_config">校验设置</string>
@@ -931,5 +931,7 @@
     <string name="check_source_config_summary">校验超时: %1$s秒\n校验项目:%2$s</string>
     <string name="record_debug_log">记录调试日志</string>
     <string name="sub_dir">Sub dir</string>
+    <string name="general">General</string>
+    <string name="use_replace">Use replace</string>
     <!-- string end -->
 </resources>