Merge pull request #27 from gedoor/master

up
pull/379/head
口口吕 5 years ago committed by GitHub
commit 44fd594a2f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 1
      app/src/main/AndroidManifest.xml
  2. 68
      app/src/main/assets/txtTocRule.json
  3. 8
      app/src/main/assets/updateLog.md
  4. 1
      app/src/main/java/io/legado/app/constant/PreferKey.kt
  5. 10
      app/src/main/java/io/legado/app/help/AppConfig.kt
  6. 8
      app/src/main/java/io/legado/app/help/BookHelp.kt
  7. 12
      app/src/main/java/io/legado/app/lib/theme/ATHUtils.kt
  8. 3
      app/src/main/java/io/legado/app/lib/theme/MaterialValueHelper.kt
  9. 8
      app/src/main/java/io/legado/app/lib/theme/ThemeStore.kt
  10. 2
      app/src/main/java/io/legado/app/lib/theme/ThemeStorePrefKeys.kt
  11. 14
      app/src/main/java/io/legado/app/model/localBook/LocalBook.kt
  12. 4
      app/src/main/java/io/legado/app/service/TTSReadAloudService.kt
  13. 4
      app/src/main/java/io/legado/app/ui/book/info/BookInfoActivity.kt
  14. 13
      app/src/main/java/io/legado/app/ui/book/read/Help.kt
  15. 45
      app/src/main/java/io/legado/app/ui/book/read/ReadBookActivity.kt
  16. 7
      app/src/main/java/io/legado/app/ui/book/read/TextActionMenu.kt
  17. 5
      app/src/main/java/io/legado/app/ui/book/read/config/MoreConfigDialog.kt
  18. 1
      app/src/main/java/io/legado/app/ui/book/read/page/ChapterProvider.kt
  19. 53
      app/src/main/java/io/legado/app/ui/book/read/page/ContentTextView.kt
  20. 1
      app/src/main/java/io/legado/app/ui/book/read/page/ContentView.kt
  21. 16
      app/src/main/java/io/legado/app/ui/book/read/page/PageView.kt
  22. 7
      app/src/main/java/io/legado/app/ui/book/read/page/delegate/PageDelegate.kt
  23. 16
      app/src/main/java/io/legado/app/ui/book/read/page/entities/TextPage.kt
  24. 16
      app/src/main/java/io/legado/app/ui/config/OtherConfigFragment.kt
  25. 28
      app/src/main/java/io/legado/app/ui/config/ThemeConfigFragment.kt
  26. 2
      app/src/main/java/io/legado/app/ui/welcome/WelcomeActivity.kt
  27. 68
      app/src/main/java/io/legado/app/ui/widget/BatteryView.kt
  28. 9
      app/src/main/java/io/legado/app/ui/widget/TitleBar.kt
  29. 11
      app/src/main/java/io/legado/app/ui/widget/number/NumberPickerDialog.kt
  30. 7
      app/src/main/java/io/legado/app/utils/ContextExtensions.kt
  31. 419
      app/src/main/res/layout-land/activity_book_info.xml
  32. 172
      app/src/main/res/layout/activity_book_info.xml
  33. 6
      app/src/main/res/layout/activity_book_read.xml
  34. 2
      app/src/main/res/layout/popup_action_menu.xml
  35. 3
      app/src/main/res/layout/view_book_page.xml
  36. 6
      app/src/main/res/values/array_values.xml
  37. 2
      app/src/main/res/values/arrays.xml
  38. 2
      app/src/main/res/values/pref_key_value.xml
  39. 8
      app/src/main/res/values/strings.xml
  40. 8
      app/src/main/res/xml/pref_config_read.xml
  41. 7
      app/src/main/res/xml/pref_config_theme.xml

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

@ -2,73 +2,97 @@
{ {
"enable": true, "enable": true,
"name": "目录", "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 "serialNumber": 0
}, },
{ {
"enable": false, "enable": false,
"name": "目录(不匹配行前空白)", "name": "目录(空白)",
"rule": "^(?<= |\\s)(?:(?:内容|文章)?简介|文案|前言|序章|楔子|正文(?!完)|终章|后记|尾声|番外|第?\\s{0,4}[\\d零一二两三四五六七八九十百千万壹贰叁肆伍陆柒捌玖拾佰仟]+?\\s{0,4}(?:章|节(?!课)|卷|集(?![合和])|部(?!分)|篇(?!张))).{0,30}$", "rule": "(?<=[ \\s])(?:(?:内容|文章)?简介|文案|前言|序章|楔子|正文(?!完|结)|终章|后记|尾声|番外|第?\\s{0,4}[\\d零一二两三四五六七八九十百千万壹贰叁肆伍陆柒捌玖拾佰仟]+?\\s{0,4}(?:章|节(?!课)|卷|集(?![合和])|部(?!分)|篇(?!张))).{0,30}$",
"serialNumber": 1 "serialNumber": 1
}, },
{ {
"enable": false, "enable": false,
"name": "目录(去简介)", "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 "serialNumber": 2
}, },
{ {
"enable": false, "enable": false,
"name": "目录(古典、轻小说备用)", "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 "serialNumber": 3
}, },
{
"enable": false,
"name": "数字(纯数字标题)",
"rule": "(?<=[ \\s])\\d+[  \\t]{0,4}$",
"serialNumber": 4
},
{ {
"enable": true, "enable": true,
"name": "数字 分隔符 标题名称", "name": "数字 分隔符 标题名称",
"rule": "^[  \\t]{0,4}\\d{1,5}[\\,\\., 、\\-].{1,30}$", "rule": "^[  \\t]{0,4}\\d{1,5}[\\,\\., 、\\-].{1,30}$",
"serialNumber": 4 "serialNumber": 5
}, },
{ {
"enable": true, "enable": true,
"name": "正文 标题/序号", "name": "正文 标题/序号",
"rule": "^[  \\t]{0,4}正文\\s{1,4}.{0,20}$", "rule": "^[  \\t]{0,4}正文[  ]{1,4}.{0,20}$",
"serialNumber": 5 "serialNumber": 6
}, },
{ {
"enable": true, "enable": true,
"name": "Chapter/Section/Part/Episode 序号 标题", "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}$", "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, "enable": true,
"name": "特殊符号 序号 标题", "name": "特殊符号 序号 标题",
"rule": "^[  \\t]{0,4}[〈〖〔【][第卷][\\d零一二两三四五六七八九十百千万壹贰叁肆伍陆柒捌玖拾佰仟]{1,10}[章节][\\.:: \f\t].{0,30}$", "rule": "(?<=[\\s ]{0,4}).{1,3}(?:第|卷|[Cc]hapter)[\\d零一二两三四五六七八九十百千万壹贰叁肆伍陆柒捌玖拾佰仟]{1,10}[章节]?[\\.:: \f\t].{0,20}$",
"serialNumber": 7 "serialNumber": 9
}, },
{ {
"enable": true, "enable": false,
"name": "特殊符号 标题", "name": "特殊符号 标题(成对)",
"rule": "^[  \\t]{0,4}[\\[〈「『〖〔《(【\\(☆★].{1,30}[\\)】)》〕〗』」〉\\]]?\\s{0,4}$", "rule": "(?<=[\\s ]{0,4})(?:[\\[〈「『〖〔《(【\\(].{1,30}[\\)】)》〕〗』」〉\\]]?|(?:内容|文章)?简介|文案|前言|序章|楔子|正文(?!完|结)|终章|后记|尾声|番外)[  ]{0,4}$",
"serialNumber": 8 "serialNumber": 10
}, },
{ {
"enable":false, "enable":true,
"name": "特殊符号 标题(不匹配空白字符)", "name": "特殊符号 标题(单个)",
"rule": "^(?<= |\\s)[\\[〈「『〖〔《(【\\(☆★].{1,30}[\\)】)》〕〗』」〉\\]]?\\s{0,4}$", "rule": "(?<=[\\s ]{0,4})(?:[☆★✦✧].{1,30}|(?:内容|文章)?简介|文案|前言|序章|楔子|正文(?!完|结)|终章|后记|尾声|番外)[  ]{0,4}$",
"serialNumber": 9 "serialNumber": 11
}, },
{ {
"enable": true, "enable": true,
"name": "章/卷 序号 标题", "name": "章/卷 序号 标题",
"rule": "^[  \\t]{0,4}(?:(?:内容|文章)?简介|文案|前言|序章|楔子|正文(?!完)|终章|后记|尾声|番外|[卷章][\\d零一二两三四五六七八九十百千万壹贰叁肆伍陆柒捌玖拾佰仟]{1,8})\\s{0,4}.{0,30}$", "rule": "^[ \\t ]{0,4}(?:(?:内容|文章)?简介|文案|前言|序章|楔子|正文(?!完|结)|终章|后记|尾声|番外|[卷章][\\d零一二两三四五六七八九十百千万壹贰叁肆伍陆柒捌玖拾佰仟]{1,8})[  ]{0,4}.{0,30}$",
"serialNumber": 10 "serialNumber": 12
}, },
{ {
"enable":false, "enable":false,
"name": "顶格标题", "name": "顶格标题",
"rule": "^\\S.{1,20}$", "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,6 +2,14 @@
* 旧版数据导入教程:先在旧版阅读(2.x)中进行备份,然后在新版阅读(3.x)【我的】->【备份与恢复】,选择【导入旧版本数据】。 * 旧版数据导入教程:先在旧版阅读(2.x)中进行备份,然后在新版阅读(3.x)【我的】->【备份与恢复】,选择【导入旧版本数据】。
* 请关注[开源阅读软件]()支持我,同时关注合作公众号[小说拾遗](),阅读公众号小编。 * 请关注[开源阅读软件]()支持我,同时关注合作公众号[小说拾遗](),阅读公众号小编。
**2020/03/10**
* 优化文字选择菜单弹出位置
* 添加屏幕方向控制
**2020/03/09**
* 底部文字对齐
* 主题添加阴影调节 by yangyxd
**2020/03/08** **2020/03/08**
* 订阅长按保存图片 * 订阅长按保存图片
* 订阅全屏播放 * 订阅全屏播放

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

@ -32,6 +32,9 @@ object AppConfig {
App.INSTANCE.putPrefBoolean("transparentStatusBar", value) App.INSTANCE.putPrefBoolean("transparentStatusBar", value)
} }
val requestedDirection: String?
get() = App.INSTANCE.getPrefString(R.string.pk_requested_direction)
var backupPath: String? var backupPath: String?
get() = App.INSTANCE.getPrefString(PreferKey.backupPath) get() = App.INSTANCE.getPrefString(PreferKey.backupPath)
set(value) { set(value) {
@ -49,7 +52,7 @@ object AppConfig {
} }
val autoRefreshBook: Boolean 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 var threadCount: Int
get() = App.INSTANCE.getPrefInt(PreferKey.threadCount, 16) get() = App.INSTANCE.getPrefInt(PreferKey.threadCount, 16)
@ -111,4 +114,9 @@ object AppConfig {
App.INSTANCE.putPrefBoolean("bookGroupAudio", value) App.INSTANCE.putPrefBoolean("bookGroupAudio", value)
} }
var elevation: Int
get() = App.INSTANCE.getPrefInt("elevation", -1)
set(value) {
App.INSTANCE.putPrefInt("elevation", value)
}
} }

@ -4,8 +4,8 @@ import android.net.Uri
import androidx.documentfile.provider.DocumentFile import androidx.documentfile.provider.DocumentFile
import com.github.houbb.opencc4j.core.impl.ZhConvertBootstrap import com.github.houbb.opencc4j.core.impl.ZhConvertBootstrap
import io.legado.app.App import io.legado.app.App
import io.legado.app.R
import io.legado.app.constant.EventBus 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.Book
import io.legado.app.data.entities.BookChapter import io.legado.app.data.entities.BookChapter
import io.legado.app.data.entities.ReplaceRule import io.legado.app.data.entities.ReplaceRule
@ -21,7 +21,7 @@ import kotlin.math.min
object BookHelp { object BookHelp {
private const val cacheFolderName = "book_cache" private const val cacheFolderName = "book_cache"
val downloadPath: String 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.getExternalFilesDir(null)?.absolutePath
?: App.INSTANCE.cacheDir.absolutePath ?: App.INSTANCE.cacheDir.absolutePath
@ -300,6 +300,8 @@ object BookHelp {
1 -> c = ZhConvertBootstrap.newInstance().toSimple(c) 1 -> c = ZhConvertBootstrap.newInstance().toSimple(c)
2 -> c = ZhConvertBootstrap.newInstance().toTraditional(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(), "") //移除尾部空行
} }
} }

@ -19,4 +19,16 @@ object ATHUtils {
a.recycle() a.recycle()
} }
} }
@JvmOverloads
fun resolveFloat(context: Context, @AttrRes attr: Int, fallback: Float = 0.0f): Float {
val a = context.theme.obtainStyledAttributes(intArrayOf(attr))
return try {
a.getFloat(0, fallback)
} catch (e: Exception) {
fallback
} finally {
a.recycle()
}
}
} }

@ -108,3 +108,6 @@ val Context.isDarkTheme: Boolean
val Fragment.isDarkTheme: Boolean val Fragment.isDarkTheme: Boolean
get() = requireContext().isDarkTheme get() = requireContext().isDarkTheme
val Context.elevation: Float
get() = ThemeStore.elevation(this)

@ -284,6 +284,14 @@ private constructor(private val mContext: Context) : ThemeStoreInterface {
) )
} }
@CheckResult
fun elevation(context: Context): Float {
return prefs(context).getFloat(
ThemeStorePrefKeys.KEY_ELEVATION,
ATHUtils.resolveFloat(context, android.R.attr.elevation, context.resources.getDimension(R.dimen.design_appbar_elevation))
)
}
@CheckResult @CheckResult
@ColorInt @ColorInt
fun bottomBackground(context: Context): Int { fun bottomBackground(context: Context): Int {

@ -27,4 +27,6 @@ object ThemeStorePrefKeys {
const val KEY_APPLY_PRIMARYDARK_STATUSBAR = "apply_primarydark_statusbar" const val KEY_APPLY_PRIMARYDARK_STATUSBAR = "apply_primarydark_statusbar"
const val KEY_APPLY_PRIMARY_NAVBAR = "apply_primary_navbar" const val KEY_APPLY_PRIMARY_NAVBAR = "apply_primary_navbar"
const val KEY_AUTO_GENERATE_PRIMARYDARK = "auto_generate_primarydark" const val KEY_AUTO_GENERATE_PRIMARYDARK = "auto_generate_primarydark"
const val KEY_ELEVATION = "elevation"
} }

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

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

@ -207,7 +207,7 @@ class BookInfoActivity :
ChangeSourceDialog.show(supportFragmentManager, it.name, it.author) ChangeSourceDialog.show(supportFragmentManager, it.name, it.author)
} }
} }
tv_toc.onClick { tv_toc_view.onClick {
if (!viewModel.inBookshelf) { if (!viewModel.inBookshelf) {
viewModel.saveBook { viewModel.saveBook {
viewModel.saveChapterList { viewModel.saveChapterList {
@ -218,7 +218,7 @@ class BookInfoActivity :
openChapterList() openChapterList()
} }
} }
tv_group.onClick { tv_change_group.onClick {
viewModel.bookData.value?.let { viewModel.bookData.value?.let {
GroupSelectDialog.show(supportFragmentManager, it.group) GroupSelectDialog.show(supportFragmentManager, it.group)
} }

@ -3,6 +3,7 @@ package io.legado.app.ui.book.read
import android.annotation.SuppressLint import android.annotation.SuppressLint
import android.app.Activity import android.app.Activity
import android.content.Context import android.content.Context
import android.content.pm.ActivityInfo
import android.os.AsyncTask import android.os.AsyncTask
import android.os.Build import android.os.Build
import android.view.* 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是否存在 * 返回NavigationBar是否存在
* 该方法需要在View完全被绘制出来之后调用否则判断不了 * 该方法需要在View完全被绘制出来之后调用否则判断不了

@ -3,6 +3,7 @@ package io.legado.app.ui.book.read
import android.annotation.SuppressLint import android.annotation.SuppressLint
import android.app.Activity import android.app.Activity
import android.content.Intent import android.content.Intent
import android.content.res.Configuration
import android.net.Uri import android.net.Uri
import android.os.Bundle import android.os.Bundle
import android.os.Handler import android.os.Handler
@ -13,6 +14,7 @@ import androidx.core.view.isVisible
import androidx.core.view.size import androidx.core.view.size
import androidx.lifecycle.Observer import androidx.lifecycle.Observer
import com.jaredrummler.android.colorpicker.ColorPickerDialogListener import com.jaredrummler.android.colorpicker.ColorPickerDialogListener
import io.legado.app.BuildConfig
import io.legado.app.R import io.legado.app.R
import io.legado.app.base.VMBaseActivity import io.legado.app.base.VMBaseActivity
import io.legado.app.constant.EventBus 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 pageFactory: TextPageFactory get() = page_view.pageFactory
override val headerHeight: Int get() = page_view.curPage.headerHeight 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?) { override fun onActivityCreated(savedInstanceState: Bundle?) {
Help.upLayoutInDisplayCutoutMode(window) Help.upLayoutInDisplayCutoutMode(window)
initView() initView()
@ -106,6 +113,11 @@ class ReadBookActivity : VMBaseActivity<ReadBookViewModel>(R.layout.activity_boo
upSystemUiVisibility() upSystemUiVisibility()
} }
override fun onConfigurationChanged(newConfig: Configuration) {
super.onConfigurationChanged(newConfig)
ReadBook.loadContent()
}
override fun onResume() { override fun onResume() {
super.onResume() super.onResume()
upSystemUiVisibility() upSystemUiVisibility()
@ -338,7 +350,8 @@ class ReadBookActivity : VMBaseActivity<ReadBookViewModel>(R.layout.activity_boo
@SuppressLint("ClickableViewAccessibility") @SuppressLint("ClickableViewAccessibility")
override fun onTouch(v: View, event: MotionEvent): Boolean { override fun onTouch(v: View, event: MotionEvent): Boolean {
when (event.action) { when (event.action) {
MotionEvent.ACTION_MOVE, MotionEvent.ACTION_UP -> { MotionEvent.ACTION_DOWN -> textActionMenu?.dismiss()
MotionEvent.ACTION_MOVE -> {
when (v.id) { when (v.id) {
R.id.cursor_left -> page_view.curPage.selectStartMove( R.id.cursor_left -> page_view.curPage.selectStartMove(
event.rawX + cursor_left.width, event.rawX + cursor_left.width,
@ -350,6 +363,7 @@ class ReadBookActivity : VMBaseActivity<ReadBookViewModel>(R.layout.activity_boo
) )
} }
} }
MotionEvent.ACTION_UP -> showTextActionMenu()
} }
return true 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.x = x - cursor_left.width
cursor_left.y = y cursor_left.y = y
cursor_left.visible(true) 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.x = x
cursor_right.y = y cursor_right.y = y
cursor_right.visible(true) 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 ?: 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 -> 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) { 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 { } else {
popup.update(x, y, WRAP_CONTENT, WRAP_CONTENT) popup.update(x, y, WRAP_CONTENT, WRAP_CONTENT)
} }
@ -663,8 +682,10 @@ class ReadBookActivity : VMBaseActivity<ReadBookViewModel>(R.layout.activity_boo
mHandler.removeCallbacks(keepScreenRunnable) mHandler.removeCallbacks(keepScreenRunnable)
textActionMenu?.dismiss() textActionMenu?.dismiss()
page_view.onDestroy() page_view.onDestroy()
if (!BuildConfig.DEBUG) {
SyncBookProgress.uploadBookProgress() SyncBookProgress.uploadBookProgress()
} }
}
override fun observeLiveBus() { override fun observeLiveBus() {
super.observeLiveBus() super.observeLiveBus()

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

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

@ -75,6 +75,7 @@ object ChapterProvider {
item.chapterIndex = bookChapter.index item.chapterIndex = bookChapter.index
item.chapterSize = chapterSize item.chapterSize = chapterSize
item.title = bookChapter.title item.title = bookChapter.title
item.upLinesPosition(visibleHeight)
} }
return TextChapter( return TextChapter(
bookChapter.index, bookChapter.index,

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

@ -109,7 +109,6 @@ class ContentView(context: Context) : FrameLayout(context) {
fun setContent(textPage: TextPage) { fun setContent(textPage: TextPage) {
setProgress(textPage) setProgress(textPage)
content_text_view.resetPageOffset()
content_text_view.setContent(textPage) content_text_view.setContent(textPage)
} }

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

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

@ -18,6 +18,21 @@ data class TextPage(
var height: Float = 0f var height: Float = 0f
) { ) {
fun upLinesPosition(visibleHeight: Int) {
if (textLines.size <= 1) return
if (visibleHeight - height > with(textLines.last()) { lineBottom - lineTop }) return
val surplus = (visibleHeight - textLines.last().lineBottom)
if (surplus == 0f) return
height += surplus
val tj = surplus / (textLines.size - 1)
for (i in 1 until textLines.size) {
val line = textLines[i]
line.lineTop = line.lineTop + tj * i
line.lineBase = line.lineBase + tj * i
line.lineBottom = line.lineBottom + tj * i
}
}
@Suppress("DEPRECATION") @Suppress("DEPRECATION")
fun format(): TextPage { fun format(): TextPage {
if (textLines.isEmpty() && ChapterProvider.visibleWidth > 0) { if (textLines.isEmpty() && ChapterProvider.visibleWidth > 0) {
@ -101,4 +116,5 @@ data class TextPage(
} }
return percent return percent
} }
} }

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

@ -1,6 +1,7 @@
package io.legado.app.ui.config package io.legado.app.ui.config
import android.content.SharedPreferences import android.content.SharedPreferences
import android.os.Build
import android.os.Bundle import android.os.Bundle
import android.view.View import android.view.View
import androidx.preference.Preference import androidx.preference.Preference
@ -16,6 +17,8 @@ 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.ColorUtils import io.legado.app.lib.theme.ColorUtils
import io.legado.app.ui.widget.number.NumberPickerDialog
import io.legado.app.ui.widget.prefs.IconListPreference
import io.legado.app.utils.* import io.legado.app.utils.*
@ -25,6 +28,12 @@ class ThemeConfigFragment : PreferenceFragmentCompat(), SharedPreferences.OnShar
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
addPreferencesFromResource(R.xml.pref_config_theme) addPreferencesFromResource(R.xml.pref_config_theme)
if (Build.VERSION.SDK_INT < 26) {
findPreference<IconListPreference>(PreferKey.launcherIcon)?.let {
preferenceScreen.removePreference(it)
}
}
upPreferenceSummary("barElevation", AppConfig.elevation.toString())
} }
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
@ -145,6 +154,19 @@ class ThemeConfigFragment : PreferenceFragmentCompat(), SharedPreferences.OnShar
recreateActivities() recreateActivities()
} }
}.show().applyTint() }.show().applyTint()
"barElevation" -> NumberPickerDialog(requireContext())
.setTitle(getString(R.string.bar_elevation))
.setMaxValue(32)
.setMinValue(0)
.setValue(AppConfig.elevation)
.setCustomButton((R.string.btn_default_s)) {
AppConfig.elevation = App.INSTANCE.resources.getDimension(R.dimen.design_appbar_elevation).toInt()
recreateActivities()
}
.show {
AppConfig.elevation = it
recreateActivities()
}
} }
return super.onPreferenceTreeClick(preference) return super.onPreferenceTreeClick(preference)
} }
@ -180,4 +202,10 @@ class ThemeConfigFragment : PreferenceFragmentCompat(), SharedPreferences.OnShar
postEvent(EventBus.RECREATE, "") postEvent(EventBus.RECREATE, "")
} }
private fun upPreferenceSummary(preferenceKey: String, value: String?) {
val preference = findPreference<Preference>(preferenceKey) ?: return
when (preferenceKey) {
"barElevation" -> preference.summary = getString(R.string.bar_elevation_s, value)
}
}
} }

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

@ -1,67 +1,57 @@
package io.legado.app.ui.widget package io.legado.app.ui.widget
import android.annotation.SuppressLint
import android.content.Context import android.content.Context
import android.graphics.Canvas import android.graphics.Canvas
import android.graphics.Paint import android.graphics.Paint
import android.graphics.Rect import android.graphics.Rect
import android.graphics.Typeface
import android.text.StaticLayout
import android.text.TextPaint
import android.util.AttributeSet import android.util.AttributeSet
import android.view.View
import androidx.annotation.ColorInt import androidx.annotation.ColorInt
import io.legado.app.R import androidx.appcompat.widget.AppCompatTextView
import io.legado.app.utils.dp import io.legado.app.utils.dp
import io.legado.app.utils.getCompatColor
import io.legado.app.utils.sp
class BatteryView(context: Context, attrs: AttributeSet?) : View(context, attrs) { class BatteryView(context: Context, attrs: AttributeSet?) : AppCompatTextView(context, attrs) {
private var battery = 100 private val batteryPaint = Paint()
private val textPaint = TextPaint()
private var batteryHeight: Int = 0
private var batteryWidth: Int = 0
private val outFrame = Rect() private val outFrame = Rect()
private val polar = Rect() private val polar = Rect()
init { init {
textPaint.textSize = 10.sp.toFloat() setPadding(4.dp, 0, 6.dp, 0)
textPaint.strokeWidth = 1.dp.toFloat() batteryPaint.strokeWidth = 1.dp.toFloat()
textPaint.isAntiAlias = true batteryPaint.isAntiAlias = true
textPaint.textAlign = Paint.Align.CENTER batteryPaint.color = paint.color
textPaint.color = context.getCompatColor(R.color.tv_text_default)
textPaint.typeface = Typeface.createFromAsset(context.assets, "number.ttf")
batteryHeight = with(textPaint.fontMetrics) { descent - ascent + leading }.toInt()
batteryWidth = StaticLayout.getDesiredWidth("100", textPaint).toInt() + 10.dp
outFrame.set(1.dp, 1.dp, batteryWidth - 3.dp, batteryHeight - 1.dp)
polar.set(outFrame.right, batteryHeight / 3, batteryWidth, batteryHeight * 2 / 3)
}
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
super.onMeasure(
MeasureSpec.makeMeasureSpec(batteryWidth, MeasureSpec.EXACTLY),
MeasureSpec.makeMeasureSpec(batteryHeight, MeasureSpec.EXACTLY)
)
} }
fun setColor(@ColorInt color: Int) { fun setColor(@ColorInt color: Int) {
textPaint.color = color setTextColor(color)
batteryPaint.color = color
invalidate() invalidate()
} }
@SuppressLint("SetTextI18n")
fun setBattery(battery: Int) { fun setBattery(battery: Int) {
this.battery = battery text = "$battery"
invalidate()
} }
override fun onDraw(canvas: Canvas) { override fun onDraw(canvas: Canvas) {
super.onDraw(canvas) super.onDraw(canvas)
textPaint.style = Paint.Style.STROKE outFrame.set(
canvas.drawRect(outFrame, textPaint) 1.dp,
textPaint.style = Paint.Style.FILL layout.getLineTop(0) + 2.dp,
canvas.drawRect(polar, textPaint) width - 3.dp,
val text = battery.toString() layout.getLineBottom(0) - 2.dp
val baseHeight = batteryHeight - textPaint.fontMetrics.descent )
canvas.drawText(text, outFrame.right / 2.toFloat(), baseHeight, textPaint) val dj = (outFrame.bottom - outFrame.top) / 3
polar.set(
outFrame.right,
outFrame.top + dj,
width - 1.dp,
outFrame.bottom - dj
)
batteryPaint.style = Paint.Style.STROKE
canvas.drawRect(outFrame, batteryPaint)
batteryPaint.style = Paint.Style.FILL
canvas.drawRect(polar, batteryPaint)
} }
} }

@ -10,6 +10,8 @@ import androidx.annotation.StyleRes
import androidx.appcompat.widget.Toolbar import androidx.appcompat.widget.Toolbar
import com.google.android.material.appbar.AppBarLayout import com.google.android.material.appbar.AppBarLayout
import io.legado.app.R import io.legado.app.R
import io.legado.app.help.AppConfig
import io.legado.app.lib.theme.elevation
import io.legado.app.lib.theme.primaryColor import io.legado.app.lib.theme.primaryColor
import io.legado.app.utils.activity import io.legado.app.utils.activity
import io.legado.app.utils.navigationBarHeight import io.legado.app.utils.navigationBarHeight
@ -141,6 +143,13 @@ class TitleBar(context: Context, attrs: AttributeSet?) : AppBarLayout(context, a
backgroundColor = context.primaryColor backgroundColor = context.primaryColor
stateListAnimator = null
elevation = if (AppConfig.elevation < 0) {
context.elevation
} else {
AppConfig.elevation.toFloat()
}
a.recycle() a.recycle()
} }

@ -40,6 +40,17 @@ class NumberPickerDialog(context: Context) {
return this return this
} }
fun setCustomButton(textId: Int, listener: (() -> Unit)?): NumberPickerDialog {
builder.setNeutralButton(textId) { _, _ ->
numberPicker?.let {
it.clearFocus()
it.hideSoftInput()
listener?.invoke()
}
}
return this;
}
fun show(callBack: ((value: Int) -> Unit)?) { fun show(callBack: ((value: Int) -> Unit)?) {
builder.setPositiveButton(R.string.ok) { _, _ -> builder.setPositiveButton(R.string.ok) { _, _ ->
numberPicker?.let { numberPicker?.let {

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

@ -0,0 +1,419 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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">
<ImageView
android:id="@+id/bg_book"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="centerCrop"
android:contentDescription="@string/bg_image"
app:layout_constraintTop_toTopOf="parent" />
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="?attr/actionBarStyle"
android:fitsSystemWindows="true"
app:popupTheme="@style/AppTheme.PopupOverlay"
app:layout_constraintTop_toTopOf="parent"
app:title="@string/book_info" />
<LinearLayout
android:id="@+id/vw_bg"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#50000000"
android:orientation="horizontal"
android:fitsSystemWindows="true">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1.0"
android:layout_gravity="center"
android:gravity="center"
android:orientation="vertical">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="68dp">
<io.legado.app.ui.widget.ArcView
android:layout_width="match_parent"
android:layout_height="78dp"
android:layout_marginTop="120dp"
app:arcDirectionTop="true"
app:arcHeight="36dp"
app:bgColor="@color/background" />
<androidx.cardview.widget.CardView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_margin="3dp"
app:cardCornerRadius="5dp"
app:cardElevation="8dp">
<io.legado.app.ui.widget.image.CoverImageView
android:id="@+id/iv_cover"
android:layout_width="130dp"
android:layout_height="200dp"
android:contentDescription="@string/img_cover"
android:scaleType="centerCrop"
android:src="@drawable/image_cover_default" />
</androidx.cardview.widget.CardView>
</RelativeLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/background"
android:orientation="vertical"
android:paddingLeft="10dp"
android:paddingTop="8dp"
android:paddingRight="16dp"
android:paddingBottom="3dp">
<TextView
android:id="@+id/tv_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="6dp"
android:gravity="center"
android:includeFontPadding="false"
android:singleLine="true"
android:text="@string/book_name"
android:textColor="@color/tv_text_default"
android:textSize="18sp"
tools:ignore="RtlHardcoded" />
<io.legado.app.ui.widget.LabelsBar
android:id="@+id/lb_kind"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginBottom="6dp"
android:gravity="center"
android:visibility="gone" />
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:gravity="center"
android:layout_gravity="center"
android:orientation="horizontal"
android:paddingTop="3dp"
android:paddingBottom="3dp">
<ImageView
android:layout_width="18sp"
android:layout_height="18sp"
android:contentDescription="@string/origin_format"
android:paddingRight="4dp"
android:src="@drawable/ic_author"
app:tint="@color/tv_text_summary"
tools:ignore="RtlHardcoded,RtlSymmetry" />
<TextView
android:id="@+id/tv_author"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ellipsize="end"
android:includeFontPadding="false"
android:singleLine="true"
android:text="@string/author"
android:textColor="@color/tv_text_summary"
android:textSize="13sp"
tools:ignore="NestedWeights" />
</LinearLayout>
</LinearLayout>
</LinearLayout>
<LinearLayout
android:layout_weight="1.0"
android:orientation="vertical"
android:layout_marginTop="65dp"
android:layout_marginLeft="1px"
android:fitsSystemWindows="true"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ScrollView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:background="@color/background"
android:fillViewport="true"
android:fitsSystemWindows="true"
android:focusable="true"
android:padding="0dp"
android:scrollbarStyle="outsideInset"
android:scrollbars="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:paddingTop="16dp"
android:paddingLeft="8dp"
android:paddingRight="8dp"
android:paddingBottom="8dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/background"
android:orientation="vertical"
android:paddingLeft="8dp"
android:paddingRight="8dp"
android:paddingBottom="8dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:orientation="horizontal"
android:paddingTop="3dp"
android:paddingBottom="3dp">
<ImageView
android:id="@+id/iv_web"
android:layout_width="18sp"
android:layout_height="18sp"
android:contentDescription="@string/origin_format"
android:paddingRight="2dp"
android:src="@drawable/ic_web_outline"
app:tint="@color/tv_text_summary"
tools:ignore="RtlHardcoded,RtlSymmetry" />
<TextView
android:id="@+id/tv_origin"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:ellipsize="end"
android:includeFontPadding="false"
android:paddingRight="6dp"
android:singleLine="true"
android:text="@string/origin_format"
android:textColor="@color/tv_text_summary"
android:textSize="13sp"
tools:ignore="NestedWeights" />
<io.legado.app.ui.widget.text.AccentBgTextView
android:id="@+id/tv_change_source"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:paddingLeft="5dp"
android:paddingRight="5dp"
android:text="@string/change_origin"
android:textSize="13sp"
app:radius="2dp" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:orientation="horizontal"
android:paddingTop="3dp"
android:paddingBottom="3dp">
<ImageView
android:id="@+id/ic_book_last"
android:layout_width="18sp"
android:layout_height="18sp"
android:contentDescription="@string/read_dur_progress"
android:paddingRight="2dp"
android:src="@drawable/ic_book_last"
app:tint="@color/tv_text_summary"
tools:ignore="RtlHardcoded,RtlSymmetry" />
<TextView
android:id="@+id/tv_lasted"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:ellipsize="end"
android:includeFontPadding="false"
android:paddingRight="6dp"
android:singleLine="true"
android:text="@string/read_dur_progress"
android:textColor="@color/tv_text_summary"
android:textSize="13sp"
tools:ignore="NestedWeights" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:orientation="horizontal"
android:paddingTop="3dp"
android:paddingBottom="3dp">
<ImageView
android:layout_width="18sp"
android:layout_height="18sp"
android:contentDescription="@string/read_dur_progress"
android:paddingRight="2dp"
android:src="@drawable/ic_groups"
app:tint="@color/tv_text_summary"
tools:ignore="RtlHardcoded,RtlSymmetry" />
<TextView
android:id="@+id/tv_group"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:ellipsize="end"
android:includeFontPadding="false"
android:paddingRight="6dp"
android:singleLine="true"
android:text="@string/group_s"
android:textColor="@color/tv_text_summary"
android:textSize="13sp"
tools:ignore="NestedWeights" />
<io.legado.app.ui.widget.text.AccentBgTextView
android:id="@+id/tv_change_group"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:paddingLeft="5dp"
android:paddingRight="5dp"
android:text="@string/change_group"
android:textSize="13sp"
app:radius="2dp" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:orientation="horizontal"
android:paddingTop="3dp"
android:paddingBottom="3dp">
<ImageView
android:layout_width="18sp"
android:layout_height="18sp"
android:contentDescription="@string/read_dur_progress"
android:paddingRight="2dp"
android:src="@drawable/ic_folder_open"
app:tint="@color/tv_text_summary"
tools:ignore="RtlHardcoded,RtlSymmetry" />
<TextView
android:id="@+id/tv_toc"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:ellipsize="end"
android:includeFontPadding="false"
android:paddingRight="6dp"
android:singleLine="true"
android:text="@string/toc_s"
android:textColor="@color/tv_text_summary"
android:textSize="13sp"
tools:ignore="NestedWeights" />
<io.legado.app.ui.widget.text.AccentBgTextView
android:id="@+id/tv_toc_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:paddingLeft="5dp"
android:paddingRight="5dp"
android:text="@string/view_toc"
android:textSize="13sp"
app:radius="2dp" />
</LinearLayout>
</LinearLayout>
<io.legado.app.ui.widget.text.ScrollTextView
android:id="@+id/tv_intro"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:clickable="true"
android:focusable="true"
android:paddingLeft="8dp"
android:paddingBottom="8dp"
android:text="@string/book_intro"
android:textColor="@color/tv_text_secondary"
android:textSize="14sp"
android:visibility="visible" />
</LinearLayout>
</ScrollView>
<View
android:layout_marginBottom="1px"
android:layout_width="match_parent"
android:layout_height="8dp"
android:background="@color/background"></View>
<LinearLayout
android:id="@+id/fl_action"
android:layout_width="match_parent"
android:layout_height="50dp"
android:background="@color/background_menu"
android:orientation="horizontal"
app:layout_constraintBottom_toBottomOf="parent">
<TextView
android:id="@+id/tv_shelf"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:background="?attr/selectableItemBackground"
android:clickable="true"
android:focusable="true"
android:gravity="center"
android:includeFontPadding="false"
android:text="@string/remove_from_bookshelf"
android:textColor="@color/tv_text_default"
android:textSize="15sp" />
<io.legado.app.ui.widget.text.AccentBgTextView
android:id="@+id/tv_read"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:background="@drawable/selector_btn_accent_bg"
android:gravity="center"
android:includeFontPadding="false"
android:text="@string/reading"
android:textColor="@color/tv_text_button_nor"
android:textSize="15sp" />
</LinearLayout>
</LinearLayout>
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>

@ -64,6 +64,27 @@
</RelativeLayout> </RelativeLayout>
<ScrollView
android:background="@color/background"
android:layout_weight="1.0"
android:padding="0dp"
android:layout_height="0dp"
android:layout_width="match_parent"
android:scrollbarStyle="outsideInset"
android:scrollbars="vertical"
android:fillViewport="true"
android:fitsSystemWindows="false"
android:focusable="true" >
<LinearLayout
android:orientation="vertical"
android:paddingLeft="8dp"
android:paddingRight="8dp"
android:paddingBottom="8dp"
android:background="@color/background"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout <LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
@ -91,34 +112,13 @@
android:id="@+id/lb_kind" android:id="@+id/lb_kind"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginBottom="3dp" android:layout_marginBottom="6dp"
android:layout_gravity="center" android:layout_gravity="center"
android:gravity="center" android:gravity="center"
android:visibility="gone" /> android:visibility="gone" />
</LinearLayout> </LinearLayout>
<ScrollView
android:background="@color/background"
android:layout_weight="1.0"
android:padding="0dp"
android:layout_height="0dp"
android:layout_width="match_parent"
android:scrollbarStyle="outsideInset"
android:scrollbars="vertical"
android:fillViewport="true"
android:fitsSystemWindows="false"
android:focusable="true" >
<LinearLayout
android:orientation="vertical"
android:paddingLeft="8dp"
android:paddingRight="8dp"
android:paddingBottom="8dp"
android:background="@color/background"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout <LinearLayout
android:orientation="vertical" android:orientation="vertical"
android:paddingLeft="8dp" android:paddingLeft="8dp"
@ -202,7 +202,7 @@
android:paddingLeft="5dp" android:paddingLeft="5dp"
android:paddingRight="5dp" android:paddingRight="5dp"
android:text="@string/change_origin" android:text="@string/change_origin"
android:textSize="16sp" android:textSize="13sp"
app:radius="2dp" /> app:radius="2dp" />
</LinearLayout> </LinearLayout>
@ -241,6 +241,94 @@
</LinearLayout> </LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:orientation="horizontal"
android:paddingTop="3dp"
android:paddingBottom="3dp">
<ImageView
android:layout_width="18sp"
android:layout_height="18sp"
android:contentDescription="@string/read_dur_progress"
android:paddingRight="2dp"
android:src="@drawable/ic_groups"
app:tint="@color/tv_text_summary"
tools:ignore="RtlHardcoded,RtlSymmetry" />
<TextView
android:id="@+id/tv_group"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:ellipsize="end"
android:includeFontPadding="false"
android:paddingRight="6dp"
android:singleLine="true"
android:text="@string/group_s"
android:textColor="@color/tv_text_summary"
android:textSize="13sp"
tools:ignore="NestedWeights" />
<io.legado.app.ui.widget.text.AccentBgTextView
android:id="@+id/tv_change_group"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:paddingLeft="5dp"
android:paddingRight="5dp"
android:text="@string/change_group"
android:textSize="13sp"
app:radius="2dp" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:orientation="horizontal"
android:paddingTop="3dp"
android:paddingBottom="3dp">
<ImageView
android:layout_width="18sp"
android:layout_height="18sp"
android:contentDescription="@string/read_dur_progress"
android:paddingRight="2dp"
android:src="@drawable/ic_folder_open"
app:tint="@color/tv_text_summary"
tools:ignore="RtlHardcoded,RtlSymmetry" />
<TextView
android:id="@+id/tv_toc"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:ellipsize="end"
android:includeFontPadding="false"
android:paddingRight="6dp"
android:singleLine="true"
android:text="@string/toc_s"
android:textColor="@color/tv_text_summary"
android:textSize="13sp"
tools:ignore="NestedWeights" />
<io.legado.app.ui.widget.text.AccentBgTextView
android:id="@+id/tv_toc_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:paddingLeft="5dp"
android:paddingRight="5dp"
android:text="@string/view_toc"
android:textSize="13sp"
app:radius="2dp" />
</LinearLayout>
</LinearLayout> </LinearLayout>
<io.legado.app.ui.widget.text.ScrollTextView <io.legado.app.ui.widget.text.ScrollTextView
@ -254,47 +342,17 @@
android:textColor="@color/tv_text_secondary" android:textColor="@color/tv_text_secondary"
android:textSize="14sp" android:textSize="14sp"
android:paddingLeft="8dp" android:paddingLeft="8dp"
android:paddingBottom="8dp"
android:visibility="visible" /> android:visibility="visible" />
</LinearLayout> </LinearLayout>
</ScrollView> </ScrollView>
<LinearLayout <View
android:id="@+id/view_other"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/background"
android:orientation="vertical"
android:paddingTop="12dp"
android:paddingBottom="12dp"
app:layout_constraintBottom_toTopOf="@+id/fl_action"
app:layout_constraintTop_toBottomOf="@+id/view_info">
<TextView
android:id="@+id/tv_group"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="12dp"
android:singleLine="true"
android:clickable="true"
android:text="@string/group_s"
android:textColor="@color/tv_text_default"
android:textSize="16sp" />
<TextView
android:id="@+id/tv_toc"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="8dp"
android:padding="12dp" android:background="@color/background"></View>
android:background="?attr/selectableItemBackground"
android:singleLine="true"
android:clickable="true"
android:text="@string/toc_s"
android:textColor="@color/tv_text_default"
android:textSize="16sp" />
</LinearLayout>
<View <View
android:layout_width="match_parent" android:layout_width="match_parent"

@ -9,6 +9,12 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="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 <ImageView
android:id="@+id/cursor_left" android:id="@+id/cursor_left"
android:layout_width="wrap_content" android:layout_width="wrap_content"

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

@ -78,7 +78,8 @@
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginLeft="3dp" android:layout_marginLeft="3dp"
tools:ignore="RtlHardcoded,RtlSymmetry" /> android:textSize="10sp"
tools:ignore="RtlHardcoded,RtlSymmetry,SmallSp" />
</LinearLayout> </LinearLayout>

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

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

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<resources> <resources>
<string name="pk_auto_refresh">auto_refresh</string> <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_full_screen">full_screen</string>
<string name="pk_threads_num">threads_num</string> <string name="pk_threads_num">threads_num</string>
<string name="pk_user_agent">user_agent</string> <string name="pk_user_agent">user_agent</string>

@ -160,7 +160,7 @@
<string name="add_book_url">添加书籍网址</string> <string name="add_book_url">添加书籍网址</string>
<string name="background">背景</string> <string name="background">背景</string>
<string name="author">作者</string> <string name="author">作者</string>
<string name="author_show">作者:%s</string> <string name="author_show">作者: %s</string>
<string name="aloud_stop">朗读停止</string> <string name="aloud_stop">朗读停止</string>
<string name="clear_cache">清除缓存</string> <string name="clear_cache">清除缓存</string>
<string name="clear_cache_success">成功清理缓存</string> <string name="clear_cache_success">成功清理缓存</string>
@ -641,4 +641,10 @@
<string name="add_to_group">加入分组</string> <string name="add_to_group">加入分组</string>
<string name="save_image">保存图片</string> <string name="save_image">保存图片</string>
<string name="no_default_path">没有默认路径</string> <string name="no_default_path">没有默认路径</string>
<string name="change_group">设置分组</string>
<string name="view_toc">查看目录</string>
<string name="bar_elevation">导航栏阴影</string>
<string name="bar_elevation_s">当前阴影大小(elevation): %s</string>
<string name="btn_default_s">默认</string>
</resources> </resources>

@ -2,6 +2,14 @@
<androidx.preference.PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android" <androidx.preference.PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"> xmlns:app="http://schemas.android.com/apk/res-auto">
<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 <io.legado.app.ui.widget.prefs.NameListPreference
android:key="keep_light" android:key="keep_light"
android:defaultValue="0" android:defaultValue="0"

@ -26,6 +26,13 @@
android:title="@string/navigation_bar_color_change" android:title="@string/navigation_bar_color_change"
app:iconSpaceReserved="false" /> app:iconSpaceReserved="false" />
<androidx.preference.Preference
android:defaultValue="true"
android:key="barElevation"
android:summary="@string/bar_elevation_s"
android:title="@string/bar_elevation"
app:iconSpaceReserved="false" />
<androidx.preference.Preference <androidx.preference.Preference
android:key="defaultTheme" android:key="defaultTheme"
android:summary="@string/restore_default_theme" android:summary="@string/restore_default_theme"

Loading…
Cancel
Save