Răsfoiți Sursa

[优化] 优化听书相关代码

HapeLee 9 luni în urmă
părinte
comite
a5a88fb7b2

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

@@ -69,6 +69,7 @@ object PreferKey {
     const val webDavAccount = "web_dav_account"
     const val webDavAccount = "web_dav_account"
     const val webDavPassword = "web_dav_password"
     const val webDavPassword = "web_dav_password"
     const val webDavDir = "webDavDir"
     const val webDavDir = "webDavDir"
+    const val webServiceAutoStart = "webServiceAutoStart"
     const val enableCustomExport = "enableCustomExport"
     const val enableCustomExport = "enableCustomExport"
     const val exportToWebDav = "webDavCacheBackup"
     const val exportToWebDav = "webDavCacheBackup"
     const val exportNoChapterName = "exportNoChapterName"
     const val exportNoChapterName = "exportNoChapterName"
@@ -243,4 +244,6 @@ object PreferKey {
 
 
     const val showTip = "showTip"
     const val showTip = "showTip"
     const val sliderVibrator = "sliderVibrator"
     const val sliderVibrator = "sliderVibrator"
+    const val audioCacheCleanTime = "audioCacheCleanTime"
+    const val audioPreDownloadNum = "audioPreDownloadNum"
 }
 }

+ 8 - 34
app/src/main/java/io/legado/app/help/config/AppConfig.kt

@@ -20,9 +20,6 @@ import io.legado.app.utils.removePref
 import io.legado.app.utils.sysConfiguration
 import io.legado.app.utils.sysConfiguration
 import io.legado.app.utils.toastOnUi
 import io.legado.app.utils.toastOnUi
 import splitties.init.appCtx
 import splitties.init.appCtx
-// 【新增引用】为了支持文件清理操作
-import java.io.File
-import io.legado.app.utils.FileUtils
 
 
 @Suppress("MemberVisibilityCanBePrivate", "ConstPropertyName")
 @Suppress("MemberVisibilityCanBePrivate", "ConstPropertyName")
 object AppConfig : SharedPreferences.OnSharedPreferenceChangeListener {
 object AppConfig : SharedPreferences.OnSharedPreferenceChangeListener {
@@ -60,7 +57,7 @@ object AppConfig : SharedPreferences.OnSharedPreferenceChangeListener {
     var optimizeRender = CanvasRecorderFactory.isSupport
     var optimizeRender = CanvasRecorderFactory.isSupport
             && appCtx.getPrefBoolean(PreferKey.optimizeRender, false)
             && appCtx.getPrefBoolean(PreferKey.optimizeRender, false)
     var recordLog = appCtx.getPrefBoolean(PreferKey.recordLog)
     var recordLog = appCtx.getPrefBoolean(PreferKey.recordLog)
-
+    var webServiceAutoStart = appCtx.getPrefBoolean(PreferKey.webServiceAutoStart)
     override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences?, key: String?) {
     override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences?, key: String?) {
         when (key) {
         when (key) {
 
 
@@ -976,39 +973,16 @@ object AppConfig : SharedPreferences.OnSharedPreferenceChangeListener {
             appCtx.putPrefBoolean(PreferKey.sliderVibrator, value)
             appCtx.putPrefBoolean(PreferKey.sliderVibrator, value)
         }
         }
 
 
-    // ================= 自定义功能区域 Start =================
-
-    // 1. 听书预加载数量
-    // 逻辑:从设置里读取字符串,转成数字。如果读不到,默认返回 10。
     val audioPreDownloadNum: Int
     val audioPreDownloadNum: Int
-        get() {
-            // 注意:EditTextPreference 保存的是 String
-            val str = appCtx.getPrefString("audioPreDownloadNum")
-            return str?.toIntOrNull() ?: 10
-        }
+        get() = appCtx.getPrefInt(PreferKey.audioPreDownloadNum, 10)
+
+    val audioCacheCleanTimeOrgin: Int
+        get() = appCtx.getPrefInt(PreferKey.audioCacheCleanTime, 10)
 
 
-    // 2. 音频缓存保留时间 (返回毫秒)
-    // 逻辑:用户输入的是“分钟”,我们在这里把它乘以 60000 变成“毫秒”。
     val audioCacheCleanTime: Long
     val audioCacheCleanTime: Long
         get() {
         get() {
-            val str = appCtx.getPrefString("audioCacheCleanTime")
-            val minutes = str?.toLongOrNull() ?: 10L // 默认 10 分钟
-            return minutes * 60 * 1000L
-        }
-
-    /**
-     * 【新增】手动清理 TTS 缓存
-     * 这个方法会自动寻找 externalCacheDir(外部存储),如果找不到再找内部。
-     * 确保和 Service 里的逻辑保持一致。
-     */
-    fun clearTtsCache() {
-        val baseDir = appCtx.externalCacheDir ?: appCtx.cacheDir
-        // 清理音频文件
-        FileUtils.delete(baseDir.absolutePath + File.separator + "httpTTS")
-        // 清理数据库索引 (可选,建议一起清,防止索引还在但文件没了)
-        FileUtils.delete(baseDir.absolutePath + File.separator + "httpTTS_cache")
-    }
-
-    // ================= 自定义功能区域 End =================
+            val str = appCtx.getPrefInt(PreferKey.audioCacheCleanTime, 10)
+            return str * 60 * 1000L
+        }
 
 
 }
 }

+ 4 - 9
app/src/main/java/io/legado/app/service/HttpReadAloudService.kt

@@ -65,11 +65,9 @@ import java.io.File
 import java.io.InputStream
 import java.io.InputStream
 import java.net.ConnectException
 import java.net.ConnectException
 import java.net.SocketTimeoutException
 import java.net.SocketTimeoutException
-import kotlin.coroutines.coroutineContext
 
 
 /**
 /**
  * 在线朗读
  * 在线朗读
- * (完美匹配版:修复文件名MD5不一致 + 修复缓存不可见 + 修复0分钟不彻底清理)
  */
  */
 @SuppressLint("UnsafeOptInUsageError")
 @SuppressLint("UnsafeOptInUsageError")
 class HttpReadAloudService : BaseReadAloudService(),
 class HttpReadAloudService : BaseReadAloudService(),
@@ -78,7 +76,7 @@ class HttpReadAloudService : BaseReadAloudService(),
         ExoPlayer.Builder(this).build()
         ExoPlayer.Builder(this).build()
     }
     }
 
 
-    // 【修改点1】改为外部存储,方便你查看文件,确认是否生成
+    // 改为外部存储
     private val ttsFolderPath: String by lazy {
     private val ttsFolderPath: String by lazy {
         val baseDir = externalCacheDir ?: cacheDir
         val baseDir = externalCacheDir ?: cacheDir
         baseDir.absolutePath + File.separator + "httpTTS" + File.separator
         baseDir.absolutePath + File.separator + "httpTTS" + File.separator
@@ -454,13 +452,10 @@ class HttpReadAloudService : BaseReadAloudService(),
     }
     }
 
 
     /**
     /**
-     * 【核心修复点】生成音频文件名
-     * 1. 之前的问题:textChapter.title 可能是 "第一章  内容" (带格式),而数据库里是 "第一章 内容" (不带格式)。
-     * 2. 现在的做法:强制使用 textChapter.chapter.title (数据库原始标题)。
-     * 3. 结果:前台 (播放) 和后台 (下载) 用的标题来源完全一致,MD5 绝对匹配,不会再重复下载了!
+     * 生成音频文件名
      */
      */
     private fun md5SpeakFileName(content: String, textChapter: TextChapter? = this.textChapter): String {
     private fun md5SpeakFileName(content: String, textChapter: TextChapter? = this.textChapter): String {
-        val titleToUse = textChapter?.chapter?.title ?: "" // 强制取“核芯”标题
+        val titleToUse = textChapter?.chapter?.title ?: ""
         return MD5Utils.md5Encode16(titleToUse) + "_" +
         return MD5Utils.md5Encode16(titleToUse) + "_" +
                 MD5Utils.md5Encode16("${ReadAloud.httpTTS?.url}-|-$speechRate-|-$content")
                 MD5Utils.md5Encode16("${ReadAloud.httpTTS?.url}-|-$speechRate-|-$content")
     }
     }
@@ -492,7 +487,7 @@ class HttpReadAloudService : BaseReadAloudService(),
 
 
     /**
     /**
      * 移除缓存文件
      * 移除缓存文件
-     * 修复逻辑:如果时间设置为0,则不再保护当前章节,退出即全删。
+     * 如果时间设置为0,则不再保护当前章节,退出即全删。
      */
      */
     private fun removeCacheFile() {
     private fun removeCacheFile() {
         val keepTime = AppConfig.audioCacheCleanTime
         val keepTime = AppConfig.audioCacheCleanTime

+ 2 - 8
app/src/main/java/io/legado/app/service/WebService.kt

@@ -1,5 +1,6 @@
 package io.legado.app.service
 package io.legado.app.service
 
 
+// ——————【新增引用】——————
 import android.annotation.SuppressLint
 import android.annotation.SuppressLint
 import android.content.Context
 import android.content.Context
 import android.content.Intent
 import android.content.Intent
@@ -21,6 +22,7 @@ import io.legado.app.utils.getPrefBoolean
 import io.legado.app.utils.getPrefInt
 import io.legado.app.utils.getPrefInt
 import io.legado.app.utils.postEvent
 import io.legado.app.utils.postEvent
 import io.legado.app.utils.printOnDebug
 import io.legado.app.utils.printOnDebug
+import io.legado.app.utils.putPrefBoolean
 import io.legado.app.utils.sendToClip
 import io.legado.app.utils.sendToClip
 import io.legado.app.utils.servicePendingIntent
 import io.legado.app.utils.servicePendingIntent
 import io.legado.app.utils.startForegroundServiceCompat
 import io.legado.app.utils.startForegroundServiceCompat
@@ -33,8 +35,6 @@ import splitties.init.appCtx
 import splitties.systemservices.powerManager
 import splitties.systemservices.powerManager
 import splitties.systemservices.wifiManager
 import splitties.systemservices.wifiManager
 import java.io.IOException
 import java.io.IOException
-// ——————【新增引用】——————
-import io.legado.app.utils.putPrefBoolean
 
 
 class WebService : BaseService() {
 class WebService : BaseService() {
 
 
@@ -43,9 +43,6 @@ class WebService : BaseService() {
         var hostAddress = ""
         var hostAddress = ""
 
 
         fun start(context: Context) {
         fun start(context: Context) {
-            // ——————【修改开始】记录开启状态——————
-            appCtx.putPrefBoolean("web_service_auto", true)
-            // ——————【修改结束】——————
             context.startService<WebService>()
             context.startService<WebService>()
         }
         }
 
 
@@ -55,9 +52,6 @@ class WebService : BaseService() {
         }
         }
 
 
         fun stop(context: Context) {
         fun stop(context: Context) {
-            // ——————【修改开始】记录关闭状态——————
-            appCtx.putPrefBoolean("web_service_auto", false)
-            // ——————【修改结束】——————
             context.stopService<WebService>()
             context.stopService<WebService>()
         }
         }
 
 

+ 63 - 7
app/src/main/java/io/legado/app/ui/book/read/config/ReadAloudConfigDialog.kt

@@ -1,5 +1,8 @@
 package io.legado.app.ui.book.read.config
 package io.legado.app.ui.book.read.config
 
 
+//import io.legado.app.lib.theme.backgroundColor
+//import io.legado.app.lib.theme.primaryColor
+// 【新增引用】为了显示清理成功的提示
 import android.content.SharedPreferences
 import android.content.SharedPreferences
 import android.os.Bundle
 import android.os.Bundle
 import android.view.LayoutInflater
 import android.view.LayoutInflater
@@ -18,16 +21,16 @@ import io.legado.app.help.config.AppConfig
 import io.legado.app.lib.dialogs.SelectItem
 import io.legado.app.lib.dialogs.SelectItem
 import io.legado.app.lib.prefs.SwitchPreference
 import io.legado.app.lib.prefs.SwitchPreference
 import io.legado.app.lib.prefs.fragment.PreferenceFragment
 import io.legado.app.lib.prefs.fragment.PreferenceFragment
-//import io.legado.app.lib.theme.backgroundColor
-//import io.legado.app.lib.theme.primaryColor
 import io.legado.app.model.ReadAloud
 import io.legado.app.model.ReadAloud
 import io.legado.app.service.BaseReadAloudService
 import io.legado.app.service.BaseReadAloudService
+import io.legado.app.ui.widget.number.NumberPickerDialog
 import io.legado.app.utils.GSON
 import io.legado.app.utils.GSON
 import io.legado.app.utils.StringUtils
 import io.legado.app.utils.StringUtils
+import io.legado.app.utils.TTSCacheUtils
 import io.legado.app.utils.fromJsonObject
 import io.legado.app.utils.fromJsonObject
 import io.legado.app.utils.postEvent
 import io.legado.app.utils.postEvent
+import io.legado.app.utils.putPrefInt
 import io.legado.app.utils.showDialogFragment
 import io.legado.app.utils.showDialogFragment
-// 【新增引用】为了显示清理成功的提示
 import io.legado.app.utils.toastOnUi
 import io.legado.app.utils.toastOnUi
 
 
 class ReadAloudConfigDialog : BasePrefDialogFragment() {
 class ReadAloudConfigDialog : BasePrefDialogFragment() {
@@ -73,17 +76,16 @@ class ReadAloudConfigDialog : BasePrefDialogFragment() {
         override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
         override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
             addPreferencesFromResource(R.xml.pref_config_aloud)
             addPreferencesFromResource(R.xml.pref_config_aloud)
             upSpeakEngineSummary()
             upSpeakEngineSummary()
+            upPreferenceSummary(PreferKey.audioPreDownloadNum)
+            upPreferenceSummary(PreferKey.audioCacheCleanTime)
             findPreference<SwitchPreference>(PreferKey.pauseReadAloudWhilePhoneCalls)?.let {
             findPreference<SwitchPreference>(PreferKey.pauseReadAloudWhilePhoneCalls)?.let {
                 it.isEnabled = AppConfig.ignoreAudioFocus
                 it.isEnabled = AppConfig.ignoreAudioFocus
             }
             }
 
 
-            // 【新增代码】绑定清理缓存按钮事件
             findPreference<Preference>("clear_cache")?.let {
             findPreference<Preference>("clear_cache")?.let {
                 it.summary = getString(R.string.clear_cache)
                 it.summary = getString(R.string.clear_cache)
                 it.setOnPreferenceClickListener {
                 it.setOnPreferenceClickListener {
-                    // 调用 AppConfig 中的万能清理函数 (自动处理外部存储)
-                    AppConfig.clearTtsCache()
-                    // 弹出提示
+                    TTSCacheUtils.clearTtsCache()
                     toastOnUi("音频缓存已清理")
                     toastOnUi("音频缓存已清理")
                     true
                     true
                 }
                 }
@@ -107,6 +109,38 @@ class ReadAloudConfigDialog : BasePrefDialogFragment() {
 
 
         override fun onPreferenceTreeClick(preference: Preference): Boolean {
         override fun onPreferenceTreeClick(preference: Preference): Boolean {
             when (preference.key) {
             when (preference.key) {
+                PreferKey.audioPreDownloadNum -> {
+                    NumberPickerDialog(requireContext())
+                        .setTitle(getString(R.string.read_aloud_preload))
+                        .setMaxValue(50)
+                        .setMinValue(0)
+                        .setValue(10)
+                        .setCustomButton((R.string.btn_default_s)) {
+                            putPrefInt(PreferKey.audioPreDownloadNum, 10)
+                            upPreferenceSummary(PreferKey.audioPreDownloadNum)
+                        }
+                        .show {
+                            putPrefInt(PreferKey.audioPreDownloadNum, it)
+                            upPreferenceSummary(PreferKey.audioPreDownloadNum)
+                        }
+                }
+
+                PreferKey.audioCacheCleanTime -> {
+                    NumberPickerDialog(requireContext())
+                        .setTitle(getString(R.string.audio_cache_clean_time))
+                        .setMaxValue(50)
+                        .setMinValue(0)
+                        .setValue(1)
+                        .setCustomButton((R.string.btn_default_s)) {
+                            putPrefInt(PreferKey.audioCacheCleanTime, 10)
+                            upPreferenceSummary(PreferKey.audioCacheCleanTime)
+                        }
+                        .show {
+                            putPrefInt(PreferKey.audioCacheCleanTime, it)
+                            upPreferenceSummary(PreferKey.audioCacheCleanTime)
+                        }
+                }
+
                 PreferKey.ttsEngine -> showDialogFragment(SpeakEngineDialog())
                 PreferKey.ttsEngine -> showDialogFragment(SpeakEngineDialog())
                 "sysTtsConfig" -> IntentHelp.openTTSSetting()
                 "sysTtsConfig" -> IntentHelp.openTTSSetting()
             }
             }
@@ -139,12 +173,34 @@ class ReadAloudConfigDialog : BasePrefDialogFragment() {
                     preference.summary = if (index >= 0) preference.entries[index] else null
                     preference.summary = if (index >= 0) preference.entries[index] else null
                 }
                 }
 
 
+
                 else -> {
                 else -> {
                     preference?.summary = value
                     preference?.summary = value
                 }
                 }
             }
             }
         }
         }
 
 
+        private fun upPreferenceSummary(preferenceKey: String, value: String? = null) {
+            val preference = findPreference<Preference>(preferenceKey) ?: return
+            when (preferenceKey) {
+                PreferKey.audioPreDownloadNum -> {
+                    preference.summary = getString(
+                        R.string.read_aloud_preload_summary,
+                        AppConfig.audioPreDownloadNum
+                    )
+                }
+
+                PreferKey.audioCacheCleanTime -> {
+                    preference.summary = getString(
+                        R.string.audio_cache_clean_time_summary,
+                        AppConfig.audioCacheCleanTimeOrgin
+                    )
+                }
+
+                else -> preference.summary = value
+            }
+        }
+
         override fun upSpeakEngineSummary() {
         override fun upSpeakEngineSummary() {
             upPreferenceSummary(
             upPreferenceSummary(
                 findPreference(PreferKey.ttsEngine),
                 findPreference(PreferKey.ttsEngine),

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

@@ -1,5 +1,6 @@
 package io.legado.app.ui.book.read.config
 package io.legado.app.ui.book.read.config
 
 
+//import io.legado.app.lib.theme.primaryColor
 import android.content.Context
 import android.content.Context
 import android.os.Bundle
 import android.os.Bundle
 import android.view.MenuItem
 import android.view.MenuItem
@@ -24,15 +25,14 @@ import io.legado.app.help.DirectLinkUpload
 import io.legado.app.help.config.AppConfig
 import io.legado.app.help.config.AppConfig
 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.theme.primaryColor
 import io.legado.app.model.ReadAloud
 import io.legado.app.model.ReadAloud
 import io.legado.app.model.ReadBook
 import io.legado.app.model.ReadBook
 import io.legado.app.ui.association.ImportHttpTtsDialog
 import io.legado.app.ui.association.ImportHttpTtsDialog
 import io.legado.app.ui.file.HandleFileContract
 import io.legado.app.ui.file.HandleFileContract
 import io.legado.app.ui.login.SourceLoginActivity
 import io.legado.app.ui.login.SourceLoginActivity
 import io.legado.app.utils.ACache
 import io.legado.app.utils.ACache
-import io.legado.app.utils.FileUtils
 import io.legado.app.utils.GSON
 import io.legado.app.utils.GSON
+import io.legado.app.utils.TTSCacheUtils
 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.isAbsUrl
@@ -49,7 +49,6 @@ import kotlinx.coroutines.flow.catch
 import kotlinx.coroutines.flow.conflate
 import kotlinx.coroutines.flow.conflate
 import kotlinx.coroutines.flow.flowOn
 import kotlinx.coroutines.flow.flowOn
 import kotlinx.coroutines.launch
 import kotlinx.coroutines.launch
-import java.io.File
 
 
 /**
 /**
  * tts引擎管理
  * tts引擎管理
@@ -236,19 +235,10 @@ class SpeakEngineDialog() : BaseBottomSheetDialogFragment(R.layout.dialog_recycl
         adapter.notifyItemRangeChanged(adapter.getHeaderCount(), adapter.itemCount)
         adapter.notifyItemRangeChanged(adapter.getHeaderCount(), adapter.itemCount)
     }
     }
 
 
-    /**
-     * 【核心修改点】清理缓存方法
-     * 原来:只删除 cacheDir (内部存储)
-     * 现在:调用 AppConfig.clearTtsCache(),自动处理 externalCacheDir (外部存储)
-     */
     fun clearCache() {
     fun clearCache() {
         execute {
         execute {
             ReadAloud.upReadAloudClass()
             ReadAloud.upReadAloudClass()
-            
-            // 调用万能清理函数
-            AppConfig.clearTtsCache()
-            
-            // 显示成功提示
+            TTSCacheUtils.clearTtsCache()
             toastOnUi(R.string.clear_cache_success)
             toastOnUi(R.string.clear_cache_success)
         }
         }
     }
     }

+ 3 - 5
app/src/main/java/io/legado/app/ui/main/MainActivity.kt

@@ -42,6 +42,7 @@ import io.legado.app.help.coroutine.Coroutine
 import io.legado.app.help.storage.Backup
 import io.legado.app.help.storage.Backup
 import io.legado.app.help.update.AppUpdateGitHub
 import io.legado.app.help.update.AppUpdateGitHub
 import io.legado.app.lib.dialogs.alert
 import io.legado.app.lib.dialogs.alert
+import io.legado.app.service.WebService
 import io.legado.app.ui.about.CrashLogsDialog
 import io.legado.app.ui.about.CrashLogsDialog
 import io.legado.app.ui.about.UpdateDialog
 import io.legado.app.ui.about.UpdateDialog
 import io.legado.app.ui.book.read.ReadBookActivity
 import io.legado.app.ui.book.read.ReadBookActivity
@@ -71,7 +72,6 @@ import kotlinx.coroutines.launch
 import kotlinx.coroutines.withContext
 import kotlinx.coroutines.withContext
 import kotlin.coroutines.resume
 import kotlin.coroutines.resume
 import kotlin.coroutines.suspendCoroutine
 import kotlin.coroutines.suspendCoroutine
-import io.legado.app.service.WebService
 
 
 /**
 /**
  * 主界面
  * 主界面
@@ -135,13 +135,11 @@ open class MainActivity : VMBaseActivity<ActivityMainBinding, MainViewModel>(),
             binding.viewPagerMain.fitsSystemWindows = true
             binding.viewPagerMain.fitsSystemWindows = true
         // 其他初始化逻辑
         // 其他初始化逻辑
         setupBackCallback()
         setupBackCallback()
-        
-        // ——————【修改开始】——————
+
         // 智能自启:如果上次是手动开启状态(web_service_auto 为 true),则自启
         // 智能自启:如果上次是手动开启状态(web_service_auto 为 true),则自启
-        if (getPrefBoolean("web_service_auto", false)) {
+        if (AppConfig.webServiceAutoStart) {
             WebService.startForeground(this)
             WebService.startForeground(this)
         }
         }
-        // ——————【修改结束】——————
         
         
         upBottomMenu()
         upBottomMenu()
         initView()
         initView()

+ 16 - 0
app/src/main/java/io/legado/app/utils/TTSCacheUtils.kt

@@ -0,0 +1,16 @@
+package io.legado.app.utils
+
+import splitties.init.appCtx
+import java.io.File
+
+object TTSCacheUtils {
+
+    fun clearTtsCache() {
+        val baseDir = appCtx.externalCacheDir ?: appCtx.cacheDir
+        // 清理音频文件
+        FileUtils.delete(baseDir.absolutePath + File.separator + "httpTTS")
+        // 清理数据库索引 (可选,建议一起清,防止索引还在但文件没了)
+        FileUtils.delete(baseDir.absolutePath + File.separator + "httpTTS_cache")
+    }
+
+}

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

@@ -1370,4 +1370,9 @@
     <string name="palette_style">调色板样式</string>
     <string name="palette_style">调色板样式</string>
     <string name="tip_compose_set">这里的选项仅可以控制使用Compose重写的界面。</string>
     <string name="tip_compose_set">这里的选项仅可以控制使用Compose重写的界面。</string>
     <string name="is_blur_enable">启用控件模糊</string>
     <string name="is_blur_enable">启用控件模糊</string>
+    <string name="web_service_auto_start">启动应用时打开Web服务</string>
+    <string name="read_aloud_preload">听书预加载数量</string>
+    <string name="read_aloud_preload_summary">%d</string>
+    <string name="audio_cache_clean_time">音频缓存保留时间(分钟)</string>
+    <string name="audio_cache_clean_time_summary">当前%d, 输入 0 代表退出即刻清理。</string>
 </resources>
 </resources>

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

@@ -1375,4 +1375,9 @@
     <string name="palette_style">调色板样式</string>
     <string name="palette_style">调色板样式</string>
     <string name="tip_compose_set">这里的选项仅可以控制使用Compose重写的界面。</string>
     <string name="tip_compose_set">这里的选项仅可以控制使用Compose重写的界面。</string>
     <string name="is_blur_enable">启用控件模糊</string>
     <string name="is_blur_enable">启用控件模糊</string>
+    <string name="web_service_auto_start">启动应用时打开Web服务</string>
+    <string name="read_aloud_preload">听书预加载数量</string>
+    <string name="read_aloud_preload_summary">%d</string>
+    <string name="audio_cache_clean_time">音频缓存保留时间(分钟)</string>
+    <string name="audio_cache_clean_time_summary">当前%d, 输入 0 代表退出即刻清理。</string>
 </resources>
 </resources>

+ 6 - 12
app/src/main/res/xml/pref_config_aloud.xml

@@ -67,22 +67,16 @@
             android:key="sysTtsConfig"
             android:key="sysTtsConfig"
             app:iconSpaceReserved="false" />
             app:iconSpaceReserved="false" />
 
 
-        <io.legado.app.lib.prefs.EditTextPreference
+        <io.legado.app.lib.prefs.Preference
             android:key="audioPreDownloadNum"
             android:key="audioPreDownloadNum"
-            android:title="听书预加载数量(章节)"
-            android:summary="设置听书时预先下载的章节数量"
-            android:defaultValue="10"
-            android:inputType="number"
-            android:persistent="true"
+            android:summary="@string/read_aloud_preload_summary"
+            android:title="@string/read_aloud_preload"
             app:iconSpaceReserved="false" />
             app:iconSpaceReserved="false" />
 
 
-        <io.legado.app.lib.prefs.EditTextPreference
+        <io.legado.app.lib.prefs.Preference
             android:key="audioCacheCleanTime"
             android:key="audioCacheCleanTime"
-            android:title="音频缓存保留时间(分钟)"
-            android:summary="听书缓存文件保留多久后自动删除(单位:分钟)。输入 0 代表退出即刻清理。"
-            android:defaultValue="10"
-            android:inputType="number"
-            android:persistent="true"
+            android:summary="@string/audio_cache_clean_time_summary"
+            android:title="@string/audio_cache_clean_time"
             app:iconSpaceReserved="false" />
             app:iconSpaceReserved="false" />
         </io.legado.app.lib.prefs.PreferenceCategory>
         </io.legado.app.lib.prefs.PreferenceCategory>
 
 

+ 6 - 0
app/src/main/res/xml/pref_config_other.xml

@@ -19,6 +19,12 @@
         app:entries="@array/default_app_variant"
         app:entries="@array/default_app_variant"
         app:entryValues="@array/default_app_variant_value" />
         app:entryValues="@array/default_app_variant_value" />
 
 
+    <io.legado.app.lib.prefs.SwitchPreference
+        android:defaultValue="false"
+        android:key="webServiceAutoStart"
+        android:title="@string/web_service_auto_start"
+        app:iconSpaceReserved="false" />
+
     <io.legado.app.lib.prefs.PreferenceCategory
     <io.legado.app.lib.prefs.PreferenceCategory
         android:title="@string/main_activity"
         android:title="@string/main_activity"
         app:allowDividerAbove="false"
         app:allowDividerAbove="false"