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. 6
      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 {
// Flag to enable support for the new language APIs
coreLibraryDesugaringEnabled true
// Sets Java compatibility to Java 8
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
// Sets Java compatibility to Java 11
sourceCompatibility JavaVersion.VERSION_11
targetCompatibility JavaVersion.VERSION_11
}
kotlinOptions {
jvmTarget = "1.8"
jvmTarget = "11"
}
buildToolsVersion '30.0.3'
tasks.withType(JavaCompile) {
@ -198,7 +198,7 @@ dependencies {
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')

@ -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**
1. 为webService添加快捷操作

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

@ -5,7 +5,7 @@ import java.util.regex.Pattern
@Suppress("RegExpRedundantEscape")
object AppPattern {
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]*?)\\}\\}")
//匹配格式化后的图片格式

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

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

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

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

@ -1,23 +1,62 @@
package io.legado.app.help.http.cronet
import okhttp3.Call
import okhttp3.Interceptor
import okhttp3.Request
import okhttp3.Response
import io.legado.app.help.http.CookieStore
import okhttp3.*
import java.io.IOException
class CronetInterceptor : Interceptor {
class CronetInterceptor(private val cookieJar: CookieJar?) : Interceptor {
@Throws(IOException::class)
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)
private fun proceedWithCronet(request: Request, call: Call): Response {
val callback = CronetUrlRequestCallback(request, call)
val urlRequest = buildRequest(request, callback)
urlRequest.start()
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")
private fun getUrlMd5(url: String): String? {
//这样在下载成功后,遇到无网条件下,只要版本未发生变化也能获取md5
if (md5 != null && md5!!.length == 32&& version==ImplVersion.getCronetVersion()) {
appCtx.putPrefString("soMd5",md5)
appCtx.putPrefString("soVersion",ImplVersion.getCronetVersion())
if (md5 != null && md5!!.length == 32 && version == ImplVersion.getCronetVersion()) {
appCtx.putPrefString("soMd5", md5)
appCtx.putPrefString("soVersion", ImplVersion.getCronetVersion())
return md5
}
val inputStream: InputStream
@ -159,11 +159,11 @@ object CronetLoader : CronetEngine.Builder.LibraryLoader() {
outputStream.write(buffer, 0, read)
outputStream.flush()
}
val tmd5=outputStream.toString()
val tmd5 = outputStream.toString()
//成功获取到md5后保存md5和版本
if(tmd5.length==32){
appCtx.putPrefString("soMd5",tmd5)
appCtx.putPrefString("soVersion",ImplVersion.getCronetVersion())
if (tmd5.length == 32) {
appCtx.putPrefString("soMd5", tmd5)
appCtx.putPrefString("soVersion", ImplVersion.getCronetVersion())
}
return tmd5

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

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

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

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

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

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

@ -53,7 +53,7 @@ class ChangeSourceDialog : BaseDialogFragment(),
override fun onStart() {
super.onStart()
val dm = requireActivity().getSize()
val dm = requireActivity().windowSize
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 {
alert(title = getString(R.string.group_edit)) {
val alertBinding = DialogEditTextBinding.inflate(layoutInflater).apply {
editView.setHint(R.string.group_name)
textInputLayout.setHint(R.string.group_name)
editView.setText(bookGroup.groupName)
}
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.VerticalDivider
import io.legado.app.utils.applyTint
import io.legado.app.utils.getSize
import io.legado.app.utils.requestInputMethod
import io.legado.app.utils.viewbindingdelegate.viewBinding
import io.legado.app.utils.visible
import io.legado.app.utils.windowSize
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.launch
@ -43,7 +43,7 @@ class GroupManageDialog : BaseDialogFragment(), Toolbar.OnMenuItemClickListener
override fun onStart() {
super.onStart()
val dm = requireActivity().getSize()
val dm = requireActivity().windowSize
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() {
alert(title = getString(R.string.add_group)) {
val alertBinding = DialogEditTextBinding.inflate(layoutInflater).apply {
editView.setHint(R.string.group_name)
textInputLayout.setHint(R.string.group_name)
}
customView { alertBinding.root }
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.VerticalDivider
import io.legado.app.utils.applyTint
import io.legado.app.utils.getSize
import io.legado.app.utils.requestInputMethod
import io.legado.app.utils.viewbindingdelegate.viewBinding
import io.legado.app.utils.windowSize
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.launch
@ -61,7 +61,7 @@ class GroupSelectDialog : BaseDialogFragment(), Toolbar.OnMenuItemClickListener
override fun onStart() {
super.onStart()
val dm = requireActivity().getSize()
val dm = requireActivity().windowSize
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() {
alert(title = getString(R.string.add_group)) {
val alertBinding = DialogEditTextBinding.inflate(layoutInflater).apply {
editView.setHint(R.string.group_name)
textInputLayout.setHint(R.string.group_name)
}
customView { alertBinding.root }
yesButton {
@ -143,7 +143,7 @@ class GroupSelectDialog : BaseDialogFragment(), Toolbar.OnMenuItemClickListener
private fun editGroup(bookGroup: BookGroup) {
alert(title = getString(R.string.group_edit)) {
val alertBinding = DialogEditTextBinding.inflate(layoutInflater).apply {
editView.setHint(R.string.group_name)
textInputLayout.setHint(R.string.group_name)
editView.setText(bookGroup.groupName)
}
customView { alertBinding.root }

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

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

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

@ -73,7 +73,7 @@ class AutoReadDialog : BaseDialogFragment() {
}
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.seekAutoRead.progress = speed
}
@ -81,13 +81,13 @@ class AutoReadDialog : BaseDialogFragment() {
private fun initOnChange() {
binding.seekAutoRead.setOnSeekBarChangeListener(object : SeekBarChangeListener {
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)
}
override fun onStopTrackingTouch(seekBar: SeekBar) {
ReadBookConfig.autoReadSpeed =
if (binding.seekAutoRead.progress < 10) 10 else binding.seekAutoRead.progress
if (binding.seekAutoRead.progress < 2) 2 else binding.seekAutoRead.progress
upTtsSpeechRate()
}
})

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

@ -11,9 +11,9 @@ import io.legado.app.base.BaseDialogFragment
import io.legado.app.constant.EventBus
import io.legado.app.databinding.DialogReadPaddingBinding
import io.legado.app.help.ReadBookConfig
import io.legado.app.utils.getSize
import io.legado.app.utils.postEvent
import io.legado.app.utils.viewbindingdelegate.viewBinding
import io.legado.app.utils.windowSize
class PaddingConfigDialog : BaseDialogFragment() {
@ -21,7 +21,7 @@ class PaddingConfigDialog : BaseDialogFragment() {
override fun onStart() {
super.onStart()
val dm = requireActivity().getSize()
val dm = requireActivity().windowSize
dialog?.window?.let {
it.clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND)
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.help.ReadAloud
import io.legado.app.utils.getPrefLong
import io.legado.app.utils.getSize
import io.legado.app.utils.postEvent
import io.legado.app.utils.windowSize
import splitties.init.appCtx
class ReadAloudConfigDialog : DialogFragment() {
@ -28,7 +28,7 @@ class ReadAloudConfigDialog : DialogFragment() {
override fun onStart() {
super.onStart()
val dm = requireActivity().getSize()
val dm = requireActivity().windowSize
dialog?.window?.let {
it.setBackgroundDrawableResource(R.color.transparent)
it.setLayout((dm.widthPixels * 0.9).toInt(), ViewGroup.LayoutParams.WRAP_CONTENT)

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

@ -45,7 +45,7 @@ class TocRegexDialog : BaseDialogFragment(), Toolbar.OnMenuItemClickListener {
override fun onStart() {
super.onStart()
val dm = requireActivity().getSize()
val dm = requireActivity().windowSize
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)
}
requireContext().alert(titleResource = R.string.import_on_line) {
val alertBinding = DialogEditTextBinding.inflate(layoutInflater)
alertBinding.apply {
val alertBinding = DialogEditTextBinding.inflate(layoutInflater).apply {
textInputLayout.hint = "url"
editView.setFilterValues(cacheUrls)
editView.delCallBack = {
cacheUrls.remove(it)

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

@ -327,6 +327,7 @@ class BookSourceActivity : VMBaseActivity<ActivityBookSourceBinding, BookSourceV
private fun checkSource() {
alert(titleResource = R.string.search_book_key) {
val alertBinding = DialogEditTextBinding.inflate(layoutInflater).apply {
textInputLayout.hint = "search word"
editView.setText(CheckSource.keyword)
}
customView { alertBinding.root }
@ -346,7 +347,7 @@ class BookSourceActivity : VMBaseActivity<ActivityBookSourceBinding, BookSourceV
private fun selectionAddToGroups() {
alert(titleResource = R.string.add_group) {
val alertBinding = DialogEditTextBinding.inflate(layoutInflater).apply {
editView.setHint(R.string.group_name)
textInputLayout.setHint(R.string.group_name)
editView.setFilterValues(groups.toList())
editView.dropDownHeight = 180.dp
}
@ -366,7 +367,7 @@ class BookSourceActivity : VMBaseActivity<ActivityBookSourceBinding, BookSourceV
private fun selectionRemoveFromGroups() {
alert(titleResource = R.string.remove_group) {
val alertBinding = DialogEditTextBinding.inflate(layoutInflater).apply {
editView.setHint(R.string.group_name)
textInputLayout.setHint(R.string.group_name)
editView.setFilterValues(groups.toList())
editView.dropDownHeight = 180.dp
}
@ -400,6 +401,7 @@ class BookSourceActivity : VMBaseActivity<ActivityBookSourceBinding, BookSourceV
?.toMutableList() ?: mutableListOf()
alert(titleResource = R.string.import_on_line) {
val alertBinding = DialogEditTextBinding.inflate(layoutInflater).apply {
textInputLayout.hint = "url"
editView.setFilterValues(cacheUrls)
editView.delCallBack = {
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.ui.widget.recycler.VerticalDivider
import io.legado.app.utils.applyTint
import io.legado.app.utils.getSize
import io.legado.app.utils.requestInputMethod
import io.legado.app.utils.splitNotBlank
import io.legado.app.utils.viewbindingdelegate.viewBinding
import io.legado.app.utils.windowSize
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.launch
@ -39,7 +39,7 @@ class GroupManageDialog : BaseDialogFragment(), Toolbar.OnMenuItemClickListener
override fun onStart() {
super.onStart()
val dm = requireActivity().getSize()
val dm = requireActivity().windowSize
dialog?.window?.setLayout((dm.widthPixels * 0.9).toInt(), (dm.heightPixels * 0.9).toInt())
}
@ -87,8 +87,9 @@ class GroupManageDialog : BaseDialogFragment(), Toolbar.OnMenuItemClickListener
@SuppressLint("InflateParams")
private fun addGroup() {
alert(title = getString(R.string.add_group)) {
val alertBinding = DialogEditTextBinding.inflate(layoutInflater)
alertBinding.editView.setHint(R.string.group_name)
val alertBinding = DialogEditTextBinding.inflate(layoutInflater).apply {
textInputLayout.setHint(R.string.group_name)
}
customView { alertBinding.root }
yesButton {
alertBinding.editView.text?.toString()?.let {
@ -104,9 +105,10 @@ class GroupManageDialog : BaseDialogFragment(), Toolbar.OnMenuItemClickListener
@SuppressLint("InflateParams")
private fun editGroup(group: String) {
alert(title = getString(R.string.group_edit)) {
val alertBinding = DialogEditTextBinding.inflate(layoutInflater)
alertBinding.editView.setHint(R.string.group_name)
alertBinding.editView.setText(group)
val alertBinding = DialogEditTextBinding.inflate(layoutInflater).apply {
textInputLayout.setHint(R.string.group_name)
editView.setText(group)
}
customView { alertBinding.root }
yesButton {
viewModel.upGroup(group, alertBinding.editView.text?.toString())

@ -5,12 +5,9 @@ import android.content.ComponentName
import android.content.Intent
import android.content.SharedPreferences
import android.content.pm.PackageManager
import android.net.Uri
import android.os.Bundle
import android.os.Process
import android.view.View
import androidx.activity.result.contract.ActivityResultContracts
import androidx.documentfile.provider.DocumentFile
import androidx.preference.ListPreference
import androidx.preference.Preference
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.BookHelp
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.receiver.SharedReceiverActivity
import io.legado.app.service.WebService
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.utils.*
import splitties.init.appCtx
import java.io.File
class OtherConfigFragment : BasePreferenceFragment(),
@ -44,10 +36,6 @@ class OtherConfigFragment : BasePreferenceFragment(),
SharedReceiverActivity::class.java.name
)
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?) {
putPrefBoolean(PreferKey.processText, isProcessTextEnabled())
@ -56,7 +44,6 @@ class OtherConfigFragment : BasePreferenceFragment(),
upPreferenceSummary(PreferKey.preDownloadNum, AppConfig.preDownloadNum.toString())
upPreferenceSummary(PreferKey.threadCount, AppConfig.threadCount.toString())
upPreferenceSummary(PreferKey.webPort, webPort.toString())
upPreferenceSummary(PreferKey.defaultCover, getPrefString(PreferKey.defaultCover))
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
@ -98,17 +85,7 @@ class OtherConfigFragment : BasePreferenceFragment(),
putPrefInt(PreferKey.webPort, it)
}
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)
}
@ -134,9 +111,6 @@ class OtherConfigFragment : BasePreferenceFragment(),
setProcessTextEnable(it.getBoolean(key, true))
}
PreferKey.showDiscovery, PreferKey.showRss -> postEvent(EventBus.NOTIFY_MAIN, true)
PreferKey.defaultCover -> upPreferenceSummary(
key, getPrefString(PreferKey.defaultCover)
)
PreferKey.language -> listView.postDelayed({
LanguageUtils.setConfiguration(appCtx)
val intent = Intent(appCtx, MainActivity::class.java)
@ -157,11 +131,6 @@ class OtherConfigFragment : BasePreferenceFragment(),
getString(R.string.pre_download_s, value)
PreferKey.threadCount -> preference.summary = getString(R.string.threads_num, 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) {
val index = preference.findIndexOfValue(value)
// Set the summary to reflect the new value.
@ -175,8 +144,10 @@ class OtherConfigFragment : BasePreferenceFragment(),
@SuppressLint("InflateParams")
private fun showUserAgentDialog() {
alert("UserAgent") {
val alertBinding = DialogEditTextBinding.inflate(layoutInflater)
alertBinding.editView.setText(AppConfig.userAgent)
val alertBinding = DialogEditTextBinding.inflate(layoutInflater).apply {
textInputLayout.hint = "UserAgent"
editView.setText(AppConfig.userAgent)
}
customView { alertBinding.root }
okButton {
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.MenuItem
import android.view.View
import androidx.activity.result.contract.ActivityResultContracts
import android.widget.SeekBar
import androidx.documentfile.provider.DocumentFile
import androidx.preference.Preference
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.PreferKey
import io.legado.app.databinding.DialogEditTextBinding
import io.legado.app.databinding.DialogImageBlurringBinding
import io.legado.app.help.AppConfig
import io.legado.app.help.LauncherIconHelp
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.PermissionsCompat
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.prefs.ColorPreference
import io.legado.app.ui.widget.seekbar.SeekBarChangeListener
import io.legado.app.utils.*
import java.io.File
@ -35,17 +38,21 @@ import java.io.File
@Suppress("SameParameterValue")
class ThemeConfigFragment : BasePreferenceFragment(),
SharedPreferences.OnSharedPreferenceChangeListener {
private val selectLightBg = registerForActivityResult(ActivityResultContracts.GetContent()) {
it ?: return@registerForActivityResult
setBgFromUri(it, PreferKey.bgImage) {
upTheme(false)
}
}
private val selectDarkBg = registerForActivityResult(ActivityResultContracts.GetContent()) {
it ?: return@registerForActivityResult
setBgFromUri(it, PreferKey.bgImageN) {
upTheme(true)
private val requestCodeCover = 111
private val requestCodeCoverDark = 112
private val requestCodeBgLight = 121
private val requestCodeBgDark = 122
private val selectImage = registerForActivityResult(ActivityResultContractUtils.SelectImage()) {
val uri = it?.second ?: return@registerForActivityResult
when (it.first) {
requestCodeCover -> setCoverFromUri(PreferKey.defaultCover, uri)
requestCodeCoverDark -> setCoverFromUri(PreferKey.defaultCoverDark, uri)
requestCodeBgLight -> setBgFromUri(uri, PreferKey.bgImage) {
upTheme(false)
}
requestCodeBgDark -> setBgFromUri(uri, PreferKey.bgImageN) {
upTheme(true)
}
}
}
@ -57,6 +64,8 @@ class ThemeConfigFragment : BasePreferenceFragment(),
upPreferenceSummary(PreferKey.bgImage, getPrefString(PreferKey.bgImage))
upPreferenceSummary(PreferKey.bgImageN, getPrefString(PreferKey.bgImageN))
upPreferenceSummary(PreferKey.barElevation, AppConfig.elevation.toString())
upPreferenceSummary(PreferKey.defaultCover, getPrefString(PreferKey.defaultCover))
upPreferenceSummary(PreferKey.defaultCoverDark, getPrefString(PreferKey.defaultCoverDark))
findPreference<ColorPreference>(PreferKey.cBackground)?.let {
it.onSaveColor = { color ->
if (!ColorUtils.isColorLight(color)) {
@ -85,14 +94,14 @@ class ThemeConfigFragment : BasePreferenceFragment(),
setHasOptionsMenu(true)
}
override fun onResume() {
super.onResume()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
preferenceManager.sharedPreferences.registerOnSharedPreferenceChangeListener(this)
}
override fun onPause() {
override fun onDestroy() {
super.onDestroy()
preferenceManager.sharedPreferences.unregisterOnSharedPreferenceChangeListener(this)
super.onPause()
}
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
@ -128,6 +137,12 @@ class ThemeConfigFragment : BasePreferenceFragment(),
PreferKey.cNBBackground -> {
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")
"saveDayTheme", "saveNightTheme" -> saveThemeAlert(key)
PreferKey.bgImage -> if (getPrefString(PreferKey.bgImage).isNullOrEmpty()) {
selectLightBg.launch("image/*")
selectImage.launch(requestCodeBgLight)
} else {
selector(items = arrayListOf("删除图片", "选择图片")) { _, i ->
if (i == 0) {
removePref(PreferKey.bgImage)
upTheme(false)
} else {
selectLightBg.launch("image/*")
selectImage.launch(requestCodeBgLight)
}
}
}
PreferKey.bgImageN -> if (getPrefString(PreferKey.bgImageN).isNullOrEmpty()) {
selectDarkBg.launch("image/*")
selectImage.launch(requestCodeBgDark)
} else {
selector(items = arrayListOf("删除图片", "选择图片")) { _, i ->
if (i == 0) {
removePref(PreferKey.bgImageN)
upTheme(true)
} 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)
}
@ -181,7 +225,9 @@ class ThemeConfigFragment : BasePreferenceFragment(),
@SuppressLint("InflateParams")
private fun saveThemeAlert(key: String) {
alert(R.string.theme_name) {
val alertBinding = DialogEditTextBinding.inflate(layoutInflater)
val alertBinding = DialogEditTextBinding.inflate(layoutInflater).apply {
textInputLayout.hint = "name"
}
customView { alertBinding.root }
okButton {
alertBinding.editView.text?.toString()?.let { themeName ->
@ -199,6 +245,34 @@ class ThemeConfigFragment : BasePreferenceFragment(),
}.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) {
if (AppConfig.isNightTheme == isNightTheme) {
listView.post {
@ -217,6 +291,14 @@ class ThemeConfigFragment : BasePreferenceFragment(),
when (preferenceKey) {
PreferKey.barElevation -> preference.summary =
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
}
}
@ -232,7 +314,6 @@ class ThemeConfigFragment : BasePreferenceFragment(),
}.getOrNull()?.let { byteArray ->
file.writeBytes(byteArray)
putPrefString(preferenceKey, file.absolutePath)
upPreferenceSummary(preferenceKey, file.absolutePath)
success()
} ?: toastOnUi("获取文件出错")
}
@ -251,7 +332,6 @@ class ThemeConfigFragment : BasePreferenceFragment(),
file = FileUtils.createFileIfNotExist(file, preferenceKey, imgFile.name)
file.writeBytes(imgFile.readBytes())
putPrefString(preferenceKey, file.absolutePath)
upPreferenceSummary(preferenceKey, file.absolutePath)
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() {
super.onStart()
val dm = requireActivity().getSize()
val dm = requireActivity().windowSize
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) {
execute {
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
val jsoup = Jsoup.parse(body!!)
jsoup.body()

@ -76,7 +76,7 @@ class FilePickerDialog : DialogFragment(),
override fun onStart() {
super.onStart()
val dm = requireActivity().getSize()
val dm = requireActivity().windowSize
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.model.webBook.WebBook
import io.legado.app.service.help.CacheBook
import io.legado.app.utils.FileUtils
import io.legado.app.utils.postEvent
import kotlinx.coroutines.asCoroutineDispatcher
import kotlinx.coroutines.delay
@ -143,7 +142,6 @@ class MainViewModel(application: Application) : BaseViewModel(application) {
fun postLoad() {
execute {
FileUtils.deleteFile(FileUtils.getPath(context.cacheDir, "Fonts"))
if (appDb.httpTTSDao.count == 0) {
DefaultData.httpTTS.let {
appDb.httpTTSDao.insert(*it.toTypedArray())

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

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

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

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

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

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

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

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

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

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

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

@ -179,7 +179,10 @@ class CoverImageView @JvmOverloads constructor(
@SuppressLint("UseCompatLoadingForDrawables")
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)
if (dw == null) {
showBookName = true

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

@ -6,20 +6,21 @@ import android.util.DisplayMetrics
import android.view.WindowInsets
import android.view.WindowMetrics
fun Activity.getSize(): DisplayMetrics {
val displayMetrics = DisplayMetrics()
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
val windowMetrics: WindowMetrics = windowManager.currentWindowMetrics
val insets = windowMetrics.windowInsets
.getInsetsIgnoringVisibility(WindowInsets.Type.systemBars())
displayMetrics.widthPixels = windowMetrics.bounds.width() - insets.left - insets.right
displayMetrics.heightPixels = windowMetrics.bounds.height() - insets.top - insets.bottom
} else {
@Suppress("DEPRECATION")
windowManager.defaultDisplay.getMetrics(displayMetrics)
val Activity.windowSize: DisplayMetrics
get() {
val displayMetrics = DisplayMetrics()
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
val windowMetrics: WindowMetrics = windowManager.currentWindowMetrics
val insets = windowMetrics.windowInsets
.getInsetsIgnoringVisibility(WindowInsets.Type.systemBars())
displayMetrics.widthPixels = windowMetrics.bounds.width() - insets.left - insets.right
displayMetrics.heightPixels = windowMetrics.bounds.height() - insets.top - insets.bottom
} else {
@Suppress("DEPRECATION")
windowManager.defaultDisplay.getMetrics(displayMetrics)
}
return displayMetrics
}
return displayMetrics
}
/**
* 该方法需要在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
val rs = RenderScript.create(appCtx)
val blurredBitmap = srcBitmap.copy(Config.ARGB_8888, true)
@ -268,7 +268,7 @@ object BitmapUtils {
script.setInput(input)
//设置模糊半径
script.setRadius(8f)
script.setRadius(radius)
//启动 ScriptIntrinsicBlur
script.forEach(output)

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

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

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

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

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

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

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

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

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

@ -25,7 +25,8 @@
android:layout_height="0dp"
android:overScrollMode="never"
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
android:id="@+id/ll_search_base_info"

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

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

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

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

@ -1,18 +1,24 @@
<?xml version="1.0" encoding="utf-8"?>
<ScrollView
xmlns:android="http://schemas.android.com/apk/res/android"
<androidx.core.widget.NestedScrollView 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_height="match_parent"
android:layout_marginTop="48dp"
android:layout_marginBottom="48dp"
android:overScrollMode="ifContentScrolls">
android:layout_height="wrap_content">
<io.legado.app.ui.widget.text.AutoCompleteTextView
<io.legado.app.ui.widget.text.AutoCompleteTextView
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_height="wrap_content"/>
</ScrollView>
android:layout_height="wrap_content"
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:layout_width="match_parent"
android:layout_height="match_parent"
android:scrollbars="none" />
android:scrollbars="none"
tools:ignore="SpeakableTextPresentCheck" />
<io.legado.app.ui.widget.anima.RotateLoading
android:id="@+id/rotate_loading"
@ -61,6 +62,10 @@
android:visibility="gone"
tools:ignore="RtlHardcoded" />
<Space
android:layout_width="0dp"
android:layout_height="0dp" />
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"

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

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

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

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

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

@ -7,8 +7,8 @@
</string-array>
<string-array name="group_style">
<item>标签</item>
<item>文件</item>
<item>標籤</item>
<item>文件</item>
</string-array>
<string-array name="theme_mode">
@ -76,4 +76,4 @@
<item>替換規則</item>
</string-array>
</resources>
</resources>

@ -343,7 +343,7 @@
<string name="pt_show_all_find">顯示所有發現</string>
<string name="ps_show_all_find">關閉則只顯示勾選源的發現</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="swap_sort">倒序-順序</string>
<string name="sort">排序</string>
@ -405,7 +405,7 @@
<string name="book_url_pattern">書籍 URL 正則 (bookUrlPattern)</string>
<string name="rule_book_info_init">預處理規則 (bookInfoInit)</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_chapter_list">目錄列表規則 (chapterList)</string>
<string name="rule_chapter_name">章節名稱規則 (ChapterName)</string>
@ -414,7 +414,7 @@
<string name="rule_update_time">更新時間 (ChapterInfo)</string>
<string name="rule_book_content">正文規則 (content)</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="source_icon">圖標 (sourceIcon)</string>
<string name="r_articles">列表規則 (ruleArticles)</string>
@ -672,10 +672,10 @@
<string name="contributors">開發人員</string>
<string name="contact">聯繫我們</string>
<string name="license">開源許可</string>
<string name="follow_official_account">關注公</string>
<string name="follow_official_account">關注公</string>
<string name="wechat">WeChat</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="click_to_apply">點擊加入</string>
<string name="middle"></string>
@ -716,46 +716,46 @@
<string name="already_in_download">該書已在下載列表</string>
<string name="click_to_open">點擊打開</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_red_envelope_search_code">支付寶紅包搜索碼</string>
<string name="alipay_red_envelope_copy">537954522 點擊複製</string>
<string name="alipay_red_envelope_qr_code">支付寶紅包二維碼</string>
<string name="alipay_payment_qr_code">支付寶收款二維碼</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="default_cover">默認封面</string>
<string name="restore_ignore">恢復忽略列表</string>
<string name="restore_ignore_summary">恢復時忽略一些內容不恢復,方便不同手機配置不同</string>
<string name="read_config">閱讀界面設置</string>
<string name="rule_image_style">图片样式(imageStyle)</string>
<string name="rule_replace_regex">换规则(replaceRegex)</string>
<string name="rule_image_style">圖片樣式 (imageStyle)</string>
<string name="rule_replace_regex">換規則 (replaceRegex)</string>
<string name="group_name">分組名稱</string>
<string name="note_content">備註內容</string>
<string name="replace_enable_default_t">认启用替换净</string>
<string name="replace_enable_default_s">新加入书架的书是否启用替换净</string>
<string name="select_restore_file">选择恢复文件</string>
<string name="replace_enable_default_t">認啟用替換淨</string>
<string name="replace_enable_default_s">新加入書架的書是否啟用替換淨</string>
<string name="select_restore_file">選擇恢復文件</string>
<string name="day_background_too_dark">白天背景不能太暗</string>
<string name="day_bottom_bar_too_dark">白天底不能太暗</string>
<string name="night_background_too_light">背景不能太亮</string>
<string name="night_bottom_bar_too_light">间底栏不能太亮</string>
<string name="accent_background_diff">强调色不能和背景颜色相似</string>
<string name="accent_text_diff">强调色不能和文字颜色相似</string>
<string name="day_bottom_bar_too_dark">白天底不能太暗</string>
<string name="night_background_too_light">背景不能太亮</string>
<string name="night_bottom_bar_too_light">間底欄不能太亮</string>
<string name="accent_background_diff">強調色不能和背景顏色相似</string>
<string name="accent_text_diff">強調色不能和文字顏色相似</string>
<string name="wrong_format">格式不對</string>
<string name="error">錯誤</string>
<string name="show_brightness_view">顯示亮度調節控制項</string>
<string name="language">語言</string>
<string name="import_rss_source">匯入訂閱源</string>
<string name="donate_summary">您嘅支援我更新嘅動力</string>
<string name="about_summary">众号[开源阅读软件]</string>
<string name="donate_summary">您嘅支援我更新嘅動力</string>
<string name="about_summary">眾號[开源阅读软件]</string>
<string name="read_record">閲讀記錄</string>
<string name="read_record_summary">閱讀時間記錄</string>
<string name="local_tts">本地TTS</string>
<string name="thread_count">線程數</string>
<string name="all_read_time">總閲讀時間</string>
<string name="un_select_all">全部唔要</string>
<string name="delete_all">除所有</string>
<string name="delete_all">除所有</string>
<string name="import_str">導入</string>
<string name="export_str">導出</string>
<string name="save_theme_config">儲存主題配置</string>
@ -789,7 +789,7 @@
<string name="non_action">無操作</string>
<string name="body_title">正文標題</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_sub_empty_msg">添加大佬們提供的規則匯入地址 添加後點擊可匯入規則</string>
<string name="get_book_progress">拉取雲端進度</string>
@ -804,6 +804,9 @@
<string name="pre_download_s">預先下載%s章正文</string>
<string name="is_enabled">係咪啟用</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_charset">導出編碼</string>
<string name="export_to_web_dav">導出到WebDav</string>
@ -836,14 +839,15 @@
<string name="hide_when_status_bar_show">狀態欄顯示時隱藏</string>
<string name="diy_source_group">自訂源分組</string>
<string name="diy_edit_source_group">輸入自訂源分組名稱</string>
<string name="reverse_toc">转目录</string>
<string name="show_discovery">显示发现</string>
<string name="style"></string>
<string name="group_style">组样</string>
<string name="export_file_name">出文件名</string>
<string name="reverse_toc">轉目錄</string>
<string name="show_discovery">顯示發現</string>
<string name="style"></string>
<string name="group_style">組樣</string>
<string name="export_file_name">出文件名</string>
<string name="reset">重置</string>
<string name="null_url">url</string>
<string name="null_url">url</string>
<string name="dict">字典</string>
<string name="unknown_error">未知错误</string>
<string name="unknown_error">未知錯誤</string>
<string name="end">end</string>
</resources>

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

@ -345,7 +345,7 @@
<string name="pt_show_all_find">顯示所有發現</string>
<string name="ps_show_all_find">關閉則只顯示勾選源的發現</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="swap_sort">倒序-順序</string>
<string name="sort">排序</string>
@ -807,6 +807,9 @@
<string name="pre_download_s">預先下載%s章正文</string>
<string name="is_enabled">是否啟用</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_charset">匯出編碼</string>
<string name="export_to_web_dav">匯出到WebDav</string>
@ -843,8 +846,9 @@
<string name="group_style">分組樣式</string>
<string name="export_file_name">匯出檔案名</string>
<string name="reset">重設</string>
<string name="null_url">url</string>
<string name="null_url">url</string>
<string name="dict">字典</string>
<string name="unknown_error">未知错误</string>
<string name="unknown_error">未知錯誤</string>
<string name="end">end</string>
</resources>

@ -807,6 +807,9 @@
<string name="pre_download_s">预先下载%s章正文</string>
<string name="is_enabled">是否启用</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_charset">导出编码</string>
<string name="export_to_web_dav">导出到WebDav</string>
@ -847,5 +850,6 @@
<string name="dict">字典</string>
<string name="unknown_error">未知错误</string>
<string name="autobackup_fail">自动备份失败</string>
<string name="end">结束</string>
</resources>

@ -807,6 +807,9 @@
<string name="pre_download_s">Download %s chapters in advance</string>
<string name="is_enabled">Is enabled</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_toc_url">Copy chapters URL</string>
<string name="export_folder">Export folder</string>
@ -849,5 +852,6 @@
<string name="dict">字典</string>
<string name="unknown_error">未知错误</string>
<string name="autobackup_fail">Autobackup failed</string>
<string name="end">end</string>
</resources>

@ -40,20 +40,6 @@
android:defaultValue="true"
android:key="showRss"
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:allowDividerBelow="false"
app:iconSpaceReserved="false" />

@ -33,6 +33,15 @@
android:title="@string/bar_elevation"
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
android:key="themeList"
android:summary="@string/theme_list_summary"
@ -77,6 +86,10 @@
android:key="backgroundImage"
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
android:defaultValue="@color/md_grey_200"
android:key="colorBottomBackground"
@ -87,6 +100,13 @@
app:cpv_dialogType="preset"
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
android:key="saveDayTheme"
android:summary="@string/save_day_theme_summary"
@ -133,6 +153,10 @@
android:key="backgroundImageNight"
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
android:defaultValue="@color/md_grey_800"
android:key="colorBottomBackgroundNight"
@ -141,6 +165,13 @@
app:cpv_dialogType="preset"
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
android:key="saveNightTheme"
android:summary="@string/save_night_theme_summary"

Loading…
Cancel
Save