Merge remote-tracking branch 'upstream/master'

pull/1251/head
Jason Yao 3 years ago
commit 9f8f71b4cd
  1. 10
      app/build.gradle
  2. 10
      app/src/main/assets/updateLog.md
  3. 5
      app/src/main/java/io/legado/app/base/BaseActivity.kt
  4. 2
      app/src/main/java/io/legado/app/constant/AppPattern.kt
  5. 3
      app/src/main/java/io/legado/app/constant/PreferKey.kt
  6. 2
      app/src/main/java/io/legado/app/help/ReadBookConfig.kt
  7. 30
      app/src/main/java/io/legado/app/help/ThemeConfig.kt
  8. 3
      app/src/main/java/io/legado/app/help/http/HttpHelper.kt
  9. 36
      app/src/main/java/io/legado/app/help/http/cronet/CronetHelper.kt
  10. 51
      app/src/main/java/io/legado/app/help/http/cronet/CronetInterceptor.kt
  11. 14
      app/src/main/java/io/legado/app/help/http/cronet/CronetLoader.kt
  12. 18
      app/src/main/java/io/legado/app/help/http/cronet/CronetUrlRequestCallback.kt
  13. 3
      app/src/main/java/io/legado/app/help/storage/Restore.kt
  14. 1
      app/src/main/java/io/legado/app/ui/association/ImportBookSourceDialog.kt
  15. 1
      app/src/main/java/io/legado/app/ui/association/ImportRssSourceDialog.kt
  16. 2
      app/src/main/java/io/legado/app/ui/book/cache/CacheActivity.kt
  17. 5
      app/src/main/java/io/legado/app/ui/book/changecover/ChangeCoverDialog.kt
  18. 2
      app/src/main/java/io/legado/app/ui/book/changesource/ChangeSourceDialog.kt
  19. 2
      app/src/main/java/io/legado/app/ui/book/group/GroupEdit.kt
  20. 6
      app/src/main/java/io/legado/app/ui/book/group/GroupManageDialog.kt
  21. 8
      app/src/main/java/io/legado/app/ui/book/group/GroupSelectDialog.kt
  22. 1
      app/src/main/java/io/legado/app/ui/book/local/ImportBookActivity.kt
  23. 4
      app/src/main/java/io/legado/app/ui/book/read/ReadBookActivity.kt
  24. 1
      app/src/main/java/io/legado/app/ui/book/read/ReadBookBaseActivity.kt
  25. 6
      app/src/main/java/io/legado/app/ui/book/read/config/AutoReadDialog.kt
  26. 7
      app/src/main/java/io/legado/app/ui/book/read/config/BgTextConfigDialog.kt
  27. 4
      app/src/main/java/io/legado/app/ui/book/read/config/PaddingConfigDialog.kt
  28. 4
      app/src/main/java/io/legado/app/ui/book/read/config/ReadAloudConfigDialog.kt
  29. 3
      app/src/main/java/io/legado/app/ui/book/read/config/SpeakEngineDialog.kt
  30. 6
      app/src/main/java/io/legado/app/ui/book/read/config/TocRegexDialog.kt
  31. 2
      app/src/main/java/io/legado/app/ui/book/source/edit/BookSourceEditActivity.kt
  32. 6
      app/src/main/java/io/legado/app/ui/book/source/manage/BookSourceActivity.kt
  33. 16
      app/src/main/java/io/legado/app/ui/book/source/manage/GroupManageDialog.kt
  34. 76
      app/src/main/java/io/legado/app/ui/config/OtherConfigFragment.kt
  35. 163
      app/src/main/java/io/legado/app/ui/config/ThemeConfigFragment.kt
  36. 2
      app/src/main/java/io/legado/app/ui/config/ThemeListDialog.kt
  37. 2
      app/src/main/java/io/legado/app/ui/dict/DictViewModel.kt
  38. 2
      app/src/main/java/io/legado/app/ui/document/FilePickerDialog.kt
  39. 2
      app/src/main/java/io/legado/app/ui/main/MainViewModel.kt
  40. 6
      app/src/main/java/io/legado/app/ui/main/bookshelf/BaseBookshelfFragment.kt
  41. 2
      app/src/main/java/io/legado/app/ui/qrcode/QrCodeActivity.kt
  42. 12
      app/src/main/java/io/legado/app/ui/replace/GroupManageDialog.kt
  43. 1
      app/src/main/java/io/legado/app/ui/replace/ReplaceRuleActivity.kt
  44. 4
      app/src/main/java/io/legado/app/ui/replace/edit/ReplaceEditActivity.kt
  45. 1
      app/src/main/java/io/legado/app/ui/rss/read/ReadRssActivity.kt
  46. 2
      app/src/main/java/io/legado/app/ui/rss/source/edit/RssSourceEditActivity.kt
  47. 20
      app/src/main/java/io/legado/app/ui/rss/source/manage/GroupManageDialog.kt
  48. 1
      app/src/main/java/io/legado/app/ui/rss/source/manage/RssSourceActivity.kt
  49. 4
      app/src/main/java/io/legado/app/ui/widget/dialog/TextDialog.kt
  50. 4
      app/src/main/java/io/legado/app/ui/widget/dialog/TextListDialog.kt
  51. 2
      app/src/main/java/io/legado/app/ui/widget/font/FontSelectDialog.kt
  52. 5
      app/src/main/java/io/legado/app/ui/widget/image/CoverImageView.kt
  53. 4
      app/src/main/java/io/legado/app/ui/widget/prefs/IconListPreference.kt
  54. 27
      app/src/main/java/io/legado/app/utils/ActivityExtensions.kt
  55. 32
      app/src/main/java/io/legado/app/utils/ActivityResultContractUtils.kt
  56. 4
      app/src/main/java/io/legado/app/utils/BitmapUtils.kt
  57. 0
      app/src/main/java/io/legado/app/utils/JsonExtensions.kt
  58. 1
      app/src/main/res/layout-land/activity_book_info.xml
  59. 7
      app/src/main/res/layout/activity_book_info.xml
  60. 4
      app/src/main/res/layout/activity_chapter_list.xml
  61. 3
      app/src/main/res/layout/activity_import_book.xml
  62. 4
      app/src/main/res/layout/activity_main.xml
  63. 21
      app/src/main/res/layout/activity_replace_edit.xml
  64. 3
      app/src/main/res/layout/activity_replace_rule.xml
  65. 4
      app/src/main/res/layout/activity_rss_artivles.xml
  66. 12
      app/src/main/res/layout/activity_rss_source_edit.xml
  67. 3
      app/src/main/res/layout/activity_search_content.xml
  68. 4
      app/src/main/res/layout/dialog_auto_read.xml
  69. 6
      app/src/main/res/layout/dialog_bookmark.xml
  70. 34
      app/src/main/res/layout/dialog_bookshelf_config.xml
  71. 14
      app/src/main/res/layout/dialog_download_choice.xml
  72. 32
      app/src/main/res/layout/dialog_edit_text.xml
  73. 30
      app/src/main/res/layout/dialog_image_blurring.xml
  74. 7
      app/src/main/res/layout/dialog_recycler_view.xml
  75. 7
      app/src/main/res/layout/dialog_toc_regex_edit.xml
  76. 2
      app/src/main/res/layout/dialog_wait.xml
  77. 1
      app/src/main/res/values-es-rES/strings.xml
  78. 1
      app/src/main/res/values-ja-rJP/strings.xml
  79. 1
      app/src/main/res/values-pt-rBR/strings.xml
  80. 4
      app/src/main/res/values-zh-rHK/arrays.xml
  81. 60
      app/src/main/res/values-zh-rHK/strings.xml
  82. 4
      app/src/main/res/values-zh-rTW/arrays.xml
  83. 10
      app/src/main/res/values-zh-rTW/strings.xml
  84. 4
      app/src/main/res/values-zh/strings.xml
  85. 4
      app/src/main/res/values/strings.xml
  86. 14
      app/src/main/res/xml/pref_config_other.xml
  87. 31
      app/src/main/res/xml/pref_config_theme.xml

@ -97,13 +97,13 @@ android {
compileOptions { compileOptions {
// Flag to enable support for the new language APIs // Flag to enable support for the new language APIs
coreLibraryDesugaringEnabled true coreLibraryDesugaringEnabled true
// Sets Java compatibility to Java 8 // Sets Java compatibility to Java 11
sourceCompatibility JavaVersion.VERSION_1_8 sourceCompatibility JavaVersion.VERSION_11
targetCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_11
} }
kotlinOptions { kotlinOptions {
jvmTarget = "1.8" jvmTarget = "11"
} }
buildToolsVersion '30.0.3' buildToolsVersion '30.0.3'
tasks.withType(JavaCompile) { tasks.withType(JavaCompile) {
@ -198,7 +198,7 @@ dependencies {
implementation('org.nanohttpd:nanohttpd-apache-fileupload:2.3.1') implementation('org.nanohttpd:nanohttpd-apache-fileupload:2.3.1')
// //
implementation('com.github.jenly1314:zxing-lite:2.1.0') implementation('com.github.jenly1314:zxing-lite:2.1.1')
// //
implementation('com.jaredrummler:colorpicker:1.1.0') implementation('com.jaredrummler:colorpicker:1.1.0')

@ -2,7 +2,6 @@
* 关注公众号 **[开源阅读]** 菜单•软件下载 提前享受新版本。 * 关注公众号 **[开源阅读]** 菜单•软件下载 提前享受新版本。
* 关注合作公众号 **[小说拾遗]** 获取好看的小说。 * 关注合作公众号 **[小说拾遗]** 获取好看的小说。
* 旧版数据导入教程:先在旧版阅读(2.x)中进行备份,然后在新版阅读(3.x)【我的】->【备份与恢复】,选择【导入旧版本数据】。
## **必读** ## **必读**
@ -12,6 +11,15 @@
* 正文出现缺字漏字、内容缺失、排版错乱等情况,有可能是净化规则出现问题, 出现简体变化问题检查一下简繁转换是否关闭。 * 正文出现缺字漏字、内容缺失、排版错乱等情况,有可能是净化规则出现问题, 出现简体变化问题检查一下简繁转换是否关闭。
* 漫画源看书显示乱码,**阅读与其他软件的源并不通用**,请导入阅读的支持的漫画源! * 漫画源看书显示乱码,**阅读与其他软件的源并不通用**,请导入阅读的支持的漫画源!
**2021/08/02**
* 关于最近版本有时候界面没有数据的问题是因为把LiveData组件换成了谷歌推荐的Flow组件导致的问题,正在查找解决办法
1. 换源界面功能添加:置顶,置底,删除 by h11128
2. Cronet:优化 by ag2s20150909
3. 优化自动翻页 by jiuZhouWorlds
4. 封面设置移到主题里面,白天和夜间可分别设置
**2021/08/01** **2021/08/01**
1. 为webService添加快捷操作 1. 为webService添加快捷操作

@ -2,6 +2,7 @@ package io.legado.app.base
import android.content.Context import android.content.Context
import android.content.res.Configuration import android.content.res.Configuration
import android.graphics.drawable.BitmapDrawable
import android.os.Build import android.os.Build
import android.os.Bundle import android.os.Bundle
import android.util.AttributeSet import android.util.AttributeSet
@ -174,8 +175,8 @@ abstract class BaseActivity<VB : ViewBinding>(
} }
if (imageBg) { if (imageBg) {
try { try {
ThemeConfig.getBgImage(this)?.let { ThemeConfig.getBgImage(this, windowSize)?.let {
window.decorView.background = it window.decorView.background = BitmapDrawable(resources, it)
} }
} catch (e: OutOfMemoryError) { } catch (e: OutOfMemoryError) {
toastOnUi(e.localizedMessage) toastOnUi(e.localizedMessage)

@ -5,7 +5,7 @@ import java.util.regex.Pattern
@Suppress("RegExpRedundantEscape") @Suppress("RegExpRedundantEscape")
object AppPattern { object AppPattern {
val JS_PATTERN: Pattern = val JS_PATTERN: Pattern =
Pattern.compile("<js>([\\w\\W]+?)</js>|@js:([\\w\\W]*)", Pattern.CASE_INSENSITIVE) Pattern.compile("<js>([\\w\\W]*?)</js>|@js:([\\w\\W]*)", Pattern.CASE_INSENSITIVE)
val EXP_PATTERN: Pattern = Pattern.compile("\\{\\{([\\w\\W]*?)\\}\\}") val EXP_PATTERN: Pattern = Pattern.compile("\\{\\{([\\w\\W]*?)\\}\\}")
//匹配格式化后的图片格式 //匹配格式化后的图片格式

@ -66,6 +66,7 @@ object PreferKey {
const val transparentStatusBar = "transparentStatusBar" const val transparentStatusBar = "transparentStatusBar"
const val immNavigationBar = "immNavigationBar" const val immNavigationBar = "immNavigationBar"
const val defaultCover = "defaultCover" const val defaultCover = "defaultCover"
const val defaultCoverDark = "defaultCoverDark"
const val replaceEnableDefault = "replaceEnableDefault" const val replaceEnableDefault = "replaceEnableDefault"
const val showBrightnessView = "showBrightnessView" const val showBrightnessView = "showBrightnessView"
const val autoClearExpired = "autoClearExpired" const val autoClearExpired = "autoClearExpired"
@ -90,11 +91,13 @@ object PreferKey {
const val cBackground = "colorBackground" const val cBackground = "colorBackground"
const val cBBackground = "colorBottomBackground" const val cBBackground = "colorBottomBackground"
const val bgImage = "backgroundImage" const val bgImage = "backgroundImage"
const val bgImageBlurring = "backgroundImageBlurring"
const val cNPrimary = "colorPrimaryNight" const val cNPrimary = "colorPrimaryNight"
const val cNAccent = "colorAccentNight" const val cNAccent = "colorAccentNight"
const val cNBackground = "colorBackgroundNight" const val cNBackground = "colorBackgroundNight"
const val cNBBackground = "colorBottomBackgroundNight" const val cNBBackground = "colorBottomBackgroundNight"
const val bgImageN = "backgroundImageNight" const val bgImageN = "backgroundImageNight"
const val bgImageNBlurring = "backgroundImageNightBlurring"
} }

@ -135,7 +135,7 @@ object ReadBookConfig {
//配置写入读取 //配置写入读取
var readBodyToLh = appCtx.getPrefBoolean(PreferKey.readBodyToLh, true) var readBodyToLh = appCtx.getPrefBoolean(PreferKey.readBodyToLh, true)
var autoReadSpeed = appCtx.getPrefInt(PreferKey.autoReadSpeed, 46) var autoReadSpeed = appCtx.getPrefInt(PreferKey.autoReadSpeed, 10)
set(value) { set(value) {
field = value field = value
appCtx.putPrefInt(PreferKey.autoReadSpeed, value) appCtx.putPrefInt(PreferKey.autoReadSpeed, value)

@ -1,9 +1,9 @@
package io.legado.app.help package io.legado.app.help
import android.content.Context import android.content.Context
import android.graphics.Bitmap
import android.graphics.Color import android.graphics.Color
import android.graphics.drawable.BitmapDrawable import android.util.DisplayMetrics
import android.graphics.drawable.Drawable
import androidx.annotation.Keep import androidx.annotation.Keep
import androidx.appcompat.app.AppCompatDelegate import androidx.appcompat.app.AppCompatDelegate
import io.legado.app.R import io.legado.app.R
@ -11,6 +11,7 @@ import io.legado.app.constant.EventBus
import io.legado.app.constant.PreferKey import io.legado.app.constant.PreferKey
import io.legado.app.constant.Theme import io.legado.app.constant.Theme
import io.legado.app.lib.theme.ThemeStore import io.legado.app.lib.theme.ThemeStore
import io.legado.app.ui.widget.image.CoverImageView
import io.legado.app.utils.* import io.legado.app.utils.*
import splitties.init.appCtx import splitties.init.appCtx
import java.io.File import java.io.File
@ -28,6 +29,7 @@ object ThemeConfig {
ReadBookConfig.upBg() ReadBookConfig.upBg()
applyTheme(context) applyTheme(context)
initNightMode() initNightMode()
CoverImageView.upDefaultCover()
postEvent(EventBus.RECREATE, "") postEvent(EventBus.RECREATE, "")
} }
@ -41,14 +43,26 @@ object ThemeConfig {
AppCompatDelegate.setDefaultNightMode(targetMode) AppCompatDelegate.setDefaultNightMode(targetMode)
} }
fun getBgImage(context: Context): Drawable? { fun getBgImage(context: Context, metrics: DisplayMetrics): Bitmap? {
val bgPath = when (Theme.getTheme()) { val bgCfg = when (Theme.getTheme()) {
Theme.Light -> context.getPrefString(PreferKey.bgImage) Theme.Light -> Pair(
Theme.Dark -> context.getPrefString(PreferKey.bgImageN) context.getPrefString(PreferKey.bgImage),
context.getPrefInt(PreferKey.bgImageBlurring, 0)
)
Theme.Dark -> Pair(
context.getPrefString(PreferKey.bgImageN),
context.getPrefInt(PreferKey.bgImageNBlurring, 0)
)
else -> null else -> null
} ?: return null
if (bgCfg.first.isNullOrBlank()) return null
val bgImage = BitmapUtils
.decodeBitmap(bgCfg.first!!, metrics.widthPixels, metrics.heightPixels)
?: return null
if (bgCfg.second == 0) {
return bgImage
} }
if (bgPath.isNullOrBlank()) return null return BitmapUtils.stackBlur(bgImage, bgCfg.second.toFloat())
return BitmapDrawable.createFromPath(bgPath)
} }
fun upConfig() { fun upConfig() {

@ -45,7 +45,8 @@ val okHttpClient: OkHttpClient by lazy {
chain.proceed(request) chain.proceed(request)
}) })
if (AppConfig.isCronet && CronetLoader.install()) { if (AppConfig.isCronet && CronetLoader.install()) {
builder.addInterceptor(CronetInterceptor()) //提供CookieJar 用于同步Cookie
builder.addInterceptor(CronetInterceptor(null))
} }

@ -1,6 +1,6 @@
package io.legado.app.help.http.cronet package io.legado.app.help.http.cronet
import io.legado.app.help.http.CookieStore import android.util.Log
import okhttp3.Headers import okhttp3.Headers
import okhttp3.MediaType import okhttp3.MediaType
import okhttp3.Request import okhttp3.Request
@ -9,29 +9,22 @@ import org.chromium.net.CronetEngine.Builder.HTTP_CACHE_DISK
import org.chromium.net.ExperimentalCronetEngine import org.chromium.net.ExperimentalCronetEngine
import org.chromium.net.UploadDataProviders import org.chromium.net.UploadDataProviders
import org.chromium.net.UrlRequest import org.chromium.net.UrlRequest
import org.chromium.net.urlconnection.CronetURLStreamHandlerFactory
import splitties.init.appCtx import splitties.init.appCtx
import java.net.URL
import java.util.concurrent.Executor import java.util.concurrent.Executor
import java.util.concurrent.Executors import java.util.concurrent.Executors
val executor: Executor by lazy { Executors.newSingleThreadExecutor() } val executor: Executor by lazy { Executors.newCachedThreadPool() }
val cronetEngine: ExperimentalCronetEngine by lazy { val cronetEngine: ExperimentalCronetEngine by lazy {
CronetLoader.preDownload() CronetLoader.preDownload()
val builder = ExperimentalCronetEngine.Builder(appCtx) val builder = ExperimentalCronetEngine.Builder(appCtx)
//设置自定义so库加载 .setLibraryLoader(CronetLoader)//设置自定义so库加载
.setLibraryLoader(CronetLoader) .setStoragePath(appCtx.externalCacheDir?.absolutePath)//设置缓存路径
//设置缓存路径 .enableHttpCache(HTTP_CACHE_DISK, (1024 * 1024 * 50))//设置缓存模式
.setStoragePath(appCtx.externalCacheDir?.absolutePath) .enableQuic(true)//设置支持http/3
//设置缓存模式 .enableHttp2(true) //设置支持http/2
.enableHttpCache(HTTP_CACHE_DISK, (1024 * 1024 * 50))
//设置支持http/3
.enableQuic(true)
//设置支持http/2
.enableHttp2(true)
.enablePublicKeyPinningBypassForLocalTrustAnchors(true) .enablePublicKeyPinningBypassForLocalTrustAnchors(true)
//.enableNetworkQualityEstimator(true) //.enableNetworkQualityEstimator(true)
@ -39,7 +32,9 @@ val cronetEngine: ExperimentalCronetEngine by lazy {
builder.enableBrotli(true) builder.enableBrotli(true)
//builder.setExperimentalOptions("{\"quic_version\": \"h3-29\"}") //builder.setExperimentalOptions("{\"quic_version\": \"h3-29\"}")
val engine = builder.build() val engine = builder.build()
URL.setURLStreamHandlerFactory(CronetURLStreamHandlerFactory(engine)) Log.d("Cronet", "Cronet Version:" + engine.versionString)
//这会导致Jsoup的网络请求出现问题,暂时不接管系统URL
//URL.setURLStreamHandlerFactory(CronetURLStreamHandlerFactory(engine))
return@lazy engine return@lazy engine
} }
@ -49,17 +44,10 @@ fun buildRequest(request: Request, callback: UrlRequest.Callback): UrlRequest {
val url = request.url.toString() val url = request.url.toString()
val requestBuilder = cronetEngine.newUrlRequestBuilder(url, callback, executor) val requestBuilder = cronetEngine.newUrlRequestBuilder(url, callback, executor)
requestBuilder.setHttpMethod(request.method) requestBuilder.setHttpMethod(request.method)
val cookie = CookieStore.getCookie(url)
if (cookie.length > 1) {
requestBuilder.addHeader("Cookie", cookie)
}
val headers: Headers = request.headers val headers: Headers = request.headers
headers.forEachIndexed { index, _ -> headers.forEachIndexed { index, _ ->
val name = headers.name(index) requestBuilder.addHeader(headers.name(index), headers.value(index))
if (!name.equals("Keep-Alive", true)) {
requestBuilder.addHeader(name, headers.value(index))
}
} }
val requestBody = request.body val requestBody = request.body

@ -1,23 +1,62 @@
package io.legado.app.help.http.cronet package io.legado.app.help.http.cronet
import okhttp3.Call import io.legado.app.help.http.CookieStore
import okhttp3.Interceptor import okhttp3.*
import okhttp3.Request
import okhttp3.Response
import java.io.IOException import java.io.IOException
class CronetInterceptor : Interceptor { class CronetInterceptor(private val cookieJar: CookieJar?) : Interceptor {
@Throws(IOException::class) @Throws(IOException::class)
override fun intercept(chain: Interceptor.Chain): Response { override fun intercept(chain: Interceptor.Chain): Response {
return proceedWithCronet(chain.request(), chain.call()) val original: Request = chain.request()
val builder: Request.Builder = original.newBuilder()
//Cronet未初始化
return if (!CronetLoader.install()) {
chain.proceed(original)
} else try {
//移除Keep-Alive,手动设置会导致400 BadRequest
builder.removeHeader("Keep-Alive")
val cookieStr = getCookie(original.url)
//设置Cookie
if (cookieStr.length > 3) {
builder.header("Cookie", cookieStr)
}
val new = builder.build()
val response: Response = proceedWithCronet(new, chain.call())
//从Response 中保存Cookie到CookieJar
cookieJar?.saveFromResponse(new.url, Cookie.parseAll(new.url, response.headers))
response
} catch (e: Exception) {
//遇到Cronet处理有问题时的情况,如证书过期等等,回退到okhttp处理
chain.proceed(original)
}
} }
@Throws(IOException::class) @Throws(IOException::class)
private fun proceedWithCronet(request: Request, call: Call): Response { private fun proceedWithCronet(request: Request, call: Call): Response {
val callback = CronetUrlRequestCallback(request, call) val callback = CronetUrlRequestCallback(request, call)
val urlRequest = buildRequest(request, callback) val urlRequest = buildRequest(request, callback)
urlRequest.start() urlRequest.start()
return callback.waitForDone() return callback.waitForDone()
} }
private fun getCookie(url: HttpUrl): String {
val sb = StringBuilder()
//处理从 Cookjar 获取到的Cookies
if (cookieJar != null) {
val cookies = cookieJar.loadForRequest(url)
for (cookie in cookies) {
sb.append(cookie.name).append("=").append(cookie.value).append("; ")
}
}
//处理自定义的Cookie
val cookie = CookieStore.getCookie(url.toString())
if (cookie.length > 3) {
sb.append(cookie)
}
return sb.toString()
}
} }

@ -142,9 +142,9 @@ object CronetLoader : CronetEngine.Builder.LibraryLoader() {
@Suppress("SameParameterValue") @Suppress("SameParameterValue")
private fun getUrlMd5(url: String): String? { private fun getUrlMd5(url: String): String? {
//这样在下载成功后,遇到无网条件下,只要版本未发生变化也能获取md5 //这样在下载成功后,遇到无网条件下,只要版本未发生变化也能获取md5
if (md5 != null && md5!!.length == 32&& version==ImplVersion.getCronetVersion()) { if (md5 != null && md5!!.length == 32 && version == ImplVersion.getCronetVersion()) {
appCtx.putPrefString("soMd5",md5) appCtx.putPrefString("soMd5", md5)
appCtx.putPrefString("soVersion",ImplVersion.getCronetVersion()) appCtx.putPrefString("soVersion", ImplVersion.getCronetVersion())
return md5 return md5
} }
val inputStream: InputStream val inputStream: InputStream
@ -159,11 +159,11 @@ object CronetLoader : CronetEngine.Builder.LibraryLoader() {
outputStream.write(buffer, 0, read) outputStream.write(buffer, 0, read)
outputStream.flush() outputStream.flush()
} }
val tmd5=outputStream.toString() val tmd5 = outputStream.toString()
//成功获取到md5后保存md5和版本 //成功获取到md5后保存md5和版本
if(tmd5.length==32){ if (tmd5.length == 32) {
appCtx.putPrefString("soMd5",tmd5) appCtx.putPrefString("soMd5", tmd5)
appCtx.putPrefString("soVersion",ImplVersion.getCronetVersion()) appCtx.putPrefString("soVersion", ImplVersion.getCronetVersion())
} }
return tmd5 return tmd5

@ -6,14 +6,13 @@ import io.legado.app.help.http.okHttpClient
import okhttp3.* import okhttp3.*
import okhttp3.EventListener import okhttp3.EventListener
import okhttp3.MediaType.Companion.toMediaTypeOrNull import okhttp3.MediaType.Companion.toMediaTypeOrNull
import okhttp3.ResponseBody.Companion.toResponseBody import okhttp3.ResponseBody.Companion.asResponseBody
import okio.Buffer
import org.chromium.net.CronetException import org.chromium.net.CronetException
import org.chromium.net.UrlRequest import org.chromium.net.UrlRequest
import org.chromium.net.UrlResponseInfo import org.chromium.net.UrlResponseInfo
import java.io.ByteArrayOutputStream
import java.io.IOException import java.io.IOException
import java.nio.ByteBuffer import java.nio.ByteBuffer
import java.nio.channels.Channels
import java.util.* import java.util.*
class CronetUrlRequestCallback @JvmOverloads internal constructor( class CronetUrlRequestCallback @JvmOverloads internal constructor(
@ -29,8 +28,7 @@ class CronetUrlRequestCallback @JvmOverloads internal constructor(
private var mResponse: Response private var mResponse: Response
private var mException: IOException? = null private var mException: IOException? = null
private val mResponseCondition = ConditionVariable() private val mResponseCondition = ConditionVariable()
private val mBytesReceived = ByteArrayOutputStream() private val mBuffer = Buffer()
private val mReceiveChannel = Channels.newChannel(mBytesReceived)
@Throws(IOException::class) @Throws(IOException::class)
fun waitForDone(): Response { fun waitForDone(): Response {
@ -64,6 +62,7 @@ class CronetUrlRequestCallback @JvmOverloads internal constructor(
override fun onResponseStarted(request: UrlRequest, info: UrlResponseInfo) { override fun onResponseStarted(request: UrlRequest, info: UrlResponseInfo) {
this.mResponse = responseFromResponse(this.mResponse, info) this.mResponse = responseFromResponse(this.mResponse, info)
// 用于调试
// val sb: StringBuilder = StringBuilder(info.url).append("\r\n") // val sb: StringBuilder = StringBuilder(info.url).append("\r\n")
// sb.append("[Cached:").append(info.wasCached()).append("][StatusCode:") // sb.append("[Cached:").append(info.wasCached()).append("][StatusCode:")
// .append(info.httpStatusCode).append("][StatusText:").append(info.httpStatusText) // .append(info.httpStatusCode).append("][StatusText:").append(info.httpStatusText)
@ -74,6 +73,8 @@ class CronetUrlRequestCallback @JvmOverloads internal constructor(
// sb.append("[").append(h.key).append("]").append(h.value).append("\r\n"); // sb.append("[").append(h.key).append("]").append(h.value).append("\r\n");
// } // }
// Log.e("Cronet", sb.toString()) // Log.e("Cronet", sb.toString())
//打印协议,用于调试
Log.e("Cronet", info.negotiatedProtocol)
if (eventListener != null) { if (eventListener != null) {
eventListener.responseHeadersEnd(mCall, this.mResponse) eventListener.responseHeadersEnd(mCall, this.mResponse)
eventListener.responseBodyStart(mCall) eventListener.responseBodyStart(mCall)
@ -89,7 +90,8 @@ class CronetUrlRequestCallback @JvmOverloads internal constructor(
) { ) {
byteBuffer.flip() byteBuffer.flip()
try { try {
mReceiveChannel.write(byteBuffer) //mReceiveChannel.write(byteBuffer)
mBuffer.write(byteBuffer)
} catch (e: IOException) { } catch (e: IOException) {
Log.i(TAG, "IOException during ByteBuffer read. Details: ", e) Log.i(TAG, "IOException during ByteBuffer read. Details: ", e)
throw e throw e
@ -102,8 +104,10 @@ class CronetUrlRequestCallback @JvmOverloads internal constructor(
eventListener?.responseBodyEnd(mCall, info.receivedByteCount) eventListener?.responseBodyEnd(mCall, info.receivedByteCount)
val contentType: MediaType? = (this.mResponse.header("content-type") val contentType: MediaType? = (this.mResponse.header("content-type")
?: "text/plain; charset=\"utf-8\"").toMediaTypeOrNull() ?: "text/plain; charset=\"utf-8\"").toMediaTypeOrNull()
// val responseBody: ResponseBody =
// mBytesReceived.toByteArray().toResponseBody(contentType)
val responseBody: ResponseBody = val responseBody: ResponseBody =
mBytesReceived.toByteArray().toResponseBody(contentType) mBuffer.asResponseBody(contentType)
val newRequest = originalRequest.newBuilder().url(info.url).build() val newRequest = originalRequest.newBuilder().url(info.url).build()
this.mResponse = this.mResponse.newBuilder().body(responseBody).request(newRequest).build() this.mResponse = this.mResponse.newBuilder().body(responseBody).request(newRequest).build()
mResponseCondition.open() mResponseCondition.open()

@ -58,7 +58,8 @@ object Restore {
//默认忽略keys //默认忽略keys
private val ignorePrefKeys = arrayOf( private val ignorePrefKeys = arrayOf(
PreferKey.defaultCover PreferKey.defaultCover,
PreferKey.defaultCoverDark
) )
private val readPrefKeys = arrayOf( private val readPrefKeys = arrayOf(
PreferKey.readStyleSelect, PreferKey.readStyleSelect,

@ -176,6 +176,7 @@ class ImportBookSourceDialog : BaseDialogFragment(), Toolbar.OnMenuItemClickList
appDb.bookSourceDao.allGroup.forEach { group -> appDb.bookSourceDao.allGroup.forEach { group ->
groups.addAll(group.splitNotBlank(AppPattern.splitGroupRegex)) groups.addAll(group.splitNotBlank(AppPattern.splitGroupRegex))
} }
textInputLayout.setHint(R.string.group_name)
editView.setFilterValues(groups.toList()) editView.setFilterValues(groups.toList())
editView.dropDownHeight = 180.dp editView.dropDownHeight = 180.dp
} }

@ -172,6 +172,7 @@ class ImportRssSourceDialog : BaseDialogFragment(), Toolbar.OnMenuItemClickListe
appDb.rssSourceDao.allGroup.forEach { group -> appDb.rssSourceDao.allGroup.forEach { group ->
groups.addAll(group.splitNotBlank(AppPattern.splitGroupRegex)) groups.addAll(group.splitNotBlank(AppPattern.splitGroupRegex))
} }
textInputLayout.setHint(R.string.group_name)
editView.setFilterValues(groups.toList()) editView.setFilterValues(groups.toList())
editView.dropDownHeight = 180.dp editView.dropDownHeight = 180.dp
} }

@ -298,6 +298,7 @@ class CacheActivity : VMBaseActivity<ActivityCacheBookBinding, CacheViewModel>()
private fun alertExportFileName() { private fun alertExportFileName() {
alert(R.string.export_file_name) { alert(R.string.export_file_name) {
val alertBinding = DialogEditTextBinding.inflate(layoutInflater).apply { val alertBinding = DialogEditTextBinding.inflate(layoutInflater).apply {
textInputLayout.hint = "file name js"
editView.setText(AppConfig.bookExportFileName) editView.setText(AppConfig.bookExportFileName)
} }
customView { alertBinding.root } customView { alertBinding.root }
@ -317,6 +318,7 @@ class CacheActivity : VMBaseActivity<ActivityCacheBookBinding, CacheViewModel>()
private fun showCharsetConfig() { private fun showCharsetConfig() {
alert(R.string.set_charset) { alert(R.string.set_charset) {
val alertBinding = DialogEditTextBinding.inflate(layoutInflater).apply { val alertBinding = DialogEditTextBinding.inflate(layoutInflater).apply {
textInputLayout.hint = "charset name"
editView.setFilterValues(charsets) editView.setFilterValues(charsets)
editView.setText(AppConfig.exportCharset) editView.setText(AppConfig.exportCharset)
} }

@ -14,9 +14,8 @@ import io.legado.app.base.BaseDialogFragment
import io.legado.app.databinding.DialogChangeCoverBinding import io.legado.app.databinding.DialogChangeCoverBinding
import io.legado.app.lib.theme.primaryColor import io.legado.app.lib.theme.primaryColor
import io.legado.app.utils.applyTint import io.legado.app.utils.applyTint
import io.legado.app.utils.getSize
import io.legado.app.utils.viewbindingdelegate.viewBinding import io.legado.app.utils.viewbindingdelegate.viewBinding
import io.legado.app.utils.windowSize
class ChangeCoverDialog : BaseDialogFragment(), class ChangeCoverDialog : BaseDialogFragment(),
@ -45,7 +44,7 @@ class ChangeCoverDialog : BaseDialogFragment(),
override fun onStart() { override fun onStart() {
super.onStart() super.onStart()
val dm = requireActivity().getSize() val dm = requireActivity().windowSize
dialog?.window?.setLayout((dm.widthPixels * 0.9).toInt(), (dm.heightPixels * 0.9).toInt()) dialog?.window?.setLayout((dm.widthPixels * 0.9).toInt(), (dm.heightPixels * 0.9).toInt())
} }

@ -53,7 +53,7 @@ class ChangeSourceDialog : BaseDialogFragment(),
override fun onStart() { override fun onStart() {
super.onStart() super.onStart()
val dm = requireActivity().getSize() val dm = requireActivity().windowSize
dialog?.window?.setLayout((dm.widthPixels * 0.9).toInt(), (dm.heightPixels * 0.9).toInt()) dialog?.window?.setLayout((dm.widthPixels * 0.9).toInt(), (dm.heightPixels * 0.9).toInt())
} }

@ -15,7 +15,7 @@ object GroupEdit {
fun show(context: Context, layoutInflater: LayoutInflater, bookGroup: BookGroup) = context.run { fun show(context: Context, layoutInflater: LayoutInflater, bookGroup: BookGroup) = context.run {
alert(title = getString(R.string.group_edit)) { alert(title = getString(R.string.group_edit)) {
val alertBinding = DialogEditTextBinding.inflate(layoutInflater).apply { val alertBinding = DialogEditTextBinding.inflate(layoutInflater).apply {
editView.setHint(R.string.group_name) textInputLayout.setHint(R.string.group_name)
editView.setText(bookGroup.groupName) editView.setText(bookGroup.groupName)
} }
if (bookGroup.groupId >= 0) { if (bookGroup.groupId >= 0) {

@ -28,10 +28,10 @@ import io.legado.app.lib.theme.primaryColor
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.applyTint import io.legado.app.utils.applyTint
import io.legado.app.utils.getSize
import io.legado.app.utils.requestInputMethod import io.legado.app.utils.requestInputMethod
import io.legado.app.utils.viewbindingdelegate.viewBinding import io.legado.app.utils.viewbindingdelegate.viewBinding
import io.legado.app.utils.visible import io.legado.app.utils.visible
import io.legado.app.utils.windowSize
import kotlinx.coroutines.flow.collect import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
@ -43,7 +43,7 @@ class GroupManageDialog : BaseDialogFragment(), Toolbar.OnMenuItemClickListener
override fun onStart() { override fun onStart() {
super.onStart() super.onStart()
val dm = requireActivity().getSize() val dm = requireActivity().windowSize
dialog?.window?.setLayout((dm.widthPixels * 0.9).toInt(), (dm.heightPixels * 0.9).toInt()) dialog?.window?.setLayout((dm.widthPixels * 0.9).toInt(), (dm.heightPixels * 0.9).toInt())
} }
@ -103,7 +103,7 @@ class GroupManageDialog : BaseDialogFragment(), Toolbar.OnMenuItemClickListener
private fun addGroup() { private fun addGroup() {
alert(title = getString(R.string.add_group)) { alert(title = getString(R.string.add_group)) {
val alertBinding = DialogEditTextBinding.inflate(layoutInflater).apply { val alertBinding = DialogEditTextBinding.inflate(layoutInflater).apply {
editView.setHint(R.string.group_name) textInputLayout.setHint(R.string.group_name)
} }
customView { alertBinding.root } customView { alertBinding.root }
yesButton { yesButton {

@ -29,9 +29,9 @@ import io.legado.app.lib.theme.primaryColor
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.applyTint import io.legado.app.utils.applyTint
import io.legado.app.utils.getSize
import io.legado.app.utils.requestInputMethod import io.legado.app.utils.requestInputMethod
import io.legado.app.utils.viewbindingdelegate.viewBinding import io.legado.app.utils.viewbindingdelegate.viewBinding
import io.legado.app.utils.windowSize
import kotlinx.coroutines.flow.collect import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
@ -61,7 +61,7 @@ class GroupSelectDialog : BaseDialogFragment(), Toolbar.OnMenuItemClickListener
override fun onStart() { override fun onStart() {
super.onStart() super.onStart()
val dm = requireActivity().getSize() val dm = requireActivity().windowSize
dialog?.window?.setLayout((dm.widthPixels * 0.9).toInt(), (dm.heightPixels * 0.9).toInt()) dialog?.window?.setLayout((dm.widthPixels * 0.9).toInt(), (dm.heightPixels * 0.9).toInt())
} }
@ -125,7 +125,7 @@ class GroupSelectDialog : BaseDialogFragment(), Toolbar.OnMenuItemClickListener
private fun addGroup() { private fun addGroup() {
alert(title = getString(R.string.add_group)) { alert(title = getString(R.string.add_group)) {
val alertBinding = DialogEditTextBinding.inflate(layoutInflater).apply { val alertBinding = DialogEditTextBinding.inflate(layoutInflater).apply {
editView.setHint(R.string.group_name) textInputLayout.setHint(R.string.group_name)
} }
customView { alertBinding.root } customView { alertBinding.root }
yesButton { yesButton {
@ -143,7 +143,7 @@ class GroupSelectDialog : BaseDialogFragment(), Toolbar.OnMenuItemClickListener
private fun editGroup(bookGroup: BookGroup) { private fun editGroup(bookGroup: BookGroup) {
alert(title = getString(R.string.group_edit)) { alert(title = getString(R.string.group_edit)) {
val alertBinding = DialogEditTextBinding.inflate(layoutInflater).apply { val alertBinding = DialogEditTextBinding.inflate(layoutInflater).apply {
editView.setHint(R.string.group_name) textInputLayout.setHint(R.string.group_name)
editView.setText(bookGroup.groupName) editView.setText(bookGroup.groupName)
} }
customView { alertBinding.root } customView { alertBinding.root }

@ -280,6 +280,7 @@ class ImportBookActivity : VMBaseActivity<ActivityImportBookBinding, ImportBookV
private fun alertImportFileName() { private fun alertImportFileName() {
alert(R.string.import_file_name) { alert(R.string.import_file_name) {
val alertBinding = DialogEditTextBinding.inflate(layoutInflater).apply { val alertBinding = DialogEditTextBinding.inflate(layoutInflater).apply {
textInputLayout.hint = "js"
editView.setText(AppConfig.bookImportFileName) editView.setText(AppConfig.bookImportFileName)
} }
customView { alertBinding.root } customView { alertBinding.root }

@ -700,7 +700,9 @@ class ReadBookActivity : ReadBookBaseActivity(),
var delayMillis = ReadBookConfig.autoReadSpeed * 1000L / binding.readView.height var delayMillis = ReadBookConfig.autoReadSpeed * 1000L / binding.readView.height
var scrollOffset = 1 var scrollOffset = 1
if (delayMillis < 20) { if (delayMillis < 20) {
scrollOffset = 20 / delayMillis.toInt() var delayInt=delayMillis.toInt()
if(delayInt==0)delayInt =1
scrollOffset = 20 / delayInt
delayMillis = 20 delayMillis = 20
} }
mHandler.removeCallbacks(autoPageRunnable) mHandler.removeCallbacks(autoPageRunnable)

@ -202,6 +202,7 @@ abstract class ReadBookBaseActivity :
fun showCharsetConfig() { fun showCharsetConfig() {
alert(R.string.set_charset) { alert(R.string.set_charset) {
val alertBinding = DialogEditTextBinding.inflate(layoutInflater).apply { val alertBinding = DialogEditTextBinding.inflate(layoutInflater).apply {
textInputLayout.hint = "charset"
editView.setFilterValues(charsets) editView.setFilterValues(charsets)
editView.setText(ReadBook.book?.charset) editView.setText(ReadBook.book?.charset)
} }

@ -73,7 +73,7 @@ class AutoReadDialog : BaseDialogFragment() {
} }
private fun initData() { private fun initData() {
val speed = if (ReadBookConfig.autoReadSpeed < 10) 10 else ReadBookConfig.autoReadSpeed val speed = if (ReadBookConfig.autoReadSpeed < 2) 2 else ReadBookConfig.autoReadSpeed
binding.tvReadSpeed.text = String.format("%ds", speed) binding.tvReadSpeed.text = String.format("%ds", speed)
binding.seekAutoRead.progress = speed binding.seekAutoRead.progress = speed
} }
@ -81,13 +81,13 @@ class AutoReadDialog : BaseDialogFragment() {
private fun initOnChange() { private fun initOnChange() {
binding.seekAutoRead.setOnSeekBarChangeListener(object : SeekBarChangeListener { binding.seekAutoRead.setOnSeekBarChangeListener(object : SeekBarChangeListener {
override fun onProgressChanged(seekBar: SeekBar, progress: Int, fromUser: Boolean) { override fun onProgressChanged(seekBar: SeekBar, progress: Int, fromUser: Boolean) {
val speed = if (progress < 10) 10 else progress val speed = if (progress < 2) 2 else progress
binding.tvReadSpeed.text = String.format("%ds", speed) binding.tvReadSpeed.text = String.format("%ds", speed)
} }
override fun onStopTrackingTouch(seekBar: SeekBar) { override fun onStopTrackingTouch(seekBar: SeekBar) {
ReadBookConfig.autoReadSpeed = ReadBookConfig.autoReadSpeed =
if (binding.seekAutoRead.progress < 10) 10 else binding.seekAutoRead.progress if (binding.seekAutoRead.progress < 2) 2 else binding.seekAutoRead.progress
upTtsSpeechRate() upTtsSpeechRate()
} }
}) })

@ -47,12 +47,12 @@ class BgTextConfigDialog : BaseDialogFragment() {
private var secondaryTextColor = 0 private var secondaryTextColor = 0
private val importFormNet = "网络导入" private val importFormNet = "网络导入"
private val selectBgImage = registerForActivityResult(ActivityResultContracts.GetContent()) { private val selectBgImage = registerForActivityResult(ActivityResultContracts.GetContent()) {
it ?: return@registerForActivityResult
setBgFromUri(it) setBgFromUri(it)
} }
private val selectExportDir = registerForActivityResult(FilePicker()) { private val selectExportDir = registerForActivityResult(FilePicker()) {
it?.let { it ?: return@registerForActivityResult
exportConfig(it) exportConfig(it)
}
} }
private val selectImportDoc = registerForActivityResult(FilePicker()) { private val selectImportDoc = registerForActivityResult(FilePicker()) {
it ?: return@registerForActivityResult it ?: return@registerForActivityResult
@ -142,6 +142,7 @@ class BgTextConfigDialog : BaseDialogFragment() {
binding.ivEdit.setOnClickListener { binding.ivEdit.setOnClickListener {
alert(R.string.style_name) { alert(R.string.style_name) {
val alertBinding = DialogEditTextBinding.inflate(layoutInflater).apply { val alertBinding = DialogEditTextBinding.inflate(layoutInflater).apply {
textInputLayout.hint = "name"
editView.setText(ReadBookConfig.durConfig.name) editView.setText(ReadBookConfig.durConfig.name)
} }
customView { alertBinding.root } customView { alertBinding.root }

@ -11,9 +11,9 @@ import io.legado.app.base.BaseDialogFragment
import io.legado.app.constant.EventBus import io.legado.app.constant.EventBus
import io.legado.app.databinding.DialogReadPaddingBinding import io.legado.app.databinding.DialogReadPaddingBinding
import io.legado.app.help.ReadBookConfig import io.legado.app.help.ReadBookConfig
import io.legado.app.utils.getSize
import io.legado.app.utils.postEvent import io.legado.app.utils.postEvent
import io.legado.app.utils.viewbindingdelegate.viewBinding import io.legado.app.utils.viewbindingdelegate.viewBinding
import io.legado.app.utils.windowSize
class PaddingConfigDialog : BaseDialogFragment() { class PaddingConfigDialog : BaseDialogFragment() {
@ -21,7 +21,7 @@ class PaddingConfigDialog : BaseDialogFragment() {
override fun onStart() { override fun onStart() {
super.onStart() super.onStart()
val dm = requireActivity().getSize() val dm = requireActivity().windowSize
dialog?.window?.let { dialog?.window?.let {
it.clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND) it.clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND)
val attr = it.attributes val attr = it.attributes

@ -19,8 +19,8 @@ import io.legado.app.lib.theme.backgroundColor
import io.legado.app.service.BaseReadAloudService import io.legado.app.service.BaseReadAloudService
import io.legado.app.service.help.ReadAloud import io.legado.app.service.help.ReadAloud
import io.legado.app.utils.getPrefLong import io.legado.app.utils.getPrefLong
import io.legado.app.utils.getSize
import io.legado.app.utils.postEvent import io.legado.app.utils.postEvent
import io.legado.app.utils.windowSize
import splitties.init.appCtx import splitties.init.appCtx
class ReadAloudConfigDialog : DialogFragment() { class ReadAloudConfigDialog : DialogFragment() {
@ -28,7 +28,7 @@ class ReadAloudConfigDialog : DialogFragment() {
override fun onStart() { override fun onStart() {
super.onStart() super.onStart()
val dm = requireActivity().getSize() val dm = requireActivity().windowSize
dialog?.window?.let { dialog?.window?.let {
it.setBackgroundDrawableResource(R.color.transparent) it.setBackgroundDrawableResource(R.color.transparent)
it.setLayout((dm.widthPixels * 0.9).toInt(), ViewGroup.LayoutParams.WRAP_CONTENT) it.setLayout((dm.widthPixels * 0.9).toInt(), ViewGroup.LayoutParams.WRAP_CONTENT)

@ -54,7 +54,7 @@ class SpeakEngineDialog : BaseDialogFragment(), Toolbar.OnMenuItemClickListener
override fun onStart() { override fun onStart() {
super.onStart() super.onStart()
val dm = requireActivity().getSize() val dm = requireActivity().windowSize
dialog?.window?.setLayout((dm.widthPixels * 0.9).toInt(), (dm.heightPixels * 0.9).toInt()) dialog?.window?.setLayout((dm.widthPixels * 0.9).toInt(), (dm.heightPixels * 0.9).toInt())
} }
@ -134,6 +134,7 @@ class SpeakEngineDialog : BaseDialogFragment(), Toolbar.OnMenuItemClickListener
?.toMutableList() ?: mutableListOf() ?.toMutableList() ?: mutableListOf()
alert(R.string.import_on_line) { alert(R.string.import_on_line) {
val alertBinding = DialogEditTextBinding.inflate(layoutInflater).apply { val alertBinding = DialogEditTextBinding.inflate(layoutInflater).apply {
textInputLayout.hint = "url"
editView.setFilterValues(cacheUrls) editView.setFilterValues(cacheUrls)
editView.delCallBack = { editView.delCallBack = {
cacheUrls.remove(it) cacheUrls.remove(it)

@ -45,7 +45,7 @@ class TocRegexDialog : BaseDialogFragment(), Toolbar.OnMenuItemClickListener {
override fun onStart() { override fun onStart() {
super.onStart() super.onStart()
val dm = requireActivity().getSize() val dm = requireActivity().windowSize
dialog?.window?.setLayout((dm.widthPixels * 0.9).toInt(), (dm.heightPixels * 0.8).toInt()) dialog?.window?.setLayout((dm.widthPixels * 0.9).toInt(), (dm.heightPixels * 0.8).toInt())
} }
@ -135,8 +135,8 @@ class TocRegexDialog : BaseDialogFragment(), Toolbar.OnMenuItemClickListener {
cacheUrls.add(0, defaultUrl) cacheUrls.add(0, defaultUrl)
} }
requireContext().alert(titleResource = R.string.import_on_line) { requireContext().alert(titleResource = R.string.import_on_line) {
val alertBinding = DialogEditTextBinding.inflate(layoutInflater) val alertBinding = DialogEditTextBinding.inflate(layoutInflater).apply {
alertBinding.apply { textInputLayout.hint = "url"
editView.setFilterValues(cacheUrls) editView.setFilterValues(cacheUrls)
editView.delCallBack = { editView.delCallBack = {
cacheUrls.remove(it) cacheUrls.remove(it)

@ -444,7 +444,7 @@ class BookSourceEditActivity :
val rect = Rect() val rect = Rect()
// 获取当前页面窗口的显示范围 // 获取当前页面窗口的显示范围
window.decorView.getWindowVisibleDisplayFrame(rect) window.decorView.getWindowVisibleDisplayFrame(rect)
val screenHeight = this@BookSourceEditActivity.getSize().heightPixels val screenHeight = this@BookSourceEditActivity.windowSize.heightPixels
val keyboardHeight = screenHeight - rect.bottom // 输入法的高度 val keyboardHeight = screenHeight - rect.bottom // 输入法的高度
val preShowing = mIsSoftKeyBoardShowing val preShowing = mIsSoftKeyBoardShowing
if (abs(keyboardHeight) > screenHeight / 5) { if (abs(keyboardHeight) > screenHeight / 5) {

@ -327,6 +327,7 @@ class BookSourceActivity : VMBaseActivity<ActivityBookSourceBinding, BookSourceV
private fun checkSource() { private fun checkSource() {
alert(titleResource = R.string.search_book_key) { alert(titleResource = R.string.search_book_key) {
val alertBinding = DialogEditTextBinding.inflate(layoutInflater).apply { val alertBinding = DialogEditTextBinding.inflate(layoutInflater).apply {
textInputLayout.hint = "search word"
editView.setText(CheckSource.keyword) editView.setText(CheckSource.keyword)
} }
customView { alertBinding.root } customView { alertBinding.root }
@ -346,7 +347,7 @@ class BookSourceActivity : VMBaseActivity<ActivityBookSourceBinding, BookSourceV
private fun selectionAddToGroups() { private fun selectionAddToGroups() {
alert(titleResource = R.string.add_group) { alert(titleResource = R.string.add_group) {
val alertBinding = DialogEditTextBinding.inflate(layoutInflater).apply { val alertBinding = DialogEditTextBinding.inflate(layoutInflater).apply {
editView.setHint(R.string.group_name) textInputLayout.setHint(R.string.group_name)
editView.setFilterValues(groups.toList()) editView.setFilterValues(groups.toList())
editView.dropDownHeight = 180.dp editView.dropDownHeight = 180.dp
} }
@ -366,7 +367,7 @@ class BookSourceActivity : VMBaseActivity<ActivityBookSourceBinding, BookSourceV
private fun selectionRemoveFromGroups() { private fun selectionRemoveFromGroups() {
alert(titleResource = R.string.remove_group) { alert(titleResource = R.string.remove_group) {
val alertBinding = DialogEditTextBinding.inflate(layoutInflater).apply { val alertBinding = DialogEditTextBinding.inflate(layoutInflater).apply {
editView.setHint(R.string.group_name) textInputLayout.setHint(R.string.group_name)
editView.setFilterValues(groups.toList()) editView.setFilterValues(groups.toList())
editView.dropDownHeight = 180.dp editView.dropDownHeight = 180.dp
} }
@ -400,6 +401,7 @@ class BookSourceActivity : VMBaseActivity<ActivityBookSourceBinding, BookSourceV
?.toMutableList() ?: mutableListOf() ?.toMutableList() ?: mutableListOf()
alert(titleResource = R.string.import_on_line) { alert(titleResource = R.string.import_on_line) {
val alertBinding = DialogEditTextBinding.inflate(layoutInflater).apply { val alertBinding = DialogEditTextBinding.inflate(layoutInflater).apply {
textInputLayout.hint = "url"
editView.setFilterValues(cacheUrls) editView.setFilterValues(cacheUrls)
editView.delCallBack = { editView.delCallBack = {
cacheUrls.remove(it) cacheUrls.remove(it)

@ -24,10 +24,10 @@ import io.legado.app.lib.theme.backgroundColor
import io.legado.app.lib.theme.primaryColor import io.legado.app.lib.theme.primaryColor
import io.legado.app.ui.widget.recycler.VerticalDivider import io.legado.app.ui.widget.recycler.VerticalDivider
import io.legado.app.utils.applyTint import io.legado.app.utils.applyTint
import io.legado.app.utils.getSize
import io.legado.app.utils.requestInputMethod import io.legado.app.utils.requestInputMethod
import io.legado.app.utils.splitNotBlank import io.legado.app.utils.splitNotBlank
import io.legado.app.utils.viewbindingdelegate.viewBinding import io.legado.app.utils.viewbindingdelegate.viewBinding
import io.legado.app.utils.windowSize
import kotlinx.coroutines.flow.collect import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
@ -39,7 +39,7 @@ class GroupManageDialog : BaseDialogFragment(), Toolbar.OnMenuItemClickListener
override fun onStart() { override fun onStart() {
super.onStart() super.onStart()
val dm = requireActivity().getSize() val dm = requireActivity().windowSize
dialog?.window?.setLayout((dm.widthPixels * 0.9).toInt(), (dm.heightPixels * 0.9).toInt()) dialog?.window?.setLayout((dm.widthPixels * 0.9).toInt(), (dm.heightPixels * 0.9).toInt())
} }
@ -87,8 +87,9 @@ class GroupManageDialog : BaseDialogFragment(), Toolbar.OnMenuItemClickListener
@SuppressLint("InflateParams") @SuppressLint("InflateParams")
private fun addGroup() { private fun addGroup() {
alert(title = getString(R.string.add_group)) { alert(title = getString(R.string.add_group)) {
val alertBinding = DialogEditTextBinding.inflate(layoutInflater) val alertBinding = DialogEditTextBinding.inflate(layoutInflater).apply {
alertBinding.editView.setHint(R.string.group_name) textInputLayout.setHint(R.string.group_name)
}
customView { alertBinding.root } customView { alertBinding.root }
yesButton { yesButton {
alertBinding.editView.text?.toString()?.let { alertBinding.editView.text?.toString()?.let {
@ -104,9 +105,10 @@ class GroupManageDialog : BaseDialogFragment(), Toolbar.OnMenuItemClickListener
@SuppressLint("InflateParams") @SuppressLint("InflateParams")
private fun editGroup(group: String) { private fun editGroup(group: String) {
alert(title = getString(R.string.group_edit)) { alert(title = getString(R.string.group_edit)) {
val alertBinding = DialogEditTextBinding.inflate(layoutInflater) val alertBinding = DialogEditTextBinding.inflate(layoutInflater).apply {
alertBinding.editView.setHint(R.string.group_name) textInputLayout.setHint(R.string.group_name)
alertBinding.editView.setText(group) editView.setText(group)
}
customView { alertBinding.root } customView { alertBinding.root }
yesButton { yesButton {
viewModel.upGroup(group, alertBinding.editView.text?.toString()) viewModel.upGroup(group, alertBinding.editView.text?.toString())

@ -5,12 +5,9 @@ import android.content.ComponentName
import android.content.Intent import android.content.Intent
import android.content.SharedPreferences import android.content.SharedPreferences
import android.content.pm.PackageManager import android.content.pm.PackageManager
import android.net.Uri
import android.os.Bundle import android.os.Bundle
import android.os.Process import android.os.Process
import android.view.View import android.view.View
import androidx.activity.result.contract.ActivityResultContracts
import androidx.documentfile.provider.DocumentFile
import androidx.preference.ListPreference import androidx.preference.ListPreference
import androidx.preference.Preference import androidx.preference.Preference
import io.legado.app.R import io.legado.app.R
@ -21,18 +18,13 @@ import io.legado.app.databinding.DialogEditTextBinding
import io.legado.app.help.AppConfig import io.legado.app.help.AppConfig
import io.legado.app.help.BookHelp import io.legado.app.help.BookHelp
import io.legado.app.lib.dialogs.alert import io.legado.app.lib.dialogs.alert
import io.legado.app.lib.dialogs.selector
import io.legado.app.lib.permission.Permissions
import io.legado.app.lib.permission.PermissionsCompat
import io.legado.app.lib.theme.ATH import io.legado.app.lib.theme.ATH
import io.legado.app.receiver.SharedReceiverActivity import io.legado.app.receiver.SharedReceiverActivity
import io.legado.app.service.WebService import io.legado.app.service.WebService
import io.legado.app.ui.main.MainActivity import io.legado.app.ui.main.MainActivity
import io.legado.app.ui.widget.image.CoverImageView
import io.legado.app.ui.widget.number.NumberPickerDialog import io.legado.app.ui.widget.number.NumberPickerDialog
import io.legado.app.utils.* import io.legado.app.utils.*
import splitties.init.appCtx import splitties.init.appCtx
import java.io.File
class OtherConfigFragment : BasePreferenceFragment(), class OtherConfigFragment : BasePreferenceFragment(),
@ -44,10 +36,6 @@ class OtherConfigFragment : BasePreferenceFragment(),
SharedReceiverActivity::class.java.name SharedReceiverActivity::class.java.name
) )
private val webPort get() = getPrefInt(PreferKey.webPort, 1122) private val webPort get() = getPrefInt(PreferKey.webPort, 1122)
private val selectCoverImage = registerForActivityResult(ActivityResultContracts.GetContent()) {
it ?: return@registerForActivityResult
setCoverFromUri(it)
}
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
putPrefBoolean(PreferKey.processText, isProcessTextEnabled()) putPrefBoolean(PreferKey.processText, isProcessTextEnabled())
@ -56,7 +44,6 @@ class OtherConfigFragment : BasePreferenceFragment(),
upPreferenceSummary(PreferKey.preDownloadNum, AppConfig.preDownloadNum.toString()) upPreferenceSummary(PreferKey.preDownloadNum, AppConfig.preDownloadNum.toString())
upPreferenceSummary(PreferKey.threadCount, AppConfig.threadCount.toString()) upPreferenceSummary(PreferKey.threadCount, AppConfig.threadCount.toString())
upPreferenceSummary(PreferKey.webPort, webPort.toString()) upPreferenceSummary(PreferKey.webPort, webPort.toString())
upPreferenceSummary(PreferKey.defaultCover, getPrefString(PreferKey.defaultCover))
} }
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
@ -98,17 +85,7 @@ class OtherConfigFragment : BasePreferenceFragment(),
putPrefInt(PreferKey.webPort, it) putPrefInt(PreferKey.webPort, it)
} }
PreferKey.cleanCache -> clearCache() PreferKey.cleanCache -> clearCache()
PreferKey.defaultCover -> if (getPrefString(PreferKey.defaultCover).isNullOrEmpty()) {
selectCoverImage.launch("image/*")
} else {
selector(items = arrayListOf("删除图片", "选择图片")) { _, i ->
if (i == 0) {
removePref(PreferKey.defaultCover)
} else {
selectCoverImage.launch("image/*")
}
}
}
} }
return super.onPreferenceTreeClick(preference) return super.onPreferenceTreeClick(preference)
} }
@ -134,9 +111,6 @@ class OtherConfigFragment : BasePreferenceFragment(),
setProcessTextEnable(it.getBoolean(key, true)) setProcessTextEnable(it.getBoolean(key, true))
} }
PreferKey.showDiscovery, PreferKey.showRss -> postEvent(EventBus.NOTIFY_MAIN, true) PreferKey.showDiscovery, PreferKey.showRss -> postEvent(EventBus.NOTIFY_MAIN, true)
PreferKey.defaultCover -> upPreferenceSummary(
key, getPrefString(PreferKey.defaultCover)
)
PreferKey.language -> listView.postDelayed({ PreferKey.language -> listView.postDelayed({
LanguageUtils.setConfiguration(appCtx) LanguageUtils.setConfiguration(appCtx)
val intent = Intent(appCtx, MainActivity::class.java) val intent = Intent(appCtx, MainActivity::class.java)
@ -157,11 +131,6 @@ class OtherConfigFragment : BasePreferenceFragment(),
getString(R.string.pre_download_s, value) getString(R.string.pre_download_s, value)
PreferKey.threadCount -> preference.summary = getString(R.string.threads_num, value) PreferKey.threadCount -> preference.summary = getString(R.string.threads_num, value)
PreferKey.webPort -> preference.summary = getString(R.string.web_port_summary, value) PreferKey.webPort -> preference.summary = getString(R.string.web_port_summary, value)
PreferKey.defaultCover -> preference.summary = if (value.isNullOrBlank()) {
getString(R.string.select_image)
} else {
value
}
else -> if (preference is ListPreference) { else -> if (preference is ListPreference) {
val index = preference.findIndexOfValue(value) val index = preference.findIndexOfValue(value)
// Set the summary to reflect the new value. // Set the summary to reflect the new value.
@ -175,8 +144,10 @@ class OtherConfigFragment : BasePreferenceFragment(),
@SuppressLint("InflateParams") @SuppressLint("InflateParams")
private fun showUserAgentDialog() { private fun showUserAgentDialog() {
alert("UserAgent") { alert("UserAgent") {
val alertBinding = DialogEditTextBinding.inflate(layoutInflater) val alertBinding = DialogEditTextBinding.inflate(layoutInflater).apply {
alertBinding.editView.setText(AppConfig.userAgent) textInputLayout.hint = "UserAgent"
editView.setText(AppConfig.userAgent)
}
customView { alertBinding.root } customView { alertBinding.root }
okButton { okButton {
val userAgent = alertBinding.editView.text?.toString() val userAgent = alertBinding.editView.text?.toString()
@ -222,41 +193,4 @@ class OtherConfigFragment : BasePreferenceFragment(),
} }
} }
private fun setCoverFromUri(uri: Uri) {
if (uri.isContentScheme()) {
val doc = DocumentFile.fromSingleUri(requireContext(), uri)
doc?.name?.let {
var file = requireContext().externalFiles
file = FileUtils.createFileIfNotExist(file, "covers", it)
kotlin.runCatching {
DocumentUtils.readBytes(requireContext(), doc.uri)
}.getOrNull()?.let { byteArray ->
file.writeBytes(byteArray)
putPrefString(PreferKey.defaultCover, file.absolutePath)
CoverImageView.upDefaultCover()
} ?: toastOnUi("获取文件出错")
}
} else {
PermissionsCompat.Builder(this)
.addPermissions(
Permissions.READ_EXTERNAL_STORAGE,
Permissions.WRITE_EXTERNAL_STORAGE
)
.rationale(R.string.bg_image_per)
.onGranted {
RealPathUtil.getPath(requireContext(), uri)?.let { path ->
val imgFile = File(path)
if (imgFile.exists()) {
var file = requireContext().externalFiles
file = FileUtils.createFileIfNotExist(file, "covers", imgFile.name)
file.writeBytes(imgFile.readBytes())
putPrefString(PreferKey.defaultCover, file.absolutePath)
CoverImageView.upDefaultCover()
}
}
}
.request()
}
}
} }

@ -9,7 +9,7 @@ import android.view.Menu
import android.view.MenuInflater import android.view.MenuInflater
import android.view.MenuItem import android.view.MenuItem
import android.view.View import android.view.View
import androidx.activity.result.contract.ActivityResultContracts import android.widget.SeekBar
import androidx.documentfile.provider.DocumentFile import androidx.documentfile.provider.DocumentFile
import androidx.preference.Preference import androidx.preference.Preference
import io.legado.app.R import io.legado.app.R
@ -18,6 +18,7 @@ import io.legado.app.constant.AppConst
import io.legado.app.constant.EventBus import io.legado.app.constant.EventBus
import io.legado.app.constant.PreferKey import io.legado.app.constant.PreferKey
import io.legado.app.databinding.DialogEditTextBinding import io.legado.app.databinding.DialogEditTextBinding
import io.legado.app.databinding.DialogImageBlurringBinding
import io.legado.app.help.AppConfig import io.legado.app.help.AppConfig
import io.legado.app.help.LauncherIconHelp import io.legado.app.help.LauncherIconHelp
import io.legado.app.help.ThemeConfig import io.legado.app.help.ThemeConfig
@ -26,8 +27,10 @@ import io.legado.app.lib.dialogs.selector
import io.legado.app.lib.permission.Permissions import io.legado.app.lib.permission.Permissions
import io.legado.app.lib.permission.PermissionsCompat import io.legado.app.lib.permission.PermissionsCompat
import io.legado.app.lib.theme.ATH import io.legado.app.lib.theme.ATH
import io.legado.app.ui.widget.image.CoverImageView
import io.legado.app.ui.widget.number.NumberPickerDialog import io.legado.app.ui.widget.number.NumberPickerDialog
import io.legado.app.ui.widget.prefs.ColorPreference import io.legado.app.ui.widget.prefs.ColorPreference
import io.legado.app.ui.widget.seekbar.SeekBarChangeListener
import io.legado.app.utils.* import io.legado.app.utils.*
import java.io.File import java.io.File
@ -35,17 +38,21 @@ import java.io.File
@Suppress("SameParameterValue") @Suppress("SameParameterValue")
class ThemeConfigFragment : BasePreferenceFragment(), class ThemeConfigFragment : BasePreferenceFragment(),
SharedPreferences.OnSharedPreferenceChangeListener { SharedPreferences.OnSharedPreferenceChangeListener {
private val requestCodeCover = 111
private val selectLightBg = registerForActivityResult(ActivityResultContracts.GetContent()) { private val requestCodeCoverDark = 112
it ?: return@registerForActivityResult private val requestCodeBgLight = 121
setBgFromUri(it, PreferKey.bgImage) { private val requestCodeBgDark = 122
upTheme(false) private val selectImage = registerForActivityResult(ActivityResultContractUtils.SelectImage()) {
} val uri = it?.second ?: return@registerForActivityResult
} when (it.first) {
private val selectDarkBg = registerForActivityResult(ActivityResultContracts.GetContent()) { requestCodeCover -> setCoverFromUri(PreferKey.defaultCover, uri)
it ?: return@registerForActivityResult requestCodeCoverDark -> setCoverFromUri(PreferKey.defaultCoverDark, uri)
setBgFromUri(it, PreferKey.bgImageN) { requestCodeBgLight -> setBgFromUri(uri, PreferKey.bgImage) {
upTheme(true) upTheme(false)
}
requestCodeBgDark -> setBgFromUri(uri, PreferKey.bgImageN) {
upTheme(true)
}
} }
} }
@ -57,6 +64,8 @@ class ThemeConfigFragment : BasePreferenceFragment(),
upPreferenceSummary(PreferKey.bgImage, getPrefString(PreferKey.bgImage)) upPreferenceSummary(PreferKey.bgImage, getPrefString(PreferKey.bgImage))
upPreferenceSummary(PreferKey.bgImageN, getPrefString(PreferKey.bgImageN)) upPreferenceSummary(PreferKey.bgImageN, getPrefString(PreferKey.bgImageN))
upPreferenceSummary(PreferKey.barElevation, AppConfig.elevation.toString()) upPreferenceSummary(PreferKey.barElevation, AppConfig.elevation.toString())
upPreferenceSummary(PreferKey.defaultCover, getPrefString(PreferKey.defaultCover))
upPreferenceSummary(PreferKey.defaultCoverDark, getPrefString(PreferKey.defaultCoverDark))
findPreference<ColorPreference>(PreferKey.cBackground)?.let { findPreference<ColorPreference>(PreferKey.cBackground)?.let {
it.onSaveColor = { color -> it.onSaveColor = { color ->
if (!ColorUtils.isColorLight(color)) { if (!ColorUtils.isColorLight(color)) {
@ -85,14 +94,14 @@ class ThemeConfigFragment : BasePreferenceFragment(),
setHasOptionsMenu(true) setHasOptionsMenu(true)
} }
override fun onResume() { override fun onCreate(savedInstanceState: Bundle?) {
super.onResume() super.onCreate(savedInstanceState)
preferenceManager.sharedPreferences.registerOnSharedPreferenceChangeListener(this) preferenceManager.sharedPreferences.registerOnSharedPreferenceChangeListener(this)
} }
override fun onPause() { override fun onDestroy() {
super.onDestroy()
preferenceManager.sharedPreferences.unregisterOnSharedPreferenceChangeListener(this) preferenceManager.sharedPreferences.unregisterOnSharedPreferenceChangeListener(this)
super.onPause()
} }
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) { override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
@ -128,6 +137,12 @@ class ThemeConfigFragment : BasePreferenceFragment(),
PreferKey.cNBBackground -> { PreferKey.cNBBackground -> {
upTheme(true) upTheme(true)
} }
PreferKey.bgImage,
PreferKey.bgImageN,
PreferKey.defaultCover,
PreferKey.defaultCoverDark -> {
upPreferenceSummary(key, getPrefString(key))
}
} }
} }
@ -151,29 +166,58 @@ class ThemeConfigFragment : BasePreferenceFragment(),
"themeList" -> ThemeListDialog().show(childFragmentManager, "themeList") "themeList" -> ThemeListDialog().show(childFragmentManager, "themeList")
"saveDayTheme", "saveNightTheme" -> saveThemeAlert(key) "saveDayTheme", "saveNightTheme" -> saveThemeAlert(key)
PreferKey.bgImage -> if (getPrefString(PreferKey.bgImage).isNullOrEmpty()) { PreferKey.bgImage -> if (getPrefString(PreferKey.bgImage).isNullOrEmpty()) {
selectLightBg.launch("image/*") selectImage.launch(requestCodeBgLight)
} else { } else {
selector(items = arrayListOf("删除图片", "选择图片")) { _, i -> selector(items = arrayListOf("删除图片", "选择图片")) { _, i ->
if (i == 0) { if (i == 0) {
removePref(PreferKey.bgImage) removePref(PreferKey.bgImage)
upTheme(false) upTheme(false)
} else { } else {
selectLightBg.launch("image/*") selectImage.launch(requestCodeBgLight)
} }
} }
} }
PreferKey.bgImageN -> if (getPrefString(PreferKey.bgImageN).isNullOrEmpty()) { PreferKey.bgImageN -> if (getPrefString(PreferKey.bgImageN).isNullOrEmpty()) {
selectDarkBg.launch("image/*") selectImage.launch(requestCodeBgDark)
} else { } else {
selector(items = arrayListOf("删除图片", "选择图片")) { _, i -> selector(items = arrayListOf("删除图片", "选择图片")) { _, i ->
if (i == 0) { if (i == 0) {
removePref(PreferKey.bgImageN) removePref(PreferKey.bgImageN)
upTheme(true) upTheme(true)
} else { } else {
selectDarkBg.launch("image/*") selectImage.launch(requestCodeBgDark)
}
}
}
PreferKey.bgImageBlurring -> alertImageBlurring(PreferKey.bgImageBlurring) {
upTheme(false)
}
PreferKey.bgImageNBlurring -> alertImageBlurring(PreferKey.bgImageNBlurring) {
upTheme(true)
}
PreferKey.defaultCover -> if (getPrefString(PreferKey.defaultCover).isNullOrEmpty()) {
selectImage.launch(requestCodeCover)
} else {
selector(items = arrayListOf("删除图片", "选择图片")) { _, i ->
if (i == 0) {
removePref(PreferKey.defaultCover)
} else {
selectImage.launch(requestCodeCover)
} }
} }
} }
PreferKey.defaultCoverDark ->
if (getPrefString(PreferKey.defaultCoverDark).isNullOrEmpty()) {
selectImage.launch(requestCodeCoverDark)
} else {
selector(items = arrayListOf("删除图片", "选择图片")) { _, i ->
if (i == 0) {
removePref(PreferKey.defaultCoverDark)
} else {
selectImage.launch(requestCodeCoverDark)
}
}
}
} }
return super.onPreferenceTreeClick(preference) return super.onPreferenceTreeClick(preference)
} }
@ -181,7 +225,9 @@ class ThemeConfigFragment : BasePreferenceFragment(),
@SuppressLint("InflateParams") @SuppressLint("InflateParams")
private fun saveThemeAlert(key: String) { private fun saveThemeAlert(key: String) {
alert(R.string.theme_name) { alert(R.string.theme_name) {
val alertBinding = DialogEditTextBinding.inflate(layoutInflater) val alertBinding = DialogEditTextBinding.inflate(layoutInflater).apply {
textInputLayout.hint = "name"
}
customView { alertBinding.root } customView { alertBinding.root }
okButton { okButton {
alertBinding.editView.text?.toString()?.let { themeName -> alertBinding.editView.text?.toString()?.let { themeName ->
@ -199,6 +245,34 @@ class ThemeConfigFragment : BasePreferenceFragment(),
}.show() }.show()
} }
private fun alertImageBlurring(preferKey: String, success: () -> Unit) {
alert(R.string.background_image_blurring) {
val alertBinding = DialogImageBlurringBinding.inflate(layoutInflater).apply {
getPrefInt(preferKey, 0).let {
seekBar.progress = it
textViewValue.text = it.toString()
}
seekBar.setOnSeekBarChangeListener(object : SeekBarChangeListener {
override fun onProgressChanged(
seekBar: SeekBar,
progress: Int,
fromUser: Boolean
) {
textViewValue.text = progress.toString()
}
})
}
customView { alertBinding.root }
okButton {
alertBinding.seekBar.progress.let {
putPrefInt(preferKey, it)
success.invoke()
}
}
noButton()
}.show()
}
private fun upTheme(isNightTheme: Boolean) { private fun upTheme(isNightTheme: Boolean) {
if (AppConfig.isNightTheme == isNightTheme) { if (AppConfig.isNightTheme == isNightTheme) {
listView.post { listView.post {
@ -217,6 +291,14 @@ class ThemeConfigFragment : BasePreferenceFragment(),
when (preferenceKey) { when (preferenceKey) {
PreferKey.barElevation -> preference.summary = PreferKey.barElevation -> preference.summary =
getString(R.string.bar_elevation_s, value) getString(R.string.bar_elevation_s, value)
PreferKey.bgImage,
PreferKey.bgImageN,
PreferKey.defaultCover,
PreferKey.defaultCoverDark -> preference.summary = if (value.isNullOrBlank()) {
getString(R.string.select_image)
} else {
value
}
else -> preference.summary = value else -> preference.summary = value
} }
} }
@ -232,7 +314,6 @@ class ThemeConfigFragment : BasePreferenceFragment(),
}.getOrNull()?.let { byteArray -> }.getOrNull()?.let { byteArray ->
file.writeBytes(byteArray) file.writeBytes(byteArray)
putPrefString(preferenceKey, file.absolutePath) putPrefString(preferenceKey, file.absolutePath)
upPreferenceSummary(preferenceKey, file.absolutePath)
success() success()
} ?: toastOnUi("获取文件出错") } ?: toastOnUi("获取文件出错")
} }
@ -251,7 +332,6 @@ class ThemeConfigFragment : BasePreferenceFragment(),
file = FileUtils.createFileIfNotExist(file, preferenceKey, imgFile.name) file = FileUtils.createFileIfNotExist(file, preferenceKey, imgFile.name)
file.writeBytes(imgFile.readBytes()) file.writeBytes(imgFile.readBytes())
putPrefString(preferenceKey, file.absolutePath) putPrefString(preferenceKey, file.absolutePath)
upPreferenceSummary(preferenceKey, file.absolutePath)
success() success()
} }
} }
@ -260,4 +340,41 @@ class ThemeConfigFragment : BasePreferenceFragment(),
} }
} }
private fun setCoverFromUri(preferenceKey: String, uri: Uri) {
if (uri.isContentScheme()) {
val doc = DocumentFile.fromSingleUri(requireContext(), uri)
doc?.name?.let {
var file = requireContext().externalFiles
file = FileUtils.createFileIfNotExist(file, "covers", it)
kotlin.runCatching {
DocumentUtils.readBytes(requireContext(), doc.uri)
}.getOrNull()?.let { byteArray ->
file.writeBytes(byteArray)
putPrefString(preferenceKey, file.absolutePath)
CoverImageView.upDefaultCover()
} ?: toastOnUi("获取文件出错")
}
} else {
PermissionsCompat.Builder(this)
.addPermissions(
Permissions.READ_EXTERNAL_STORAGE,
Permissions.WRITE_EXTERNAL_STORAGE
)
.rationale(R.string.bg_image_per)
.onGranted {
RealPathUtil.getPath(requireContext(), uri)?.let { path ->
val imgFile = File(path)
if (imgFile.exists()) {
var file = requireContext().externalFiles
file = FileUtils.createFileIfNotExist(file, "covers", imgFile.name)
file.writeBytes(imgFile.readBytes())
putPrefString(PreferKey.defaultCover, file.absolutePath)
CoverImageView.upDefaultCover()
}
}
}
.request()
}
}
} }

@ -26,7 +26,7 @@ class ThemeListDialog : BaseDialogFragment(), Toolbar.OnMenuItemClickListener {
override fun onStart() { override fun onStart() {
super.onStart() super.onStart()
val dm = requireActivity().getSize() val dm = requireActivity().windowSize
dialog?.window?.setLayout((dm.widthPixels * 0.9).toInt(), (dm.heightPixels * 0.9).toInt()) dialog?.window?.setLayout((dm.widthPixels * 0.9).toInt(), (dm.heightPixels * 0.9).toInt())
} }

@ -16,7 +16,7 @@ class DictViewModel(application: Application) : BaseViewModel(application) {
fun dict(word: String) { fun dict(word: String) {
execute { execute {
val body = okHttpClient.newCallStrResponse { val body = okHttpClient.newCallStrResponse {
get("http://apii.dict.cn/mini.php", mapOf(Pair("q", word))) get("https://apii.dict.cn/mini.php", mapOf(Pair("q", word)))
}.body }.body
val jsoup = Jsoup.parse(body!!) val jsoup = Jsoup.parse(body!!)
jsoup.body() jsoup.body()

@ -76,7 +76,7 @@ class FilePickerDialog : DialogFragment(),
override fun onStart() { override fun onStart() {
super.onStart() super.onStart()
val dm = requireActivity().getSize() val dm = requireActivity().windowSize
dialog?.window?.setLayout((dm.widthPixels * 0.9).toInt(), (dm.heightPixels * 0.8).toInt()) dialog?.window?.setLayout((dm.widthPixels * 0.9).toInt(), (dm.heightPixels * 0.8).toInt())
} }

@ -12,7 +12,6 @@ import io.legado.app.help.DefaultData
import io.legado.app.help.LocalConfig import io.legado.app.help.LocalConfig
import io.legado.app.model.webBook.WebBook import io.legado.app.model.webBook.WebBook
import io.legado.app.service.help.CacheBook import io.legado.app.service.help.CacheBook
import io.legado.app.utils.FileUtils
import io.legado.app.utils.postEvent import io.legado.app.utils.postEvent
import kotlinx.coroutines.asCoroutineDispatcher import kotlinx.coroutines.asCoroutineDispatcher
import kotlinx.coroutines.delay import kotlinx.coroutines.delay
@ -143,7 +142,6 @@ class MainViewModel(application: Application) : BaseViewModel(application) {
fun postLoad() { fun postLoad() {
execute { execute {
FileUtils.deleteFile(FileUtils.getPath(context.cacheDir, "Fonts"))
if (appDb.httpTTSDao.count == 0) { if (appDb.httpTTSDao.count == 0) {
DefaultData.httpTTS.let { DefaultData.httpTTS.let {
appDb.httpTTSDao.insert(*it.toTypedArray()) appDb.httpTTSDao.insert(*it.toTypedArray())

@ -65,7 +65,9 @@ abstract class BaseBookshelfFragment(layoutId: Int) : VMBaseFragment<BookshelfVi
@SuppressLint("InflateParams") @SuppressLint("InflateParams")
fun addBookByUrl() { fun addBookByUrl() {
alert(titleResource = R.string.add_book_url) { alert(titleResource = R.string.add_book_url) {
val alertBinding = DialogEditTextBinding.inflate(layoutInflater) val alertBinding = DialogEditTextBinding.inflate(layoutInflater).apply {
textInputLayout.hint = "url"
}
customView { alertBinding.root } customView { alertBinding.root }
okButton { okButton {
alertBinding.editView.text?.toString()?.let { alertBinding.editView.text?.toString()?.let {
@ -122,7 +124,7 @@ abstract class BaseBookshelfFragment(layoutId: Int) : VMBaseFragment<BookshelfVi
private fun importBookshelfAlert(groupId: Long) { private fun importBookshelfAlert(groupId: Long) {
alert(titleResource = R.string.import_bookshelf) { alert(titleResource = R.string.import_bookshelf) {
val alertBinding = DialogEditTextBinding.inflate(layoutInflater).apply { val alertBinding = DialogEditTextBinding.inflate(layoutInflater).apply {
editView.hint = "url/json" textInputLayout.hint = "url/json"
} }
customView { alertBinding.root } customView { alertBinding.root }
okButton { okButton {

@ -20,7 +20,7 @@ class QrCodeActivity : BaseActivity<ActivityQrcodeCaptureBinding>(), OnScanResul
override val binding by viewBinding(ActivityQrcodeCaptureBinding::inflate) override val binding by viewBinding(ActivityQrcodeCaptureBinding::inflate)
private val selectQrImage = registerForActivityResult(ActivityResultContracts.GetContent()) { private val selectQrImage = registerForActivityResult(ActivityResultContracts.GetContent()) {
it.readBytes(this)?.let { bytes -> it?.readBytes(this)?.let { bytes ->
val bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.size) val bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.size)
onScanResultCallback(QRCodeUtils.parseCodeResult(bitmap)) onScanResultCallback(QRCodeUtils.parseCodeResult(bitmap))
} }

@ -36,7 +36,7 @@ class GroupManageDialog : BaseDialogFragment(), Toolbar.OnMenuItemClickListener
override fun onStart() { override fun onStart() {
super.onStart() super.onStart()
val dm = requireActivity().getSize() val dm = requireActivity().windowSize
dialog?.window?.setLayout((dm.widthPixels * 0.9).toInt(), (dm.heightPixels * 0.9).toInt()) dialog?.window?.setLayout((dm.widthPixels * 0.9).toInt(), (dm.heightPixels * 0.9).toInt())
} }
@ -88,12 +88,10 @@ class GroupManageDialog : BaseDialogFragment(), Toolbar.OnMenuItemClickListener
@SuppressLint("InflateParams") @SuppressLint("InflateParams")
private fun addGroup() { private fun addGroup() {
alert(title = getString(R.string.add_group)) { alert(title = getString(R.string.add_group)) {
val alertBinding = DialogEditTextBinding.inflate(layoutInflater) val alertBinding = DialogEditTextBinding.inflate(layoutInflater).apply {
customView { textInputLayout.setHint(R.string.group_name)
alertBinding.apply {
editView.hint = "分组名称"
}.root
} }
customView { alertBinding.root }
yesButton { yesButton {
alertBinding.editView.text?.toString()?.let { alertBinding.editView.text?.toString()?.let {
if (it.isNotBlank()) { if (it.isNotBlank()) {
@ -109,7 +107,7 @@ class GroupManageDialog : BaseDialogFragment(), Toolbar.OnMenuItemClickListener
private fun editGroup(group: String) { private fun editGroup(group: String) {
alert(title = getString(R.string.group_edit)) { alert(title = getString(R.string.group_edit)) {
val alertBinding = DialogEditTextBinding.inflate(layoutInflater).apply { val alertBinding = DialogEditTextBinding.inflate(layoutInflater).apply {
editView.hint = "分组名称" textInputLayout.setHint(R.string.group_name)
editView.setText(group) editView.setText(group)
} }
customView { alertBinding.root } customView { alertBinding.root }

@ -255,6 +255,7 @@ class ReplaceRuleActivity : VMBaseActivity<ActivityReplaceRuleBinding, ReplaceRu
?.toMutableList() ?: mutableListOf() ?.toMutableList() ?: mutableListOf()
alert(titleResource = R.string.import_replace_rule_on_line) { alert(titleResource = R.string.import_replace_rule_on_line) {
val alertBinding = DialogEditTextBinding.inflate(layoutInflater).apply { val alertBinding = DialogEditTextBinding.inflate(layoutInflater).apply {
textInputLayout.hint = "url"
editView.setFilterValues(cacheUrls) editView.setFilterValues(cacheUrls)
editView.delCallBack = { editView.delCallBack = {
cacheUrls.remove(it) cacheUrls.remove(it)

@ -19,9 +19,9 @@ import io.legado.app.databinding.ActivityReplaceEditBinding
import io.legado.app.lib.dialogs.selector import io.legado.app.lib.dialogs.selector
import io.legado.app.ui.widget.KeyboardToolPop import io.legado.app.ui.widget.KeyboardToolPop
import io.legado.app.ui.widget.dialog.TextDialog import io.legado.app.ui.widget.dialog.TextDialog
import io.legado.app.utils.getSize
import io.legado.app.utils.toastOnUi import io.legado.app.utils.toastOnUi
import io.legado.app.utils.viewbindingdelegate.viewBinding import io.legado.app.utils.viewbindingdelegate.viewBinding
import io.legado.app.utils.windowSize
import kotlin.math.abs import kotlin.math.abs
/** /**
@ -166,7 +166,7 @@ class ReplaceEditActivity :
val rect = Rect() val rect = Rect()
// 获取当前页面窗口的显示范围 // 获取当前页面窗口的显示范围
window.decorView.getWindowVisibleDisplayFrame(rect) window.decorView.getWindowVisibleDisplayFrame(rect)
val screenHeight = this.getSize().heightPixels val screenHeight = this.windowSize.heightPixels
val keyboardHeight = screenHeight - rect.bottom // 输入法的高度 val keyboardHeight = screenHeight - rect.bottom // 输入法的高度
val preShowing = mIsSoftKeyBoardShowing val preShowing = mIsSoftKeyBoardShowing
if (abs(keyboardHeight) > screenHeight / 5) { if (abs(keyboardHeight) > screenHeight / 5) {

@ -43,6 +43,7 @@ class ReadRssActivity : VMBaseActivity<ActivityRssReadBinding, ReadRssViewModel>
private var customWebViewCallback: WebChromeClient.CustomViewCallback? = null private var customWebViewCallback: WebChromeClient.CustomViewCallback? = null
private var webPic: String? = null private var webPic: String? = null
private val saveImage = registerForActivityResult(FilePicker()) { private val saveImage = registerForActivityResult(FilePicker()) {
it ?: return@registerForActivityResult
ACache.get(this).put(imagePathKey, it.toString()) ACache.get(this).put(imagePathKey, it.toString())
viewModel.saveImage(webPic, it.toString()) viewModel.saveImage(webPic, it.toString())
} }

@ -256,7 +256,7 @@ class RssSourceEditActivity :
val rect = Rect() val rect = Rect()
// 获取当前页面窗口的显示范围 // 获取当前页面窗口的显示范围
window.decorView.getWindowVisibleDisplayFrame(rect) window.decorView.getWindowVisibleDisplayFrame(rect)
val screenHeight = this@RssSourceEditActivity.getSize().heightPixels val screenHeight = this@RssSourceEditActivity.windowSize.heightPixels
val keyboardHeight = screenHeight - rect.bottom // 输入法的高度 val keyboardHeight = screenHeight - rect.bottom // 输入法的高度
val preShowing = mIsSoftKeyBoardShowing val preShowing = mIsSoftKeyBoardShowing
if (abs(keyboardHeight) > screenHeight / 5) { if (abs(keyboardHeight) > screenHeight / 5) {

@ -37,7 +37,7 @@ class GroupManageDialog : BaseDialogFragment(), Toolbar.OnMenuItemClickListener
override fun onStart() { override fun onStart() {
super.onStart() super.onStart()
val dm = requireActivity().getSize() val dm = requireActivity().windowSize
dialog?.window?.setLayout((dm.widthPixels * 0.9).toInt(), (dm.heightPixels * 0.9).toInt()) dialog?.window?.setLayout((dm.widthPixels * 0.9).toInt(), (dm.heightPixels * 0.9).toInt())
} }
@ -89,12 +89,10 @@ class GroupManageDialog : BaseDialogFragment(), Toolbar.OnMenuItemClickListener
@SuppressLint("InflateParams") @SuppressLint("InflateParams")
private fun addGroup() { private fun addGroup() {
alert(title = getString(R.string.add_group)) { alert(title = getString(R.string.add_group)) {
val alertBinding = DialogEditTextBinding.inflate(layoutInflater) val alertBinding = DialogEditTextBinding.inflate(layoutInflater).apply {
customView { textInputLayout.setHint(R.string.group_name)
alertBinding.apply {
editView.setHint(R.string.group_name)
}.root
} }
customView { alertBinding.root }
yesButton { yesButton {
alertBinding.editView.text?.toString()?.let { alertBinding.editView.text?.toString()?.let {
if (it.isNotBlank()) { if (it.isNotBlank()) {
@ -109,13 +107,11 @@ class GroupManageDialog : BaseDialogFragment(), Toolbar.OnMenuItemClickListener
@SuppressLint("InflateParams") @SuppressLint("InflateParams")
private fun editGroup(group: String) { private fun editGroup(group: String) {
alert(title = getString(R.string.group_edit)) { alert(title = getString(R.string.group_edit)) {
val alertBinding = DialogEditTextBinding.inflate(layoutInflater) val alertBinding = DialogEditTextBinding.inflate(layoutInflater).apply {
customView { textInputLayout.setHint(R.string.group_name)
alertBinding.apply { editView.setText(group)
editView.setHint(R.string.group_name)
editView.setText(group)
}.root
} }
customView { alertBinding.root }
yesButton { yesButton {
viewModel.upGroup(group, alertBinding.editView.text?.toString()) viewModel.upGroup(group, alertBinding.editView.text?.toString())
} }

@ -263,6 +263,7 @@ class RssSourceActivity : VMBaseActivity<ActivityRssSourceBinding, RssSourceView
?.toMutableList() ?: mutableListOf() ?.toMutableList() ?: mutableListOf()
alert(titleResource = R.string.import_on_line) { alert(titleResource = R.string.import_on_line) {
val alertBinding = DialogEditTextBinding.inflate(layoutInflater).apply { val alertBinding = DialogEditTextBinding.inflate(layoutInflater).apply {
textInputLayout.hint = "url"
editView.setFilterValues(cacheUrls) editView.setFilterValues(cacheUrls)
editView.delCallBack = { editView.delCallBack = {
cacheUrls.remove(it) cacheUrls.remove(it)

@ -8,8 +8,8 @@ import androidx.fragment.app.FragmentManager
import io.legado.app.R import io.legado.app.R
import io.legado.app.base.BaseDialogFragment import io.legado.app.base.BaseDialogFragment
import io.legado.app.databinding.DialogTextViewBinding import io.legado.app.databinding.DialogTextViewBinding
import io.legado.app.utils.getSize
import io.legado.app.utils.viewbindingdelegate.viewBinding import io.legado.app.utils.viewbindingdelegate.viewBinding
import io.legado.app.utils.windowSize
import io.noties.markwon.Markwon import io.noties.markwon.Markwon
import io.noties.markwon.ext.tables.TablePlugin import io.noties.markwon.ext.tables.TablePlugin
import io.noties.markwon.html.HtmlPlugin import io.noties.markwon.html.HtmlPlugin
@ -49,7 +49,7 @@ class TextDialog : BaseDialogFragment() {
override fun onStart() { override fun onStart() {
super.onStart() super.onStart()
val dm = requireActivity().getSize() val dm = requireActivity().windowSize
dialog?.window?.setLayout((dm.widthPixels * 0.9).toInt(), (dm.heightPixels * 0.9).toInt()) dialog?.window?.setLayout((dm.widthPixels * 0.9).toInt(), (dm.heightPixels * 0.9).toInt())
} }

@ -13,8 +13,8 @@ import io.legado.app.base.adapter.ItemViewHolder
import io.legado.app.base.adapter.RecyclerAdapter import io.legado.app.base.adapter.RecyclerAdapter
import io.legado.app.databinding.DialogRecyclerViewBinding import io.legado.app.databinding.DialogRecyclerViewBinding
import io.legado.app.databinding.ItemLogBinding import io.legado.app.databinding.ItemLogBinding
import io.legado.app.utils.getSize
import io.legado.app.utils.viewbindingdelegate.viewBinding import io.legado.app.utils.viewbindingdelegate.viewBinding
import io.legado.app.utils.windowSize
class TextListDialog : BaseDialogFragment() { class TextListDialog : BaseDialogFragment() {
@ -35,7 +35,7 @@ class TextListDialog : BaseDialogFragment() {
override fun onStart() { override fun onStart() {
super.onStart() super.onStart()
val dm = requireActivity().getSize() val dm = requireActivity().windowSize
dialog?.window?.setLayout((dm.widthPixels * 0.9).toInt(), (dm.heightPixels * 0.9).toInt()) dialog?.window?.setLayout((dm.widthPixels * 0.9).toInt(), (dm.heightPixels * 0.9).toInt())
} }

@ -65,7 +65,7 @@ class FontSelectDialog : BaseDialogFragment(),
override fun onStart() { override fun onStart() {
super.onStart() super.onStart()
val dm = requireActivity().getSize() val dm = requireActivity().windowSize
dialog?.window?.setLayout((dm.widthPixels * 0.9).toInt(), (dm.heightPixels * 0.9).toInt()) dialog?.window?.setLayout((dm.widthPixels * 0.9).toInt(), (dm.heightPixels * 0.9).toInt())
} }

@ -179,7 +179,10 @@ class CoverImageView @JvmOverloads constructor(
@SuppressLint("UseCompatLoadingForDrawables") @SuppressLint("UseCompatLoadingForDrawables")
fun upDefaultCover() { fun upDefaultCover() {
val path = appCtx.getPrefString(PreferKey.defaultCover) val preferKey =
if (AppConfig.isNightTheme) PreferKey.defaultCoverDark
else PreferKey.defaultCover
val path = appCtx.getPrefString(preferKey)
var dw = Drawable.createFromPath(path) var dw = Drawable.createFromPath(path)
if (dw == null) { if (dw == null) {
showBookName = true showBookName = true

@ -21,8 +21,8 @@ import io.legado.app.databinding.DialogRecyclerViewBinding
import io.legado.app.databinding.ItemIconPreferenceBinding import io.legado.app.databinding.ItemIconPreferenceBinding
import io.legado.app.lib.theme.primaryColor import io.legado.app.lib.theme.primaryColor
import io.legado.app.utils.getCompatDrawable import io.legado.app.utils.getCompatDrawable
import io.legado.app.utils.getSize
import io.legado.app.utils.viewbindingdelegate.viewBinding import io.legado.app.utils.viewbindingdelegate.viewBinding
import io.legado.app.utils.windowSize
class IconListPreference(context: Context, attrs: AttributeSet) : ListPreference(context, attrs) { class IconListPreference(context: Context, attrs: AttributeSet) : ListPreference(context, attrs) {
@ -131,7 +131,7 @@ class IconListPreference(context: Context, attrs: AttributeSet) : ListPreference
override fun onStart() { override fun onStart() {
super.onStart() super.onStart()
val dm = requireActivity().getSize() val dm = requireActivity().windowSize
dialog?.window?.setLayout( dialog?.window?.setLayout(
(dm.widthPixels * 0.8).toInt(), (dm.widthPixels * 0.8).toInt(),
ViewGroup.LayoutParams.WRAP_CONTENT ViewGroup.LayoutParams.WRAP_CONTENT

@ -6,20 +6,21 @@ import android.util.DisplayMetrics
import android.view.WindowInsets import android.view.WindowInsets
import android.view.WindowMetrics import android.view.WindowMetrics
fun Activity.getSize(): DisplayMetrics { val Activity.windowSize: DisplayMetrics
val displayMetrics = DisplayMetrics() get() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { val displayMetrics = DisplayMetrics()
val windowMetrics: WindowMetrics = windowManager.currentWindowMetrics if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
val insets = windowMetrics.windowInsets val windowMetrics: WindowMetrics = windowManager.currentWindowMetrics
.getInsetsIgnoringVisibility(WindowInsets.Type.systemBars()) val insets = windowMetrics.windowInsets
displayMetrics.widthPixels = windowMetrics.bounds.width() - insets.left - insets.right .getInsetsIgnoringVisibility(WindowInsets.Type.systemBars())
displayMetrics.heightPixels = windowMetrics.bounds.height() - insets.top - insets.bottom displayMetrics.widthPixels = windowMetrics.bounds.width() - insets.left - insets.right
} else { displayMetrics.heightPixels = windowMetrics.bounds.height() - insets.top - insets.bottom
@Suppress("DEPRECATION") } else {
windowManager.defaultDisplay.getMetrics(displayMetrics) @Suppress("DEPRECATION")
windowManager.defaultDisplay.getMetrics(displayMetrics)
}
return displayMetrics
} }
return displayMetrics
}
/** /**
* 该方法需要在View完全被绘制出来之后调用否则判断不了 * 该方法需要在View完全被绘制出来之后调用否则判断不了

@ -0,0 +1,32 @@
package io.legado.app.utils
import android.app.Activity.RESULT_OK
import android.content.Context
import android.content.Intent
import android.net.Uri
import androidx.activity.result.contract.ActivityResultContract
object ActivityResultContractUtils {
class SelectImage : ActivityResultContract<Int, Pair<Int?, Uri?>?>() {
var requestCode: Int? = null
override fun createIntent(context: Context, input: Int?): Intent {
requestCode = input
return Intent(Intent.ACTION_GET_CONTENT)
.addCategory(Intent.CATEGORY_OPENABLE)
.setType("image/*")
}
override fun parseResult(resultCode: Int, intent: Intent?): Pair<Int?, Uri?>? {
if (resultCode == RESULT_OK) {
return Pair(requestCode, intent?.data)
}
return null
}
}
}

@ -249,7 +249,7 @@ object BitmapUtils {
/** /**
* 高斯模糊 * 高斯模糊
*/ */
fun stackBlur(srcBitmap: Bitmap?): Bitmap? { fun stackBlur(srcBitmap: Bitmap?, radius: Float = 8f): Bitmap? {
if (srcBitmap == null) return null if (srcBitmap == null) return null
val rs = RenderScript.create(appCtx) val rs = RenderScript.create(appCtx)
val blurredBitmap = srcBitmap.copy(Config.ARGB_8888, true) val blurredBitmap = srcBitmap.copy(Config.ARGB_8888, true)
@ -268,7 +268,7 @@ object BitmapUtils {
script.setInput(input) script.setInput(input)
//设置模糊半径 //设置模糊半径
script.setRadius(8f) script.setRadius(radius)
//启动 ScriptIntrinsicBlur //启动 ScriptIntrinsicBlur
script.forEach(output) script.forEach(output)

@ -362,6 +362,7 @@
android:layout_marginTop="8dp" android:layout_marginTop="8dp"
android:clickable="true" android:clickable="true"
android:focusable="true" android:focusable="true"
android:minHeight="48dp"
android:paddingLeft="8dp" android:paddingLeft="8dp"
android:paddingBottom="8dp" android:paddingBottom="8dp"
android:text="@string/book_intro" android:text="@string/book_intro"

@ -333,16 +333,17 @@
<io.legado.app.ui.widget.text.ScrollTextView <io.legado.app.ui.widget.text.ScrollTextView
android:id="@+id/tv_intro" android:id="@+id/tv_intro"
android:layout_marginTop="8dp"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:clickable="true" android:clickable="true"
android:focusable="true" android:focusable="true"
android:minHeight="48dp"
android:paddingLeft="8dp"
android:paddingBottom="8dp"
android:text="@string/book_intro" android:text="@string/book_intro"
android:textColor="@color/secondaryText" android:textColor="@color/secondaryText"
android:textSize="14sp" android:textSize="14sp"
android:paddingLeft="8dp"
android:paddingBottom="8dp"
android:visibility="visible" android:visibility="visible"
tools:ignore="RtlHardcoded,RtlSymmetry" /> tools:ignore="RtlHardcoded,RtlSymmetry" />

@ -1,6 +1,7 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:orientation="vertical"> android:orientation="vertical">
@ -15,6 +16,7 @@
<androidx.viewpager.widget.ViewPager <androidx.viewpager.widget.ViewPager
android:id="@+id/view_pager" android:id="@+id/view_pager"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" /> android:layout_height="match_parent"
tools:ignore="SpeakableTextPresentCheck" />
</LinearLayout> </LinearLayout>

@ -69,7 +69,8 @@
<io.legado.app.ui.widget.recycler.scroller.FastScrollRecyclerView <io.legado.app.ui.widget.recycler.scroller.FastScrollRecyclerView
android:id="@+id/recycler_view" android:id="@+id/recycler_view"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" /> android:layout_height="match_parent"
tools:ignore="SpeakableTextPresentCheck" />
<TextView <TextView
android:id="@+id/tv_empty_msg" android:id="@+id/tv_empty_msg"

@ -1,6 +1,7 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:orientation="vertical"> android:orientation="vertical">
@ -9,7 +10,8 @@
android:id="@+id/view_pager_main" android:id="@+id/view_pager_main"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="0dp" android:layout_height="0dp"
android:layout_weight="1" /> android:layout_weight="1"
tools:ignore="SpeakableTextPresentCheck" />
<com.google.android.material.bottomnavigation.BottomNavigationView <com.google.android.material.bottomnavigation.BottomNavigationView
android:id="@+id/bottom_navigation_view" android:id="@+id/bottom_navigation_view"

@ -1,6 +1,7 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/root_view" android:id="@+id/root_view"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
@ -35,7 +36,8 @@
<io.legado.app.ui.widget.text.EditText <io.legado.app.ui.widget.text.EditText
android:id="@+id/et_name" android:id="@+id/et_name"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" /> android:layout_height="wrap_content"
tools:ignore="SpeakableTextPresentCheck,TouchTargetSizeCheck" />
</io.legado.app.ui.widget.text.TextInputLayout> </io.legado.app.ui.widget.text.TextInputLayout>
<io.legado.app.ui.widget.text.TextInputLayout <io.legado.app.ui.widget.text.TextInputLayout
@ -47,7 +49,8 @@
<io.legado.app.ui.widget.text.EditText <io.legado.app.ui.widget.text.EditText
android:id="@+id/et_group" android:id="@+id/et_group"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" /> android:layout_height="wrap_content"
tools:ignore="SpeakableTextPresentCheck,TouchTargetSizeCheck" />
</io.legado.app.ui.widget.text.TextInputLayout> </io.legado.app.ui.widget.text.TextInputLayout>
<io.legado.app.ui.widget.text.TextInputLayout <io.legado.app.ui.widget.text.TextInputLayout
@ -59,7 +62,8 @@
<io.legado.app.ui.widget.text.EditText <io.legado.app.ui.widget.text.EditText
android:id="@+id/et_replace_rule" android:id="@+id/et_replace_rule"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" /> android:layout_height="wrap_content"
tools:ignore="SpeakableTextPresentCheck,TouchTargetSizeCheck" />
</io.legado.app.ui.widget.text.TextInputLayout> </io.legado.app.ui.widget.text.TextInputLayout>
<LinearLayout <LinearLayout
@ -73,14 +77,15 @@
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_weight="1" android:layout_weight="1"
android:text="@string/use_regex" /> android:text="@string/use_regex"
tools:ignore="TouchTargetSizeCheck" />
<ImageView <ImageView
android:id="@+id/iv_help" android:id="@+id/iv_help"
android:layout_width="24dp" android:layout_width="24dp"
android:layout_height="24dp" android:layout_height="24dp"
android:src="@drawable/ic_help" android:src="@drawable/ic_help"
app:tint="@color/secondaryText" app:tint="@color/primaryText"
android:contentDescription="@string/help" /> android:contentDescription="@string/help" />
</LinearLayout> </LinearLayout>
@ -94,7 +99,8 @@
<io.legado.app.ui.widget.text.EditText <io.legado.app.ui.widget.text.EditText
android:id="@+id/et_replace_to" android:id="@+id/et_replace_to"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" /> android:layout_height="wrap_content"
tools:ignore="SpeakableTextPresentCheck,TouchTargetSizeCheck" />
</io.legado.app.ui.widget.text.TextInputLayout> </io.legado.app.ui.widget.text.TextInputLayout>
<io.legado.app.ui.widget.text.TextInputLayout <io.legado.app.ui.widget.text.TextInputLayout
@ -106,7 +112,8 @@
<io.legado.app.ui.widget.text.EditText <io.legado.app.ui.widget.text.EditText
android:id="@+id/et_scope" android:id="@+id/et_scope"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" /> android:layout_height="wrap_content"
tools:ignore="SpeakableTextPresentCheck,TouchTargetSizeCheck" />
</io.legado.app.ui.widget.text.TextInputLayout> </io.legado.app.ui.widget.text.TextInputLayout>
</LinearLayout> </LinearLayout>

@ -23,7 +23,8 @@
<io.legado.app.ui.widget.recycler.scroller.FastScrollRecyclerView <io.legado.app.ui.widget.recycler.scroller.FastScrollRecyclerView
android:id="@+id/recycler_view" android:id="@+id/recycler_view"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" /> android:layout_height="match_parent"
tools:ignore="SpeakableTextPresentCheck" />
</FrameLayout> </FrameLayout>

@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
@ -19,6 +20,7 @@
<androidx.viewpager.widget.ViewPager <androidx.viewpager.widget.ViewPager
android:id="@+id/view_pager" android:id="@+id/view_pager"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" /> android:layout_height="wrap_content"
tools:ignore="SpeakableTextPresentCheck" />
</LinearLayout> </LinearLayout>

@ -34,14 +34,16 @@
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:checked="true" android:checked="true"
android:text="@string/is_enable" /> android:text="@string/is_enable"
tools:ignore="TouchTargetSizeCheck" />
<io.legado.app.lib.theme.view.ATECheckBox <io.legado.app.lib.theme.view.ATECheckBox
android:id="@+id/cb_single_url" android:id="@+id/cb_single_url"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:checked="false" android:checked="false"
android:text="@string/single_url" /> android:text="@string/single_url"
tools:ignore="TouchTargetSizeCheck" />
</LinearLayout> </LinearLayout>
@ -64,14 +66,16 @@
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:checked="false" android:checked="false"
android:text="@string/enable_js" /> android:text="@string/enable_js"
tools:ignore="TouchTargetSizeCheck" />
<io.legado.app.lib.theme.view.ATECheckBox <io.legado.app.lib.theme.view.ATECheckBox
android:id="@+id/cb_enable_base_url" android:id="@+id/cb_enable_base_url"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:checked="false" android:checked="false"
android:text="@string/load_with_base_url" /> android:text="@string/load_with_base_url"
tools:ignore="TouchTargetSizeCheck" />
</LinearLayout> </LinearLayout>

@ -25,7 +25,8 @@
android:layout_height="0dp" android:layout_height="0dp"
android:overScrollMode="never" android:overScrollMode="never"
app:layout_constraintBottom_toTopOf="@+id/ll_search_base_info" app:layout_constraintBottom_toTopOf="@+id/ll_search_base_info"
app:layout_constraintTop_toBottomOf="@id/refresh_progress_bar" /> app:layout_constraintTop_toBottomOf="@id/refresh_progress_bar"
tools:ignore="SpeakableTextPresentCheck" />
<LinearLayout <LinearLayout
android:id="@+id/ll_search_base_info" android:id="@+id/ll_search_base_info"

@ -47,8 +47,8 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginStart="15dp" android:layout_marginStart="15dp"
android:layout_marginEnd="15dp" android:layout_marginEnd="15dp"
android:min="10" android:min="2"
android:max="100" android:max="60"
tools:ignore="UnusedAttribute" /> tools:ignore="UnusedAttribute" />
</LinearLayout> </LinearLayout>

@ -43,7 +43,8 @@
android:id="@+id/edit_book_text" android:id="@+id/edit_book_text"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:hint="@string/content" /> android:hint="@string/content"
tools:ignore="SpeakableTextPresentCheck,TouchTargetSizeCheck" />
</io.legado.app.ui.widget.text.TextInputLayout> </io.legado.app.ui.widget.text.TextInputLayout>
@ -56,7 +57,8 @@
android:id="@+id/edit_content" android:id="@+id/edit_content"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:hint="@string/note_content" /> android:hint="@string/note_content"
tools:ignore="SpeakableTextPresentCheck,TouchTargetSizeCheck" />
</io.legado.app.ui.widget.text.TextInputLayout> </io.legado.app.ui.widget.text.TextInputLayout>

@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:padding="16dp" android:padding="16dp"
@ -31,7 +32,8 @@
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:entries="@array/group_style" android:entries="@array/group_style"
app:theme="@style/Spinner" /> app:theme="@style/Spinner"
tools:ignore="TouchTargetSizeCheck" />
</LinearLayout> </LinearLayout>
@ -51,27 +53,32 @@
<RadioButton <RadioButton
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="@string/layout_list" /> android:text="@string/layout_list"
tools:ignore="TouchTargetSizeCheck" />
<RadioButton <RadioButton
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="@string/layout_grid3" /> android:text="@string/layout_grid3"
tools:ignore="TouchTargetSizeCheck" />
<RadioButton <RadioButton
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="@string/layout_grid4" /> android:text="@string/layout_grid4"
tools:ignore="TouchTargetSizeCheck" />
<RadioButton <RadioButton
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="@string/layout_grid5" /> android:text="@string/layout_grid5"
tools:ignore="TouchTargetSizeCheck" />
<RadioButton <RadioButton
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="@string/layout_grid6" /> android:text="@string/layout_grid6"
tools:ignore="TouchTargetSizeCheck" />
</RadioGroup> </RadioGroup>
</LinearLayout> </LinearLayout>
@ -84,8 +91,9 @@
android:padding="6dp" android:padding="6dp"
android:text="@string/show_unread" android:text="@string/show_unread"
app:layout_constraintLeft_toRightOf="@+id/ll_layout" app:layout_constraintLeft_toRightOf="@+id/ll_layout"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" app:layout_constraintTop_toTopOf="parent"
app:layout_constraintRight_toRightOf="parent" /> tools:ignore="TouchTargetSizeCheck" />
<LinearLayout <LinearLayout
android:id="@+id/ll_sort" android:id="@+id/ll_sort"
@ -112,22 +120,26 @@
<RadioButton <RadioButton
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="@string/bookshelf_px_0" /> android:text="@string/bookshelf_px_0"
tools:ignore="TouchTargetSizeCheck" />
<RadioButton <RadioButton
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="@string/bookshelf_px_1" /> android:text="@string/bookshelf_px_1"
tools:ignore="TouchTargetSizeCheck" />
<RadioButton <RadioButton
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="@string/bookshelf_px_2" /> android:text="@string/bookshelf_px_2"
tools:ignore="TouchTargetSizeCheck" />
<RadioButton <RadioButton
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="@string/bookshelf_px_3" /> android:text="@string/bookshelf_px_3"
tools:ignore="TouchTargetSizeCheck" />
</RadioGroup> </RadioGroup>

@ -4,10 +4,10 @@
android:id="@+id/ll_content" android:id="@+id/ll_content"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:padding="16dp"
android:background="@color/background" android:background="@color/background"
android:gravity="center" android:gravity="center"
android:orientation="horizontal"> android:orientation="horizontal"
android:padding="16dp">
<View <View
android:layout_width="0dp" android:layout_width="0dp"
@ -30,6 +30,8 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_gravity="center_vertical" android:layout_gravity="center_vertical"
android:background="@drawable/bg_edit" android:background="@drawable/bg_edit"
android:hint="@string/start"
android:importantForAutofill="no"
android:inputType="number" android:inputType="number"
android:lines="1" android:lines="1"
android:maxLength="5" android:maxLength="5"
@ -40,7 +42,8 @@
android:paddingBottom="4dp" android:paddingBottom="4dp"
android:textColor="@color/primaryText" android:textColor="@color/primaryText"
android:textCursorDrawable="@drawable/shape_text_cursor" android:textCursorDrawable="@drawable/shape_text_cursor"
android:textSize="14sp" /> android:textSize="14sp"
tools:ignore="TouchTargetSizeCheck" />
<TextView <TextView
android:layout_width="wrap_content" android:layout_width="wrap_content"
@ -58,6 +61,8 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_gravity="center_vertical" android:layout_gravity="center_vertical"
android:background="@drawable/bg_edit" android:background="@drawable/bg_edit"
android:hint="@string/end"
android:importantForAutofill="no"
android:inputType="number" android:inputType="number"
android:lines="1" android:lines="1"
android:maxLength="5" android:maxLength="5"
@ -68,7 +73,8 @@
android:paddingBottom="4dp" android:paddingBottom="4dp"
android:textColor="@color/primaryText" android:textColor="@color/primaryText"
android:textCursorDrawable="@drawable/shape_text_cursor" android:textCursorDrawable="@drawable/shape_text_cursor"
android:textSize="14sp" /> android:textSize="14sp"
tools:ignore="TouchTargetSizeCheck,SpeakableTextPresentCheck" />
<View <View
android:layout_width="0dp" android:layout_width="0dp"

@ -1,18 +1,24 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<ScrollView <androidx.core.widget.NestedScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingLeft="20dp"
android:paddingRight="20dp"
android:paddingTop="12dp"
android:overScrollMode="ifContentScrolls">
<io.legado.app.ui.widget.text.TextInputLayout
android:id="@+id/text_input_layout"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="wrap_content">
android:layout_marginTop="48dp"
android:layout_marginBottom="48dp"
android:overScrollMode="ifContentScrolls">
<io.legado.app.ui.widget.text.AutoCompleteTextView <io.legado.app.ui.widget.text.AutoCompleteTextView
android:id="@+id/edit_view" android:id="@+id/edit_view"
android:layout_marginLeft="20dp"
android:layout_marginRight="20dp"
android:layout_marginStart="20dp"
android:layout_marginEnd="20dp"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content"/> android:layout_height="wrap_content"
</ScrollView> tools:ignore="SpeakableTextPresentCheck,TouchTargetSizeCheck" />
</io.legado.app.ui.widget.text.TextInputLayout>
</androidx.core.widget.NestedScrollView>

@ -0,0 +1,30 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="10dp">
<TextView
android:id="@+id/text_view_value"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="6dp"
android:layout_gravity="center_horizontal"
android:textColor="@color/primaryText"
android:textSize="17sp" />
<androidx.appcompat.widget.AppCompatSeekBar
android:id="@+id/seek_bar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="6dp"
android:max="25" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="6dp"
android:text="@string/background_image_hint" />
</LinearLayout>

@ -23,7 +23,8 @@
android:id="@+id/recycler_view" android:id="@+id/recycler_view"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:scrollbars="none" /> android:scrollbars="none"
tools:ignore="SpeakableTextPresentCheck" />
<io.legado.app.ui.widget.anima.RotateLoading <io.legado.app.ui.widget.anima.RotateLoading
android:id="@+id/rotate_loading" android:id="@+id/rotate_loading"
@ -61,6 +62,10 @@
android:visibility="gone" android:visibility="gone"
tools:ignore="RtlHardcoded" /> tools:ignore="RtlHardcoded" />
<Space
android:layout_width="0dp"
android:layout_height="0dp" />
<LinearLayout <LinearLayout
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"

@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="vertical" android:orientation="vertical"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
@ -15,7 +16,8 @@
<io.legado.app.ui.widget.text.EditText <io.legado.app.ui.widget.text.EditText
android:id="@+id/tv_rule_name" android:id="@+id/tv_rule_name"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" /> android:layout_height="wrap_content"
tools:ignore="SpeakableTextPresentCheck,TouchTargetSizeCheck" />
</io.legado.app.ui.widget.text.TextInputLayout> </io.legado.app.ui.widget.text.TextInputLayout>
@ -27,7 +29,8 @@
<io.legado.app.ui.widget.text.EditText <io.legado.app.ui.widget.text.EditText
android:id="@+id/tv_rule_regex" android:id="@+id/tv_rule_regex"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" /> android:layout_height="wrap_content"
tools:ignore="SpeakableTextPresentCheck,TouchTargetSizeCheck" />
</io.legado.app.ui.widget.text.TextInputLayout> </io.legado.app.ui.widget.text.TextInputLayout>

@ -20,6 +20,6 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:padding="6dp" android:padding="6dp"
android:gravity="center" android:gravity="center"
android:text="执行中......" android:text="@string/loading"
android:textColor="@color/primaryText" /> android:textColor="@color/primaryText" />
</LinearLayout> </LinearLayout>

@ -847,4 +847,5 @@
<string name="null_url">URL nula</string> <string name="null_url">URL nula</string>
<string name="dict">字典</string> <string name="dict">字典</string>
<string name="unknown_error">未知错误</string> <string name="unknown_error">未知错误</string>
<string name="end">end</string>
</resources> </resources>

@ -847,4 +847,5 @@
<string name="null_url">url为空</string> <string name="null_url">url为空</string>
<string name="dict">字典</string> <string name="dict">字典</string>
<string name="unknown_error">未知错误</string> <string name="unknown_error">未知错误</string>
<string name="end">end</string>
</resources> </resources>

@ -847,4 +847,5 @@
<string name="null_url">Nenhuma url</string> <string name="null_url">Nenhuma url</string>
<string name="dict">Dicionários</string> <string name="dict">Dicionários</string>
<string name="unknown_error">未知错误</string> <string name="unknown_error">未知错误</string>
<string name="end">end</string>
</resources> </resources>

@ -7,8 +7,8 @@
</string-array> </string-array>
<string-array name="group_style"> <string-array name="group_style">
<item>标签</item> <item>標籤</item>
<item>文件</item> <item>文件</item>
</string-array> </string-array>
<string-array name="theme_mode"> <string-array name="theme_mode">

@ -343,7 +343,7 @@
<string name="pt_show_all_find">顯示所有發現</string> <string name="pt_show_all_find">顯示所有發現</string>
<string name="ps_show_all_find">關閉則只顯示勾選源的發現</string> <string name="ps_show_all_find">關閉則只顯示勾選源的發現</string>
<string name="update_toc">更新目錄</string> <string name="update_toc">更新目錄</string>
<string name="txt_toc_regex">Txt目錄正則</string> <string name="txt_toc_regex">TXT目錄正則</string>
<string name="set_charset">設置編碼</string> <string name="set_charset">設置編碼</string>
<string name="swap_sort">倒序-順序</string> <string name="swap_sort">倒序-順序</string>
<string name="sort">排序</string> <string name="sort">排序</string>
@ -405,7 +405,7 @@
<string name="book_url_pattern">書籍 URL 正則 (bookUrlPattern)</string> <string name="book_url_pattern">書籍 URL 正則 (bookUrlPattern)</string>
<string name="rule_book_info_init">預處理規則 (bookInfoInit)</string> <string name="rule_book_info_init">預處理規則 (bookInfoInit)</string>
<string name="rule_toc_url">目錄 URL 規則 (tocUrl)</string> <string name="rule_toc_url">目錄 URL 規則 (tocUrl)</string>
<string name="rule_can_re_name">许修改书名作者(canReName)</string> <string name="rule_can_re_name">許修改書名作者 (canReName)</string>
<string name="rule_next_toc_url">目錄下一頁規則 (nextTocUrl)</string> <string name="rule_next_toc_url">目錄下一頁規則 (nextTocUrl)</string>
<string name="rule_chapter_list">目錄列表規則 (chapterList)</string> <string name="rule_chapter_list">目錄列表規則 (chapterList)</string>
<string name="rule_chapter_name">章節名稱規則 (ChapterName)</string> <string name="rule_chapter_name">章節名稱規則 (ChapterName)</string>
@ -414,7 +414,7 @@
<string name="rule_update_time">更新時間 (ChapterInfo)</string> <string name="rule_update_time">更新時間 (ChapterInfo)</string>
<string name="rule_book_content">正文規則 (content)</string> <string name="rule_book_content">正文規則 (content)</string>
<string name="rule_next_content">正文下一頁 URL 規則 (nextContentUrl)</string> <string name="rule_next_content">正文下一頁 URL 規則 (nextContentUrl)</string>
<string name="rule_web_js">WebViewJs(webJs)</string> <string name="rule_web_js">WebViewJs (webJs)</string>
<string name="rule_source_regex">資源正則 (sourceRegex)</string> <string name="rule_source_regex">資源正則 (sourceRegex)</string>
<string name="source_icon">圖標 (sourceIcon)</string> <string name="source_icon">圖標 (sourceIcon)</string>
<string name="r_articles">列表規則 (ruleArticles)</string> <string name="r_articles">列表規則 (ruleArticles)</string>
@ -672,10 +672,10 @@
<string name="contributors">開發人員</string> <string name="contributors">開發人員</string>
<string name="contact">聯繫我們</string> <string name="contact">聯繫我們</string>
<string name="license">開源許可</string> <string name="license">開源許可</string>
<string name="follow_official_account">關注公</string> <string name="follow_official_account">關注公</string>
<string name="wechat">WeChat</string> <string name="wechat">WeChat</string>
<string name="thanks">你的支持是我更新的動力</string> <string name="thanks">你的支持是我更新的動力</string>
<string name="about_official_account">众号[开源阅读]</string> <string name="about_official_account">眾號[开源阅读]</string>
<string name="source_auto_changing">正在自動換源</string> <string name="source_auto_changing">正在自動換源</string>
<string name="click_to_apply">點擊加入</string> <string name="click_to_apply">點擊加入</string>
<string name="middle"></string> <string name="middle"></string>
@ -716,46 +716,46 @@
<string name="already_in_download">該書已在下載列表</string> <string name="already_in_download">該書已在下載列表</string>
<string name="click_to_open">點擊打開</string> <string name="click_to_open">點擊打開</string>
<string name="follow_public_account_summary">關注[legado-top]點擊廣告支持我</string> <string name="follow_public_account_summary">關注[legado-top]點擊廣告支持我</string>
<string name="weChat_appreciation_code">微信赞赏码</string> <string name="weChat_appreciation_code">微信讚賞碼</string>
<string name="alipay">支付寶</string> <string name="alipay">支付寶</string>
<string name="alipay_red_envelope_search_code">支付寶紅包搜索碼</string> <string name="alipay_red_envelope_search_code">支付寶紅包搜索碼</string>
<string name="alipay_red_envelope_copy">537954522 點擊複製</string> <string name="alipay_red_envelope_copy">537954522 點擊複製</string>
<string name="alipay_red_envelope_qr_code">支付寶紅包二維碼</string> <string name="alipay_red_envelope_qr_code">支付寶紅包二維碼</string>
<string name="alipay_payment_qr_code">支付寶收款二維碼</string> <string name="alipay_payment_qr_code">支付寶收款二維碼</string>
<string name="qq_collection_qr_code">QQ收款二維碼</string> <string name="qq_collection_qr_code">QQ收款二維碼</string>
<string name="contributors_summary">gedoor,Invinciblelee等,详情请在github中查看</string> <string name="contributors_summary">gedoor,Invinciblelee等,詳情請在github中查看</string>
<string name="clear_cache_summary">清除已下載書籍和字體緩存</string> <string name="clear_cache_summary">清除已下載書籍和字體緩存</string>
<string name="default_cover">默認封面</string> <string name="default_cover">默認封面</string>
<string name="restore_ignore">恢復忽略列表</string> <string name="restore_ignore">恢復忽略列表</string>
<string name="restore_ignore_summary">恢復時忽略一些內容不恢復,方便不同手機配置不同</string> <string name="restore_ignore_summary">恢復時忽略一些內容不恢復,方便不同手機配置不同</string>
<string name="read_config">閱讀界面設置</string> <string name="read_config">閱讀界面設置</string>
<string name="rule_image_style">图片样式(imageStyle)</string> <string name="rule_image_style">圖片樣式 (imageStyle)</string>
<string name="rule_replace_regex">换规则(replaceRegex)</string> <string name="rule_replace_regex">換規則 (replaceRegex)</string>
<string name="group_name">分組名稱</string> <string name="group_name">分組名稱</string>
<string name="note_content">備註內容</string> <string name="note_content">備註內容</string>
<string name="replace_enable_default_t">认启用替换净</string> <string name="replace_enable_default_t">認啟用替換淨</string>
<string name="replace_enable_default_s">新加入书架的书是否启用替换净</string> <string name="replace_enable_default_s">新加入書架的書是否啟用替換淨</string>
<string name="select_restore_file">选择恢复文件</string> <string name="select_restore_file">選擇恢復文件</string>
<string name="day_background_too_dark">白天背景不能太暗</string> <string name="day_background_too_dark">白天背景不能太暗</string>
<string name="day_bottom_bar_too_dark">白天底不能太暗</string> <string name="day_bottom_bar_too_dark">白天底不能太暗</string>
<string name="night_background_too_light">背景不能太亮</string> <string name="night_background_too_light">背景不能太亮</string>
<string name="night_bottom_bar_too_light">间底栏不能太亮</string> <string name="night_bottom_bar_too_light">間底欄不能太亮</string>
<string name="accent_background_diff">强调色不能和背景颜色相似</string> <string name="accent_background_diff">強調色不能和背景顏色相似</string>
<string name="accent_text_diff">强调色不能和文字颜色相似</string> <string name="accent_text_diff">強調色不能和文字顏色相似</string>
<string name="wrong_format">格式不對</string> <string name="wrong_format">格式不對</string>
<string name="error">錯誤</string> <string name="error">錯誤</string>
<string name="show_brightness_view">顯示亮度調節控制項</string> <string name="show_brightness_view">顯示亮度調節控制項</string>
<string name="language">語言</string> <string name="language">語言</string>
<string name="import_rss_source">匯入訂閱源</string> <string name="import_rss_source">匯入訂閱源</string>
<string name="donate_summary">您嘅支援我更新嘅動力</string> <string name="donate_summary">您嘅支援我更新嘅動力</string>
<string name="about_summary">众号[开源阅读软件]</string> <string name="about_summary">眾號[开源阅读软件]</string>
<string name="read_record">閲讀記錄</string> <string name="read_record">閲讀記錄</string>
<string name="read_record_summary">閱讀時間記錄</string> <string name="read_record_summary">閱讀時間記錄</string>
<string name="local_tts">本地TTS</string> <string name="local_tts">本地TTS</string>
<string name="thread_count">線程數</string> <string name="thread_count">線程數</string>
<string name="all_read_time">總閲讀時間</string> <string name="all_read_time">總閲讀時間</string>
<string name="un_select_all">全部唔要</string> <string name="un_select_all">全部唔要</string>
<string name="delete_all">除所有</string> <string name="delete_all">除所有</string>
<string name="import_str">導入</string> <string name="import_str">導入</string>
<string name="export_str">導出</string> <string name="export_str">導出</string>
<string name="save_theme_config">儲存主題配置</string> <string name="save_theme_config">儲存主題配置</string>
@ -789,7 +789,7 @@
<string name="non_action">無操作</string> <string name="non_action">無操作</string>
<string name="body_title">正文標題</string> <string name="body_title">正文標題</string>
<string name="show_hide">顯示/隱藏</string> <string name="show_hide">顯示/隱藏</string>
<string name="header_footer">页眉<![CDATA[&]]>页脚</string> <string name="header_footer">頁眉<![CDATA[&]]>頁腳</string>
<string name="rule_subscription">規則訂閱</string> <string name="rule_subscription">規則訂閱</string>
<string name="rule_sub_empty_msg">添加大佬們提供的規則匯入地址 添加後點擊可匯入規則</string> <string name="rule_sub_empty_msg">添加大佬們提供的規則匯入地址 添加後點擊可匯入規則</string>
<string name="get_book_progress">拉取雲端進度</string> <string name="get_book_progress">拉取雲端進度</string>
@ -804,6 +804,9 @@
<string name="pre_download_s">預先下載%s章正文</string> <string name="pre_download_s">預先下載%s章正文</string>
<string name="is_enabled">係咪啟用</string> <string name="is_enabled">係咪啟用</string>
<string name="background_image">背景圖片</string> <string name="background_image">背景圖片</string>
<string name="background_image_blurring">背景圖片虛化</string>
<string name="background_image_blurring_radius">虛化半徑</string>
<string name="background_image_hint">0為停用,啓用範圍1~25\n半徑數值越大,虛化效果越高</string>
<string name="export_folder">導出資料夾</string> <string name="export_folder">導出資料夾</string>
<string name="export_charset">導出編碼</string> <string name="export_charset">導出編碼</string>
<string name="export_to_web_dav">導出到WebDav</string> <string name="export_to_web_dav">導出到WebDav</string>
@ -836,14 +839,15 @@
<string name="hide_when_status_bar_show">狀態欄顯示時隱藏</string> <string name="hide_when_status_bar_show">狀態欄顯示時隱藏</string>
<string name="diy_source_group">自訂源分組</string> <string name="diy_source_group">自訂源分組</string>
<string name="diy_edit_source_group">輸入自訂源分組名稱</string> <string name="diy_edit_source_group">輸入自訂源分組名稱</string>
<string name="reverse_toc">转目录</string> <string name="reverse_toc">轉目錄</string>
<string name="show_discovery">显示发现</string> <string name="show_discovery">顯示發現</string>
<string name="style"></string> <string name="style"></string>
<string name="group_style">组样</string> <string name="group_style">組樣</string>
<string name="export_file_name">出文件名</string> <string name="export_file_name">出文件名</string>
<string name="reset">重置</string> <string name="reset">重置</string>
<string name="null_url">url</string> <string name="null_url">url</string>
<string name="dict">字典</string> <string name="dict">字典</string>
<string name="unknown_error">未知错误</string> <string name="unknown_error">未知錯誤</string>
<string name="end">end</string>
</resources> </resources>

@ -6,8 +6,8 @@
</string-array> </string-array>
<string-array name="group_style"> <string-array name="group_style">
<item>标签</item> <item>標籤</item>
<item>文件</item> <item>文件</item>
</string-array> </string-array>
<string-array name="text_suffix"> <string-array name="text_suffix">

@ -345,7 +345,7 @@
<string name="pt_show_all_find">顯示所有發現</string> <string name="pt_show_all_find">顯示所有發現</string>
<string name="ps_show_all_find">關閉則只顯示勾選源的發現</string> <string name="ps_show_all_find">關閉則只顯示勾選源的發現</string>
<string name="update_toc">更新目錄</string> <string name="update_toc">更新目錄</string>
<string name="txt_toc_regex">Txt目錄正則</string> <string name="txt_toc_regex">TXT目錄正則</string>
<string name="set_charset">設定編碼</string> <string name="set_charset">設定編碼</string>
<string name="swap_sort">倒序-順序</string> <string name="swap_sort">倒序-順序</string>
<string name="sort">排序</string> <string name="sort">排序</string>
@ -807,6 +807,9 @@
<string name="pre_download_s">預先下載%s章正文</string> <string name="pre_download_s">預先下載%s章正文</string>
<string name="is_enabled">是否啟用</string> <string name="is_enabled">是否啟用</string>
<string name="background_image">背景圖片</string> <string name="background_image">背景圖片</string>
<string name="background_image_blurring">背景圖片虛化</string>
<string name="background_image_blurring_radius">虛化半徑</string>
<string name="background_image_hint">0為停用,啓用範圍1~25\n半徑數值越大,虛化效果越高</string>
<string name="export_folder">匯出資料夾</string> <string name="export_folder">匯出資料夾</string>
<string name="export_charset">匯出編碼</string> <string name="export_charset">匯出編碼</string>
<string name="export_to_web_dav">匯出到WebDav</string> <string name="export_to_web_dav">匯出到WebDav</string>
@ -843,8 +846,9 @@
<string name="group_style">分組樣式</string> <string name="group_style">分組樣式</string>
<string name="export_file_name">匯出檔案名</string> <string name="export_file_name">匯出檔案名</string>
<string name="reset">重設</string> <string name="reset">重設</string>
<string name="null_url">url</string> <string name="null_url">url</string>
<string name="dict">字典</string> <string name="dict">字典</string>
<string name="unknown_error">未知错误</string> <string name="unknown_error">未知錯誤</string>
<string name="end">end</string>
</resources> </resources>

@ -807,6 +807,9 @@
<string name="pre_download_s">预先下载%s章正文</string> <string name="pre_download_s">预先下载%s章正文</string>
<string name="is_enabled">是否启用</string> <string name="is_enabled">是否启用</string>
<string name="background_image">背景图片</string> <string name="background_image">背景图片</string>
<string name="background_image_blurring">背景图片虚化</string>
<string name="background_image_blurring_radius">虚化半径</string>
<string name="background_image_hint">0为停用,启用范围1~25\n半径数值越大,虚化效果越高</string>
<string name="export_folder">导出文件夹</string> <string name="export_folder">导出文件夹</string>
<string name="export_charset">导出编码</string> <string name="export_charset">导出编码</string>
<string name="export_to_web_dav">导出到WebDav</string> <string name="export_to_web_dav">导出到WebDav</string>
@ -847,5 +850,6 @@
<string name="dict">字典</string> <string name="dict">字典</string>
<string name="unknown_error">未知错误</string> <string name="unknown_error">未知错误</string>
<string name="autobackup_fail">自动备份失败</string> <string name="autobackup_fail">自动备份失败</string>
<string name="end">结束</string>
</resources> </resources>

@ -807,6 +807,9 @@
<string name="pre_download_s">Download %s chapters in advance</string> <string name="pre_download_s">Download %s chapters in advance</string>
<string name="is_enabled">Is enabled</string> <string name="is_enabled">Is enabled</string>
<string name="background_image">Background image</string> <string name="background_image">Background image</string>
<string name="background_image_blurring">Background image blurring</string>
<string name="background_image_blurring_radius">Blurring radius</string>
<string name="background_image_hint">Disabled when 0, enable range from 1 to 25\nThe greater the radius, the stronger the effect of blurring</string>
<string name="copy_book_url">Copy book URL</string> <string name="copy_book_url">Copy book URL</string>
<string name="copy_toc_url">Copy chapters URL</string> <string name="copy_toc_url">Copy chapters URL</string>
<string name="export_folder">Export folder</string> <string name="export_folder">Export folder</string>
@ -849,5 +852,6 @@
<string name="dict">字典</string> <string name="dict">字典</string>
<string name="unknown_error">未知错误</string> <string name="unknown_error">未知错误</string>
<string name="autobackup_fail">Autobackup failed</string> <string name="autobackup_fail">Autobackup failed</string>
<string name="end">end</string>
</resources> </resources>

@ -40,20 +40,6 @@
android:defaultValue="true" android:defaultValue="true"
android:key="showRss" android:key="showRss"
android:title="@string/show_rss" android:title="@string/show_rss"
app:iconSpaceReserved="false" />
<io.legado.app.ui.widget.prefs.Preference
android:key="defaultCover"
android:title="@string/default_cover"
app:allowDividerAbove="false"
app:allowDividerBelow="false"
app:iconSpaceReserved="false" />
<io.legado.app.ui.widget.prefs.SwitchPreference
android:defaultValue="false"
android:key="useDefaultCover"
android:title="@string/use_default_cover"
android:summary="@string/use_default_cover_s"
app:allowDividerAbove="false" app:allowDividerAbove="false"
app:allowDividerBelow="false" app:allowDividerBelow="false"
app:iconSpaceReserved="false" /> app:iconSpaceReserved="false" />

@ -33,6 +33,15 @@
android:title="@string/bar_elevation" android:title="@string/bar_elevation"
app:iconSpaceReserved="false" /> app:iconSpaceReserved="false" />
<io.legado.app.ui.widget.prefs.SwitchPreference
android:defaultValue="false"
android:key="useDefaultCover"
android:title="@string/use_default_cover"
android:summary="@string/use_default_cover_s"
app:allowDividerAbove="false"
app:allowDividerBelow="false"
app:iconSpaceReserved="false" />
<io.legado.app.ui.widget.prefs.Preference <io.legado.app.ui.widget.prefs.Preference
android:key="themeList" android:key="themeList"
android:summary="@string/theme_list_summary" android:summary="@string/theme_list_summary"
@ -77,6 +86,10 @@
android:key="backgroundImage" android:key="backgroundImage"
android:title="@string/background_image" /> android:title="@string/background_image" />
<io.legado.app.ui.widget.prefs.Preference
android:key="backgroundImageBlurring"
android:title="@string/background_image_blurring" />
<io.legado.app.ui.widget.prefs.ColorPreference <io.legado.app.ui.widget.prefs.ColorPreference
android:defaultValue="@color/md_grey_200" android:defaultValue="@color/md_grey_200"
android:key="colorBottomBackground" android:key="colorBottomBackground"
@ -87,6 +100,13 @@
app:cpv_dialogType="preset" app:cpv_dialogType="preset"
app:iconSpaceReserved="false" /> app:iconSpaceReserved="false" />
<io.legado.app.ui.widget.prefs.Preference
android:key="defaultCover"
android:title="@string/default_cover"
app:allowDividerAbove="false"
app:allowDividerBelow="false"
app:iconSpaceReserved="false" />
<io.legado.app.ui.widget.prefs.Preference <io.legado.app.ui.widget.prefs.Preference
android:key="saveDayTheme" android:key="saveDayTheme"
android:summary="@string/save_day_theme_summary" android:summary="@string/save_day_theme_summary"
@ -133,6 +153,10 @@
android:key="backgroundImageNight" android:key="backgroundImageNight"
android:title="@string/background_image" /> android:title="@string/background_image" />
<io.legado.app.ui.widget.prefs.Preference
android:key="backgroundImageNightBlurring"
android:title="@string/background_image_blurring" />
<io.legado.app.ui.widget.prefs.ColorPreference <io.legado.app.ui.widget.prefs.ColorPreference
android:defaultValue="@color/md_grey_800" android:defaultValue="@color/md_grey_800"
android:key="colorBottomBackgroundNight" android:key="colorBottomBackgroundNight"
@ -141,6 +165,13 @@
app:cpv_dialogType="preset" app:cpv_dialogType="preset"
app:iconSpaceReserved="false" /> app:iconSpaceReserved="false" />
<io.legado.app.ui.widget.prefs.Preference
android:key="defaultCoverDark"
android:title="@string/default_cover"
app:allowDividerAbove="false"
app:allowDividerBelow="false"
app:iconSpaceReserved="false" />
<io.legado.app.ui.widget.prefs.Preference <io.legado.app.ui.widget.prefs.Preference
android:key="saveNightTheme" android:key="saveNightTheme"
android:summary="@string/save_night_theme_summary" android:summary="@string/save_night_theme_summary"

Loading…
Cancel
Save