Merge pull request #18 from gedoor/master

get update
pull/379/head
口口吕 5 years ago committed by GitHub
commit 5b59bcde90
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 3
      app/src/main/assets/updateLog.md
  2. 12
      app/src/main/java/io/legado/app/data/dao/BookSourceDao.kt
  3. 2
      app/src/main/java/io/legado/app/data/dao/RssSourceDao.kt
  4. 5
      app/src/main/java/io/legado/app/ui/book/read/ReadBookActivity.kt
  5. 6
      app/src/main/java/io/legado/app/ui/book/read/TextActionMenu.kt
  6. 10
      app/src/main/java/io/legado/app/ui/book/read/config/PaddingConfigDialog.kt
  7. 8
      app/src/main/java/io/legado/app/ui/book/read/page/ChapterProvider.kt
  8. 507
      app/src/main/java/io/legado/app/ui/book/read/page/ContentTextView.kt
  9. 36
      app/src/main/java/io/legado/app/ui/book/read/page/ContentView.kt
  10. 6
      app/src/main/java/io/legado/app/ui/book/read/page/DataSource.kt
  11. 8
      app/src/main/java/io/legado/app/ui/book/read/page/PageFactory.kt
  12. 9
      app/src/main/java/io/legado/app/ui/book/read/page/PageView.kt
  13. 58
      app/src/main/java/io/legado/app/ui/book/read/page/TextPageFactory.kt
  14. 3
      app/src/main/java/io/legado/app/ui/book/read/page/delegate/HorizontalPageDelegate.kt
  15. 45
      app/src/main/java/io/legado/app/ui/book/read/page/delegate/PageDelegate.kt
  16. 20
      app/src/main/java/io/legado/app/ui/book/read/page/delegate/SimulationPageDelegate.kt
  17. 7
      app/src/main/res/layout/dialog_read_padding.xml
  18. 2
      build.gradle
  19. 4
      gradle/wrapper/gradle-wrapper.properties

@ -2,6 +2,9 @@
* 旧版数据导入教程: * 旧版数据导入教程:
* 先在旧版阅读(2.x)中进行备份,然后在新版阅读(3.x)【我的】->【备份与恢复】,选择【导入旧版本数据】。 * 先在旧版阅读(2.x)中进行备份,然后在新版阅读(3.x)【我的】->【备份与恢复】,选择【导入旧版本数据】。
**2020/02/25**
* 优化文本选择和滚动,感觉很完美了
**2020/02/24** **2020/02/24**
* 滚动暂时可以滚了,先这样吧,头大 * 滚动暂时可以滚了,先这样吧,头大
* 紧急修复朗读报错的bug * 紧急修复朗读报错的bug

@ -14,19 +14,19 @@ interface BookSourceDao {
@Query("select * from book_sources where bookSourceName like :searchKey or bookSourceGroup like :searchKey or bookSourceUrl like :searchKey order by customOrder asc") @Query("select * from book_sources where bookSourceName like :searchKey or bookSourceGroup like :searchKey or bookSourceUrl like :searchKey order by customOrder asc")
fun liveDataSearch(searchKey: String = ""): LiveData<List<BookSource>> fun liveDataSearch(searchKey: String = ""): LiveData<List<BookSource>>
@Query("select * from book_sources where enabled = 1 and enabledExplore = 1 and exploreUrl is not null and exploreUrl <> '' order by customOrder asc") @Query("select * from book_sources where enabledExplore = 1 and trim(exploreUrl) <> '' order by customOrder asc")
fun liveExplore(): LiveData<List<BookSource>> fun liveExplore(): LiveData<List<BookSource>>
@Query("select * from book_sources where enabled = 1 and enabledExplore = 1 and exploreUrl is not null and exploreUrl <> '' and (bookSourceGroup like :key or bookSourceName like :key) order by customOrder asc") @Query("select * from book_sources where enabledExplore = 1 and trim(exploreUrl) <> '' and (bookSourceGroup like :key or bookSourceName like :key) order by customOrder asc")
fun liveExplore(key: String): LiveData<List<BookSource>> fun liveExplore(key: String): LiveData<List<BookSource>>
@Query("select bookSourceGroup from book_sources where bookSourceGroup is not null and bookSourceGroup <> ''") @Query("select bookSourceGroup from book_sources where trim(bookSourceGroup) <> ''")
fun liveGroup(): LiveData<List<String>> fun liveGroup(): LiveData<List<String>>
@Query("select bookSourceGroup from book_sources where enabled = 1 and bookSourceGroup is not null and bookSourceGroup <> ''") @Query("select bookSourceGroup from book_sources where enabled = 1 and trim(bookSourceGroup) <> ''")
fun liveGroupEnabled(): LiveData<List<String>> fun liveGroupEnabled(): LiveData<List<String>>
@Query("select bookSourceGroup from book_sources where enabled = 1 and enabledExplore = 1 and exploreUrl is not null and exploreUrl <> '' and bookSourceGroup is not null and bookSourceGroup <> ''") @Query("select bookSourceGroup from book_sources where enabledExplore = 1 and trim(exploreUrl) <> '' and trim(bookSourceGroup) <> ''")
fun liveGroupExplore(): LiveData<List<String>> fun liveGroupExplore(): LiveData<List<String>>
@Query("select distinct enabled from book_sources where bookSourceName like :searchKey or bookSourceGroup like :searchKey or bookSourceUrl like :searchKey") @Query("select distinct enabled from book_sources where bookSourceName like :searchKey or bookSourceGroup like :searchKey or bookSourceUrl like :searchKey")
@ -41,7 +41,7 @@ interface BookSourceDao {
@Query("select * from book_sources where enabled = 1 and bookSourceGroup like '%' || :group || '%'") @Query("select * from book_sources where enabled = 1 and bookSourceGroup like '%' || :group || '%'")
fun getEnabledByGroup(group: String): List<BookSource> fun getEnabledByGroup(group: String): List<BookSource>
@get:Query("select * from book_sources where bookUrlPattern is not null || bookUrlPattern <> ''") @get:Query("select * from book_sources where trim(bookUrlPattern) <> ''")
val hasBookUrlPattern: List<BookSource> val hasBookUrlPattern: List<BookSource>
@get:Query("select * from book_sources where bookSourceGroup is null or bookSourceGroup = ''") @get:Query("select * from book_sources where bookSourceGroup is null or bookSourceGroup = ''")

@ -28,7 +28,7 @@ interface RssSourceDao {
@Query("SELECT * FROM rssSources where enabled = 1 order by customOrder") @Query("SELECT * FROM rssSources where enabled = 1 order by customOrder")
fun liveEnabled(): LiveData<List<RssSource>> fun liveEnabled(): LiveData<List<RssSource>>
@Query("select sourceGroup from rssSources where sourceGroup is not null and sourceGroup <> ''") @Query("select sourceGroup from rssSources where trim(sourceGroup) <> ''")
fun liveGroup(): LiveData<List<String>> fun liveGroup(): LiveData<List<String>>
@get:Query("select min(customOrder) from rssSources") @get:Query("select min(customOrder) from rssSources")

@ -8,7 +8,6 @@ import android.os.Bundle
import android.os.Handler import android.os.Handler
import android.view.* import android.view.*
import android.view.ViewGroup.LayoutParams.WRAP_CONTENT import android.view.ViewGroup.LayoutParams.WRAP_CONTENT
import androidx.appcompat.view.menu.MenuItemImpl
import androidx.core.view.get import androidx.core.view.get
import androidx.core.view.isVisible import androidx.core.view.isVisible
import androidx.core.view.size import androidx.core.view.size
@ -403,8 +402,8 @@ class ReadBookActivity : VMBaseActivity<ReadBookViewModel>(R.layout.activity_boo
/** /**
* 文本选择菜单操作 * 文本选择菜单操作
*/ */
override fun onMenuItemSelected(item: MenuItemImpl): Boolean { override fun onMenuItemSelected(itemId: Int): Boolean {
when (item.itemId) { when (itemId) {
R.id.menu_replace -> { R.id.menu_replace -> {
ReplaceEditDialog.show(supportFragmentManager, pattern = selectedText) ReplaceEditDialog.show(supportFragmentManager, pattern = selectedText)
return true return true

@ -27,7 +27,7 @@ import kotlinx.android.synthetic.main.popup_action_menu.view.*
import org.jetbrains.anko.sdk27.listeners.onClick import org.jetbrains.anko.sdk27.listeners.onClick
import org.jetbrains.anko.toast import org.jetbrains.anko.toast
@SuppressLint("RestrictedApi")
class TextActionMenu(private val context: Context, private val callBack: CallBack) : class TextActionMenu(private val context: Context, private val callBack: CallBack) :
PopupWindow(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT) { PopupWindow(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT) {
@ -70,7 +70,7 @@ class TextActionMenu(private val context: Context, private val callBack: CallBac
override fun registerListener(holder: ItemViewHolder) { override fun registerListener(holder: ItemViewHolder) {
holder.itemView.onClick { holder.itemView.onClick {
getItem(holder.layoutPosition)?.let { getItem(holder.layoutPosition)?.let {
if (!callBack.onMenuItemSelected(it)) { if (!callBack.onMenuItemSelected(it.itemId)) {
onMenuItemSelected(it) onMenuItemSelected(it)
} }
} }
@ -150,7 +150,7 @@ class TextActionMenu(private val context: Context, private val callBack: CallBac
interface CallBack { interface CallBack {
val selectedText: String val selectedText: String
fun onMenuItemSelected(item: MenuItemImpl): Boolean fun onMenuItemSelected(itemId: Int): Boolean
fun onMenuActionFinally() fun onMenuActionFinally()
} }

@ -10,6 +10,7 @@ import io.legado.app.R
import io.legado.app.constant.EventBus import io.legado.app.constant.EventBus
import io.legado.app.help.ReadBookConfig import io.legado.app.help.ReadBookConfig
import io.legado.app.ui.book.read.Help import io.legado.app.ui.book.read.Help
import io.legado.app.utils.dp
import io.legado.app.utils.postEvent import io.legado.app.utils.postEvent
import io.legado.app.utils.visible import io.legado.app.utils.visible
import kotlinx.android.synthetic.main.dialog_read_padding.* import kotlinx.android.synthetic.main.dialog_read_padding.*
@ -51,13 +52,20 @@ class PaddingConfigDialog : DialogFragment() {
} }
private fun initData() = with(ReadBookConfig) { private fun initData() = with(ReadBookConfig) {
if (hideStatusBar) {
tv_header_padding.visible()
dsb_header_padding_top.visible()
dsb_header_padding_bottom.visible()
dsb_header_padding_left.visible()
dsb_header_padding_right.visible()
tv_body_padding.setPadding(0, 10.dp, 0, 10.dp)
}
//正文 //正文
dsb_padding_top.progress = paddingTop dsb_padding_top.progress = paddingTop
dsb_padding_bottom.progress = paddingBottom dsb_padding_bottom.progress = paddingBottom
dsb_padding_left.progress = paddingLeft dsb_padding_left.progress = paddingLeft
dsb_padding_right.progress = paddingRight dsb_padding_right.progress = paddingRight
//页眉 //页眉
tv_header_padding.visible(hideStatusBar)
dsb_header_padding_top.progress = headerPaddingTop dsb_header_padding_top.progress = headerPaddingTop
dsb_header_padding_bottom.progress = headerPaddingBottom dsb_header_padding_bottom.progress = headerPaddingBottom
dsb_header_padding_left.progress = headerPaddingLeft dsb_header_padding_left.progress = headerPaddingLeft

@ -23,10 +23,12 @@ import io.legado.app.utils.removePref
object ChapterProvider { object ChapterProvider {
var viewWidth = 0 var viewWidth = 0
var viewHeight = 0 var viewHeight = 0
var visibleWidth = 0
var visibleHeight = 0
var paddingLeft = 0 var paddingLeft = 0
var paddingTop = 0 var paddingTop = 0
var visibleWidth = 0
var visibleHeight = 0
var visibleRight = 0
var visibleBottom = 0
private var lineSpacingExtra = 0f private var lineSpacingExtra = 0f
private var paragraphSpacing = 0 private var paragraphSpacing = 0
var typeface: Typeface = Typeface.SANS_SERIF var typeface: Typeface = Typeface.SANS_SERIF
@ -342,6 +344,8 @@ object ChapterProvider {
paddingTop = ReadBookConfig.paddingTop.dp paddingTop = ReadBookConfig.paddingTop.dp
visibleWidth = viewWidth - paddingLeft - ReadBookConfig.paddingRight.dp visibleWidth = viewWidth - paddingLeft - ReadBookConfig.paddingRight.dp
visibleHeight = viewHeight - paddingTop - ReadBookConfig.paddingBottom.dp visibleHeight = viewHeight - paddingTop - ReadBookConfig.paddingBottom.dp
visibleRight = paddingLeft + visibleWidth
visibleBottom = paddingTop + visibleHeight
} }
} }

@ -3,6 +3,7 @@ package io.legado.app.ui.book.read.page
import android.content.Context import android.content.Context
import android.graphics.Canvas import android.graphics.Canvas
import android.graphics.Paint import android.graphics.Paint
import android.graphics.RectF
import android.util.AttributeSet import android.util.AttributeSet
import android.view.View import android.view.View
import io.legado.app.R import io.legado.app.R
@ -26,16 +27,14 @@ class ContentTextView(context: Context, attrs: AttributeSet?) : View(context, at
} }
} }
private var callBack: CallBack private var callBack: CallBack
private var selectLineStart = 0 private val visibleRect = RectF()
private var selectCharStart = 0 private val selectStart = arrayOf(0, 0, 0)
private var selectLineEnd = 0 private val selectEnd = arrayOf(0, 0, 0)
private var selectCharEnd = 0
private var textPage: TextPage = TextPage() private var textPage: TextPage = TextPage()
//滚动参数 //滚动参数
private val pageFactory: TextPageFactory get() = callBack.pageFactory private val pageFactory: TextPageFactory get() = callBack.pageFactory
private val maxScrollOffset = 100f private val maxScrollOffset = 100f
private var pageOffset = 0f private var pageOffset = 0f
private var linePos = 0
init { init {
callBack = activity as CallBack callBack = activity as CallBack
@ -53,38 +52,30 @@ class ContentTextView(context: Context, attrs: AttributeSet?) : View(context, at
ChapterProvider.viewWidth = w ChapterProvider.viewWidth = w
ChapterProvider.viewHeight = h ChapterProvider.viewHeight = h
ChapterProvider.upSize() ChapterProvider.upSize()
visibleRect.set(
ChapterProvider.paddingLeft.toFloat(),
ChapterProvider.paddingTop.toFloat(),
ChapterProvider.visibleRight.toFloat(),
ChapterProvider.visibleBottom.toFloat()
)
textPage.format() textPage.format()
} }
override fun onDraw(canvas: Canvas) { override fun onDraw(canvas: Canvas) {
super.onDraw(canvas) super.onDraw(canvas)
if (ReadBookConfig.isScroll) { canvas.clipRect(visibleRect)
drawScrollPage(canvas) drawPage(canvas)
} else {
drawHorizontalPage(canvas)
}
}
private fun drawHorizontalPage(canvas: Canvas) {
textPage.textLines.forEach { textLine ->
drawChars(
canvas,
textLine.textChars,
textLine.lineTop,
textLine.lineBase,
textLine.lineBottom,
textLine.isTitle,
textLine.isReadAloud
)
}
} }
private fun drawScrollPage(canvas: Canvas) { /**
val mPageOffset = pageOffset * 绘制页面
*/
private fun drawPage(canvas: Canvas) {
var relativeOffset = relativeOffset(0)
textPage.textLines.forEach { textLine -> textPage.textLines.forEach { textLine ->
val lineTop = textLine.lineTop + mPageOffset val lineTop = textLine.lineTop + relativeOffset
val lineBase = textLine.lineBase + mPageOffset val lineBase = textLine.lineBase + relativeOffset
val lineBottom = textLine.lineBottom + mPageOffset val lineBottom = textLine.lineBottom + relativeOffset
drawChars( drawChars(
canvas, canvas,
textLine.textChars, textLine.textChars,
@ -95,11 +86,14 @@ class ContentTextView(context: Context, attrs: AttributeSet?) : View(context, at
textLine.isReadAloud textLine.isReadAloud
) )
} }
pageFactory.nextPage?.textLines?.forEach { textLine -> if (!ReadBookConfig.isScroll) return
val yPy = mPageOffset + textPage.height - ChapterProvider.paddingTop //滚动翻页
val lineTop = textLine.lineTop + yPy val nextPage = relativePage(1)
val lineBase = textLine.lineBase + yPy relativeOffset = relativeOffset(1)
val lineBottom = textLine.lineBottom + yPy nextPage.textLines.forEach { textLine ->
val lineTop = textLine.lineTop + relativeOffset
val lineBase = textLine.lineBase + relativeOffset
val lineBottom = textLine.lineBottom + relativeOffset
drawChars( drawChars(
canvas, canvas,
textLine.textChars, textLine.textChars,
@ -110,23 +104,28 @@ class ContentTextView(context: Context, attrs: AttributeSet?) : View(context, at
textLine.isReadAloud textLine.isReadAloud
) )
} }
pageFactory.prevPage?.textLines?.forEach { textLine -> relativeOffset = relativeOffset(2)
val yPy = mPageOffset + ChapterProvider.paddingTop if (relativeOffset < ChapterProvider.visibleHeight) {
val lineTop = -textLine.lineTop + yPy relativePage(2).textLines.forEach { textLine ->
val lineBase = -textLine.lineBase + yPy val lineTop = textLine.lineTop + relativeOffset
val lineBottom = -textLine.lineBottom + yPy val lineBase = textLine.lineBase + relativeOffset
drawChars( val lineBottom = textLine.lineBottom + relativeOffset
canvas, drawChars(
textLine.textChars, canvas,
lineTop, textLine.textChars,
lineBase, lineTop,
lineBottom, lineBase,
textLine.isTitle, lineBottom,
textLine.isReadAloud textLine.isTitle,
) textLine.isReadAloud
)
}
} }
} }
/**
* 绘制文字
*/
private fun drawChars( private fun drawChars(
canvas: Canvas, canvas: Canvas,
textChars: List<TextChar>, textChars: List<TextChar>,
@ -147,6 +146,9 @@ class ContentTextView(context: Context, attrs: AttributeSet?) : View(context, at
} }
} }
/**
* 滚动事件
*/
fun onScroll(mOffset: Float) { fun onScroll(mOffset: Float) {
if (mOffset == 0f) return if (mOffset == 0f) return
var offset = mOffset var offset = mOffset
@ -159,13 +161,13 @@ class ContentTextView(context: Context, attrs: AttributeSet?) : View(context, at
pageOffset += offset pageOffset += offset
if (pageOffset > 0) { if (pageOffset > 0) {
pageFactory.moveToPrev() pageFactory.moveToPrev()
textPage = pageFactory.currentPage ?: TextPage().format() textPage = pageFactory.currentPage
pageOffset -= textPage.height pageOffset -= textPage.height
upView?.invoke(textPage) upView?.invoke(textPage)
} else if (pageOffset < -textPage.height) { } else if (pageOffset < -textPage.height) {
pageOffset += textPage.height pageOffset += textPage.height
pageFactory.moveToNext() pageFactory.moveToNext()
textPage = pageFactory.currentPage ?: TextPage().format() textPage = pageFactory.currentPage
upView?.invoke(textPage) upView?.invoke(textPage)
} }
invalidate() invalidate()
@ -173,99 +175,290 @@ class ContentTextView(context: Context, attrs: AttributeSet?) : View(context, at
fun resetPageOffset() { fun resetPageOffset() {
pageOffset = 0f pageOffset = 0f
linePos = 0
} }
fun selectText(x: Float, y: Float, select: (lineIndex: Int, charIndex: Int) -> Unit) { /**
* 选择初始文字
*/
fun selectText(
x: Float,
y: Float,
select: (relativePage: Int, lineIndex: Int, charIndex: Int) -> Unit
) {
if (!visibleRect.contains(x, y)) return
var relativeOffset = relativeOffset(0)
for ((lineIndex, textLine) in textPage.textLines.withIndex()) { for ((lineIndex, textLine) in textPage.textLines.withIndex()) {
if (y > textLine.lineTop && y < textLine.lineBottom) { if (y > textLine.lineTop + relativeOffset && y < textLine.lineBottom + relativeOffset) {
for ((charIndex, textChar) in textLine.textChars.withIndex()) {
if (x > textChar.start && x < textChar.end) {
textChar.selected = true
invalidate()
selectStart[0] = 0
selectStart[1] = lineIndex
selectStart[2] = charIndex
selectEnd[0] = 0
selectEnd[1] = lineIndex
selectEnd[2] = charIndex
upSelectedStart(textChar.start, textLine.lineBottom + relativeOffset)
upSelectedEnd(textChar.end, textLine.lineBottom + relativeOffset)
select(0, lineIndex, charIndex)
return
}
}
return
}
}
if (!ReadBookConfig.isScroll) return
//滚动翻页
relativeOffset = relativeOffset(1)
if (relativeOffset >= ChapterProvider.visibleHeight) return
val nextPage = relativePage(1)
for ((lineIndex, textLine) in nextPage.textLines.withIndex()) {
if (y > textLine.lineTop + relativeOffset && y < textLine.lineBottom + relativeOffset) {
for ((charIndex, textChar) in textLine.textChars.withIndex()) {
if (x > textChar.start && x < textChar.end) {
textChar.selected = true
invalidate()
selectStart[0] = 1
selectStart[1] = lineIndex
selectStart[2] = charIndex
selectEnd[0] = 1
selectEnd[1] = lineIndex
selectEnd[2] = charIndex
upSelectedStart(textChar.start, textLine.lineBottom + relativeOffset)
upSelectedEnd(textChar.end, textLine.lineBottom + relativeOffset)
select(1, lineIndex, charIndex)
return
}
}
return
}
}
relativeOffset = relativeOffset(2)
if (relativeOffset >= ChapterProvider.visibleHeight) return
for ((lineIndex, textLine) in relativePage(2).textLines.withIndex()) {
if (y > textLine.lineTop + relativeOffset && y < textLine.lineBottom + relativeOffset) {
for ((charIndex, textChar) in textLine.textChars.withIndex()) { for ((charIndex, textChar) in textLine.textChars.withIndex()) {
if (x > textChar.start && x < textChar.end) { if (x > textChar.start && x < textChar.end) {
textChar.selected = true textChar.selected = true
invalidate() invalidate()
selectLineStart = lineIndex selectStart[0] = 2
selectCharStart = charIndex selectStart[1] = lineIndex
selectLineEnd = lineIndex selectStart[2] = charIndex
selectCharEnd = charIndex selectEnd[0] = 2
upSelectedStart(textChar.start, textLine.lineBottom) selectEnd[1] = lineIndex
upSelectedEnd(textChar.end, textLine.lineBottom) selectEnd[2] = charIndex
select(lineIndex, charIndex) upSelectedStart(textChar.start, textLine.lineBottom + relativeOffset)
upSelectedEnd(textChar.end, textLine.lineBottom + relativeOffset)
select(2, lineIndex, charIndex)
return
} }
} }
break return
} }
} }
} }
/**
* 开始选择符移动
*/
fun selectStartMove(x: Float, y: Float) { fun selectStartMove(x: Float, y: Float) {
if (!visibleRect.contains(x, y)) return
var relativeOffset = relativeOffset(0)
for ((lineIndex, textLine) in textPage.textLines.withIndex()) { for ((lineIndex, textLine) in textPage.textLines.withIndex()) {
if (y > textLine.lineTop && y < textLine.lineBottom) { if (y > textLine.lineTop + relativeOffset && y < textLine.lineBottom + relativeOffset) {
for ((charIndex, textChar) in textLine.textChars.withIndex()) { for ((charIndex, textChar) in textLine.textChars.withIndex()) {
if (x > textChar.start && x < textChar.end) { if (x > textChar.start && x < textChar.end) {
if (selectLineStart != lineIndex || selectCharStart != charIndex) { if (selectStart[0] != 0 || selectStart[1] != lineIndex || selectStart[2] != charIndex) {
selectLineStart = lineIndex if (selectToInt(0, lineIndex, charIndex) > selectToInt(selectEnd)) {
selectCharStart = charIndex return
upSelectedStart(textChar.start, textLine.lineBottom) }
upSelectChars(textPage) selectStart[0] = 0
selectStart[1] = lineIndex
selectStart[2] = charIndex
upSelectedStart(textChar.start, textLine.lineBottom + relativeOffset)
upSelectChars()
} }
break return
} }
} }
break return
}
}
if (!ReadBookConfig.isScroll) return
//滚动翻页
relativeOffset = relativeOffset(1)
if (relativeOffset >= ChapterProvider.visibleHeight) return
for ((lineIndex, textLine) in relativePage(1).textLines.withIndex()) {
if (y > textLine.lineTop + relativeOffset && y < textLine.lineBottom + relativeOffset) {
for ((charIndex, textChar) in textLine.textChars.withIndex()) {
if (x > textChar.start && x < textChar.end) {
if (selectStart[0] != 1 || selectStart[1] != lineIndex || selectStart[2] != charIndex) {
if (selectToInt(1, lineIndex, charIndex) > selectToInt(selectEnd)) {
return
}
selectStart[0] = 1
selectStart[1] = lineIndex
selectStart[2] = charIndex
upSelectedStart(textChar.start, textLine.lineBottom + relativeOffset)
upSelectChars()
}
return
}
}
return
}
}
relativeOffset = relativeOffset(2)
if (relativeOffset >= ChapterProvider.visibleHeight) return
for ((lineIndex, textLine) in relativePage(2).textLines.withIndex()) {
if (y > textLine.lineTop + relativeOffset && y < textLine.lineBottom + relativeOffset) {
for ((charIndex, textChar) in textLine.textChars.withIndex()) {
if (x > textChar.start && x < textChar.end) {
if (selectStart[0] != 2 || selectStart[1] != lineIndex || selectStart[2] != charIndex) {
if (selectToInt(2, lineIndex, charIndex) > selectToInt(selectEnd)) {
return
}
selectStart[0] = 2
selectStart[1] = lineIndex
selectStart[2] = charIndex
upSelectedStart(textChar.start, textLine.lineBottom + relativeOffset)
upSelectChars()
}
return
}
}
return
} }
} }
} }
fun selectStartMoveIndex(lineIndex: Int, charIndex: Int) { /**
selectLineStart = lineIndex * 结束选择符移动
selectCharStart = charIndex */
val textLine = textPage.textLines[lineIndex]
val textChar = textLine.textChars[charIndex]
upSelectedStart(textChar.start, textLine.lineBottom)
upSelectChars(textPage)
}
fun selectEndMove(x: Float, y: Float) { fun selectEndMove(x: Float, y: Float) {
if (!visibleRect.contains(x, y)) return
var relativeOffset = relativeOffset(0)
for ((lineIndex, textLine) in textPage.textLines.withIndex()) { for ((lineIndex, textLine) in textPage.textLines.withIndex()) {
if (y > textLine.lineTop && y < textLine.lineBottom) { if (y > textLine.lineTop + relativeOffset && y < textLine.lineBottom + relativeOffset) {
for ((charIndex, textChar) in textLine.textChars.withIndex()) {
if (x > textChar.start && x < textChar.end) {
if (selectEnd[0] != 0 || selectEnd[1] != lineIndex || selectEnd[2] != charIndex) {
if (selectToInt(0, lineIndex, charIndex) < selectToInt(selectStart)) {
return
}
selectEnd[0] = 0
selectEnd[1] = lineIndex
selectEnd[2] = charIndex
upSelectedEnd(textChar.end, textLine.lineBottom + relativeOffset)
upSelectChars()
}
return
}
}
return
}
}
if (!ReadBookConfig.isScroll) return
//滚动翻页
relativeOffset = relativeOffset(1)
if (relativeOffset >= ChapterProvider.visibleHeight) return
for ((lineIndex, textLine) in relativePage(1).textLines.withIndex()) {
if (y > textLine.lineTop + relativeOffset && y < textLine.lineBottom + relativeOffset) {
for ((charIndex, textChar) in textLine.textChars.withIndex()) {
if (x > textChar.start && x < textChar.end) {
if (selectEnd[0] != 1 || selectEnd[1] != lineIndex || selectEnd[2] != charIndex) {
if (selectToInt(1, lineIndex, charIndex) < selectToInt(selectStart)) {
return
}
selectEnd[0] = 1
selectEnd[1] = lineIndex
selectEnd[2] = charIndex
upSelectedEnd(textChar.end, textLine.lineBottom + relativeOffset)
upSelectChars()
}
return
}
}
return
}
}
relativeOffset = relativeOffset(2)
if (relativeOffset >= ChapterProvider.visibleHeight) return
for ((lineIndex, textLine) in relativePage(2).textLines.withIndex()) {
if (y > textLine.lineTop + relativeOffset && y < textLine.lineBottom + relativeOffset) {
for ((charIndex, textChar) in textLine.textChars.withIndex()) { for ((charIndex, textChar) in textLine.textChars.withIndex()) {
if (x > textChar.start && x < textChar.end) { if (x > textChar.start && x < textChar.end) {
if (selectLineEnd != lineIndex || selectCharEnd != charIndex) { if (selectEnd[0] != 2 || selectEnd[1] != lineIndex || selectEnd[2] != charIndex) {
selectLineEnd = lineIndex if (selectToInt(2, lineIndex, charIndex) < selectToInt(selectStart)) {
selectCharEnd = charIndex return
upSelectedEnd(textChar.end, textLine.lineBottom) }
upSelectChars(textPage) selectEnd[0] = 2
selectEnd[1] = lineIndex
selectEnd[2] = charIndex
upSelectedEnd(textChar.end, textLine.lineBottom + relativeOffset)
upSelectChars()
} }
break return
} }
} }
break return
} }
} }
} }
fun selectEndMoveIndex(lineIndex: Int, charIndex: Int) { /**
selectLineEnd = lineIndex * 选择开始文字
selectCharEnd = charIndex */
val textLine = textPage.textLines[lineIndex] fun selectStartMoveIndex(relativePage: Int, lineIndex: Int, charIndex: Int) {
selectStart[0] = relativePage
selectStart[1] = lineIndex
selectStart[2] = charIndex
val textLine = relativePage(relativePage).textLines[lineIndex]
val textChar = textLine.textChars[charIndex] val textChar = textLine.textChars[charIndex]
upSelectedEnd(textChar.end, textLine.lineBottom) upSelectedStart(textChar.start, textLine.lineBottom + relativeOffset(relativePage))
upSelectChars(textPage) upSelectChars()
} }
private fun upSelectChars(textPage: TextPage) { /**
for ((lineIndex, textLine) in textPage.textLines.withIndex()) { * 选择结束文字
for ((charIndex, textChar) in textLine.textChars.withIndex()) { */
textChar.selected = fun selectEndMoveIndex(relativePage: Int, lineIndex: Int, charIndex: Int) {
if (lineIndex == selectLineStart && lineIndex == selectLineEnd) { selectEnd[0] = relativePage
charIndex in selectCharStart..selectCharEnd selectEnd[1] = lineIndex
} else if (lineIndex == selectLineStart) { selectEnd[2] = charIndex
charIndex >= selectCharStart val textLine = relativePage(relativePage).textLines[lineIndex]
} else if (lineIndex == selectLineEnd) { val textChar = textLine.textChars[charIndex]
charIndex <= selectCharEnd upSelectedEnd(textChar.end, textLine.lineBottom + relativeOffset(relativePage))
} else { upSelectChars()
lineIndex in (selectLineStart + 1) until selectLineEnd }
}
private fun upSelectChars() {
val last = if (ReadBookConfig.isScroll) 2 else 0
for (relativePos in 0..last) {
for ((lineIndex, textLine) in relativePage(relativePos).textLines.withIndex()) {
for ((charIndex, textChar) in textLine.textChars.withIndex()) {
textChar.selected =
if (relativePos == selectStart[0]
&& relativePos == selectEnd[0]
&& lineIndex == selectStart[1]
&& lineIndex == selectEnd[1]
) {
charIndex in selectStart[2]..selectEnd[2]
} else if (relativePos == selectStart[0] && lineIndex == selectStart[1]) {
charIndex >= selectStart[2]
} else if (relativePos == selectEnd[0] && lineIndex == selectEnd[1]) {
charIndex <= selectEnd[2]
} else if (relativePos == selectStart[0] && relativePos == selectEnd[0]) {
lineIndex in (selectStart[1] + 1) until selectEnd[1]
} else if (relativePos == selectStart[0]) {
lineIndex > selectStart[1]
} else if (relativePos == selectEnd[0]) {
lineIndex < selectEnd[1]
} else {
relativePos in selectStart[0] + 1 until selectEnd[0]
}
}
} }
} }
invalidate() invalidate()
@ -280,9 +473,12 @@ class ContentTextView(context: Context, attrs: AttributeSet?) : View(context, at
} }
fun cancelSelect() { fun cancelSelect() {
textPage.textLines.forEach { textLine -> val last = if (ReadBookConfig.isScroll) 2 else 0
textLine.textChars.forEach { for (relativePos in 0..last) {
it.selected = false relativePage(relativePos).textLines.forEach { textLine ->
textLine.textChars.forEach {
it.selected = false
}
} }
} }
invalidate() invalidate()
@ -292,31 +488,86 @@ class ContentTextView(context: Context, attrs: AttributeSet?) : View(context, at
val selectedText: String val selectedText: String
get() { get() {
val stringBuilder = StringBuilder() val stringBuilder = StringBuilder()
for (lineIndex in selectLineStart..selectLineEnd) { for (relativePos in selectStart[0]..selectEnd[0]) {
if (lineIndex == selectLineStart && lineIndex == selectLineEnd) { val textPage = relativePage(relativePos)
stringBuilder.append( if (relativePos == selectStart[0] && relativePos == selectEnd[0]) {
textPage.textLines[lineIndex].text.substring( for (lineIndex in selectStart[1]..selectEnd[1]) {
selectCharStart, if (lineIndex == selectStart[1] && lineIndex == selectEnd[1]) {
selectCharEnd + 1 stringBuilder.append(
) textPage.textLines[lineIndex].text.substring(
) selectStart[2],
} else if (lineIndex == selectLineStart) { selectEnd[2] + 1
stringBuilder.append( )
textPage.textLines[lineIndex].text.substring( )
selectCharStart } else if (lineIndex == selectStart[1]) {
) stringBuilder.append(
) textPage.textLines[lineIndex].text.substring(
} else if (lineIndex == selectLineEnd) { selectStart[2]
stringBuilder.append( )
textPage.textLines[lineIndex].text.substring(0, selectCharEnd + 1) )
) } else if (lineIndex == selectEnd[1]) {
} else { stringBuilder.append(
stringBuilder.append(textPage.textLines[lineIndex].text) textPage.textLines[lineIndex].text.substring(0, selectEnd[2] + 1)
)
} else {
stringBuilder.append(textPage.textLines[lineIndex].text)
}
}
} else if (relativePos == selectStart[0]) {
for (lineIndex in selectStart[1] until relativePage(relativePos).textLines.size) {
if (lineIndex == selectStart[1]) {
stringBuilder.append(
textPage.textLines[lineIndex].text.substring(
selectStart[2]
)
)
} else {
stringBuilder.append(textPage.textLines[lineIndex].text)
}
}
} else if (relativePos == selectEnd[0]) {
for (lineIndex in 0..selectEnd[1]) {
if (lineIndex == selectEnd[1]) {
stringBuilder.append(
textPage.textLines[lineIndex].text.substring(0, selectEnd[2] + 1)
)
} else {
stringBuilder.append(textPage.textLines[lineIndex].text)
}
}
} else if (relativePos in selectStart[0] + 1 until selectEnd[0]) {
for (lineIndex in selectStart[1]..selectEnd[1]) {
stringBuilder.append(textPage.textLines[lineIndex].text)
}
} }
} }
return stringBuilder.toString() return stringBuilder.toString()
} }
private fun selectToInt(page: Int, line: Int, char: Int): Int {
return page * 1000000 + line * 100000 + char
}
private fun selectToInt(select: Array<Int>): Int {
return select[0] * 1000000 + select[1] * 100000 + select[2]
}
private fun relativeOffset(relativePos: Int): Float {
return when (relativePos) {
0 -> pageOffset
1 -> pageOffset + textPage.height
else -> pageOffset + textPage.height + pageFactory.nextPage.height
}
}
private fun relativePage(relativePos: Int): TextPage {
return when (relativePos) {
0 -> textPage
1 -> pageFactory.nextPage
else -> pageFactory.nextPagePlus
}
}
interface CallBack { interface CallBack {
fun upSelectedStart(x: Float, y: Float) fun upSelectedStart(x: Float, y: Float)
fun upSelectedEnd(x: Float, y: Float) fun upSelectedEnd(x: Float, y: Float)

@ -15,7 +15,6 @@ import java.util.*
class ContentView(context: Context) : FrameLayout(context) { class ContentView(context: Context) : FrameLayout(context) {
private var pageSize: Int = 0
init { init {
//设置背景防止切换背景时文字重叠 //设置背景防止切换背景时文字重叠
@ -26,8 +25,7 @@ class ContentView(context: Context) : FrameLayout(context) {
upTime() upTime()
content_text_view.upView = { content_text_view.upView = {
tv_bottom_left.text = it.title tv_bottom_left.text = it.title
pageSize = it.pageSize setPageIndex(it.index, it.pageSize)
setPageIndex(it.index)
} }
} }
@ -95,18 +93,19 @@ class ContentView(context: Context) : FrameLayout(context) {
tv_top_right.text = context.getString(R.string.battery_show, battery) tv_top_right.text = context.getString(R.string.battery_show, battery)
} }
fun setContent(textPage: TextPage?) { fun setContent(textPage: TextPage) {
if (textPage != null) { tv_bottom_left.text = textPage.title
tv_bottom_left.text = textPage.title setPageIndex(textPage.index, textPage.pageSize)
pageSize = textPage.pageSize content_text_view.resetPageOffset()
setPageIndex(textPage.index) content_text_view.setContent(textPage)
content_text_view.resetPageOffset() }
content_text_view.setContent(textPage)
} fun resetPageOffset() {
content_text_view.resetPageOffset()
} }
@SuppressLint("SetTextI18n") @SuppressLint("SetTextI18n")
fun setPageIndex(pageIndex: Int?) { fun setPageIndex(pageIndex: Int?, pageSize: Int) {
pageIndex?.let { pageIndex?.let {
tv_bottom_right.text = "${pageIndex.plus(1)}/${pageSize}" tv_bottom_right.text = "${pageIndex.plus(1)}/${pageSize}"
} }
@ -120,7 +119,10 @@ class ContentView(context: Context) : FrameLayout(context) {
content_text_view.selectAble = selectAble content_text_view.selectAble = selectAble
} }
fun selectText(e: MotionEvent, select: (lineIndex: Int, charIndex: Int) -> Unit) { fun selectText(
e: MotionEvent,
select: (relativePage: Int, lineIndex: Int, charIndex: Int) -> Unit
) {
val y = e.y - headerHeight val y = e.y - headerHeight
return content_text_view.selectText(e.x, y, select) return content_text_view.selectText(e.x, y, select)
} }
@ -129,16 +131,16 @@ class ContentView(context: Context) : FrameLayout(context) {
content_text_view.selectStartMove(x, y - headerHeight) content_text_view.selectStartMove(x, y - headerHeight)
} }
fun selectStartMoveIndex(lineIndex: Int, charIndex: Int) { fun selectStartMoveIndex(relativePage: Int, lineIndex: Int, charIndex: Int) {
content_text_view.selectStartMoveIndex(lineIndex, charIndex) content_text_view.selectStartMoveIndex(relativePage, lineIndex, charIndex)
} }
fun selectEndMove(x: Float, y: Float) { fun selectEndMove(x: Float, y: Float) {
content_text_view.selectEndMove(x, y - headerHeight) content_text_view.selectEndMove(x, y - headerHeight)
} }
fun selectEndMoveIndex(lineIndex: Int, charIndex: Int) { fun selectEndMoveIndex(relativePage: Int, lineIndex: Int, charIndex: Int) {
content_text_view.selectEndMoveIndex(lineIndex, charIndex) content_text_view.selectEndMoveIndex(relativePage, lineIndex, charIndex)
} }
fun cancelSelect() { fun cancelSelect() {

@ -7,11 +7,11 @@ interface DataSource {
val pageIndex: Int get() = ReadBook.durChapterPos() val pageIndex: Int get() = ReadBook.durChapterPos()
fun getCurrentChapter(): TextChapter? val currentChapter: TextChapter?
fun getNextChapter(): TextChapter? val nextChapter: TextChapter?
fun getPreviousChapter(): TextChapter? val prevChapter: TextChapter?
fun hasNextChapter(): Boolean fun hasNextChapter(): Boolean

@ -10,11 +10,13 @@ abstract class PageFactory<DATA>(protected val dataSource: DataSource) {
abstract fun moveToPrev(): Boolean abstract fun moveToPrev(): Boolean
abstract val nextPage: DATA? abstract val nextPage: DATA
abstract val prevPage: DATA? abstract val prevPage: DATA
abstract val currentPage: DATA? abstract val currentPage: DATA
abstract val nextPagePlus: DATA
abstract fun hasNext(): Boolean abstract fun hasNext(): Boolean

@ -164,15 +164,18 @@ class PageView(context: Context, attrs: AttributeSet) :
nextPage.upBattery(battery) nextPage.upBattery(battery)
} }
override fun getCurrentChapter(): TextChapter? { override val currentChapter: TextChapter?
get() {
return if (callBack.isInitFinish) ReadBook.textChapter(0) else null return if (callBack.isInitFinish) ReadBook.textChapter(0) else null
} }
override fun getNextChapter(): TextChapter? { override val nextChapter: TextChapter?
get() {
return if (callBack.isInitFinish) ReadBook.textChapter(1) else null return if (callBack.isInitFinish) ReadBook.textChapter(1) else null
} }
override fun getPreviousChapter(): TextChapter? { override val prevChapter: TextChapter?
get() {
return if (callBack.isInitFinish) ReadBook.textChapter(-1) else null return if (callBack.isInitFinish) ReadBook.textChapter(-1) else null
} }

@ -10,7 +10,7 @@ class TextPageFactory(dataSource: DataSource) : PageFactory<TextPage>(dataSource
} }
override fun hasNext(): Boolean = with(dataSource) { override fun hasNext(): Boolean = with(dataSource) {
return hasNextChapter() || getCurrentChapter()?.isLastIndex(pageIndex) != true return hasNextChapter() || currentChapter?.isLastIndex(pageIndex) != true
} }
override fun moveToFirst() { override fun moveToFirst() {
@ -18,7 +18,7 @@ class TextPageFactory(dataSource: DataSource) : PageFactory<TextPage>(dataSource
} }
override fun moveToLast() = with(dataSource) { override fun moveToLast() = with(dataSource) {
getCurrentChapter()?.let { currentChapter?.let {
if (it.pageSize() == 0) { if (it.pageSize() == 0) {
ReadBook.setPageIndex(0) ReadBook.setPageIndex(0)
} else { } else {
@ -29,7 +29,7 @@ class TextPageFactory(dataSource: DataSource) : PageFactory<TextPage>(dataSource
override fun moveToNext(): Boolean = with(dataSource) { override fun moveToNext(): Boolean = with(dataSource) {
return if (hasNext()) { return if (hasNext()) {
if (getCurrentChapter()?.isLastIndex(pageIndex) == true) { if (currentChapter?.isLastIndex(pageIndex) == true) {
ReadBook.moveToNextChapter(false) ReadBook.moveToNextChapter(false)
} else { } else {
ReadBook.setPageIndex(pageIndex.plus(1)) ReadBook.setPageIndex(pageIndex.plus(1))
@ -51,28 +51,62 @@ class TextPageFactory(dataSource: DataSource) : PageFactory<TextPage>(dataSource
false false
} }
override val currentPage: TextPage? override val currentPage: TextPage
get() = with(dataSource) { get() = with(dataSource) {
return getCurrentChapter()?.page(pageIndex) currentChapter?.let {
return@with it.page(pageIndex)
?: TextPage(title = it.title).format()
}
return TextPage().format()
} }
override val nextPage: TextPage? override val nextPage: TextPage
get() = with(dataSource) { get() = with(dataSource) {
getCurrentChapter()?.let { currentChapter?.let {
if (pageIndex < it.pageSize() - 1) { if (pageIndex < it.pageSize() - 1) {
return getCurrentChapter()?.page(pageIndex + 1)?.removePageAloudSpan() return@with it.page(pageIndex + 1)?.removePageAloudSpan()
?: TextPage(title = it.title).format()
} }
} }
return getNextChapter()?.page(0)?.removePageAloudSpan() nextChapter?.let {
return@with it.page(0)?.removePageAloudSpan()
?: TextPage(title = it.title).format()
}
return TextPage().format()
} }
override val prevPage: TextPage? override val prevPage: TextPage
get() = with(dataSource) { get() = with(dataSource) {
if (pageIndex > 0) { if (pageIndex > 0) {
return getCurrentChapter()?.page(pageIndex - 1)?.removePageAloudSpan() currentChapter?.let {
return@with it.page(pageIndex - 1)?.removePageAloudSpan()
?: TextPage(title = it.title).format()
}
} }
return getPreviousChapter()?.lastPage()?.removePageAloudSpan() prevChapter?.let {
return@with it.lastPage()?.removePageAloudSpan()
?: TextPage(title = it.title).format()
}
return TextPage().format()
} }
override val nextPagePlus: TextPage
get() = with(dataSource) {
currentChapter?.let {
if (pageIndex < it.pageSize() - 2) {
return@with it.page(pageIndex + 2)?.removePageAloudSpan()
?: TextPage(title = it.title).format()
}
nextChapter?.let { nc ->
if (pageIndex < it.pageSize() - 1) {
return@with nc.page(0)?.removePageAloudSpan()
?: TextPage(title = nc.title).format()
}
return@with nc.page(1)?.removePageAloudSpan()
?: TextPage(title = nc.title).format()
}
}
return TextPage().format()
}
} }

@ -22,7 +22,8 @@ abstract class HorizontalPageDelegate(pageView: PageView) : PageDelegate(pageVie
private fun onScroll(event: MotionEvent) { private fun onScroll(event: MotionEvent) {
//判断是否移动了 //判断是否移动了
if (!isMoved) { if (!isMoved) {
isMoved = abs(startX - event.x) > slop || abs(startY - event.y) > slop isMoved = abs(startX - event.x) > slop
|| abs(startX - event.x) > abs(startY - event.y)
if (isMoved) { if (isMoved) {
if (event.x - startX > 0) { if (event.x - startX > 0) {
//如果上一页不存在 //如果上一页不存在

@ -67,9 +67,14 @@ abstract class PageDelegate(protected val pageView: PageView) :
var isTextSelected = false var isTextSelected = false
var selectedOnDown = false var selectedOnDown = false
var firstRelativePage = 0
var firstLineIndex: Int = 0 var firstLineIndex: Int = 0
var firstCharIndex: Int = 0 var firstCharIndex: Int = 0
init {
curPage.resetPageOffset()
}
open fun setStartPoint(x: Float, y: Float, invalidate: Boolean = true) { open fun setStartPoint(x: Float, y: Float, invalidate: Boolean = true) {
startX = x startX = x
startY = y startY = y
@ -131,7 +136,7 @@ abstract class PageDelegate(protected val pageView: PageView) :
bitmap = null bitmap = null
} }
fun setViewSize(width: Int, height: Int) { open fun setViewSize(width: Int, height: Int) {
viewWidth = width viewWidth = width
viewHeight = height viewHeight = height
pageView.invalidate() pageView.invalidate()
@ -282,23 +287,41 @@ abstract class PageDelegate(protected val pageView: PageView) :
* 长按选择 * 长按选择
*/ */
override fun onLongPress(e: MotionEvent) { override fun onLongPress(e: MotionEvent) {
curPage.selectText(e) { lineIndex, charIndex -> curPage.selectText(e) { relativePage, lineIndex, charIndex ->
isTextSelected = true isTextSelected = true
firstRelativePage = relativePage
firstLineIndex = lineIndex firstLineIndex = lineIndex
firstCharIndex = charIndex firstCharIndex = charIndex
} }
} }
protected fun selectText(event: MotionEvent) { protected fun selectText(event: MotionEvent) {
curPage.selectText(event) { lineIndex, charIndex -> curPage.selectText(event) { relativePage, lineIndex, charIndex ->
if (lineIndex > firstLineIndex when {
|| (lineIndex == firstLineIndex && charIndex > firstCharIndex) relativePage > firstRelativePage -> {
) { curPage.selectStartMoveIndex(firstRelativePage, firstLineIndex, firstCharIndex)
curPage.selectStartMoveIndex(firstLineIndex, firstCharIndex) curPage.selectEndMoveIndex(relativePage, lineIndex, charIndex)
curPage.selectEndMoveIndex(lineIndex, charIndex) }
} else { relativePage < firstRelativePage -> {
curPage.selectEndMoveIndex(firstLineIndex, firstCharIndex) curPage.selectEndMoveIndex(firstRelativePage, firstLineIndex, firstCharIndex)
curPage.selectStartMoveIndex(lineIndex, charIndex) curPage.selectStartMoveIndex(relativePage, lineIndex, charIndex)
}
lineIndex > firstLineIndex -> {
curPage.selectStartMoveIndex(firstRelativePage, firstLineIndex, firstCharIndex)
curPage.selectEndMoveIndex(relativePage, lineIndex, charIndex)
}
lineIndex < firstLineIndex -> {
curPage.selectEndMoveIndex(firstRelativePage, firstLineIndex, firstCharIndex)
curPage.selectStartMoveIndex(relativePage, lineIndex, charIndex)
}
charIndex > firstCharIndex -> {
curPage.selectStartMoveIndex(firstRelativePage, firstLineIndex, firstCharIndex)
curPage.selectEndMoveIndex(relativePage, lineIndex, charIndex)
}
else -> {
curPage.selectEndMoveIndex(firstRelativePage, firstLineIndex, firstCharIndex)
curPage.selectStartMoveIndex(relativePage, lineIndex, charIndex)
}
} }
} }
} }

@ -115,6 +115,11 @@ class SimulationPageDelegate(pageView: PageView) : HorizontalPageDelegate(pageVi
mFrontShadowDrawableHBT.gradientType = GradientDrawable.LINEAR_GRADIENT mFrontShadowDrawableHBT.gradientType = GradientDrawable.LINEAR_GRADIENT
} }
override fun setViewSize(width: Int, height: Int) {
super.setViewSize(width, height)
mMaxLength = hypot(viewWidth.toDouble(), viewWidth.toDouble()).toFloat()
}
override fun setStartPoint(x: Float, y: Float, invalidate: Boolean) { override fun setStartPoint(x: Float, y: Float, invalidate: Boolean) {
super.setStartPoint(x, y, invalidate) super.setStartPoint(x, y, invalidate)
calcCornerXY(x, y) calcCornerXY(x, y)
@ -171,7 +176,6 @@ class SimulationPageDelegate(pageView: PageView) : HorizontalPageDelegate(pageVi
override fun onAnimStart() { override fun onAnimStart() {
var dx: Float var dx: Float
val dy: Float val dy: Float
// dx 水平方向滑动的距离,负值会使滚动向左滚动
// dy 垂直方向滑动的距离,负值会使滚动向上滚动 // dy 垂直方向滑动的距离,负值会使滚动向上滚动
if (isCancel) { if (isCancel) {
dx = if (mCornerX > 0 && mDirection == Direction.NEXT) { dx = if (mCornerX > 0 && mDirection == Direction.NEXT) {
@ -480,8 +484,10 @@ class SimulationPageDelegate(pageView: PageView) : HorizontalPageDelegate(pageVi
private fun calcPoints() { private fun calcPoints() {
mTouchX = touchX mTouchX = touchX
mTouchY = touchY mTouchY = touchY
mMiddleX = (mTouchX + mCornerX) / 2 mMiddleX = (mTouchX + mCornerX) / 2
mMiddleY = (mTouchY + mCornerY) / 2 mMiddleY = (mTouchY + mCornerY) / 2
mBezierControl1.x = mBezierControl1.x =
mMiddleX - (mCornerY - mMiddleY) * (mCornerY - mMiddleY) / (mCornerX - mMiddleX) mMiddleX - (mCornerY - mMiddleY) * (mCornerY - mMiddleY) / (mCornerX - mMiddleX)
mBezierControl1.y = mCornerY.toFloat() mBezierControl1.y = mCornerY.toFloat()
@ -492,6 +498,7 @@ class SimulationPageDelegate(pageView: PageView) : HorizontalPageDelegate(pageVi
} else { } else {
mMiddleY - (mCornerX - mMiddleX) * (mCornerX - mMiddleX) / (mCornerY - mMiddleY) mMiddleY - (mCornerX - mMiddleX) * (mCornerX - mMiddleX) / (mCornerY - mMiddleY)
} }
mBezierStart1.x = mBezierControl1.x - (mCornerX - mBezierControl1.x) / 2 mBezierStart1.x = mBezierControl1.x - (mCornerX - mBezierControl1.x) / 2
mBezierStart1.y = mCornerY.toFloat() mBezierStart1.y = mCornerY.toFloat()
//固定左边上下两个点 //固定左边上下两个点
@ -500,24 +507,27 @@ class SimulationPageDelegate(pageView: PageView) : HorizontalPageDelegate(pageVi
if (mBezierStart1.x < 0) if (mBezierStart1.x < 0)
mBezierStart1.x = viewWidth - mBezierStart1.x mBezierStart1.x = viewWidth - mBezierStart1.x
val f1: Float = abs(mCornerX - mTouchX) val f1 = abs(mCornerX - mTouchX)
val f2: Float = viewWidth * f1 / mBezierStart1.x val f2 = viewWidth * f1 / mBezierStart1.x
mTouchX = abs(mCornerX - f2) mTouchX = abs(mCornerX - f2)
val f3: Float = abs(mCornerX - mTouchX) * abs(mCornerY - mTouchY) / f1 val f3 = abs(mCornerX - mTouchX) * abs(mCornerY - mTouchY) / f1
mTouchY = abs(mCornerY - f3) mTouchY = abs(mCornerY - f3)
mMiddleX = (mTouchX + mCornerX) / 2 mMiddleX = (mTouchX + mCornerX) / 2
mMiddleY = (mTouchY + mCornerY) / 2 mMiddleY = (mTouchY + mCornerY) / 2
mBezierControl1.x = mBezierControl1.x =
mMiddleX - (mCornerY - mMiddleY) * (mCornerY - mMiddleY) / (mCornerX - mMiddleX) mMiddleX - (mCornerY - mMiddleY) * (mCornerY - mMiddleY) / (mCornerX - mMiddleX)
mBezierControl1.y = mCornerY.toFloat() mBezierControl1.y = mCornerY.toFloat()
mBezierControl2.x = mCornerX.toFloat() mBezierControl2.x = mCornerX.toFloat()
mBezierControl2.y = if ((mCornerY - mMiddleY).toInt() == 0) { mBezierControl2.y = if ((mCornerY - mMiddleY).toInt() == 0) {
mMiddleY - (mCornerX - mMiddleX) * (mCornerX - mMiddleX) / 0.1f mMiddleY - (mCornerX - mMiddleX) * (mCornerX - mMiddleX) / 0.1f
} else { } else {
mMiddleY - (mCornerX - mMiddleX) * (mCornerX - mMiddleX) / (mCornerY - mMiddleY) mMiddleY - (mCornerX - mMiddleX) * (mCornerX - mMiddleX) / (mCornerY - mMiddleY)
} }
mBezierStart1.x = (mBezierControl1.x - (mCornerX - mBezierControl1.x) / 2)
mBezierStart1.x = mBezierControl1.x - (mCornerX - mBezierControl1.x) / 2
} }
} }
mBezierStart2.x = mCornerX.toFloat() mBezierStart2.x = mCornerX.toFloat()

@ -13,12 +13,14 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:paddingBottom="10dp" android:paddingBottom="10dp"
android:textSize="18sp" android:textSize="18sp"
android:visibility="gone"
android:text="@string/header" /> android:text="@string/header" />
<io.legado.app.ui.widget.DetailSeekBar <io.legado.app.ui.widget.DetailSeekBar
android:id="@+id/dsb_header_padding_top" android:id="@+id/dsb_header_padding_top"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:visibility="gone"
app:title="@string/padding_top" app:title="@string/padding_top"
app:max="100" /> app:max="100" />
@ -26,6 +28,7 @@
android:id="@+id/dsb_header_padding_bottom" android:id="@+id/dsb_header_padding_bottom"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:visibility="gone"
app:title="@string/padding_bottom" app:title="@string/padding_bottom"
app:max="100" /> app:max="100" />
@ -33,6 +36,7 @@
android:id="@+id/dsb_header_padding_left" android:id="@+id/dsb_header_padding_left"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:visibility="gone"
app:title="@string/padding_left" app:title="@string/padding_left"
app:max="100" /> app:max="100" />
@ -40,13 +44,14 @@
android:id="@+id/dsb_header_padding_right" android:id="@+id/dsb_header_padding_right"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:visibility="gone"
app:title="@string/padding_right" app:title="@string/padding_right"
app:max="100" /> app:max="100" />
<io.legado.app.ui.widget.text.AccentTextView <io.legado.app.ui.widget.text.AccentTextView
android:id="@+id/tv_body_padding"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:paddingTop="10dp"
android:paddingBottom="10dp" android:paddingBottom="10dp"
android:textSize="18sp" android:textSize="18sp"
android:text="@string/main_body" /> android:text="@string/main_body" />

@ -9,7 +9,7 @@ buildscript {
maven { url 'https://plugins.gradle.org/m2/' } maven { url 'https://plugins.gradle.org/m2/' }
} }
dependencies { dependencies {
classpath 'com.android.tools.build:gradle:3.5.3' classpath 'com.android.tools.build:gradle:3.6.0'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
classpath 'de.timfreiheit.resourceplaceholders:placeholders:0.3' classpath 'de.timfreiheit.resourceplaceholders:placeholders:0.3'
classpath 'com.google.gms:google-services:4.3.3' classpath 'com.google.gms:google-services:4.3.3'

@ -1,6 +1,6 @@
#Wed Aug 21 20:30:49 CST 2019 #Tue Feb 25 08:10:32 CST 2020
distributionBase=GRADLE_USER_HOME distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-5.4.1-all.zip distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.4-all.zip

Loading…
Cancel
Save