Horis 3 years ago
parent
commit
be0faf93da

+ 26 - 9
app/src/main/java/io/legado/app/ui/book/read/ReadBookActivity.kt

@@ -605,19 +605,36 @@ class ReadBookActivity : BaseReadBookActivity(),
             MotionEvent.ACTION_DOWN -> textActionMenu.dismiss()
             MotionEvent.ACTION_MOVE -> {
                 when (v.id) {
-                    R.id.cursor_left -> readView.curPage.selectStartMove(
-                        event.rawX + cursorLeft.width,
-                        event.rawY - cursorLeft.height
-                    )
+                    R.id.cursor_left -> if (!readView.curPage.getReverseStartCursor()) {
+                        readView.curPage.selectStartMove(
+                            event.rawX + cursorLeft.width,
+                            event.rawY - cursorLeft.height
+                        )
+                    } else {
+                        readView.curPage.selectEndMove(
+                            event.rawX - cursorRight.width,
+                            event.rawY - cursorRight.height
+                        )
+                    }
 
-                    R.id.cursor_right -> readView.curPage.selectEndMove(
-                        event.rawX - cursorRight.width,
-                        event.rawY - cursorRight.height
-                    )
+                    R.id.cursor_right -> if (readView.curPage.getReverseEndCursor()) {
+                        readView.curPage.selectStartMove(
+                            event.rawX + cursorLeft.width,
+                            event.rawY - cursorLeft.height
+                        )
+                    } else {
+                        readView.curPage.selectEndMove(
+                            event.rawX - cursorRight.width,
+                            event.rawY - cursorRight.height
+                        )
+                    }
                 }
             }
 
-            MotionEvent.ACTION_UP -> showTextActionMenu()
+            MotionEvent.ACTION_UP -> {
+                readView.curPage.resetReverseCursor()
+                showTextActionMenu()
+            }
         }
         return true
     }

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

@@ -55,6 +55,8 @@ class ContentTextView(context: Context, attrs: AttributeSet?) : View(context, at
     } else {
         256 * 1024 * 1024
     }
+    var reverseStartCursor = false
+    var reverseEndCursor = false
 
     //滚动参数
     private val pageFactory: TextPageFactory get() = callBack.pageFactory
@@ -373,17 +375,27 @@ class ContentTextView(context: Context, attrs: AttributeSet?) : View(context, at
      */
     fun selectStartMove(x: Float, y: Float) {
         touchRough(x, y) { relativeOffset, textPos, _, textLine, textColumn ->
-            if (selectStart.compare(textPos) != 0) {
-                if (textPos.compare(selectEnd) <= 0) {
-                    selectStart.upData(pos = textPos)
-                    upSelectedStart(
-                        textColumn.start,
-                        textLine.lineBottom + relativeOffset,
-                        textLine.lineTop + relativeOffset
-                    )
-                    upSelectChars()
-                }
+            if (selectStart.compare(textPos) == 0) {
+                return@touchRough
+            }
+            if (textPos.compare(selectEnd) <= 0) {
+                selectStart.upData(pos = textPos)
+                upSelectedStart(
+                    if (textPos.isTouch) textColumn.start else textColumn.end,
+                    textLine.lineBottom + relativeOffset,
+                    textLine.lineTop + relativeOffset
+                )
+            } else {
+                reverseStartCursor = true
+                reverseEndCursor = false
+                selectStartMoveIndex(selectEnd)
+                selectEnd.upData(textPos)
+                upSelectedEnd(
+                    if (selectEnd.isTouch || selectEnd.isLast) textColumn.end else textColumn.start,
+                    textLine.lineBottom + relativeOffset
+                )
             }
+            upSelectChars()
         }
     }
 
@@ -392,13 +404,27 @@ class ContentTextView(context: Context, attrs: AttributeSet?) : View(context, at
      */
     fun selectEndMove(x: Float, y: Float) {
         touchRough(x, y) { relativeOffset, textPos, _, textLine, textColumn ->
-            if (textPos.compare(selectEnd) != 0) {
-                if (textPos.compare(selectStart) >= 0) {
-                    selectEnd.upData(textPos)
-                    upSelectedEnd(textColumn.end, textLine.lineBottom + relativeOffset)
-                    upSelectChars()
-                }
+            if (textPos.compare(selectEnd) == 0) {
+                return@touchRough
+            }
+            if (textPos.compare(selectStart) >= 0) {
+                selectEnd.upData(textPos)
+                upSelectedEnd(
+                    if (selectEnd.isTouch || selectEnd.isLast) textColumn.end else textColumn.start,
+                    textLine.lineBottom + relativeOffset
+                )
+            } else {
+                reverseEndCursor = true
+                reverseStartCursor = false
+                selectEndMoveIndex(selectStart)
+                selectStart.upData(textPos)
+                upSelectedStart(
+                    if (textPos.isTouch) textColumn.start else textColumn.end,
+                    textLine.lineBottom + relativeOffset,
+                    textLine.lineTop + relativeOffset
+                )
             }
+            upSelectChars()
         }
     }
 
@@ -461,7 +487,6 @@ class ContentTextView(context: Context, attrs: AttributeSet?) : View(context, at
             column: BaseColumn
         ) -> Unit
     ) {
-        if (!visibleRect.contains(x, y)) return
         var relativeOffset: Float
         for (relativePos in 0..2) {
             relativeOffset = relativeOffset(relativePos)
@@ -483,10 +508,15 @@ class ContentTextView(context: Context, attrs: AttributeSet?) : View(context, at
                             return
                         }
                     }
-                    val (charIndex, textColumn) = textLine.columns.withIndex().last()
+                    val isLast = textLine.columns.first().start < x
+                    val (charIndex, textColumn) = if (isLast) {
+                        textLine.columns.withIndex().last()
+                    } else {
+                        textLine.columns.withIndex().first()
+                    }
                     touched.invoke(
                         relativeOffset,
-                        TextPos(relativePos, lineIndex, charIndex),
+                        TextPos(relativePos, lineIndex, charIndex, false, isLast),
                         textPage, textLine, textColumn
                     )
                     return
@@ -545,10 +575,18 @@ class ContentTextView(context: Context, attrs: AttributeSet?) : View(context, at
     /**
      * 选择开始文字
      */
-    fun selectStartMoveIndex(relativePagePos: Int, lineIndex: Int, charIndex: Int) {
+    fun selectStartMoveIndex(
+        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(
@@ -559,19 +597,35 @@ class ContentTextView(context: Context, attrs: AttributeSet?) : View(context, at
         upSelectChars()
     }
 
+    fun selectStartMoveIndex(textPos: TextPos) = textPos.run {
+        selectStartMoveIndex(relativePagePos, lineIndex, columnIndex, isTouch, isLast)
+    }
+
     /**
      * 选择结束文字
      */
-    fun selectEndMoveIndex(relativePage: Int, lineIndex: Int, charIndex: Int) {
+    fun selectEndMoveIndex(
+        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(textColumn.end, textLine.lineBottom + relativeOffset(relativePage))
         upSelectChars()
     }
 
+    fun selectEndMoveIndex(textPos: TextPos) = textPos.run {
+        selectEndMoveIndex(relativePagePos, lineIndex, columnIndex, isTouch, isLast)
+    }
+
     private fun upSelectChars() {
         val last = if (callBack.isScroll) 2 else 0
         val textPos = TextPos(0, 0, 0)
@@ -583,8 +637,14 @@ class ContentTextView(context: Context, attrs: AttributeSet?) : View(context, at
                 for ((charIndex, column) in textLine.columns.withIndex()) {
                     textPos.columnIndex = charIndex
                     if (column is TextColumn) {
-                        column.selected =
-                            textPos.compare(selectStart) >= 0 && textPos.compare(selectEnd) <= 0
+                        val compareStart = textPos.compare(selectStart)
+                        val compareEnd = textPos.compare(selectEnd)
+                        column.selected = when {
+                            compareStart == 0 -> selectStart.isTouch
+                            compareEnd == 0 -> selectEnd.isTouch || selectEnd.isLast
+                            compareStart > 0 && compareEnd < 0 -> true
+                            else -> false
+                        }
                         column.isSearchResult =
                             column.selected && callBack.isSelectingSearchResult
                         if (column.isSearchResult) {
@@ -609,6 +669,11 @@ class ContentTextView(context: Context, attrs: AttributeSet?) : View(context, at
         }
     }
 
+    fun resetReverseCursor() {
+        reverseStartCursor = false
+        reverseEndCursor = false
+    }
+
     fun cancelSelect(clearSearchResult: Boolean = false) {
         val last = if (callBack.isScroll) 2 else 0
         for (relativePos in 0..last) {
@@ -641,16 +706,34 @@ class ContentTextView(context: Context, attrs: AttributeSet?) : View(context, at
                     textPos.columnIndex = charIndex
                     val compareStart = textPos.compare(selectStart)
                     val compareEnd = textPos.compare(selectEnd)
-                    if (compareStart >= 0 && compareEnd <= 0) {
-                        if (column is TextColumn) {
-                            builder.append(column.charData)
-                        }
-                        if (
-                            textLine.isParagraphEnd
-                            && charIndex == textLine.charSize - 1
-                            && compareEnd != 0
-                        ) {
-                            builder.append("\n")
+                    if (column is TextColumn) {
+                        when {
+                            compareStart == 0 -> {
+                                if (selectStart.isTouch) {
+                                    builder.append(column.charData)
+                                }
+                                if (
+                                    textLine.isParagraphEnd
+                                    && charIndex == textLine.charSize - 1
+                                    && compareEnd != 0
+                                ) {
+                                    builder.append("\n")
+                                }
+                            }
+
+                            compareEnd == 0 -> if (selectEnd.isTouch || selectEnd.isLast) {
+                                builder.append(column.charData)
+                            }
+
+                            compareStart > 0 && compareEnd < 0 -> {
+                                builder.append(column.charData)
+                                if (
+                                    textLine.isParagraphEnd
+                                    && charIndex == textLine.charSize - 1
+                                ) {
+                                    builder.append("\n")
+                                }
+                            }
                         }
                     }
                 }

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

@@ -365,16 +365,60 @@ class PageView(context: Context) : FrameLayout(context) {
         binding.contentTextView.selectStartMove(x, y - headerHeight)
     }
 
-    fun selectStartMoveIndex(relativePagePos: Int, lineIndex: Int, charIndex: Int) {
-        binding.contentTextView.selectStartMoveIndex(relativePagePos, lineIndex, charIndex)
+    fun selectStartMoveIndex(
+        relativePagePos: Int,
+        lineIndex: Int,
+        charIndex: Int,
+        isTouch: Boolean = true,
+        isLast: Boolean = false
+    ) {
+        binding.contentTextView.selectStartMoveIndex(
+            relativePagePos,
+            lineIndex,
+            charIndex,
+            isTouch,
+            isLast
+        )
+    }
+
+    fun selectStartMoveIndex(textPos: TextPos) {
+        binding.contentTextView.selectStartMoveIndex(textPos)
     }
 
     fun selectEndMove(x: Float, y: Float) {
         binding.contentTextView.selectEndMove(x, y - headerHeight)
     }
 
-    fun selectEndMoveIndex(relativePagePos: Int, lineIndex: Int, charIndex: Int) {
-        binding.contentTextView.selectEndMoveIndex(relativePagePos, lineIndex, charIndex)
+    fun selectEndMoveIndex(
+        relativePagePos: Int,
+        lineIndex: Int,
+        charIndex: Int,
+        isTouch: Boolean = true,
+        isLast: Boolean = false
+    ) {
+        binding.contentTextView.selectEndMoveIndex(
+            relativePagePos,
+            lineIndex,
+            charIndex,
+            isTouch,
+            isLast
+        )
+    }
+
+    fun selectEndMoveIndex(textPos: TextPos) {
+        binding.contentTextView.selectEndMoveIndex(textPos)
+    }
+
+    fun getReverseStartCursor(): Boolean {
+        return binding.contentTextView.reverseStartCursor
+    }
+
+    fun getReverseEndCursor(): Boolean {
+        return binding.contentTextView.reverseEndCursor
+    }
+
+    fun resetReverseCursor() {
+        binding.contentTextView.resetReverseCursor()
     }
 
     fun cancelSelect(clearSearchResult: Boolean = false) {

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

@@ -360,16 +360,8 @@ class ReadView(context: Context, attrs: AttributeSet) :
                         }
                     }
                 }
-                curPage.selectStartMoveIndex(
-                    startPos.relativePagePos,
-                    startPos.lineIndex,
-                    startPos.columnIndex
-                )
-                curPage.selectEndMoveIndex(
-                    endPos.relativePagePos,
-                    endPos.lineIndex,
-                    endPos.columnIndex
-                )
+                curPage.selectStartMoveIndex(startPos)
+                curPage.selectEndMoveIndex(endPos)
             }
         }
     }
@@ -441,28 +433,12 @@ class ReadView(context: Context, attrs: AttributeSet) :
             val compare = initialTextPos.compare(textPos)
             when {
                 compare >= 0 -> {
-                    curPage.selectStartMoveIndex(
-                        textPos.relativePagePos,
-                        textPos.lineIndex,
-                        textPos.columnIndex
-                    )
-                    curPage.selectEndMoveIndex(
-                        initialTextPos.relativePagePos,
-                        initialTextPos.lineIndex,
-                        initialTextPos.columnIndex
-                    )
+                    curPage.selectStartMoveIndex(textPos)
+                    curPage.selectEndMoveIndex(initialTextPos)
                 }
                 else -> {
-                    curPage.selectStartMoveIndex(
-                        initialTextPos.relativePagePos,
-                        initialTextPos.lineIndex,
-                        initialTextPos.columnIndex
-                    )
-                    curPage.selectEndMoveIndex(
-                        textPos.relativePagePos,
-                        textPos.lineIndex,
-                        textPos.columnIndex
-                    )
+                    curPage.selectStartMoveIndex(initialTextPos)
+                    curPage.selectEndMoveIndex(textPos)
                 }
             }
         }

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

@@ -10,19 +10,31 @@ import androidx.annotation.Keep
 data class TextPos(
     var relativePagePos: Int,
     var lineIndex: Int,
-    var columnIndex: Int
+    var columnIndex: Int,
+    var isTouch: Boolean = true,
+    var isLast: Boolean = false
 ) {
 
-    fun upData(relativePos: Int, lineIndex: Int, charIndex: Int) {
+    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 {

+ 3 - 3
app/src/main/res/values-es-rES/strings.xml

@@ -378,7 +378,7 @@
     <string name="behavior_main_t">Ocultar automáticamente la barra de herramientas</string>
     <string name="behavior_main_s">La barra de herramientas se ocultará automáticamente cuando deslice la Librería</string>
     <string name="login">Iniciar sesión</string>
-    <string name="login_source">Iniciar sesión% s</string>
+    <string name="login_source">Iniciar sesión %s</string>
     <string name="success">Completado</string>
     <string name="source_no_login">La fuente actual no se ha configurado con una dirección de inicio de sesión</string>
     <string name="no_prev_page">Sin página anterior</string>
@@ -450,7 +450,7 @@
     <string name="error_get_book_info">Error al obtener la información del libro</string>
     <string name="error_get_content">Error al obtener el contenido</string>
     <string name="error_get_chapter_list">Error al obtener la lista de capítulos</string>
-    <string name="error_get_web_content">Error al acceder al sitio:% s</string>
+    <string name="error_get_web_content">Error al acceder al sitio: %s</string>
     <string name="error_read_file">Error al leer el archivo</string>
     <string name="error_load_toc">Error al cargar la lista de capítulos</string>
     <string name="error_get_data">Error al obtener los datos</string>
@@ -812,7 +812,7 @@
     <string name="export_bookshelf">Exportar lista de libros</string>
     <string name="import_bookshelf">Importar lista de libros</string>
     <string name="pre_download">Descarga anterior</string>
-    <string name="pre_download_s">Descargue% s capítulos antes</string>
+    <string name="pre_download_s">Descargue %s capítulos antes</string>
     <string name="is_enabled">Está habilitado</string>
     <string name="background_image">Imagen de fondo</string>
     <string name="copy_book_url">Copiar URL del libro</string>