Merge pull request #3 from gedoor/master

更新
pull/282/head
10bits 4 years ago committed by GitHub
commit e34fd9bf0c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      README.md
  2. 2
      app/build.gradle
  3. 2
      app/src/main/AndroidManifest.xml
  4. 79
      app/src/main/assets/18PlusList.txt
  5. 18
      app/src/main/assets/updateLog.md
  6. 3
      app/src/main/java/io/legado/app/data/entities/rule/ContentRule.kt
  7. 2
      app/src/main/java/io/legado/app/help/AppConfig.kt
  8. 14
      app/src/main/java/io/legado/app/help/SourceHelp.kt
  9. 55
      app/src/main/java/io/legado/app/help/http/AjaxWebView.kt
  10. 6
      app/src/main/java/io/legado/app/lib/theme/ATH.kt
  11. 14
      app/src/main/java/io/legado/app/model/webBook/BookContent.kt
  12. 28
      app/src/main/java/io/legado/app/service/help/ReadBook.kt
  13. 4
      app/src/main/java/io/legado/app/ui/book/read/Help.kt
  14. 6
      app/src/main/java/io/legado/app/ui/book/read/ReadBookActivity.kt
  15. 97
      app/src/main/java/io/legado/app/ui/book/read/page/ContentTextView.kt
  16. 5
      app/src/main/java/io/legado/app/ui/book/read/page/PageView.kt
  17. 5
      app/src/main/java/io/legado/app/ui/book/read/page/delegate/NoAnimPageDelegate.kt
  18. 16
      app/src/main/java/io/legado/app/ui/book/read/page/delegate/PageDelegate.kt
  19. 1
      app/src/main/java/io/legado/app/ui/book/read/page/entities/TextPage.kt
  20. 29
      app/src/main/java/io/legado/app/ui/book/read/page/provider/ChapterProvider.kt
  21. 5
      app/src/main/java/io/legado/app/ui/book/read/page/provider/ImageProvider.kt
  22. 4
      app/src/main/java/io/legado/app/ui/book/source/edit/BookSourceEditActivity.kt
  23. 7
      app/src/main/java/io/legado/app/ui/book/source/manage/BookSourceViewModel.kt
  24. 4
      app/src/main/java/io/legado/app/ui/book/source/manage/GroupManageDialog.kt
  25. 4
      app/src/main/java/io/legado/app/ui/config/OtherConfigFragment.kt
  26. 6
      app/src/main/java/io/legado/app/ui/main/MainViewModel.kt
  27. 68
      app/src/main/java/io/legado/app/ui/widget/dialog/PhotoDialog.kt
  28. 1267
      app/src/main/java/io/legado/app/ui/widget/image/PhotoView.kt
  29. 48
      app/src/main/java/io/legado/app/ui/widget/image/photo/Info.kt
  30. 56
      app/src/main/java/io/legado/app/ui/widget/image/photo/RotateGestureDetector.kt
  31. 15
      app/src/main/res/layout/dialog_photo_view.xml
  32. 14
      app/src/main/res/values-zh-rHK/strings.xml
  33. 14
      app/src/main/res/values-zh-rTW/strings.xml
  34. 4
      app/src/main/res/values-zh/strings.xml
  35. 66
      app/src/main/res/values/strings.xml

@ -5,5 +5,7 @@
## 阅读3.0 ## 阅读3.0
书源规则 https://celeter.github.io 书源规则 https://celeter.github.io
[![aVElJs.th.jpg](https://s1.ax1x.com/2020/07/28/aVElJs.th.jpg)](https://imgchr.com/i/aVElJs) [![aVEQij.th.jpg](https://s1.ax1x.com/2020/07/28/aVEQij.th.jpg)](https://imgchr.com/i/aVEQij) [![aVEudg.th.jpg](https://s1.ax1x.com/2020/07/28/aVEudg.th.jpg)](https://imgchr.com/i/aVEudg) [![aVEneS.th.jpg](https://s1.ax1x.com/2020/07/28/aVEneS.th.jpg)](https://imgchr.com/i/aVEneS) [![aVEKoQ.th.jpg](https://s1.ax1x.com/2020/07/28/aVEKoQ.th.jpg)](https://imgchr.com/i/aVEKoQ) [![aVE1Wn.th.jpg](https://s1.ax1x.com/2020/07/28/aVE1Wn.th.jpg)](https://imgchr.com/i/aVE1Wn)
## 免责声明 ## 免责声明
https://gedoor.github.io/MyBookshelf/disclaimer.html https://gedoor.github.io/MyBookshelf/disclaimer.html

@ -124,7 +124,7 @@ dependencies {
implementation 'com.crashlytics.sdk.android:crashlytics:2.10.1' implementation 'com.crashlytics.sdk.android:crashlytics:2.10.1'
//androidX //androidX
implementation 'androidx.core:core-ktx:1.3.0' implementation 'androidx.core:core-ktx:1.3.1'
implementation 'androidx.appcompat:appcompat:1.1.0' implementation 'androidx.appcompat:appcompat:1.1.0'
implementation 'androidx.media:media:1.1.0' implementation 'androidx.media:media:1.1.0'
implementation 'androidx.preference:preference:1.1.1' implementation 'androidx.preference:preference:1.1.1'

@ -295,8 +295,10 @@
android:launchMode="singleTop"> android:launchMode="singleTop">
<intent-filter> <intent-filter>
<action android:name="android.intent.action.VIEW" /> <action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" /> <category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" /> <category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="file" /> <data android:scheme="file" />
<data android:scheme="content" /> <data android:scheme="content" />
<data android:mimeType="text/plain" /> <data android:mimeType="text/plain" />

@ -1,3 +1,82 @@
OGN5dS5jb20= OGN5dS5jb20=
c2cwMC54eXo= c2cwMC54eXo=
aXRyYWZmaWNuZXQuY29t aXRyYWZmaWNuZXQuY29t
eGlhb3FpYW5nNTIw
MTIzeGlhb3FpYW5n
eGlhb3FpYW5neHM=
eGlhb3FpYW5nNTIw
MzM1eHM=
eGN4czk=
eGN4czUyMA==
c2h1YmFvYW4=
c2h1YmFvd2FuZzEyMw==
c2h1YmFvYW4=
aGFpdGFuZzEyMw==
eXV6aGFpd3VsYQ==
cG8xOA==
Ymwtbm92ZWw=
NXRucw==
c2hhb3NodWdl
amluamlzaHV3dQ==
NDJ3Zw==
eWlxdXNodQ==
c2h1YmFvd2FuZzEyMw==
M2hlYmFv
MzNoZWJhbw==
bHVvcWl1enc=
bXlzaHVnZQ==
c3NzeHN3
eWl0ZQ==
Y3Vpd2VpanV1
Y3Vpd2VpanV4cw==
Y3Vpd2VpanV4
eGlhb3FpYW5nd3g=
YXN6dw==
YXN6dzY=
c2FuaGFveHM=
ODdzaHV3dQ==
NDh3eA==
bG9uZ3Rlbmcy
NnF3eA==
bG9uZ3Rlbmd4cw==
aGF4ZHU=
M3R3eA==
aGF4d3g1
NjZsZXdlbg==
eGJhbnpodQ==
aGR5cA==
ZHliejk=
ZGl5aWJhbnpodTk=
ZGl5aWJhbnpodQ==
ZGl5aWJhbnpodTc=
YnoyMjI=
d29kZWFwaTAwMQ==
dGFuZ3poZWthbg==
YmF4aWFueHM=
eGlhb3NodW9zaGVuemhhbg==
ZGFtb2tl
emh3ZW5wZw==
eXV6aGFpZ2U=
d21wOA==
OXhpYW53ZW4=
bmFucmVudmlw
cmV5b28=
eWZ4aWFvc2h1b2U=
c2Fuaml1enc=
N3Fpbmc3
cWR4aWFvc2h1bw==
Y2hpbmVzZXpq
MzlzaHViYW8=
a3l4czU=
NTZtcw==
bml1c2hh
bWt4czY=
MjIyMjJ4cw==
OTVkdXNodQ==
YmFuemh1MjI=
d3JsdHh0
dHVkb3V0eHQ=
cm5neHM=
OTl3ZW5rdQ==
bGFvc2lqaXhz
ZnVzaHV6aGFpMQ==

@ -3,6 +3,24 @@
* 请关注公众号[开源阅读]()支持我,同时关注合作公众号[小说拾遗](),阅读公众号小编。 * 请关注公众号[开源阅读]()支持我,同时关注合作公众号[小说拾遗](),阅读公众号小编。
* 新公众号[开源阅读]()已启用,[开源阅读软件]()备用 * 新公众号[开源阅读]()已启用,[开源阅读软件]()备用
**2020/07/30**
* 所有版本都加上书源屏蔽列表,有其它想法的可以自己编译软件,反正是开源的
**2020/07/29**
* 正文图片样式为FULL的自动为滚动模式
**2020/07/28**
* 长图正文规则添加图片样式FULL,可以滚动浏览了
**2020/07/26**
* 优化翻页,加快翻页速度
**2020/07/25**
* 正文规则添加多页合并后的替换规则,格式同样是##regex##replaceTo
* 正文图片添加长按缩放
* 正文规则添加图片样式规则,可以设置为FULL
* 其它一些bug修复
**2020/07/21** **2020/07/21**
* 优化文字选择,不再缓存 * 优化文字选择,不再缓存
* 添加忽略恢复列表,方便不同手机配置不同 * 添加忽略恢复列表,方便不同手机配置不同

@ -9,5 +9,6 @@ data class ContentRule(
var nextContentUrl: String? = null, var nextContentUrl: String? = null,
var webJs: String? = null, var webJs: String? = null,
var sourceRegex: String? = null, var sourceRegex: String? = null,
var imageStyle: Int = 0 //0默认大小居中,1最大宽度 var replaceRegex: String? = null,
var imageStyle: String? = null //默认大小居中,1最大宽度
) : Parcelable ) : Parcelable

@ -137,5 +137,7 @@ object AppConfig {
val readBodyToLh: Boolean get() = App.INSTANCE.getPrefBoolean(PreferKey.readBodyToLh, true) val readBodyToLh: Boolean get() = App.INSTANCE.getPrefBoolean(PreferKey.readBodyToLh, true)
val isGooglePlay: Boolean get() = App.INSTANCE.channel == "google" val isGooglePlay: Boolean get() = App.INSTANCE.channel == "google"
val isCoolApk: Boolean get() = App.INSTANCE.channel == "coolApk"
} }

@ -3,6 +3,7 @@ package io.legado.app.help
import android.os.Handler import android.os.Handler
import android.os.Looper import android.os.Looper
import io.legado.app.App import io.legado.app.App
import io.legado.app.data.entities.BookSource
import io.legado.app.data.entities.RssSource import io.legado.app.data.entities.RssSource
import io.legado.app.utils.EncoderUtils import io.legado.app.utils.EncoderUtils
import io.legado.app.utils.NetworkUtils import io.legado.app.utils.NetworkUtils
@ -33,9 +34,20 @@ object SourceHelp {
} }
} }
fun insertBookSource(vararg bookSources: BookSource) {
bookSources.forEach { bookSource ->
if (is18Plus(bookSource.bookSourceUrl)) {
handler.post {
App.INSTANCE.toast("${bookSource.bookSourceName}是18+网址,禁止导入.")
}
} else {
App.db.bookSourceDao().insert(bookSource)
}
}
}
private fun is18Plus(url: String?): Boolean { private fun is18Plus(url: String?): Boolean {
url ?: return false url ?: return false
if (AppConfig.isGooglePlay) return false
val baseUrl = NetworkUtils.getBaseUrl(url) val baseUrl = NetworkUtils.getBaseUrl(url)
baseUrl ?: return false baseUrl ?: return false
try { try {

@ -1,12 +1,14 @@
package io.legado.app.help.http package io.legado.app.help.http
import android.annotation.SuppressLint import android.annotation.SuppressLint
import android.os.Build
import android.os.Handler import android.os.Handler
import android.os.Looper import android.os.Looper
import android.os.Message import android.os.Message
import android.text.TextUtils import android.text.TextUtils
import android.webkit.* import android.webkit.CookieManager
import android.webkit.WebSettings
import android.webkit.WebView
import android.webkit.WebViewClient
import io.legado.app.App import io.legado.app.App
import io.legado.app.constant.AppConst import io.legado.app.constant.AppConst
import org.apache.commons.text.StringEscapeUtils import org.apache.commons.text.StringEscapeUtils
@ -142,30 +144,6 @@ class AjaxWebView {
handler.postDelayed(runnable, 1000) handler.postDelayed(runnable, 1000)
} }
override fun onReceivedError(
view: WebView,
errorCode: Int,
description: String,
failingUrl: String
) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
handler.obtainMessage(MSG_ERROR, Exception(description))
.sendToTarget()
}
}
override fun onReceivedError(
view: WebView,
request: WebResourceRequest,
error: WebResourceError
) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
handler.obtainMessage(
MSG_ERROR,
Exception(error.description.toString())
).sendToTarget()
}
}
} }
private class EvalJsRunnable( private class EvalJsRunnable(
@ -213,31 +191,6 @@ class AjaxWebView {
} }
} }
override fun onReceivedError(
view: WebView,
errorCode: Int,
description: String,
failingUrl: String
) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
handler.obtainMessage(MSG_ERROR, Exception(description))
.sendToTarget()
}
}
override fun onReceivedError(
view: WebView,
request: WebResourceRequest,
error: WebResourceError
) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
handler.obtainMessage(
MSG_ERROR,
Exception(error.description.toString())
).sendToTarget()
}
}
override fun onPageFinished(view: WebView, url: String) { override fun onPageFinished(view: WebView, url: String) {
params.setCookie(url) params.setCookie(url)
if (params.hasJavaScript()) { if (params.hasJavaScript()) {

@ -5,6 +5,7 @@ import android.app.Activity
import android.app.ActivityManager import android.app.ActivityManager
import android.content.Context import android.content.Context
import android.graphics.Color import android.graphics.Color
import android.graphics.drawable.GradientDrawable
import android.os.Build import android.os.Build
import android.view.View import android.view.View
import android.view.View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR import android.view.View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR
@ -17,6 +18,7 @@ import androidx.viewpager.widget.ViewPager
import com.google.android.material.bottomnavigation.BottomNavigationView import com.google.android.material.bottomnavigation.BottomNavigationView
import io.legado.app.R import io.legado.app.R
import io.legado.app.help.AppConfig import io.legado.app.help.AppConfig
import io.legado.app.utils.dp
import io.legado.app.utils.getCompatColor import io.legado.app.utils.getCompatColor
import kotlinx.android.synthetic.main.activity_main.view.* import kotlinx.android.synthetic.main.activity_main.view.*
import org.jetbrains.anko.backgroundColor import org.jetbrains.anko.backgroundColor
@ -138,6 +140,10 @@ object ATH {
} }
fun setAlertDialogTint(dialog: AlertDialog): AlertDialog { fun setAlertDialogTint(dialog: AlertDialog): AlertDialog {
val background = GradientDrawable()
background.cornerRadius = 3F.dp
background.setColor(dialog.context.backgroundColor)
dialog.window?.setBackgroundDrawable(background)
val colorStateList = Selector.colorBuild() val colorStateList = Selector.colorBuild()
.setDefaultColor(ThemeStore.accentColor(dialog.context)) .setDefaultColor(ThemeStore.accentColor(dialog.context))
.setPressedColor(ColorUtils.darkenColor(ThemeStore.accentColor(dialog.context))) .setPressedColor(ColorUtils.darkenColor(ThemeStore.accentColor(dialog.context)))

@ -95,13 +95,19 @@ object BookContent {
content.append(item.content).append("\n") content.append(item.content).append("\n")
} }
} }
content.deleteCharAt(content.length - 1) content.deleteCharAt(content.length - 1)
var contentStr = content.toString().htmlFormat()
val replaceRegex = bookSource.ruleContent?.replaceRegex
replaceRegex?.trim { it <= ' ' }?.split("##")?.let {
if (it.size > 1) {
contentStr = contentStr.replace(it[1].toRegex(), it.getOrNull(2) ?: "")
}
}
Debug.log(bookSource.bookSourceUrl, "┌获取章节名称") Debug.log(bookSource.bookSourceUrl, "┌获取章节名称")
Debug.log(bookSource.bookSourceUrl, "${bookChapter.title}") Debug.log(bookSource.bookSourceUrl, "${bookChapter.title}")
Debug.log(bookSource.bookSourceUrl, "┌获取正文内容") Debug.log(bookSource.bookSourceUrl, "┌获取正文内容")
Debug.log(bookSource.bookSourceUrl, "\n$content") Debug.log(bookSource.bookSourceUrl, "\n$contentStr")
return content.toString() return contentStr
} }
@Throws(Exception::class) @Throws(Exception::class)
@ -126,7 +132,7 @@ object BookContent {
} }
Debug.log(bookSource.bookSourceUrl, "" + nextUrlList.joinToString(""), printLog) Debug.log(bookSource.bookSourceUrl, "" + nextUrlList.joinToString(""), printLog)
} }
val content = analyzeRule.getString(contentRule.content).htmlFormat() val content = analyzeRule.getString(contentRule.content)
return ContentData(content, nextUrlList) return ContentData(content, nextUrlList)
} }
} }

@ -64,6 +64,7 @@ object ReadBook {
null null
} }
} }
callBack?.upPageAnim()
} }
fun upMsg(msg: String?) { fun upMsg(msg: String?) {
@ -313,7 +314,13 @@ object ReadBook {
when (chapter.index) { when (chapter.index) {
durChapterIndex -> { durChapterIndex -> {
curTextChapter = curTextChapter =
ChapterProvider.getTextChapter(book, chapter, contents, chapterSize) ChapterProvider.getTextChapter(
book,
chapter,
contents,
chapterSize,
imageStyle
)
if (upContent) callBack?.upContent(resetPageOffset = resetPageOffset) if (upContent) callBack?.upContent(resetPageOffset = resetPageOffset)
callBack?.upView() callBack?.upView()
curPageChanged() curPageChanged()
@ -322,12 +329,24 @@ object ReadBook {
} }
durChapterIndex - 1 -> { durChapterIndex - 1 -> {
prevTextChapter = prevTextChapter =
ChapterProvider.getTextChapter(book, chapter, contents, chapterSize) ChapterProvider.getTextChapter(
book,
chapter,
contents,
chapterSize,
imageStyle
)
if (upContent) callBack?.upContent(-1, resetPageOffset) if (upContent) callBack?.upContent(-1, resetPageOffset)
} }
durChapterIndex + 1 -> { durChapterIndex + 1 -> {
nextTextChapter = nextTextChapter =
ChapterProvider.getTextChapter(book, chapter, contents, chapterSize) ChapterProvider.getTextChapter(
book,
chapter,
contents,
chapterSize,
imageStyle
)
if (upContent) callBack?.upContent(1, resetPageOffset) if (upContent) callBack?.upContent(1, resetPageOffset)
} }
} }
@ -338,6 +357,8 @@ object ReadBook {
} }
} }
val imageStyle get() = webBook?.bookSource?.ruleContent?.imageStyle
fun saveRead() { fun saveRead() {
Coroutine.async { Coroutine.async {
book?.let { book -> book?.let { book ->
@ -358,5 +379,6 @@ object ReadBook {
fun upView() fun upView()
fun pageChanged() fun pageChanged()
fun contentLoadFinish() fun contentLoadFinish()
fun upPageAnim()
} }
} }

@ -20,6 +20,7 @@ import io.legado.app.lib.dialogs.noButton
import io.legado.app.lib.dialogs.yesButton import io.legado.app.lib.dialogs.yesButton
import io.legado.app.lib.theme.ATH import io.legado.app.lib.theme.ATH
import io.legado.app.lib.theme.ThemeStore import io.legado.app.lib.theme.ThemeStore
import io.legado.app.lib.theme.backgroundColor
import io.legado.app.service.help.Download import io.legado.app.service.help.Download
import io.legado.app.service.help.ReadBook import io.legado.app.service.help.ReadBook
import io.legado.app.utils.applyTint import io.legado.app.utils.applyTint
@ -131,6 +132,7 @@ object Help {
LayoutInflater.from(context).inflate(R.layout.dialog_download_choice, null) LayoutInflater.from(context).inflate(R.layout.dialog_download_choice, null)
.apply { .apply {
view = this view = this
setBackgroundColor(context.backgroundColor)
edit_start.setText(book.durChapterIndex.toString()) edit_start.setText(book.durChapterIndex.toString())
edit_end.setText(book.totalChapterNum.toString()) edit_end.setText(book.totalChapterNum.toString())
} }
@ -157,7 +159,7 @@ object Help {
customView { customView {
layoutInflater.inflate(R.layout.dialog_edit_text, null).apply { layoutInflater.inflate(R.layout.dialog_edit_text, null).apply {
editText = edit_view.apply { editText = edit_view.apply {
hint = "备注内容" setHint(R.string.note_content)
} }
} }
} }

@ -550,6 +550,12 @@ class ReadBookActivity : VMBaseActivity<ReadBookViewModel>(R.layout.activity_boo
} }
} }
override fun upPageAnim() {
launch {
page_view?.upPageAnim()
}
}
/** /**
* 页面改变 * 页面改变
*/ */

@ -16,6 +16,7 @@ import io.legado.app.ui.book.read.page.entities.TextLine
import io.legado.app.ui.book.read.page.entities.TextPage import io.legado.app.ui.book.read.page.entities.TextPage
import io.legado.app.ui.book.read.page.provider.ChapterProvider import io.legado.app.ui.book.read.page.provider.ChapterProvider
import io.legado.app.ui.book.read.page.provider.ImageProvider import io.legado.app.ui.book.read.page.provider.ImageProvider
import io.legado.app.ui.widget.dialog.PhotoDialog
import io.legado.app.utils.activity import io.legado.app.utils.activity
import io.legado.app.utils.getCompatColor import io.legado.app.utils.getCompatColor
import io.legado.app.utils.getPrefBoolean import io.legado.app.utils.getPrefBoolean
@ -213,74 +214,61 @@ class ContentTextView(context: Context, attrs: AttributeSet?) : View(context, at
) { ) {
if (!selectAble) return if (!selectAble) return
if (!visibleRect.contains(x, y)) return if (!visibleRect.contains(x, y)) return
var relativeOffset = relativeOffset(0) var relativeOffset: Float
for ((lineIndex, textLine) in textPage.textLines.withIndex()) { for (relativePos in 0..2) {
relativeOffset = relativeOffset(relativePos)
if (relativePos > 0) {
//滚动翻页
if (!ReadBookConfig.isScroll) return
if (relativeOffset >= ChapterProvider.visibleHeight) return
}
val page = relativePage(relativePos)
for ((lineIndex, textLine) in page.textLines.withIndex()) {
if (y > textLine.lineTop + relativeOffset && y < textLine.lineBottom + relativeOffset) { if (y > textLine.lineTop + relativeOffset && y < textLine.lineBottom + relativeOffset) {
for ((charIndex, textChar) in textLine.textChars.withIndex()) { for ((charIndex, textChar) in textLine.textChars.withIndex()) {
if (x > textChar.start && x < textChar.end) { if (x > textChar.start && x < textChar.end) {
textChar.selected = true initSelect(
invalidate() page.chapterIndex,
selectStart[0] = 0 relativePos,
selectStart[1] = lineIndex textLine,
selectStart[2] = charIndex textChar,
selectEnd[0] = 0 lineIndex,
selectEnd[1] = lineIndex charIndex,
selectEnd[2] = charIndex relativeOffset,
upSelectedStart( select
textChar.start,
textLine.lineBottom + relativeOffset,
textLine.lineTop + relativeOffset
) )
upSelectedEnd(textChar.end, textLine.lineBottom + relativeOffset)
select(0, lineIndex, charIndex)
return return
} }
} }
return return
} }
} }
if (!ReadBookConfig.isScroll) return
//滚动翻页
relativeOffset = relativeOffset(1)
if (relativeOffset >= ChapterProvider.visibleHeight) return
val nextPage = relativePage(1)
for ((lineIndex, textLine) in nextPage.textLines.withIndex()) {
if (y > textLine.lineTop + relativeOffset && y < textLine.lineBottom + relativeOffset) {
for ((charIndex, textChar) in textLine.textChars.withIndex()) {
if (x > textChar.start && x < textChar.end) {
textChar.selected = true
invalidate()
selectStart[0] = 1
selectStart[1] = lineIndex
selectStart[2] = charIndex
selectEnd[0] = 1
selectEnd[1] = lineIndex
selectEnd[2] = charIndex
upSelectedStart(
textChar.start,
textLine.lineBottom + relativeOffset,
textLine.lineTop + relativeOffset
)
upSelectedEnd(textChar.end, textLine.lineBottom + relativeOffset)
select(1, lineIndex, charIndex)
return
}
} }
return
} }
private fun initSelect(
chapterIndex: Int,
relativePage: Int,
textLine: TextLine,
textChar: TextChar,
lineIndex: Int,
charIndex: Int,
relativeOffset: Float,
select: (relativePage: Int, lineIndex: Int, charIndex: Int) -> Unit
) {
if (textChar.isImage) {
activity?.supportFragmentManager?.let {
PhotoDialog.show(it, chapterIndex, textChar.charData)
} }
relativeOffset = relativeOffset(2) } else {
if (relativeOffset >= ChapterProvider.visibleHeight) return
for ((lineIndex, textLine) in relativePage(2).textLines.withIndex()) {
if (y > textLine.lineTop + relativeOffset && y < textLine.lineBottom + relativeOffset) {
for ((charIndex, textChar) in textLine.textChars.withIndex()) {
if (x > textChar.start && x < textChar.end) {
textChar.selected = true textChar.selected = true
invalidate() invalidate()
selectStart[0] = 2 selectStart[0] = relativePage
selectStart[1] = lineIndex selectStart[1] = lineIndex
selectStart[2] = charIndex selectStart[2] = charIndex
selectEnd[0] = 2 selectEnd[0] = relativePage
selectEnd[1] = lineIndex selectEnd[1] = lineIndex
selectEnd[2] = charIndex selectEnd[2] = charIndex
upSelectedStart( upSelectedStart(
@ -289,12 +277,7 @@ class ContentTextView(context: Context, attrs: AttributeSet?) : View(context, at
textLine.lineTop + relativeOffset textLine.lineTop + relativeOffset
) )
upSelectedEnd(textChar.end, textLine.lineBottom + relativeOffset) upSelectedEnd(textChar.end, textLine.lineBottom + relativeOffset)
select(2, lineIndex, charIndex) select(relativePage, lineIndex, charIndex)
return
}
}
return
}
} }
} }

@ -17,6 +17,7 @@ import io.legado.app.ui.book.read.page.provider.ChapterProvider
import io.legado.app.utils.activity import io.legado.app.utils.activity
import io.legado.app.utils.screenshot import io.legado.app.utils.screenshot
import kotlinx.android.synthetic.main.activity_book_read.view.* import kotlinx.android.synthetic.main.activity_book_read.view.*
import java.util.*
class PageView(context: Context, attrs: AttributeSet) : class PageView(context: Context, attrs: AttributeSet) :
FrameLayout(context, attrs), FrameLayout(context, attrs),
@ -109,7 +110,9 @@ class PageView(context: Context, attrs: AttributeSet) :
fun upPageAnim() { fun upPageAnim() {
pageDelegate?.onDestroy() pageDelegate?.onDestroy()
pageDelegate = null pageDelegate = null
pageDelegate = when (ReadBookConfig.pageAnim) { pageDelegate = if (ReadBook.imageStyle?.toUpperCase(Locale.ROOT) == "FULL") {
ScrollPageDelegate(this)
} else when (ReadBookConfig.pageAnim) {
0 -> CoverPageDelegate(this) 0 -> CoverPageDelegate(this)
1 -> SlidePageDelegate(this) 1 -> SlidePageDelegate(this)
2 -> SimulationPageDelegate(this) 2 -> SimulationPageDelegate(this)

@ -1,5 +1,6 @@
package io.legado.app.ui.book.read.page.delegate package io.legado.app.ui.book.read.page.delegate
import android.view.MotionEvent
import io.legado.app.ui.book.read.page.PageView import io.legado.app.ui.book.read.page.PageView
class NoAnimPageDelegate(pageView: PageView) : HorizontalPageDelegate(pageView) { class NoAnimPageDelegate(pageView: PageView) : HorizontalPageDelegate(pageView) {
@ -11,4 +12,8 @@ class NoAnimPageDelegate(pageView: PageView) : HorizontalPageDelegate(pageView)
stopScroll() stopScroll()
} }
override fun onDoubleTap(e: MotionEvent): Boolean {
return onSingleTapUp(e)
}
} }

@ -10,12 +10,12 @@ import android.view.animation.DecelerateInterpolator
import android.widget.Scroller import android.widget.Scroller
import androidx.annotation.CallSuper import androidx.annotation.CallSuper
import com.google.android.material.snackbar.Snackbar import com.google.android.material.snackbar.Snackbar
import io.legado.app.R
import io.legado.app.help.AppConfig import io.legado.app.help.AppConfig
import io.legado.app.help.ReadBookConfig import io.legado.app.help.ReadBookConfig
import io.legado.app.ui.book.read.page.ContentView import io.legado.app.ui.book.read.page.ContentView
import io.legado.app.ui.book.read.page.PageView import io.legado.app.ui.book.read.page.PageView
import kotlin.math.abs import kotlin.math.abs
import io.legado.app.R
abstract class PageDelegate(protected val pageView: PageView) : abstract class PageDelegate(protected val pageView: PageView) :
GestureDetector.SimpleOnGestureListener() { GestureDetector.SimpleOnGestureListener() {
@ -24,6 +24,7 @@ abstract class PageDelegate(protected val pageView: PageView) :
pageView.width * 0.66f, pageView.height * 0.66f pageView.width * 0.66f, pageView.height * 0.66f
) )
protected val context: Context = pageView.context protected val context: Context = pageView.context
private val animationSpeed = 300
//起始点 //起始点
protected var startX: Float = 0f protected var startX: Float = 0f
@ -115,13 +116,12 @@ abstract class PageDelegate(protected val pageView: PageView) :
} }
protected fun startScroll(startX: Int, startY: Int, dx: Int, dy: Int) { protected fun startScroll(startX: Int, startY: Int, dx: Int, dy: Int) {
scroller.startScroll( val duration = if (dx != 0) {
startX, (animationSpeed * abs(dx)) / viewWidth
startY, } else {
dx, (animationSpeed * abs(dy)) / viewHeight
dy, }
if (dx != 0) (abs(dx) * 0.3).toInt() else (abs(dy) * 0.3).toInt() scroller.startScroll(startX, startY, dx, dy, duration)
)
isRunning = true isRunning = true
isStarted = true isStarted = true
pageView.invalidate() pageView.invalidate()

@ -22,6 +22,7 @@ data class TextPage(
fun upLinesPosition() = ChapterProvider.apply { fun upLinesPosition() = ChapterProvider.apply {
if (!ReadBookConfig.textBottomJustify) return@apply if (!ReadBookConfig.textBottomJustify) return@apply
if (textLines.size <= 1) return@apply if (textLines.size <= 1) return@apply
if (textLines.last().isImage) return@apply
if (visibleHeight - height >= with(textLines.last()) { lineBottom - lineTop }) return@apply if (visibleHeight - height >= with(textLines.last()) { lineBottom - lineTop }) return@apply
val surplus = (visibleBottom - textLines.last().lineBottom) val surplus = (visibleBottom - textLines.last().lineBottom)
if (surplus == 0f) return@apply if (surplus == 0f) return@apply

@ -17,6 +17,7 @@ import io.legado.app.ui.book.read.page.entities.TextChar
import io.legado.app.ui.book.read.page.entities.TextLine import io.legado.app.ui.book.read.page.entities.TextLine
import io.legado.app.ui.book.read.page.entities.TextPage import io.legado.app.ui.book.read.page.entities.TextPage
import io.legado.app.utils.* import io.legado.app.utils.*
import java.util.*
import java.util.regex.Pattern import java.util.regex.Pattern
@ -51,7 +52,8 @@ object ChapterProvider {
book: Book, book: Book,
bookChapter: BookChapter, bookChapter: BookChapter,
contents: List<String>, contents: List<String>,
chapterSize: Int chapterSize: Int,
imageStyle: String?
): TextChapter { ): TextChapter {
val textPages = arrayListOf<TextPage>() val textPages = arrayListOf<TextPage>()
val pageLines = arrayListOf<Int>() val pageLines = arrayListOf<Int>()
@ -69,7 +71,7 @@ object ChapterProvider {
src?.let { src?.let {
durY = durY =
setTypeImage( setTypeImage(
book, bookChapter, src, durY, textPages book, bookChapter, src, durY, textPages, imageStyle
) )
} }
} else { } else {
@ -116,26 +118,39 @@ object ChapterProvider {
chapter: BookChapter, chapter: BookChapter,
src: String, src: String,
y: Float, y: Float,
textPages: ArrayList<TextPage> textPages: ArrayList<TextPage>,
imageStyle: String?
): Float { ): Float {
var durY = y var durY = y
ImageProvider.getImage(book, chapter.index, src)?.let { ImageProvider.getImage(book, chapter.index, src)?.let {
if (durY > visibleHeight) {
textPages.last().height = durY
textPages.add(TextPage())
durY = 0f
}
var height = it.height var height = it.height
var width = it.width var width = it.width
when (imageStyle?.toUpperCase(Locale.ROOT)) {
"FULL" -> {
width = visibleWidth
height = it.height * visibleWidth / it.width
}
else -> {
if (it.width > visibleWidth) { if (it.width > visibleWidth) {
height = it.height * visibleWidth / it.width height = it.height * visibleWidth / it.width
width = width = visibleWidth
visibleWidth
} }
if (height > visibleHeight) { if (height > visibleHeight) {
width = width * visibleHeight / height width = width * visibleHeight / height
height = height = visibleHeight
visibleHeight
} }
if (durY + height > visibleHeight) { if (durY + height > visibleHeight) {
textPages.last().height = durY
textPages.add(TextPage()) textPages.add(TextPage())
durY = 0f durY = 0f
} }
}
}
val textLine = TextLine(isImage = true) val textLine = TextLine(isImage = true)
textLine.lineTop = durY textLine.lineTop = durY
durY += height durY += height

@ -10,10 +10,11 @@ import io.legado.app.utils.FileUtils
import io.legado.app.utils.MD5Utils import io.legado.app.utils.MD5Utils
import io.legado.app.utils.externalFilesDir import io.legado.app.utils.externalFilesDir
import java.io.FileOutputStream import java.io.FileOutputStream
import java.util.concurrent.ConcurrentHashMap
object ImageProvider { object ImageProvider {
private val cache = hashMapOf<Int, HashMap<String, Bitmap>>() private val cache = ConcurrentHashMap<Int, ConcurrentHashMap<String, Bitmap>>()
@Synchronized @Synchronized
fun getCache(chapterIndex: Int, src: String): Bitmap? { fun getCache(chapterIndex: Int, src: String): Bitmap? {
@ -24,7 +25,7 @@ object ImageProvider {
fun setCache(chapterIndex: Int, src: String, bitmap: Bitmap) { fun setCache(chapterIndex: Int, src: String, bitmap: Bitmap) {
var indexCache = cache[chapterIndex] var indexCache = cache[chapterIndex]
if (indexCache == null) { if (indexCache == null) {
indexCache = hashMapOf() indexCache = ConcurrentHashMap()
cache[chapterIndex] = indexCache cache[chapterIndex] = indexCache
} }
indexCache[src] = bitmap indexCache[src] = bitmap

@ -233,6 +233,8 @@ class BookSourceEditActivity :
add(EditEntity("nextContentUrl", cr?.nextContentUrl, R.string.rule_next_content)) add(EditEntity("nextContentUrl", cr?.nextContentUrl, R.string.rule_next_content))
add(EditEntity("webJs", cr?.webJs, R.string.rule_web_js)) add(EditEntity("webJs", cr?.webJs, R.string.rule_web_js))
add(EditEntity("sourceRegex", cr?.sourceRegex, R.string.rule_source_regex)) add(EditEntity("sourceRegex", cr?.sourceRegex, R.string.rule_source_regex))
add(EditEntity("replaceRegex", cr?.replaceRegex, R.string.rule_replace_regex))
add(EditEntity("imageStyle", cr?.imageStyle, R.string.rule_image_style))
} }
//发现 //发现
val er = source?.getExploreRule() val er = source?.getExploreRule()
@ -332,6 +334,8 @@ class BookSourceEditActivity :
"nextContentUrl" -> contentRule.nextContentUrl = it.value "nextContentUrl" -> contentRule.nextContentUrl = it.value
"webJs" -> contentRule.webJs = it.value "webJs" -> contentRule.webJs = it.value
"sourceRegex" -> contentRule.sourceRegex = it.value "sourceRegex" -> contentRule.sourceRegex = it.value
"replaceRegex" -> contentRule.replaceRegex = it.value
"imageStyle" -> contentRule.imageStyle = it.value
} }
} }
source.ruleSearch = searchRule source.ruleSearch = searchRule

@ -8,6 +8,7 @@ import com.jayway.jsonpath.JsonPath
import io.legado.app.App import io.legado.app.App
import io.legado.app.base.BaseViewModel import io.legado.app.base.BaseViewModel
import io.legado.app.data.entities.BookSource import io.legado.app.data.entities.BookSource
import io.legado.app.help.SourceHelp
import io.legado.app.help.http.HttpHelper import io.legado.app.help.http.HttpHelper
import io.legado.app.help.storage.OldRule import io.legado.app.help.storage.OldRule
import io.legado.app.help.storage.Restore.jsonPath import io.legado.app.help.storage.Restore.jsonPath
@ -205,7 +206,7 @@ class BookSourceViewModel(application: Application) : BaseViewModel(application)
} }
} else { } else {
OldRule.jsonToBookSource(text1)?.let { OldRule.jsonToBookSource(text1)?.let {
App.db.bookSourceDao().insert(it) SourceHelp.insertBookSource(it)
count = 1 count = 1
} }
} }
@ -220,7 +221,7 @@ class BookSourceViewModel(application: Application) : BaseViewModel(application)
bookSources.add(it) bookSources.add(it)
} }
} }
App.db.bookSourceDao().insert(*bookSources.toTypedArray()) SourceHelp.insertBookSource(*bookSources.toTypedArray())
"导入${bookSources.size}" "导入${bookSources.size}"
} }
text1.isAbsUrl() -> { text1.isAbsUrl() -> {
@ -251,7 +252,7 @@ class BookSourceViewModel(application: Application) : BaseViewModel(application)
bookSources.add(source) bookSources.add(source)
} }
} }
App.db.bookSourceDao().insert(*bookSources.toTypedArray()) SourceHelp.insertBookSource(*bookSources.toTypedArray())
return bookSources.size return bookSources.size
} }
} }

@ -89,7 +89,7 @@ class GroupManageDialog : DialogFragment(), Toolbar.OnMenuItemClickListener {
customView { customView {
layoutInflater.inflate(R.layout.dialog_edit_text, null).apply { layoutInflater.inflate(R.layout.dialog_edit_text, null).apply {
editText = edit_view.apply { editText = edit_view.apply {
hint = "分组名称" setHint(R.string.group_name)
} }
} }
} }
@ -111,7 +111,7 @@ class GroupManageDialog : DialogFragment(), Toolbar.OnMenuItemClickListener {
customView { customView {
layoutInflater.inflate(R.layout.dialog_edit_text, null).apply { layoutInflater.inflate(R.layout.dialog_edit_text, null).apply {
editText = edit_view.apply { editText = edit_view.apply {
hint = "分组名称" setHint(R.string.group_name)
setText(group) setText(group)
} }
} }

@ -80,9 +80,7 @@ class OtherConfigFragment : PreferenceFragmentCompat(),
} }
PreferKey.cleanCache -> { PreferKey.cleanCache -> {
BookHelp.clearCache() BookHelp.clearCache()
requireActivity().cacheDir.listFiles()?.forEach { FileUtils.deleteFile(requireActivity().cacheDir.absolutePath)
it.delete()
}
toast(R.string.clear_cache_success) toast(R.string.clear_cache_success)
} }
PreferKey.defaultCover -> { PreferKey.defaultCover -> {

@ -81,11 +81,7 @@ class MainViewModel(application: Application) : BaseViewModel(application) {
fun postLoad() { fun postLoad() {
execute { execute {
FileUtils.getDirFile(context.cacheDir, "Fonts").let { FileUtils.deleteFile(FileUtils.getPath(context.cacheDir, "Fonts"))
if (it.exists()) {
it.delete()
}
}
} }
} }
} }

@ -0,0 +1,68 @@
package io.legado.app.ui.widget.dialog
import android.os.Bundle
import android.util.DisplayMetrics
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.FragmentManager
import io.legado.app.R
import io.legado.app.base.BaseDialogFragment
import io.legado.app.service.help.ReadBook
import io.legado.app.ui.book.read.page.provider.ImageProvider
import kotlinx.android.synthetic.main.dialog_photo_view.*
class PhotoDialog : BaseDialogFragment() {
companion object {
fun show(
fragmentManager: FragmentManager,
chapterIndex: Int,
src: String
) {
PhotoDialog().apply {
val bundle = Bundle()
bundle.putInt("chapterIndex", chapterIndex)
bundle.putString("src", src)
arguments = bundle
}.show(fragmentManager, "photoDialog")
}
}
override fun onStart() {
super.onStart()
val dm = DisplayMetrics()
activity?.windowManager?.defaultDisplay?.getMetrics(dm)
dialog?.window?.setLayout(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT
)
}
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
return inflater.inflate(R.layout.dialog_photo_view, container)
}
override fun onFragmentCreated(view: View, savedInstanceState: Bundle?) {
arguments?.let {
val chapterIndex = it.getInt("chapterIndex")
val src = it.getString("src")
ReadBook.book?.let { book ->
src?.let {
ImageProvider.getImage(book, chapterIndex, src)?.let { bitmap ->
photo_view.setImageBitmap(bitmap)
}
}
}
}
}
}

File diff suppressed because it is too large Load Diff

@ -0,0 +1,48 @@
package io.legado.app.ui.widget.image.photo
import android.graphics.PointF
import android.graphics.RectF
import android.widget.ImageView
class Info(
rect: RectF,
img: RectF,
widget: RectF,
base: RectF,
screenCenter: PointF,
scale: Float,
degrees: Float,
scaleType: ImageView.ScaleType?
) {
// 内部图片在整个手机界面的位置
var mRect = RectF()
// 控件在窗口的位置
var mImgRect = RectF()
var mWidgetRect = RectF()
var mBaseRect = RectF()
var mScreenCenter = PointF()
var mScale = 0f
var mDegrees = 0f
var mScaleType: ImageView.ScaleType? = null
init {
mRect.set(rect)
mImgRect.set(img)
mWidgetRect.set(widget)
mScale = scale
mScaleType = scaleType
mDegrees = degrees
mBaseRect.set(base)
mScreenCenter.set(screenCenter)
}
}

@ -0,0 +1,56 @@
package io.legado.app.ui.widget.image.photo
import android.view.MotionEvent
import kotlin.math.abs
import kotlin.math.atan
class RotateGestureDetector(l: OnRotateListener) {
private val MAX_DEGREES_STEP = 120
private val mListener: OnRotateListener? = null
private var mPrevSlope = 0f
private var mCurrSlope = 0f
private val x1 = 0f
private val y1 = 0f
private val x2 = 0f
private val y2 = 0f
fun onTouchEvent(event: MotionEvent) {
when (event.actionMasked) {
MotionEvent.ACTION_POINTER_DOWN,
MotionEvent.ACTION_POINTER_UP -> {
if (event.pointerCount == 2) mPrevSlope = caculateSlope(event)
}
MotionEvent.ACTION_MOVE -> if (event.pointerCount > 1) {
mCurrSlope = caculateSlope(event)
val currDegrees = Math.toDegrees(atan(mCurrSlope.toDouble()));
val prevDegrees = Math.toDegrees(atan(mPrevSlope.toDouble()));
val deltaSlope = currDegrees - prevDegrees;
if (abs(deltaSlope) <= MAX_DEGREES_STEP) {
mListener?.onRotate(deltaSlope.toFloat(), (x2 + x1) / 2, (y2 + y1) / 2);
}
mPrevSlope = mCurrSlope;
}
}
}
private fun caculateSlope(event: MotionEvent): Float {
val x1 = event.getX(0);
val y1 = event.getY(0);
val x2 = event.getX(1);
val y2 = event.getY(1);
return (y2 - y1) / (x2 - x1);
}
}
interface OnRotateListener {
fun onRotate(degrees: Float, focusX: Float, focusY: Float)
}

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/background">
<io.legado.app.ui.widget.image.PhotoView
android:id="@+id/photo_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="centerInside" />
</androidx.constraintlayout.widget.ConstraintLayout>

@ -719,9 +719,13 @@
<string name="alipay_payment_qr_code">支付寶收款二維碼</string> <string name="alipay_payment_qr_code">支付寶收款二維碼</string>
<string name="qq_collection_qr_code">QQ收款二維碼</string> <string name="qq_collection_qr_code">QQ收款二維碼</string>
<string name="contributors_summary">gedoor,Invinciblelee等,详情请在github中查看</string> <string name="contributors_summary">gedoor,Invinciblelee等,详情请在github中查看</string>
<string name="clear_cache_summary">清除已下载书籍和字体缓存</string> <string name="clear_cache_summary">清除已下載書籍和字體緩存</string>
<string name="default_cover">默认封面</string> <string name="default_cover">默認封面</string>
<string name="restore_ignore">恢复忽略列表</string> <string name="restore_ignore">恢復忽略列表</string>
<string name="restore_ignore_summary">恢复时忽略一些内容不恢复,方便不同手机配置不同</string> <string name="restore_ignore_summary">恢復時忽略一些內容不恢復,方便不同手機配置不同</string>
<string name="read_config">阅读界面设置</string> <string name="read_config">閱讀界面設置</string>
<string name="rule_image_style">图片样式(imageStyle)</string>
<string name="rule_replace_regex">替换规则(replaceRegex)</string>
<string name="group_name">分組名稱</string>
<string name="note_content">備註內容</string>
</resources> </resources>

@ -719,10 +719,14 @@
<string name="alipay_payment_qr_code">支付寶收款二維碼</string> <string name="alipay_payment_qr_code">支付寶收款二維碼</string>
<string name="qq_collection_qr_code">QQ收款二維碼</string> <string name="qq_collection_qr_code">QQ收款二維碼</string>
<string name="contributors_summary">gedoor,Invinciblelee等,详情请在github中查看</string> <string name="contributors_summary">gedoor,Invinciblelee等,详情请在github中查看</string>
<string name="clear_cache_summary">清除已下载书籍和字体缓存</string> <string name="clear_cache_summary">清除已下載書籍和字體緩存</string>
<string name="default_cover">默认封面</string> <string name="default_cover">默認封面</string>
<string name="restore_ignore">恢复忽略列表</string> <string name="restore_ignore">恢復忽略列表</string>
<string name="restore_ignore_summary">恢复时忽略一些内容不恢复,方便不同手机配置不同</string> <string name="restore_ignore_summary">恢復時忽略一些內容不恢復,方便不同手機配置不同</string>
<string name="read_config">阅读界面设置</string> <string name="read_config">閱讀界面設置</string>
<string name="rule_image_style">图片样式(imageStyle)</string>
<string name="rule_replace_regex">替换规则(replaceRegex)</string>
<string name="group_name">分組名稱</string>
<string name="note_content">備註內容</string>
</resources> </resources>

@ -724,4 +724,8 @@
<string name="restore_ignore">恢复忽略列表</string> <string name="restore_ignore">恢复忽略列表</string>
<string name="restore_ignore_summary">恢复时忽略一些内容不恢复,方便不同手机配置不同</string> <string name="restore_ignore_summary">恢复时忽略一些内容不恢复,方便不同手机配置不同</string>
<string name="read_config">阅读界面设置</string> <string name="read_config">阅读界面设置</string>
<string name="rule_image_style">图片样式(imageStyle)</string>
<string name="rule_replace_regex">替换规则(replaceRegex)</string>
<string name="group_name">分组名称</string>
<string name="note_content">备注内容</string>
</resources> </resources>

@ -40,7 +40,7 @@
<string name="in_favorites">in Favorites</string> <string name="in_favorites">in Favorites</string>
<string name="out_favorites">Not in Favorites</string> <string name="out_favorites">Not in Favorites</string>
<string name="rss">Subscription</string> <string name="rss">Subscription</string>
<string name="all">ALL</string> <string name="all">All</string>
<string name="recent_reading">Recent reading</string> <string name="recent_reading">Recent reading</string>
<string name="last_read">Last reading</string> <string name="last_read">Last reading</string>
<string name="update_log">What\'s new</string> <string name="update_log">What\'s new</string>
@ -55,8 +55,8 @@
<string name="bookshelf_layout">Layout</string> <string name="bookshelf_layout">Layout</string>
<string name="view">View</string> <string name="view">View</string>
<string name="book_library">Library</string> <string name="book_library">Library</string>
<string name="book_local">Import Books</string> <string name="book_local">Import books</string>
<string name="book_source">Book Sources</string> <string name="book_source">Book sources</string>
<string name="book_source_manage">Sources management</string> <string name="book_source_manage">Sources management</string>
<string name="book_source_manage_desc">Create/Import/Edit/Manage Book sources</string> <string name="book_source_manage_desc">Create/Import/Edit/Manage Book sources</string>
<string name="setting">Settings</string> <string name="setting">Settings</string>
@ -76,17 +76,17 @@
<string name="read_dur_progress">Origin: %s</string> <string name="read_dur_progress">Origin: %s</string>
<string name="book_name">Title</string> <string name="book_name">Title</string>
<string name="lasted_show">Latest: %s</string> <string name="lasted_show">Latest: %s</string>
<string name="check_add_bookshelf">Would you like to put %s on the bookshelf?</string> <string name="check_add_bookshelf">Would you like to add %s to your Bookshelf?</string>
<string name="import_books_count">%s text files in total</string> <string name="import_books_count">%s text file(s) in total</string>
<string name="is_loading">Loading…</string> <string name="is_loading">Loading…</string>
<string name="retry">Retry</string> <string name="retry">Retry</string>
<string name="web_service">Web service</string> <string name="web_service">Web service</string>
<string name="web_service_desc">Enable web service</string> <string name="web_service_desc">Enable web service</string>
<string name="web_edit_source">web editing book sources</string> <string name="web_edit_source">Edit book sources on the web</string>
<string name="http_ip">http://%1$s:%2$d</string> <string name="http_ip">http://%1$s:%2$d</string>
<string name="download_offline">Offline download</string> <string name="download_offline">Offline download</string>
<string name="download_offline_t">Offline download</string> <string name="download_offline_t">Offline download</string>
<string name="download_offline_s">Download the selected chapter to Storage</string> <string name="download_offline_s">Download the selected chapter(s) to Storage</string>
<string name="change_origin">Change Origin</string> <string name="change_origin">Change Origin</string>
<string name="about_description"> <string name="about_description">
\u3000\u3000 This is an open source reading software newly developed by Kotlin, welcome to join us. Follow the WeChat Official Account [开源阅读]! \u3000\u3000 This is an open source reading software newly developed by Kotlin, welcome to join us. Follow the WeChat Official Account [开源阅读]!
@ -101,7 +101,7 @@
<string name="ps_auto_download">Download the latest chapters automatically when updating books</string> <string name="ps_auto_download">Download the latest chapters automatically when updating books</string>
<string name="backup_restore">Backup and restore</string> <string name="backup_restore">Backup and restore</string>
<string name="web_dav_set">WebDav settings</string> <string name="web_dav_set">WebDav settings</string>
<string name="web_dav_set_import_old">WebDav settings/import legacy data</string> <string name="web_dav_set_import_old">WebDav settings/Import legacy data</string>
<string name="backup">Backup</string> <string name="backup">Backup</string>
<string name="restore">Restore</string> <string name="restore">Restore</string>
<string name="backup_permission">Backup needs storage permission</string> <string name="backup_permission">Backup needs storage permission</string>
@ -145,7 +145,7 @@
<string name="pause">Pause</string> <string name="pause">Pause</string>
<string name="resume">Resume</string> <string name="resume">Resume</string>
<string name="set_timer">Timer</string> <string name="set_timer">Timer</string>
<string name="read_aloud_pause">Speaking Pause</string> <string name="read_aloud_pause">Speak Paused</string>
<string name="read_aloud_timer">Speaking(%d min left)</string> <string name="read_aloud_timer">Speaking(%d min left)</string>
<string name="ps_hide_navigation_bar">Hide virtual buttons when reading</string> <string name="ps_hide_navigation_bar">Hide virtual buttons when reading</string>
<string name="pt_hide_navigation_bar">Hide navigation bar</string> <string name="pt_hide_navigation_bar">Hide navigation bar</string>
@ -161,24 +161,24 @@
<string name="background">Background</string> <string name="background">Background</string>
<string name="author">Author</string> <string name="author">Author</string>
<string name="author_show">Author: %s</string> <string name="author_show">Author: %s</string>
<string name="aloud_stop">Pause</string> <string name="aloud_stop">Speak Stopped</string>
<string name="clear_cache">Clear cache</string> <string name="clear_cache">Clear cache</string>
<string name="clear_cache_success">Cache cleared</string> <string name="clear_cache_success">Cache cleared</string>
<string name="action_save">Save</string> <string name="action_save">Save</string>
<string name="edit_source">Edit source</string> <string name="edit_source">Edit source</string>
<string name="edit_book_source">Edit Book Sources</string> <string name="edit_book_source">Edit Book source</string>
<string name="disable_book_source">Disable Book Source</string> <string name="disable_book_source">Disable Book source</string>
<string name="add_book_source">Add Book Source</string> <string name="add_book_source">Add Book source</string>
<string name="add_rss_source">Add subscription source</string> <string name="add_rss_source">Add subscription source</string>
<string name="book_file_selector">Add books</string> <string name="book_file_selector">Add books</string>
<string name="scan_book_source">Scan</string> <string name="scan_book_source">Scan</string>
<string name="copy_source">Copy source</string> <string name="copy_source">Copy source</string>
<string name="paste_source">Paste source</string> <string name="paste_source">Paste source</string>
<string name="source_rule_s">Source rule description</string> <string name="source_rule_s">Source rules description</string>
<string name="check_update">Check for Updates</string> <string name="check_update">Check for Updates</string>
<string name="camera_scan">Scan QR code</string> <string name="camera_scan">Scan QR code</string>
<string name="scan_image">Scan local images</string> <string name="scan_image">Scan local images</string>
<string name="rule_summary">Rule description</string> <string name="rule_summary">Rules description</string>
<string name="share">Share</string> <string name="share">Share</string>
<string name="share_app">Share to</string> <string name="share_app">Share to</string>
<string name="flow_sys">Follow system</string> <string name="flow_sys">Follow system</string>
@ -187,7 +187,7 @@
<string name="import_book_source_local">Import local sources</string> <string name="import_book_source_local">Import local sources</string>
<string name="import_book_source_on_line">Import online sources</string> <string name="import_book_source_on_line">Import online sources</string>
<string name="replace_rule_title">Replacement</string> <string name="replace_rule_title">Replacement</string>
<string name="replace_rule_edit">Edit replacement rules</string> <string name="replace_rule_edit">Edit replacement rule</string>
<string name="replace_rule">Pattern</string> <string name="replace_rule">Pattern</string>
<string name="replace_to">Replacement</string> <string name="replace_to">Replacement</string>
<string name="img_cover">Cover</string> <string name="img_cover">Cover</string>
@ -204,7 +204,7 @@
<string name="clear_all_content">Clearing the cache will delete all saved chapters. Are you sure to delete it?</string> <string name="clear_all_content">Clearing the cache will delete all saved chapters. Are you sure to delete it?</string>
<string name="book_source_share_url">Book sources sharing</string> <string name="book_source_share_url">Book sources sharing</string>
<string name="replace_rule_summary">Rule name</string> <string name="replace_rule_summary">Rule name</string>
<string name="replace_rule_invalid">Pattern rule is empty or does not meet regular expression requirements</string> <string name="replace_rule_invalid">Pattern rule is empty or does not conform the regex specification.</string>
<string name="select_action">Selection action</string> <string name="select_action">Selection action</string>
<string name="select_all">Select all</string> <string name="select_all">Select all</string>
<string name="select_all_count">Select all(%1$d/%2$d)</string> <string name="select_all_count">Select all(%1$d/%2$d)</string>
@ -240,7 +240,7 @@
<string name="clear_font">Default font</string> <string name="clear_font">Default font</string>
<string name="find_on_www">Discovery</string> <string name="find_on_www">Discovery</string>
<string name="find_source_manage">Discovery</string> <string name="find_source_manage">Discovery</string>
<string name="find_empty">No content.Go to Sources Management to add it!</string> <string name="find_empty">No content.Go to Sources management to add it!</string>
<string name="del_all">Delete all</string> <string name="del_all">Delete all</string>
<string name="searchHistory">Search history</string> <string name="searchHistory">Search history</string>
<string name="clear">Clear</string> <string name="clear">Clear</string>
@ -268,8 +268,8 @@
<string name="load_over_time">Loading timeout</string> <string name="load_over_time">Loading timeout</string>
<string name="join_group">Follow:%s</string> <string name="join_group">Follow:%s</string>
<string name="copy_complete">Copied successfully</string> <string name="copy_complete">Copied successfully</string>
<string name="arrange_bookshelf">Bookshelf Arrangement</string> <string name="arrange_bookshelf">Bookshelf arrangement</string>
<string name="clear_bookshelf_s">it will delete all books. Be careful,please.</string> <string name="clear_bookshelf_s">It will delete all books. Be careful,please.</string>
<string name="search_book_source">Search book sources</string> <string name="search_book_source">Search book sources</string>
<string name="search_rss_source">Search subscription sources</string> <string name="search_rss_source">Search subscription sources</string>
<string name="search_book_source_num">Search( %d sources in total)</string> <string name="search_book_source_num">Search( %d sources in total)</string>
@ -317,11 +317,11 @@
<string name="auto_next_page">Auto scroll</string> <string name="auto_next_page">Auto scroll</string>
<string name="auto_next_page_stop">Stop Auto scroll</string> <string name="auto_next_page_stop">Stop Auto scroll</string>
<string name="auto_next_page_speed">Auto scroll speed</string> <string name="auto_next_page_speed">Auto scroll speed</string>
<string name="book_info">Book info</string> <string name="book_info">Book infomation</string>
<string name="book_info_edit">Edit book info</string> <string name="book_info_edit">Edit book infomation</string>
<string name="ps_default_read">Use Bookshelf as start page</string> <string name="ps_default_read">Use Bookshelf as start page</string>
<string name="pt_default_read">Auto jump to Recent list</string> <string name="pt_default_read">Auto jump to Recent list</string>
<string name="use_to">Replacement object, book name or source name is available</string> <string name="use_to">Replacement object. Book name or source name is available</string>
<string name="menu_action_group">Groups</string> <string name="menu_action_group">Groups</string>
<string name="download_path">Cache path</string> <string name="download_path">Cache path</string>
<string name="cleanCache">Clear cache</string> <string name="cleanCache">Clear cache</string>
@ -330,11 +330,11 @@
<string name="download_update">Download updates</string> <string name="download_update">Download updates</string>
<string name="volume_key_page_on_play">Volume keys to turn page when reading</string> <string name="volume_key_page_on_play">Volume keys to turn page when reading</string>
<string name="tip_margin_change">Margin adjustment</string> <string name="tip_margin_change">Margin adjustment</string>
<string name="allow_update">Allow update</string> <string name="allow_update">Enable update</string>
<string name="disable_update">Disable update</string> <string name="disable_update">Disable update</string>
<string name="revert_selection">Inverse</string> <string name="revert_selection">Inverse</string>
<string name="search_book_key">Search bookName/author</string> <string name="search_book_key">Search book name/author</string>
<string name="debug_hint">BookName,Author,URL</string> <string name="debug_hint">Book name,Author,URL</string>
<string name="faq">FAQ</string> <string name="faq">FAQ</string>
<string name="pt_show_all_find">Display all Discovery</string> <string name="pt_show_all_find">Display all Discovery</string>
<string name="ps_show_all_find">Display the selected origin\'s Discovery if closed</string> <string name="ps_show_all_find">Display the selected origin\'s Discovery if closed</string>
@ -410,6 +410,8 @@
<string name="rule_next_content">正文下一页URL规则(nextContentUrl)</string> <string name="rule_next_content">正文下一页URL规则(nextContentUrl)</string>
<string name="rule_web_js">webJs</string> <string name="rule_web_js">webJs</string>
<string name="rule_source_regex">资源正则(sourceRegex)</string> <string name="rule_source_regex">资源正则(sourceRegex)</string>
<string name="rule_replace_regex">替换规则(replaceRegex)</string>
<string name="rule_image_style">图片样式(imageStyle)</string>
<string name="source_icon">图标(sourceIcon)</string> <string name="source_icon">图标(sourceIcon)</string>
<string name="r_articles">列表规则(ruleArticles)</string> <string name="r_articles">列表规则(ruleArticles)</string>
@ -554,7 +556,7 @@
<string name="group_select">Group selection</string> <string name="group_select">Group selection</string>
<string name="group_edit">Group editing</string> <string name="group_edit">Group editing</string>
<string name="move_to_group">Move to group</string> <string name="move_to_group">Move to group</string>
<string name="add_group">Add to group</string> <string name="add_group">Add to Groups</string>
<string name="add_replace_rule">New replacement</string> <string name="add_replace_rule">New replacement</string>
<string name="group">Group</string> <string name="group">Group</string>
<string name="group_s">Group: %s</string> <string name="group_s">Group: %s</string>
@ -574,7 +576,7 @@
<string name="web_dav_account">WebDav account</string> <string name="web_dav_account">WebDav account</string>
<string name="web_dav_account_s">Input your WebDav account</string> <string name="web_dav_account_s">Input your WebDav account</string>
<string name="rss_source">Subscription source</string> <string name="rss_source">Subscription source</string>
<string name="rss_source_edit">Subscription source editing</string> <string name="rss_source_edit">Edit Subscription source</string>
<string name="screen">Filter</string> <string name="screen">Filter</string>
<string name="screen_find">Search Discovery sources</string> <string name="screen_find">Search Discovery sources</string>
<string name="dur_pos">Current location:</string> <string name="dur_pos">Current location:</string>
@ -722,8 +724,10 @@
<string name="contributors_summary">gedoor,Invinciblelee etc. Checking in github for details</string> <string name="contributors_summary">gedoor,Invinciblelee etc. Checking in github for details</string>
<string name="clear_cache_summary">Clear the cache of the downloaded books and fonts</string> <string name="clear_cache_summary">Clear the cache of the downloaded books and fonts</string>
<string name="default_cover">Default cover</string> <string name="default_cover">Default cover</string>
<string name="restore_ignore">恢复忽略列表</string> <string name="restore_ignore">Bypass list</string>
<string name="restore_ignore_summary">恢复时忽略一些内容不恢复,方便不同手机配置不同</string> <string name="restore_ignore_summary">Ignore some contents while restoring</string>
<string name="read_config">阅读界面设置</string> <string name="read_config">Reading interface settings</string>
<string name="group_name">Group name</string>
<string name="note_content">Remarks section</string>
</resources> </resources>
Loading…
Cancel
Save