Merge pull request #10 from gedoor/master

merge
pull/441/head
口口吕 4 years ago committed by GitHub
commit 26035a36ec
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 4
      app/src/main/assets/defaultData/txtTocRule.json
  2. 9
      app/src/main/assets/updateLog.md
  3. 73
      app/src/main/java/io/legado/app/App.kt
  4. 4
      app/src/main/java/io/legado/app/constant/PreferKey.kt
  5. 27
      app/src/main/java/io/legado/app/help/BookHelp.kt
  6. 8
      app/src/main/java/io/legado/app/help/JsExtensions.kt
  7. 74
      app/src/main/java/io/legado/app/help/ThemeConfig.kt
  8. 15
      app/src/main/java/io/legado/app/help/http/HttpHelper.kt
  9. 15
      app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeRule.kt
  10. 24
      app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeUrl.kt
  11. 3
      app/src/main/java/io/legado/app/ui/about/AboutFragment.kt
  12. 9
      app/src/main/java/io/legado/app/ui/book/explore/ExploreShowActivity.kt
  13. 12
      app/src/main/java/io/legado/app/ui/book/read/ReadBookActivity.kt
  14. 12
      app/src/main/java/io/legado/app/ui/book/read/ReadBookActivityHelp.kt
  15. 5
      app/src/main/java/io/legado/app/ui/book/read/ReadMenu.kt
  16. 42
      app/src/main/java/io/legado/app/ui/book/read/config/PageKeyDialog.kt
  17. 29
      app/src/main/java/io/legado/app/ui/book/read/page/ContentTextView.kt
  18. 8
      app/src/main/java/io/legado/app/ui/book/read/page/ContentView.kt
  19. 4
      app/src/main/java/io/legado/app/ui/config/ThemeConfigFragment.kt
  20. 5
      app/src/main/java/io/legado/app/ui/widget/ArcView.kt
  21. 5
      app/src/main/java/io/legado/app/ui/widget/BatteryView.kt
  22. 5
      app/src/main/java/io/legado/app/ui/widget/DetailSeekBar.kt
  23. 5
      app/src/main/java/io/legado/app/ui/widget/LabelsBar.kt
  24. 5
      app/src/main/java/io/legado/app/ui/widget/SearchView.kt
  25. 5
      app/src/main/java/io/legado/app/ui/widget/SelectActionBar.kt
  26. 3
      app/src/main/java/io/legado/app/ui/widget/ShadowLayout.kt
  27. 5
      app/src/main/java/io/legado/app/ui/widget/TitleBar.kt
  28. 5
      app/src/main/java/io/legado/app/ui/widget/anima/RefreshProgressBar.kt
  29. 21
      app/src/main/java/io/legado/app/ui/widget/anima/RotateLoading.kt
  30. 22
      app/src/main/java/io/legado/app/ui/widget/anima/explosion_field/ExplosionView.kt
  31. 5
      app/src/main/java/io/legado/app/ui/widget/dynamiclayout/DynamicFrameLayout.kt
  32. 6
      app/src/main/java/io/legado/app/ui/widget/image/CircleImageView.kt
  33. 6
      app/src/main/java/io/legado/app/ui/widget/image/CoverImageView.kt
  34. 5
      app/src/main/java/io/legado/app/ui/widget/image/FilletImageView.kt
  35. 5
      app/src/main/java/io/legado/app/ui/widget/image/PhotoView.kt
  36. 13
      app/src/main/java/io/legado/app/ui/widget/recycler/LoadMoreView.kt
  37. 33
      app/src/main/java/io/legado/app/ui/widget/seekbar/VerticalSeekBar.kt
  38. 5
      app/src/main/java/io/legado/app/ui/widget/seekbar/VerticalSeekBarWrapper.kt
  39. 6
      app/src/main/java/io/legado/app/ui/widget/text/AccentBgTextView.kt
  40. 5
      app/src/main/java/io/legado/app/ui/widget/text/AutoCompleteTextView.kt
  41. 6
      app/src/main/java/io/legado/app/ui/widget/text/BadgeView.kt
  42. 15
      app/src/main/java/io/legado/app/ui/widget/text/InertiaScrollTextView.kt
  43. 2
      app/src/main/java/io/legado/app/utils/ContextExtensions.kt
  44. 9
      app/src/main/res/layout/dialog_page_key.xml
  45. 2
      app/src/main/res/values-zh-rHK/strings.xml
  46. 2
      app/src/main/res/values-zh-rTW/strings.xml
  47. 2
      app/src/main/res/values-zh/strings.xml
  48. 2
      app/src/main/res/values/strings.xml

@ -24,7 +24,7 @@
"id": -4,
"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
},
{
@ -125,4 +125,4 @@
"rule": "^.{1,20}[((][\\d零一二两三四五六七八九十百千万壹贰叁肆伍陆柒捌玖拾佰仟]{1,8}[))][  \t]{0,4}$",
"serialNumber": 17
}
]
]

@ -3,8 +3,15 @@
* 关注合作公众号 **[小说拾遗]()** 获取好看的小说。
* 旧版数据导入教程:先在旧版阅读(2.x)中进行备份,然后在新版阅读(3.x)【我的】->【备份与恢复】,选择【导入旧版本数据】。
**2020/10/20**
**2020/10/23**
* 修复选择错误的bug
* 修复长图最后一张不能滚动的bug
* js添加java.getCookie(sourceUrl)来获取登录后的cookie by [AndyBernie](https://github.com/AndyBernie)
* 修复简繁转换没有处理标题
**2020/10/21**
* 默认分组无书籍时自动隐藏
* 自定义翻页按键支持多个按键
**2020/10/19**
* 优化分组管理

@ -4,10 +4,8 @@ import android.app.NotificationChannel
import android.app.NotificationManager
import android.content.Context
import android.content.res.Configuration
import android.graphics.Color
import android.os.Build
import android.provider.Settings
import android.util.Log
import androidx.annotation.RequiresApi
import androidx.appcompat.app.AppCompatDelegate
import androidx.multidex.MultiDexApplication
@ -16,14 +14,10 @@ import io.legado.app.constant.AppConst.channelIdDownload
import io.legado.app.constant.AppConst.channelIdReadAloud
import io.legado.app.constant.AppConst.channelIdWeb
import io.legado.app.constant.EventBus
import io.legado.app.constant.PreferKey
import io.legado.app.data.AppDatabase
import io.legado.app.help.ActivityHelp
import io.legado.app.help.AppConfig
import io.legado.app.help.CrashHandler
import io.legado.app.help.ReadBookConfig
import io.legado.app.lib.theme.ThemeStore
import io.legado.app.utils.*
import io.legado.app.help.*
import io.legado.app.utils.LanguageUtils
import io.legado.app.utils.postEvent
@Suppress("DEPRECATION")
class App : MultiDexApplication() {
@ -72,68 +66,9 @@ class App : MultiDexApplication() {
}
}
/**
* 更新主题
*/
fun applyTheme() {
when {
AppConfig.isEInkMode -> {
ThemeStore.editTheme(this)
.coloredNavigationBar(true)
.primaryColor(Color.WHITE)
.accentColor(Color.BLACK)
.backgroundColor(Color.WHITE)
.bottomBackground(Color.WHITE)
.apply()
}
AppConfig.isNightTheme -> {
val primary =
getPrefInt(PreferKey.cNPrimary, getCompatColor(R.color.md_blue_grey_600))
val accent =
getPrefInt(PreferKey.cNAccent, getCompatColor(R.color.md_deep_orange_800))
var background =
getPrefInt(PreferKey.cNBackground, getCompatColor(R.color.md_grey_900))
if (ColorUtils.isColorLight(background)) {
background = getCompatColor(R.color.md_grey_900)
putPrefInt(PreferKey.cNBackground, background)
}
val bBackground =
getPrefInt(PreferKey.cNBBackground, getCompatColor(R.color.md_grey_850))
ThemeStore.editTheme(this)
.coloredNavigationBar(true)
.primaryColor(ColorUtils.withAlpha(primary, 1f))
.accentColor(ColorUtils.withAlpha(accent, 1f))
.backgroundColor(ColorUtils.withAlpha(background, 1f))
.bottomBackground(ColorUtils.withAlpha(bBackground, 1f))
.apply()
}
else -> {
val primary =
getPrefInt(PreferKey.cPrimary, getCompatColor(R.color.md_brown_500))
val accent =
getPrefInt(PreferKey.cAccent, getCompatColor(R.color.md_red_600))
var background =
getPrefInt(PreferKey.cBackground, getCompatColor(R.color.md_grey_100))
if (!ColorUtils.isColorLight(background)) {
background = getCompatColor(R.color.md_grey_100)
putPrefInt(PreferKey.cBackground, background)
}
val bBackground =
getPrefInt(PreferKey.cBBackground, getCompatColor(R.color.md_grey_200))
ThemeStore.editTheme(this)
.coloredNavigationBar(true)
.primaryColor(ColorUtils.withAlpha(primary, 1f))
.accentColor(ColorUtils.withAlpha(accent, 1f))
.backgroundColor(ColorUtils.withAlpha(background, 1f))
.bottomBackground(ColorUtils.withAlpha(bBackground, 1f))
.apply()
}
}
}
fun applyDayNight() {
ReadBookConfig.upBg()
applyTheme()
ThemeConfig.applyTheme(this)
initNightMode()
postEvent(EventBus.RECREATE, "")
}

@ -12,8 +12,8 @@ object PreferKey {
const val speakEngine = "speakEngine"
const val readAloudByPage = "readAloudByPage"
const val ttsSpeechRate = "ttsSpeechRate"
const val prevKey = "prevKeyCode"
const val nextKey = "nextKeyCode"
const val prevKeys = "prevKeyCodes"
const val nextKeys = "nextKeyCodes"
const val showRss = "showRss"
const val bookshelfLayout = "bookshelfLayout"
const val bookshelfSort = "bookshelfSort"

@ -101,7 +101,7 @@ object BookHelp {
downloadImages.add(src)
val analyzeUrl = AnalyzeUrl(src)
try {
analyzeUrl.getImageBytes(book.origin)?.let {
analyzeUrl.getResponseBytes(book.origin)?.let {
FileUtils.createFileIfNotExist(
downloadDir,
cacheFolderName,
@ -324,7 +324,8 @@ object BookHelp {
content: String,
enableReplace: Boolean,
): List<String> {
var c = content
var title1 = title
var content1 = content
if (enableReplace) {
synchronized(this) {
if (bookName != name || bookOrigin != origin) {
@ -341,10 +342,10 @@ object BookHelp {
item.pattern.let {
if (it.isNotEmpty()) {
try {
c = if (item.isRegex) {
c.replace(it.toRegex(), item.replacement)
content1 = if (item.isRegex) {
content1.replace(it.toRegex(), item.replacement)
} else {
c.replace(it, item.replacement)
content1.replace(it, item.replacement)
}
} catch (e: Exception) {
withContext(Main) {
@ -357,8 +358,14 @@ object BookHelp {
}
try {
when (AppConfig.chineseConverterType) {
1 -> c = HanLP.convertToSimplifiedChinese(c)
2 -> c = HanLP.convertToTraditionalChinese(c)
1 -> {
title1 = HanLP.convertToSimplifiedChinese(title1)
content1 = HanLP.convertToSimplifiedChinese(content1)
}
2 -> {
title1 = HanLP.convertToTraditionalChinese(title1)
content1 = HanLP.convertToTraditionalChinese(content1)
}
}
} catch (e: Exception) {
withContext(Main) {
@ -366,11 +373,11 @@ object BookHelp {
}
}
val contents = arrayListOf<String>()
c.split("\n").forEach {
content1.split("\n").forEach {
val str = it.replace("^[\\n\\s\\r]+".toRegex(), "")
if (contents.isEmpty()) {
contents.add(title)
if (str != title && str.isNotEmpty()) {
contents.add(title1)
if (str != title1 && str.isNotEmpty()) {
contents.add("${ReadBookConfig.paragraphIndent}$str")
}
} else if (str.isNotEmpty()) {

@ -4,6 +4,7 @@ import android.util.Base64
import androidx.annotation.Keep
import io.legado.app.constant.AppConst.dateFormat
import io.legado.app.help.http.SSLHelper
import io.legado.app.help.http.CookieStore
import io.legado.app.model.analyzeRule.AnalyzeUrl
import io.legado.app.utils.*
import org.jsoup.Connection
@ -119,6 +120,13 @@ interface JsExtensions {
.execute()
}
/**
*js实现读取cookie
*/
fun getCookie(tag: String): String {
return CookieStore.getCookie(tag)
}
/**
* js实现解码,不能删
*/

@ -7,6 +7,7 @@ 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.lib.theme.ThemeStore
import io.legado.app.utils.*
import java.io.File
@ -14,16 +15,16 @@ object ThemeConfig {
const val configFileName = "themeConfig.json"
val configFilePath = FileUtils.getPath(App.INSTANCE.filesDir, configFileName)
val configList = arrayListOf<Config>()
init {
upConfig()
val configList: ArrayList<Config> by lazy {
val cList = getConfigs() ?: DefaultData.defaultThemeConfigs
ArrayList(cList)
}
fun upConfig() {
(getConfigs() ?: DefaultData.defaultThemeConfigs).let {
configList.clear()
configList.addAll(it)
getConfigs()?.let {
it.forEach { config ->
addConfig(config)
}
}
}
@ -137,6 +138,65 @@ object ThemeConfig {
addConfig(config)
}
/**
* 更新主题
*/
fun applyTheme(context: Context) = with(context) {
when {
AppConfig.isEInkMode -> {
ThemeStore.editTheme(this)
.coloredNavigationBar(true)
.primaryColor(Color.WHITE)
.accentColor(Color.BLACK)
.backgroundColor(Color.WHITE)
.bottomBackground(Color.WHITE)
.apply()
}
AppConfig.isNightTheme -> {
val primary =
getPrefInt(PreferKey.cNPrimary, getCompatColor(R.color.md_blue_grey_600))
val accent =
getPrefInt(PreferKey.cNAccent, getCompatColor(R.color.md_deep_orange_800))
var background =
getPrefInt(PreferKey.cNBackground, getCompatColor(R.color.md_grey_900))
if (ColorUtils.isColorLight(background)) {
background = getCompatColor(R.color.md_grey_900)
putPrefInt(PreferKey.cNBackground, background)
}
val bBackground =
getPrefInt(PreferKey.cNBBackground, getCompatColor(R.color.md_grey_850))
ThemeStore.editTheme(this)
.coloredNavigationBar(true)
.primaryColor(ColorUtils.withAlpha(primary, 1f))
.accentColor(ColorUtils.withAlpha(accent, 1f))
.backgroundColor(ColorUtils.withAlpha(background, 1f))
.bottomBackground(ColorUtils.withAlpha(bBackground, 1f))
.apply()
}
else -> {
val primary =
getPrefInt(PreferKey.cPrimary, getCompatColor(R.color.md_brown_500))
val accent =
getPrefInt(PreferKey.cAccent, getCompatColor(R.color.md_red_600))
var background =
getPrefInt(PreferKey.cBackground, getCompatColor(R.color.md_grey_100))
if (!ColorUtils.isColorLight(background)) {
background = getCompatColor(R.color.md_grey_100)
putPrefInt(PreferKey.cBackground, background)
}
val bBackground =
getPrefInt(PreferKey.cBBackground, getCompatColor(R.color.md_grey_200))
ThemeStore.editTheme(this)
.coloredNavigationBar(true)
.primaryColor(ColorUtils.withAlpha(primary, 1f))
.accentColor(ColorUtils.withAlpha(accent, 1f))
.backgroundColor(ColorUtils.withAlpha(background, 1f))
.bottomBackground(ColorUtils.withAlpha(bBackground, 1f))
.apply()
}
}
}
@Keep
class Config(
var themeName: String,

@ -48,21 +48,6 @@ object HttpHelper {
return null
}
fun getBytes(
url: String,
queryMap: Map<String, String>,
headers: Map<String, String>
): ByteArray? {
NetworkUtils.getBaseUrl(url)?.let { baseUrl ->
return getByteRetrofit(baseUrl)
.create(HttpGetApi::class.java)
.getMapByte(url, queryMap, headers)
.execute()
.body()
}
return null
}
suspend fun simpleGetAsync(url: String, encode: String? = null): String? {
NetworkUtils.getBaseUrl(url)?.let { baseUrl ->
val response = getApiService<HttpGetApi>(baseUrl, encode)

@ -649,16 +649,12 @@ class AnalyzeRule(var book: BaseBook? = null) : JsExtensions {
* 章节数转数字
*/
fun toNumChapter(s: String?): String? {
if (s == null) {
return null
}
val pattern = Pattern.compile("(第)(.+?)(章)")
val matcher = pattern.matcher(s)
return if (matcher.find()) {
matcher.group(1)!! + StringUtils.stringToInt(matcher.group(2)) + matcher.group(3)
} else {
s
s ?: return null
val matcher = titleNumPattern.matcher(s)
if (matcher.find()) {
return "${matcher.group(1)}${StringUtils.stringToInt(matcher.group(2))}${matcher.group(3)}"
}
return s
}
companion object {
@ -667,6 +663,7 @@ class AnalyzeRule(var book: BaseBook? = null) : JsExtensions {
private val evalPattern =
Pattern.compile("@get:\\{[^}]+?\\}|\\{\\{[\\w\\W]*?\\}\\}", Pattern.CASE_INSENSITIVE)
private val regexPattern = Pattern.compile("\\$\\d{1,2}")
private val titleNumPattern = Pattern.compile("(第)(.+?)(章)")
}
}

@ -188,9 +188,9 @@ class AnalyzeUrl(
GSON.fromJsonObject<Map<String, String>>(headers)
?.let { headerMap.putAll(it) }
}
headerMap[UA_NAME] ?: let {
headerMap[UA_NAME] = userAgent
}
}
headerMap[UA_NAME] ?: let {
headerMap[UA_NAME] = userAgent
}
option.charset?.let { charset = it }
option.body?.let {
@ -281,7 +281,7 @@ class AnalyzeUrl(
fun getResponse(tag: String): Call<String> {
val cookie = CookieStore.getCookie(tag)
if (cookie.isNotEmpty()) {
headerMap["Cookie"] = cookie
headerMap["Cookie"] += ";${cookie}"
}
return when {
method == RequestMethod.POST -> {
@ -324,7 +324,7 @@ class AnalyzeUrl(
}
val cookie = CookieStore.getCookie(tag)
if (cookie.isNotEmpty()) {
headerMap["Cookie"] = cookie
headerMap["Cookie"] += ";${cookie}"
}
val res = when {
method == RequestMethod.POST -> {
@ -352,23 +352,11 @@ class AnalyzeUrl(
return Res(NetworkUtils.getUrl(res), res.body())
}
fun getImageBytes(tag: String): ByteArray? {
val cookie = CookieStore.getCookie(tag)
if (cookie.isNotEmpty()) {
headerMap["Cookie"] += cookie
}
return if (fieldMap.isEmpty()) {
HttpHelper.getBytes(url, mapOf(), headerMap)
} else {
HttpHelper.getBytes(url, fieldMap, headerMap)
}
}
suspend fun getResponseBytes(tag: String? = null): ByteArray? {
if (tag != null) {
val cookie = CookieStore.getCookie(tag)
if (cookie.isNotEmpty()) {
headerMap["Cookie"] = cookie
headerMap["Cookie"] += ";${cookie}"
}
}
val response = when {

@ -29,7 +29,8 @@ class AboutFragment : PreferenceFragmentCompat() {
Pair("(QQ群3)981838750", "g_Sgmp2nQPKqcZQ5qPcKLHziwX_mpps9"),
Pair("(QQ群4)256929088", "czEJPLDnT4Pd9SKQ6RoRVzKhDxLchZrO"),
Pair("(QQ群5)811843556", "zKZ2UYGZ7o5CzcA6ylxzlqi21si_iqaX"),
Pair("(QQ群6)870270970", "FeCF8iSxfQbe90HPvGsvcqs5P5oSeY5n")
Pair("(QQ群6)870270970", "FeCF8iSxfQbe90HPvGsvcqs5P5oSeY5n"),
Pair("(QQ群7)15987187", "S2g2TMD0LGd3sefUADd1AbyPEW2o2XfC")
)
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {

@ -38,6 +38,13 @@ class ExploreShowActivity : VMBaseActivity<ExploreShowViewModel>(R.layout.activi
loadMoreView = LoadMoreView(this)
adapter.addFooterView(loadMoreView)
loadMoreView.startLoad()
loadMoreView.setOnClickListener {
if (!isLoading) {
loadMoreView.hasMore()
scrollToBottom()
isLoading = true
}
}
recycler_view.addOnScrollListener(object : RecyclerView.OnScrollListener() {
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
super.onScrolled(recyclerView, dx, dy)
@ -75,4 +82,4 @@ class ExploreShowActivity : VMBaseActivity<ExploreShowViewModel>(R.layout.activi
Pair("author", book.author)
)
}
}
}

@ -313,30 +313,30 @@ class ReadBookActivity : VMBaseActivity<ReadBookViewModel>(R.layout.activity_boo
* 按键事件
*/
override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean {
when (keyCode) {
getPrefInt(PreferKey.prevKey) -> {
when {
ReadBookActivityHelp.isPrevKey(this, keyCode) -> {
if (keyCode != KeyEvent.KEYCODE_UNKNOWN) {
page_view.pageDelegate?.keyTurnPage(PageDelegate.Direction.PREV)
return true
}
}
getPrefInt(PreferKey.nextKey) -> {
ReadBookActivityHelp.isNextKey(this, keyCode) -> {
if (keyCode != KeyEvent.KEYCODE_UNKNOWN) {
page_view.pageDelegate?.keyTurnPage(PageDelegate.Direction.NEXT)
return true
}
}
KeyEvent.KEYCODE_VOLUME_UP -> {
keyCode == KeyEvent.KEYCODE_VOLUME_UP -> {
if (volumeKeyPage(PageDelegate.Direction.PREV)) {
return true
}
}
KeyEvent.KEYCODE_VOLUME_DOWN -> {
keyCode == KeyEvent.KEYCODE_VOLUME_DOWN -> {
if (volumeKeyPage(PageDelegate.Direction.NEXT)) {
return true
}
}
KeyEvent.KEYCODE_SPACE -> {
keyCode == KeyEvent.KEYCODE_SPACE -> {
page_view.pageDelegate?.keyTurnPage(PageDelegate.Direction.NEXT)
return true
}

@ -13,6 +13,7 @@ import android.view.WindowManager
import android.widget.EditText
import io.legado.app.App
import io.legado.app.R
import io.legado.app.constant.PreferKey
import io.legado.app.data.entities.Bookmark
import io.legado.app.help.AppConfig
import io.legado.app.help.ReadBookConfig
@ -24,6 +25,7 @@ import io.legado.app.service.help.CacheBook
import io.legado.app.service.help.ReadBook
import io.legado.app.ui.widget.text.AutoCompleteTextView
import io.legado.app.utils.applyTint
import io.legado.app.utils.getPrefString
import io.legado.app.utils.requestInputMethod
import kotlinx.android.synthetic.main.dialog_download_choice.view.*
import kotlinx.android.synthetic.main.dialog_edit_text.view.*
@ -186,4 +188,14 @@ object ReadBookActivityHelp {
cancelButton()
}.show().applyTint()
}
fun isPrevKey(context: Context, keyCode: Int): Boolean {
val prevKeysStr = context.getPrefString(PreferKey.prevKeys)
return prevKeysStr?.split(",")?.contains(keyCode.toString()) ?: false
}
fun isNextKey(context: Context, keyCode: Int): Boolean {
val nextKeysStr = context.getPrefString(PreferKey.nextKeys)
return nextKeysStr?.split(",")?.contains(keyCode.toString()) ?: false
}
}

@ -26,9 +26,8 @@ import org.jetbrains.anko.sdk27.listeners.onLongClick
*/
class ReadMenu @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
defStyleAttr: Int = 0
) : FrameLayout(context, attrs, defStyleAttr) {
attrs: AttributeSet? = null
) : FrameLayout(context, attrs) {
var cnaShowMenu: Boolean = false
private val callBack: CallBack? get() = activity as? CallBack
private lateinit var menuTopIn: Animation

@ -6,10 +6,9 @@ import android.view.KeyEvent
import io.legado.app.R
import io.legado.app.constant.PreferKey
import io.legado.app.lib.theme.backgroundColor
import io.legado.app.utils.getPrefInt
import io.legado.app.utils.getPrefString
import io.legado.app.utils.hideSoftInput
import io.legado.app.utils.putPrefInt
import io.legado.app.utils.removePref
import io.legado.app.utils.putPrefString
import kotlinx.android.synthetic.main.dialog_page_key.*
import org.jetbrains.anko.sdk27.listeners.onClick
@ -19,33 +18,34 @@ class PageKeyDialog(context: Context) : Dialog(context, R.style.AppTheme_AlertDi
init {
setContentView(R.layout.dialog_page_key)
content_view.setBackgroundColor(context.backgroundColor)
et_prev.setText(context.getPrefInt(PreferKey.prevKey).toString())
et_next.setText(context.getPrefInt(PreferKey.nextKey).toString())
et_prev.setText(context.getPrefString(PreferKey.prevKeys))
et_next.setText(context.getPrefString(PreferKey.nextKeys))
tv_ok.onClick {
val prevKey = et_prev.text?.toString()
if (prevKey.isNullOrEmpty()) {
context.removePref(PreferKey.prevKey)
} else {
context.putPrefInt(PreferKey.prevKey, prevKey.toInt())
}
val nextKey = et_next.text?.toString()
if (nextKey.isNullOrEmpty()) {
context.removePref(PreferKey.nextKey)
} else {
context.putPrefInt(PreferKey.nextKey, nextKey.toInt())
}
context.putPrefString(PreferKey.prevKeys, et_prev.text?.toString())
context.putPrefString(PreferKey.nextKeys, et_next.text?.toString())
dismiss()
}
}
override fun onKeyDown(keyCode: Int, event: KeyEvent): Boolean {
if (keyCode != KeyEvent.KEYCODE_BACK) {
if (keyCode != KeyEvent.KEYCODE_BACK && keyCode != KeyEvent.KEYCODE_DEL) {
if (et_prev.hasFocus()) {
et_prev.setText(keyCode.toString())
val editableText = et_prev.editableText
if (editableText.isEmpty() or editableText.endsWith(",")) {
editableText.append(keyCode.toString())
} else {
editableText.append(",").append(keyCode.toString())
}
return true
} else if (et_next.hasFocus()) {
et_next.setText(keyCode.toString())
val editableText = et_next.editableText
if (editableText.isEmpty() or editableText.endsWith(",")) {
editableText.append(keyCode.toString())
} else {
editableText.append(",").append(keyCode.toString())
}
return true
}
return true
}
return super.onKeyDown(keyCode, event)
}

@ -23,7 +23,9 @@ import io.legado.app.utils.getCompatColor
import io.legado.app.utils.getPrefBoolean
import kotlinx.coroutines.CoroutineScope
/**
* 阅读内容界面
*/
class ContentTextView(context: Context, attrs: AttributeSet?) : View(context, attrs) {
var selectAble = context.getPrefBoolean(PreferKey.textSelectAble)
var upView: ((TextPage) -> Unit)? = null
@ -41,7 +43,6 @@ class ContentTextView(context: Context, attrs: AttributeSet?) : View(context, at
//滚动参数
private val pageFactory: TextPageFactory get() = callBack.pageFactory
private val maxScrollOffset = 100f
private var pageOffset = 0f
init {
@ -173,17 +174,13 @@ class ContentTextView(context: Context, attrs: AttributeSet?) : View(context, at
*/
fun onScroll(mOffset: Float) {
if (mOffset == 0f) return
var offset = mOffset
if (offset > maxScrollOffset) {
offset = maxScrollOffset
} else if (offset < -maxScrollOffset) {
offset = -maxScrollOffset
}
pageOffset += offset
pageOffset += mOffset
if (!pageFactory.hasPrev() && pageOffset > 0) {
pageOffset = 0f
} else if (!pageFactory.hasNext() && pageOffset < 0) {
} else if (!pageFactory.hasNext()
&& pageOffset < 0
&& pageOffset + textPage.height < ChapterProvider.visibleHeight
) {
pageOffset = 0f
} else if (pageOffset > 0) {
pageFactory.moveToPrev(false)
@ -263,7 +260,10 @@ class ContentTextView(context: Context, attrs: AttributeSet?) : View(context, at
for ((charIndex, textChar) in textLine.textChars.withIndex()) {
if (x > textChar.start && x < textChar.end) {
if (selectStart[0] != relativePos || selectStart[1] != lineIndex || selectStart[2] != charIndex) {
if (selectToInt(relativePos, lineIndex, charIndex) > selectToInt(selectEnd)) {
if (selectToInt(relativePos, lineIndex, charIndex) > selectToInt(
selectEnd
)
) {
return
}
selectStart[0] = relativePos
@ -306,7 +306,10 @@ class ContentTextView(context: Context, attrs: AttributeSet?) : View(context, at
if (x > textChar.start && x < textChar.end) {
Log.e("char", "$relativePos $lineIndex $charIndex")
if (selectEnd[0] != relativePos || selectEnd[1] != lineIndex || selectEnd[2] != charIndex) {
if (selectToInt(relativePos, lineIndex, charIndex) < selectToInt(selectStart)) {
if (selectToInt(relativePos, lineIndex, charIndex) < selectToInt(
selectStart
)
) {
return
}
selectEnd[0] = relativePos

@ -33,9 +33,11 @@ class ContentView(context: Context) : FrameLayout(context) {
private var tvBookName: BatteryView? = null
val headerHeight: Int
get() = if (ReadBookConfig.hideStatusBar) {
if (ll_header.isGone) 0 else ll_header.height
} else context.statusBarHeight
get() {
val h1 = if (ReadBookConfig.hideStatusBar) 0 else context.statusBarHeight
val h2 = if (ll_header.isGone) 0 else ll_header.height
return h1 + h2
}
init {
//设置背景防止切换背景时文字重叠

@ -177,7 +177,7 @@ class ThemeConfigFragment : BasePreferenceFragment(),
@SuppressLint("InflateParams")
private fun saveThemeAlert(key: String) {
alert("主题名称") {
alert(R.string.theme_name) {
var editText: AutoCompleteTextView? = null
customView {
layoutInflater.inflate(R.layout.dialog_edit_text, null).apply {
@ -203,7 +203,7 @@ class ThemeConfigFragment : BasePreferenceFragment(),
private fun upTheme(isNightTheme: Boolean) {
if (AppConfig.isNightTheme == isNightTheme) {
listView.post {
App.INSTANCE.applyTheme()
ThemeConfig.applyTheme(requireContext())
recreateActivities()
}
}

@ -8,9 +8,8 @@ import io.legado.app.R
class ArcView @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
defStyleAttr: Int = 0
) : View(context, attrs, defStyleAttr) {
attrs: AttributeSet? = null
) : View(context, attrs) {
private var mWidth = 0
private var mHeight = 0

@ -12,7 +12,10 @@ import androidx.appcompat.widget.AppCompatTextView
import io.legado.app.utils.dp
import java.io.File
class BatteryView(context: Context, attrs: AttributeSet?) : AppCompatTextView(context, attrs) {
class BatteryView @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null
) : AppCompatTextView(context, attrs) {
private val batteryPaint = Paint()
private val outFrame = Rect()
private val polar = Rect()

@ -13,7 +13,10 @@ import io.legado.app.utils.progressAdd
import kotlinx.android.synthetic.main.view_detail_seek_bar.view.*
import org.jetbrains.anko.sdk27.listeners.onClick
class DetailSeekBar(context: Context, attrs: AttributeSet?) : FrameLayout(context, attrs),
class DetailSeekBar @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null
) : FrameLayout(context, attrs),
SeekBar.OnSeekBarChangeListener {
private val isBottomBackground: Boolean
var valueFormat: ((progress: Int) -> String)? = null

@ -8,7 +8,10 @@ import io.legado.app.ui.widget.text.AccentBgTextView
import io.legado.app.utils.dp
@Suppress("unused", "MemberVisibilityCanBePrivate")
class LabelsBar(context: Context, attrs: AttributeSet?) : LinearLayout(context, attrs) {
class LabelsBar @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null
) : LinearLayout(context, attrs) {
private val unUsedViews = arrayListOf<TextView>()
private val usedViews = arrayListOf<TextView>()

@ -18,9 +18,8 @@ import io.legado.app.R
class SearchView @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
defStyleAttr: Int = 0
) : SearchView(context, attrs, defStyleAttr) {
attrs: AttributeSet? = null
) : SearchView(context, attrs) {
private var mSearchHintIcon: Drawable? = null
private var textView: TextView? = null

@ -17,7 +17,10 @@ import kotlinx.android.synthetic.main.view_select_action_bar.view.*
import org.jetbrains.anko.sdk27.listeners.onClick
@Suppress("unused")
class SelectActionBar(context: Context, attrs: AttributeSet?) : FrameLayout(context, attrs) {
class SelectActionBar @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null
) : FrameLayout(context, attrs) {
private var callBack: CallBack? = null
private var selMenu: PopupMenu? = null

@ -14,11 +14,10 @@ import io.legado.app.utils.getCompatColor
/**
* ShadowLayout.java
*
*
* Created by lijiankun on 17/8/11.
*/
@Suppress("unused")
class ShadowLayout(
class ShadowLayout @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null
) : RelativeLayout(context, attrs) {

@ -22,7 +22,10 @@ import org.jetbrains.anko.bottomPadding
import org.jetbrains.anko.topPadding
@Suppress("unused")
class TitleBar(context: Context, attrs: AttributeSet?) : AppBarLayout(context, attrs) {
class TitleBar @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null
) : AppBarLayout(context, attrs) {
val toolbar: Toolbar
val menu: Menu

@ -14,9 +14,8 @@ import io.legado.app.R
@Suppress("unused", "MemberVisibilityCanBePrivate")
class RefreshProgressBar @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
defStyleAttr: Int = 0
) : View(context, attrs, defStyleAttr) {
attrs: AttributeSet? = null
) : View(context, attrs) {
private var a = 1
private var durProgress = 0
private var secondDurProgress = 0

@ -18,9 +18,12 @@ import io.legado.app.utils.dp
* Created by Victor on 2015/4/28.
*/
@Suppress("MemberVisibilityCanBePrivate")
class RotateLoading : View {
class RotateLoading @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null
) : View(context, attrs) {
private lateinit var mPaint: Paint
private var mPaint: Paint
private var loadingRectF: RectF? = null
private var shadowRectF: RectF? = null
@ -55,19 +58,7 @@ class RotateLoading : View {
private val hidden = Runnable { this.stopInternal() }
constructor(context: Context) : super(context) {
initView(context, null)
}
constructor(context: Context, attrs: AttributeSet) : super(context, attrs) {
initView(context, attrs)
}
constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr) {
initView(context, attrs)
}
private fun initView(context: Context, attrs: AttributeSet?) {
init {
loadingColor = context.accentColor
thisWidth = DEFAULT_WIDTH.dp
shadowPosition = DEFAULT_SHADOW_POSITION.dp

@ -30,7 +30,8 @@ import java.util.*
@Suppress("unused")
class ExplosionView : View {
class ExplosionView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null) :
View(context, attrs) {
private var customDuration = ExplosionAnimator.DEFAULT_DURATION
private var idPlayAnimationEffect = 0
@ -40,24 +41,7 @@ class ExplosionView : View {
private val mExplosions = ArrayList<ExplosionAnimator>()
private val mExpandInset = IntArray(2)
constructor(context: Context) : super(context) {
init()
}
constructor(context: Context, attrs: AttributeSet) : super(context, attrs) {
init()
}
constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(
context,
attrs,
defStyleAttr
) {
init()
}
private fun init() {
init {
Arrays.fill(mExpandInset, Utils.dp2Px(32))
}

@ -13,7 +13,10 @@ import io.legado.app.R
import kotlinx.android.synthetic.main.view_dynamic.view.*
@Suppress("unused")
class DynamicFrameLayout(context: Context, attrs: AttributeSet?) : FrameLayout(context, attrs), ViewSwitcher {
class DynamicFrameLayout @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null
) : FrameLayout(context, attrs), ViewSwitcher {
private var errorView: View? = null
private var errorImage: AppCompatImageView? = null

@ -25,8 +25,10 @@ import kotlin.math.min
import kotlin.math.pow
@Suppress("unused", "MemberVisibilityCanBePrivate")
class CircleImageView(context: Context, attrs: AttributeSet) :
AppCompatImageView(context, attrs) {
class CircleImageView @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null
) : AppCompatImageView(context, attrs) {
private val mDrawableRect = RectF()
private val mBorderRect = RectF()

@ -22,12 +22,10 @@ import io.legado.app.utils.getPrefString
@Suppress("unused")
class CoverImageView @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
defStyleAttr: Int = 0
attrs: AttributeSet? = null
) : androidx.appcompat.widget.AppCompatImageView(
context,
attrs,
defStyleAttr
attrs
) {
internal var width: Float = 0.toFloat()
internal var height: Float = 0.toFloat()

@ -12,9 +12,8 @@ import kotlin.math.max
class FilletImageView @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
defStyleAttr: Int = 0
) : AppCompatImageView(context, attrs, defStyleAttr) {
attrs: AttributeSet? = null
) : AppCompatImageView(context, attrs) {
internal var width: Float = 0.toFloat()
internal var height: Float = 0.toFloat()
private var leftTopRadius: Int = 0

@ -27,9 +27,8 @@ import kotlin.math.roundToInt
@Suppress("UNUSED_PARAMETER", "unused", "MemberVisibilityCanBePrivate", "PropertyName")
class PhotoView @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
defStyleAttr: Int = 0
) : AppCompatImageView(context, attrs, defStyleAttr) {
attrs: AttributeSet? = null
) : AppCompatImageView(context, attrs) {
val MIN_ROTATE = 35
val ANIMA_DURING = 340
val MAX_SCALE = 2.5f

@ -1,6 +1,7 @@
package io.legado.app.ui.widget.recycler
import android.content.Context
import android.util.AttributeSet
import android.view.View
import android.view.ViewGroup
import android.widget.FrameLayout
@ -10,7 +11,7 @@ import io.legado.app.utils.visible
import kotlinx.android.synthetic.main.view_load_more.view.*
@Suppress("unused")
class LoadMoreView(context: Context) : FrameLayout(context) {
class LoadMoreView(context: Context, attrs: AttributeSet? = null) : FrameLayout(context, attrs) {
var hasMore = true
private set
@ -32,7 +33,13 @@ class LoadMoreView(context: Context) : FrameLayout(context) {
fun stopLoad() {
rotate_loading.hide()
}
fun hasMore() {
hasMore = true
tv_text.invisible()
rotate_loading.show()
}
fun noMore(msg: String? = null) {
hasMore = false
rotate_loading.hide()
@ -44,4 +51,4 @@ class LoadMoreView(context: Context) : FrameLayout(context) {
tv_text.visible()
}
}
}

@ -17,7 +17,8 @@ import java.lang.reflect.InvocationTargetException
import java.lang.reflect.Method
@Suppress("SameParameterValue")
class VerticalSeekBar : AppCompatSeekBar {
class VerticalSeekBar @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null) :
AppCompatSeekBar(context, attrs) {
private var mIsDragging: Boolean = false
private var mThumb: Drawable? = null
@ -54,38 +55,12 @@ class VerticalSeekBar : AppCompatSeekBar {
}
}
constructor(context: Context) : super(context) {
initialize(context, null, 0, 0)
}
constructor(context: Context, attrs: AttributeSet) : super(context, attrs) {
initialize(context, attrs, 0, 0)
}
constructor(context: Context, attrs: AttributeSet, defStyle: Int) : super(
context,
attrs,
defStyle
) {
initialize(context, attrs, defStyle, 0)
}
private fun initialize(
context: Context,
attrs: AttributeSet?,
defStyleAttr: Int,
defStyleRes: Int
) {
init {
ATH.setTint(this, ThemeStore.accentColor(context))
ViewCompat.setLayoutDirection(this, ViewCompat.LAYOUT_DIRECTION_LTR)
if (attrs != null) {
val a = context.obtainStyledAttributes(
attrs,
R.styleable.VerticalSeekBar,
defStyleAttr,
defStyleRes
)
val a = context.obtainStyledAttributes(attrs, R.styleable.VerticalSeekBar)
val rotationAngle = a.getInteger(R.styleable.VerticalSeekBar_seekBarRotation, 0)
if (isValidRotationAngle(rotationAngle)) {
mRotationAngle = rotationAngle

@ -13,9 +13,8 @@ import kotlin.math.max
class VerticalSeekBarWrapper @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
defStyleAttr: Int = 0
) : FrameLayout(context, attrs, defStyleAttr) {
attrs: AttributeSet? = null
) : FrameLayout(context, attrs) {
private val childSeekBar: VerticalSeekBar?
get() {

@ -11,8 +11,10 @@ import io.legado.app.utils.ColorUtils
import io.legado.app.utils.dp
import io.legado.app.utils.getCompatColor
class AccentBgTextView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null) :
AppCompatTextView(context, attrs) {
class AccentBgTextView @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null
) : AppCompatTextView(context, attrs) {
private var radius = 0

@ -19,9 +19,8 @@ import org.jetbrains.anko.sdk27.listeners.onClick
@Suppress("unused")
class AutoCompleteTextView @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
defStyleAttr: Int = 0
) : AppCompatAutoCompleteTextView(context, attrs, defStyleAttr) {
attrs: AttributeSet? = null
) : AppCompatAutoCompleteTextView(context, attrs) {
var delCallBack: ((value: String) -> Unit)? = null

@ -24,11 +24,11 @@ import io.legado.app.utils.visible
/**
* Created by milad heydari on 5/6/2016.
*/
@Suppress("MemberVisibilityCanBePrivate", "unused")
class BadgeView @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
defStyle: Int = android.R.attr.textViewStyle
) : AppCompatTextView(context, attrs, defStyle) {
attrs: AttributeSet? = null
) : AppCompatTextView(context, attrs) {
var isHideOnNull = true
set(hideOnNull) {

@ -15,14 +15,11 @@ import kotlin.math.max
import kotlin.math.min
open class InertiaScrollTextView : AppCompatTextView {
constructor(context: Context) : super(context)
constructor(context: Context, attrs: AttributeSet?) : super(context, attrs)
constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int)
: super(context, attrs, defStyleAttr)
@Suppress("unused")
open class InertiaScrollTextView @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null
) : AppCompatTextView(context, attrs) {
private val scrollStateIdle = 0
private val scrollStateDragging = 1
@ -218,7 +215,7 @@ open class InertiaScrollTextView : AppCompatTextView {
}
}
internal fun postOnAnimation() {
fun postOnAnimation() {
if (mEatRunOnAnimationRequest) {
mReSchedulePostAnimationCallback = true
} else {

@ -56,7 +56,7 @@ fun Context.getPrefString(key: String, defValue: String? = null) =
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) }
fun Context.getPrefStringSet(

@ -26,7 +26,6 @@
android:id="@+id/et_prev"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="number"
android:singleLine="true" />
</io.legado.app.ui.widget.text.TextInputLayout>
@ -41,11 +40,17 @@
android:id="@+id/et_next"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="number"
android:singleLine="true" />
</io.legado.app.ui.widget.text.TextInputLayout>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="5dp"
android:textColor="@color/secondaryText"
android:text="@string/page_key_set_help" />
<TextView
android:id="@+id/tv_ok"
android:layout_width="match_parent"

@ -769,5 +769,7 @@
<string name="search_content">全文搜索</string>
<string name="rss_source_empty">关注公众号[开源阅读]获取订阅源!</string>
<string name="explore_empty">当前没有发现源,关注公众号[开源阅读]添加带发现的书源!</string>
<string name="page_key_set_help">将焦点放到输入框按下物理按键会自动录入键值,多个按键会自动用英文逗号隔开.</string>
<string name="theme_name">主题名称</string>
</resources>

@ -769,5 +769,7 @@
<string name="search_content">全文搜尋</string>
<string name="rss_source_empty">關注公眾號[开源阅读]獲取訂閱源!</string>
<string name="explore_empty">目前沒有發現源,關注公眾號[开源阅读]添加包含發現的書源!</string>
<string name="page_key_set_help">将焦点放到输入框按下物理按键会自动录入键值,多个按键会自动用英文逗号隔开.</string>
<string name="theme_name">主题名称</string>
</resources>

@ -772,5 +772,7 @@
<string name="search_content">全文搜索</string>
<string name="rss_source_empty">关注公众号[开源阅读]获取订阅源!</string>
<string name="explore_empty">当前没有发现源,关注公众号[开源阅读]添加带发现的书源!</string>
<string name="page_key_set_help">将焦点放到输入框按下物理按键会自动录入键值,多个按键会自动用英文逗号隔开.</string>
<string name="theme_name">主题名称</string>
</resources>

@ -775,5 +775,7 @@
<string name="search_content">Search content</string>
<string name="rss_source_empty">关注公众号[开源阅读]获取订阅源!</string>
<string name="explore_empty">当前没有发现源,关注公众号[开源阅读]添加带发现的书源!</string>
<string name="page_key_set_help">将焦点放到输入框按下物理按键会自动录入键值,多个按键会自动用英文逗号隔开.</string>
<string name="theme_name">主题名称</string>
</resources>

Loading…
Cancel
Save