diff --git a/app/build.gradle b/app/build.gradle index 1b0c7d4b0..3c8a18f6c 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 { @@ -75,8 +75,11 @@ android { } compileOptions { - sourceCompatibility = '1.8' - targetCompatibility = '1.8' + // Flag to enable support for the new language APIs + //coreLibraryDesugaringEnabled true + // Sets Java compatibility to Java 8 + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 } kotlinOptions { @@ -103,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 @@ -137,7 +140,7 @@ dependencies { implementation "org.jetbrains.anko:anko-sdk27-listeners:$anko_version" //liveEventBus - implementation 'com.jeremyliao:live-event-bus-x:1.4.5' + implementation 'com.jeremyliao:live-event-bus-x:1.5.7' //协程 def coroutines_version = '1.3.3' diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro index 008a0715b..9af1203b9 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,7 +168,10 @@ -dontnote org.python.core.** -dontwarn com.hwangjr.rxbus.** -dontwarn okhttp3.** +-dontwarn org.conscrypt.** +-dontwarn com.jeremyliao.liveeventbus.** +-keep class com.jeremyliao.liveeventbus.** { *; } -keep class retrofit2.**{*;} -keep class okhttp3.**{*;} -keep class okio.**{*;} @@ -183,6 +188,7 @@ -keep class com.gyf.barlibrary.* {*;} ##JSOUP -keep class org.jsoup.**{*;} +-keep class **.xpath.**{*;} -keep class org.slf4j.**{*;} -dontwarn org.slf4j.** @@ -206,8 +212,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 +226,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/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index e4bc75603..f4d3af897 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -133,7 +133,9 @@ android:name=".ui.about.DonateActivity" android:launchMode="singleTask" /> - + @@ -144,7 +146,9 @@ - + @@ -159,7 +163,7 @@ + android:launchMode="singleTop"> @@ -171,16 +175,36 @@ android:scheme="yuedu" /> - - - - - - - - - - + + + + + + + + + + diff --git a/app/src/main/assets/txtTocRule.json b/app/src/main/assets/txtTocRule.json index 1304059d0..fc5469653 100644 --- a/app/src/main/assets/txtTocRule.json +++ b/app/src/main/assets/txtTocRule.json @@ -2,67 +2,73 @@ { "enable": true, "name": "目录", - "rule": "^[ \\t]{0,4}(?:(?:内容|文章)?简介|文案|前言|序章|楔子|正文(?!完)|终章|后记|尾声|番外|第?\\s{0,4}[\\d零一二两三四五六七八九十百千万壹贰叁肆伍陆柒捌玖拾佰仟]+?\\s{0,4}(?:章|节(?!课)|卷|集(?![合和])|部(?!分)|篇(?!张))).{0,30}$", + "rule": "^[  \\t]{0,4}(?:(?:内容|文章)?简介|文案|前言|序章|楔子|正文(?!完)|终章|后记|尾声|番外|第?\\s{0,4}[\\d零一二两三四五六七八九十百千万壹贰叁肆伍陆柒捌玖拾佰仟]+?\\s{0,4}(?:章|节(?!课)|卷|集(?![合和])|部(?!分)|篇(?!张))).{0,30}$", "serialNumber": 0 }, { "enable": false, "name": "目录(不匹配行前空白)", - "rule": "^(?<=\\s)(?:(?:内容|文章)?简介|文案|前言|序章|楔子|正文(?!完)|终章|后记|尾声|番外|第?\\s{0,4}[\\d零一二两三四五六七八九十百千万壹贰叁肆伍陆柒捌玖拾佰仟]+?\\s{0,4}(?:章|节(?!课)|卷|集(?![合和])|部(?!分)|篇(?!张))).{0,30}$", + "rule": "^(?<= |\\s)(?:(?:内容|文章)?简介|文案|前言|序章|楔子|正文(?!完)|终章|后记|尾声|番外|第?\\s{0,4}[\\d零一二两三四五六七八九十百千万壹贰叁肆伍陆柒捌玖拾佰仟]+?\\s{0,4}(?:章|节(?!课)|卷|集(?![合和])|部(?!分)|篇(?!张))).{0,30}$", "serialNumber": 1 }, { "enable": false, "name": "目录(去简介)", - "rule": "^(?<=\\s)(?:前言|序章|楔子|正文(?!完)|终章|后记|尾声|番外|第?\\s{0,4}[\\d零一二两三四五六七八九十百千万壹贰叁肆伍陆柒捌玖拾佰仟]+?\\s{0,4}(?:章|节(?!课)|卷|集(?![合和])|部(?!分)|篇(?!张))).{0,30}$", + "rule": "^(?<= |\\s)(?:前言|序章|楔子|正文(?!完)|终章|后记|尾声|番外|第?\\s{0,4}[\\d零一二两三四五六七八九十百千万壹贰叁肆伍陆柒捌玖拾佰仟]+?\\s{0,4}(?:章|节(?!课)|卷|集(?![合和])|部(?!分)|回(?![合来事去])|场(?![和合比电是])|篇(?!张))).{0,30}$", "serialNumber": 2 }, { "enable": false, "name": "目录(古典、轻小说备用)", - "rule": "^[ \\t]{0,4}(?:前言|序章|楔子|正文(?!完)|终章|后记|尾声|番外|第?\\s{0,4}[\\d零一二两三四五六七八九十百千万壹贰叁肆伍陆柒捌玖拾佰仟]+?\\s{0,4}(?:章|节(?!课)|卷|集(?![合和])|部(?!分)|回(?![合来事去])|场(?![和合比电是])|篇(?!张))).{0,30}$", + "rule": "^[  \\t]{0,4}(?:前言|序章|楔子|正文(?!完)|终章|后记|尾声|番外|第?\\s{0,4}[\\d零一二两三四五六七八九十百千万壹贰叁肆伍陆柒捌玖拾佰仟]+?\\s{0,4}(?:章|节(?!课)|卷|集(?![合和])|部(?!分)|回(?![合来事去])|场(?![和合比电是])|篇(?!张))).{0,30}$", "serialNumber": 3 }, { "enable": true, "name": "数字 分隔符 标题名称", - "rule": "^[ \\t]{0,4}\\d{1,5}[\\,\\., 、\\-].{1,30}$", + "rule": "^[  \\t]{0,4}\\d{1,5}[\\,\\., 、\\-].{1,30}$", "serialNumber": 4 }, { "enable": true, "name": "正文 标题/序号", - "rule": "^[ \\t]{0,4}正文\\s{1,4}.{0,20}$", + "rule": "^[  \\t]{0,4}正文\\s{1,4}.{0,20}$", "serialNumber": 5 }, { "enable": true, - "name": "Chapter/Section/Part 序号 标题", - "rule": "^[ \\t]{0,4}(?:[Cc]hapter|[Ss]ection|[Pp]art)\\s{0,4}\\d{1,4}.{0,30}$", + "name": "Chapter/Section/Part/Episode 序号 标题", + "rule": "^[  \\t]{0,4}(?:[Cc]hapter|[Ss]ection|[Pp]art|PART|[Ee]pisode)\\s{0,4}\\d{1,4}.{0,30}$", "serialNumber": 6 }, { "enable": true, "name": "特殊符号 序号 标题", - "rule": "^[ \\t]{0,4}[〈〖〔【][第卷][\\d零一二两三四五六七八九十百千万壹贰叁肆伍陆柒捌玖拾佰仟]{1,10}[章节][\\.:: \f\t].{0,30}$", + "rule": "^[  \\t]{0,4}[〈〖〔【][第卷][\\d零一二两三四五六七八九十百千万壹贰叁肆伍陆柒捌玖拾佰仟]{1,10}[章节][\\.:: \f\t].{0,30}$", "serialNumber": 7 }, { "enable": true, "name": "特殊符号 标题", - "rule": "^[ \\t]{0,4}[\\[〈「『〖〔《(【\\(☆★].{1,30}[\\)】)》〕〗』」〉\\]]?\\s{0,4}$", + "rule": "^[  \\t]{0,4}[\\[〈「『〖〔《(【\\(☆★].{1,30}[\\)】)》〕〗』」〉\\]]?\\s{0,4}$", "serialNumber": 8 }, { "enable":false, "name": "特殊符号 标题(不匹配空白字符)", - "rule": "^(?<=\\s)[\\[〈「『〖〔《(【\\(☆★].{1,30}[\\)】)》〕〗』」〉\\]]?\\s{0,4}$", + "rule": "^(?<= |\\s)[\\[〈「『〖〔《(【\\(☆★].{1,30}[\\)】)》〕〗』」〉\\]]?\\s{0,4}$", "serialNumber": 9 }, + { + "enable": true, + "name": "章/卷 序号 标题", + "rule": "^[  \\t]{0,4}(?:(?:内容|文章)?简介|文案|前言|序章|楔子|正文(?!完)|终章|后记|尾声|番外|[卷章][\\d零一二两三四五六七八九十百千万壹贰叁肆伍陆柒捌玖拾佰仟]{1,8})\\s{0,4}.{0,30}$", + "serialNumber": 10 + }, { "enable":false, "name": "顶格标题", "rule": "^\\S.{1,20}$", - "serialNumber": 10 + "serialNumber": 11 } ] diff --git a/app/src/main/assets/updateLog.md b/app/src/main/assets/updateLog.md index b78537486..311f51c87 100644 --- a/app/src/main/assets/updateLog.md +++ b/app/src/main/assets/updateLog.md @@ -2,10 +2,27 @@ * 旧版数据导入教程:先在旧版阅读(2.x)中进行备份,然后在新版阅读(3.x)【我的】->【备份与恢复】,选择【导入旧版本数据】。 * 请关注[开源阅读软件]()支持我,同时关注合作公众号[小说拾遗](),阅读公众号小编。 +**2020/03/05** +* 修复翻页动画 +* 修复主题模式跟随 +* 修复滚动翻页切换章节时跳动 + +**2020/03/04** +* 修复仿真翻页动画 +* 添加阅读记录同步,正常退出进入软件时同步阅读记录 + +**2020/03/03** +* 修复bug +* 优化排版,确保段距为0时每行在相同的位置 +* 修复底部遮挡 + **2020/03/02** * 添加书源登录 * 替换规则实时生效 * 页面最后一行计算是否能放下时不计算行距 +* 优化翻页动画 +* 优化书源校验 +* 按键翻页有动画了 **2020/03/01** * 修复书源解析的一个bug diff --git a/app/src/main/java/io/legado/app/App.kt b/app/src/main/java/io/legado/app/App.kt index 95f29cd64..d1a3e9464 100644 --- a/app/src/main/java/io/legado/app/App.kt +++ b/app/src/main/java/io/legado/app/App.kt @@ -48,13 +48,9 @@ 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() - - LiveEventBus.get() + applyDayNight() + LiveEventBus .config() .supportBroadcast(this) .lifecycleObserverAlwaysActive(true) diff --git a/app/src/main/java/io/legado/app/base/BaseDialogFragment.kt b/app/src/main/java/io/legado/app/base/BaseDialogFragment.kt index e893e34c4..84e9d4b0b 100644 --- a/app/src/main/java/io/legado/app/base/BaseDialogFragment.kt +++ b/app/src/main/java/io/legado/app/base/BaseDialogFragment.kt @@ -1,6 +1,7 @@ package io.legado.app.base import android.os.Bundle +import android.view.View import androidx.fragment.app.DialogFragment import io.legado.app.help.coroutine.Coroutine import kotlinx.coroutines.CoroutineScope @@ -18,6 +19,14 @@ abstract class BaseDialogFragment : DialogFragment(), CoroutineScope { job = Job() } + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + onFragmentCreated(view, savedInstanceState) + observeLiveBus() + } + + abstract fun onFragmentCreated(view: View, savedInstanceState: Bundle?) + override fun onDestroy() { super.onDestroy() job.cancel() @@ -30,4 +39,7 @@ abstract class BaseDialogFragment : DialogFragment(), CoroutineScope { ): Coroutine { return Coroutine.async(scope, context) { block() } } + + open fun observeLiveBus() { + } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/base/BaseFragment.kt b/app/src/main/java/io/legado/app/base/BaseFragment.kt index c4b712349..c19033aa8 100644 --- a/app/src/main/java/io/legado/app/base/BaseFragment.kt +++ b/app/src/main/java/io/legado/app/base/BaseFragment.kt @@ -1,5 +1,6 @@ package io.legado.app.base +import android.annotation.SuppressLint import android.os.Bundle import android.view.* import androidx.appcompat.view.SupportMenuInflater @@ -18,6 +19,7 @@ abstract class BaseFragment(layoutID: Int) : Fragment(layoutID), private set val menuInflater: MenuInflater + @SuppressLint("RestrictedApi") get() = SupportMenuInflater(requireContext()) override val coroutineContext: CoroutineContext diff --git a/app/src/main/java/io/legado/app/constant/Pattern.kt b/app/src/main/java/io/legado/app/constant/AppPattern.kt similarity index 76% rename from app/src/main/java/io/legado/app/constant/Pattern.kt rename to app/src/main/java/io/legado/app/constant/AppPattern.kt index fd623bf69..396edb73d 100644 --- a/app/src/main/java/io/legado/app/constant/Pattern.kt +++ b/app/src/main/java/io/legado/app/constant/AppPattern.kt @@ -2,7 +2,9 @@ package io.legado.app.constant import java.util.regex.Pattern -object Pattern { +object AppPattern { val JS_PATTERN: Pattern = Pattern.compile("([\\w\\W]*?|@js:[\\w\\W]*$)", Pattern.CASE_INSENSITIVE) val EXP_PATTERN: Pattern = Pattern.compile("\\{\\{([\\w\\W]*?)\\}\\}") + + val authorRegex = "作\\s*者\\s*[::]".toRegex() } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/constant/EventBus.kt b/app/src/main/java/io/legado/app/constant/EventBus.kt index 402827cb4..88031b4fc 100644 --- a/app/src/main/java/io/legado/app/constant/EventBus.kt +++ b/app/src/main/java/io/legado/app/constant/EventBus.kt @@ -20,6 +20,5 @@ object EventBus { const val SHOW_RSS = "showRss" const val WEB_SERVICE_STOP = "webServiceStop" const val UP_DOWNLOAD = "upDownload" - const val UP_TABS = "upTabs" const val SAVE_CONTENT = "saveContent" } \ No newline at end of file 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/constant/RSSKeywords.kt b/app/src/main/java/io/legado/app/constant/RSSKeywords.kt deleted file mode 100644 index 686842950..000000000 --- a/app/src/main/java/io/legado/app/constant/RSSKeywords.kt +++ /dev/null @@ -1,17 +0,0 @@ -package io.legado.app.constant - -object RSSKeywords { - - const val RSS_ITEM = "item" - const val RSS_ITEM_TITLE = "title" - const val RSS_ITEM_LINK = "link" - const val RSS_ITEM_CATEGORY = "category" - const val RSS_ITEM_THUMBNAIL = "media:thumbnail" - const val RSS_ITEM_ENCLOSURE = "enclosure" - const val RSS_ITEM_DESCRIPTION = "description" - const val RSS_ITEM_CONTENT = "content:encoded" - const val RSS_ITEM_PUB_DATE = "pubDate" - const val RSS_ITEM_TIME = "time" - const val RSS_ITEM_URL = "url" - const val RSS_ITEM_TYPE = "type" -} \ No newline at end of file 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/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/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/data/entities/Book.kt b/app/src/main/java/io/legado/app/data/entities/Book.kt index d29ce696e..833561f1b 100644 --- a/app/src/main/java/io/legado/app/data/entities/Book.kt +++ b/app/src/main/java/io/legado/app/data/entities/Book.kt @@ -5,6 +5,7 @@ import androidx.room.Entity import androidx.room.Ignore import androidx.room.Index import androidx.room.PrimaryKey +import io.legado.app.constant.AppPattern import io.legado.app.constant.BookType import io.legado.app.utils.GSON import io.legado.app.utils.fromJsonObject @@ -86,7 +87,7 @@ data class Book( @IgnoredOnParcel override var tocHtml: String? = null - fun getRealAuthor() = author.replace("作者:", "") + fun getRealAuthor() = author.replace(AppPattern.authorRegex, "") fun getUnreadChapterNum() = max(totalChapterNum - durChapterIndex - 1, 0) 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/BookHelp.kt b/app/src/main/java/io/legado/app/help/BookHelp.kt index 7df2540c5..304df9997 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 @@ -177,7 +180,7 @@ object BookHelp { fun formatAuthor(author: String?): String { return author - ?.replace("作\\s*者[\\s::]*".toRegex(), "") + ?.replace("作\\s*者\\s*[::]\n*".toRegex(), "") ?.replace("\\s+".toRegex(), " ") ?.trim { it <= ' ' } ?: "" @@ -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 a3a6de521..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 = @@ -27,6 +29,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 +71,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() { @@ -228,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",//夜间背景 @@ -239,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/ImportOldData.kt b/app/src/main/java/io/legado/app/help/storage/ImportOldData.kt index 9087c3e9f..8d0c9cd2c 100644 --- a/app/src/main/java/io/legado/app/help/storage/ImportOldData.kt +++ b/app/src/main/java/io/legado/app/help/storage/ImportOldData.kt @@ -36,7 +36,7 @@ object ImportOldData { try {// Book source val sourceFile = - FileUtils.createFileIfNotExist(file, "myBookSource.json") + FileUtils.getFile(file, "myBookSource.json") val json = sourceFile.readText() val importCount = importOldSource(json) withContext(Dispatchers.Main) { @@ -49,12 +49,17 @@ object ImportOldData { } try {// Replace rules - val ruleFile = - FileUtils.createFileIfNotExist(file, "myBookReplaceRule.json") - val json = ruleFile.readText() - val importCount = importOldReplaceRule(json) - withContext(Dispatchers.Main) { - context.toast("成功导入替换规则${importCount}") + val ruleFile = FileUtils.getFile(file, "myBookReplaceRule.json") + if (ruleFile.exists()) { + val json = ruleFile.readText() + val importCount = importOldReplaceRule(json) + withContext(Dispatchers.Main) { + context.toast("成功导入替换规则${importCount}") + } + } else { + withContext(Dispatchers.Main) { + context.toast("未找到替换规则") + } } } catch (e: Exception) { withContext(Dispatchers.Main) { 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..5393249c3 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 @@ -2,20 +2,25 @@ package io.legado.app.help.storage import android.content.Context import android.net.Uri +import androidx.appcompat.app.AppCompatDelegate import androidx.documentfile.provider.DocumentFile import com.jayway.jsonpath.Configuration 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.EventBus import io.legado.app.constant.PreferKey import io.legado.app.data.entities.* +import io.legado.app.help.AppConfig import io.legado.app.help.LauncherIconHelp import io.legado.app.help.ReadBookConfig 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 +65,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 +89,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 +130,18 @@ object Restore { ChapterProvider.upStyle() ReadBook.loadContent() } - LauncherIconHelp.changeIcon(App.INSTANCE.getPrefString(PreferKey.launcherIcon)) + withContext(Main) { + if (AppConfig.isNightTheme && AppCompatDelegate.getDefaultNightMode() != AppCompatDelegate.MODE_NIGHT_YES) { + App.INSTANCE.applyDayNight() + } else if (!AppConfig.isNightTheme && AppCompatDelegate.getDefaultNightMode() == AppCompatDelegate.MODE_NIGHT_YES) { + App.INSTANCE.applyDayNight() + } else { + postEvent(EventBus.RECREATE, "true") + } + 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/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..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 @@ -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,17 @@ 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.restoreDatabase() + Restore.restoreConfig() + } } }.onSuccess { success.invoke() @@ -102,10 +113,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/analyzeRule/AnalyzeByJSonPath.kt b/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeByJSonPath.kt index e7360da7e..1cc90b89e 100644 --- a/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeByJSonPath.kt +++ b/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeByJSonPath.kt @@ -1,12 +1,14 @@ package io.legado.app.model.analyzeRule import android.text.TextUtils +import androidx.annotation.Keep import com.jayway.jsonpath.JsonPath import com.jayway.jsonpath.ReadContext import io.legado.app.utils.splitNotBlank import java.util.* import java.util.regex.Pattern +@Keep class AnalyzeByJSonPath { private var ctx: ReadContext? = null diff --git a/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeByJSoup.kt b/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeByJSoup.kt index 38fb633c5..7e49ac677 100644 --- a/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeByJSoup.kt +++ b/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeByJSoup.kt @@ -2,6 +2,7 @@ package io.legado.app.model.analyzeRule import android.text.TextUtils.isEmpty import android.text.TextUtils.join +import androidx.annotation.Keep import io.legado.app.utils.splitNotBlank import org.jsoup.Jsoup import org.jsoup.nodes.Element @@ -15,7 +16,7 @@ import java.util.* * Created by GKF on 2018/1/25. * 书源规则解析 */ - +@Keep class AnalyzeByJSoup { private var element: Element? = null diff --git a/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeByRegex.kt b/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeByRegex.kt index 5475df744..05851b423 100644 --- a/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeByRegex.kt +++ b/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeByRegex.kt @@ -1,8 +1,10 @@ package io.legado.app.model.analyzeRule +import androidx.annotation.Keep import java.util.* import java.util.regex.Pattern +@Keep object AnalyzeByRegex { fun getElement(res: String, regs: Array, index: Int = 0): List? { diff --git a/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeByXPath.kt b/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeByXPath.kt index 707ab9a22..52f3b7560 100644 --- a/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeByXPath.kt +++ b/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeByXPath.kt @@ -1,6 +1,7 @@ package io.legado.app.model.analyzeRule import android.text.TextUtils +import androidx.annotation.Keep import io.legado.app.utils.splitNotBlank import org.jsoup.nodes.Document import org.jsoup.nodes.Element @@ -9,6 +10,7 @@ import org.seimicrawler.xpath.JXDocument import org.seimicrawler.xpath.JXNode import java.util.* +@Keep class AnalyzeByXPath { private var jxDocument: JXDocument? = null private var jxNode: JXNode? = null diff --git a/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeRule.kt b/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeRule.kt index f88a5ee85..9b1e7d3b0 100644 --- a/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeRule.kt +++ b/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeRule.kt @@ -3,7 +3,7 @@ package io.legado.app.model.analyzeRule import android.text.TextUtils import androidx.annotation.Keep import io.legado.app.constant.AppConst.SCRIPT_ENGINE -import io.legado.app.constant.Pattern.JS_PATTERN +import io.legado.app.constant.AppPattern.JS_PATTERN import io.legado.app.data.entities.BaseBook import io.legado.app.data.entities.BookChapter import io.legado.app.help.JsExtensions diff --git a/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeUrl.kt b/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeUrl.kt index 9ac402267..7b1488c96 100644 --- a/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeUrl.kt +++ b/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeUrl.kt @@ -4,8 +4,8 @@ import android.annotation.SuppressLint import android.text.TextUtils import androidx.annotation.Keep import io.legado.app.constant.AppConst.SCRIPT_ENGINE -import io.legado.app.constant.Pattern.EXP_PATTERN -import io.legado.app.constant.Pattern.JS_PATTERN +import io.legado.app.constant.AppPattern.EXP_PATTERN +import io.legado.app.constant.AppPattern.JS_PATTERN import io.legado.app.data.entities.BaseBook import io.legado.app.help.JsExtensions import io.legado.app.help.http.* diff --git a/app/src/main/java/io/legado/app/model/localBook/AnalyzeTxtFile.kt b/app/src/main/java/io/legado/app/model/localBook/AnalyzeTxtFile.kt index fad747b34..16426a036 100644 --- a/app/src/main/java/io/legado/app/model/localBook/AnalyzeTxtFile.kt +++ b/app/src/main/java/io/legado/app/model/localBook/AnalyzeTxtFile.kt @@ -20,7 +20,7 @@ object AnalyzeTxtFile { private const val BUFFER_SIZE = 512 * 1024 //没有标题的时候,每个章节的最大长度 private const val MAX_LENGTH_WITH_NO_CHAPTER = 10 * 1024 - private val cacheFolder: File by lazy { + val cacheFolder: File by lazy { val rootFile = App.INSTANCE.getExternalFilesDir(null) ?: App.INSTANCE.externalCacheDir ?: App.INSTANCE.cacheDir 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 44ee337b2..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 @@ -1,8 +1,10 @@ package io.legado.app.model.localBook +import android.net.Uri import androidx.documentfile.provider.DocumentFile import io.legado.app.App import io.legado.app.data.entities.Book +import io.legado.app.utils.FileUtils object LocalBook { @@ -27,4 +29,17 @@ object LocalBook { } } + fun deleteBook(book: Book, deleteOriginal: Boolean) { + 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() + } + } + } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/model/rss/RssParser.kt b/app/src/main/java/io/legado/app/model/rss/RssParser.kt index 816a3858f..7bda16e6d 100644 --- a/app/src/main/java/io/legado/app/model/rss/RssParser.kt +++ b/app/src/main/java/io/legado/app/model/rss/RssParser.kt @@ -1,6 +1,5 @@ package io.legado.app.model.rss -import io.legado.app.constant.RSSKeywords import io.legado.app.data.entities.RssArticle import io.legado.app.model.Debug import org.xmlpull.v1.XmlPullParser @@ -34,26 +33,26 @@ object RssParser { // Start parsing the item if (eventType == XmlPullParser.START_TAG) { when { - xmlPullParser.name.equals(RSSKeywords.RSS_ITEM, true) -> + xmlPullParser.name.equals(RSS_ITEM, true) -> insideItem = true - xmlPullParser.name.equals(RSSKeywords.RSS_ITEM_TITLE, true) -> + xmlPullParser.name.equals(RSS_ITEM_TITLE, true) -> if (insideItem) currentArticle.title = xmlPullParser.nextText().trim() - xmlPullParser.name.equals(RSSKeywords.RSS_ITEM_LINK, true) -> + xmlPullParser.name.equals(RSS_ITEM_LINK, true) -> if (insideItem) currentArticle.link = xmlPullParser.nextText().trim() - xmlPullParser.name.equals(RSSKeywords.RSS_ITEM_THUMBNAIL, true) -> + xmlPullParser.name.equals(RSS_ITEM_THUMBNAIL, true) -> if (insideItem) currentArticle.image = - xmlPullParser.getAttributeValue(null, RSSKeywords.RSS_ITEM_URL) - xmlPullParser.name.equals(RSSKeywords.RSS_ITEM_ENCLOSURE, true) -> + xmlPullParser.getAttributeValue(null, RSS_ITEM_URL) + xmlPullParser.name.equals(RSS_ITEM_ENCLOSURE, true) -> if (insideItem) { val type = - xmlPullParser.getAttributeValue(null, RSSKeywords.RSS_ITEM_TYPE) + xmlPullParser.getAttributeValue(null, RSS_ITEM_TYPE) if (type != null && type.contains("image/")) { currentArticle.image = - xmlPullParser.getAttributeValue(null, RSSKeywords.RSS_ITEM_URL) + xmlPullParser.getAttributeValue(null, RSS_ITEM_URL) } } xmlPullParser.name - .equals(RSSKeywords.RSS_ITEM_DESCRIPTION, true) -> + .equals(RSS_ITEM_DESCRIPTION, true) -> if (insideItem) { val description = xmlPullParser.nextText() currentArticle.description = description.trim() @@ -61,7 +60,7 @@ object RssParser { currentArticle.image = getImageUrl(description) } } - xmlPullParser.name.equals(RSSKeywords.RSS_ITEM_CONTENT, true) -> + xmlPullParser.name.equals(RSS_ITEM_CONTENT, true) -> if (insideItem) { val content = xmlPullParser.nextText().trim() currentArticle.content = content @@ -70,7 +69,7 @@ object RssParser { } } xmlPullParser.name - .equals(RSSKeywords.RSS_ITEM_PUB_DATE, true) -> + .equals(RSS_ITEM_PUB_DATE, true) -> if (insideItem) { val nextTokenType = xmlPullParser.next() if (nextTokenType == XmlPullParser.TEXT) { @@ -79,7 +78,7 @@ object RssParser { // Skip to be able to find date inside 'tag' tag continue@loop } - xmlPullParser.name.equals(RSSKeywords.RSS_ITEM_TIME, true) -> + xmlPullParser.name.equals(RSS_ITEM_TIME, true) -> if (insideItem) currentArticle.pubDate = xmlPullParser.nextText() } } else if (eventType == XmlPullParser.END_TAG @@ -129,4 +128,17 @@ object RssParser { } return url } + + private const val RSS_ITEM = "item" + private const val RSS_ITEM_TITLE = "title" + private const val RSS_ITEM_LINK = "link" + private const val RSS_ITEM_CATEGORY = "category" + private const val RSS_ITEM_THUMBNAIL = "media:thumbnail" + private const val RSS_ITEM_ENCLOSURE = "enclosure" + private const val RSS_ITEM_DESCRIPTION = "description" + private const val RSS_ITEM_CONTENT = "content:encoded" + private const val RSS_ITEM_PUB_DATE = "pubDate" + private const val RSS_ITEM_TIME = "time" + private const val RSS_ITEM_URL = "url" + private const val RSS_ITEM_TYPE = "type" } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/model/rss/RssParserByRule.kt b/app/src/main/java/io/legado/app/model/rss/RssParserByRule.kt index a9c193545..b06950031 100644 --- a/app/src/main/java/io/legado/app/model/rss/RssParserByRule.kt +++ b/app/src/main/java/io/legado/app/model/rss/RssParserByRule.kt @@ -1,5 +1,6 @@ package io.legado.app.model.rss +import androidx.annotation.Keep import io.legado.app.App import io.legado.app.R import io.legado.app.data.entities.RssArticle @@ -8,6 +9,7 @@ import io.legado.app.model.Debug import io.legado.app.model.analyzeRule.AnalyzeRule import io.legado.app.utils.NetworkUtils +@Keep object RssParserByRule { @Throws(Exception::class) diff --git a/app/src/main/java/io/legado/app/model/webBook/BookInfo.kt b/app/src/main/java/io/legado/app/model/webBook/BookInfo.kt index 3e25fc9c3..70c1a92be 100644 --- a/app/src/main/java/io/legado/app/model/webBook/BookInfo.kt +++ b/app/src/main/java/io/legado/app/model/webBook/BookInfo.kt @@ -2,6 +2,7 @@ package io.legado.app.model.webBook import io.legado.app.App import io.legado.app.R +import io.legado.app.constant.AppPattern import io.legado.app.data.entities.Book import io.legado.app.data.entities.BookSource import io.legado.app.model.Debug @@ -38,7 +39,7 @@ object BookInfo { Debug.log(bookSource.bookSourceUrl, "└${book.name}") Debug.log(bookSource.bookSourceUrl, "┌获取作者") analyzeRule.getString(infoRule.author).let { - if (it.isNotEmpty()) book.author = it + if (it.isNotEmpty()) book.author = it.replace(AppPattern.authorRegex, "") } Debug.log(bookSource.bookSourceUrl, "└${book.author}") Debug.log(bookSource.bookSourceUrl, "┌获取分类") diff --git a/app/src/main/java/io/legado/app/service/BaseReadAloudService.kt b/app/src/main/java/io/legado/app/service/BaseReadAloudService.kt index e1e3f8620..3ad351ca7 100644 --- a/app/src/main/java/io/legado/app/service/BaseReadAloudService.kt +++ b/app/src/main/java/io/legado/app/service/BaseReadAloudService.kt @@ -124,16 +124,16 @@ abstract class BaseReadAloudService : BaseService(), open fun play() { pause = false - postEvent(EventBus.ALOUD_STATE, Status.PLAY) upNotification() + postEvent(EventBus.ALOUD_STATE, Status.PLAY) } @CallSuper open fun pauseReadAloud(pause: Boolean) { - postEvent(EventBus.ALOUD_STATE, Status.PAUSE) BaseReadAloudService.pause = pause upNotification() upMediaSessionPlaybackState(PlaybackStateCompat.STATE_PAUSED) + postEvent(EventBus.ALOUD_STATE, Status.PAUSE) } @CallSuper diff --git a/app/src/main/java/io/legado/app/service/CheckSourceService.kt b/app/src/main/java/io/legado/app/service/CheckSourceService.kt index d94b3a6d1..336dfb18d 100644 --- a/app/src/main/java/io/legado/app/service/CheckSourceService.kt +++ b/app/src/main/java/io/legado/app/service/CheckSourceService.kt @@ -18,11 +18,12 @@ import org.jetbrains.anko.toast import java.util.concurrent.Executors class CheckSourceService : BaseService() { - private var searchPool = - Executors.newFixedThreadPool(AppConfig.threadCount).asCoroutineDispatcher() + private val threadCount = AppConfig.threadCount + private var searchPool = Executors.newFixedThreadPool(threadCount).asCoroutineDispatcher() private var task: Coroutine<*>? = null - private val allIds = LinkedHashSet() - private val checkedIds = LinkedHashSet() + private val allIds = ArrayList() + private val checkedIds = ArrayList() + private var processIndex = 0 override fun onCreate() { super.onCreate() @@ -50,30 +51,44 @@ class CheckSourceService : BaseService() { allIds.clear() checkedIds.clear() allIds.addAll(ids) + processIndex = 0 updateNotification(0, getString(R.string.progress_show, 0, allIds.size)) - task = execute(context = searchPool) { - allIds.forEach { sourceUrl -> - App.db.bookSourceDao().getBookSource(sourceUrl)?.let { source -> - val webBook = WebBook(source) - webBook.searchBook("我的", scope = this, context = searchPool) - .onError(IO) { - source.addGroup("失效") - App.db.bookSourceDao().update(source) - }.onFinally { - checkedIds.add(sourceUrl) - updateNotification( - checkedIds.size, - getString(R.string.progress_show, checkedIds.size, allIds.size) - ) - } - } + task = execute { + for (i in 0 until threadCount) { + check() } }.onError { toast("校验书源出错:${it.localizedMessage}") } + } + - task?.invokeOnCompletion { - stopSelf() + private fun check() { + synchronized(this) { + processIndex++ + } + if (processIndex < allIds.size) { + val sourceUrl = allIds[processIndex] + App.db.bookSourceDao().getBookSource(sourceUrl)?.let { source -> + val webBook = WebBook(source) + webBook.searchBook("我的", scope = this, context = searchPool) + .onError(IO) { + source.addGroup("失效") + App.db.bookSourceDao().update(source) + }.onFinally(IO) { + check() + checkedIds.add(sourceUrl) + updateNotification( + checkedIds.size, + getString(R.string.progress_show, checkedIds.size, allIds.size) + ) + synchronized(this) { + if (processIndex >= allIds.size + threadCount - 1) { + stopSelf() + } + } + } + } } } diff --git a/app/src/main/java/io/legado/app/service/HttpReadAloudService.kt b/app/src/main/java/io/legado/app/service/HttpReadAloudService.kt index 9b4b56ebe..7796ffce0 100644 --- a/app/src/main/java/io/legado/app/service/HttpReadAloudService.kt +++ b/app/src/main/java/io/legado/app/service/HttpReadAloudService.kt @@ -13,7 +13,6 @@ import io.legado.app.utils.FileUtils import io.legado.app.utils.LogUtils import io.legado.app.utils.postEvent import kotlinx.coroutines.isActive -import org.jetbrains.anko.toast import java.io.File import java.io.FileDescriptor import java.io.FileInputStream @@ -84,8 +83,6 @@ class HttpReadAloudService : BaseReadAloudService(), break } } - }.onError { - toast("下载朗读文件出错:${it.localizedMessage}") } } 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/README.md b/app/src/main/java/io/legado/app/ui/README.md index a8bf2b216..b408eb6b9 100644 --- a/app/src/main/java/io/legado/app/ui/README.md +++ b/app/src/main/java/io/legado/app/ui/README.md @@ -7,14 +7,14 @@ * book\read 书籍阅读界面 * book\search 搜索书籍界面 * book\source 搜索书源界面 -* changeCover 封面换源界面 -* changeSource 换源界面 -* chapterList 目录界面 -* config 配置界面 -* download 下载界面 -* explore 发现界面 +* book\changeCover 封面换源界面 +* book\changeSource 换源界面 +* book\chapterList 目录界面 +* book\download 下载界面 +* book\explore 发现界面 +* book\local 书籍导入界面 * fileChooser 文件选择界面 -* importBook 书籍导入界面 +* config 配置界面 * main 主界面 * qrCode 二维码扫描界面 * replaceRule 替换净化界面 diff --git a/app/src/main/java/io/legado/app/ui/audio/AudioPlayActivity.kt b/app/src/main/java/io/legado/app/ui/audio/AudioPlayActivity.kt index dffd6a50f..502e49986 100644 --- a/app/src/main/java/io/legado/app/ui/audio/AudioPlayActivity.kt +++ b/app/src/main/java/io/legado/app/ui/audio/AudioPlayActivity.kt @@ -25,8 +25,8 @@ import io.legado.app.lib.dialogs.noButton import io.legado.app.lib.dialogs.okButton import io.legado.app.service.AudioPlayService import io.legado.app.service.help.AudioPlay -import io.legado.app.ui.changesource.ChangeSourceDialog -import io.legado.app.ui.chapterlist.ChapterListActivity +import io.legado.app.ui.book.changesource.ChangeSourceDialog +import io.legado.app.ui.book.chapterlist.ChapterListActivity import io.legado.app.utils.* import kotlinx.android.synthetic.main.activity_audio_play.* import org.apache.commons.lang3.time.DateFormatUtils @@ -46,8 +46,9 @@ class AudioPlayActivity : private var adjustProgress = false override fun onActivityCreated(savedInstanceState: Bundle?) { - title_bar.background.alpha = 0 - AudioPlay.titleData.observe(this, Observer { title_bar.title = it }) + setSupportActionBar(toolbar) + supportActionBar?.setDisplayHomeAsUpEnabled(true) + AudioPlay.titleData.observe(this, Observer { toolbar.title = it }) AudioPlay.coverData.observe(this, Observer { upCover(it) }) viewModel.initData(intent) initView() diff --git a/app/src/main/java/io/legado/app/ui/changecover/ChangeCoverDialog.kt b/app/src/main/java/io/legado/app/ui/book/changecover/ChangeCoverDialog.kt similarity index 86% rename from app/src/main/java/io/legado/app/ui/changecover/ChangeCoverDialog.kt rename to app/src/main/java/io/legado/app/ui/book/changecover/ChangeCoverDialog.kt index d1c081f76..fdc64fa5f 100644 --- a/app/src/main/java/io/legado/app/ui/changecover/ChangeCoverDialog.kt +++ b/app/src/main/java/io/legado/app/ui/book/changecover/ChangeCoverDialog.kt @@ -1,4 +1,4 @@ -package io.legado.app.ui.changecover +package io.legado.app.ui.book.changecover import android.os.Bundle import android.util.DisplayMetrics @@ -52,27 +52,22 @@ class ChangeCoverDialog : DialogFragment(), callBack = activity as? CallBack viewModel = getViewModel(ChangeCoverViewModel::class.java) viewModel.callBack = this - return inflater.inflate(R.layout.dialog_change_source, container) + return inflater.inflate(R.layout.dialog_change_cover, container) } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - viewModel.searchStateData.observe(this, Observer { + viewModel.searchStateData.observe(viewLifecycleOwner, Observer { refresh_progress_bar.isAutoLoading = it }) tool_bar.setTitle(R.string.change_cover_source) arguments?.let { bundle -> - bundle.getString("name")?.let { - viewModel.name = it - } - bundle.getString("author")?.let { - viewModel.author = it - } + viewModel.initData(bundle) } recycler_view.layoutManager = GridLayoutManager(requireContext(), 3) adapter = CoverAdapter(requireContext(), this) recycler_view.adapter = adapter - viewModel.initData() + viewModel.loadDbSearchBook() } override fun changeTo(coverUrl: String) { diff --git a/app/src/main/java/io/legado/app/ui/changecover/ChangeCoverViewModel.kt b/app/src/main/java/io/legado/app/ui/book/changecover/ChangeCoverViewModel.kt similarity index 87% rename from app/src/main/java/io/legado/app/ui/changecover/ChangeCoverViewModel.kt rename to app/src/main/java/io/legado/app/ui/book/changecover/ChangeCoverViewModel.kt index d8ed01d9f..0316c4fc9 100644 --- a/app/src/main/java/io/legado/app/ui/changecover/ChangeCoverViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/book/changecover/ChangeCoverViewModel.kt @@ -1,9 +1,11 @@ -package io.legado.app.ui.changecover +package io.legado.app.ui.book.changecover import android.app.Application +import android.os.Bundle import androidx.lifecycle.MutableLiveData import io.legado.app.App import io.legado.app.base.BaseViewModel +import io.legado.app.constant.AppPattern import io.legado.app.help.AppConfig import io.legado.app.help.coroutine.Coroutine import io.legado.app.model.WebBook @@ -21,7 +23,16 @@ class ChangeCoverViewModel(application: Application) : BaseViewModel(application private var task: Coroutine<*>? = null val searchStateData = MutableLiveData() - fun initData() { + fun initData(bundle: Bundle) { + bundle.getString("name")?.let { + name = it + } + bundle.getString("author")?.let { + author = it.replace(AppPattern.authorRegex, "") + } + } + + fun loadDbSearchBook() { execute { App.db.searchBookDao().getEnableHasCover(name, author) }.onSuccess { diff --git a/app/src/main/java/io/legado/app/ui/changecover/CoverAdapter.kt b/app/src/main/java/io/legado/app/ui/book/changecover/CoverAdapter.kt similarity index 96% rename from app/src/main/java/io/legado/app/ui/changecover/CoverAdapter.kt rename to app/src/main/java/io/legado/app/ui/book/changecover/CoverAdapter.kt index eae791b2c..55a841fcd 100644 --- a/app/src/main/java/io/legado/app/ui/changecover/CoverAdapter.kt +++ b/app/src/main/java/io/legado/app/ui/book/changecover/CoverAdapter.kt @@ -1,4 +1,4 @@ -package io.legado.app.ui.changecover +package io.legado.app.ui.book.changecover import android.content.Context import io.legado.app.R diff --git a/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceAdapter.kt b/app/src/main/java/io/legado/app/ui/book/changesource/ChangeSourceAdapter.kt similarity index 97% rename from app/src/main/java/io/legado/app/ui/changesource/ChangeSourceAdapter.kt rename to app/src/main/java/io/legado/app/ui/book/changesource/ChangeSourceAdapter.kt index 1fa9284c1..132858e0f 100644 --- a/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceAdapter.kt +++ b/app/src/main/java/io/legado/app/ui/book/changesource/ChangeSourceAdapter.kt @@ -1,4 +1,4 @@ -package io.legado.app.ui.changesource +package io.legado.app.ui.book.changesource import android.content.Context import android.os.Bundle diff --git a/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceDialog.kt b/app/src/main/java/io/legado/app/ui/book/changesource/ChangeSourceDialog.kt similarity index 95% rename from app/src/main/java/io/legado/app/ui/changesource/ChangeSourceDialog.kt rename to app/src/main/java/io/legado/app/ui/book/changesource/ChangeSourceDialog.kt index d1ce27f2e..5188e38ce 100644 --- a/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceDialog.kt +++ b/app/src/main/java/io/legado/app/ui/book/changesource/ChangeSourceDialog.kt @@ -1,4 +1,4 @@ -package io.legado.app.ui.changesource +package io.legado.app.ui.book.changesource import android.os.Bundle import android.util.DisplayMetrics @@ -16,9 +16,11 @@ import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView import io.legado.app.R import io.legado.app.constant.PreferKey +import io.legado.app.constant.Theme import io.legado.app.data.entities.Book import io.legado.app.data.entities.SearchBook import io.legado.app.ui.widget.recycler.VerticalDivider +import io.legado.app.utils.applyTint import io.legado.app.utils.getPrefBoolean import io.legado.app.utils.getViewModel import io.legado.app.utils.putPrefBoolean @@ -69,10 +71,8 @@ class ChangeSourceDialog : DialogFragment(), super.onViewCreated(view, savedInstanceState) viewModel.initData(arguments) showTitle() - tool_bar.inflateMenu(R.menu.change_source) - tool_bar.setOnMenuItemClickListener(this) - initRecyclerView() initMenu() + initRecyclerView() initSearchView() initLiveData() viewModel.loadDbSearchBook() @@ -85,6 +85,9 @@ class ChangeSourceDialog : DialogFragment(), } private fun initMenu() { + tool_bar.inflateMenu(R.menu.change_source) + tool_bar.menu.applyTint(requireContext(), Theme.getTheme()) + tool_bar.setOnMenuItemClickListener(this) tool_bar.menu.findItem(R.id.menu_load_toc)?.isChecked = getPrefBoolean(PreferKey.changeSourceLoadToc) } @@ -110,7 +113,7 @@ class ChangeSourceDialog : DialogFragment(), } private fun initSearchView() { - val searchView = tool_bar.menu.findItem(R.id.menu_search).actionView as SearchView + val searchView = tool_bar.menu.findItem(R.id.menu_screen).actionView as SearchView searchView.setOnCloseListener { showTitle() false @@ -149,6 +152,7 @@ class ChangeSourceDialog : DialogFragment(), putPrefBoolean(PreferKey.changeSourceLoadToc, !item.isChecked) item.isChecked = !item.isChecked } + R.id.menu_stop -> viewModel.stopSearch() } return false } diff --git a/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceViewModel.kt b/app/src/main/java/io/legado/app/ui/book/changesource/ChangeSourceViewModel.kt similarity index 96% rename from app/src/main/java/io/legado/app/ui/changesource/ChangeSourceViewModel.kt rename to app/src/main/java/io/legado/app/ui/book/changesource/ChangeSourceViewModel.kt index 1a683427f..151577c00 100644 --- a/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/book/changesource/ChangeSourceViewModel.kt @@ -1,4 +1,4 @@ -package io.legado.app.ui.changesource +package io.legado.app.ui.book.changesource import android.app.Application import android.os.Bundle @@ -6,6 +6,7 @@ import androidx.lifecycle.MutableLiveData import io.legado.app.App import io.legado.app.R import io.legado.app.base.BaseViewModel +import io.legado.app.constant.AppPattern import io.legado.app.constant.PreferKey import io.legado.app.data.entities.Book import io.legado.app.data.entities.SearchBook @@ -35,7 +36,7 @@ class ChangeSourceViewModel(application: Application) : BaseViewModel(applicatio name = it } bundle.getString("author")?.let { - author = it + author = it.replace(AppPattern.authorRegex, "") } } } @@ -145,6 +146,10 @@ class ChangeSourceViewModel(application: Application) : BaseViewModel(applicatio } } + fun stopSearch() { + task?.cancel() + } + override fun onCleared() { super.onCleared() searchPool.close() diff --git a/app/src/main/java/io/legado/app/ui/changesource/DiffCallBack.kt b/app/src/main/java/io/legado/app/ui/book/changesource/DiffCallBack.kt similarity index 97% rename from app/src/main/java/io/legado/app/ui/changesource/DiffCallBack.kt rename to app/src/main/java/io/legado/app/ui/book/changesource/DiffCallBack.kt index 91e640ac3..b0a8f19ef 100644 --- a/app/src/main/java/io/legado/app/ui/changesource/DiffCallBack.kt +++ b/app/src/main/java/io/legado/app/ui/book/changesource/DiffCallBack.kt @@ -1,4 +1,4 @@ -package io.legado.app.ui.changesource +package io.legado.app.ui.book.changesource import android.os.Bundle import androidx.recyclerview.widget.DiffUtil diff --git a/app/src/main/java/io/legado/app/ui/chapterlist/BookmarkAdapter.kt b/app/src/main/java/io/legado/app/ui/book/chapterlist/BookmarkAdapter.kt similarity index 98% rename from app/src/main/java/io/legado/app/ui/chapterlist/BookmarkAdapter.kt rename to app/src/main/java/io/legado/app/ui/book/chapterlist/BookmarkAdapter.kt index ea3f41801..05e3751c9 100644 --- a/app/src/main/java/io/legado/app/ui/chapterlist/BookmarkAdapter.kt +++ b/app/src/main/java/io/legado/app/ui/book/chapterlist/BookmarkAdapter.kt @@ -1,4 +1,4 @@ -package io.legado.app.ui.chapterlist +package io.legado.app.ui.book.chapterlist import android.os.AsyncTask.execute import android.view.LayoutInflater diff --git a/app/src/main/java/io/legado/app/ui/chapterlist/BookmarkFragment.kt b/app/src/main/java/io/legado/app/ui/book/chapterlist/BookmarkFragment.kt similarity index 98% rename from app/src/main/java/io/legado/app/ui/chapterlist/BookmarkFragment.kt rename to app/src/main/java/io/legado/app/ui/book/chapterlist/BookmarkFragment.kt index b2337d0d9..6aa36d62e 100644 --- a/app/src/main/java/io/legado/app/ui/chapterlist/BookmarkFragment.kt +++ b/app/src/main/java/io/legado/app/ui/book/chapterlist/BookmarkFragment.kt @@ -1,4 +1,4 @@ -package io.legado.app.ui.chapterlist +package io.legado.app.ui.book.chapterlist import android.app.Activity import android.content.Intent diff --git a/app/src/main/java/io/legado/app/ui/chapterlist/ChapterListActivity.kt b/app/src/main/java/io/legado/app/ui/book/chapterlist/ChapterListActivity.kt similarity index 98% rename from app/src/main/java/io/legado/app/ui/chapterlist/ChapterListActivity.kt rename to app/src/main/java/io/legado/app/ui/book/chapterlist/ChapterListActivity.kt index a0d401a5e..7420fc047 100644 --- a/app/src/main/java/io/legado/app/ui/chapterlist/ChapterListActivity.kt +++ b/app/src/main/java/io/legado/app/ui/book/chapterlist/ChapterListActivity.kt @@ -1,4 +1,4 @@ -package io.legado.app.ui.chapterlist +package io.legado.app.ui.book.chapterlist import android.os.Bundle import android.view.Menu diff --git a/app/src/main/java/io/legado/app/ui/chapterlist/ChapterListAdapter.kt b/app/src/main/java/io/legado/app/ui/book/chapterlist/ChapterListAdapter.kt similarity index 98% rename from app/src/main/java/io/legado/app/ui/chapterlist/ChapterListAdapter.kt rename to app/src/main/java/io/legado/app/ui/book/chapterlist/ChapterListAdapter.kt index 08b222970..b9d20920b 100644 --- a/app/src/main/java/io/legado/app/ui/chapterlist/ChapterListAdapter.kt +++ b/app/src/main/java/io/legado/app/ui/book/chapterlist/ChapterListAdapter.kt @@ -1,4 +1,4 @@ -package io.legado.app.ui.chapterlist +package io.legado.app.ui.book.chapterlist import android.content.Context import android.widget.TextView diff --git a/app/src/main/java/io/legado/app/ui/chapterlist/ChapterListFragment.kt b/app/src/main/java/io/legado/app/ui/book/chapterlist/ChapterListFragment.kt similarity index 99% rename from app/src/main/java/io/legado/app/ui/chapterlist/ChapterListFragment.kt rename to app/src/main/java/io/legado/app/ui/book/chapterlist/ChapterListFragment.kt index 0bfc9a765..9e9b5c813 100644 --- a/app/src/main/java/io/legado/app/ui/chapterlist/ChapterListFragment.kt +++ b/app/src/main/java/io/legado/app/ui/book/chapterlist/ChapterListFragment.kt @@ -1,4 +1,4 @@ -package io.legado.app.ui.chapterlist +package io.legado.app.ui.book.chapterlist import android.app.Activity.RESULT_OK import android.content.Intent diff --git a/app/src/main/java/io/legado/app/ui/chapterlist/ChapterListViewModel.kt b/app/src/main/java/io/legado/app/ui/book/chapterlist/ChapterListViewModel.kt similarity index 94% rename from app/src/main/java/io/legado/app/ui/chapterlist/ChapterListViewModel.kt rename to app/src/main/java/io/legado/app/ui/book/chapterlist/ChapterListViewModel.kt index 4156c4ac9..ad3361fd1 100644 --- a/app/src/main/java/io/legado/app/ui/chapterlist/ChapterListViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/book/chapterlist/ChapterListViewModel.kt @@ -1,4 +1,4 @@ -package io.legado.app.ui.chapterlist +package io.legado.app.ui.book.chapterlist import android.app.Application diff --git a/app/src/main/java/io/legado/app/ui/download/DownloadActivity.kt b/app/src/main/java/io/legado/app/ui/book/download/DownloadActivity.kt similarity index 99% rename from app/src/main/java/io/legado/app/ui/download/DownloadActivity.kt rename to app/src/main/java/io/legado/app/ui/book/download/DownloadActivity.kt index cdcbf9746..f731806a7 100644 --- a/app/src/main/java/io/legado/app/ui/download/DownloadActivity.kt +++ b/app/src/main/java/io/legado/app/ui/book/download/DownloadActivity.kt @@ -1,4 +1,4 @@ -package io.legado.app.ui.download +package io.legado.app.ui.book.download import android.app.Activity import android.content.Intent diff --git a/app/src/main/java/io/legado/app/ui/download/DownloadAdapter.kt b/app/src/main/java/io/legado/app/ui/book/download/DownloadAdapter.kt similarity index 98% rename from app/src/main/java/io/legado/app/ui/download/DownloadAdapter.kt rename to app/src/main/java/io/legado/app/ui/book/download/DownloadAdapter.kt index 57cafc78a..082e5aecc 100644 --- a/app/src/main/java/io/legado/app/ui/download/DownloadAdapter.kt +++ b/app/src/main/java/io/legado/app/ui/book/download/DownloadAdapter.kt @@ -1,4 +1,4 @@ -package io.legado.app.ui.download +package io.legado.app.ui.book.download import android.content.Context import android.widget.ImageView diff --git a/app/src/main/java/io/legado/app/ui/download/DownloadViewModel.kt b/app/src/main/java/io/legado/app/ui/book/download/DownloadViewModel.kt similarity index 98% rename from app/src/main/java/io/legado/app/ui/download/DownloadViewModel.kt rename to app/src/main/java/io/legado/app/ui/book/download/DownloadViewModel.kt index da12d3d53..e5886d100 100644 --- a/app/src/main/java/io/legado/app/ui/download/DownloadViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/book/download/DownloadViewModel.kt @@ -1,4 +1,4 @@ -package io.legado.app.ui.download +package io.legado.app.ui.book.download import android.app.Application import android.net.Uri diff --git a/app/src/main/java/io/legado/app/ui/explore/ExploreShowActivity.kt b/app/src/main/java/io/legado/app/ui/book/explore/ExploreShowActivity.kt similarity index 98% rename from app/src/main/java/io/legado/app/ui/explore/ExploreShowActivity.kt rename to app/src/main/java/io/legado/app/ui/book/explore/ExploreShowActivity.kt index 08a96a340..04bf86188 100644 --- a/app/src/main/java/io/legado/app/ui/explore/ExploreShowActivity.kt +++ b/app/src/main/java/io/legado/app/ui/book/explore/ExploreShowActivity.kt @@ -1,4 +1,4 @@ -package io.legado.app.ui.explore +package io.legado.app.ui.book.explore import android.os.Bundle import androidx.lifecycle.Observer diff --git a/app/src/main/java/io/legado/app/ui/explore/ExploreShowAdapter.kt b/app/src/main/java/io/legado/app/ui/book/explore/ExploreShowAdapter.kt similarity index 97% rename from app/src/main/java/io/legado/app/ui/explore/ExploreShowAdapter.kt rename to app/src/main/java/io/legado/app/ui/book/explore/ExploreShowAdapter.kt index 2204dae03..322e4a7a3 100644 --- a/app/src/main/java/io/legado/app/ui/explore/ExploreShowAdapter.kt +++ b/app/src/main/java/io/legado/app/ui/book/explore/ExploreShowAdapter.kt @@ -1,4 +1,4 @@ -package io.legado.app.ui.explore +package io.legado.app.ui.book.explore import android.content.Context import io.legado.app.R diff --git a/app/src/main/java/io/legado/app/ui/explore/ExploreShowViewModel.kt b/app/src/main/java/io/legado/app/ui/book/explore/ExploreShowViewModel.kt similarity index 97% rename from app/src/main/java/io/legado/app/ui/explore/ExploreShowViewModel.kt rename to app/src/main/java/io/legado/app/ui/book/explore/ExploreShowViewModel.kt index 849b1ca87..d34e21916 100644 --- a/app/src/main/java/io/legado/app/ui/explore/ExploreShowViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/book/explore/ExploreShowViewModel.kt @@ -1,4 +1,4 @@ -package io.legado.app.ui.explore +package io.legado.app.ui.book.explore import android.app.Application import android.content.Intent 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 efcddba7c..1deccd667 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 @@ -20,14 +20,15 @@ import io.legado.app.data.entities.BookChapter 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.ui.audio.AudioPlayActivity +import io.legado.app.ui.book.changecover.ChangeCoverDialog +import io.legado.app.ui.book.changesource.ChangeSourceDialog +import io.legado.app.ui.book.chapterlist.ChapterListActivity import io.legado.app.ui.book.group.GroupSelectDialog import io.legado.app.ui.book.info.edit.BookInfoEditActivity import io.legado.app.ui.book.read.ReadBookActivity import io.legado.app.ui.book.source.edit.BookSourceEditActivity -import io.legado.app.ui.changecover.ChangeCoverDialog -import io.legado.app.ui.changesource.ChangeSourceDialog -import io.legado.app.ui.chapterlist.ChapterListActivity import io.legado.app.utils.getViewModel import io.legado.app.utils.gone import io.legado.app.utils.visible @@ -52,7 +53,8 @@ class BookInfoActivity : get() = getViewModel(BookInfoViewModel::class.java) override fun onActivityCreated(savedInstanceState: Bundle?) { - title_bar.background.alpha = 0 + setSupportActionBar(toolbar) + supportActionBar?.setDisplayHomeAsUpEnabled(true) tv_intro.movementMethod = ScrollingMovementMethod.getInstance() viewModel.bookData.observe(this, Observer { showBook(it) }) viewModel.chapterListData.observe(this, Observer { upLoading(false, it) }) @@ -103,7 +105,7 @@ class BookInfoActivity : private fun showBook(book: Book) { showCover(book) tv_name.text = book.name - tv_author.text = getString(R.string.author_show, book.author) + tv_author.text = getString(R.string.author_show, book.getRealAuthor()) tv_origin.text = getString(R.string.origin_show, book.originName) tv_lasted.text = getString(R.string.lasted_show, book.latestChapterTitle) tv_toc.text = getString(R.string.toc_s, getString(R.string.loading)) @@ -186,9 +188,7 @@ class BookInfoActivity : } tv_shelf.onClick { if (viewModel.inBookshelf) { - viewModel.delBook { - upTvBookshelf() - } + deleteBook() } else { viewModel.addToBookshelf { upTvBookshelf() @@ -223,6 +223,32 @@ class BookInfoActivity : } } + private fun deleteBook() { + viewModel.bookData.value?.let { + if (it.isLocalBook()) { + alert( + titleResource = R.string.sure, + messageResource = R.string.sure_delete_book_file + ) { + positiveButton(R.string.yes) { + viewModel.delBook(true) { + finish() + } + } + negativeButton(R.string.no) { + viewModel.delBook(false) { + finish() + } + } + }.show() + } else { + viewModel.delBook { + upTvBookshelf() + } + } + } + } + private fun openChapterList() { if (viewModel.chapterListData.value.isNullOrEmpty()) { toast(R.string.chapter_list_empty) @@ -320,7 +346,7 @@ class BookInfoActivity : } } else { if (!viewModel.inBookshelf) { - viewModel.delBook(null) + viewModel.delBook() } } } 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 1a675e21a..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 @@ -11,6 +11,7 @@ import io.legado.app.data.entities.BookChapter import io.legado.app.help.BookHelp import io.legado.app.model.WebBook import io.legado.app.model.localBook.AnalyzeTxtFile +import io.legado.app.model.localBook.LocalBook import kotlinx.coroutines.Dispatchers.IO class BookInfoViewModel(application: Application) : BaseViewModel(application) { @@ -198,12 +199,15 @@ class BookInfoViewModel(application: Application) : BaseViewModel(application) { } } - fun delBook(success: (() -> Unit)?) { + 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) + } } - inBookshelf = false }.onSuccess { success?.invoke() } diff --git a/app/src/main/java/io/legado/app/ui/book/info/edit/BookInfoEditActivity.kt b/app/src/main/java/io/legado/app/ui/book/info/edit/BookInfoEditActivity.kt index 6bcae9257..969b1ee45 100644 --- a/app/src/main/java/io/legado/app/ui/book/info/edit/BookInfoEditActivity.kt +++ b/app/src/main/java/io/legado/app/ui/book/info/edit/BookInfoEditActivity.kt @@ -8,7 +8,7 @@ import androidx.lifecycle.Observer import io.legado.app.R import io.legado.app.base.VMBaseActivity import io.legado.app.data.entities.Book -import io.legado.app.ui.changecover.ChangeCoverDialog +import io.legado.app.ui.book.changecover.ChangeCoverDialog import io.legado.app.utils.getViewModel import kotlinx.android.synthetic.main.activity_book_info_edit.* import org.jetbrains.anko.sdk27.listeners.onClick diff --git a/app/src/main/java/io/legado/app/ui/importbook/ImportBookActivity.kt b/app/src/main/java/io/legado/app/ui/book/local/ImportBookActivity.kt similarity index 99% rename from app/src/main/java/io/legado/app/ui/importbook/ImportBookActivity.kt rename to app/src/main/java/io/legado/app/ui/book/local/ImportBookActivity.kt index 8afa2793b..ed6bd4c74 100644 --- a/app/src/main/java/io/legado/app/ui/importbook/ImportBookActivity.kt +++ b/app/src/main/java/io/legado/app/ui/book/local/ImportBookActivity.kt @@ -1,4 +1,4 @@ -package io.legado.app.ui.importbook +package io.legado.app.ui.book.local import android.annotation.SuppressLint import android.app.Activity diff --git a/app/src/main/java/io/legado/app/ui/importbook/ImportBookAdapter.kt b/app/src/main/java/io/legado/app/ui/book/local/ImportBookAdapter.kt similarity index 99% rename from app/src/main/java/io/legado/app/ui/importbook/ImportBookAdapter.kt rename to app/src/main/java/io/legado/app/ui/book/local/ImportBookAdapter.kt index 6cb49d10f..acc3b7265 100644 --- a/app/src/main/java/io/legado/app/ui/importbook/ImportBookAdapter.kt +++ b/app/src/main/java/io/legado/app/ui/book/local/ImportBookAdapter.kt @@ -1,4 +1,4 @@ -package io.legado.app.ui.importbook +package io.legado.app.ui.book.local import android.content.Context import androidx.documentfile.provider.DocumentFile diff --git a/app/src/main/java/io/legado/app/ui/importbook/ImportBookViewModel.kt b/app/src/main/java/io/legado/app/ui/book/local/ImportBookViewModel.kt similarity index 96% rename from app/src/main/java/io/legado/app/ui/importbook/ImportBookViewModel.kt rename to app/src/main/java/io/legado/app/ui/book/local/ImportBookViewModel.kt index 1250da682..847a692bd 100644 --- a/app/src/main/java/io/legado/app/ui/importbook/ImportBookViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/book/local/ImportBookViewModel.kt @@ -1,4 +1,4 @@ -package io.legado.app.ui.importbook +package io.legado.app.ui.book.local import android.app.Application import android.net.Uri 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 09d29a7f3..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.changesource.ChangeSourceDialog -import io.legado.app.ui.chapterlist.ChapterListActivity import io.legado.app.ui.login.SourceLogin import io.legado.app.ui.replacerule.ReplaceRuleActivity import io.legado.app.ui.replacerule.edit.ReplaceEditDialog @@ -215,6 +216,7 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_boo R.id.menu_enable_replace -> ReadBook.book?.let { it.useReplaceRule = !it.useReplaceRule menu?.findItem(R.id.menu_enable_replace)?.isChecked = it.useReplaceRule + onReplaceRuleSave() } R.id.menu_book_info -> ReadBook.book?.let { startActivity(Pair("bookUrl", it.bookUrl)) @@ -270,18 +272,18 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_boo } } KeyEvent.KEYCODE_SPACE -> { - page_view.moveToNextPage() + page_view.pageDelegate?.keyTurnPage(PageDelegate.Direction.NEXT) return true } getPrefInt(PreferKey.prevKey) -> { if (keyCode != KeyEvent.KEYCODE_UNKNOWN) { - page_view.moveToPrevPage() + page_view.pageDelegate?.keyTurnPage(PageDelegate.Direction.PREV) return true } } getPrefInt(PreferKey.nextKey) -> { if (keyCode != KeyEvent.KEYCODE_UNKNOWN) { - page_view.moveToNextPage() + page_view.pageDelegate?.keyTurnPage(PageDelegate.Direction.NEXT) return true } } @@ -439,11 +441,7 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_boo if (getPrefBoolean("volumeKeyPageOnPlay") || BaseReadAloudService.pause ) { - when (direction) { - PageDelegate.Direction.PREV -> page_view.moveToPrevPage() - PageDelegate.Direction.NEXT -> page_view.moveToNextPage() - else -> return true - } + page_view.pageDelegate?.keyTurnPage(direction) return true } } @@ -663,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/config/BgTextConfigDialog.kt b/app/src/main/java/io/legado/app/ui/book/read/config/BgTextConfigDialog.kt index 5a3d3ec8b..73f85dce0 100644 --- a/app/src/main/java/io/legado/app/ui/book/read/config/BgTextConfigDialog.kt +++ b/app/src/main/java/io/legado/app/ui/book/read/config/BgTextConfigDialog.kt @@ -6,6 +6,7 @@ import android.content.Context import android.content.DialogInterface import android.content.Intent import android.graphics.Color +import android.net.Uri import android.os.Bundle import android.util.DisplayMetrics import android.view.Gravity @@ -13,11 +14,11 @@ import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import androidx.documentfile.provider.DocumentFile -import androidx.fragment.app.DialogFragment import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView import com.jaredrummler.android.colorpicker.ColorPickerDialog import io.legado.app.R +import io.legado.app.base.BaseDialogFragment import io.legado.app.base.adapter.ItemViewHolder import io.legado.app.base.adapter.SimpleRecyclerAdapter import io.legado.app.constant.EventBus @@ -31,9 +32,8 @@ import kotlinx.android.synthetic.main.dialog_read_bg_text.* import kotlinx.android.synthetic.main.item_bg_image.view.* import org.jetbrains.anko.sdk27.listeners.onCheckedChange import org.jetbrains.anko.sdk27.listeners.onClick -import java.io.File -class BgTextConfigDialog : DialogFragment() { +class BgTextConfigDialog : BaseDialogFragment() { companion object { const val TEXT_COLOR = 121 @@ -69,8 +69,7 @@ class BgTextConfigDialog : DialogFragment() { return inflater.inflate(R.layout.dialog_read_bg_text, container) } - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - super.onViewCreated(view, savedInstanceState) + override fun onFragmentCreated(view: View, savedInstanceState: Bundle?) { initData() initView() } @@ -171,39 +170,44 @@ class BgTextConfigDialog : DialogFragment() { resultSelectBg -> { if (resultCode == RESULT_OK) { data?.data?.let { uri -> - if (uri.toString().isContentPath()) { - val doc = DocumentFile.fromSingleUri(requireContext(), uri) - doc?.let { - var file = requireContext().getExternalFilesDir(null) - ?: requireContext().filesDir - file = - FileUtils.createFileIfNotExist(file.absolutePath + File.separator + "bg" + File.separator + doc.name) - DocumentUtils.readBytes(requireContext(), uri)?.let { - file.writeBytes(it) - ReadBookConfig.durConfig.setBg(2, file.absolutePath) - ReadBookConfig.upBg() - postEvent(EventBus.UP_CONFIG, false) - } - } - } else { - PermissionsCompat.Builder(this) - .addPermissions( - Permissions.READ_EXTERNAL_STORAGE, - Permissions.WRITE_EXTERNAL_STORAGE - ) - .rationale(R.string.bg_image_per) - .onGranted { - RealPathUtil.getPath(requireContext(), uri)?.let { path -> - ReadBookConfig.durConfig.setBg(2, path) - ReadBookConfig.upBg() - postEvent(EventBus.UP_CONFIG, false) - } - } - .request() - } + setBgFromUri(uri) } } } } } + + private fun setBgFromUri(uri: Uri) { + if (uri.toString().isContentPath()) { + val doc = DocumentFile.fromSingleUri(requireContext(), uri) + doc?.name?.let { + var file = requireContext().getExternalFilesDir(null) + ?: requireContext().filesDir + file = FileUtils.createFileIfNotExist(file, it, "bg") + kotlin.runCatching { + DocumentUtils.readBytes(requireContext(), doc.uri) + }.getOrNull()?.let { byteArray -> + file.writeBytes(byteArray) + ReadBookConfig.durConfig.setBg(2, file.absolutePath) + ReadBookConfig.upBg() + postEvent(EventBus.UP_CONFIG, false) + } ?: toast("获取文件出错") + } + } else { + PermissionsCompat.Builder(this) + .addPermissions( + Permissions.READ_EXTERNAL_STORAGE, + Permissions.WRITE_EXTERNAL_STORAGE + ) + .rationale(R.string.bg_image_per) + .onGranted { + RealPathUtil.getPath(requireContext(), uri)?.let { path -> + ReadBookConfig.durConfig.setBg(2, path) + ReadBookConfig.upBg() + postEvent(EventBus.UP_CONFIG, false) + } + } + .request() + } + } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/book/read/config/MoreConfigDialog.kt b/app/src/main/java/io/legado/app/ui/book/read/config/MoreConfigDialog.kt index 9d8ea8ba8..6f472f270 100644 --- a/app/src/main/java/io/legado/app/ui/book/read/config/MoreConfigDialog.kt +++ b/app/src/main/java/io/legado/app/ui/book/read/config/MoreConfigDialog.kt @@ -33,7 +33,7 @@ class MoreConfigDialog : DialogFragment() { } dialog?.window?.let { it.setBackgroundDrawableResource(R.color.background) - it.decorView.setPadding(0, 5, 0, 0) + it.decorView.setPadding(0, 0, 0, 0) val attr = it.attributes attr.dimAmount = 0.0f attr.gravity = Gravity.BOTTOM diff --git a/app/src/main/java/io/legado/app/ui/book/read/config/ReadAloudDialog.kt b/app/src/main/java/io/legado/app/ui/book/read/config/ReadAloudDialog.kt index 8cce7d4d2..b295a05dc 100644 --- a/app/src/main/java/io/legado/app/ui/book/read/config/ReadAloudDialog.kt +++ b/app/src/main/java/io/legado/app/ui/book/read/config/ReadAloudDialog.kt @@ -7,8 +7,8 @@ import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import android.widget.SeekBar -import androidx.fragment.app.DialogFragment import io.legado.app.R +import io.legado.app.base.BaseDialogFragment import io.legado.app.constant.EventBus import io.legado.app.help.AppConfig import io.legado.app.lib.theme.bottomBackground @@ -23,7 +23,7 @@ import kotlinx.android.synthetic.main.dialog_read_aloud.* import org.jetbrains.anko.sdk27.listeners.onClick import org.jetbrains.anko.sdk27.listeners.onLongClick -class ReadAloudDialog : DialogFragment() { +class ReadAloudDialog : BaseDialogFragment() { var callBack: CallBack? = null override fun onStart() { @@ -53,21 +53,16 @@ class ReadAloudDialog : DialogFragment() { return inflater.inflate(R.layout.dialog_read_aloud, container) } - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - super.onViewCreated(view, savedInstanceState) + override fun onFragmentCreated(view: View, savedInstanceState: Bundle?) { ll_bottom_bg.setBackgroundColor(requireContext().bottomBackground) - initData() initOnChange() + initData() initOnClick() } private fun initData() { - observeEvent(EventBus.ALOUD_STATE) { upPlayState() } - observeEvent(EventBus.TTS_DS) { seek_timer.progress = it } upPlayState() seek_timer.progress = BaseReadAloudService.timeMinute - tv_timer.text = - requireContext().getString(R.string.timer_m, BaseReadAloudService.timeMinute) cb_tts_follow_sys.isChecked = requireContext().getPrefBoolean("ttsFollowSys", true) seek_tts_SpeechRate.isEnabled = !cb_tts_follow_sys.isChecked seek_tts_SpeechRate.progress = AppConfig.ttsSpeechRate @@ -139,6 +134,11 @@ class ReadAloudDialog : DialogFragment() { } } + override fun observeLiveBus() { + observeEvent(EventBus.ALOUD_STATE) { upPlayState() } + observeEvent(EventBus.TTS_DS) { seek_timer.progress = it } + } + interface CallBack { fun showMenuBar() fun openChapterList() diff --git a/app/src/main/java/io/legado/app/ui/book/read/config/ReadStyleDialog.kt b/app/src/main/java/io/legado/app/ui/book/read/config/ReadStyleDialog.kt index f7355534a..b51d8c088 100644 --- a/app/src/main/java/io/legado/app/ui/book/read/config/ReadStyleDialog.kt +++ b/app/src/main/java/io/legado/app/ui/book/read/config/ReadStyleDialog.kt @@ -42,7 +42,7 @@ class ReadStyleDialog : DialogFragment(), FontSelectDialog.CallBack { } dialog?.window?.let { it.setBackgroundDrawableResource(R.color.background) - it.decorView.setPadding(0, 5, 0, 0) + it.decorView.setPadding(0, 0, 0, 0) val attr = it.attributes attr.dimAmount = 0.0f attr.gravity = Gravity.BOTTOM diff --git a/app/src/main/java/io/legado/app/ui/book/read/config/TocRegexDialog.kt b/app/src/main/java/io/legado/app/ui/book/read/config/TocRegexDialog.kt index f2046ac4b..af5d1ed65 100644 --- a/app/src/main/java/io/legado/app/ui/book/read/config/TocRegexDialog.kt +++ b/app/src/main/java/io/legado/app/ui/book/read/config/TocRegexDialog.kt @@ -61,8 +61,7 @@ class TocRegexDialog : BaseDialogFragment(), Toolbar.OnMenuItemClickListener { return inflater.inflate(R.layout.dialog_toc_regex, container) } - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - super.onViewCreated(view, savedInstanceState) + override fun onFragmentCreated(view: View, savedInstanceState: Bundle?) { durRegex = arguments?.getString("tocRegex") tool_bar.setTitle(R.string.txt_toc_regex) tool_bar.inflateMenu(R.menu.txt_toc_regex) 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..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") @@ -28,7 +29,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 +52,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 +61,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 +76,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 +107,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 @@ -231,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 ) @@ -257,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 ) @@ -284,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 ) @@ -346,7 +291,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 +311,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/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 c6839b214..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 @@ -26,12 +26,12 @@ class PageView(context: Context, attrs: AttributeSet) : init { callBack = activity as CallBack - prevPage = ContentView(context) - addView(prevPage) nextPage = ContentView(context) addView(nextPage) curPage = ContentView(context) addView(curPage) + prevPage = ContentView(context) + addView(prevPage) upBg() setWillNotDraw(false) pageFactory = TextPageFactory(this) @@ -40,6 +40,7 @@ class PageView(context: Context, attrs: AttributeSet) : override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) { super.onSizeChanged(w, h, oldw, oldh) + prevPage.x = -w.toFloat() pageDelegate?.setViewSize(w, h) if (oldw != 0 && oldh != 0) { ReadBook.loadContent() @@ -75,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 } @@ -99,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 { @@ -116,22 +115,6 @@ class PageView(context: Context, attrs: AttributeSet) : callBack.screenOffTimerStart() } - fun moveToPrevPage(noAnim: Boolean = true) { - if (noAnim) { - fillPage(PageDelegate.Direction.PREV) - } else { - pageDelegate?.prevPageByAnim() - } - } - - fun moveToNextPage(noAnim: Boolean = true) { - if (noAnim) { - fillPage(PageDelegate.Direction.NEXT) - } else { - pageDelegate?.nextPageByAnim() - } - } - fun upStyle() { ChapterProvider.upStyle() curPage.upStyle() 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/CoverPageDelegate.kt b/app/src/main/java/io/legado/app/ui/book/read/page/delegate/CoverPageDelegate.kt index 21ffcee77..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 @@ -6,9 +6,8 @@ import android.graphics.drawable.GradientDrawable import io.legado.app.ui.book.read.page.PageView class CoverPageDelegate(pageView: PageView) : HorizontalPageDelegate(pageView) { - - private val shadowDrawableR: GradientDrawable private val bitmapMatrix = Matrix() + private val shadowDrawableR: GradientDrawable init { val shadowColors = intArrayOf(0x66111111, 0x00000000) @@ -18,6 +17,44 @@ class CoverPageDelegate(pageView: PageView) : HorizontalPageDelegate(pageView) { shadowDrawableR.gradientType = GradientDrawable.LINEAR_GRADIENT } + override fun onDraw(canvas: Canvas) { + val offsetX = touchX - startX + + 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) { + 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) { + 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) + } + } + + private fun addShadow(left: Int, canvas: Canvas) { + if (left < 0) { + shadowDrawableR.setBounds(left + viewWidth, 0, left + viewWidth + 30, viewHeight) + shadowDrawableR.draw(canvas) + } else if (left > 0) { + shadowDrawableR.setBounds(left, 0, left + 30, viewHeight) + shadowDrawableR.draw(canvas) + } + } + + override fun onAnimStop() { + if (!isCancel) { + pageView.fillPage(mDirection) + } + } + override fun onAnimStart() { val distanceX: Float when (mDirection) { @@ -38,43 +75,7 @@ class CoverPageDelegate(pageView: PageView) : HorizontalPageDelegate(pageView) { viewWidth - (touchX - startX) } } - startScroll(touchX.toInt(), 0, distanceX.toInt(), 0) } - override fun onAnimStop() { - curPage.x = 0.toFloat() - if (!isCancel) { - pageView.fillPage(mDirection) - } - } - - override fun onDraw(canvas: Canvas) { - val offsetX = touchX - startX - - if ((mDirection == Direction.NEXT && offsetX > 0) - || (mDirection == Direction.PREV && offsetX < 0) - ) return - - val distanceX = if (offsetX > 0) offsetX - viewWidth else offsetX + viewWidth - bitmap?.let { - if (mDirection == Direction.PREV) { - bitmapMatrix.setTranslate(distanceX, 0.toFloat()) - canvas.drawBitmap(it, bitmapMatrix, null) - } else if (mDirection == Direction.NEXT) { - curPage.translationX = offsetX - } - addShadow(distanceX.toInt(), canvas) - } - } - - private fun addShadow(left: Int, canvas: Canvas) { - if (left < 0) { - shadowDrawableR.setBounds(left + viewWidth, 0, left + viewWidth + 30, viewHeight) - shadowDrawableR.draw(canvas) - } else if (left > 0) { - shadowDrawableR.setBounds(left, 0, left + 30, viewHeight) - shadowDrawableR.draw(canvas) - } - } } 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 700728b14..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 @@ -1,13 +1,44 @@ 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 kotlin.math.abs +import io.legado.app.utils.screenshot 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 -> { + abort() + } MotionEvent.ACTION_MOVE -> { if (isTextSelected) { selectText(event) @@ -20,19 +51,37 @@ 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 return } setDirection(Direction.PREV) - setBitmap() } else { //如果不存在表示没有下一页了 if (!hasNext()) { @@ -40,7 +89,6 @@ abstract class HorizontalPageDelegate(pageView: PageView) : PageDelegate(pageVie return } setDirection(Direction.NEXT) - setBitmap() } } } @@ -48,23 +96,34 @@ 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) } } override fun nextPageByAnim() { + super.nextPageByAnim() if (!hasNext()) return setDirection(Direction.NEXT) - setBitmap() setTouchPoint(viewWidth.toFloat(), 0f) onAnimStart() } override fun prevPageByAnim() { + super.prevPageByAnim() if (!hasPrev()) return setDirection(Direction.PREV) - setBitmap() setTouchPoint(0f, 0f) 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/PageDelegate.kt b/app/src/main/java/io/legado/app/ui/book/read/page/delegate/PageDelegate.kt index 76b40fb78..125d6bb5f 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 @@ -1,7 +1,6 @@ package io.legado.app.ui.book.read.page.delegate import android.content.Context -import android.graphics.Bitmap import android.graphics.Canvas import android.graphics.RectF import android.view.GestureDetector @@ -15,7 +14,6 @@ import io.legado.app.help.AppConfig import io.legado.app.help.ReadBookConfig import io.legado.app.ui.book.read.page.ContentView import io.legado.app.ui.book.read.page.PageView -import io.legado.app.utils.screenshot import kotlin.math.abs abstract class PageDelegate(protected val pageView: PageView) : @@ -25,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 @@ -40,23 +38,26 @@ abstract class PageDelegate(protected val pageView: PageView) : protected val curPage: ContentView get() = pageView.curPage protected val prevPage: ContentView get() = pageView.prevPage - protected var bitmap: Bitmap? = null - 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 @@ -126,11 +127,10 @@ abstract class PageDelegate(protected val pageView: PageView) : } private fun stopScroll() { + isMoved = false isRunning = false isStarted = false pageView.invalidate() - bitmap?.recycle() - bitmap = null } open fun setViewSize(width: Int, height: Int) { @@ -166,23 +166,28 @@ abstract class PageDelegate(protected val pageView: PageView) : open fun onScroll() {}//移动contentView, slidePage - abstract fun nextPageByAnim() + open fun nextPageByAnim() { + abort() + } + + open fun prevPageByAnim() { + abort() + } - abstract fun prevPageByAnim() + open fun keyTurnPage(direction: Direction) { + if (isRunning) return + when (direction) { + Direction.NEXT -> nextPageByAnim() + Direction.PREV -> prevPageByAnim() + else -> return + } + } @CallSuper open fun setDirection(direction: Direction) { mDirection = direction } - open fun setBitmap() { - bitmap = when (mDirection) { - Direction.NEXT -> nextPage.screenshot() - Direction.PREV -> prevPage.screenshot() - else -> null - } - } - /** * 触摸事件处理 */ @@ -191,11 +196,14 @@ abstract class PageDelegate(protected val pageView: PageView) : if (isStarted) return 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 +240,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)) { @@ -321,7 +333,7 @@ abstract class PageDelegate(protected val pageView: PageView) : } open fun onDestroy() { - bitmap?.recycle() + } enum class Direction { 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 a3434aeed..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 @@ -61,10 +79,12 @@ class ScrollPageDelegate(pageView: PageView) : PageDelegate(pageView) { } override fun nextPageByAnim() { + super.nextPageByAnim() startScroll(0, 0, 0, -ChapterProvider.visibleHeight) } override fun prevPageByAnim() { + super.prevPageByAnim() startScroll(0, 0, 0, ChapterProvider.visibleHeight) } } \ 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 6d7dd7bf8..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) @@ -119,20 +115,20 @@ class SimulationPageDelegate(pageView: PageView) : HorizontalPageDelegate(pageVi } 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 * 0.33 && startY < viewHeight * 0.66) + if ((startY > viewHeight / 3 && startY < viewHeight * 2 / 3) || mDirection == Direction.PREV ) { touchY = viewHeight.toFloat() } - if (startY > viewHeight * 0.33 && startY < viewHeight / 2.0 + if (startY > viewHeight / 3 && startY < viewHeight / 2 && mDirection == Direction.NEXT ) { touchY = 1f @@ -145,33 +141,19 @@ class SimulationPageDelegate(pageView: PageView) : HorizontalPageDelegate(pageVi 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 } } - override 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 @@ -209,15 +191,10 @@ class SimulationPageDelegate(pageView: PageView) : HorizontalPageDelegate(pageVi if (!isCancel) { pageView.fillPage(mDirection) } - prevBitmap?.recycle() - prevBitmap = null - nextBitmap?.recycle() - nextBitmap = null - curBitmap?.recycle() - curBitmap = null } override fun onDraw(canvas: Canvas) { + if (!isRunning) return when (mDirection) { Direction.NEXT -> { calcPoints() @@ -292,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) @@ -480,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) } @@ -492,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) @@ -515,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) @@ -526,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 @@ -538,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 0308d965e..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 @@ -28,7 +28,6 @@ class SlidePageDelegate(pageView: PageView) : HorizontalPageDelegate(pageView) { viewWidth - (touchX - startX) } } - startScroll(touchX.toInt(), 0, distanceX.toInt(), 0) } @@ -38,27 +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 - bitmap?.let { + if (!isRunning) return + if (mDirection == Direction.PREV) { + 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) { bitmapMatrix.setTranslate(distanceX, 0.toFloat()) - canvas.drawBitmap(it, bitmapMatrix, null) + nextBitmap?.let { canvas.drawBitmap(it, bitmapMatrix, null) } + bitmapMatrix.setTranslate(distanceX - viewWidth, 0.toFloat()) + curBitmap?.let { canvas.drawBitmap(it, bitmapMatrix, null) } } } - override fun onScroll() { - val offsetX = touchX - startX - - if ((mDirection == Direction.NEXT && offsetX > 0) - || (mDirection == Direction.PREV && offsetX < 0) - ) return - - curPage.translationX = offsetX - } - override fun onAnimStop() { - curPage.x = 0.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/book/search/SearchActivity.kt b/app/src/main/java/io/legado/app/ui/book/search/SearchActivity.kt index 1227f4232..a41fcd656 100644 --- a/app/src/main/java/io/legado/app/ui/book/search/SearchActivity.kt +++ b/app/src/main/java/io/legado/app/ui/book/search/SearchActivity.kt @@ -280,12 +280,16 @@ class SearchActivity : VMBaseActivity(R.layout.activity_book_se */ @Synchronized private fun upSearchItems(items: List, isMandatoryUpdate: Boolean) { - if (!isMandatoryUpdate && System.currentTimeMillis() - refreshTime < 1000) { + if (!isMandatoryUpdate && System.currentTimeMillis() - refreshTime < 500) { return } refreshTime = System.currentTimeMillis() - val diffResult = DiffUtil.calculateDiff(DiffCallBack(ArrayList(adapter.getItems()), items)) - adapter.setItems(items, diffResult) + try { + val diffResult = DiffUtil.calculateDiff(DiffCallBack(adapter.getItems(), items)) + adapter.setItems(items, diffResult) + } catch (e: Exception) { + e.printStackTrace() + } } /** 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/config/ConfigActivity.kt b/app/src/main/java/io/legado/app/ui/config/ConfigActivity.kt index a685ccd13..6d7bfcfe7 100644 --- a/app/src/main/java/io/legado/app/ui/config/ConfigActivity.kt +++ b/app/src/main/java/io/legado/app/ui/config/ConfigActivity.kt @@ -3,7 +3,9 @@ package io.legado.app.ui.config import android.os.Bundle import io.legado.app.R import io.legado.app.base.VMBaseActivity +import io.legado.app.constant.EventBus import io.legado.app.utils.getViewModel +import io.legado.app.utils.observeEvent import kotlinx.android.synthetic.main.activity_config.* class ConfigActivity : VMBaseActivity(R.layout.activity_config) { @@ -47,4 +49,10 @@ class ConfigActivity : VMBaseActivity(R.layout.activity_config) } + override fun observeLiveBus() { + super.observeLiveBus() + observeEvent(EventBus.RECREATE) { + recreate() + } + } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/config/ThemeConfigFragment.kt b/app/src/main/java/io/legado/app/ui/config/ThemeConfigFragment.kt index 0652350c5..22f5e7f3d 100644 --- a/app/src/main/java/io/legado/app/ui/config/ThemeConfigFragment.kt +++ b/app/src/main/java/io/legado/app/ui/config/ThemeConfigFragment.kt @@ -18,7 +18,6 @@ import io.legado.app.lib.dialogs.yesButton import io.legado.app.lib.theme.ATH import io.legado.app.lib.theme.ColorUtils import io.legado.app.utils.* -import org.jetbrains.anko.defaultSharedPreferences class ThemeConfigFragment : PreferenceFragmentCompat(), SharedPreferences.OnSharedPreferenceChangeListener { @@ -27,7 +26,6 @@ class ThemeConfigFragment : PreferenceFragmentCompat(), SharedPreferences.OnShar override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { addPreferencesFromResource(R.xml.pref_config_theme) - onSharedPreferenceChanged(requireContext().defaultSharedPreferences, "defaultTheme") } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { @@ -49,9 +47,7 @@ class ThemeConfigFragment : PreferenceFragmentCompat(), SharedPreferences.OnShar sharedPreferences ?: return when (key) { PreferKey.launcherIcon -> LauncherIconHelp.changeIcon(getPrefString(key)) - "transparentStatusBar" -> { - recreateActivities() - } + "transparentStatusBar" -> recreateActivities() "colorPrimary", "colorAccent", "colorBackground", @@ -100,7 +96,6 @@ class ThemeConfigFragment : PreferenceFragmentCompat(), SharedPreferences.OnShar upTheme(true) } } - "defaultTheme" -> findPreference(key)?.summary = items[getPrefInt(key)] } } @@ -147,7 +142,6 @@ class ThemeConfigFragment : PreferenceFragmentCompat(), SharedPreferences.OnShar AppConfig.isNightTheme = true } } - putPrefInt("defaultTheme", which) App.INSTANCE.applyDayNight() recreateActivities() } 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..0d43b28c2 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 @@ -34,14 +34,18 @@ class MainActivity : VMBaseActivity(R.layout.activity_main), get() = getViewModel(MainViewModel::class.java) private var pagePosition = 0 - private val fragmentList = arrayListOf() - private var rssFragment: RssFragment? = null + private val fragmentId = arrayOf(0, 1, 2, 3) + private val fragmentMap = mapOf( + Pair(fragmentId[0], BookshelfFragment()), + Pair(fragmentId[1], ExploreFragment()), + Pair(fragmentId[2], RssFragment()), + Pair(fragmentId[3], MyFragment()) + ) override fun onActivityCreated(savedInstanceState: Bundle?) { ATH.applyEdgeEffectColor(view_pager_main) ATH.applyBottomNavigationColor(bottom_navigation_view) view_pager_main.offscreenPageLimit = 3 - upFragmentList() view_pager_main.adapter = TabFragmentPageAdapter(supportFragmentManager) view_pager_main.addOnPageChangeListener(this) bottom_navigation_view.setOnNavigationItemSelectedListener(this) @@ -69,22 +73,6 @@ class MainActivity : VMBaseActivity(R.layout.activity_main), return false } - private fun upFragmentList() { - if (fragmentList.isEmpty()) { - fragmentList.add(BookshelfFragment()) - fragmentList.add(ExploreFragment()) - fragmentList.add(RssFragment()) - fragmentList.add(MyFragment()) - } - if (AppConfig.isShowRSS && fragmentList.size < 4) { - fragmentList.add(2, - rssFragment ?: RssFragment().apply { rssFragment = this }) - } - if (!AppConfig.isShowRSS && fragmentList.size == 4) { - fragmentList.removeAt(2) - } - } - private fun upVersion() { if (getPrefInt(PreferKey.versionCode) != App.INSTANCE.versionCode) { putPrefInt(PreferKey.versionCode, App.INSTANCE.versionCode) @@ -144,7 +132,6 @@ class MainActivity : VMBaseActivity(R.layout.activity_main), } observeEvent(EventBus.SHOW_RSS) { bottom_navigation_view.menu.findItem(R.id.menu_rss).isVisible = AppConfig.isShowRSS - upFragmentList() view_pager_main.adapter?.notifyDataSetChanged() if (AppConfig.isShowRSS) { view_pager_main.setCurrentItem(3, false) @@ -160,7 +147,16 @@ class MainActivity : VMBaseActivity(R.layout.activity_main), } override fun getItem(position: Int): Fragment { - return fragmentList[position] + return when (position) { + 0 -> fragmentMap.getValue(fragmentId[0]) + 1 -> fragmentMap.getValue(fragmentId[1]) + 2 -> if (AppConfig.isShowRSS) { + fragmentMap.getValue(fragmentId[2]) + } else { + fragmentMap.getValue(fragmentId[3]) + } + else -> fragmentMap.getValue(fragmentId[3]) + } } override fun getCount(): Int { @@ -168,4 +164,5 @@ class MainActivity : VMBaseActivity(R.layout.activity_main), } } + } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfFragment.kt b/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfFragment.kt index f49cf2ea6..9cb7dc9de 100644 --- a/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfFragment.kt +++ b/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfFragment.kt @@ -15,7 +15,6 @@ import io.legado.app.App import io.legado.app.R import io.legado.app.base.VMBaseFragment import io.legado.app.constant.AppConst -import io.legado.app.constant.EventBus import io.legado.app.constant.PreferKey import io.legado.app.data.entities.BookGroup import io.legado.app.lib.dialogs.alert @@ -25,10 +24,10 @@ import io.legado.app.lib.dialogs.okButton import io.legado.app.lib.theme.ATH import io.legado.app.lib.theme.accentColor import io.legado.app.ui.book.arrange.ArrangeBookActivity +import io.legado.app.ui.book.download.DownloadActivity import io.legado.app.ui.book.group.GroupManageDialog +import io.legado.app.ui.book.local.ImportBookActivity import io.legado.app.ui.book.search.SearchActivity -import io.legado.app.ui.download.DownloadActivity -import io.legado.app.ui.importbook.ImportBookActivity import io.legado.app.ui.widget.text.AutoCompleteTextView import io.legado.app.utils.* import kotlinx.android.synthetic.main.dialog_bookshelf_config.view.* @@ -99,9 +98,6 @@ class BookshelfFragment : VMBaseFragment(R.layout.fragment_b TabLayoutMediator(tab_layout, view_pager_bookshelf) { tab, position -> tab.text = bookGroups[position].groupName }.attach() - observeEvent(EventBus.UP_TABS) { - tab_layout.getTabAt(it)?.select() - } } private fun initBookGroupData() { diff --git a/app/src/main/java/io/legado/app/ui/main/bookshelf/books/BooksFragment.kt b/app/src/main/java/io/legado/app/ui/main/bookshelf/books/BooksFragment.kt index 49cadb56c..5d922cae9 100644 --- a/app/src/main/java/io/legado/app/ui/main/bookshelf/books/BooksFragment.kt +++ b/app/src/main/java/io/legado/app/ui/main/bookshelf/books/BooksFragment.kt @@ -57,9 +57,6 @@ class BooksFragment : BaseFragment(R.layout.fragment_books), } initRecyclerView() upRecyclerData() - observeEvent(EventBus.UP_BOOK) { - booksAdapter.notification(it) - } } private fun initRecyclerView() { @@ -111,7 +108,7 @@ class BooksFragment : BaseFragment(R.layout.fragment_books), else -> list.sortedByDescending { it.durChapterTime } } val diffResult = DiffUtil - .calculateDiff(BooksDiffCallBack(ArrayList(booksAdapter.getItems()), books)) + .calculateDiff(BooksDiffCallBack(booksAdapter.getItems(), books)) booksAdapter.setItems(books, diffResult) }) } @@ -135,4 +132,10 @@ class BooksFragment : BaseFragment(R.layout.fragment_books), return bookUrl in activityViewModel.updateList } + override fun observeLiveBus() { + super.observeLiveBus() + observeEvent(EventBus.UP_BOOK) { + booksAdapter.notification(it) + } + } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/main/explore/ExploreFragment.kt b/app/src/main/java/io/legado/app/ui/main/explore/ExploreFragment.kt index 78cdd141a..f4257732c 100644 --- a/app/src/main/java/io/legado/app/ui/main/explore/ExploreFragment.kt +++ b/app/src/main/java/io/legado/app/ui/main/explore/ExploreFragment.kt @@ -18,7 +18,7 @@ import io.legado.app.data.entities.BookSource import io.legado.app.lib.theme.ATH import io.legado.app.lib.theme.primaryTextColor import io.legado.app.ui.book.source.edit.BookSourceEditActivity -import io.legado.app.ui.explore.ExploreShowActivity +import io.legado.app.ui.book.explore.ExploreShowActivity import io.legado.app.utils.getViewModel import io.legado.app.utils.splitNotBlank import io.legado.app.utils.startActivity diff --git a/app/src/main/java/io/legado/app/ui/main/my/MyFragment.kt b/app/src/main/java/io/legado/app/ui/main/my/MyFragment.kt index de1f63ae1..ddb045c9e 100644 --- a/app/src/main/java/io/legado/app/ui/main/my/MyFragment.kt +++ b/app/src/main/java/io/legado/app/ui/main/my/MyFragment.kt @@ -23,6 +23,7 @@ import io.legado.app.ui.config.ConfigActivity import io.legado.app.ui.config.ConfigViewModel import io.legado.app.ui.filechooser.FileChooserDialog import io.legado.app.ui.replacerule.ReplaceRuleActivity +import io.legado.app.ui.widget.prefs.NameListPreference import io.legado.app.ui.widget.prefs.SwitchPreference import io.legado.app.utils.* import kotlinx.android.synthetic.main.view_title_bar.* @@ -74,6 +75,12 @@ class MyFragment : BaseFragment(R.layout.fragment_my_config), FileChooserDialog. observeEvent(EventBus.WEB_SERVICE_STOP) { webServicePre?.isChecked = false } + findPreference(PreferKey.themeMode)?.let { + it.setOnPreferenceChangeListener { _, _ -> + view?.post { App.INSTANCE.applyDayNight() } + true + } + } } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { @@ -96,7 +103,6 @@ class MyFragment : BaseFragment(R.layout.fragment_my_config), FileChooserDialog. key: String? ) { when (key) { - PreferKey.themeMode -> App.INSTANCE.applyDayNight() PreferKey.webService -> { if (requireContext().getPrefBoolean("webService")) { WebService.start(requireContext()) diff --git a/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleActivity.kt b/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleActivity.kt index e5be539c5..91f7e7b75 100644 --- a/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleActivity.kt +++ b/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleActivity.kt @@ -141,8 +141,8 @@ class ReplaceRuleActivity : VMBaseActivity(R.layout.activi } private fun observeReplaceRuleData(key: String? = null) { - replaceRuleLiveData?.removeObservers(this) dataInit = false + replaceRuleLiveData?.removeObservers(this) replaceRuleLiveData = if (key.isNullOrEmpty()) { App.db.replaceRuleDao().liveDataAll() } else { @@ -304,22 +304,27 @@ class ReplaceRuleActivity : VMBaseActivity(R.layout.activi } override fun update(vararg rule: ReplaceRule) { + setResult(Activity.RESULT_OK) viewModel.update(*rule) } override fun delete(rule: ReplaceRule) { + setResult(Activity.RESULT_OK) viewModel.delete(rule) } override fun edit(rule: ReplaceRule) { + setResult(Activity.RESULT_OK) ReplaceEditDialog.show(supportFragmentManager, rule.id) } override fun toTop(rule: ReplaceRule) { + setResult(Activity.RESULT_OK) viewModel.toTop(rule) } override fun upOrder() { + setResult(Activity.RESULT_OK) viewModel.upOrder() } } \ No newline at end of file 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/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/ui/widget/font/FontSelectDialog.kt b/app/src/main/java/io/legado/app/ui/widget/font/FontSelectDialog.kt index bbeb7f04e..ac5a1281c 100644 --- a/app/src/main/java/io/legado/app/ui/widget/font/FontSelectDialog.kt +++ b/app/src/main/java/io/legado/app/ui/widget/font/FontSelectDialog.kt @@ -60,7 +60,7 @@ class FontSelectDialog : BaseDialogFragment(), return inflater.inflate(R.layout.dialog_font_select, container) } - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + override fun onFragmentCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) tool_bar.setTitle(R.string.select_font) tool_bar.inflateMenu(R.menu.font_select) 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/java/io/legado/app/utils/EventBusKt.kt b/app/src/main/java/io/legado/app/utils/EventBusKt.kt index 82c3f0f30..6731e06d6 100644 --- a/app/src/main/java/io/legado/app/utils/EventBusKt.kt +++ b/app/src/main/java/io/legado/app/utils/EventBusKt.kt @@ -4,13 +4,14 @@ import androidx.appcompat.app.AppCompatActivity import androidx.fragment.app.Fragment import androidx.lifecycle.Observer import com.jeremyliao.liveeventbus.LiveEventBus +import com.jeremyliao.liveeventbus.core.Observable -inline fun eventObservable(tag: String): LiveEventBus.Observable { - return LiveEventBus.get().with(tag, EVENT::class.java) +inline fun eventObservable(tag: String): Observable { + return LiveEventBus.get(tag, EVENT::class.java) } inline fun postEvent(tag: String, event: EVENT) { - LiveEventBus.get().with(tag, EVENT::class.java).post(event) + LiveEventBus.get(tag).post(event) } inline fun AppCompatActivity.observeEvent( diff --git a/app/src/main/java/io/legado/app/utils/MenuExtensions.kt b/app/src/main/java/io/legado/app/utils/MenuExtensions.kt index d8ecff3e1..9f13d543d 100644 --- a/app/src/main/java/io/legado/app/utils/MenuExtensions.kt +++ b/app/src/main/java/io/legado/app/utils/MenuExtensions.kt @@ -1,5 +1,6 @@ package io.legado.app.utils +import android.annotation.SuppressLint import android.content.Context import android.view.Menu import android.view.MenuItem @@ -13,6 +14,7 @@ import io.legado.app.lib.theme.primaryTextColor import java.lang.reflect.Method import java.util.* +@SuppressLint("RestrictedApi") fun Menu.applyTint(context: Context, theme: Theme = Theme.Auto): Menu = this.let { menu -> if (menu is MenuBuilder) { menu.setOptionalIconsVisible(true) 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/app/src/main/res/layout/activity_audio_play.xml b/app/src/main/res/layout/activity_audio_play.xml index 71a7edfe8..7869b3b1c 100644 --- a/app/src/main/res/layout/activity_audio_play.xml +++ b/app/src/main/res/layout/activity_audio_play.xml @@ -21,10 +21,13 @@ android:layout_height="match_parent" android:background="#50000000" /> - + app:layout_constraintTop_toBottomOf="@+id/toolbar" /> - @@ -38,7 +41,7 @@ android:scaleType="centerCrop" android:src="@drawable/image_cover_default" app:layout_constraintLeft_toLeftOf="parent" - app:layout_constraintTop_toBottomOf="@+id/title_bar" /> + app:layout_constraintTop_toBottomOf="@+id/toolbar" /> + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/dialog_change_source.xml b/app/src/main/res/layout/dialog_change_source.xml index 1199d4538..cc7486b05 100644 --- a/app/src/main/res/layout/dialog_change_source.xml +++ b/app/src/main/res/layout/dialog_change_source.xml @@ -1,5 +1,5 @@ - + app:fitStatusBar="false" /> + android:layout_height="2dp" /> + android:layout_height="match_parent" /> - \ No newline at end of file + \ No newline at end of file diff --git a/app/src/main/res/layout/view_read_menu.xml b/app/src/main/res/layout/view_read_menu.xml index 4d4f8f18b..17e2c89f8 100644 --- a/app/src/main/res/layout/view_read_menu.xml +++ b/app/src/main/res/layout/view_read_menu.xml @@ -81,8 +81,9 @@ @@ -90,7 +91,7 @@ android:id="@+id/fabAutoPage" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:layout_margin="10dp" + android:layout_margin="16dp" android:contentDescription="@string/auto_next_page" android:src="@drawable/ic_auto_page" android:tint="@color/tv_text_default" @@ -110,7 +111,7 @@ android:id="@+id/fabReplaceRule" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:layout_margin="10dp" + android:layout_margin="16dp" android:contentDescription="@string/replace_rule_title" android:src="@drawable/ic_find_replace" android:tint="@color/tv_text_default" @@ -130,7 +131,7 @@ android:id="@+id/fabNightTheme" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:layout_margin="10dp" + android:layout_margin="16dp" android:contentDescription="@string/dark_theme" android:src="@drawable/ic_brightness" android:tint="@color/tv_text_default" @@ -143,8 +144,6 @@ - - + + 文章内容为空 正在换源请等待… 目录列表为空 - 正文边距 - Tip边距 字距 基本 @@ -616,7 +614,7 @@ 长按选择文本 页眉 正文 - 页角 + 页脚 文本选择结束位置 文本选择开始位置 共用布局 @@ -630,4 +628,5 @@ 其它朗读设置 系统内置字体样式 + 是否删除源文件 diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml index d5c9e7104..4cc3907e0 100644 --- a/app/src/main/res/values/styles.xml +++ b/app/src/main/res/values/styles.xml @@ -33,7 +33,6 @@ @style/Style.PopupMenu @color/transparent true - 0dp