Compare commits

..

1 Commits

22 changed files with 128 additions and 80 deletions

View File

@ -27,7 +27,7 @@ jobs:
with:
node-version: 16
- uses: pnpm/action-setup@v4
- uses: pnpm/action-setup@v3
name: Install pnpm
id: pnpm-install
with:

View File

@ -113,14 +113,6 @@
-identifiernamestring class * {
@org.chromium.build.annotations.IdentifierNameString *;
}
# Mark fields with this to help R8 figure out that they cannot be null.
-assumenosideeffects class ** {
@org.chromium.build.annotations.AssumeNonNull *** *(...) return _NONNULL_;
}
-assumenosideeffects class ** {
@org.chromium.build.annotations.AssumeNonNull *** * return _NONNULL_;
}
# -------- Config Path: components/cronet/android/cronet_impl_common_proguard.cfg --------
# Proguard config for apps that depend on cronet_impl_common_java.jar.

Binary file not shown.

Binary file not shown.

View File

@ -1 +1 @@
{"x86":"7bb90297b32867b4663edba1521c304a","arm64-v8a":"6281481485abdb423b9d1fcee5978157","armeabi-v7a":"3fa31a4b27e69408c6438eb24f53634b","x86_64":"5fbb8757a52a113ea8a8771b39fd7a1b","version":"125.0.6422.53"}
{"x86":"a9d092828a1a33ed43b3030e16353e9a","armeabi-v7a":"522f2f5304bf9250a43edc56bfff0fb4","x86_64":"bc89c549d18bcd26fef8e82fbad4a7cd","arm64-v8a":"ad9209119e3e74e532d07256b6e4e0ba","version":"124.0.6367.171"}

View File

@ -13,7 +13,7 @@
* 漫画源看书显示乱码,**阅读与其他软件的源并不通用**,请导入阅读的支持的漫画源!
**2024/02/27**
* 更新cronet: 125.0.6422.53
* 更新cronet: 124.0.6367.171
* 更新cronet: 123.0.6312.80
* 更新cronet: 123.0.6312.40

View File

@ -71,8 +71,6 @@ open class WebDav(
<resourcetype />
</prop>
</propfind>"""
private const val DEFAULT_CONTENT_TYPE = "application/octet-stream"
}
@ -306,12 +304,18 @@ open class WebDav(
* 上传文件
*/
@Throws(WebDavException::class)
suspend fun upload(localPath: String, contentType: String = DEFAULT_CONTENT_TYPE) {
suspend fun upload(
localPath: String,
contentType: String = "application/octet-stream"
) {
upload(File(localPath), contentType)
}
@Throws(WebDavException::class)
suspend fun upload(file: File, contentType: String = DEFAULT_CONTENT_TYPE) {
suspend fun upload(
file: File,
contentType: String = "application/octet-stream"
) {
kotlin.runCatching {
withContext(IO) {
if (!file.exists()) throw WebDavException("文件不存在")
@ -332,7 +336,7 @@ open class WebDav(
}
@Throws(WebDavException::class)
suspend fun upload(byteArray: ByteArray, contentType: String = DEFAULT_CONTENT_TYPE) {
suspend fun upload(byteArray: ByteArray, contentType: String) {
// 务必注意RequestBody不要嵌套不然上传时内容可能会被追加多余的文件信息
kotlin.runCatching {
withContext(IO) {
@ -352,7 +356,7 @@ open class WebDav(
}
@Throws(WebDavException::class)
suspend fun upload(uri: Uri, contentType: String = DEFAULT_CONTENT_TYPE) {
suspend fun upload(uri: Uri, contentType: String) {
// 务必注意RequestBody不要嵌套不然上传时内容可能会被追加多余的文件信息
kotlin.runCatching {
withContext(IO) {

View File

@ -93,7 +93,7 @@ object ReadBook : CoroutineScope by MainScope() {
readRecord.readTime = appDb.readRecordDao.getReadTime(book.name) ?: 0
chapterSize = appDb.bookChapterDao.getChapterCount(book.bookUrl)
contentProcessor = ContentProcessor.get(book)
durChapterIndex = book.durChapterIndex
durChapterIndex = min(book.durChapterIndex, chapterSize - 1).coerceAtLeast(0)
durChapterPos = book.durChapterPos
isLocalBook = book.isLocal
clearTextChapter()

View File

@ -14,7 +14,10 @@ import io.legado.app.model.analyzeRule.CustomUrl
import io.legado.app.model.localBook.LocalBook
import io.legado.app.utils.NetworkUtils
import io.legado.app.utils.isContentScheme
import io.legado.app.utils.readBytes
import kotlinx.coroutines.runBlocking
import splitties.init.appCtx
import java.io.File
class RemoteBookWebDav(
val rootBookUrl: String,
@ -68,17 +71,20 @@ class RemoteBookWebDav(
override suspend fun upload(book: Book) {
if (!NetworkUtils.isAvailable()) throw NoStackTraceException("网络不可用")
val localBookUri = Uri.parse(book.bookUrl)
val putUrl = "$rootBookUrl${book.originName}"
val putUrl = "$rootBookUrl${File.separator}${book.originName}"
val webDav = WebDav(putUrl, authorization)
if (localBookUri.isContentScheme()) {
webDav.upload(localBookUri)
webDav.upload(
byteArray = localBookUri.readBytes(appCtx),
contentType = "application/octet-stream"
)
} else {
webDav.upload(localBookUri.path!!)
}
book.origin = BookType.webDavTag + CustomUrl(putUrl)
.putAttribute("serverID", serverID)
.toString()
book.update()
book.save()
}
override suspend fun delete(remoteBookUrl: String) {

View File

@ -20,7 +20,7 @@ import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.callbackFlow
import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.map
import java.util.Collections
import java.util.*
class RemoteBookViewModel(application: Application) : BaseViewModel(application) {
var sortKey = RemoteBookSort.Default
@ -78,7 +78,6 @@ class RemoteBookViewModel(application: Application) : BaseViewModel(application)
}
return@sortedWith compare
}
else -> list.sortedWith { o1, o2 ->
val compare = -compareValues(o1.isDir, o2.isDir)
if (compare == 0) {
@ -133,8 +132,10 @@ class RemoteBookViewModel(application: Application) : BaseViewModel(application)
val downloadBookUri = bookWebDav.downloadRemoteBook(remoteBook)
LocalBook.importFiles(downloadBookUri).forEach { book ->
book.origin = BookType.webDavTag + CustomUrl(remoteBook.path)
.putAttribute("serverID", bookWebDav.serverID)
.toString()
.putAttribute(
"serverID",
bookWebDav.serverID
).toString()
book.save()
}
remoteBook.isOnBookShelf = true
@ -151,7 +152,7 @@ class RemoteBookViewModel(application: Application) : BaseViewModel(application)
}
fun updateCallBackFlow(filterKey: String?) {
dataCallback?.screen(filterKey)
dataCallback?.screen(filterKey)
}
interface DataCallback {

View File

@ -116,9 +116,6 @@ class ReadBookViewModel(application: Application) : BaseViewModel(application) {
ReadBook.loadOrUpContent()
checkLocalBookFileExist(book)
} else {
if (ReadBook.durChapterIndex > ReadBook.chapterSize - 1) {
ReadBook.durChapterIndex = ReadBook.chapterSize - 1
}
ReadBook.loadContent(resetPageOffset = false)
checkLocalBookFileExist(book)
}

View File

@ -278,18 +278,17 @@ class ContentTextView(context: Context, attrs: AttributeSet?) : View(context, at
if (textPos.compare(selectEnd) <= 0) {
selectStart.upData(pos = textPos)
upSelectedStart(
if (textPos.columnIndex < textLine.columns.lastIndex) textColumn.start else textColumn.end,
if (textPos.isTouch) textColumn.start else textColumn.end,
textLine.lineBottom + relativeOffset,
textLine.lineTop + relativeOffset
)
} else {
reverseStartCursor = true
reverseEndCursor = false
selectEnd.columnIndex++
selectStartMoveIndex(selectEnd)
selectEnd.upData(textPos)
upSelectedEnd(
if (textPos.columnIndex > -1) textColumn.end else textColumn.start,
if (selectEnd.isTouch || selectEnd.isLast) textColumn.end else textColumn.start,
textLine.lineBottom + relativeOffset
)
}
@ -308,17 +307,16 @@ class ContentTextView(context: Context, attrs: AttributeSet?) : View(context, at
if (textPos.compare(selectStart) >= 0) {
selectEnd.upData(textPos)
upSelectedEnd(
if (textPos.columnIndex > -1) textColumn.end else textColumn.start,
if (selectEnd.isTouch || selectEnd.isLast) textColumn.end else textColumn.start,
textLine.lineBottom + relativeOffset
)
} else {
reverseEndCursor = true
reverseStartCursor = false
selectStart.columnIndex--
selectEndMoveIndex(selectStart)
selectStart.upData(textPos)
upSelectedStart(
if (textPos.columnIndex < textLine.columns.lastIndex) textColumn.start else textColumn.end,
if (textPos.isTouch) textColumn.start else textColumn.end,
textLine.lineBottom + relativeOffset,
textLine.lineTop + relativeOffset
)
@ -420,11 +418,11 @@ class ContentTextView(context: Context, attrs: AttributeSet?) : View(context, at
}
}
val isLast = columns.first().start < x
val charIndex = if (isLast) columns.lastIndex + 1 else -1
val charIndex = if (isLast) columns.lastIndex else 0
val textColumn = if (isLast) columns.last() else columns.first()
touched.invoke(
relativeOffset,
TextPos(relativePos, lineIndex, charIndex),
TextPos(relativePos, lineIndex, charIndex, false, isLast),
textPage, textLine, textColumn
)
return
@ -491,14 +489,18 @@ class ContentTextView(context: Context, attrs: AttributeSet?) : View(context, at
relativePagePos: Int,
lineIndex: Int,
charIndex: Int,
isTouch: Boolean,
isLast: Boolean = false
) {
selectStart.relativePagePos = relativePagePos
selectStart.lineIndex = lineIndex
selectStart.columnIndex = charIndex
selectStart.isTouch = isTouch
selectStart.isLast = isLast
val textLine = relativePage(relativePagePos).getLine(lineIndex)
val textColumn = textLine.getColumn(charIndex)
upSelectedStart(
if (charIndex < textLine.columns.lastIndex) textColumn.start else textColumn.end,
textColumn.start,
textLine.lineBottom + relativeOffset(relativePagePos),
textLine.lineTop + relativeOffset(relativePagePos)
)
@ -506,7 +508,7 @@ class ContentTextView(context: Context, attrs: AttributeSet?) : View(context, at
}
fun selectStartMoveIndex(textPos: TextPos) = textPos.run {
selectStartMoveIndex(relativePagePos, lineIndex, columnIndex)
selectStartMoveIndex(relativePagePos, lineIndex, columnIndex, isTouch, isLast)
}
/**
@ -516,21 +518,22 @@ class ContentTextView(context: Context, attrs: AttributeSet?) : View(context, at
relativePage: Int,
lineIndex: Int,
charIndex: Int,
isTouch: Boolean,
isLast: Boolean = false
) {
selectEnd.relativePagePos = relativePage
selectEnd.lineIndex = lineIndex
selectEnd.columnIndex = charIndex
selectEnd.isTouch = isTouch
selectEnd.isLast = isLast
val textLine = relativePage(relativePage).getLine(lineIndex)
val textColumn = textLine.getColumn(charIndex)
upSelectedEnd(
if (charIndex > -1) textColumn.end else textColumn.start,
textLine.lineBottom + relativeOffset(relativePage)
)
upSelectedEnd(textColumn.end, textLine.lineBottom + relativeOffset(relativePage))
upSelectChars()
}
fun selectEndMoveIndex(textPos: TextPos) = textPos.run {
selectEndMoveIndex(relativePagePos, lineIndex, columnIndex)
selectEndMoveIndex(relativePagePos, lineIndex, columnIndex, isTouch, isLast)
}
private fun upSelectChars() {
@ -550,8 +553,8 @@ class ContentTextView(context: Context, attrs: AttributeSet?) : View(context, at
val compareStart = textPos.compare(selectStart)
val compareEnd = textPos.compare(selectEnd)
column.selected = when {
compareStart == 0 -> true
compareEnd == 0 -> true
compareStart == 0 -> selectStart.isTouch
compareEnd == 0 -> selectEnd.isTouch || selectEnd.isLast
compareStart > 0 && compareEnd < 0 -> true
else -> false
}
@ -621,19 +624,19 @@ class ContentTextView(context: Context, attrs: AttributeSet?) : View(context, at
if (column is TextColumn) {
when {
compareStart == 0 -> {
if (textPos.columnIndex < textLine.columns.lastIndex) {
if (selectStart.isTouch) {
builder.append(column.charData)
}
if (
textLine.isParagraphEnd
&& charIndex == textLine.columns.lastIndex
&& charIndex == textLine.charSize - 1
&& compareEnd != 0
) {
builder.append("\n")
}
}
compareEnd == 0 -> if (textPos.columnIndex > -1) {
compareEnd == 0 -> if (selectEnd.isTouch || selectEnd.isLast) {
builder.append(column.charData)
}
@ -641,7 +644,7 @@ class ContentTextView(context: Context, attrs: AttributeSet?) : View(context, at
builder.append(column.charData)
if (
textLine.isParagraphEnd
&& charIndex == textLine.columns.lastIndex
&& charIndex == textLine.charSize - 1
) {
builder.append("\n")
}

View File

@ -404,9 +404,17 @@ class PageView(context: Context) : FrameLayout(context) {
fun selectStartMoveIndex(
relativePagePos: Int,
lineIndex: Int,
charIndex: Int
charIndex: Int,
isTouch: Boolean = true,
isLast: Boolean = false
) {
binding.contentTextView.selectStartMoveIndex(relativePagePos, lineIndex, charIndex)
binding.contentTextView.selectStartMoveIndex(
relativePagePos,
lineIndex,
charIndex,
isTouch,
isLast
)
}
fun selectStartMoveIndex(textPos: TextPos) {
@ -420,9 +428,17 @@ class PageView(context: Context) : FrameLayout(context) {
fun selectEndMoveIndex(
relativePagePos: Int,
lineIndex: Int,
charIndex: Int
charIndex: Int,
isTouch: Boolean = true,
isLast: Boolean = false
) {
binding.contentTextView.selectEndMoveIndex(relativePagePos, lineIndex, charIndex)
binding.contentTextView.selectEndMoveIndex(
relativePagePos,
lineIndex,
charIndex,
isTouch,
isLast
)
}
fun selectEndMoveIndex(textPos: TextPos) {

View File

@ -443,13 +443,9 @@ class ReadView(context: Context, attrs: AttributeSet) :
curPage.selectText(x, y) { textPos ->
val compare = initialTextPos.compare(textPos)
when {
compare > 0 -> {
compare >= 0 -> {
curPage.selectStartMoveIndex(textPos)
curPage.selectEndMoveIndex(
initialTextPos.relativePagePos,
initialTextPos.lineIndex,
initialTextPos.columnIndex - 1
)
curPage.selectEndMoveIndex(initialTextPos)
}
else -> {

View File

@ -11,22 +11,30 @@ data class TextPos(
var relativePagePos: Int,
var lineIndex: Int,
var columnIndex: Int,
var isTouch: Boolean = true,
var isLast: Boolean = false
) {
fun upData(
relativePos: Int,
lineIndex: Int,
charIndex: Int,
isTouch: Boolean,
isLast: Boolean
) {
this.relativePagePos = relativePos
this.lineIndex = lineIndex
this.columnIndex = charIndex
this.isTouch = isTouch
this.isLast = isLast
}
fun upData(pos: TextPos) {
relativePagePos = pos.relativePagePos
lineIndex = pos.lineIndex
columnIndex = pos.columnIndex
isTouch = pos.isTouch
isLast = pos.isLast
}
fun compare(pos: TextPos): Int {
@ -57,6 +65,8 @@ data class TextPos(
relativePagePos = 0
lineIndex = -1
columnIndex = -1
isTouch = true
isLast = false
}
fun isSelected(): Boolean {

View File

@ -6,8 +6,10 @@ import android.graphics.Canvas
import android.graphics.Paint
import android.graphics.Rect
import android.graphics.Typeface
import android.os.Build
import android.text.SpannableStringBuilder
import android.text.Spanned
import android.text.StaticLayout
import android.text.style.LineHeightSpan
import android.util.AttributeSet
import androidx.annotation.ColorInt
import androidx.appcompat.widget.AppCompatTextView
@ -27,6 +29,13 @@ class BatteryView @JvmOverloads constructor(
private val outFrame = Rect()
private val polar = Rect()
private val canvasRecorder = CanvasRecorderFactory.create()
private val batterySpan = LineHeightSpan { _, _, _, _, _, fm ->
fm.top = -22
fm.ascent = -28
fm.descent = 7
fm.bottom = 1
fm.leading = 0
}
var isBattery = false
set(value) {
field = value
@ -39,9 +48,6 @@ class BatteryView @JvmOverloads constructor(
init {
setPadding(4.dpToPx(), 3.dpToPx(), 6.dpToPx(), 3.dpToPx())
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
isFallbackLineSpacing = false
}
batteryPaint.strokeWidth = 1f.dpToPx()
batteryPaint.isAntiAlias = true
batteryPaint.color = paint.color
@ -63,9 +69,9 @@ class BatteryView @JvmOverloads constructor(
fun setBattery(battery: Int, text: String? = null) {
this.battery = battery
if (text.isNullOrEmpty()) {
setText(battery.toString())
setText(getBatteryText(battery.toString()))
} else {
setText("$text $battery")
setText(getBatteryText("$text $battery"))
}
}
@ -78,16 +84,17 @@ class BatteryView @JvmOverloads constructor(
if (AppConfig.optimizeRender) {
canvasRecorder.recordIfNeededThenDraw(canvas, width, height) {
super.onDraw(this)
if (!isBattery) return@recordIfNeededThenDraw
drawBattery(this)
}
} else {
super.onDraw(canvas)
if (!isBattery) return
drawBattery(canvas)
}
}
private fun drawBattery(canvas: Canvas) {
if (!isBattery) return
layout.getLineBounds(0, outFrame)
val batteryStart = layout
.getPrimaryHorizontal(text.length - battery.toString().length)
@ -113,10 +120,22 @@ class BatteryView @JvmOverloads constructor(
canvas.drawRect(polar, batteryPaint)
}
@Suppress("UNNECESSARY_SAFE_CALL")
private fun getBatteryText(text: CharSequence?): SpannableStringBuilder? {
if (text == null) {
return null
}
return SpannableStringBuilder(text).apply {
setSpan(batterySpan, 0, text.length, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
}
}
override fun invalidate() {
super.invalidate()
canvasRecorder?.invalidate()
kotlin.runCatching {
canvasRecorder.invalidate()
}
}
}

View File

@ -4,14 +4,17 @@ package io.legado.app.utils
import android.annotation.SuppressLint
import android.content.Context
import android.view.View
import android.widget.TextView
import android.widget.Toast
import androidx.cardview.widget.CardView
import androidx.fragment.app.Fragment
import io.legado.app.BuildConfig
import io.legado.app.databinding.ViewToastBinding
import io.legado.app.R
import io.legado.app.help.config.AppConfig
import io.legado.app.lib.theme.bottomBackground
import io.legado.app.lib.theme.getPrimaryTextColor
import splitties.systemservices.layoutInflater
import splitties.views.inflate
private var toast: Toast? = null
@ -28,13 +31,14 @@ fun Context.toastOnUi(message: CharSequence?, duration: Int = Toast.LENGTH_SHORT
kotlin.runCatching {
toast?.cancel()
toast = Toast(this)
val toastView: View = inflate(R.layout.view_toast)
toast?.view = toastView
val cardView = toastView.findViewById<CardView>(R.id.cv_content)
cardView.setCardBackgroundColor(bottomBackground)
val isLight = ColorUtils.isColorLight(bottomBackground)
ViewToastBinding.inflate(layoutInflater).run {
toast?.view = root
cvToast.setCardBackgroundColor(bottomBackground)
tvText.setTextColor(getPrimaryTextColor(isLight))
tvText.text = message
}
val textView = toastView.findViewById<TextView>(R.id.tv_text)
textView.setTextColor(getPrimaryTextColor(isLight))
textView.text = message
toast?.duration = duration
toast?.show()
}

View File

@ -6,7 +6,7 @@
android:orientation="vertical">
<androidx.cardview.widget.CardView
android:id="@+id/cv_toast"
android:id="@+id/cv_content"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:cardCornerRadius="10dp"

View File

@ -42,7 +42,7 @@ android.defaults.buildfeatures.shaders=false
# and none from the library's dependencies, thereby reducing the size of the R class for that library.
android.nonTransitiveRClass=true
# https://chromiumdash.appspot.com/releases?platform=Android
CronetVersion=125.0.6422.53
CronetMainVersion=125.0.0.0
CronetVersion=124.0.6367.171
CronetMainVersion=124.0.0.0
android.injected.testOnly=false
android.nonFinalResIds=true