diff --git a/app/src/main/assets/updateLog.md b/app/src/main/assets/updateLog.md index 630769a92..b8633fd1f 100644 --- a/app/src/main/assets/updateLog.md +++ b/app/src/main/assets/updateLog.md @@ -2,6 +2,15 @@ * 旧版数据导入教程:先在旧版阅读(2.x)中进行备份,然后在新版阅读(3.x)【我的】->【备份与恢复】,选择【导入旧版本数据】。 * 请关注[开源阅读软件]()支持我,同时关注合作公众号[小说拾遗](),阅读公众号小编。 +**2020/03/04** +* 修复仿真翻页动画 +* 添加阅读记录同步,正常退出进入软件时同步阅读记录 + +**2020/03/03** +* 修复bug +* 优化排版,确保段距为0时每行在相同的位置 +* 修复底部遮挡 + **2020/03/02** * 添加书源登录 * 替换规则实时生效 diff --git a/app/src/main/java/io/legado/app/constant/PreferKey.kt b/app/src/main/java/io/legado/app/constant/PreferKey.kt index 72d8c6b15..b427f687b 100644 --- a/app/src/main/java/io/legado/app/constant/PreferKey.kt +++ b/app/src/main/java/io/legado/app/constant/PreferKey.kt @@ -32,6 +32,7 @@ object PreferKey { const val webDavUrl = "web_dav_url" const val webDavAccount = "web_dav_account" const val webDavPassword = "web_dav_password" + const val webDavCreateDir = "webDavCreateDir" const val changeSourceLoadToc = "changeSourceLoadToc" const val chineseConverterType = "chineseConverterType" const val launcherIcon = "launcherIcon" diff --git a/app/src/main/java/io/legado/app/data/dao/BookDao.kt b/app/src/main/java/io/legado/app/data/dao/BookDao.kt index b0c07339c..f25d76be5 100644 --- a/app/src/main/java/io/legado/app/data/dao/BookDao.kt +++ b/app/src/main/java/io/legado/app/data/dao/BookDao.kt @@ -4,6 +4,7 @@ import androidx.lifecycle.LiveData import androidx.room.* import io.legado.app.constant.BookType import io.legado.app.data.entities.Book +import io.legado.app.data.entities.BookProgress @Dao interface BookDao { @@ -67,4 +68,23 @@ interface BookDao { @Query("update books set `group` = :newGroupId where `group` = :oldGroupId") fun upGroup(oldGroupId: Int, newGroupId: Int) + + @get:Query("select bookUrl, durChapterIndex, durChapterPos, durChapterTime, durChapterTitle from books") + val allBookProgress: List + + @Query( + """ + update books set + durChapterIndex = :durChapterIndex, durChapterPos = :durChapterPos, + durChapterTime = :durChapterTime, durChapterTitle = :durChapterTitle + where bookUrl = :bookUrl and durChapterTime < :durChapterTime + """ + ) + fun upBookProgress( + bookUrl: String, + durChapterIndex: Int, + durChapterPos: Int, + durChapterTime: Long, + durChapterTitle: String? + ) } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/data/entities/BookProgress.kt b/app/src/main/java/io/legado/app/data/entities/BookProgress.kt new file mode 100644 index 000000000..c0d693284 --- /dev/null +++ b/app/src/main/java/io/legado/app/data/entities/BookProgress.kt @@ -0,0 +1,9 @@ +package io.legado.app.data.entities + +data class BookProgress( + val bookUrl: String, + val durChapterIndex: Int, + val durChapterPos: Int, + val durChapterTime: Long, + val durChapterTitle: String? +) \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/help/ReadBookConfig.kt b/app/src/main/java/io/legado/app/help/ReadBookConfig.kt index a3a6de521..0801f88dd 100644 --- a/app/src/main/java/io/legado/app/help/ReadBookConfig.kt +++ b/app/src/main/java/io/legado/app/help/ReadBookConfig.kt @@ -27,6 +27,7 @@ object ReadBookConfig { val durConfig get() = getConfig(styleSelect) private val shareConfig get() = getConfig(5) var bg: Drawable? = null + var bgMeanColor: Int = 0 init { upConfig() @@ -68,6 +69,13 @@ object ReadBookConfig { val width = dm.widthPixels val height = dm.heightPixels bg = durConfig.bgDrawable(width, height) + bg?.let { + if (it is BitmapDrawable) { + bgMeanColor = BitmapUtils.getMeanColor(it.bitmap) + } else if (it is ColorDrawable) { + bgMeanColor = it.color + } + } } fun save() { diff --git a/app/src/main/java/io/legado/app/help/storage/SyncBookProgress.kt b/app/src/main/java/io/legado/app/help/storage/SyncBookProgress.kt new file mode 100644 index 000000000..ddb4d6ef5 --- /dev/null +++ b/app/src/main/java/io/legado/app/help/storage/SyncBookProgress.kt @@ -0,0 +1,50 @@ +package io.legado.app.help.storage + +import io.legado.app.App +import io.legado.app.data.entities.BookProgress +import io.legado.app.help.coroutine.Coroutine +import io.legado.app.lib.webdav.WebDav +import io.legado.app.utils.FileUtils +import io.legado.app.utils.GSON +import io.legado.app.utils.fromJsonArray + +@Suppress("BlockingMethodInNonBlockingContext") +object SyncBookProgress { + const val fileName = "bookProgress.json" + private val file = FileUtils.createFileIfNotExist(App.INSTANCE.cacheDir, fileName) + private val webDavUrl = "${WebDavHelp.rootWebDavUrl}$fileName" + + fun uploadBookProgress() { + Coroutine.async { + val value = App.db.bookDao().allBookProgress + if (value.isNotEmpty()) { + val json = GSON.toJson(value) + file.writeText(json) + if (WebDavHelp.initWebDav()) { + WebDav(webDavUrl).upload(file.absolutePath) + } + } + } + } + + fun downloadBookProgress() { + Coroutine.async { + if (WebDavHelp.initWebDav()) { + WebDav(webDavUrl).downloadTo(file.absolutePath, true) + if (file.exists()) { + val json = file.readText() + GSON.fromJsonArray(json)?.forEach { + App.db.bookDao().upBookProgress( + it.bookUrl, + it.durChapterIndex, + it.durChapterPos, + it.durChapterTime, + it.durChapterTitle + ) + } + } + } + } + } + +} \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/help/storage/WebDavHelp.kt b/app/src/main/java/io/legado/app/help/storage/WebDavHelp.kt index a1386f9f7..50857893d 100644 --- a/app/src/main/java/io/legado/app/help/storage/WebDavHelp.kt +++ b/app/src/main/java/io/legado/app/help/storage/WebDavHelp.kt @@ -10,6 +10,7 @@ import io.legado.app.lib.webdav.WebDav import io.legado.app.lib.webdav.http.HttpAuth import io.legado.app.utils.FileUtils import io.legado.app.utils.ZipUtils +import io.legado.app.utils.getPrefBoolean import io.legado.app.utils.getPrefString import kotlinx.coroutines.Dispatchers.IO import kotlinx.coroutines.Dispatchers.Main @@ -25,31 +26,36 @@ object WebDavHelp { private const val defaultWebDavUrl = "https://dav.jianguoyun.com/dav/" private val zipFilePath = "${FileUtils.getCachePath()}${File.separator}backup.zip" - private fun getWebDavUrl(): String { + val rootWebDavUrl: String + get() { var url = App.INSTANCE.getPrefString(PreferKey.webDavUrl) if (url.isNullOrEmpty()) { url = defaultWebDavUrl } - if (!url.endsWith("/")) url += "/" + if (!url.endsWith("/")) url = "${url}/" + if (App.INSTANCE.getPrefBoolean(PreferKey.webDavCreateDir, true)) { + url = "${url}legado/" + } return url } - private fun initWebDav(): Boolean { + fun initWebDav(): Boolean { val account = App.INSTANCE.getPrefString(PreferKey.webDavAccount) val password = App.INSTANCE.getPrefString(PreferKey.webDavPassword) if (!account.isNullOrBlank() && !password.isNullOrBlank()) { HttpAuth.auth = HttpAuth.Auth(account, password) + WebDav(rootWebDavUrl).makeAsDir() return true } return false } private fun getWebDavFileNames(): ArrayList { - val url = getWebDavUrl() + val url = rootWebDavUrl val names = arrayListOf() if (initWebDav()) { try { - var files = WebDav(url + "legado/").listFiles() + var files = WebDav(url).listFiles() files = files.reversed() for (index: Int in 0 until min(10, files.size)) { files[index].displayName?.let { @@ -81,12 +87,16 @@ object WebDavHelp { private fun restoreWebDav(name: String, success: () -> Unit) { Coroutine.async { - getWebDavUrl().let { - val file = WebDav(it + "legado/" + name) - file.downloadTo(zipFilePath, true) - @Suppress("BlockingMethodInNonBlockingContext") - ZipUtils.unzipFile(zipFilePath, Backup.backupPath) - Restore.restore(Backup.backupPath) + rootWebDavUrl.let { + if (name == SyncBookProgress.fileName) { + SyncBookProgress.downloadBookProgress() + } else { + val webDav = WebDav(it + name) + webDav.downloadTo(zipFilePath, true) + @Suppress("BlockingMethodInNonBlockingContext") + ZipUtils.unzipFile(zipFilePath, Backup.backupPath) + Restore.restore(Backup.backupPath) + } } }.onSuccess { success.invoke() @@ -102,10 +112,9 @@ object WebDavHelp { } FileUtils.deleteFile(zipFilePath) if (ZipUtils.zipFiles(paths, zipFilePath)) { - WebDav(getWebDavUrl() + "legado").makeAsDir() - val putUrl = getWebDavUrl() + "legado/backup" + - SimpleDateFormat("yyyy-MM-dd", Locale.getDefault()) - .format(Date(System.currentTimeMillis())) + ".zip" + val backupDate = SimpleDateFormat("yyyy-MM-dd", Locale.getDefault()) + .format(Date(System.currentTimeMillis())) + val putUrl = "${rootWebDavUrl}backup${backupDate}.zip" WebDav(putUrl).upload(zipFilePath) } } diff --git a/app/src/main/java/io/legado/app/lib/webdav/WebDav.kt b/app/src/main/java/io/legado/app/lib/webdav/WebDav.kt index 32b79ce79..47aa59344 100644 --- a/app/src/main/java/io/legado/app/lib/webdav/WebDav.kt +++ b/app/src/main/java/io/legado/app/lib/webdav/WebDav.kt @@ -202,7 +202,6 @@ constructor(urlStr: String) { * 上传文件 */ @Throws(IOException::class) - @JvmOverloads fun upload(localPath: String, contentType: String? = null): Boolean { val file = File(localPath) if (!file.exists()) return false diff --git a/app/src/main/java/io/legado/app/model/localBook/LocalBook.kt b/app/src/main/java/io/legado/app/model/localBook/LocalBook.kt index c58410cd7..9a893b8a3 100644 --- a/app/src/main/java/io/legado/app/model/localBook/LocalBook.kt +++ b/app/src/main/java/io/legado/app/model/localBook/LocalBook.kt @@ -30,15 +30,16 @@ object LocalBook { } fun deleteBook(book: Book, deleteOriginal: Boolean) { - if (book.isTxt()) { - val bookFile = - FileUtils.getFile(AnalyzeTxtFile.cacheFolder, book.originName, subDirs = *arrayOf()) - bookFile.delete() - } + kotlin.runCatching { + if (book.isTxt()) { + val bookFile = FileUtils.getFile(AnalyzeTxtFile.cacheFolder, book.originName) + bookFile.delete() + } - if (deleteOriginal) { - val uri = Uri.parse(book.bookUrl) - DocumentFile.fromSingleUri(App.INSTANCE, uri)?.delete() + if (deleteOriginal) { + val uri = Uri.parse(book.bookUrl) + DocumentFile.fromSingleUri(App.INSTANCE, uri)?.delete() + } } } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/book/info/BookInfoActivity.kt b/app/src/main/java/io/legado/app/ui/book/info/BookInfoActivity.kt index 782b538ee..d20cf203b 100644 --- a/app/src/main/java/io/legado/app/ui/book/info/BookInfoActivity.kt +++ b/app/src/main/java/io/legado/app/ui/book/info/BookInfoActivity.kt @@ -21,8 +21,6 @@ import io.legado.app.help.BlurTransformation import io.legado.app.help.ImageLoader import io.legado.app.help.IntentDataHelp import io.legado.app.lib.dialogs.alert -import io.legado.app.lib.dialogs.noButton -import io.legado.app.lib.dialogs.okButton import io.legado.app.ui.audio.AudioPlayActivity import io.legado.app.ui.book.changecover.ChangeCoverDialog import io.legado.app.ui.book.changesource.ChangeSourceDialog @@ -232,17 +230,17 @@ class BookInfoActivity : titleResource = R.string.sure, messageResource = R.string.sure_delete_book_file ) { - okButton { + positiveButton(R.string.yes) { viewModel.delBook(true) { finish() } } - noButton { + negativeButton(R.string.no) { viewModel.delBook(false) { finish() } } - } + }.show() } else { viewModel.delBook { upTvBookshelf() diff --git a/app/src/main/java/io/legado/app/ui/book/info/BookInfoViewModel.kt b/app/src/main/java/io/legado/app/ui/book/info/BookInfoViewModel.kt index 0364696a6..485d704ce 100644 --- a/app/src/main/java/io/legado/app/ui/book/info/BookInfoViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/book/info/BookInfoViewModel.kt @@ -202,12 +202,12 @@ class BookInfoViewModel(application: Application) : BaseViewModel(application) { fun delBook(deleteOriginal: Boolean = false, success: (() -> Unit)? = null) { execute { bookData.value?.let { + App.db.bookDao().delete(it) + inBookshelf = false if (it.isLocalBook()) { LocalBook.deleteBook(it, deleteOriginal) } - App.db.bookDao().delete(it) } - inBookshelf = false }.onSuccess { success?.invoke() } diff --git a/app/src/main/java/io/legado/app/ui/book/read/page/ChapterProvider.kt b/app/src/main/java/io/legado/app/ui/book/read/page/ChapterProvider.kt index 430db0e53..bc9dfc6e1 100644 --- a/app/src/main/java/io/legado/app/ui/book/read/page/ChapterProvider.kt +++ b/app/src/main/java/io/legado/app/ui/book/read/page/ChapterProvider.kt @@ -28,7 +28,7 @@ object ChapterProvider { var visibleHeight = 0 var visibleRight = 0 var visibleBottom = 0 - private var lineSpacingExtra = 0f + private var lineSpacingExtra = 0 private var paragraphSpacing = 0 var typeface: Typeface = Typeface.SANS_SERIF var titlePaint = TextPaint() @@ -51,7 +51,7 @@ object ChapterProvider { val pageLengths = arrayListOf() val stringBuilder = StringBuilder() var surplusText = content - var durY = 0 + var durY = 0f textPages.add(TextPage()) while (surplusText.isNotEmpty()) { if (textPages.first().textLines.isEmpty()) { @@ -60,7 +60,9 @@ object ChapterProvider { if (end > 0) { val title = surplusText.substring(0, end) surplusText = surplusText.substring(end + 1) - durY = joinTitle(title, durY, textPages, pageLines, pageLengths, stringBuilder) + durY = setTypeText( + title, durY, textPages, pageLines, pageLengths, stringBuilder, true + ) } } else { //正文 @@ -73,7 +75,8 @@ object ChapterProvider { text = surplusText surplusText = "" } - durY = joinBody(text, durY, textPages, pageLines, pageLengths, stringBuilder) + durY = + setTypeText(text, durY, textPages, pageLines, pageLengths, stringBuilder, false) } } textPages.last().height = durY + 20.dp @@ -103,116 +106,59 @@ object ChapterProvider { } /** - * 标题 + * 排版文字 */ - private fun joinTitle( - title: String, - y: Int, - textPages: ArrayList, - pageLines: ArrayList, - pageLengths: ArrayList, - stringBuilder: StringBuilder - ): Int { - var durY = y - val layout = StaticLayout( - title, titlePaint, visibleWidth, - Layout.Alignment.ALIGN_NORMAL, 1f, lineSpacingExtra, true - ) - for (lineIndex in 0 until layout.lineCount) { - textPages.last().height = durY - val textLine = TextLine(isTitle = true) - if (durY + layout.getLineBaseline(lineIndex) - layout.getLineTop(lineIndex) - + contentPaint.fontMetrics.descent < visibleHeight - ) { - textPages.last().textLines.add(textLine) - durY = durY + layout.getLineBottom(lineIndex) - layout.getLineTop(lineIndex) - } else { - textPages.last().text = stringBuilder.toString() - stringBuilder.clear() - pageLines.add(textPages.last().textLines.size) - pageLengths.add(textPages.last().text.length) - //新页面 - durY = layout.getLineBottom(lineIndex) - layout.getLineTop(lineIndex) - textPages.add(TextPage()) - textPages.last().textLines.add(textLine) - } - textLine.lineTop = (paddingTop + durY - - (layout.getLineBottom(lineIndex) - layout.getLineTop(lineIndex))).toFloat() - textLine.lineBase = (paddingTop + durY - - (layout.getLineBottom(lineIndex) - layout.getLineBaseline(lineIndex))).toFloat() - textLine.lineBottom = textLine.lineBase + contentPaint.fontMetrics.descent - val words = - title.substring(layout.getLineStart(lineIndex), layout.getLineEnd(lineIndex)) - stringBuilder.append(words) - textLine.text = words - val desiredWidth = layout.getLineWidth(lineIndex) - if (lineIndex != layout.lineCount - 1) { - addCharsToLineMiddle(textLine, words, titlePaint, desiredWidth, 0f) - } else { - //最后一行 - val x = if (ReadBookConfig.titleCenter) - (visibleWidth - layout.getLineWidth(lineIndex)) / 2 - else 0f - addCharsToLineLast(textLine, words, stringBuilder, titlePaint, x) - } - } - durY += paragraphSpacing - return durY - } - - /** - * 正文 - */ - private fun joinBody( + private fun setTypeText( text: String, - y: Int, + y: Float, textPages: ArrayList, pageLines: ArrayList, pageLengths: ArrayList, - stringBuilder: StringBuilder - ): Int { + stringBuilder: StringBuilder, + isTitle: Boolean + ): Float { var durY = y + val textPaint = if (isTitle) titlePaint else contentPaint val layout = StaticLayout( - text, contentPaint, visibleWidth, - Layout.Alignment.ALIGN_NORMAL, 1f, lineSpacingExtra, true + text, textPaint, visibleWidth, + Layout.Alignment.ALIGN_NORMAL, 0f, 0f, true ) for (lineIndex in 0 until layout.lineCount) { textPages.last().height = durY - val textLine = TextLine() - if (durY + layout.getLineBaseline(lineIndex) - layout.getLineTop(lineIndex) - + contentPaint.fontMetrics.descent < visibleHeight - ) { + val textLine = TextLine(isTitle = isTitle) + if (durY + textPaint.textHeight < visibleHeight) { textPages.last().textLines.add(textLine) - durY = durY + layout.getLineBottom(lineIndex) - layout.getLineTop(lineIndex) + durY += textPaint.textHeight + lineSpacingExtra } else { textPages.last().text = stringBuilder.toString() stringBuilder.clear() pageLines.add(textPages.last().textLines.size) pageLengths.add(textPages.last().text.length) //新页面 - durY = layout.getLineBottom(lineIndex) - layout.getLineTop(lineIndex) + durY = textPaint.textHeight + lineSpacingExtra textPages.add(TextPage()) textPages.last().textLines.add(textLine) } - textLine.lineTop = (paddingTop + durY - - (layout.getLineBottom(lineIndex) - layout.getLineTop(lineIndex))).toFloat() - textLine.lineBase = (paddingTop + durY - - (layout.getLineBottom(lineIndex) - layout.getLineBaseline(lineIndex))).toFloat() - textLine.lineBottom = textLine.lineBase + contentPaint.fontMetrics.descent + textLine.lineBottom = paddingTop + durY - lineSpacingExtra + textLine.lineBase = textLine.lineBottom - textPaint.fontMetrics.descent + textLine.lineTop = textLine.lineBottom - textPaint.textHeight val words = text.substring(layout.getLineStart(lineIndex), layout.getLineEnd(lineIndex)) stringBuilder.append(words) textLine.text = words val desiredWidth = layout.getLineWidth(lineIndex) - if (lineIndex == 0 && layout.lineCount > 1) { + if (lineIndex == 0 && layout.lineCount > 1 && !isTitle) { //第一行 - addCharsToLineFirst(textLine, words, contentPaint, desiredWidth) + addCharsToLineFirst(textLine, words, textPaint, desiredWidth) } else if (lineIndex == layout.lineCount - 1) { //最后一行 - addCharsToLineLast(textLine, words, stringBuilder, contentPaint, 0f) + val x = if (isTitle && ReadBookConfig.titleCenter) + (visibleWidth - layout.getLineWidth(lineIndex)) / 2 + else 0f + addCharsToLineLast(textLine, words, stringBuilder, textPaint, x) } else { //中间行 - addCharsToLineMiddle(textLine, words, contentPaint, desiredWidth, 0f) + addCharsToLineMiddle(textLine, words, textPaint, desiredWidth, 0f) } } durY += paragraphSpacing @@ -346,7 +292,7 @@ object ChapterProvider { val bold = if (ReadBookConfig.textBold) Typeface.BOLD else Typeface.NORMAL contentPaint.typeface = Typeface.create(typeface, bold) //间距 - lineSpacingExtra = ReadBookConfig.lineSpacingExtra.dp.toFloat() + lineSpacingExtra = ReadBookConfig.lineSpacingExtra.dp paragraphSpacing = ReadBookConfig.paragraphSpacing.dp titlePaint.textSize = (ReadBookConfig.textSize + 2).dp.toFloat() contentPaint.textSize = ReadBookConfig.textSize.dp.toFloat() @@ -366,4 +312,8 @@ object ChapterProvider { visibleBottom = paddingTop + visibleHeight } + private val TextPaint.textHeight: Float + get() { + return this.fontMetrics.descent - fontMetrics.ascent + fontMetrics.leading + } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/book/read/page/delegate/CoverPageDelegate.kt b/app/src/main/java/io/legado/app/ui/book/read/page/delegate/CoverPageDelegate.kt index 2f4b2c404..c973fc87c 100644 --- a/app/src/main/java/io/legado/app/ui/book/read/page/delegate/CoverPageDelegate.kt +++ b/app/src/main/java/io/legado/app/ui/book/read/page/delegate/CoverPageDelegate.kt @@ -1,11 +1,12 @@ package io.legado.app.ui.book.read.page.delegate import android.graphics.Canvas +import android.graphics.Matrix import android.graphics.drawable.GradientDrawable import io.legado.app.ui.book.read.page.PageView class CoverPageDelegate(pageView: PageView) : HorizontalPageDelegate(pageView) { - + private val bitmapMatrix = Matrix() private val shadowDrawableR: GradientDrawable init { @@ -16,13 +17,6 @@ class CoverPageDelegate(pageView: PageView) : HorizontalPageDelegate(pageView) { shadowDrawableR.gradientType = GradientDrawable.LINEAR_GRADIENT } - override fun setStartPoint(x: Float, y: Float, invalidate: Boolean) { - curPage.x = 0.toFloat() - prevPage.x = -viewWidth.toFloat() - nextPage.x = 0.toFloat() - super.setStartPoint(x, y, invalidate) - } - override fun onDraw(canvas: Canvas) { val offsetX = touchX - startX @@ -33,10 +27,14 @@ class CoverPageDelegate(pageView: PageView) : HorizontalPageDelegate(pageView) { val distanceX = if (offsetX > 0) offsetX - viewWidth else offsetX + viewWidth if (!isRunning) return if (mDirection == Direction.PREV) { - prevPage.translationX = offsetX - viewWidth + bitmapMatrix.setTranslate(distanceX, 0.toFloat()) + curBitmap?.let { canvas.drawBitmap(it, 0f, 0f, null) } + prevBitmap?.let { canvas.drawBitmap(it, bitmapMatrix, null) } addShadow(distanceX.toInt(), canvas) } else if (mDirection == Direction.NEXT) { - curPage.translationX = offsetX + bitmapMatrix.setTranslate(distanceX - viewWidth, 0.toFloat()) + nextBitmap?.let { canvas.drawBitmap(it, 0f, 0f, null) } + curBitmap?.let { canvas.drawBitmap(it, bitmapMatrix, null) } addShadow(distanceX.toInt(), canvas) } } @@ -52,8 +50,6 @@ class CoverPageDelegate(pageView: PageView) : HorizontalPageDelegate(pageView) { } override fun onAnimStop() { - curPage.x = 0.toFloat() - prevPage.x = -viewWidth.toFloat() if (!isCancel) { pageView.fillPage(mDirection) } diff --git a/app/src/main/java/io/legado/app/ui/book/read/page/delegate/HorizontalPageDelegate.kt b/app/src/main/java/io/legado/app/ui/book/read/page/delegate/HorizontalPageDelegate.kt index a95d01e2a..74583bae0 100644 --- a/app/src/main/java/io/legado/app/ui/book/read/page/delegate/HorizontalPageDelegate.kt +++ b/app/src/main/java/io/legado/app/ui/book/read/page/delegate/HorizontalPageDelegate.kt @@ -1,11 +1,40 @@ package io.legado.app.ui.book.read.page.delegate +import android.graphics.Bitmap import android.view.MotionEvent import io.legado.app.ui.book.read.page.PageView +import io.legado.app.utils.screenshot import kotlin.math.abs abstract class HorizontalPageDelegate(pageView: PageView) : PageDelegate(pageView) { + protected var curBitmap: Bitmap? = null + protected var prevBitmap: Bitmap? = null + protected var nextBitmap: Bitmap? = null + + override fun setDirection(direction: Direction) { + super.setDirection(direction) + setBitmap() + } + + private fun setBitmap() { + when (mDirection) { + Direction.PREV -> { + prevBitmap?.recycle() + prevBitmap = prevPage.screenshot() + curBitmap?.recycle() + curBitmap = curPage.screenshot() + } + Direction.NEXT -> { + nextBitmap?.recycle() + nextBitmap = nextPage.screenshot() + curBitmap?.recycle() + curBitmap = curPage.screenshot() + } + else -> Unit + } + } + override fun onTouch(event: MotionEvent) { when (event.action) { MotionEvent.ACTION_DOWN -> { @@ -69,4 +98,14 @@ abstract class HorizontalPageDelegate(pageView: PageView) : PageDelegate(pageVie onAnimStart() } + override fun onDestroy() { + super.onDestroy() + prevBitmap?.recycle() + prevBitmap = null + curBitmap?.recycle() + curBitmap = null + nextBitmap?.recycle() + nextBitmap = null + } + } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/book/read/page/delegate/SimulationPageDelegate.kt b/app/src/main/java/io/legado/app/ui/book/read/page/delegate/SimulationPageDelegate.kt index b337a17a1..616a41614 100644 --- a/app/src/main/java/io/legado/app/ui/book/read/page/delegate/SimulationPageDelegate.kt +++ b/app/src/main/java/io/legado/app/ui/book/read/page/delegate/SimulationPageDelegate.kt @@ -3,8 +3,8 @@ package io.legado.app.ui.book.read.page.delegate import android.graphics.* import android.graphics.drawable.GradientDrawable import android.os.Build +import io.legado.app.help.ReadBookConfig import io.legado.app.ui.book.read.page.PageView -import io.legado.app.utils.screenshot import kotlin.math.* @Suppress("DEPRECATION") @@ -73,10 +73,6 @@ class SimulationPageDelegate(pageView: PageView) : HorizontalPageDelegate(pageVi private val mPaint: Paint = Paint().apply { style = Paint.Style.FILL } - private var curBitmap: Bitmap? = null - private var prevBitmap: Bitmap? = null - private var nextBitmap: Bitmap? = null - init { //设置颜色数组 val color = intArrayOf(0x333333, -0x4fcccccd) @@ -118,31 +114,21 @@ class SimulationPageDelegate(pageView: PageView) : HorizontalPageDelegate(pageVi mMaxLength = hypot(viewWidth.toDouble(), viewHeight.toDouble()).toFloat() } - override fun onDestroy() { - super.onDestroy() - prevBitmap?.recycle() - prevBitmap = null - curBitmap?.recycle() - curBitmap = null - nextBitmap?.recycle() - nextBitmap = null - } - override fun setStartPoint(x: Float, y: Float, invalidate: Boolean) { - super.setStartPoint(x, y, invalidate) + super.setStartPoint(x, y, false) calcCornerXY(x, y) } override fun setTouchPoint(x: Float, y: Float, invalidate: Boolean) { super.setTouchPoint(x, y, false) //触摸y中间位置吧y变成屏幕高度 - if ((startY > viewHeight / 3.0 && startY < viewHeight * 2 / 3.0) + if ((startY > viewHeight / 3 && startY < viewHeight * 2 / 3) || mDirection == Direction.PREV ) { touchY = viewHeight.toFloat() } - if (startY > viewHeight / 3.0 && startY < viewHeight / 2.0 + if (startY > viewHeight / 3 && startY < viewHeight / 2 && mDirection == Direction.NEXT ) { touchY = 1f @@ -152,37 +138,22 @@ class SimulationPageDelegate(pageView: PageView) : HorizontalPageDelegate(pageVi override fun setDirection(direction: Direction) { super.setDirection(direction) - setBitmap() when (direction) { Direction.PREV -> //上一页滑动不出现对角 - if (startX > viewWidth / 2.0) { + if (startX > viewWidth / 2) { calcCornerXY(startX, viewHeight.toFloat()) } else { calcCornerXY(viewWidth - startX, viewHeight.toFloat()) } Direction.NEXT -> - if (viewWidth / 2.0 > startX) { + if (viewWidth / 2 > startX) { calcCornerXY(viewWidth - startX, startY) } else -> Unit } } - private fun setBitmap() { - when (mDirection) { - Direction.PREV -> { - prevBitmap = prevPage.screenshot() - curBitmap = curPage.screenshot() - } - Direction.NEXT -> { - nextBitmap = nextPage.screenshot() - curBitmap = curPage.screenshot() - } - else -> Unit - } - } - override fun onAnimStart() { var dx: Float val dy: Float @@ -223,6 +194,7 @@ class SimulationPageDelegate(pageView: PageView) : HorizontalPageDelegate(pageVi } override fun onDraw(canvas: Canvas) { + if (!isRunning) return when (mDirection) { Direction.NEXT -> { calcPoints() @@ -297,6 +269,7 @@ class SimulationPageDelegate(pageView: PageView) : HorizontalPageDelegate(pageVi mMatrix.setValues(mMatrixArray) mMatrix.preTranslate(-mBezierControl1.x, -mBezierControl1.y) mMatrix.postTranslate(mBezierControl1.x, mBezierControl1.y) + canvas.drawColor(ReadBookConfig.bgMeanColor) canvas.drawBitmap(bitmap, mMatrix, mPaint) mPaint.colorFilter = null canvas.rotate(mDegrees, mBezierStart1.x, mBezierStart1.y) @@ -485,8 +458,8 @@ class SimulationPageDelegate(pageView: PageView) : HorizontalPageDelegate(pageVi * 计算拖拽点对应的拖拽脚 */ private fun calcCornerXY(x: Float, y: Float) { - mCornerX = if (x <= viewWidth / 2.0) 0 else viewWidth - mCornerY = if (y <= viewHeight / 2.0) 0 else viewHeight + mCornerX = if (x <= viewWidth / 2) 0 else viewWidth + mCornerY = if (y <= viewHeight / 2) 0 else viewHeight mIsRtOrLb = (mCornerX == 0 && mCornerY == viewHeight) || (mCornerY == 0 && mCornerX == viewWidth) } @@ -497,21 +470,23 @@ class SimulationPageDelegate(pageView: PageView) : HorizontalPageDelegate(pageVi mMiddleX = (mTouchX + mCornerX) / 2 mMiddleY = (mTouchY + mCornerY) / 2 - mBezierControl1.x = mMiddleX - (mCornerY - mMiddleY) * (mCornerY - mMiddleY) / (mCornerX - mMiddleX) mBezierControl1.y = mCornerY.toFloat() - mBezierControl2.x = mCornerX.toFloat() - mBezierControl2.y = if ((mCornerY - mMiddleY).toInt() == 0) { - mMiddleY - (mCornerX - mMiddleX) * (mCornerX - mMiddleX) / 0.1f + + val f4 = mCornerY - mMiddleY + if (f4 == 0f) { + mBezierControl2.y = mMiddleY - (mCornerX - mMiddleX) * (mCornerX - mMiddleX) / 0.1f + } else { - mMiddleY - (mCornerX - mMiddleX) * (mCornerX - mMiddleX) / (mCornerY - mMiddleY) + mBezierControl2.y = + mMiddleY - (mCornerX - mMiddleX) * (mCornerX - mMiddleX) / (mCornerY - mMiddleY) } - mBezierStart1.x = mBezierControl1.x - (mCornerX - mBezierControl1.x) / 2 mBezierStart1.y = mCornerY.toFloat() - //固定左边上下两个点 + + // 固定左边上下两个点 if (mTouchX > 0 && mTouchX < viewWidth) { if (mBezierStart1.x < 0 || mBezierStart1.x > viewWidth) { if (mBezierStart1.x < 0) @@ -520,6 +495,7 @@ class SimulationPageDelegate(pageView: PageView) : HorizontalPageDelegate(pageVi val f1 = abs(mCornerX - mTouchX) val f2 = viewWidth * f1 / mBezierStart1.x mTouchX = abs(mCornerX - f2) + val f3 = abs(mCornerX - mTouchX) * abs(mCornerY - mTouchY) / f1 mTouchY = abs(mCornerY - f3) @@ -531,10 +507,14 @@ class SimulationPageDelegate(pageView: PageView) : HorizontalPageDelegate(pageVi mBezierControl1.y = mCornerY.toFloat() mBezierControl2.x = mCornerX.toFloat() - mBezierControl2.y = if ((mCornerY - mMiddleY).toInt() == 0) { - mMiddleY - (mCornerX - mMiddleX) * (mCornerX - mMiddleX) / 0.1f + + val f5 = mCornerY - mMiddleY + if (f5 == 0f) { + mBezierControl2.y = + mMiddleY - (mCornerX - mMiddleX) * (mCornerX - mMiddleX) / 0.1f } else { - mMiddleY - (mCornerX - mMiddleX) * (mCornerX - mMiddleX) / (mCornerY - mMiddleY) + mBezierControl2.y = + mMiddleY - (mCornerX - mMiddleX) * (mCornerX - mMiddleX) / (mCornerY - mMiddleY) } mBezierStart1.x = mBezierControl1.x - (mCornerX - mBezierControl1.x) / 2 @@ -543,12 +523,19 @@ class SimulationPageDelegate(pageView: PageView) : HorizontalPageDelegate(pageVi mBezierStart2.x = mCornerX.toFloat() mBezierStart2.y = mBezierControl2.y - (mCornerY - mBezierControl2.y) / 2 - mTouchToCornerDis = hypot(mTouchX - mCornerX, touchY - mCornerY) + mTouchToCornerDis = hypot( + (mTouchX - mCornerX).toDouble(), + (mTouchY - mCornerY).toDouble() + ).toFloat() - mBezierEnd1 = - getCross(PointF(mTouchX, mTouchY), mBezierControl1, mBezierStart1, mBezierStart2) - mBezierEnd2 = - getCross(PointF(mTouchX, mTouchY), mBezierControl2, mBezierStart1, mBezierStart2) + mBezierEnd1 = getCross( + PointF(mTouchX, mTouchY), mBezierControl1, mBezierStart1, + mBezierStart2 + ) + mBezierEnd2 = getCross( + PointF(mTouchX, mTouchY), mBezierControl2, mBezierStart1, + mBezierStart2 + ) mBezierVertex1.x = (mBezierStart1.x + 2 * mBezierControl1.x + mBezierEnd1.x) / 4 mBezierVertex1.y = (2 * mBezierControl1.y + mBezierStart1.y + mBezierEnd1.y) / 4 diff --git a/app/src/main/java/io/legado/app/ui/book/read/page/delegate/SlidePageDelegate.kt b/app/src/main/java/io/legado/app/ui/book/read/page/delegate/SlidePageDelegate.kt index 850c6b4ea..197b65c39 100644 --- a/app/src/main/java/io/legado/app/ui/book/read/page/delegate/SlidePageDelegate.kt +++ b/app/src/main/java/io/legado/app/ui/book/read/page/delegate/SlidePageDelegate.kt @@ -1,16 +1,12 @@ package io.legado.app.ui.book.read.page.delegate import android.graphics.Canvas +import android.graphics.Matrix import io.legado.app.ui.book.read.page.PageView class SlidePageDelegate(pageView: PageView) : HorizontalPageDelegate(pageView) { - override fun setStartPoint(x: Float, y: Float, invalidate: Boolean) { - curPage.x = 0f - prevPage.x = -viewWidth.toFloat() - nextPage.x = viewWidth.toFloat() - super.setStartPoint(x, y, invalidate) - } + private val bitmapMatrix = Matrix() override fun onAnimStart() { val distanceX: Float @@ -41,21 +37,22 @@ class SlidePageDelegate(pageView: PageView) : HorizontalPageDelegate(pageView) { if ((mDirection == Direction.NEXT && offsetX > 0) || (mDirection == Direction.PREV && offsetX < 0) ) return - + val distanceX = if (offsetX > 0) offsetX - viewWidth else offsetX + viewWidth if (!isRunning) return if (mDirection == Direction.PREV) { - curPage.translationX = offsetX - prevPage.translationX = offsetX - viewWidth + bitmapMatrix.setTranslate(distanceX + viewWidth, 0.toFloat()) + curBitmap?.let { canvas.drawBitmap(it, bitmapMatrix, null) } + bitmapMatrix.setTranslate(distanceX, 0.toFloat()) + prevBitmap?.let { canvas.drawBitmap(it, bitmapMatrix, null) } } else if (mDirection == Direction.NEXT) { - curPage.translationX = offsetX - nextPage.translationX = offsetX + viewWidth + bitmapMatrix.setTranslate(distanceX, 0.toFloat()) + nextBitmap?.let { canvas.drawBitmap(it, bitmapMatrix, null) } + bitmapMatrix.setTranslate(distanceX - viewWidth, 0.toFloat()) + curBitmap?.let { canvas.drawBitmap(it, bitmapMatrix, null) } } } override fun onAnimStop() { - curPage.x = 0f - prevPage.x = -viewWidth.toFloat() - nextPage.x = viewWidth.toFloat() if (!isCancel) { pageView.fillPage(mDirection) } diff --git a/app/src/main/java/io/legado/app/ui/book/read/page/entities/TextPage.kt b/app/src/main/java/io/legado/app/ui/book/read/page/entities/TextPage.kt index 4e6089ddd..e8782b6c3 100644 --- a/app/src/main/java/io/legado/app/ui/book/read/page/entities/TextPage.kt +++ b/app/src/main/java/io/legado/app/ui/book/read/page/entities/TextPage.kt @@ -14,7 +14,7 @@ data class TextPage( var pageSize: Int = 0, var chapterSize: Int = 0, var chapterIndex: Int = 0, - var height: Int = 0 + var height: Float = 0f ) { @Suppress("DEPRECATION") @@ -46,7 +46,7 @@ data class TextPage( } textLines.add(textLine) } - height = ChapterProvider.visibleHeight + height = ChapterProvider.visibleHeight.toFloat() } return this } diff --git a/app/src/main/java/io/legado/app/ui/main/MainActivity.kt b/app/src/main/java/io/legado/app/ui/main/MainActivity.kt index 8b4705ae0..298ccb294 100644 --- a/app/src/main/java/io/legado/app/ui/main/MainActivity.kt +++ b/app/src/main/java/io/legado/app/ui/main/MainActivity.kt @@ -16,6 +16,7 @@ import io.legado.app.constant.EventBus import io.legado.app.constant.PreferKey import io.legado.app.help.AppConfig import io.legado.app.help.storage.Backup +import io.legado.app.help.storage.SyncBookProgress import io.legado.app.lib.theme.ATH import io.legado.app.service.BaseReadAloudService import io.legado.app.service.help.ReadAloud @@ -128,6 +129,7 @@ class MainActivity : VMBaseActivity(R.layout.activity_main), override fun finish() { if (!BuildConfig.DEBUG) { + SyncBookProgress.uploadBookProgress() Backup.autoBack(this) } super.finish() diff --git a/app/src/main/java/io/legado/app/ui/welcome/WelcomeActivity.kt b/app/src/main/java/io/legado/app/ui/welcome/WelcomeActivity.kt index 7e535f009..5c84aa679 100644 --- a/app/src/main/java/io/legado/app/ui/welcome/WelcomeActivity.kt +++ b/app/src/main/java/io/legado/app/ui/welcome/WelcomeActivity.kt @@ -8,6 +8,7 @@ import io.legado.app.R import io.legado.app.base.BaseActivity import io.legado.app.help.AppConfig import io.legado.app.help.coroutine.Coroutine +import io.legado.app.help.storage.SyncBookProgress import io.legado.app.lib.theme.accentColor import io.legado.app.ui.book.read.ReadBookActivity import io.legado.app.ui.main.MainActivity @@ -41,6 +42,7 @@ open class WelcomeActivity : BaseActivity(R.layout.activity_welcome) { else -> null } } + SyncBookProgress.downloadBookProgress() root_view.postDelayed({ startMainActivity() }, 300) } diff --git a/app/src/main/java/io/legado/app/utils/BitmapUtils.kt b/app/src/main/java/io/legado/app/utils/BitmapUtils.kt index 371be8122..138a0c063 100644 --- a/app/src/main/java/io/legado/app/utils/BitmapUtils.kt +++ b/app/src/main/java/io/legado/app/utils/BitmapUtils.kt @@ -5,6 +5,7 @@ import android.graphics.Bitmap import android.graphics.Bitmap.Config import android.graphics.BitmapFactory import android.graphics.Canvas +import android.graphics.Color import android.renderscript.Allocation import android.renderscript.Element import android.renderscript.RenderScript @@ -12,10 +13,7 @@ import android.renderscript.ScriptIntrinsicBlur import android.view.View import io.legado.app.App import java.io.IOException -import kotlin.math.ceil -import kotlin.math.floor -import kotlin.math.min -import kotlin.math.sqrt +import kotlin.math.* @Suppress("unused", "WeakerAccess") @@ -257,4 +255,31 @@ object BitmapUtils { return blurredBitmap } + fun getMeanColor(bitmap: Bitmap): Int { + val width: Int = bitmap.width + val height: Int = bitmap.height + var pixel: Int + var pixelSumRed = 0 + var pixelSumBlue = 0 + var pixelSumGreen = 0 + for (i in 0..99) { + for (j in 70..99) { + pixel = bitmap.getPixel( + (i * width / 100.toFloat()).roundToInt(), + (j * height / 100.toFloat()).roundToInt() + ) + pixelSumRed += Color.red(pixel) + pixelSumGreen += Color.green(pixel) + pixelSumBlue += Color.blue(pixel) + } + } + val averagePixelRed = pixelSumRed / 3000 + val averagePixelBlue = pixelSumBlue / 3000 + val averagePixelGreen = pixelSumGreen / 3000 + return Color.rgb( + averagePixelRed + 3, + averagePixelGreen + 3, averagePixelBlue + 3 + ) + } + } diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 3c92dae8f..68f3af591 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -614,7 +614,7 @@ 长按选择文本 页眉 正文 - 页角 + 页脚 文本选择结束位置 文本选择开始位置 共用布局 diff --git a/app/src/main/res/xml/pref_config_backup.xml b/app/src/main/res/xml/pref_config_backup.xml index 3f99cfef2..b2442aa09 100644 --- a/app/src/main/res/xml/pref_config_backup.xml +++ b/app/src/main/res/xml/pref_config_backup.xml @@ -24,6 +24,13 @@ android:summary="@string/web_dav_pw_s" app:iconSpaceReserved="false" /> + +