Merge branch 'master' into master

pull/2353/head
Xwite 3 years ago committed by GitHub
commit be13ad560c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 35
      app/build.gradle
  2. 2
      app/src/main/assets/help/readMenuHelp.md
  3. 3
      app/src/main/assets/updateLog.md
  4. 24
      app/src/main/java/io/legado/app/help/http/cronet/CronetHelper.kt
  5. 2
      app/src/main/java/io/legado/app/model/webBook/BookContent.kt
  6. 2
      app/src/main/java/io/legado/app/ui/association/VerificationCodeDialog.kt
  7. 22
      app/src/main/java/io/legado/app/ui/book/read/ReadMenu.kt
  8. 4
      app/src/main/java/io/legado/app/ui/widget/code/CodeView.kt
  9. 4
      app/src/main/java/io/legado/app/ui/widget/text/InertiaScrollTextView.kt
  10. 53
      app/src/main/java/io/legado/app/ui/widget/text/NestScrollMultiAutoCompleteTextView.kt
  11. 7
      app/src/main/java/io/legado/app/ui/widget/text/NestScrollTextView.kt
  12. 2
      app/src/main/res/layout-land/activity_book_info.xml
  13. 2
      app/src/main/res/layout/activity_book_info.xml
  14. 38
      app/src/main/res/layout/view_read_menu.xml
  15. 10
      app/src/main/res/menu/book_read_source.xml
  16. 10
      epublib/build.gradle
  17. 1
      gradle.properties
  18. 4
      gradle/wrapper/gradle-wrapper.properties

@ -16,8 +16,7 @@ def version = "3." + releaseTime()
def gitCommits = Integer.parseInt('git rev-list HEAD --count'.execute().text.trim())
android {
compileSdkVersion 33
buildToolsVersion "33.0.0"
compileSdk 33
namespace 'io.legado.app'
kotlinOptions {
jvmTarget = "11"
@ -39,14 +38,16 @@ android {
}
defaultConfig {
applicationId "io.legado.app"
minSdkVersion 21
targetSdkVersion 33
minSdk 21
targetSdk 33
versionCode 10000 + gitCommits
versionName version
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
project.ext.set("archivesBaseName", name + "_" + version)
multiDexEnabled true
buildConfigField "String", "Cronet_Version", "\"$CronetVersion\""
javaCompileOptions {
annotationProcessorOptions {
arguments += [
@ -63,7 +64,6 @@ android {
}
buildTypes {
release {
buildConfigField "String", "Cronet_Version", "\"$CronetVersion\""
if (project.hasProperty("RELEASE_STORE_FILE")) {
signingConfig signingConfigs.myConfig
}
@ -73,7 +73,7 @@ android {
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
debug {
buildConfigField "String", "Cronet_Version", "\"$CronetVersion\""
if (project.hasProperty("RELEASE_STORE_FILE")) {
signingConfig signingConfigs.myConfig
}
@ -82,23 +82,25 @@ android {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
android.applicationVariants.all { variant ->
variant.outputs.all {
def flavor = variant.productFlavors[0].name
outputFileName = "${name}_${flavor}_${defaultConfig.versionName}.apk"
}
}
android.applicationVariants.all { variant ->
variant.outputs.all {
def flavor = variant.productFlavors[0].name
outputFileName = "${name}_${flavor}_${defaultConfig.versionName}.apk"
}
}
flavorDimensions "mode"
flavorDimensions.add("mode")
productFlavors {
app {
dimension "mode"
manifestPlaceholders = [APP_CHANNEL_VALUE: "app"]
manifestPlaceholders.put("APP_CHANNEL_VALUE", "app")
}
google {
dimension "mode"
applicationId "io.legado.play"
manifestPlaceholders = [APP_CHANNEL_VALUE: "google"]
manifestPlaceholders.put("APP_CHANNEL_VALUE", "google")
}
}
compileOptions {
@ -125,6 +127,7 @@ android {
}
dependencies {
compileOnly "com.android.tools.build:gradle:$agp_version"
//noinspection GradleDependency,GradlePackageUpdate
coreLibraryDesugaring('com.android.tools:desugar_jdk_libs:1.2.2')
testImplementation('junit:junit:4.13.2')
@ -211,7 +214,7 @@ dependencies {
implementation(fileTree(dir: 'cronetlib', include: ['*.jar', '*.aar']))
//Glide
def glideVersion = "4.14.0"
def glideVersion = "4.14.1"
implementation("com.github.bumptech.glide:glide:$glideVersion")
kapt("com.github.bumptech.glide:compiler:$glideVersion")
@ -227,7 +230,7 @@ dependencies {
implementation('com.jaredrummler:colorpicker:1.1.0')
//apache
implementation('org.apache.commons:commons-text:1.9')
implementation('org.apache.commons:commons-text:1.10.0')
//MarkDown
def markwonVersion = "4.6.2"

@ -17,7 +17,7 @@
## 全文搜索
搜索本地缓存或者本地文件,不能搜索在线内容
如果搜索结果不符合预期,确保`替换净化`没有启用`内容替换`类规则(如替换主人公姓名)
书籍字数、净化规则数量、简繁转化、文章分段都会影响到搜索速度,请酌情启用
## 朗读设置界面
* 后台->进入后台朗读,可以做一些其它事

@ -11,10 +11,11 @@
* 正文出现缺字漏字、内容缺失、排版错乱等情况,有可能是净化规则或简繁转换出现问题。
* 漫画源看书显示乱码,**阅读与其他软件的源并不通用**,请导入阅读的支持的漫画源!
**2022/09/27**
**2022/09/28**
* 更新cronet: 106.0.5249.65
* 正文选择菜单朗读按钮长按可切换朗读选择内容和从选择开始处一直朗读
* 修复某些情况下无法搜索到标题的bug,净化规则较多的可能会降低搜索速度
**2022/09/26**

@ -12,6 +12,7 @@ import org.chromium.net.CronetEngine.Builder.HTTP_CACHE_DISK
import org.chromium.net.ExperimentalCronetEngine
import org.chromium.net.UploadDataProviders
import org.chromium.net.UrlRequest
import org.json.JSONObject
import splitties.init.appCtx
@ -29,6 +30,7 @@ val cronetEngine: ExperimentalCronetEngine? by lazy {
enableHttp2(true) //设置支持http/2
enablePublicKeyPinningBypassForLocalTrustAnchors(true)
enableBrotli(true)//Brotli压缩
setExperimentalOptions(options)
}
try {
val engine = builder.build()
@ -40,6 +42,28 @@ val cronetEngine: ExperimentalCronetEngine? by lazy {
}
}
val options by lazy {
val options = JSONObject()
//设置域名映射规则
//MAP hostname ip,MAP hostname ip
// val host = JSONObject()
// host.put("host_resolver_rules","")
// options.put("HostResolverRules", host)
//启用DnsHttpsSvcb更容易迁移到http3
val dnsSvcb = JSONObject()
dnsSvcb.put("enable", true)
dnsSvcb.put("enable_insecure", true)
dnsSvcb.put("use_alpn", true)
options.put("UseDnsHttpsSvcb", dnsSvcb)
options.put("AsyncDNS", JSONObject("{'enable':true}"))
options.toString()
}
fun buildRequest(request: Request, callback: UrlRequest.Callback): UrlRequest? {
val url = request.url.toString()
val headers: Headers = request.headers

@ -120,7 +120,7 @@ object BookContent {
Debug.log(bookSource.bookSourceUrl, "${bookChapter.title}")
Debug.log(bookSource.bookSourceUrl, "┌获取正文内容")
Debug.log(bookSource.bookSourceUrl, "\n$contentStr")
if (contentStr.isBlank()) {
if (!bookChapter.isVolume && contentStr.isBlank()) {
throw ContentEmptyException("内容为空")
}
if (needSave) {

@ -67,7 +67,7 @@ class VerificationCodeDialog() : BaseDialogFragment(R.layout.dialog_verification
}
}.error(R.drawable.image_loading_error)
.diskCacheStrategy(DiskCacheStrategy.NONE)
.skipMemoryCache(true)
//.skipMemoryCache(true)
.into(verificationCodeImageView)
verificationCodeImageView.setOnClickListener {
showDialogFragment(PhotoDialog(imageUrl, sourceOrigin))

@ -84,6 +84,8 @@ class ReadMenu @JvmOverloads constructor(
inflate(R.menu.book_read_source)
setOnMenuItemClickListener {
when (it.itemId) {
R.id.menu_login -> callBack.showLogin()
R.id.menu_chapter_pay -> callBack.payAction()
R.id.menu_edit_source -> callBack.openSourceEditActivity()
R.id.menu_disable_source -> callBack.disableSource()
}
@ -93,11 +95,9 @@ class ReadMenu @JvmOverloads constructor(
}
private val menuInListener = object : Animation.AnimationListener {
override fun onAnimationStart(animation: Animation) {
binding.tvSourceAction.text =
ReadBook.bookSource?.bookSourceName ?: context.getString(R.string.book_source)
binding.tvSourceAction.isGone = ReadBook.isLocalBook
binding.tvLogin.isGone = ReadBook.bookSource?.loginUrl.isNullOrEmpty()
binding.tvPay.isGone = ReadBook.bookSource?.loginUrl.isNullOrEmpty()
|| ReadBook.curTextChapter?.isVip != true
|| ReadBook.curTextChapter?.isPay == true
callBack.upSystemUiVisibility()
binding.llBrightness.visible(showBrightnessView)
}
@ -335,16 +335,14 @@ class ReadMenu @JvmOverloads constructor(
tvChapterName.setOnLongClickListener(chapterViewLongClickListener)
tvChapterUrl.setOnClickListener(chapterViewClickListener)
tvChapterUrl.setOnLongClickListener(chapterViewLongClickListener)
//登录
tvLogin.setOnClickListener {
callBack.showLogin()
}
//购买
tvPay.setOnClickListener {
callBack.payAction()
}
//书源操作
tvSourceAction.onClick {
sourceMenu.menu.findItem(R.id.menu_login).isVisible =
!ReadBook.bookSource?.loginUrl.isNullOrEmpty()
sourceMenu.menu.findItem(R.id.menu_chapter_pay).isVisible =
!ReadBook.bookSource?.loginUrl.isNullOrEmpty()
&& ReadBook.curTextChapter?.isVip == true
&& ReadBook.curTextChapter?.isPay != true
sourceMenu.show()
}
//亮度跟随

@ -13,7 +13,7 @@ import android.text.style.ForegroundColorSpan
import android.text.style.ReplacementSpan
import android.util.AttributeSet
import androidx.annotation.ColorInt
import io.legado.app.ui.widget.text.ScrollMultiAutoCompleteTextView
import io.legado.app.ui.widget.text.NestScrollMultiAutoCompleteTextView
import java.util.*
import java.util.regex.Matcher
import java.util.regex.Pattern
@ -21,7 +21,7 @@ import kotlin.math.roundToInt
@Suppress("unused")
class CodeView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null) :
ScrollMultiAutoCompleteTextView(context, attrs) {
NestScrollMultiAutoCompleteTextView(context, attrs) {
private var tabWidth = 0
private var tabWidthInCharacters = 0

@ -15,7 +15,9 @@ import kotlin.math.abs
import kotlin.math.max
import kotlin.math.min
/**
* 惯性滚动 TextView
*/
@Suppress("unused")
open class InertiaScrollTextView @JvmOverloads constructor(
context: Context,

@ -3,20 +3,50 @@ package io.legado.app.ui.widget.text
import android.annotation.SuppressLint
import android.content.Context
import android.util.AttributeSet
import android.view.GestureDetector
import android.view.MotionEvent
import androidx.appcompat.widget.AppCompatMultiAutoCompleteTextView
open class ScrollMultiAutoCompleteTextView @JvmOverloads constructor(
/**
* 嵌套滚动 MultiAutoCompleteTextView
*/
open class NestScrollMultiAutoCompleteTextView @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null
) : AppCompatMultiAutoCompleteTextView(context, attrs) {
//是否到顶或者到底的标志
private var disallowIntercept = true
//滑动距离的最大边界
private var mOffsetHeight = 0
//是否到顶或者到底的标志
private var mBottomFlag = false
private val gestureDetector = GestureDetector(context,
object : GestureDetector.SimpleOnGestureListener() {
override fun onDown(e: MotionEvent): Boolean {
disallowIntercept = true
return super.onDown(e)
}
override fun onScroll(
e1: MotionEvent,
e2: MotionEvent,
distanceX: Float,
distanceY: Float
): Boolean {
val y = scrollY + distanceY
if (y < 0 || y > mOffsetHeight) {
disallowIntercept = false
//这里触发父布局或祖父布局的滑动事件
parent.requestDisallowInterceptTouchEvent(false)
} else {
disallowIntercept = true
}
return true
}
})
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec)
@ -34,9 +64,8 @@ open class ScrollMultiAutoCompleteTextView @JvmOverloads constructor(
}
override fun dispatchTouchEvent(event: MotionEvent): Boolean {
if (event.action == MotionEvent.ACTION_DOWN) {
//如果是新的按下事件,则对mBottomFlag重新初始化
mBottomFlag = lineCount <= maxLines
if (lineCount > maxLines) {
gestureDetector.onTouchEvent(event)
}
return super.dispatchTouchEvent(event)
}
@ -45,22 +74,12 @@ open class ScrollMultiAutoCompleteTextView @JvmOverloads constructor(
override fun onTouchEvent(event: MotionEvent): Boolean {
val result = super.onTouchEvent(event)
//如果是需要拦截,则再拦截,这个方法会在onScrollChanged方法之后再调用一次
if (!mBottomFlag) {
if (disallowIntercept && lineCount > maxLines) {
parent.requestDisallowInterceptTouchEvent(true)
}
return result
}
override fun onScrollChanged(horiz: Int, vert: Int, oldHoriz: Int, oldVert: Int) {
super.onScrollChanged(horiz, vert, oldHoriz, oldVert)
if (vert == mOffsetHeight || vert == 0) {
//这里触发父布局或祖父布局的滑动事件
parent.requestDisallowInterceptTouchEvent(false)
mBottomFlag = true
}
}
private fun initOffsetHeight() {
val mLayoutHeight: Int

@ -6,7 +6,12 @@ import android.util.AttributeSet
import android.view.MotionEvent
import androidx.appcompat.widget.AppCompatTextView
class ScrollTextView(context: Context, attrs: AttributeSet?) : AppCompatTextView(context, attrs) {
/**
* 嵌套滚动 TextView
*/
class NestScrollTextView(context: Context, attrs: AttributeSet?) :
AppCompatTextView(context, attrs) {
//滑动距离的最大边界
private var mOffsetHeight = 0

@ -355,7 +355,7 @@
</LinearLayout>
<io.legado.app.ui.widget.text.ScrollTextView
<io.legado.app.ui.widget.text.NestScrollTextView
android:id="@+id/tv_intro"
android:layout_width="match_parent"
android:layout_height="wrap_content"

@ -331,7 +331,7 @@
</LinearLayout>
<io.legado.app.ui.widget.text.ScrollTextView
<io.legado.app.ui.widget.text.NestScrollTextView
android:id="@+id/tv_intro"
android:layout_width="match_parent"
android:layout_height="wrap_content"

@ -35,7 +35,7 @@
android:singleLine="true"
android:visibility="gone"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toLeftOf="@+id/tv_login"
app:layout_constraintRight_toLeftOf="@+id/tv_source_action"
app:layout_constraintTop_toTopOf="parent" />
<TextView
@ -47,53 +47,23 @@
android:singleLine="true"
android:visibility="gone"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toLeftOf="@+id/tv_login"
app:layout_constraintRight_toLeftOf="@+id/tv_source_action"
app:layout_constraintTop_toBottomOf="@+id/tv_chapter_name" />
<io.legado.app.ui.widget.text.AccentBgTextView
android:id="@+id/tv_login"
android:layout_width="wrap_content"
android:layout_height="0dp"
android:layout_margin="1dp"
android:gravity="center"
android:maxWidth="80dp"
android:paddingLeft="6dp"
android:paddingRight="6dp"
android:text="@string/login"
app:layout_constraintBottom_toBottomOf="@+id/tv_chapter_url"
app:layout_constraintRight_toLeftOf="@+id/tv_pay"
app:layout_constraintTop_toTopOf="parent"
app:radius="1dp" />
<io.legado.app.ui.widget.text.AccentBgTextView
android:id="@+id/tv_pay"
android:layout_width="wrap_content"
android:layout_height="0dp"
android:layout_margin="1dp"
android:gravity="center"
android:maxWidth="80dp"
android:paddingLeft="6dp"
android:paddingRight="6dp"
android:text="@string/chapter_pay"
app:layout_constraintBottom_toBottomOf="@+id/tv_chapter_url"
app:layout_constraintRight_toLeftOf="@id/tv_source_action"
app:layout_constraintTop_toTopOf="parent"
app:radius="1dp" />
<io.legado.app.ui.widget.text.AccentBgTextView
android:id="@+id/tv_source_action"
android:layout_width="wrap_content"
android:layout_height="0dp"
android:layout_margin="1dp"
android:gravity="center"
android:maxWidth="80dp"
android:maxWidth="120dp"
android:paddingLeft="6dp"
android:paddingRight="6dp"
android:text="@string/book_source"
app:layout_constraintBottom_toBottomOf="@+id/tv_chapter_url"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:radius="1dp" />
app:radius="2dp" />
</androidx.constraintlayout.widget.ConstraintLayout>

@ -4,6 +4,16 @@
tools:context=".ui.main.MainActivity"
tools:ignore="AlwaysShowAction">
<item
android:id="@+id/menu_login"
android:title="@string/login"
app:showAsAction="never" />
<item
android:id="@+id/menu_chapter_pay"
android:title="@string/chapter_pay"
app:showAsAction="never" />
<item
android:id="@+id/menu_edit_source"
android:title="@string/edit_book_source"

@ -3,12 +3,11 @@ plugins {
}
android {
compileSdkVersion 32
buildToolsVersion '32.0.0'
compileSdk 33
namespace 'me.ag2s.epublib'
defaultConfig {
minSdkVersion 21
targetSdkVersion 32
minSdk 21
targetSdk 33
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
consumerProguardFiles "consumer-rules.pro"
@ -19,8 +18,6 @@ android {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
android {
}
}
compileOptions {
@ -33,5 +30,6 @@ android {
}
dependencies {
compileOnly "com.android.tools.build:gradle:$agp_version"
implementation "androidx.annotation:annotation:1.5.0"
}

@ -19,6 +19,7 @@ android.useAndroidX=true
android.enableJetifier=true
# Kotlin code style for this project: "official" or "obsolete":
kotlin.code.style=official
kotlin.incremental.useClasspathSnapshot=true
android.enableResourceOptimizations=true
android.enableNewResourceShrinker=true
android.experimental.enableNewResourceShrinker.preciseShrinking=true

@ -1,6 +1,6 @@
#Mon May 23 22:07:39 CST 2022
#Mon Sep 26 08:03:55 CST 2022
distributionBase=GRADLE_USER_HOME
distributionUrl=https\://services.gradle.org/distributions/gradle-7.4.2-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-7.5.1-bin.zip
distributionPath=wrapper/dists
zipStorePath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME

Loading…
Cancel
Save