pull/149/head
yangyxd 5 years ago
commit fb72f0b437
  1. 1
      app/src/main/AndroidManifest.xml
  2. 68
      app/src/main/assets/txtTocRule.json
  3. 5
      app/src/main/assets/updateLog.md
  4. 1
      app/src/main/java/io/legado/app/constant/PreferKey.kt
  5. 5
      app/src/main/java/io/legado/app/help/AppConfig.kt
  6. 8
      app/src/main/java/io/legado/app/help/BookHelp.kt
  7. 14
      app/src/main/java/io/legado/app/model/localBook/LocalBook.kt
  8. 4
      app/src/main/java/io/legado/app/service/TTSReadAloudService.kt
  9. 13
      app/src/main/java/io/legado/app/ui/book/read/Help.kt
  10. 45
      app/src/main/java/io/legado/app/ui/book/read/ReadBookActivity.kt
  11. 7
      app/src/main/java/io/legado/app/ui/book/read/TextActionMenu.kt
  12. 5
      app/src/main/java/io/legado/app/ui/book/read/config/MoreConfigDialog.kt
  13. 53
      app/src/main/java/io/legado/app/ui/book/read/page/ContentTextView.kt
  14. 16
      app/src/main/java/io/legado/app/ui/book/read/page/PageView.kt
  15. 7
      app/src/main/java/io/legado/app/ui/book/read/page/delegate/PageDelegate.kt
  16. 16
      app/src/main/java/io/legado/app/ui/config/OtherConfigFragment.kt
  17. 2
      app/src/main/java/io/legado/app/ui/welcome/WelcomeActivity.kt
  18. 8
      app/src/main/java/io/legado/app/ui/widget/TitleBar.kt
  19. 7
      app/src/main/java/io/legado/app/utils/ContextExtensions.kt
  20. 6
      app/src/main/res/layout/activity_book_read.xml
  21. 2
      app/src/main/res/layout/popup_action_menu.xml
  22. 6
      app/src/main/res/values/array_values.xml
  23. 2
      app/src/main/res/values/arrays.xml
  24. 2
      app/src/main/res/values/pref_key_value.xml
  25. 1
      app/src/main/res/values/strings.xml
  26. 8
      app/src/main/res/xml/pref_config_read.xml

@ -185,6 +185,7 @@
android:launchMode="singleTop" />
<activity
android:name="io.legado.app.ui.book.chapterlist.ChapterListActivity"
android:screenOrientation="behind"
android:launchMode="singleTop" />
<!--RSS阅读-->
<activity

@ -2,73 +2,97 @@
{
"enable": true,
"name": "目录",
"rule": "^[  \\t]{0,4}(?:(?:内容|文章)?简介|文案|前言|序章|楔子|正文(?!完)|终章|后记|尾声|番外|第?\\s{0,4}[\\d零一二两三四五六七八九十百千万壹贰叁肆伍陆柒捌玖拾佰仟]+?\\s{0,4}(?:章|节(?!课)|卷|集(?![合和])|部(?!分)|篇(?!张))).{0,30}$",
"rule": "^[  \\t]{0,4}(?:(?:内容|文章)?简介|文案|前言|序章|楔子|正文(?!完|结)|终章|后记|尾声|番外|第?\\s{0,4}[\\d零一二两三四五六七八九十百千万壹贰叁肆伍陆柒捌玖拾佰仟]+?\\s{0,4}(?:章|节(?!课)|卷|集(?![合和])|部(?!分)|篇(?!张))).{0,30}$",
"serialNumber": 0
},
{
"enable": false,
"name": "目录(不匹配行前空白)",
"rule": "^(?<= |\\s)(?:(?:内容|文章)?简介|文案|前言|序章|楔子|正文(?!完)|终章|后记|尾声|番外|第?\\s{0,4}[\\d零一二两三四五六七八九十百千万壹贰叁肆伍陆柒捌玖拾佰仟]+?\\s{0,4}(?:章|节(?!课)|卷|集(?![合和])|部(?!分)|篇(?!张))).{0,30}$",
"name": "目录(空白)",
"rule": "(?<=[ \\s])(?:(?:内容|文章)?简介|文案|前言|序章|楔子|正文(?!完|结)|终章|后记|尾声|番外|第?\\s{0,4}[\\d零一二两三四五六七八九十百千万壹贰叁肆伍陆柒捌玖拾佰仟]+?\\s{0,4}(?:章|节(?!课)|卷|集(?![合和])|部(?!分)|篇(?!张))).{0,30}$",
"serialNumber": 1
},
{
"enable": false,
"name": "目录(去简介)",
"rule": "^(?<= |\\s)(?:前言|序章|楔子|正文(?!完)|终章|后记|尾声|番外|第?\\s{0,4}[\\d零一二两三四五六七八九十百千万壹贰叁肆伍陆柒捌玖拾佰仟]+?\\s{0,4}(?:章|节(?!课)|卷|集(?![合和])|部(?!分)|回(?![合来事去])|场(?![和合比电是])|篇(?!张))).{0,30}$",
"rule": "(?<=[ \\s])(?:前言|序章|楔子|正文(?!完|结)|终章|后记|尾声|番外|第?\\s{0,4}[\\d零一二两三四五六七八九十百千万壹贰叁肆伍陆柒捌玖拾佰仟]+?\\s{0,4}(?:章|节(?!课)|卷|集(?![合和])|部(?!分)|回(?![合来事去])|场(?![和合比电是])|篇(?!张))).{0,30}$",
"serialNumber": 2
},
{
"enable": false,
"name": "目录(古典、轻小说备用)",
"rule": "^[  \\t]{0,4}(?:前言|序章|楔子|正文(?!完)|终章|后记|尾声|番外|第?\\s{0,4}[\\d零一二两三四五六七八九十百千万壹贰叁肆伍陆柒捌玖拾佰仟]+?\\s{0,4}(?:章|节(?!课)|卷|集(?![合和])|部(?!分)|回(?![合来事去])|场(?![和合比电是])|篇(?!张))).{0,30}$",
"rule": "^[  \\t]{0,4}(?:前言|序章|楔子|正文(?!完|结)|终章|后记|尾声|番外|第?\\s{0,4}[\\d零一二两三四五六七八九十百千万壹贰叁肆伍陆柒捌玖拾佰仟]+?\\s{0,4}(?:章|节(?!课)|卷|集(?![合和])|部(?!分)|回(?![合来事去])|场(?![和合比电是])|篇(?!张))).{0,30}$",
"serialNumber": 3
},
{
"enable": false,
"name": "数字(纯数字标题)",
"rule": "(?<=[ \\s])\\d+[  \\t]{0,4}$",
"serialNumber": 4
},
{
"enable": true,
"name": "数字 分隔符 标题名称",
"rule": "^[  \\t]{0,4}\\d{1,5}[\\,\\., 、\\-].{1,30}$",
"serialNumber": 4
"serialNumber": 5
},
{
"enable": true,
"name": "正文 标题/序号",
"rule": "^[  \\t]{0,4}正文\\s{1,4}.{0,20}$",
"serialNumber": 5
"rule": "^[  \\t]{0,4}正文[  ]{1,4}.{0,20}$",
"serialNumber": 6
},
{
"enable": true,
"name": "Chapter/Section/Part/Episode 序号 标题",
"rule": "^[  \\t]{0,4}(?:[Cc]hapter|[Ss]ection|[Pp]art|PART|[Ee]pisode|(?:内容|文章)?简介|文案|前言|序章|楔子|正文(?!完|结)|终章|后记|尾声|番外)\\s{0,4}\\d{1,4}.{0,30}$",
"serialNumber": 7
},
{
"enable": false,
"name": "Chapter(去简介)",
"rule": "^[  \\t]{0,4}(?:[Cc]hapter|[Ss]ection|[Pp]art|PART|[Ee]pisode)\\s{0,4}\\d{1,4}.{0,30}$",
"serialNumber": 6
"serialNumber": 8
},
{
"enable": true,
"name": "特殊符号 序号 标题",
"rule": "^[  \\t]{0,4}[〈〖〔【][第卷][\\d零一二两三四五六七八九十百千万壹贰叁肆伍陆柒捌玖拾佰仟]{1,10}[章节][\\.:: \f\t].{0,30}$",
"serialNumber": 7
"rule": "(?<=[\\s ]{0,4}).{1,3}(?:第|卷|[Cc]hapter)[\\d零一二两三四五六七八九十百千万壹贰叁肆伍陆柒捌玖拾佰仟]{1,10}[章节]?[\\.:: \f\t].{0,20}$",
"serialNumber": 9
},
{
"enable": true,
"name": "特殊符号 标题",
"rule": "^[  \\t]{0,4}[\\[〈「『〖〔《(【\\(☆★].{1,30}[\\)】)》〕〗』」〉\\]]?\\s{0,4}$",
"serialNumber": 8
"enable": false,
"name": "特殊符号 标题(成对)",
"rule": "(?<=[\\s ]{0,4})(?:[\\[〈「『〖〔《(【\\(].{1,30}[\\)】)》〕〗』」〉\\]]?|(?:内容|文章)?简介|文案|前言|序章|楔子|正文(?!完|结)|终章|后记|尾声|番外)[  ]{0,4}$",
"serialNumber": 10
},
{
"enable":false,
"name": "特殊符号 标题(不匹配空白字符)",
"rule": "^(?<= |\\s)[\\[〈「『〖〔《(【\\(☆★].{1,30}[\\)】)》〕〗』」〉\\]]?\\s{0,4}$",
"serialNumber": 9
"enable":true,
"name": "特殊符号 标题(单个)",
"rule": "(?<=[\\s ]{0,4})(?:[☆★✦✧].{1,30}|(?:内容|文章)?简介|文案|前言|序章|楔子|正文(?!完|结)|终章|后记|尾声|番外)[  ]{0,4}$",
"serialNumber": 11
},
{
"enable": true,
"name": "章/卷 序号 标题",
"rule": "^[  \\t]{0,4}(?:(?:内容|文章)?简介|文案|前言|序章|楔子|正文(?!完)|终章|后记|尾声|番外|[卷章][\\d零一二两三四五六七八九十百千万壹贰叁肆伍陆柒捌玖拾佰仟]{1,8})\\s{0,4}.{0,30}$",
"serialNumber": 10
"rule": "^[ \\t ]{0,4}(?:(?:内容|文章)?简介|文案|前言|序章|楔子|正文(?!完|结)|终章|后记|尾声|番外|[卷章][\\d零一二两三四五六七八九十百千万壹贰叁肆伍陆柒捌玖拾佰仟]{1,8})[  ]{0,4}.{0,30}$",
"serialNumber": 12
},
{
"enable":false,
"name": "顶格标题",
"rule": "^\\S.{1,20}$",
"serialNumber": 11
"serialNumber": 13
},
{
"enable":false,
"name": "双标题(前向)",
"rule": "(?m)(?<=[ \\t ]{0,4})第[\\d零一二两三四五六七八九十百千万壹贰叁肆伍陆柒捌玖拾佰仟]{1,8}章.{0,30}$(?=[\\s ]{0,8}第[\\d零一二两三四五六七八九十百千万壹贰叁肆伍陆柒捌玖拾佰仟]{1,8}章)",
"serialNumber": 14
},
{
"enable":false,
"name": "双标题(后向)",
"rule": "(?m)(?<=[ \\t ]{0,4}第[\\d零一二两三四五六七八九十百千万壹贰叁肆伍陆柒捌玖拾佰仟]{1,8}章.{0,30}$[\\s ]{0,8})第[\\d零一二两三四五六七八九十百千万壹贰叁肆伍陆柒捌玖拾佰仟]{1,8}章.{0,30}$",
"serialNumber": 15
}
]

@ -2,8 +2,13 @@
* 旧版数据导入教程:先在旧版阅读(2.x)中进行备份,然后在新版阅读(3.x)【我的】->【备份与恢复】,选择【导入旧版本数据】。
* 请关注[开源阅读软件]()支持我,同时关注合作公众号[小说拾遗](),阅读公众号小编。
**2020/03/10**
* 优化文字选择菜单弹出位置
* 添加屏幕方向控制
**2020/03/09**
* 底部文字对齐
* 主题添加阴影调节 by yangyxd
**2020/03/08**
* 订阅长按保存图片

@ -3,7 +3,6 @@ package io.legado.app.constant
object PreferKey {
const val versionCode = "versionCode"
const val themeMode = "themeMode"
const val downloadPath = "downloadPath"
const val hideStatusBar = "hideStatusBar"
const val clickTurnPage = "clickTurnPage"
const val clickAllNext = "clickAllNext"

@ -32,6 +32,9 @@ object AppConfig {
App.INSTANCE.putPrefBoolean("transparentStatusBar", value)
}
val requestedDirection: String?
get() = App.INSTANCE.getPrefString(R.string.pk_requested_direction)
var backupPath: String?
get() = App.INSTANCE.getPrefString(PreferKey.backupPath)
set(value) {
@ -49,7 +52,7 @@ object AppConfig {
}
val autoRefreshBook: Boolean
get() = App.INSTANCE.getPrefBoolean(App.INSTANCE.getString(R.string.pk_auto_refresh))
get() = App.INSTANCE.getPrefBoolean(R.string.pk_auto_refresh)
var threadCount: Int
get() = App.INSTANCE.getPrefInt(PreferKey.threadCount, 16)

@ -4,8 +4,8 @@ import android.net.Uri
import androidx.documentfile.provider.DocumentFile
import com.github.houbb.opencc4j.core.impl.ZhConvertBootstrap
import io.legado.app.App
import io.legado.app.R
import io.legado.app.constant.EventBus
import io.legado.app.constant.PreferKey
import io.legado.app.data.entities.Book
import io.legado.app.data.entities.BookChapter
import io.legado.app.data.entities.ReplaceRule
@ -21,7 +21,7 @@ import kotlin.math.min
object BookHelp {
private const val cacheFolderName = "book_cache"
val downloadPath: String
get() = App.INSTANCE.getPrefString(PreferKey.downloadPath)
get() = App.INSTANCE.getPrefString(R.string.pk_download_path)
?: App.INSTANCE.getExternalFilesDir(null)?.absolutePath
?: App.INSTANCE.cacheDir.absolutePath
@ -300,6 +300,8 @@ object BookHelp {
1 -> c = ZhConvertBootstrap.newInstance().toSimple(c)
2 -> c = ZhConvertBootstrap.newInstance().toTraditional(c)
}
return c.replace("\\s*\\n+\\s*".toRegex(), "\n${ReadBookConfig.bodyIndent}")
return c
.replace("\\s*\\n+\\s*".toRegex(), "\n${ReadBookConfig.bodyIndent}")
.replace("[\\n\\s]+$".toRegex(), "") //移除尾部空行
}
}

@ -4,6 +4,7 @@ import android.net.Uri
import androidx.documentfile.provider.DocumentFile
import io.legado.app.App
import io.legado.app.data.entities.Book
import io.legado.app.help.BookHelp
import io.legado.app.utils.FileUtils
@ -12,8 +13,17 @@ object LocalBook {
fun importFile(doc: DocumentFile) {
doc.name?.let { fileName ->
val str = fileName.substringBeforeLast(".")
var name = str.substringBefore("作者")
val author = str.substringAfter("作者", "")
val authorIndex = str.indexOf("作者")
var name: String
var author: String
if (authorIndex == -1) {
name = str
author = ""
} else {
name = str.substring(0, authorIndex)
author = str.substring(authorIndex)
author = BookHelp.formatAuthor(author)
}
val smhStart = name.indexOf("")
val smhEnd = name.indexOf("")
if (smhStart != -1 && smhEnd != -1) {

@ -175,9 +175,7 @@ class TTSReadAloudService : BaseReadAloudService(), TextToSpeech.OnInitListener
}
override fun onError(s: String) {
launch {
toast(s)
}
pauseReadAloud(true)
}
}

@ -3,6 +3,7 @@ package io.legado.app.ui.book.read
import android.annotation.SuppressLint
import android.app.Activity
import android.content.Context
import android.content.pm.ActivityInfo
import android.os.AsyncTask
import android.os.Build
import android.view.*
@ -62,6 +63,18 @@ object Help {
}
}
@SuppressLint("SourceLockedOrientationActivity")
fun setOrientation(activity: Activity) = activity.apply {
when (AppConfig.requestedDirection) {
"0" -> requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED
"1" -> requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
"2" -> requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE
"3" -> requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_SENSOR
}
}
/**
* 返回NavigationBar是否存在
* 该方法需要在View完全被绘制出来之后调用否则判断不了

@ -3,6 +3,7 @@ package io.legado.app.ui.book.read
import android.annotation.SuppressLint
import android.app.Activity
import android.content.Intent
import android.content.res.Configuration
import android.net.Uri
import android.os.Bundle
import android.os.Handler
@ -13,6 +14,7 @@ import androidx.core.view.isVisible
import androidx.core.view.size
import androidx.lifecycle.Observer
import com.jaredrummler.android.colorpicker.ColorPickerDialogListener
import io.legado.app.BuildConfig
import io.legado.app.R
import io.legado.app.base.VMBaseActivity
import io.legado.app.constant.EventBus
@ -88,6 +90,11 @@ class ReadBookActivity : VMBaseActivity<ReadBookViewModel>(R.layout.activity_boo
override val pageFactory: TextPageFactory get() = page_view.pageFactory
override val headerHeight: Int get() = page_view.curPage.headerHeight
override fun onCreate(savedInstanceState: Bundle?) {
Help.setOrientation(this)
super.onCreate(savedInstanceState)
}
override fun onActivityCreated(savedInstanceState: Bundle?) {
Help.upLayoutInDisplayCutoutMode(window)
initView()
@ -106,6 +113,11 @@ class ReadBookActivity : VMBaseActivity<ReadBookViewModel>(R.layout.activity_boo
upSystemUiVisibility()
}
override fun onConfigurationChanged(newConfig: Configuration) {
super.onConfigurationChanged(newConfig)
ReadBook.loadContent()
}
override fun onResume() {
super.onResume()
upSystemUiVisibility()
@ -338,7 +350,8 @@ class ReadBookActivity : VMBaseActivity<ReadBookViewModel>(R.layout.activity_boo
@SuppressLint("ClickableViewAccessibility")
override fun onTouch(v: View, event: MotionEvent): Boolean {
when (event.action) {
MotionEvent.ACTION_MOVE, MotionEvent.ACTION_UP -> {
MotionEvent.ACTION_DOWN -> textActionMenu?.dismiss()
MotionEvent.ACTION_MOVE -> {
when (v.id) {
R.id.cursor_left -> page_view.curPage.selectStartMove(
event.rawX + cursor_left.width,
@ -350,6 +363,7 @@ class ReadBookActivity : VMBaseActivity<ReadBookViewModel>(R.layout.activity_boo
)
}
}
MotionEvent.ACTION_UP -> showTextActionMenu()
}
return true
}
@ -357,11 +371,12 @@ class ReadBookActivity : VMBaseActivity<ReadBookViewModel>(R.layout.activity_boo
/**
* 更新文字选择开始位置
*/
override fun upSelectedStart(x: Float, y: Float) {
override fun upSelectedStart(x: Float, y: Float, top: Float) {
cursor_left.x = x - cursor_left.width
cursor_left.y = y
cursor_left.visible(true)
showTextActionMenu()
text_menu_position.x = x
text_menu_position.y = top
}
/**
@ -371,7 +386,6 @@ class ReadBookActivity : VMBaseActivity<ReadBookViewModel>(R.layout.activity_boo
cursor_right.x = x
cursor_right.y = y
cursor_right.visible(true)
showTextActionMenu()
}
/**
@ -386,19 +400,24 @@ class ReadBookActivity : VMBaseActivity<ReadBookViewModel>(R.layout.activity_boo
/**
* 显示文本操作菜单
*/
private fun showTextActionMenu() {
override fun showTextActionMenu() {
textActionMenu ?: let {
textActionMenu = TextActionMenu(this, this)
textActionMenu = TextActionMenu(this, this).apply {
contentView.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED)
}
val x = cursor_left.x.toInt() + cursor_left.width
val y = if (cursor_left.y - statusBarHeight > ReadBookConfig.textSize.dp * 1.5 + 20.dp) {
(page_view.height - cursor_left.y + ReadBookConfig.textSize.dp * 1.5).toInt()
} else {
(page_view.height - cursor_left.y - cursor_left.height - 40.dp).toInt()
}
textActionMenu?.let { popup ->
val popupHeight = popup.contentView.measuredHeight
val x = text_menu_position.x.toInt()
var y = text_menu_position.y.toInt() - popupHeight
if (y < statusBarHeight) {
y = (cursor_left.y + cursor_left.height).toInt()
}
if (cursor_right.y > y && cursor_right.y < y + popupHeight) {
y = (cursor_right.y + cursor_right.height).toInt()
}
if (!popup.isShowing) {
popup.showAtLocation(cursor_left, Gravity.BOTTOM or Gravity.START, x, y)
popup.showAtLocation(text_menu_position, Gravity.TOP or Gravity.START, x, y)
} else {
popup.update(x, y, WRAP_CONTENT, WRAP_CONTENT)
}
@ -663,8 +682,10 @@ class ReadBookActivity : VMBaseActivity<ReadBookViewModel>(R.layout.activity_boo
mHandler.removeCallbacks(keepScreenRunnable)
textActionMenu?.dismiss()
page_view.onDestroy()
if (!BuildConfig.DEBUG) {
SyncBookProgress.uploadBookProgress()
}
}
override fun observeLiveBus() {
super.observeLiveBus()

@ -151,9 +151,7 @@ class TextActionMenu(private val context: Context, private val callBack: CallBac
*/
@RequiresApi(Build.VERSION_CODES.M)
private fun onInitializeMenu(menu: Menu) {
// Start with a menu Item order value that is high enough
// so that your "PROCESS_TEXT" menu items appear after the
// standard selection menu items like Cut, Copy, Paste.
try {
var menuItemOrder = 100
for (resolveInfo in getSupportedActivities()) {
menu.add(
@ -161,6 +159,9 @@ class TextActionMenu(private val context: Context, private val callBack: CallBac
menuItemOrder++, resolveInfo.loadLabel(context.packageManager)
).intent = createProcessTextIntentForResolveInfo(resolveInfo)
}
} catch (e: Exception) {
context.toast("获取文字操作菜单出错:${e.localizedMessage}")
}
}
interface CallBack {

@ -104,6 +104,11 @@ class MoreConfigDialog : DialogFragment() {
}
PreferKey.keepLight -> postEvent(key, true)
PreferKey.textSelectAble -> postEvent(key, getPrefBoolean(key))
getString(R.string.pk_requested_direction) -> {
activity?.let {
Help.setOrientation(it)
}
}
}
}

@ -31,6 +31,7 @@ class ContentTextView(context: Context, attrs: AttributeSet?) : View(context, at
private val selectStart = arrayOf(0, 0, 0)
private val selectEnd = arrayOf(0, 0, 0)
private var textPage: TextPage = TextPage()
//滚动参数
private val pageFactory: TextPageFactory get() = callBack.pageFactory
private val maxScrollOffset = 100f
@ -210,7 +211,11 @@ class ContentTextView(context: Context, attrs: AttributeSet?) : View(context, at
selectEnd[0] = 0
selectEnd[1] = lineIndex
selectEnd[2] = charIndex
upSelectedStart(textChar.start, textLine.lineBottom + relativeOffset)
upSelectedStart(
textChar.start,
textLine.lineBottom + relativeOffset,
textLine.lineTop + relativeOffset
)
upSelectedEnd(textChar.end, textLine.lineBottom + relativeOffset)
select(0, lineIndex, charIndex)
return
@ -236,7 +241,11 @@ class ContentTextView(context: Context, attrs: AttributeSet?) : View(context, at
selectEnd[0] = 1
selectEnd[1] = lineIndex
selectEnd[2] = charIndex
upSelectedStart(textChar.start, textLine.lineBottom + relativeOffset)
upSelectedStart(
textChar.start,
textLine.lineBottom + relativeOffset,
textLine.lineTop + relativeOffset
)
upSelectedEnd(textChar.end, textLine.lineBottom + relativeOffset)
select(1, lineIndex, charIndex)
return
@ -259,7 +268,11 @@ class ContentTextView(context: Context, attrs: AttributeSet?) : View(context, at
selectEnd[0] = 2
selectEnd[1] = lineIndex
selectEnd[2] = charIndex
upSelectedStart(textChar.start, textLine.lineBottom + relativeOffset)
upSelectedStart(
textChar.start,
textLine.lineBottom + relativeOffset,
textLine.lineTop + relativeOffset
)
upSelectedEnd(textChar.end, textLine.lineBottom + relativeOffset)
select(2, lineIndex, charIndex)
return
@ -287,7 +300,11 @@ class ContentTextView(context: Context, attrs: AttributeSet?) : View(context, at
selectStart[0] = 0
selectStart[1] = lineIndex
selectStart[2] = charIndex
upSelectedStart(textChar.start, textLine.lineBottom + relativeOffset)
upSelectedStart(
textChar.start,
textLine.lineBottom + relativeOffset,
textLine.lineTop + relativeOffset
)
upSelectChars()
}
return
@ -311,7 +328,11 @@ class ContentTextView(context: Context, attrs: AttributeSet?) : View(context, at
selectStart[0] = 1
selectStart[1] = lineIndex
selectStart[2] = charIndex
upSelectedStart(textChar.start, textLine.lineBottom + relativeOffset)
upSelectedStart(
textChar.start,
textLine.lineBottom + relativeOffset,
textLine.lineTop + relativeOffset
)
upSelectChars()
}
return
@ -333,7 +354,11 @@ class ContentTextView(context: Context, attrs: AttributeSet?) : View(context, at
selectStart[0] = 2
selectStart[1] = lineIndex
selectStart[2] = charIndex
upSelectedStart(textChar.start, textLine.lineBottom + relativeOffset)
upSelectedStart(
textChar.start,
textLine.lineBottom + relativeOffset,
textLine.lineTop + relativeOffset
)
upSelectChars()
}
return
@ -427,7 +452,11 @@ class ContentTextView(context: Context, attrs: AttributeSet?) : View(context, at
selectStart[2] = charIndex
val textLine = relativePage(relativePage).textLines[lineIndex]
val textChar = textLine.textChars[charIndex]
upSelectedStart(textChar.start, textLine.lineBottom + relativeOffset(relativePage))
upSelectedStart(
textChar.start,
textLine.lineBottom + relativeOffset(relativePage),
textLine.lineTop
)
upSelectChars()
}
@ -475,12 +504,12 @@ class ContentTextView(context: Context, attrs: AttributeSet?) : View(context, at
invalidate()
}
private fun upSelectedStart(x: Float, y: Float) {
callBack.upSelectedStart(x, y + callBack.headerHeight)
private fun upSelectedStart(x: Float, y: Float, top: Float) = callBack.apply {
upSelectedStart(x, y + headerHeight, top + headerHeight)
}
private fun upSelectedEnd(x: Float, y: Float) {
callBack.upSelectedEnd(x, y + callBack.headerHeight)
private fun upSelectedEnd(x: Float, y: Float) = callBack.apply {
upSelectedEnd(x, y + headerHeight)
}
fun cancelSelect() {
@ -580,7 +609,7 @@ class ContentTextView(context: Context, attrs: AttributeSet?) : View(context, at
}
interface CallBack {
fun upSelectedStart(x: Float, y: Float)
fun upSelectedStart(x: Float, y: Float, top: Float)
fun upSelectedEnd(x: Float, y: Float)
fun onCancelSelect()
val headerHeight: Int

@ -16,25 +16,20 @@ class PageView(context: Context, attrs: AttributeSet) :
FrameLayout(context, attrs),
DataSource {
var callBack: CallBack
var pageFactory: TextPageFactory
val callBack: CallBack get() = activity as CallBack
var pageFactory: TextPageFactory = TextPageFactory(this)
var pageDelegate: PageDelegate? = null
var prevPage: ContentView
var curPage: ContentView
var nextPage: ContentView
var prevPage: ContentView = ContentView(context)
var curPage: ContentView = ContentView(context)
var nextPage: ContentView = ContentView(context)
init {
callBack = activity as CallBack
nextPage = ContentView(context)
addView(nextPage)
curPage = ContentView(context)
addView(curPage)
prevPage = ContentView(context)
addView(prevPage)
upBg()
setWillNotDraw(false)
pageFactory = TextPageFactory(this)
upPageAnim()
}
@ -170,5 +165,6 @@ class PageView(context: Context, attrs: AttributeSet) :
val isInitFinish: Boolean
fun clickCenter()
fun screenOffTimerStart()
fun showTextActionMenu()
}
}

@ -200,7 +200,11 @@ abstract class PageDelegate(protected val pageView: PageView) :
//GestureDetector.onFling小幅移动不会触发,所以要自己判断
when (event.action) {
MotionEvent.ACTION_UP,
MotionEvent.ACTION_CANCEL -> if (isMoved) {
MotionEvent.ACTION_CANCEL -> {
if (isTextSelected) {
pageView.callBack.showTextActionMenu()
}
if (isMoved) {
if (selectedOnDown) {
selectedOnDown = false
}
@ -209,6 +213,7 @@ abstract class PageDelegate(protected val pageView: PageView) :
}
}
}
}
/**
* 按下

@ -40,7 +40,7 @@ class OtherConfigFragment : PreferenceFragmentCompat(),
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
putPrefBoolean(PreferKey.processText, isProcessTextEnabled())
addPreferencesFromResource(R.xml.pref_config_other)
upPreferenceSummary(PreferKey.downloadPath, BookHelp.downloadPath)
upPreferenceSummary(getString(R.string.pk_download_path), BookHelp.downloadPath)
upPreferenceSummary(PreferKey.threadCount, AppConfig.threadCount.toString())
upPreferenceSummary(PreferKey.webPort, webPort.toString())
}
@ -74,7 +74,7 @@ class OtherConfigFragment : PreferenceFragmentCompat(),
.show {
putPrefInt(PreferKey.webPort, it)
}
PreferKey.downloadPath -> selectDownloadPath()
getString(R.string.pk_download_path) -> selectDownloadPath()
PreferKey.cleanCache -> {
BookHelp.clearCache()
toast(R.string.clear_cache_success)
@ -85,7 +85,7 @@ class OtherConfigFragment : PreferenceFragmentCompat(),
override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences?, key: String?) {
when (key) {
PreferKey.downloadPath -> {
getString(R.string.pk_download_path) -> {
upPreferenceSummary(key, BookHelp.downloadPath)
}
PreferKey.threadCount -> upPreferenceSummary(
@ -141,13 +141,17 @@ class OtherConfigFragment : PreferenceFragmentCompat(),
private fun selectDownloadPath() {
FilePicker.selectFolder(this, requestCodeDownloadPath) {
removePref(PreferKey.downloadPath)
removePref(getString(R.string.pk_download_path))
}
}
private fun putDownloadPath(path: String) {
putPrefString(getString(R.string.pk_download_path), path)
}
override fun onFilePicked(requestCode: Int, currentPath: String) {
if (requestCode == requestCodeDownloadPath) {
putPrefString(PreferKey.downloadPath, currentPath)
putDownloadPath(currentPath)
}
}
@ -160,7 +164,7 @@ class OtherConfigFragment : PreferenceFragmentCompat(),
uri,
Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION
)
putPrefString(PreferKey.downloadPath, uri.toString())
putDownloadPath(uri.toString())
}
}
}

@ -48,7 +48,7 @@ open class WelcomeActivity : BaseActivity(R.layout.activity_welcome) {
private fun startMainActivity() {
startActivity<MainActivity>()
if (getPrefBoolean(getString(R.string.pk_default_read))) {
if (getPrefBoolean(R.string.pk_default_read)) {
startActivity<ReadBookActivity>()
}
finish()

@ -142,12 +142,12 @@ class TitleBar(context: Context, attrs: AttributeSet?) : AppBarLayout(context, a
}
backgroundColor = context.primaryColor
// targetElevation = context.elevation
stateListAnimator = null
if (AppConfig.elevation < 0) {
elevation = context.elevation
elevation = if (AppConfig.elevation < 0) {
context.elevation
} else {
elevation = AppConfig.elevation.toFloat()
AppConfig.elevation.toFloat()
}
a.recycle()

@ -12,6 +12,7 @@ import android.os.BatteryManager
import android.provider.Settings
import androidx.annotation.ColorRes
import androidx.annotation.DrawableRes
import androidx.annotation.StringRes
import androidx.core.content.ContextCompat
import androidx.core.content.FileProvider
import androidx.core.content.edit
@ -28,6 +29,9 @@ import java.io.FileOutputStream
fun Context.getPrefBoolean(key: String, defValue: Boolean = false) =
defaultSharedPreferences.getBoolean(key, defValue)
fun Context.getPrefBoolean(@StringRes keyId: Int, defValue: Boolean = false) =
defaultSharedPreferences.getBoolean(getString(keyId), defValue)
fun Context.putPrefBoolean(key: String, value: Boolean = false) =
defaultSharedPreferences.edit { putBoolean(key, value) }
@ -46,6 +50,9 @@ fun Context.putPrefLong(key: String, value: Long) =
fun Context.getPrefString(key: String, defValue: String? = null) =
defaultSharedPreferences.getString(key, defValue)
fun Context.getPrefString(@StringRes keyId: Int, defValue: String? = null) =
defaultSharedPreferences.getString(getString(keyId), defValue)
fun Context.putPrefString(key: String, value: String) =
defaultSharedPreferences.edit { putString(key, value) }

@ -9,6 +9,12 @@
android:layout_width="match_parent"
android:layout_height="match_parent" />
<View
android:id="@+id/text_menu_position"
android:layout_width="0dp"
android:layout_height="0dp"
android:visibility="invisible" />
<ImageView
android:id="@+id/cursor_left"
android:layout_width="wrap_content"

@ -16,7 +16,7 @@
android:id="@+id/iv_menu_more"
android:layout_width="24dp"
android:layout_height="24dp"
android:background="?attr/selectableItemBackground"
android:background="?attr/selectableItemBackgroundBorderless"
android:src="@drawable/ic_more_vert"
android:tint="@color/tv_text_default"
android:visibility="gone"

@ -38,5 +38,11 @@
<item>9</item>
</string-array>
<string-array name="screen_direction_value">
<item>0</item>
<item>1</item>
<item>2</item>
<item>3</item>
</string-array>
</resources>

@ -67,7 +67,7 @@
<item>@string/app_folder_picker</item>
</string-array>
<string-array name="screen_direction_list_title">
<string-array name="screen_direction_title">
<item>@string/screen_unspecified</item>
<item>@string/screen_portrait</item>
<item>@string/screen_landscape</item>

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="pk_auto_refresh">auto_refresh</string>
<string name="pk_screen_direction">list_screen_direction</string>
<string name="pk_requested_direction">list_screen_direction</string>
<string name="pk_full_screen">full_screen</string>
<string name="pk_threads_num">threads_num</string>
<string name="pk_user_agent">user_agent</string>

@ -646,4 +646,5 @@
<string name="bar_elevation">导航栏阴影</string>
<string name="bar_elevation_s">当前阴影大小(elevation): %s</string>
<string name="btn_default_s">默认</string>
</resources>

@ -2,6 +2,14 @@
<androidx.preference.PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<io.legado.app.ui.widget.prefs.NameListPreference
android:key="@string/pk_requested_direction"
android:defaultValue="0"
android:title="@string/screen_direction"
android:entries="@array/screen_direction_title"
android:entryValues="@array/screen_direction_value"
app:iconSpaceReserved="false" />
<io.legado.app.ui.widget.prefs.NameListPreference
android:key="keep_light"
android:defaultValue="0"

Loading…
Cancel
Save