diff --git a/app/build.gradle b/app/build.gradle index b2c3924d8..e36182ccc 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -55,7 +55,7 @@ android { signingConfig signingConfigs.myConfig } applicationIdSuffix '.release' - minifyEnabled false + minifyEnabled true proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' } debug { @@ -106,7 +106,7 @@ dependencies { implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" //fireBase - implementation 'com.google.firebase:firebase-core:17.2.2' + implementation 'com.google.firebase:firebase-core:17.2.3' implementation 'com.crashlytics.sdk.android:crashlytics:2.10.1' //androidX diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro index 008a0715b..2c9c17581 100644 --- a/app/proguard-rules.pro +++ b/app/proguard-rules.pro @@ -154,6 +154,8 @@ -keep class **.analyzeRule.**{*;} # 保持web类 -keep class **.web.**{*;} +#数据类 +-keep class **.data.**{*;} -dontwarn rx.** @@ -166,6 +168,7 @@ -dontnote org.python.core.** -dontwarn com.hwangjr.rxbus.** -dontwarn okhttp3.** +-dontwarn org.conscrypt.** -keep class retrofit2.**{*;} -keep class okhttp3.**{*;} @@ -206,8 +209,6 @@ -keep class javax.script.** { *; } -keep class com.sun.script.javascript.** { *; } -keep class org.mozilla.javascript.** { *; } --dontwarn org.mozilla.javascript.** --dontwarn sun.** ###EPUB -dontwarn nl.siegmann.epublib.** @@ -222,9 +223,6 @@ -keepclassmembers class * { public (org.json.JSONObject); } --keep public class com.kunfei.bookshelf.R$*{ - public static final int *; -} -keepclassmembers enum * { public static **[] values(); public static ** valueOf(java.lang.String); diff --git a/app/src/main/java/io/legado/app/App.kt b/app/src/main/java/io/legado/app/App.kt index 95f29cd64..88379b333 100644 --- a/app/src/main/java/io/legado/app/App.kt +++ b/app/src/main/java/io/legado/app/App.kt @@ -48,12 +48,8 @@ class App : Application() { versionCode = it.versionCode versionName = it.versionName } - - if (!ThemeStore.isConfigured(this, versionCode)) applyTheme() - initNightMode() - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) createChannelId() - + applyDayNight() LiveEventBus.get() .config() .supportBroadcast(this) diff --git a/app/src/main/java/io/legado/app/data/AppDatabase.kt b/app/src/main/java/io/legado/app/data/AppDatabase.kt index e548f4584..f32d6a199 100644 --- a/app/src/main/java/io/legado/app/data/AppDatabase.kt +++ b/app/src/main/java/io/legado/app/data/AppDatabase.kt @@ -32,7 +32,7 @@ abstract class AppDatabase : RoomDatabase() { .fallbackToDestructiveMigration() .addCallback(object : Callback() { override fun onDestructiveMigration(db: SupportSQLiteDatabase) { - GlobalScope.launch { Restore.restore(Backup.backupPath) } + GlobalScope.launch { Restore.restoreDatabase(Backup.backupPath) } } }) .build() diff --git a/app/src/main/java/io/legado/app/data/dao/ReplaceRuleDao.kt b/app/src/main/java/io/legado/app/data/dao/ReplaceRuleDao.kt index 0abc76dc8..5643ef975 100644 --- a/app/src/main/java/io/legado/app/data/dao/ReplaceRuleDao.kt +++ b/app/src/main/java/io/legado/app/data/dao/ReplaceRuleDao.kt @@ -33,14 +33,20 @@ interface ReplaceRuleDao { fun findByIds(vararg ids: Long): List @Query( - """SELECT * FROM replace_rules WHERE isEnabled = 1 - AND (scope LIKE '%' || :scope || '%' or scope is null or scope = '')""" + """ + SELECT * FROM replace_rules WHERE isEnabled = 1 + AND (scope LIKE '%' || :scope || '%' or scope is null or scope = '') + order by sortOrder + """ ) fun findEnabledByScope(scope: String): List @Query( - """SELECT * FROM replace_rules WHERE isEnabled = 1 - AND (scope LIKE '%' || :name || '%' or scope LIKE '%' || :origin || '%' or scope is null or scope = '')""" + """ + SELECT * FROM replace_rules WHERE isEnabled = 1 + AND (scope LIKE '%' || :name || '%' or scope LIKE '%' || :origin || '%' or scope is null or scope = '') + order by sortOrder + """ ) fun findEnabledByScope(name: String, origin: String): List diff --git a/app/src/main/java/io/legado/app/help/BookHelp.kt b/app/src/main/java/io/legado/app/help/BookHelp.kt index 7df2540c5..31f0d4b5e 100644 --- a/app/src/main/java/io/legado/app/help/BookHelp.kt +++ b/app/src/main/java/io/legado/app/help/BookHelp.kt @@ -11,7 +11,10 @@ import io.legado.app.data.entities.BookChapter import io.legado.app.data.entities.ReplaceRule import io.legado.app.model.localBook.AnalyzeTxtFile import io.legado.app.utils.* +import kotlinx.coroutines.Dispatchers.Main +import kotlinx.coroutines.withContext import org.apache.commons.text.similarity.JaccardSimilarity +import org.jetbrains.anko.toast import java.io.File import kotlin.math.min @@ -262,7 +265,7 @@ object BookHelp { } } - fun disposeContent( + suspend fun disposeContent( title: String, name: String, origin: String?, @@ -272,13 +275,19 @@ object BookHelp { var c = content if (enableReplace) { upReplaceRules(name, origin) - for (item in replaceRules) { + replaceRules.forEach { item -> item.pattern.let { if (it.isNotEmpty()) { - c = if (item.isRegex) { - c.replace(it.toRegex(), item.replacement) - } else { - c.replace(it, item.replacement) + try { + c = if (item.isRegex) { + c.replace(it.toRegex(), item.replacement) + } else { + c.replace(it, item.replacement) + } + } catch (e: Exception) { + withContext(Main) { + App.INSTANCE.toast("${item.name}替换出错") + } } } } diff --git a/app/src/main/java/io/legado/app/help/JsExtensions.kt b/app/src/main/java/io/legado/app/help/JsExtensions.kt index 32da4bb06..7cfd763a1 100644 --- a/app/src/main/java/io/legado/app/help/JsExtensions.kt +++ b/app/src/main/java/io/legado/app/help/JsExtensions.kt @@ -1,13 +1,14 @@ package io.legado.app.help import android.util.Base64 +import androidx.annotation.Keep import io.legado.app.constant.AppConst.DATE_FORMAT import io.legado.app.model.analyzeRule.AnalyzeUrl import io.legado.app.utils.EncoderUtils import io.legado.app.utils.MD5Utils import java.util.* - +@Keep @Suppress("unused") interface JsExtensions { 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 0801f88dd..dcef91c72 100644 --- a/app/src/main/java/io/legado/app/help/ReadBookConfig.kt +++ b/app/src/main/java/io/legado/app/help/ReadBookConfig.kt @@ -4,6 +4,7 @@ import android.graphics.Color import android.graphics.drawable.BitmapDrawable import android.graphics.drawable.ColorDrawable import android.graphics.drawable.Drawable +import androidx.annotation.Keep import io.legado.app.App import io.legado.app.R import io.legado.app.constant.PreferKey @@ -15,6 +16,7 @@ import java.io.File /** * 阅读界面配置 */ +@Keep object ReadBookConfig { const val readConfigFileName = "readConfig.json" private val configFilePath = @@ -236,6 +238,7 @@ object ReadBookConfig { if (shareLayout) shareConfig.footerPaddingTop = value else durConfig.footerPaddingTop = value + @Keep class Config( private var bgStr: String = "#EEEEEE",//白天背景 private var bgStrNight: String = "#000000",//夜间背景 @@ -247,7 +250,7 @@ object ReadBookConfig { private var textColorNight: String = "#ADADAD",//夜间文字颜色 var textBold: Boolean = false,//是否粗体字 var textSize: Int = 20,//文字大小 - var letterSpacing: Float = 1f,//字间距 + var letterSpacing: Float = 0.5f,//字间距 var lineSpacingExtra: Int = 12,//行间距 var paragraphSpacing: Int = 12,//段距 var titleCenter: Boolean = true,//标题居中 diff --git a/app/src/main/java/io/legado/app/help/storage/Restore.kt b/app/src/main/java/io/legado/app/help/storage/Restore.kt index d9be6e9bd..8cdce0ae5 100644 --- a/app/src/main/java/io/legado/app/help/storage/Restore.kt +++ b/app/src/main/java/io/legado/app/help/storage/Restore.kt @@ -8,6 +8,7 @@ import com.jayway.jsonpath.JsonPath import com.jayway.jsonpath.Option import com.jayway.jsonpath.ParseContext import io.legado.app.App +import io.legado.app.BuildConfig import io.legado.app.constant.PreferKey import io.legado.app.data.entities.* import io.legado.app.help.LauncherIconHelp @@ -16,6 +17,7 @@ import io.legado.app.service.help.ReadBook import io.legado.app.ui.book.read.page.ChapterProvider import io.legado.app.utils.* import kotlinx.coroutines.Dispatchers.IO +import kotlinx.coroutines.Dispatchers.Main import kotlinx.coroutines.withContext import org.jetbrains.anko.defaultSharedPreferences import java.io.File @@ -60,10 +62,11 @@ object Restore { } } } - restore(Backup.backupPath) + restoreDatabase() + restoreConfig() } - suspend fun restore(path: String) { + suspend fun restoreDatabase(path: String = Backup.backupPath) { withContext(IO) { fileToListT(path, "bookshelf.json")?.let { App.db.bookDao().insert(*it.toTypedArray()) @@ -83,11 +86,16 @@ object Restore { fileToListT(path, "replaceRule.json")?.let { App.db.replaceRuleDao().insert(*it.toTypedArray()) } + } + } + + suspend fun restoreConfig(path: String = Backup.backupPath) { + withContext(IO) { try { val file = FileUtils.createFileIfNotExist(path + File.separator + ReadBookConfig.readConfigFileName) val configFile = - File(App.INSTANCE.filesDir.absolutePath + File.separator + ReadBookConfig.readConfigFileName) + FileUtils.getFile(App.INSTANCE.filesDir, ReadBookConfig.readConfigFileName) if (file.exists()) { file.copyTo(configFile, true) ReadBookConfig.upConfig() @@ -119,7 +127,11 @@ object Restore { ChapterProvider.upStyle() ReadBook.loadContent() } - LauncherIconHelp.changeIcon(App.INSTANCE.getPrefString(PreferKey.launcherIcon)) + withContext(Main) { + App.INSTANCE.applyDayNight() + if (!BuildConfig.DEBUG) + LauncherIconHelp.changeIcon(App.INSTANCE.getPrefString(PreferKey.launcherIcon)) + } } private inline fun fileToListT(path: String, fileName: String): List? { 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 50857893d..ad4c93a2a 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 @@ -95,7 +95,8 @@ object WebDavHelp { webDav.downloadTo(zipFilePath, true) @Suppress("BlockingMethodInNonBlockingContext") ZipUtils.unzipFile(zipFilePath, Backup.backupPath) - Restore.restore(Backup.backupPath) + Restore.restoreDatabase() + Restore.restoreConfig() } } }.onSuccess { diff --git a/app/src/main/java/io/legado/app/service/help/ReadBook.kt b/app/src/main/java/io/legado/app/service/help/ReadBook.kt index 207c34ec6..85f2fff45 100644 --- a/app/src/main/java/io/legado/app/service/help/ReadBook.kt +++ b/app/src/main/java/io/legado/app/service/help/ReadBook.kt @@ -69,11 +69,11 @@ object ReadBook { nextTextChapter = null book?.let { if (curTextChapter == null) { - loadContent(durChapterIndex) + loadContent(durChapterIndex, upContent) } else if (upContent) { callBack?.upContent() } - loadContent(durChapterIndex.plus(1)) + loadContent(durChapterIndex.plus(1), upContent) GlobalScope.launch(Dispatchers.IO) { for (i in 2..10) { delay(100) @@ -99,11 +99,11 @@ object ReadBook { prevTextChapter = null book?.let { if (curTextChapter == null) { - loadContent(durChapterIndex) + loadContent(durChapterIndex, upContent) } else if (upContent) { callBack?.upContent() } - loadContent(durChapterIndex.minus(1)) + loadContent(durChapterIndex.minus(1), upContent) GlobalScope.launch(Dispatchers.IO) { for (i in -5..-2) { delay(100) @@ -190,13 +190,13 @@ object ReadBook { loadContent(durChapterIndex - 1) } - fun loadContent(index: Int) { + fun loadContent(index: Int, upContent: Boolean = true) { book?.let { book -> if (addLoading(index)) { Coroutine.async { App.db.bookChapterDao().getChapter(book.bookUrl, index)?.let { chapter -> BookHelp.getContent(book, chapter)?.let { - contentLoadFinish(chapter, it) + contentLoadFinish(chapter, it, upContent) removeLoading(chapter.index) } ?: download(chapter) } ?: removeLoading(index) @@ -262,7 +262,11 @@ object ReadBook { /** * 内容加载完成 */ - private fun contentLoadFinish(chapter: BookChapter, content: String) { + private fun contentLoadFinish( + chapter: BookChapter, + content: String, + upContent: Boolean = true + ) { Coroutine.async { if (chapter.index in durChapterIndex - 1..durChapterIndex + 1) { val c = BookHelp.disposeContent( @@ -275,18 +279,18 @@ object ReadBook { when (chapter.index) { durChapterIndex -> { curTextChapter = ChapterProvider.getTextChapter(chapter, c, chapterSize) - callBack?.upContent() + if (upContent) callBack?.upContent() callBack?.upView() curPageChanged() callBack?.contentLoadFinish() } durChapterIndex - 1 -> { prevTextChapter = ChapterProvider.getTextChapter(chapter, c, chapterSize) - callBack?.upContent(-1) + if (upContent) callBack?.upContent(-1) } durChapterIndex + 1 -> { nextTextChapter = ChapterProvider.getTextChapter(chapter, c, chapterSize) - callBack?.upContent(1) + if (upContent) callBack?.upContent(1) } } } diff --git a/app/src/main/java/io/legado/app/ui/book/read/ReadBookActivity.kt b/app/src/main/java/io/legado/app/ui/book/read/ReadBookActivity.kt index 447a030b8..de1f1d728 100644 --- a/app/src/main/java/io/legado/app/ui/book/read/ReadBookActivity.kt +++ b/app/src/main/java/io/legado/app/ui/book/read/ReadBookActivity.kt @@ -23,6 +23,7 @@ import io.legado.app.data.entities.BookChapter import io.legado.app.help.BookHelp import io.legado.app.help.ReadBookConfig import io.legado.app.help.coroutine.Coroutine +import io.legado.app.help.storage.SyncBookProgress import io.legado.app.lib.dialogs.alert import io.legado.app.lib.dialogs.noButton import io.legado.app.lib.dialogs.okButton @@ -31,6 +32,8 @@ import io.legado.app.receiver.TimeBatteryReceiver import io.legado.app.service.BaseReadAloudService import io.legado.app.service.help.ReadAloud import io.legado.app.service.help.ReadBook +import io.legado.app.ui.book.changesource.ChangeSourceDialog +import io.legado.app.ui.book.chapterlist.ChapterListActivity import io.legado.app.ui.book.info.BookInfoActivity import io.legado.app.ui.book.read.config.* import io.legado.app.ui.book.read.config.BgTextConfigDialog.Companion.BG_COLOR @@ -40,8 +43,6 @@ import io.legado.app.ui.book.read.page.PageView import io.legado.app.ui.book.read.page.TextPageFactory import io.legado.app.ui.book.read.page.delegate.PageDelegate import io.legado.app.ui.book.source.edit.BookSourceEditActivity -import io.legado.app.ui.book.changesource.ChangeSourceDialog -import io.legado.app.ui.book.chapterlist.ChapterListActivity import io.legado.app.ui.login.SourceLogin import io.legado.app.ui.replacerule.ReplaceRuleActivity import io.legado.app.ui.replacerule.edit.ReplaceEditDialog @@ -660,6 +661,7 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_boo mHandler.removeCallbacks(keepScreenRunnable) textActionMenu?.dismiss() page_view.onDestroy() + SyncBookProgress.uploadBookProgress() } override fun observeLiveBus() { 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 bc9dfc6e1..20afe26cf 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 @@ -16,6 +16,7 @@ import io.legado.app.ui.book.read.page.entities.TextPage import io.legado.app.utils.dp import io.legado.app.utils.getPrefString import io.legado.app.utils.removePref +import io.legado.app.utils.toStringArray @Suppress("DEPRECATION") @@ -177,10 +178,10 @@ object ChapterProvider { var x = 0f val bodyIndent = ReadBookConfig.bodyIndent val icw = StaticLayout.getDesiredWidth(bodyIndent, textPaint) / bodyIndent.length - for (i in 0..bodyIndent.lastIndex) { + bodyIndent.toStringArray().forEach { val x1 = x + icw textLine.addTextChar( - charData = bodyIndent[i].toString(), + charData = it, start = paddingLeft + x, end = paddingLeft + x1 ) @@ -203,12 +204,11 @@ object ChapterProvider { val gapCount: Int = words.length - 1 val d = (visibleWidth - desiredWidth) / gapCount var x = startX - for (i in words.indices) { - val char = words[i] - val cw = StaticLayout.getDesiredWidth(char.toString(), textPaint) + for ((i, char) in words.toStringArray().withIndex()) { + val cw = StaticLayout.getDesiredWidth(char, textPaint) val x1 = if (i != words.lastIndex) (x + cw + d) else (x + cw) textLine.addTextChar( - charData = char.toString(), + charData = char, start = paddingLeft + x, end = paddingLeft + x1 ) @@ -230,12 +230,11 @@ object ChapterProvider { stringBuilder.append("\n") textLine.text = "$words\n" var x = startX - for (i in words.indices) { - val char = words[i].toString() - val cw = StaticLayout.getDesiredWidth(char, textPaint) + words.toStringArray().forEach { + val cw = StaticLayout.getDesiredWidth(it, textPaint) val x1 = x + cw textLine.addTextChar( - charData = char, + charData = it, start = paddingLeft + x, end = paddingLeft + x1 ) diff --git a/app/src/main/java/io/legado/app/ui/book/read/page/ContentTextView.kt b/app/src/main/java/io/legado/app/ui/book/read/page/ContentTextView.kt index e8beebf6a..44baa68f6 100644 --- a/app/src/main/java/io/legado/app/ui/book/read/page/ContentTextView.kt +++ b/app/src/main/java/io/legado/app/ui/book/read/page/ContentTextView.kt @@ -170,13 +170,13 @@ class ContentTextView(context: Context, attrs: AttributeSet?) : View(context, at } else if (!pageFactory.hasNext() && pageOffset < 0) { pageOffset = 0f } else if (pageOffset > 0) { - pageFactory.moveToPrev() + pageFactory.moveToPrev(false) textPage = pageFactory.currentPage pageOffset -= textPage.height upView?.invoke(textPage) } else if (pageOffset < -textPage.height) { pageOffset += textPage.height - pageFactory.moveToNext() + pageFactory.moveToNext(false) textPage = pageFactory.currentPage upView?.invoke(textPage) } diff --git a/app/src/main/java/io/legado/app/ui/book/read/page/DataSource.kt b/app/src/main/java/io/legado/app/ui/book/read/page/DataSource.kt index 1d188f598..4f7afa04f 100644 --- a/app/src/main/java/io/legado/app/ui/book/read/page/DataSource.kt +++ b/app/src/main/java/io/legado/app/ui/book/read/page/DataSource.kt @@ -16,4 +16,6 @@ interface DataSource { fun hasNextChapter(): Boolean fun hasPrevChapter(): Boolean + + fun upContent(relativePosition: Int = 0) } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/book/read/page/PageFactory.kt b/app/src/main/java/io/legado/app/ui/book/read/page/PageFactory.kt index 7a04ae5ec..75fd79094 100644 --- a/app/src/main/java/io/legado/app/ui/book/read/page/PageFactory.kt +++ b/app/src/main/java/io/legado/app/ui/book/read/page/PageFactory.kt @@ -6,9 +6,9 @@ abstract class PageFactory(protected val dataSource: DataSource) { abstract fun moveToLast() - abstract fun moveToNext():Boolean + abstract fun moveToNext(upContent: Boolean): Boolean - abstract fun moveToPrev(): Boolean + abstract fun moveToPrev(upContent: Boolean): Boolean abstract val nextPage: DATA diff --git a/app/src/main/java/io/legado/app/ui/book/read/page/PageView.kt b/app/src/main/java/io/legado/app/ui/book/read/page/PageView.kt index 7f89a98a7..dbde99c7e 100644 --- a/app/src/main/java/io/legado/app/ui/book/read/page/PageView.kt +++ b/app/src/main/java/io/legado/app/ui/book/read/page/PageView.kt @@ -76,12 +76,10 @@ class PageView(context: Context, attrs: AttributeSet) : fun fillPage(direction: PageDelegate.Direction) { when (direction) { PageDelegate.Direction.PREV -> { - pageFactory.moveToPrev() - upContent() + pageFactory.moveToPrev(true) } PageDelegate.Direction.NEXT -> { - pageFactory.moveToNext() - upContent() + pageFactory.moveToNext(true) } else -> Unit } @@ -100,7 +98,7 @@ class PageView(context: Context, attrs: AttributeSet) : upContent() } - fun upContent(relativePosition: Int = 0) { + override fun upContent(relativePosition: Int) { if (ReadBookConfig.isScroll) { curPage.setContent(pageFactory.currentPage) } else { diff --git a/app/src/main/java/io/legado/app/ui/book/read/page/TextPageFactory.kt b/app/src/main/java/io/legado/app/ui/book/read/page/TextPageFactory.kt index 571f0d68f..a867daf3d 100644 --- a/app/src/main/java/io/legado/app/ui/book/read/page/TextPageFactory.kt +++ b/app/src/main/java/io/legado/app/ui/book/read/page/TextPageFactory.kt @@ -31,25 +31,27 @@ class TextPageFactory(dataSource: DataSource) : PageFactory(dataSource } ?: ReadBook.setPageIndex(0) } - override fun moveToNext(): Boolean = with(dataSource) { + override fun moveToNext(upContent: Boolean): Boolean = with(dataSource) { return if (hasNext()) { if (currentChapter?.isLastIndex(pageIndex) == true) { - ReadBook.moveToNextChapter(false) + ReadBook.moveToNextChapter(upContent) } else { ReadBook.setPageIndex(pageIndex.plus(1)) } + if (upContent) upContent() true } else false } - override fun moveToPrev(): Boolean = with(dataSource) { + override fun moveToPrev(upContent: Boolean): Boolean = with(dataSource) { return if (hasPrev()) { if (pageIndex <= 0) { - ReadBook.moveToPrevChapter(false) + ReadBook.moveToPrevChapter(upContent) } else { ReadBook.setPageIndex(pageIndex.minus(1)) } + if (upContent) upContent() true } else false 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 74583bae0..b10503fc8 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 @@ -4,7 +4,6 @@ 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) { @@ -52,12 +51,31 @@ abstract class HorizontalPageDelegate(pageView: PageView) : PageDelegate(pageVie } private fun onScroll(event: MotionEvent) { + + val action: Int = event.action + val pointerUp = + action and MotionEvent.ACTION_MASK == MotionEvent.ACTION_POINTER_UP + val skipIndex = if (pointerUp) event.actionIndex else -1 + // Determine focal point + var sumX = 0f + var sumY = 0f + val count: Int = event.pointerCount + for (i in 0 until count) { + if (skipIndex == i) continue + sumX += event.getX(i) + sumY += event.getY(i) + } + val div = if (pointerUp) count - 1 else count + val focusX = sumX / div + val focusY = sumY / div //判断是否移动了 if (!isMoved) { - isMoved = abs(startX - event.x) > slop - || abs(startX - event.x) > abs(startY - event.y) + val deltaX = (focusX - startX).toInt() + val deltaY = (focusY - startY).toInt() + val distance = deltaX * deltaX + deltaY * deltaY + isMoved = distance > slopSquare if (isMoved) { - if (event.x - startX > 0) { + if (sumX - startX > 0) { //如果上一页不存在 if (!hasPrev()) { noNext = true @@ -78,7 +96,7 @@ abstract class HorizontalPageDelegate(pageView: PageView) : PageDelegate(pageVie isCancel = if (mDirection == Direction.NEXT) touchX > lastX else touchX < lastX isRunning = true //设置触摸点 - setTouchPoint(event.x, event.y) + setTouchPoint(sumX, sumY) } } diff --git a/app/src/main/java/io/legado/app/ui/book/read/page/delegate/PageDelegate.kt b/app/src/main/java/io/legado/app/ui/book/read/page/delegate/PageDelegate.kt index fef7e5b0e..d28f8c816 100644 --- a/app/src/main/java/io/legado/app/ui/book/read/page/delegate/PageDelegate.kt +++ b/app/src/main/java/io/legado/app/ui/book/read/page/delegate/PageDelegate.kt @@ -23,7 +23,7 @@ abstract class PageDelegate(protected val pageView: PageView) : pageView.width * 0.66f, pageView.height * 0.66f ) protected val context: Context = pageView.context - protected val slop = ViewConfiguration.get(context).scaledTouchSlop + //起始点 protected var startX: Float = 0f protected var startY: Float = 0f @@ -41,18 +41,23 @@ abstract class PageDelegate(protected val pageView: PageView) : protected var viewWidth: Int = pageView.width protected var viewHeight: Int = pageView.height - private val snackBar: Snackbar by lazy { - Snackbar.make(pageView, "", Snackbar.LENGTH_SHORT) - } - private val scroller: Scroller by lazy { Scroller(pageView.context, DecelerateInterpolator()) } + protected val slopSquare by lazy { + val scaledTouchSlop = ViewConfiguration.get(context).scaledTouchSlop + scaledTouchSlop * scaledTouchSlop + } + private val detector: GestureDetector by lazy { GestureDetector(pageView.context, this) } + private val snackBar: Snackbar by lazy { + Snackbar.make(pageView, "", Snackbar.LENGTH_SHORT) + } + var isMoved = false var noNext = true @@ -189,13 +194,17 @@ abstract class PageDelegate(protected val pageView: PageView) : @CallSuper open fun onTouch(event: MotionEvent) { if (isStarted) return + detector.setIsLongpressEnabled(false) if (!detector.onTouchEvent(event)) { //GestureDetector.onFling小幅移动不会触发,所以要自己判断 - if (event.action == MotionEvent.ACTION_UP && isMoved) { - if (selectedOnDown) { - selectedOnDown = false + when (event.action) { + MotionEvent.ACTION_UP, + MotionEvent.ACTION_CANCEL -> if (isMoved) { + if (selectedOnDown) { + selectedOnDown = false + } + if (!noNext) onAnimStart() } - if (!noNext) onAnimStart() } } } @@ -232,6 +241,10 @@ abstract class PageDelegate(protected val pageView: PageView) : selectedOnDown = false return true } + if (isMoved) { + if (!noNext) onAnimStart() + return true + } val x = e.x val y = e.y if (centerRectF.contains(x, y)) { diff --git a/app/src/main/java/io/legado/app/ui/book/read/page/delegate/ScrollPageDelegate.kt b/app/src/main/java/io/legado/app/ui/book/read/page/delegate/ScrollPageDelegate.kt index 0e5fb7dff..3fa333cbf 100644 --- a/app/src/main/java/io/legado/app/ui/book/read/page/delegate/ScrollPageDelegate.kt +++ b/app/src/main/java/io/legado/app/ui/book/read/page/delegate/ScrollPageDelegate.kt @@ -4,7 +4,6 @@ import android.view.MotionEvent import android.view.VelocityTracker import io.legado.app.ui.book.read.page.ChapterProvider import io.legado.app.ui.book.read.page.PageView -import kotlin.math.abs class ScrollPageDelegate(pageView: PageView) : PageDelegate(pageView) { @@ -46,9 +45,28 @@ class ScrollPageDelegate(pageView: PageView) : PageDelegate(pageView) { private fun onScroll(event: MotionEvent) { mVelocity.addMovement(event) mVelocity.computeCurrentVelocity(velocityDuration) - setTouchPoint(event.x, event.y) + val action: Int = event.action + val pointerUp = + action and MotionEvent.ACTION_MASK == MotionEvent.ACTION_POINTER_UP + val skipIndex = if (pointerUp) event.actionIndex else -1 + // Determine focal point + var sumX = 0f + var sumY = 0f + val count: Int = event.pointerCount + for (i in 0 until count) { + if (skipIndex == i) continue + sumX += event.getX(i) + sumY += event.getY(i) + } + val div = if (pointerUp) count - 1 else count + val focusX = sumX / div + val focusY = sumY / div + setTouchPoint(sumX, sumY) if (!isMoved) { - isMoved = abs(startX - event.x) > slop || abs(startY - event.y) > slop + val deltaX = (focusX - startX).toInt() + val deltaY = (focusY - startY).toInt() + val distance = deltaX * deltaX + deltaY * deltaY + isMoved = distance > slopSquare } if (isMoved) { isRunning = true diff --git a/app/src/main/java/io/legado/app/ui/config/BackupRestoreUi.kt b/app/src/main/java/io/legado/app/ui/config/BackupRestoreUi.kt index 1bec0a184..913f78971 100644 --- a/app/src/main/java/io/legado/app/ui/config/BackupRestoreUi.kt +++ b/app/src/main/java/io/legado/app/ui/config/BackupRestoreUi.kt @@ -114,7 +114,8 @@ object BackupRestoreUi { .onGranted { Coroutine.async { AppConfig.backupPath = path - Restore.restore(path) + Restore.restoreDatabase(path) + Restore.restoreConfig(path) }.onSuccess { fragment.toast(R.string.restore_success) } 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 298ccb294..8b4705ae0 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,7 +16,6 @@ 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 @@ -129,7 +128,6 @@ 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/replacerule/edit/ReplaceEditViewModel.kt b/app/src/main/java/io/legado/app/ui/replacerule/edit/ReplaceEditViewModel.kt index 722deb738..e4a0d443c 100644 --- a/app/src/main/java/io/legado/app/ui/replacerule/edit/ReplaceEditViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/replacerule/edit/ReplaceEditViewModel.kt @@ -23,7 +23,7 @@ class ReplaceEditViewModel(application: Application) : BaseViewModel(application bundle.getString("pattern")?.let { pattern -> val isRegex = bundle.getBoolean("isRegex") replaceRuleData.postValue( - ReplaceRule(pattern = pattern, isRegex = isRegex) + ReplaceRule(name = pattern, pattern = pattern, isRegex = isRegex) ) } } diff --git a/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesActivity.kt b/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesActivity.kt index 3b53a6475..31ac9cdda 100644 --- a/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesActivity.kt +++ b/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesActivity.kt @@ -60,7 +60,7 @@ class RssArticlesActivity : VMBaseActivity(R.layout.activi R.id.menu_clear -> { viewModel.url?.let { refresh_progress_bar.isAutoLoading = true - viewModel.clear() + viewModel.clearArticles() } } } diff --git a/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesViewModel.kt b/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesViewModel.kt index 42bc5c2d4..ccfff44df 100644 --- a/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesViewModel.kt @@ -106,7 +106,7 @@ class RssArticlesViewModel(application: Application) : BaseViewModel(application } } - fun clear() { + fun clearArticles() { execute { url?.let { App.db.rssArticleDao().delete(it) diff --git a/app/src/main/java/io/legado/app/utils/RealPathUtil.kt b/app/src/main/java/io/legado/app/utils/RealPathUtil.kt index 5ded2f823..3eedc2fde 100644 --- a/app/src/main/java/io/legado/app/utils/RealPathUtil.kt +++ b/app/src/main/java/io/legado/app/utils/RealPathUtil.kt @@ -102,8 +102,6 @@ object RealPathUtil { val projection = arrayOf( column ) - var input: FileInputStream? = null - var output: FileOutputStream? = null try { cursor = context.contentResolver.query(uri!!, projection, selection, selectionArgs, null) @@ -115,6 +113,8 @@ object RealPathUtil { e.printStackTrace() val file = File(context.cacheDir, "tmp") val filePath = file.absolutePath + var input: FileInputStream? = null + var output: FileOutputStream? = null try { val pfd = context.contentResolver.openFileDescriptor(filePathUri!!, "r") @@ -127,11 +127,12 @@ object RealPathUtil { while (input.read(bytes).also { read = it } != -1) { output.write(bytes, 0, read) } - input.close() - output.close() return File(filePath).absolutePath } catch (ignored: IOException) { ignored.printStackTrace() + } finally { + input?.close() + output?.close() } } finally { cursor?.close() diff --git a/app/src/main/java/io/legado/app/utils/StringExtensions.kt b/app/src/main/java/io/legado/app/utils/StringExtensions.kt index 3f4f40ee2..ae881eb64 100644 --- a/app/src/main/java/io/legado/app/utils/StringExtensions.kt +++ b/app/src/main/java/io/legado/app/utils/StringExtensions.kt @@ -48,6 +48,17 @@ fun String.splitNotBlank(regex: Regex, limit: Int = 0): Array = run { this.split(regex, limit).map { it.trim() }.filterNot { it.isBlank() }.toTypedArray() } +fun String.toStringArray(): Array { + var codePointIndex = 0 + return Array(codePointCount(0, length)) { + substring( + codePointIndex, + offsetByCodePoints(codePointIndex, 1) + .apply { codePointIndex = this } + ) + } +} + fun Char?.isHAN(): Boolean { this ?: return false val ub: Character.UnicodeBlock = Character.UnicodeBlock.of(this) ?: return false diff --git a/build.gradle b/build.gradle index ce09ff149..5eb9c16b8 100644 --- a/build.gradle +++ b/build.gradle @@ -13,7 +13,7 @@ buildscript { classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" classpath 'de.timfreiheit.resourceplaceholders:placeholders:0.3' classpath 'com.google.gms:google-services:4.3.3' - classpath 'io.fabric.tools:gradle:1.31.0' + classpath 'io.fabric.tools:gradle:1.31.2' } } diff --git a/gradle.properties b/gradle.properties index 41a06e351..23339e0df 100644 --- a/gradle.properties +++ b/gradle.properties @@ -19,4 +19,3 @@ android.useAndroidX=true android.enableJetifier=true # Kotlin code style for this project: "official" or "obsolete": kotlin.code.style=official -android.enableR8=false \ No newline at end of file