فهرست منبع

Merge remote-tracking branch 'upstream/master'

Seidko 4 سال پیش
والد
کامیت
72bad963f3
30فایلهای تغییر یافته به همراه282 افزوده شده و 167 حذف شده
  1. BIN
      app/cronetlib/cronet_api.jar
  2. BIN
      app/cronetlib/cronet_impl_common_java.jar
  3. 1 1
      app/src/main/assets/cronet.json
  4. 3 2
      app/src/main/assets/updateLog.md
  5. 1 1
      app/src/main/java/io/legado/app/api/controller/BookController.kt
  6. 2 2
      app/src/main/java/io/legado/app/help/ContentProcessor.kt
  7. 2 2
      app/src/main/java/io/legado/app/help/CrashHandler.kt
  8. 55 26
      app/src/main/java/io/legado/app/help/JsExtensions.kt
  9. 8 8
      app/src/main/java/io/legado/app/model/Debug.kt
  10. 2 2
      app/src/main/java/io/legado/app/model/ReadBook.kt
  11. 1 1
      app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeRule.kt
  12. 2 2
      app/src/main/java/io/legado/app/ui/book/explore/ExploreShowViewModel.kt
  13. 3 2
      app/src/main/java/io/legado/app/ui/book/read/ReadBookViewModel.kt
  14. 1 1
      app/src/main/java/io/legado/app/ui/book/read/config/BgTextConfigDialog.kt
  15. 69 63
      app/src/main/java/io/legado/app/ui/book/read/page/ContentTextView.kt
  16. 56 5
      app/src/main/java/io/legado/app/ui/book/read/page/PageView.kt
  17. 28 19
      app/src/main/java/io/legado/app/ui/book/read/page/ReadView.kt
  18. 5 1
      app/src/main/java/io/legado/app/ui/book/read/page/delegate/HorizontalPageDelegate.kt
  19. 3 0
      app/src/main/java/io/legado/app/ui/book/read/page/entities/TextChapter.kt
  20. 6 4
      app/src/main/java/io/legado/app/ui/book/read/page/entities/TextColumn.kt
  21. 6 3
      app/src/main/java/io/legado/app/ui/book/read/page/entities/TextLine.kt
  22. 5 2
      app/src/main/java/io/legado/app/ui/book/read/page/entities/TextPage.kt
  23. 3 0
      app/src/main/java/io/legado/app/ui/book/read/page/entities/TextPos.kt
  24. 13 13
      app/src/main/java/io/legado/app/ui/book/read/page/provider/ChapterProvider.kt
  25. 1 1
      app/src/main/java/io/legado/app/ui/book/source/manage/BookSourceViewModel.kt
  26. 2 2
      app/src/main/java/io/legado/app/ui/rss/source/edit/RssSourceEditViewModel.kt
  27. 1 1
      app/src/main/java/io/legado/app/ui/rss/source/manage/RssSourceViewModel.kt
  28. 1 1
      app/src/main/java/io/legado/app/utils/ContextExtensions.kt
  29. 1 1
      app/src/main/java/io/legado/app/utils/ThrowableExtensions.kt
  30. 1 1
      gradle.properties

BIN
app/cronetlib/cronet_api.jar


BIN
app/cronetlib/cronet_impl_common_java.jar


+ 1 - 1
app/src/main/assets/cronet.json

@@ -1 +1 @@
-{"arm64-v8a":"11ded68691faa98fb1ab552210c8d4a8","armeabi-v7a":"4a986b523de502fc85ba6ea51f6f7184","x86_64":"80a642112fe079f3d689a6420a27e926","x86":"e72bf103350222d212bcb0b641733d43","version":"105.0.5195.77"}
+{"arm64-v8a":"27f6651b39339e6734e7ca63a9c9022b","armeabi-v7a":"abbf91c8b8f3dd02a4bda8872e3b9b98","x86_64":"d6923e011add8b18a824ef5a7c85772e","x86":"ba27795b663a8420790da40d40b99f96","version":"105.0.5195.79"}

+ 3 - 2
app/src/main/assets/updateLog.md

@@ -11,10 +11,11 @@
 * 正文出现缺字漏字、内容缺失、排版错乱等情况,有可能是净化规则或简繁转换出现问题。
 * 漫画源看书显示乱码,**阅读与其他软件的源并不通用**,请导入阅读的支持的漫画源!
 
-**2022/09/03**
+**2022/09/07**
 
-* 更新cronet: 105.0.5195.77
+* 更新cronet: 105.0.5195.79
 * 更新web端书源编辑 by jgckM
+* 修复仿真翻页点击时翻页动画异常,化仿真翻页点击翻页效果 by 821938089
 
 **2022/08/31**
 

+ 1 - 1
app/src/main/java/io/legado/app/api/controller/BookController.kt

@@ -188,7 +188,7 @@ object BookController {
             }
             returnData.setData(content)
         } catch (e: Exception) {
-            returnData.setErrorMsg(e.msg)
+            returnData.setErrorMsg(e.stackTraceStr)
         }
         return returnData
     }

+ 2 - 2
app/src/main/java/io/legado/app/help/ContentProcessor.kt

@@ -9,8 +9,8 @@ import io.legado.app.data.entities.ReplaceRule
 import io.legado.app.exception.RegexTimeoutException
 import io.legado.app.help.config.AppConfig
 import io.legado.app.help.config.ReadBookConfig
-import io.legado.app.utils.msg
 import io.legado.app.utils.replace
+import io.legado.app.utils.stackTraceStr
 import io.legado.app.utils.toastOnUi
 import kotlinx.coroutines.CancellationException
 import splitties.init.appCtx
@@ -149,7 +149,7 @@ class ContentProcessor private constructor(
                 } catch (e: RegexTimeoutException) {
                     item.isEnabled = false
                     appDb.replaceRuleDao.update(item)
-                    return item.name + e.msg
+                    return item.name + e.stackTraceStr
                 } catch (e: CancellationException) {
                     return mContent
                 } catch (e: Exception) {

+ 2 - 2
app/src/main/java/io/legado/app/help/CrashHandler.kt

@@ -8,7 +8,7 @@ import io.legado.app.model.ReadAloud
 import io.legado.app.utils.FileUtils
 import io.legado.app.utils.getFile
 import io.legado.app.utils.longToastOnUi
-import io.legado.app.utils.msg
+import io.legado.app.utils.stackTraceStr
 import splitties.init.appCtx
 import java.io.PrintWriter
 import java.io.StringWriter
@@ -48,7 +48,7 @@ class CrashHandler(val context: Context) : Thread.UncaughtExceptionHandler {
         if (ex == null) return
         //保存日志文件
         saveCrashInfo2File(ex)
-        context.longToastOnUi(ex.msg)
+        context.longToastOnUi(ex.stackTraceStr)
         Thread.sleep(3000)
     }
 

+ 55 - 26
app/src/main/java/io/legado/app/help/JsExtensions.kt

@@ -27,6 +27,7 @@ import splitties.init.appCtx
 import java.io.ByteArrayInputStream
 import java.io.ByteArrayOutputStream
 import java.io.File
+import java.io.FileOutputStream
 import java.net.URLEncoder
 import java.nio.charset.Charset
 import java.text.SimpleDateFormat
@@ -56,9 +57,8 @@ interface JsExtensions {
                 analyzeUrl.getStrResponseAwait().body
             }.onFailure {
                 AppLog.put("ajax(${urlStr}) error\n${it.localizedMessage}", it)
-                it.printOnDebug()
             }.getOrElse {
-                it.msg
+                it.stackTraceStr
             }
         }
     }
@@ -91,10 +91,9 @@ interface JsExtensions {
             kotlin.runCatching {
                 analyzeUrl.getStrResponseAwait()
             }.onFailure {
-                log("connect(${urlStr}) error\n${it.stackTraceToString()}")
-                it.printOnDebug()
+                AppLog.put("connect(${urlStr}) error\n${it.localizedMessage}", it)
             }.getOrElse {
-                StrResponse(analyzeUrl.url, it.localizedMessage)
+                StrResponse(analyzeUrl.url, it.stackTraceStr)
             }
         }
     }
@@ -106,10 +105,9 @@ interface JsExtensions {
             kotlin.runCatching {
                 analyzeUrl.getStrResponseAwait()
             }.onFailure {
-                log("ajax($urlStr,$header) error\n${it.stackTraceToString()}")
-                it.printOnDebug()
+                AppLog.put("ajax($urlStr,$header) error\n${it.localizedMessage}", it)
             }.getOrElse {
-                StrResponse(analyzeUrl.url, it.localizedMessage)
+                StrResponse(analyzeUrl.url, it.stackTraceStr)
             }
         }
     }
@@ -128,7 +126,7 @@ interface JsExtensions {
                 html = html,
                 javaScript = js,
                 headerMap = getSource()?.getHeaderMap(true),
-                tag =  getSource()?.getKey()
+                tag = getSource()?.getKey()
             ).getStrResponse().body
         }
     }
@@ -146,15 +144,18 @@ interface JsExtensions {
      * 使用内置浏览器打开链接,并等待网页结果
      */
     fun startBrowserAwait(url: String, title: String): StrResponse {
-        return StrResponse(url, SourceVerificationHelp.getVerificationResult(getSource(), url, title, true))
+        return StrResponse(
+            url,
+            SourceVerificationHelp.getVerificationResult(getSource(), url, title, true)
+        )
     }
 
     /**
      * 打开图片验证码对话框,等待返回验证结果
      */
-     fun getVerificationCode(imageUrl: String): String {
-         return SourceVerificationHelp.getVerificationResult(getSource(), imageUrl, "", false)
-     }
+    fun getVerificationCode(imageUrl: String): String {
+        return SourceVerificationHelp.getVerificationResult(getSource(), imageUrl, "", false)
+    }
 
     /**
      * 可从网络,本地文件(阅读私有缓存目录和书籍保存位置支持相对路径)导入JavaScript脚本
@@ -206,6 +207,29 @@ interface JsExtensions {
         }
     }
 
+    /**
+     * 下载文件
+     * @param url 下载地址:可带参数type,文件后缀,不带默认zip
+     * @return 下载的文件相对路径
+     */
+    fun downloadFile(url: String): String {
+        val analyzeUrl = AnalyzeUrl(url, source = getSource())
+        val type = analyzeUrl.type ?: "zip"
+        val path = FileUtils.getPath(
+            FileUtils.createFolderIfNotExist(FileUtils.getCachePath()),
+            "${MD5Utils.md5Encode16(url)}.${type}"
+        )
+        FileUtils.delete(path)
+        analyzeUrl.getInputStream().use { iStream ->
+            val file = FileUtils.createFileIfNotExist(path)
+            FileOutputStream(file).use { oStream ->
+                iStream.copyTo(oStream)
+            }
+        }
+        return path.substring(FileUtils.getCachePath().length)
+    }
+
+
     /**
      * 实现16进制字符串转文件
      * @param content 需要转成文件的16进制字符串
@@ -214,18 +238,18 @@ interface JsExtensions {
      */
     fun downloadFile(content: String, url: String): String {
         val type = AnalyzeUrl(url, source = getSource()).type ?: return ""
-        val zipPath = FileUtils.getPath(
+        val path = FileUtils.getPath(
             FileUtils.createFolderIfNotExist(FileUtils.getCachePath()),
             "${MD5Utils.md5Encode16(url)}.${type}"
         )
-        FileUtils.delete(zipPath)
-        val zipFile = FileUtils.createFileIfNotExist(zipPath)
+        FileUtils.delete(path)
+        val file = FileUtils.createFileIfNotExist(path)
         StringUtils.hexStringToByte(content).let {
             if (it.isNotEmpty()) {
-                zipFile.writeBytes(it)
+                file.writeBytes(it)
             }
         }
-        return zipPath.substring(FileUtils.getCachePath().length)
+        return path.substring(FileUtils.getCachePath().length)
     }
 
     /**
@@ -436,13 +460,15 @@ interface JsExtensions {
     }
 
     /**
-     * js实现文件夹内所有文件读取
+     * js实现文件夹内所有文本文件读取
+     * @param path 文件夹相对路径
+     * @return 所有文件字符串换行连接
      */
-    fun getTxtInFolder(unzipPath: String): String {
-        if (unzipPath.isEmpty()) return ""
-        val unzipFolder = getFile(unzipPath)
+    fun getTxtInFolder(path: String): String {
+        if (path.isEmpty()) return ""
+        val folder = getFile(path)
         val contents = StringBuilder()
-        unzipFolder.listFiles().let {
+        folder.listFiles().let {
             if (it != null) {
                 for (f in it) {
                     val charsetName = EncodingDetect.getEncode(f)
@@ -452,7 +478,7 @@ interface JsExtensions {
                 contents.deleteCharAt(contents.length - 1)
             }
         }
-        FileUtils.delete(unzipFolder.absolutePath)
+        FileUtils.delete(folder.absolutePath)
         return contents.toString()
     }
 
@@ -836,7 +862,7 @@ interface JsExtensions {
     }
 
     fun desBase64DecodeToString(
-       data: String, key: String, transformation: String, iv: String
+        data: String, key: String, transformation: String, iv: String
     ): String? {
         return EncoderUtils.decryptBase64DES(
             data.encodeToByteArray(),
@@ -1031,7 +1057,10 @@ interface JsExtensions {
         algorithm: String,
         key: String
     ): String {
-        return Base64.encodeToString(HMac(algorithm, key.toByteArray()).digest(data), Base64.NO_WRAP)
+        return Base64.encodeToString(
+            HMac(algorithm, key.toByteArray()).digest(data),
+            Base64.NO_WRAP
+        )
     }
 
     fun md5Encode(str: String): String {

+ 8 - 8
app/src/main/java/io/legado/app/model/Debug.kt

@@ -9,7 +9,7 @@ import io.legado.app.model.rss.Rss
 import io.legado.app.model.webBook.WebBook
 import io.legado.app.utils.HtmlFormatter
 import io.legado.app.utils.isAbsUrl
-import io.legado.app.utils.msg
+import io.legado.app.utils.stackTraceStr
 import kotlinx.coroutines.CoroutineScope
 import java.text.SimpleDateFormat
 import java.util.*
@@ -128,7 +128,7 @@ object Debug {
                 }
             }
             .onError {
-                log(debugSource, it.msg, state = -1)
+                log(debugSource, it.stackTraceStr, state = -1)
             }
     }
 
@@ -145,7 +145,7 @@ object Debug {
                 log(debugSource, "︽内容页解析完成", state = 1000)
             }
             .onError {
-                log(debugSource, it.msg, state = -1)
+                log(debugSource, it.stackTraceStr, state = -1)
             }
     }
 
@@ -204,7 +204,7 @@ object Debug {
                 }
             }
             .onError {
-                log(debugSource, it.msg, state = -1)
+                log(debugSource, it.stackTraceStr, state = -1)
             }
         tasks.add(explore)
     }
@@ -222,7 +222,7 @@ object Debug {
                 }
             }
             .onError {
-                log(debugSource, it.msg, state = -1)
+                log(debugSource, it.stackTraceStr, state = -1)
             }
         tasks.add(search)
     }
@@ -246,7 +246,7 @@ object Debug {
                 }
             }
             .onError {
-                log(debugSource, it.msg, state = -1)
+                log(debugSource, it.stackTraceStr, state = -1)
             }
         tasks.add(info)
     }
@@ -261,7 +261,7 @@ object Debug {
                 contentDebug(scope, bookSource, book, it.first(), nextChapterUrl)
             }
             .onError {
-                log(debugSource, it.msg, state = -1)
+                log(debugSource, it.stackTraceStr, state = -1)
             }
         tasks.add(chapterList)
     }
@@ -284,7 +284,7 @@ object Debug {
         ).onSuccess {
             log(debugSource, "︽正文页解析完成", state = 1000)
         }.onError {
-            log(debugSource, it.msg, state = -1)
+            log(debugSource, it.stackTraceStr, state = -1)
         }
         tasks.add(content)
     }

+ 2 - 2
app/src/main/java/io/legado/app/model/ReadBook.kt

@@ -14,7 +14,7 @@ import io.legado.app.model.webBook.WebBook
 import io.legado.app.service.BaseReadAloudService
 import io.legado.app.ui.book.read.page.entities.TextChapter
 import io.legado.app.ui.book.read.page.provider.ChapterProvider
-import io.legado.app.utils.msg
+import io.legado.app.utils.stackTraceStr
 import io.legado.app.utils.toastOnUi
 import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.Dispatchers.IO
@@ -387,7 +387,7 @@ object ReadBook : CoroutineScope by MainScope() {
             }
         }.onError {
             AppLog.put("ChapterProvider ERROR", it)
-            appCtx.toastOnUi("ChapterProvider ERROR:\n${it.msg}")
+            appCtx.toastOnUi("ChapterProvider ERROR:\n${it.stackTraceStr}")
         }.onSuccess {
             success?.invoke()
         }

+ 1 - 1
app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeRule.kt

@@ -667,7 +667,7 @@ class AnalyzeRule(
                 log("ajax(${urlStr}) error\n${it.stackTraceToString()}")
                 it.printOnDebug()
             }.getOrElse {
-                it.msg
+                it.stackTraceStr
             }
         }
     }

+ 2 - 2
app/src/main/java/io/legado/app/ui/book/explore/ExploreShowViewModel.kt

@@ -9,8 +9,8 @@ import io.legado.app.data.appDb
 import io.legado.app.data.entities.BookSource
 import io.legado.app.data.entities.SearchBook
 import io.legado.app.model.webBook.WebBook
-import io.legado.app.utils.msg
 import io.legado.app.utils.printOnDebug
+import io.legado.app.utils.stackTraceStr
 
 import kotlinx.coroutines.Dispatchers.IO
 
@@ -46,7 +46,7 @@ class ExploreShowViewModel(application: Application) : BaseViewModel(application
                     page++
                 }.onError {
                     it.printOnDebug()
-                    errorLiveData.postValue(it.msg)
+                    errorLiveData.postValue(it.stackTraceStr)
                 }
         }
     }

+ 3 - 2
app/src/main/java/io/legado/app/ui/book/read/ReadBookViewModel.kt

@@ -254,11 +254,12 @@ class ReadBookViewModel(application: Application) : BaseViewModel(application) {
                     return@execute
                 }
             }
-            throw NoStackTraceException("自动换源失败")
+            throw NoStackTraceException("没有搜索到 ${name}(${author})")
         }.onStart {
             ReadBook.upMsg(context.getString(R.string.source_auto_changing))
         }.onError {
-            context.toastOnUi(it.msg)
+            AppLog.put("自动换源失败\n${it.localizedMessage}", it)
+            context.toastOnUi("自动换源失败\n${it.localizedMessage}")
         }.onFinally {
             ReadBook.upMsg(null)
         }

+ 1 - 1
app/src/main/java/io/legado/app/ui/book/read/config/BgTextConfigDialog.kt

@@ -322,7 +322,7 @@ class BgTextConfigDialog : BaseDialogFragment(R.layout.dialog_read_bg_text) {
                 importConfig(it)
             }
         }.onError {
-            longToast(it.msg)
+            longToast(it.stackTraceStr)
         }
     }
 

+ 69 - 63
app/src/main/java/io/legado/app/ui/book/read/page/ContentTextView.kt

@@ -16,7 +16,7 @@ import io.legado.app.help.config.AppConfig
 import io.legado.app.help.config.ReadBookConfig
 import io.legado.app.lib.theme.accentColor
 import io.legado.app.model.ReadBook
-import io.legado.app.ui.book.read.page.entities.TextChar
+import io.legado.app.ui.book.read.page.entities.TextColumn
 import io.legado.app.ui.book.read.page.entities.TextLine
 import io.legado.app.ui.book.read.page.entities.TextPage
 import io.legado.app.ui.book.read.page.entities.TextPos
@@ -30,7 +30,7 @@ import io.legado.app.utils.toastOnUi
 import kotlin.math.min
 
 /**
- * 阅读内容界面
+ * 阅读内容视图
  */
 class ContentTextView(context: Context, attrs: AttributeSet?) : View(context, attrs) {
     var selectAble = context.getPrefBoolean(PreferKey.textSelectAble, true)
@@ -51,7 +51,6 @@ class ContentTextView(context: Context, attrs: AttributeSet?) : View(context, at
     private var cacheIncreased = false
     private val increaseSize = 8 * 1024 * 1024
     private val maxCacheSize = 256 * 1024 * 1024
-    private val reviewButtonArea: ArrayList<FloatArray> = arrayListOf()
 
     //滚动参数
     private val pageFactory: TextPageFactory get() = callBack.pageFactory
@@ -68,12 +67,18 @@ class ContentTextView(context: Context, attrs: AttributeSet?) : View(context, at
         callBack = activity as CallBack
     }
 
+    /**
+     * 设置内容
+     */
     fun setContent(textPage: TextPage) {
         this.textPage = textPage
         imagePaint.isAntiAlias = AppConfig.useAntiAlias
         invalidate()
     }
 
+    /**
+     * 更新绘制区域
+     */
     fun upVisibleRect() {
         visibleRect.set(
             ChapterProvider.paddingLeft.toFloat(),
@@ -102,7 +107,6 @@ class ContentTextView(context: Context, attrs: AttributeSet?) : View(context, at
      * 绘制页面
      */
     private fun drawPage(canvas: Canvas) {
-        reviewButtonArea.clear()
         var relativeOffset = relativeOffset(0)
         textPage.textLines.forEach { textLine ->
             draw(canvas, textPage, textLine, relativeOffset)
@@ -125,6 +129,9 @@ class ContentTextView(context: Context, attrs: AttributeSet?) : View(context, at
         }
     }
 
+    /**
+     * 绘制页面
+     */
     private fun draw(
         canvas: Canvas,
         textPage: TextPage,
@@ -161,23 +168,17 @@ class ContentTextView(context: Context, attrs: AttributeSet?) : View(context, at
         reviewCountPaint.textSize = textPaint.textSize * 0.6F
         reviewCountPaint.color = textColor
         textLine.textChars.forEach {
-            if (it.isImage) {
-                drawImage(canvas, textPage, textLine, it, lineTop, lineBottom)
-            } else {
-                textPaint.color = textColor
-                if (it.isSearchResult) {
-                    textPaint.color = context.accentColor
+            when (it.style) {
+                0 -> {
+                    textPaint.color = textColor
+                    if (it.isSearchResult) {
+                        textPaint.color = context.accentColor
+                    }
+                    canvas.drawText(it.charData, it.start, lineBase, textPaint)
                 }
-                if (it.charData == "\uD83D\uDCAC" && it.isLineEnd) {
+                1 -> drawImage(canvas, textPage, textLine, it, lineTop, lineBottom)
+                2 -> {
                     if (textLine.reviewCount <= 0) return@forEach
-                    reviewButtonArea.add(
-                        floatArrayOf(
-                            it.start - textPaint.textSize * 0.4F,
-                            lineBase + textPaint.textSize * 0.2F,
-                            it.start + textPaint.textSize * 2F,
-                            lineBase - textPaint.textSize * 1F,
-                        )
-                    )
                     canvas.drawLine(
                         it.start,
                         lineBase - textPaint.textSize * 2 / 5,
@@ -243,7 +244,7 @@ class ContentTextView(context: Context, attrs: AttributeSet?) : View(context, at
                         lineBase - textPaint.textSize / 6,
                         reviewCountPaint
                     )
-                } else canvas.drawText(it.charData, it.start, lineBase, textPaint)
+                }
             }
             if (it.selected) {
                 canvas.drawRect(it.start, lineTop, it.end, lineBottom, selectedPaint)
@@ -259,7 +260,7 @@ class ContentTextView(context: Context, attrs: AttributeSet?) : View(context, at
         canvas: Canvas,
         textPage: TextPage,
         textLine: TextLine,
-        textChar: TextChar,
+        textChar: TextColumn,
         lineTop: Float,
         lineBottom: Float
     ) {
@@ -344,20 +345,11 @@ class ContentTextView(context: Context, attrs: AttributeSet?) : View(context, at
         invalidate()
     }
 
-    fun resetPageOffset() {
-        pageOffset = 0
-    }
-
     /**
-     * 点击评论按钮
+     * 重置滚动位置
      */
-    fun pressReviewButton(x: Float, y: Float): Boolean {
-        reviewButtonArea.forEach {
-            if (x in it[0]..it[2] && y in it[3]..it[1]) {
-                return true
-            }
-        }
-        return false
+    fun resetPageOffset() {
+        pageOffset = 0
     }
 
     /**
@@ -366,34 +358,49 @@ class ContentTextView(context: Context, attrs: AttributeSet?) : View(context, at
     fun longPress(
         x: Float,
         y: Float,
-        select: (relativePage: Int, lineIndex: Int, charIndex: Int) -> Unit,
+        select: (textPos: TextPos) -> Unit,
     ) {
-        touch(x, y) { _, relativePos, _, lineIndex, _, charIndex, textChar ->
-            if (textChar.isImage) {
-                callBack.onImageLongPress(x, y, textChar.charData)
+        touch(x, y) { _, textPos, _, _, textColumn ->
+            if (textColumn.style == 2) return@touch
+            if (textColumn.style == 1) {
+                callBack.onImageLongPress(x, y, textColumn.charData)
             } else {
                 if (!selectAble) return@touch
-                if (textChar.charData == "\uD83D\uDCAC" && textChar.isLineEnd) return@touch
-                textChar.selected = true
+                textColumn.selected = true
                 invalidate()
-                select(relativePos, lineIndex, charIndex)
+                select(textPos)
             }
         }
     }
 
+    /**
+     * 单击
+     * @return true:已处理, false:未处理
+     */
+    fun click(x: Float, y: Float): Boolean {
+        var handled = false
+        touch(x, y) { _, textPos, textPage, textLine, textColumn ->
+            if (textColumn.style == 2) {
+                context.toastOnUi("Button Pressed!")
+                handled = true
+            }
+        }
+        return handled
+    }
+
     /**
      * 选择文字
      */
     fun selectText(
         x: Float,
         y: Float,
-        select: (relativePage: Int, lineIndex: Int, charIndex: Int) -> Unit,
+        select: (textPos: TextPos) -> Unit,
     ) {
-        touch(x, y) { _, relativePos, _, lineIndex, _, charIndex, textChar ->
-            if (textChar.charData == "\uD83D\uDCAC" && textChar.isLineEnd) return@touch
-            textChar.selected = true
+        touch(x, y) { _, textPos, _, _, textColumn ->
+            if (textColumn.style == 2) return@touch
+            textColumn.selected = true
             invalidate()
-            select(relativePos, lineIndex, charIndex)
+            select(textPos)
         }
     }
 
@@ -401,11 +408,10 @@ class ContentTextView(context: Context, attrs: AttributeSet?) : View(context, at
      * 开始选择符移动
      */
     fun selectStartMove(x: Float, y: Float) {
-        touch(x, y) { relativeOffset, relativePos, _, lineIndex, textLine, charIndex, textChar ->
-            val pos = TextPos(relativePos, lineIndex, charIndex)
-            if (selectStart.compare(pos) != 0) {
-                if (pos.compare(selectEnd) <= 0) {
-                    selectStart.upData(pos = pos)
+        touch(x, y) { relativeOffset, textPos, _, textLine, textChar ->
+            if (selectStart.compare(textPos) != 0) {
+                if (textPos.compare(selectEnd) <= 0) {
+                    selectStart.upData(pos = textPos)
                     upSelectedStart(
                         textChar.start,
                         textLine.lineBottom + relativeOffset,
@@ -421,11 +427,10 @@ class ContentTextView(context: Context, attrs: AttributeSet?) : View(context, at
      * 结束选择符移动
      */
     fun selectEndMove(x: Float, y: Float) {
-        touch(x, y) { relativeOffset, relativePos, _, lineIndex, textLine, charIndex, textChar ->
-            val pos = TextPos(relativePos, lineIndex, charIndex)
-            if (pos.compare(selectEnd) != 0) {
-                if (pos.compare(selectStart) >= 0) {
-                    selectEnd.upData(pos)
+        touch(x, y) { relativeOffset, textPos, _, textLine, textChar ->
+            if (textPos.compare(selectEnd) != 0) {
+                if (textPos.compare(selectStart) >= 0) {
+                    selectEnd.upData(textPos)
                     upSelectedEnd(textChar.end, textLine.lineBottom + relativeOffset)
                     upSelectChars()
                 }
@@ -433,17 +438,19 @@ class ContentTextView(context: Context, attrs: AttributeSet?) : View(context, at
         }
     }
 
+    /**
+     * 触碰位置信息
+     * @param touched 回调
+     */
     private fun touch(
         x: Float,
         y: Float,
         touched: (
             relativeOffset: Float,
-            relativePos: Int,
+            textPos: TextPos,
             textPage: TextPage,
-            lineIndex: Int,
             textLine: TextLine,
-            charIndex: Int,
-            textChar: TextChar
+            textColumn: TextColumn
         ) -> Unit
     ) {
         if (!visibleRect.contains(x, y)) return
@@ -462,9 +469,8 @@ class ContentTextView(context: Context, attrs: AttributeSet?) : View(context, at
                         if (textChar.isTouch(x)) {
                             touched.invoke(
                                 relativeOffset,
-                                relativePos, textPage,
-                                lineIndex, textLine,
-                                charIndex, textChar
+                                TextPos(relativePos, lineIndex, charIndex),
+                                textPage, textLine, textChar
                             )
                             return
                         }
@@ -514,7 +520,7 @@ class ContentTextView(context: Context, attrs: AttributeSet?) : View(context, at
                 textPos.lineIndex = lineIndex
                 for ((charIndex, textChar) in textLine.textChars.withIndex()) {
                     textPos.charIndex = charIndex
-                    if (textChar.charData == "\uD83D\uDCAC" && textChar.isLineEnd) continue
+                    if (textChar.style == 2) continue
                     textChar.selected =
                         textPos.compare(selectStart) >= 0 && textPos.compare(selectEnd) <= 0
                     textChar.isSearchResult = textChar.selected && callBack.isSelectingSearchResult

+ 56 - 5
app/src/main/java/io/legado/app/ui/book/read/page/PageView.kt

@@ -14,6 +14,7 @@ import io.legado.app.help.config.ReadTipConfig
 import io.legado.app.model.ReadBook
 import io.legado.app.ui.book.read.ReadBookActivity
 import io.legado.app.ui.book.read.page.entities.TextPage
+import io.legado.app.ui.book.read.page.entities.TextPos
 import io.legado.app.ui.book.read.page.provider.ChapterProvider
 import io.legado.app.ui.widget.BatteryView
 import io.legado.app.utils.activity
@@ -24,7 +25,7 @@ import splitties.views.backgroundColor
 import java.util.*
 
 /**
- * 阅读界面
+ * 页面视图
  */
 class PageView(context: Context) : FrameLayout(context) {
 
@@ -104,6 +105,9 @@ class PageView(context: Context) : FrameLayout(context) {
         isGone = ReadBookConfig.hideStatusBar || readBookActivity?.isInMultiWindow == true
     }
 
+    /**
+     * 更新阅读信息
+     */
     private fun upTipStyle() = binding.run {
         tvHeaderLeft.tag = null
         tvHeaderMiddle.tag = null
@@ -189,6 +193,10 @@ class PageView(context: Context) : FrameLayout(context) {
         }
     }
 
+    /**
+     * 获取信息视图
+     * @param tip 信息类型
+     */
     private fun getTipView(tip: Int): BatteryView? = binding.run {
         return when (tip) {
             ReadTipConfig.tipHeaderLeft -> tvHeaderLeft
@@ -201,6 +209,9 @@ class PageView(context: Context) : FrameLayout(context) {
         }
     }
 
+    /**
+     * 更新背景
+     */
     fun upBg() {
         if (ReadBookConfig.bgAlpha < 100) {
             binding.vwRoot.backgroundColor = ReadBookConfig.bgMeanColor
@@ -211,15 +222,24 @@ class PageView(context: Context) : FrameLayout(context) {
         upBgAlpha()
     }
 
+    /**
+     * 更新背景透明度
+     */
     fun upBgAlpha() {
         binding.vwBg.alpha = ReadBookConfig.bgAlpha / 100f
     }
 
+    /**
+     * 更新时间信息
+     */
     fun upTime() {
         tvTime?.text = timeFormat.format(Date(System.currentTimeMillis()))
         upTimeBattery()
     }
 
+    /**
+     * 更新电池信息
+     */
     @SuppressLint("SetTextI18n")
     fun upBattery(battery: Int) {
         this.battery = battery
@@ -228,6 +248,9 @@ class PageView(context: Context) : FrameLayout(context) {
         upTimeBattery()
     }
 
+    /**
+     * 更新电池信息
+     */
     @SuppressLint("SetTextI18n")
     private fun upTimeBattery() {
         val time = timeFormat.format(Date(System.currentTimeMillis()))
@@ -235,6 +258,9 @@ class PageView(context: Context) : FrameLayout(context) {
         tvTimeBatteryP?.text = "$time $battery%"
     }
 
+    /**
+     * 设置内容
+     */
     fun setContent(textPage: TextPage, resetPageOffset: Boolean = true) {
         setProgress(textPage)
         if (resetPageOffset) {
@@ -243,14 +269,23 @@ class PageView(context: Context) : FrameLayout(context) {
         binding.contentTextView.setContent(textPage)
     }
 
+    /**
+     * 设置无障碍文本
+     */
     fun setContentDescription(content: String) {
         binding.contentTextView.contentDescription = content
     }
 
+    /**
+     * 重置滚动位置
+     */
     fun resetPageOffset() {
         binding.contentTextView.resetPageOffset()
     }
 
+    /**
+     * 设置进度
+     */
     @SuppressLint("SetTextI18n")
     fun setProgress(textPage: TextPage) = textPage.apply {
         tvBookName?.text = ReadBook.book?.name
@@ -260,28 +295,44 @@ class PageView(context: Context) : FrameLayout(context) {
         tvPageAndTotal?.text = "${index.plus(1)}/$pageSize  $readProgress"
     }
 
+    /**
+     * 滚动事件
+     */
     fun scroll(offset: Int) {
         binding.contentTextView.scroll(offset)
     }
 
+    /**
+     * 更新是否开启选择功能
+     */
     fun upSelectAble(selectAble: Boolean) {
         binding.contentTextView.selectAble = selectAble
     }
 
-    fun pressReviewButton(x: Float, y: Float): Boolean {
-        return binding.contentTextView.pressReviewButton(x, y - headerHeight)
+    /**
+     * 优先处理页面内单击
+     * @return true:已处理, false:未处理
+     */
+    fun onClick(x: Float, y: Float): Boolean {
+        return binding.contentTextView.click(x, y - headerHeight)
     }
 
+    /**
+     * 长按事件
+     */
     fun longPress(
         x: Float, y: Float,
-        select: (relativePagePos: Int, lineIndex: Int, charIndex: Int) -> Unit,
+        select: (textPos: TextPos) -> Unit,
     ) {
         return binding.contentTextView.longPress(x, y - headerHeight, select)
     }
 
+    /**
+     * 选择文本
+     */
     fun selectText(
         x: Float, y: Float,
-        select: (relativePagePos: Int, lineIndex: Int, charIndex: Int) -> Unit,
+        select: (textPos: TextPos) -> Unit,
     ) {
         return binding.contentTextView.selectText(x, y - headerHeight, select)
     }

+ 28 - 19
app/src/main/java/io/legado/app/ui/book/read/page/ReadView.kt

@@ -33,7 +33,9 @@ import java.text.BreakIterator
 import java.util.*
 import kotlin.math.abs
 
-
+/**
+ * 阅读视图
+ */
 class ReadView(context: Context, attrs: AttributeSet) :
     FrameLayout(context, attrs),
     DataSource {
@@ -223,7 +225,9 @@ class ReadView(context: Context, attrs: AttributeSet) :
                 pressDown = false
                 if (!isPageMove) {
                     if (!longPressed && !pressOnTextSelected) {
-                        onSingleTapUp()
+                        if (!curPage.onClick(startX, startY)) {
+                            onSingleTapUp()
+                        }
                         return true
                     }
                 }
@@ -293,18 +297,18 @@ class ReadView(context: Context, attrs: AttributeSet) :
      */
     private fun onLongPress() {
         kotlin.runCatching {
-            curPage.longPress(startX, startY) { relativePos, lineIndex, charIndex ->
+            curPage.longPress(startX, startY) { textPos: TextPos ->
                 isTextSelected = true
                 pressOnTextSelected = true
-                initialTextPos.upData(relativePos, lineIndex, charIndex)
-                val startPos = TextPos(relativePos, lineIndex, charIndex)
-                val endPos = TextPos(relativePos, lineIndex, charIndex)
-                val page = curPage.relativePage(relativePos)
+                initialTextPos.upData(textPos)
+                val startPos = textPos.copy()
+                val endPos = textPos.copy()
+                val page = curPage.relativePage(textPos.relativePagePos)
                 val stringBuilder = StringBuilder()
-                var cIndex = charIndex
-                var lineStart = lineIndex
-                var lineEnd = lineIndex
-                for (index in lineIndex - 1 downTo 0) {
+                var cIndex = textPos.charIndex
+                var lineStart = textPos.lineIndex
+                var lineEnd = textPos.lineIndex
+                for (index in textPos.lineIndex - 1 downTo 0) {
                     val textLine = page.getLine(index)
                     if (textLine.isParagraphEnd) {
                         break
@@ -314,7 +318,7 @@ class ReadView(context: Context, attrs: AttributeSet) :
                         cIndex += textLine.charSize
                     }
                 }
-                for (index in lineIndex until page.lineSize) {
+                for (index in textPos.lineIndex until page.lineSize) {
                     val textLine = page.getLine(index)
                     stringBuilder.append(textLine.text)
                     lineEnd += 1
@@ -370,9 +374,6 @@ class ReadView(context: Context, attrs: AttributeSet) :
      */
     private fun onSingleTapUp() {
         when {
-            curPage.pressReviewButton(startX, startY) -> {
-                context.toastOnUi("Button Pressed!")
-            }
             isTextSelected -> Unit
             mcRect.contains(startX, startY) -> if (!isAbortAnim) {
                 click(AppConfig.clickActionMC)
@@ -423,11 +424,15 @@ class ReadView(context: Context, attrs: AttributeSet) :
      * 选择文本
      */
     private fun selectText(x: Float, y: Float) {
-        curPage.selectText(x, y) { relativePagePos, lineIndex, charIndex ->
-            val compare = initialTextPos.compare(relativePagePos, lineIndex, charIndex)
+        curPage.selectText(x, y) { textPos ->
+            val compare = initialTextPos.compare(textPos)
             when {
                 compare >= 0 -> {
-                    curPage.selectStartMoveIndex(relativePagePos, lineIndex, charIndex)
+                    curPage.selectStartMoveIndex(
+                        textPos.relativePagePos,
+                        textPos.lineIndex,
+                        textPos.charIndex
+                    )
                     curPage.selectEndMoveIndex(
                         initialTextPos.relativePagePos,
                         initialTextPos.lineIndex,
@@ -440,7 +445,11 @@ class ReadView(context: Context, attrs: AttributeSet) :
                         initialTextPos.lineIndex,
                         initialTextPos.charIndex
                     )
-                    curPage.selectEndMoveIndex(relativePagePos, lineIndex, charIndex)
+                    curPage.selectEndMoveIndex(
+                        textPos.relativePagePos,
+                        textPos.lineIndex,
+                        textPos.charIndex
+                    )
                 }
             }
         }

+ 5 - 1
app/src/main/java/io/legado/app/ui/book/read/page/delegate/HorizontalPageDelegate.kt

@@ -119,7 +119,11 @@ abstract class HorizontalPageDelegate(readView: ReadView) : PageDelegate(readVie
         abortAnim()
         if (!hasNext()) return
         setDirection(PageDirection.NEXT)
-        readView.setStartPoint(viewWidth.toFloat(), 1f, false)
+        val y = when {
+            viewHeight / 2 < startY -> viewHeight.toFloat() * 0.9f
+            else -> 1f
+        }
+        readView.setStartPoint(viewWidth.toFloat() * 0.9f, y, false)
         onAnimStart(animationSpeed)
     }
 

+ 3 - 0
app/src/main/java/io/legado/app/ui/book/read/page/entities/TextChapter.kt

@@ -2,6 +2,9 @@ package io.legado.app.ui.book.read.page.entities
 
 import kotlin.math.min
 
+/**
+ * 章节信息
+ */
 @Suppress("unused")
 data class TextChapter(
     val position: Int,

+ 6 - 4
app/src/main/java/io/legado/app/ui/book/read/page/entities/TextChar.kt → app/src/main/java/io/legado/app/ui/book/read/page/entities/TextColumn.kt

@@ -1,13 +1,15 @@
 package io.legado.app.ui.book.read.page.entities
 
-data class TextChar(
+/**
+ * 字符信息
+ */
+data class TextColumn(
     val charData: String,
     var start: Float,
     var end: Float,
+    val style: Int = 0, //0:文字,1:图片,2:按钮
     var selected: Boolean = false,
-    var isImage: Boolean = false,
-    var isSearchResult: Boolean = false,
-    var isLineEnd: Boolean = false
+    var isSearchResult: Boolean = false
 ) {
 
     fun isTouch(x: Float): Boolean {

+ 6 - 3
app/src/main/java/io/legado/app/ui/book/read/page/entities/TextLine.kt

@@ -4,10 +4,13 @@ import android.text.TextPaint
 import io.legado.app.ui.book.read.page.provider.ChapterProvider
 import io.legado.app.utils.textHeight
 
+/**
+ * 行信息
+ */
 @Suppress("unused", "MemberVisibilityCanBePrivate")
 data class TextLine(
     var text: String = "",
-    val textChars: ArrayList<TextChar> = arrayListOf(),
+    val textChars: ArrayList<TextColumn> = arrayListOf(),
     val reviewCount: Int = 1,
     var lineTop: Float = 0f,
     var lineBase: Float = 0f,
@@ -28,13 +31,13 @@ data class TextLine(
         lineBase = lineBottom - textPaint.fontMetrics.descent
     }
 
-    fun getTextChar(index: Int): TextChar {
+    fun getTextChar(index: Int): TextColumn {
         return textChars.getOrElse(index) {
             textChars.last()
         }
     }
 
-    fun getTextCharReverseAt(index: Int): TextChar {
+    fun getTextCharReverseAt(index: Int): TextColumn {
         return textChars[textChars.lastIndex - index]
     }
 

+ 5 - 2
app/src/main/java/io/legado/app/ui/book/read/page/entities/TextPage.kt

@@ -11,6 +11,9 @@ import splitties.init.appCtx
 import java.text.DecimalFormat
 import kotlin.math.min
 
+/**
+ * 页面信息
+ */
 @Suppress("unused", "MemberVisibilityCanBePrivate")
 data class TextPage(
     var index: Int = 0,
@@ -111,11 +114,11 @@ data class TextPage(
                     val cw = StaticLayout.getDesiredWidth(char, ChapterProvider.contentPaint)
                     val x1 = x + cw
                     textLine.textChars.add(
-                        TextChar(
+                        TextColumn(
                             char,
                             start = x,
                             end = x1,
-                            isLineEnd = textLine.text.length - 1 == i
+                            style = if (textLine.text.length - 1 == index && char == "\uD83D\uDCAC") 2 else 0
                         )
                     )
                     x = x1

+ 3 - 0
app/src/main/java/io/legado/app/ui/book/read/page/entities/TextPos.kt

@@ -1,5 +1,8 @@
 package io.legado.app.ui.book.read.page.entities
 
+/**
+ * 位置信息
+ */
 data class TextPos(
     var relativePagePos: Int,
     var lineIndex: Int,

+ 13 - 13
app/src/main/java/io/legado/app/ui/book/read/page/provider/ChapterProvider.kt

@@ -14,7 +14,7 @@ import io.legado.app.help.config.AppConfig
 import io.legado.app.help.config.ReadBookConfig
 import io.legado.app.model.ReadBook
 import io.legado.app.ui.book.read.page.entities.TextChapter
-import io.legado.app.ui.book.read.page.entities.TextChar
+import io.legado.app.ui.book.read.page.entities.TextColumn
 import io.legado.app.ui.book.read.page.entities.TextLine
 import io.legado.app.ui.book.read.page.entities.TextPage
 import io.legado.app.utils.*
@@ -264,7 +264,7 @@ object ChapterProvider {
                 Pair(0f, width.toFloat())
             }
             textLine.textChars.add(
-                TextChar(charData = src, start = x + start, end = x + end, isImage = true)
+                TextColumn(charData = src, start = x + start, end = x + end, style = 1)
             )
             textPages.last().textLines.add(textLine)
         }
@@ -409,14 +409,13 @@ object ChapterProvider {
         }
         val bodyIndent = ReadBookConfig.paragraphIndent
         val icw = StaticLayout.getDesiredWidth(bodyIndent, textPaint) / bodyIndent.length
-        for ((index, char) in bodyIndent.toStringArray().withIndex()) {
+        for (char in bodyIndent.toStringArray()) {
             val x1 = x + icw
             textLine.textChars.add(
-                TextChar(
+                TextColumn(
                     charData = char,
                     start = absStartX + x,
-                    end = absStartX + x1,
-                    isLineEnd = bodyIndent.length - 1 == index
+                    end = absStartX + x1
                 )
             )
             x = x1
@@ -452,7 +451,7 @@ object ChapterProvider {
         words.forEachIndexed { index, char ->
             val cw = StaticLayout.getDesiredWidth(char, textPaint)
             val x1 = if (index != words.lastIndex) (x + cw + d) else (x + cw)
-            addCharToLine(book, absStartX, textLine, char, x, x1, srcList)
+            addCharToLine(book, absStartX, textLine, char, x, x1, index + 1 == words.size, srcList)
             x = x1
         }
         exceed(absStartX, textLine, words)
@@ -471,10 +470,10 @@ object ChapterProvider {
         srcList: LinkedList<String>?
     ) {
         var x = startX
-        words.forEach { char ->
+        words.forEachIndexed { index, char ->
             val cw = StaticLayout.getDesiredWidth(char, textPaint)
             val x1 = x + cw
-            addCharToLine(book, absStartX, textLine, char, x, x1, srcList)
+            addCharToLine(book, absStartX, textLine, char, x, x1, index + 1 == words.size, srcList)
             x = x1
         }
         exceed(absStartX, textLine, words)
@@ -490,26 +489,27 @@ object ChapterProvider {
         char: String,
         xStart: Float,
         xEnd: Float,
+        isLineEnd: Boolean,
         srcList: LinkedList<String>?
     ) {
         if (srcList != null && char == srcReplaceChar) {
             val src = srcList.removeFirst()
             ImageProvider.cacheImage(book, src, ReadBook.bookSource)
             textLine.textChars.add(
-                TextChar(
+                TextColumn(
                     charData = src,
                     start = absStartX + xStart,
                     end = absStartX + xEnd,
-                    isImage = true
+                    style = 1
                 )
             )
         } else {
             textLine.textChars.add(
-                TextChar(
+                TextColumn(
                     charData = char,
                     start = absStartX + xStart,
                     end = absStartX + xEnd,
-                    isLineEnd = true
+                    style = if (isLineEnd && char == "\uD83D\uDCAC") 2 else 0
                 )
             )
         }

+ 1 - 1
app/src/main/java/io/legado/app/ui/book/source/manage/BookSourceViewModel.kt

@@ -128,7 +128,7 @@ class BookSourceViewModel(application: Application) : BaseViewModel(application)
         }.onSuccess {
             success.invoke(it)
         }.onError {
-            context.toastOnUi(it.msg)
+            context.toastOnUi(it.stackTraceStr)
         }
     }
 

+ 2 - 2
app/src/main/java/io/legado/app/ui/rss/source/edit/RssSourceEditViewModel.kt

@@ -8,8 +8,8 @@ import io.legado.app.data.entities.RssSource
 import io.legado.app.help.RuleComplete
 import io.legado.app.help.http.CookieStore
 import io.legado.app.utils.getClipText
-import io.legado.app.utils.msg
 import io.legado.app.utils.printOnDebug
+import io.legado.app.utils.stackTraceStr
 
 import io.legado.app.utils.toastOnUi
 import kotlinx.coroutines.Dispatchers
@@ -74,7 +74,7 @@ class RssSourceEditViewModel(application: Application) : BaseViewModel(applicati
                 finally.invoke(it)
             }
         }.onError {
-            context.toastOnUi(it.msg)
+            context.toastOnUi(it.stackTraceStr)
         }
     }
 

+ 1 - 1
app/src/main/java/io/legado/app/ui/rss/source/manage/RssSourceViewModel.kt

@@ -83,7 +83,7 @@ class RssSourceViewModel(application: Application) : BaseViewModel(application)
         }.onSuccess {
             success.invoke(it)
         }.onError {
-            context.toastOnUi(it.msg)
+            context.toastOnUi(it.stackTraceStr)
         }
     }
 

+ 1 - 1
app/src/main/java/io/legado/app/utils/ContextExtensions.kt

@@ -325,7 +325,7 @@ fun Context.openFileUri(uri: Uri, type: String? = null) {
     try {
         startActivity(intent)
     } catch (e: Exception) {
-        toastOnUi(e.msg)
+        toastOnUi(e.stackTraceStr)
     }
 }
 

+ 1 - 1
app/src/main/java/io/legado/app/utils/ThrowableExtensions.kt

@@ -2,7 +2,7 @@ package io.legado.app.utils
 
 import java.io.IOException
 
-val Throwable.msg: String
+val Throwable.stackTraceStr: String
     get() {
         val stackTrace = stackTraceToString()
         val lMsg = this.localizedMessage ?: "noErrorMsg"

+ 1 - 1
gradle.properties

@@ -26,4 +26,4 @@ android.experimental.enableNewResourceShrinker.preciseShrinking=true
 # 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=105.0.5195.77
+CronetVersion=105.0.5195.79