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

@ -3,8 +3,15 @@
* 关注合作公众号 **[小说拾遗]()** 获取好看的小说。 * 关注合作公众号 **[小说拾遗]()** 获取好看的小说。
* 旧版数据导入教程:先在旧版阅读(2.x)中进行备份,然后在新版阅读(3.x)【我的】->【备份与恢复】,选择【导入旧版本数据】。 * 旧版数据导入教程:先在旧版阅读(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** **2020/10/19**
* 优化分组管理 * 优化分组管理

@ -4,10 +4,8 @@ import android.app.NotificationChannel
import android.app.NotificationManager import android.app.NotificationManager
import android.content.Context import android.content.Context
import android.content.res.Configuration import android.content.res.Configuration
import android.graphics.Color
import android.os.Build import android.os.Build
import android.provider.Settings import android.provider.Settings
import android.util.Log
import androidx.annotation.RequiresApi import androidx.annotation.RequiresApi
import androidx.appcompat.app.AppCompatDelegate import androidx.appcompat.app.AppCompatDelegate
import androidx.multidex.MultiDexApplication 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.channelIdReadAloud
import io.legado.app.constant.AppConst.channelIdWeb import io.legado.app.constant.AppConst.channelIdWeb
import io.legado.app.constant.EventBus import io.legado.app.constant.EventBus
import io.legado.app.constant.PreferKey
import io.legado.app.data.AppDatabase import io.legado.app.data.AppDatabase
import io.legado.app.help.ActivityHelp import io.legado.app.help.*
import io.legado.app.help.AppConfig import io.legado.app.utils.LanguageUtils
import io.legado.app.help.CrashHandler import io.legado.app.utils.postEvent
import io.legado.app.help.ReadBookConfig
import io.legado.app.lib.theme.ThemeStore
import io.legado.app.utils.*
@Suppress("DEPRECATION") @Suppress("DEPRECATION")
class App : MultiDexApplication() { 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() { fun applyDayNight() {
ReadBookConfig.upBg() ReadBookConfig.upBg()
applyTheme() ThemeConfig.applyTheme(this)
initNightMode() initNightMode()
postEvent(EventBus.RECREATE, "") postEvent(EventBus.RECREATE, "")
} }

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

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

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

@ -7,6 +7,7 @@ import io.legado.app.App
import io.legado.app.R 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.constant.PreferKey
import io.legado.app.lib.theme.ThemeStore
import io.legado.app.utils.* import io.legado.app.utils.*
import java.io.File import java.io.File
@ -14,16 +15,16 @@ object ThemeConfig {
const val configFileName = "themeConfig.json" const val configFileName = "themeConfig.json"
val configFilePath = FileUtils.getPath(App.INSTANCE.filesDir, configFileName) val configFilePath = FileUtils.getPath(App.INSTANCE.filesDir, configFileName)
val configList = arrayListOf<Config>() val configList: ArrayList<Config> by lazy {
val cList = getConfigs() ?: DefaultData.defaultThemeConfigs
init { ArrayList(cList)
upConfig()
} }
fun upConfig() { fun upConfig() {
(getConfigs() ?: DefaultData.defaultThemeConfigs).let { getConfigs()?.let {
configList.clear() it.forEach { config ->
configList.addAll(it) addConfig(config)
}
} }
} }
@ -137,6 +138,65 @@ object ThemeConfig {
addConfig(config) 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 @Keep
class Config( class Config(
var themeName: String, var themeName: String,

@ -48,21 +48,6 @@ object HttpHelper {
return null 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? { suspend fun simpleGetAsync(url: String, encode: String? = null): String? {
NetworkUtils.getBaseUrl(url)?.let { baseUrl -> NetworkUtils.getBaseUrl(url)?.let { baseUrl ->
val response = getApiService<HttpGetApi>(baseUrl, encode) val response = getApiService<HttpGetApi>(baseUrl, encode)

@ -649,16 +649,12 @@ class AnalyzeRule(var book: BaseBook? = null) : JsExtensions {
* 章节数转数字 * 章节数转数字
*/ */
fun toNumChapter(s: String?): String? { fun toNumChapter(s: String?): String? {
if (s == null) { s ?: return null
return null val matcher = titleNumPattern.matcher(s)
} if (matcher.find()) {
val pattern = Pattern.compile("(第)(.+?)(章)") return "${matcher.group(1)}${StringUtils.stringToInt(matcher.group(2))}${matcher.group(3)}"
val matcher = pattern.matcher(s)
return if (matcher.find()) {
matcher.group(1)!! + StringUtils.stringToInt(matcher.group(2)) + matcher.group(3)
} else {
s
} }
return s
} }
companion object { companion object {
@ -667,6 +663,7 @@ class AnalyzeRule(var book: BaseBook? = null) : JsExtensions {
private val evalPattern = private val evalPattern =
Pattern.compile("@get:\\{[^}]+?\\}|\\{\\{[\\w\\W]*?\\}\\}", Pattern.CASE_INSENSITIVE) Pattern.compile("@get:\\{[^}]+?\\}|\\{\\{[\\w\\W]*?\\}\\}", Pattern.CASE_INSENSITIVE)
private val regexPattern = Pattern.compile("\\$\\d{1,2}") 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) GSON.fromJsonObject<Map<String, String>>(headers)
?.let { headerMap.putAll(it) } ?.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.charset?.let { charset = it }
option.body?.let { option.body?.let {
@ -281,7 +281,7 @@ class AnalyzeUrl(
fun getResponse(tag: String): Call<String> { fun getResponse(tag: String): Call<String> {
val cookie = CookieStore.getCookie(tag) val cookie = CookieStore.getCookie(tag)
if (cookie.isNotEmpty()) { if (cookie.isNotEmpty()) {
headerMap["Cookie"] = cookie headerMap["Cookie"] += ";${cookie}"
} }
return when { return when {
method == RequestMethod.POST -> { method == RequestMethod.POST -> {
@ -324,7 +324,7 @@ class AnalyzeUrl(
} }
val cookie = CookieStore.getCookie(tag) val cookie = CookieStore.getCookie(tag)
if (cookie.isNotEmpty()) { if (cookie.isNotEmpty()) {
headerMap["Cookie"] = cookie headerMap["Cookie"] += ";${cookie}"
} }
val res = when { val res = when {
method == RequestMethod.POST -> { method == RequestMethod.POST -> {
@ -352,23 +352,11 @@ class AnalyzeUrl(
return Res(NetworkUtils.getUrl(res), res.body()) 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? { suspend fun getResponseBytes(tag: String? = null): ByteArray? {
if (tag != null) { if (tag != null) {
val cookie = CookieStore.getCookie(tag) val cookie = CookieStore.getCookie(tag)
if (cookie.isNotEmpty()) { if (cookie.isNotEmpty()) {
headerMap["Cookie"] = cookie headerMap["Cookie"] += ";${cookie}"
} }
} }
val response = when { val response = when {

@ -29,7 +29,8 @@ class AboutFragment : PreferenceFragmentCompat() {
Pair("(QQ群3)981838750", "g_Sgmp2nQPKqcZQ5qPcKLHziwX_mpps9"), Pair("(QQ群3)981838750", "g_Sgmp2nQPKqcZQ5qPcKLHziwX_mpps9"),
Pair("(QQ群4)256929088", "czEJPLDnT4Pd9SKQ6RoRVzKhDxLchZrO"), Pair("(QQ群4)256929088", "czEJPLDnT4Pd9SKQ6RoRVzKhDxLchZrO"),
Pair("(QQ群5)811843556", "zKZ2UYGZ7o5CzcA6ylxzlqi21si_iqaX"), 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?) { override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {

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

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

@ -13,6 +13,7 @@ import android.view.WindowManager
import android.widget.EditText import android.widget.EditText
import io.legado.app.App import io.legado.app.App
import io.legado.app.R import io.legado.app.R
import io.legado.app.constant.PreferKey
import io.legado.app.data.entities.Bookmark import io.legado.app.data.entities.Bookmark
import io.legado.app.help.AppConfig import io.legado.app.help.AppConfig
import io.legado.app.help.ReadBookConfig 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.service.help.ReadBook
import io.legado.app.ui.widget.text.AutoCompleteTextView import io.legado.app.ui.widget.text.AutoCompleteTextView
import io.legado.app.utils.applyTint import io.legado.app.utils.applyTint
import io.legado.app.utils.getPrefString
import io.legado.app.utils.requestInputMethod import io.legado.app.utils.requestInputMethod
import kotlinx.android.synthetic.main.dialog_download_choice.view.* import kotlinx.android.synthetic.main.dialog_download_choice.view.*
import kotlinx.android.synthetic.main.dialog_edit_text.view.* import kotlinx.android.synthetic.main.dialog_edit_text.view.*
@ -186,4 +188,14 @@ object ReadBookActivityHelp {
cancelButton() cancelButton()
}.show().applyTint() }.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( class ReadMenu @JvmOverloads constructor(
context: Context, context: Context,
attrs: AttributeSet? = null, attrs: AttributeSet? = null
defStyleAttr: Int = 0 ) : FrameLayout(context, attrs) {
) : FrameLayout(context, attrs, defStyleAttr) {
var cnaShowMenu: Boolean = false var cnaShowMenu: Boolean = false
private val callBack: CallBack? get() = activity as? CallBack private val callBack: CallBack? get() = activity as? CallBack
private lateinit var menuTopIn: Animation private lateinit var menuTopIn: Animation

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

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

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

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

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

@ -12,7 +12,10 @@ import androidx.appcompat.widget.AppCompatTextView
import io.legado.app.utils.dp import io.legado.app.utils.dp
import java.io.File 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 batteryPaint = Paint()
private val outFrame = Rect() private val outFrame = Rect()
private val polar = 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 kotlinx.android.synthetic.main.view_detail_seek_bar.view.*
import org.jetbrains.anko.sdk27.listeners.onClick 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 { SeekBar.OnSeekBarChangeListener {
private val isBottomBackground: Boolean private val isBottomBackground: Boolean
var valueFormat: ((progress: Int) -> String)? = null var valueFormat: ((progress: Int) -> String)? = null

@ -8,7 +8,10 @@ import io.legado.app.ui.widget.text.AccentBgTextView
import io.legado.app.utils.dp import io.legado.app.utils.dp
@Suppress("unused", "MemberVisibilityCanBePrivate") @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 unUsedViews = arrayListOf<TextView>()
private val usedViews = arrayListOf<TextView>() private val usedViews = arrayListOf<TextView>()

@ -18,9 +18,8 @@ import io.legado.app.R
class SearchView @JvmOverloads constructor( class SearchView @JvmOverloads constructor(
context: Context, context: Context,
attrs: AttributeSet? = null, attrs: AttributeSet? = null
defStyleAttr: Int = 0 ) : SearchView(context, attrs) {
) : SearchView(context, attrs, defStyleAttr) {
private var mSearchHintIcon: Drawable? = null private var mSearchHintIcon: Drawable? = null
private var textView: TextView? = 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 import org.jetbrains.anko.sdk27.listeners.onClick
@Suppress("unused") @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 callBack: CallBack? = null
private var selMenu: PopupMenu? = null private var selMenu: PopupMenu? = null

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

@ -22,7 +22,10 @@ import org.jetbrains.anko.bottomPadding
import org.jetbrains.anko.topPadding import org.jetbrains.anko.topPadding
@Suppress("unused") @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 toolbar: Toolbar
val menu: Menu val menu: Menu

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

@ -18,9 +18,12 @@ import io.legado.app.utils.dp
* Created by Victor on 2015/4/28. * Created by Victor on 2015/4/28.
*/ */
@Suppress("MemberVisibilityCanBePrivate") @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 loadingRectF: RectF? = null
private var shadowRectF: RectF? = null private var shadowRectF: RectF? = null
@ -55,19 +58,7 @@ class RotateLoading : View {
private val hidden = Runnable { this.stopInternal() } private val hidden = Runnable { this.stopInternal() }
constructor(context: Context) : super(context) { init {
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?) {
loadingColor = context.accentColor loadingColor = context.accentColor
thisWidth = DEFAULT_WIDTH.dp thisWidth = DEFAULT_WIDTH.dp
shadowPosition = DEFAULT_SHADOW_POSITION.dp shadowPosition = DEFAULT_SHADOW_POSITION.dp

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

@ -13,7 +13,10 @@ import io.legado.app.R
import kotlinx.android.synthetic.main.view_dynamic.view.* import kotlinx.android.synthetic.main.view_dynamic.view.*
@Suppress("unused") @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 errorView: View? = null
private var errorImage: AppCompatImageView? = null private var errorImage: AppCompatImageView? = null

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

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

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

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

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

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

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

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

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

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

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

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

@ -26,7 +26,6 @@
android:id="@+id/et_prev" android:id="@+id/et_prev"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:inputType="number"
android:singleLine="true" /> android:singleLine="true" />
</io.legado.app.ui.widget.text.TextInputLayout> </io.legado.app.ui.widget.text.TextInputLayout>
@ -41,11 +40,17 @@
android:id="@+id/et_next" android:id="@+id/et_next"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:inputType="number"
android:singleLine="true" /> android:singleLine="true" />
</io.legado.app.ui.widget.text.TextInputLayout> </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 <TextView
android:id="@+id/tv_ok" android:id="@+id/tv_ok"
android:layout_width="match_parent" android:layout_width="match_parent"

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

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

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

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

Loading…
Cancel
Save