diff --git a/app/build.gradle b/app/build.gradle index 0cba83027..827a987af 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -111,7 +111,7 @@ kapt { } dependencies { - coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.0.10' + coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.1.0' implementation fileTree(dir: 'libs', include: ['*.jar']) testImplementation 'junit:junit:4.13.1' androidTestImplementation 'androidx.test:runner:1.3.0' diff --git a/app/src/main/assets/help/help.md b/app/src/main/assets/help/appHelp.md similarity index 98% rename from app/src/main/assets/help/help.md rename to app/src/main/assets/help/appHelp.md index 45c8b79a8..78dd3e976 100644 --- a/app/src/main/assets/help/help.md +++ b/app/src/main/assets/help/appHelp.md @@ -2,7 +2,7 @@ ## **新人必读** -【温馨提醒】 *更新前一定要做好备份,以免数据丢失!* +【温馨提醒】 *本帮助可以在我的-右上角帮助按钮再次打开,更新前一定要做好备份,以免数据丢失!* 1. 为什么第一次安装好之后什么东西都没有? * 阅读只是一个转码工具,不提供内容,第一次安装app,需要自己手动导入书源,可以从公众号[开源阅读]()、QQ群、酷安评论里获取由书友制作分享的书源。 diff --git a/app/src/main/assets/help/bookSourcesHelp.md b/app/src/main/assets/help/bookSourcesHelp.md new file mode 100644 index 000000000..3cadf2a67 --- /dev/null +++ b/app/src/main/assets/help/bookSourcesHelp.md @@ -0,0 +1,25 @@ +# 书源管理界面帮助 + +* 书源右上角标志 + * 绿点表示书源有发现,且启用了发现 + * 红点表示书源有发现,但是未启用 + * 没有标志表示此书源没有发现 +* 右上角有分组菜单,可以按分组筛选书源 +* 右上角更多菜单里包含 + * 新建书源 + * 本地导入 + * 网络导入 + * 二维码导入 + * 分享选中书源 +* 选择书源的更多操作在右下角的菜单里面,操作都是针对选择的书源 + * 启用所选 + * 禁用所选 + * 添加分组 + * 移除分组 + * 启用发现 + * 禁用发现 + * 置顶所选 + * 置底所选 + * 导出所选 + * 校验所选 +* 校验失败的书源分组会加上"失效",选择"失效"分组即可批量操作 \ No newline at end of file diff --git a/app/src/main/assets/help/httpTts.md b/app/src/main/assets/help/httpTTSHelp.md similarity index 100% rename from app/src/main/assets/help/httpTts.md rename to app/src/main/assets/help/httpTTSHelp.md diff --git a/app/src/main/assets/help/readMenuHelp.md b/app/src/main/assets/help/readMenuHelp.md new file mode 100644 index 000000000..0e675bba6 --- /dev/null +++ b/app/src/main/assets/help/readMenuHelp.md @@ -0,0 +1,42 @@ +# 阅读界面帮助文档 + +1.阅读界面主菜单 +* 顶部操作 + * 章节名称:点击可编辑书源 + * 章节url:点击可打开浏览器浏览 + * 菜单:不同类型的书籍显示的菜单不同,详情查看菜单文字,长按菜单图标可显示文字 +* 中间左侧-亮度调节 + * 亮度调节的顶端有跟随系统亮度的开关,打开后亮度跟随系统,关闭后才可以调节亮度条 +* 底部操作 + * 4个圆形按钮依次为 全文搜索✧自动翻页✧替换净化✧切换夜间模式 + * 上一章✧下一章中间的进度条为页数进度,要快速跳转章节点击目录按钮进入目录快速跳转 + * 目录->目录和书签界面 + * 朗读->单击开始朗读,长按进入朗读设置界面 + * 界面->所有排版设置都在里面 + * 设置->其它一些设置,找不到的设置去这里看看,可滚动 + +2.朗读设置界面 +* 后台->进入后台朗读,可以做一些其它事 +* 设置->朗读引擎设置,可以切换本地TTS和在线朗读,在线朗读可自定义 + +3.排版设置界面 +* 白天模式和夜间模式背景不同布局相同 +* 共用布局->启用共用布局时所有背景使用同一布局,关闭共用布局则每个背景单独布局 +* 长按背景可进入文字颜色和背景设置界面 + +4.其它设置界面 +* 屏幕方向 +* 屏幕超时 +* 隐藏状态栏 +* 扩展到刘海 +* 隐藏导航栏 +* 文字两端对齐 +* 文字底部对齐 +* 音量键翻页 +* 点击翻页 +* 朗读时音量键翻页 +* 自动换源->书源被删除时自动切换到其它书源 +* 长按选择文本 +* 显示亮度调节控件 +* 点击区域设置 +* 自定义翻页按键 \ No newline at end of file diff --git a/app/src/main/assets/help/regex.md b/app/src/main/assets/help/regexHelp.md similarity index 99% rename from app/src/main/assets/help/regex.md rename to app/src/main/assets/help/regexHelp.md index 93888dcf2..f69a6cdc2 100644 --- a/app/src/main/assets/help/regex.md +++ b/app/src/main/assets/help/regexHelp.md @@ -1,4 +1,4 @@ -## 正则表达式学习 +# 正则表达式学习 - [基本匹配](#1-基本匹配) - [元字符](#2-元字符) diff --git a/app/src/main/assets/help/webDavHelp.md b/app/src/main/assets/help/webDavHelp.md new file mode 100644 index 000000000..dee978b42 --- /dev/null +++ b/app/src/main/assets/help/webDavHelp.md @@ -0,0 +1,19 @@ +# WebDav备份教程 + +### 阅读支持云备份,采用WebDav协议,所有支持WebDav的云盘都可以,建议采用坚果云,每月免费1G流量,用来备份阅读足够了,下面就采用坚果云来讲解配置步骤. + +1. 打开坚果云网站 https://www.jianguoyun.com/d/home#/ +2. 如果没有注册过坚果云先注册一下 +3. 登录坚果云 +4. 右上角用户名点开点账户信息 +5. 点击安全选项 +6. 在第三方管理里添加应用 +7. 将应用示例里的服务器地址,用户名,和密码填到阅读的WebDav设置里 +8. 阅读的WebDav配置在我的-备份与恢复,创建子文件夹选项保持默认即可 +9. 设置完成后手动执行一下备份,看看是否成功 +10. 恢复时选择想要恢复的备份文件 + +### 自动备份说明 + +* 设置好备份之后每次退出App会自动进行备份 +* WebDav同一天的备份会覆盖,不同日期的备份不会覆盖 \ No newline at end of file diff --git a/app/src/main/assets/updateLog.md b/app/src/main/assets/updateLog.md index bea3064fa..ed4c5904d 100644 --- a/app/src/main/assets/updateLog.md +++ b/app/src/main/assets/updateLog.md @@ -3,6 +3,20 @@ * 关注合作公众号 **[小说拾遗]()** 获取好看的小说。 * 旧版数据导入教程:先在旧版阅读(2.x)中进行备份,然后在新版阅读(3.x)【我的】->【备份与恢复】,选择【导入旧版本数据】。 +**2020/11/13** +* 正文规则添加字体规则,返回ByteArray +* js添加方法: +``` +base64DecodeToByteArray(str: String?): ByteArray? +base64DecodeToByteArray(str: String?, flags: Int): ByteArray? +``` + +**2020/11/08** +* 优化书源,订阅源导入,添加保持原名选项 +* 优化使用体验,初次使用是自动弹出帮助文档 +* 添加阅读界面的点击区域设置 +* 滚动翻页时自动翻页也采用滚动模式 + **2020/11/07** * 详情页菜单添加拷贝URL * 解决一些书名太长缓存报错的bug diff --git a/app/src/main/java/io/legado/app/constant/AppConst.kt b/app/src/main/java/io/legado/app/constant/AppConst.kt index b841ec595..ec37a11a2 100644 --- a/app/src/main/java/io/legado/app/constant/AppConst.kt +++ b/app/src/main/java/io/legado/app/constant/AppConst.kt @@ -38,7 +38,7 @@ object AppConst { val keyboardToolChars: List by lazy { arrayListOf( - "※", "@", "&", "|", "%", "/", ":", "[", "]", "{", "}", "<", ">", "\\", + "❓", "@", "&", "|", "%", "/", ":", "[", "]", "{", "}", "<", ">", "\\", "$", "#", "!", ".", "href", "src", "textNodes", "xpath", "json", "css", "id", "class", "tag" ) 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 2e385f9ca..1f99d7cba 100644 --- a/app/src/main/java/io/legado/app/constant/PreferKey.kt +++ b/app/src/main/java/io/legado/app/constant/PreferKey.kt @@ -5,8 +5,15 @@ object PreferKey { const val language = "language" const val themeMode = "themeMode" const val hideStatusBar = "hideStatusBar" - const val clickTurnPage = "clickTurnPage" - const val clickAllNext = "clickAllNext" + const val clickActionTopLeft = "clickActionTopLeft" + const val clickActionTopCenter = "clickActionTopCenter" + const val clickActionTopRight = "clickActionTopRight" + const val clickActionMiddleLeft = "clickActionMiddleLeft" + const val clickActionMiddleCenter = "clickActionMiddleCenter" + const val clickActionMiddleRight = "clickActionMiddleRight" + const val clickActionBottomLeft = "clickActionBottomLeft" + const val clickActionBottomCenter = "clickActionBottomCenter" + const val clickActionBottomRight = "clickActionBottomRight" const val hideNavigationBar = "hideNavigationBar" const val precisionSearch = "precisionSearch" const val speakEngine = "speakEngine" @@ -53,6 +60,7 @@ object PreferKey { const val showBrightnessView = "showBrightnessView" const val autoClearExpired = "autoClearExpired" const val autoChangeSource = "autoChangeSource" + const val importKeepName = "importKeepName" const val cPrimary = "colorPrimary" const val cAccent = "colorAccent" diff --git a/app/src/main/java/io/legado/app/data/entities/BookChapter.kt b/app/src/main/java/io/legado/app/data/entities/BookChapter.kt index ecc00633f..3441a4ed4 100644 --- a/app/src/main/java/io/legado/app/data/entities/BookChapter.kt +++ b/app/src/main/java/io/legado/app/data/entities/BookChapter.kt @@ -6,6 +6,7 @@ import androidx.room.ForeignKey import androidx.room.Ignore import androidx.room.Index import io.legado.app.utils.GSON +import io.legado.app.utils.MD5Utils import io.legado.app.utils.NetworkUtils import io.legado.app.utils.fromJsonObject import kotlinx.android.parcel.IgnoredOnParcel @@ -62,5 +63,9 @@ data class BookChapter( fun getAbsoluteURL(): String { return NetworkUtils.getAbsoluteURL(baseUrl, url)!! } + + fun getFileName(): String = String.format("%05d-%s.nb", index, MD5Utils.md5Encode16(title)) + + fun getFontName(): String = String.format("%05d-%s.ttf", index, MD5Utils.md5Encode16(title)) } diff --git a/app/src/main/java/io/legado/app/data/entities/rule/ContentRule.kt b/app/src/main/java/io/legado/app/data/entities/rule/ContentRule.kt index ab6471dde..ed0d482cb 100644 --- a/app/src/main/java/io/legado/app/data/entities/rule/ContentRule.kt +++ b/app/src/main/java/io/legado/app/data/entities/rule/ContentRule.kt @@ -10,5 +10,6 @@ data class ContentRule( var webJs: String? = null, var sourceRegex: String? = null, var replaceRegex: String? = null, - var imageStyle: String? = null //默认大小居中,FULL最大宽度 + var imageStyle: String? = null, //默认大小居中,FULL最大宽度 + var font: String? = null //必须返回ByteArray ) : Parcelable \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/help/AppConfig.kt b/app/src/main/java/io/legado/app/help/AppConfig.kt index e2831a80f..a6064e855 100644 --- a/app/src/main/java/io/legado/app/help/AppConfig.kt +++ b/app/src/main/java/io/legado/app/help/AppConfig.kt @@ -134,5 +134,19 @@ object AppConfig { val changeSourceLoadInfo get() = App.INSTANCE.getPrefBoolean(PreferKey.changeSourceLoadToc) val changeSourceLoadToc get() = App.INSTANCE.getPrefBoolean(PreferKey.changeSourceLoadToc) + + val importKeepName get() = App.INSTANCE.getPrefBoolean(PreferKey.importKeepName) + + val clickActionTopLeft get() = App.INSTANCE.getPrefInt(PreferKey.clickActionTopLeft, 2) + val clickActionTopCenter get() = App.INSTANCE.getPrefInt(PreferKey.clickActionTopCenter, 2) + val clickActionTopRight get() = App.INSTANCE.getPrefInt(PreferKey.clickActionTopRight, 1) + val clickActionMiddleLeft get() = App.INSTANCE.getPrefInt(PreferKey.clickActionMiddleLeft, 2) + val clickActionMiddleCenter + get() = App.INSTANCE.getPrefInt(PreferKey.clickActionMiddleCenter, 0) + val clickActionMiddleRight get() = App.INSTANCE.getPrefInt(PreferKey.clickActionMiddleRight, 1) + val clickActionBottomLeft get() = App.INSTANCE.getPrefInt(PreferKey.clickActionBottomLeft, 2) + val clickActionBottomCenter + get() = App.INSTANCE.getPrefInt(PreferKey.clickActionBottomCenter, 1) + val clickActionBottomRight get() = App.INSTANCE.getPrefInt(PreferKey.clickActionBottomRight, 1) } 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 8b594b11f..a8c4235d4 100644 --- a/app/src/main/java/io/legado/app/help/BookHelp.kt +++ b/app/src/main/java/io/legado/app/help/BookHelp.kt @@ -31,14 +31,6 @@ object BookHelp { private val downloadDir: File = App.INSTANCE.externalFilesDir private val downloadImages = CopyOnWriteArraySet() - fun formatChapterName(bookChapter: BookChapter): String { - return String.format( - "%05d-%s.nb", - bookChapter.index, - MD5Utils.md5Encode16(bookChapter.title) - ) - } - fun clearCache() { FileUtils.deleteFile( FileUtils.getPath(downloadDir, cacheFolderName) @@ -75,7 +67,7 @@ object BookHelp { downloadDir, cacheFolderName, book.getFolderName(), - formatChapterName(bookChapter), + bookChapter.getFileName(), ).writeText(content) //保存图片 content.split("\n").forEach { @@ -91,6 +83,30 @@ object BookHelp { postEvent(EventBus.SAVE_CONTENT, bookChapter) } + fun saveFont(book: Book, bookChapter: BookChapter, font: ByteArray) { + FileUtils.createFileIfNotExist( + downloadDir, + cacheFolderName, + book.getFolderName(), + "font", + bookChapter.getFontName() + ).writeBytes(font) + } + + fun getFontPath(book: Book, bookChapter: BookChapter): String? { + val fontFile = FileUtils.getFile( + downloadDir, + cacheFolderName, + book.getFolderName(), + "font", + bookChapter.getFontName() + ) + if (fontFile.exists()) { + return fontFile.absolutePath + } + return null + } + suspend fun saveImage(book: Book, src: String) { while (downloadImages.contains(src)) { delay(100) @@ -158,7 +174,7 @@ object BookHelp { downloadDir, cacheFolderName, book.getFolderName(), - formatChapterName(bookChapter) + bookChapter.getFileName() ) } } @@ -171,7 +187,7 @@ object BookHelp { downloadDir, cacheFolderName, book.getFolderName(), - formatChapterName(bookChapter) + bookChapter.getFileName() ) if (file.exists()) { return file.readText() @@ -188,7 +204,7 @@ object BookHelp { downloadDir, cacheFolderName, book.getFolderName(), - formatChapterName(bookChapter) + bookChapter.getFileName() ).delete() } } 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 56d4f5d69..642905691 100644 --- a/app/src/main/java/io/legado/app/help/JsExtensions.kt +++ b/app/src/main/java/io/legado/app/help/JsExtensions.kt @@ -121,10 +121,10 @@ interface JsExtensions { .execute() } - /** - *js实现读取cookie - */ - fun getCookie(tag: String, key: String? = null): String { + /** + *js实现读取cookie + */ + fun getCookie(tag: String, key: String? = null): String { val cookie = CookieStore.getCookie(tag) val cookieMap = CookieStore.cookieToMap(cookie) return if (key != null) { @@ -132,7 +132,7 @@ interface JsExtensions { } else { cookie } - } + } /** * js实现解码,不能删 @@ -191,4 +191,19 @@ interface JsExtensions { fun htmlFormat(str: String): String { return str.htmlFormat() } + + fun base64DecodeToByteArray(str: String?): ByteArray? { + if (str.isNullOrBlank()) { + return null + } + return Base64.decode(str, Base64.DEFAULT) + } + + fun base64DecodeToByteArray(str: String?, flags: Int): ByteArray? { + if (str.isNullOrBlank()) { + return null + } + return Base64.decode(str, flags) + } + } diff --git a/app/src/main/java/io/legado/app/help/LocalConfig.kt b/app/src/main/java/io/legado/app/help/LocalConfig.kt new file mode 100644 index 000000000..11c9ce430 --- /dev/null +++ b/app/src/main/java/io/legado/app/help/LocalConfig.kt @@ -0,0 +1,56 @@ +package io.legado.app.help + +import android.content.Context +import androidx.core.content.edit +import io.legado.app.App + +object LocalConfig { + + private val localConfig = + App.INSTANCE.getSharedPreferences("local", Context.MODE_PRIVATE) + + val isFirstOpenApp: Boolean + get() { + val value = localConfig.getBoolean("firstOpen", true) + if (value) { + localConfig.edit { putBoolean("firstOpen", false) } + } + return value + } + + val isFirstRead: Boolean + get() { + val value = localConfig.getBoolean("firstRead", true) + if (value) { + localConfig.edit { putBoolean("firstRead", false) } + } + return value + } + + val isFirstOpenBackup: Boolean + get() { + val value = localConfig.getBoolean("firstBackup", true) + if (value) { + localConfig.edit { putBoolean("firstBackup", false) } + } + return value + } + + val isFirstReadMenuShow: Boolean + get() { + val value = localConfig.getBoolean("firstReadMenu", true) + if (value) { + localConfig.edit { putBoolean("firstReadMenu", false) } + } + return value + } + + val isFirstOpenBookSources: Boolean + get() { + val value = localConfig.getBoolean("firstOpenBookSources", true) + if (value) { + localConfig.edit { putBoolean("firstOpenBookSources", false) } + } + return value + } +} \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/help/ReadBookConfig.kt b/app/src/main/java/io/legado/app/help/ReadBookConfig.kt index 6b388742f..2303c414b 100644 --- a/app/src/main/java/io/legado/app/help/ReadBookConfig.kt +++ b/app/src/main/java/io/legado/app/help/ReadBookConfig.kt @@ -153,8 +153,6 @@ object ReadBookConfig { App.INSTANCE.putPrefBoolean(PreferKey.shareLayout, value) } } - val clickTurnPage get() = App.INSTANCE.getPrefBoolean(PreferKey.clickTurnPage, true) - val clickAllNext get() = App.INSTANCE.getPrefBoolean(PreferKey.clickAllNext, false) val textFullJustify get() = App.INSTANCE.getPrefBoolean(PreferKey.textFullJustify, true) val textBottomJustify get() = App.INSTANCE.getPrefBoolean(PreferKey.textBottomJustify, true) var hideStatusBar = App.INSTANCE.getPrefBoolean(PreferKey.hideStatusBar) diff --git a/app/src/main/java/io/legado/app/lib/dialogs/AlertBuilder.kt b/app/src/main/java/io/legado/app/lib/dialogs/AlertBuilder.kt index a938b3584..6a245e5fb 100644 --- a/app/src/main/java/io/legado/app/lib/dialogs/AlertBuilder.kt +++ b/app/src/main/java/io/legado/app/lib/dialogs/AlertBuilder.kt @@ -1,19 +1,3 @@ -/* - * Copyright 2016 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - @file:Suppress("NOTHING_TO_INLINE", "unused") package io.legado.app.lib.dialogs @@ -63,19 +47,34 @@ interface AlertBuilder { @Deprecated(NO_GETTER, level = ERROR) get fun positiveButton(buttonText: String, onClicked: ((dialog: DialogInterface) -> Unit)? = null) - fun positiveButton(@StringRes buttonTextResource: Int, onClicked: ((dialog: DialogInterface) -> Unit)? = null) + fun positiveButton( + @StringRes buttonTextResource: Int, + onClicked: ((dialog: DialogInterface) -> Unit)? = null + ) fun negativeButton(buttonText: String, onClicked: ((dialog: DialogInterface) -> Unit)? = null) - fun negativeButton(@StringRes buttonTextResource: Int, onClicked: ((dialog: DialogInterface) -> Unit)? = null) + fun negativeButton( + @StringRes buttonTextResource: Int, + onClicked: ((dialog: DialogInterface) -> Unit)? = null + ) fun neutralButton(buttonText: String, onClicked: ((dialog: DialogInterface) -> Unit)? = null) - fun neutralButton(@StringRes buttonTextResource: Int, onClicked: ((dialog: DialogInterface) -> Unit)? = null) + fun neutralButton( + @StringRes buttonTextResource: Int, + onClicked: ((dialog: DialogInterface) -> Unit)? = null + ) fun onCancelled(handler: (dialog: DialogInterface) -> Unit) fun onKeyPressed(handler: (dialog: DialogInterface, keyCode: Int, e: KeyEvent) -> Boolean) - fun items(items: List, onItemSelected: (dialog: DialogInterface, index: Int) -> Unit) + fun onDismiss(handler: (dialog: DialogInterface) -> Unit) + + fun items( + items: List, + onItemSelected: (dialog: DialogInterface, index: Int) -> Unit + ) + fun items( items: List, onItemSelected: (dialog: DialogInterface, item: T, index: Int) -> Unit @@ -95,24 +94,25 @@ interface AlertBuilder { fun build(): D fun show(): D -} -fun AlertBuilder<*>.customTitle(view: () -> View) { - customTitle = view() -} -fun AlertBuilder<*>.customView(view: () -> View) { - customView = view() -} + fun customTitle(view: () -> View) { + customTitle = view() + } + + fun customView(view: () -> View) { + customView = view() + } -inline fun AlertBuilder<*>.okButton(noinline handler: ((dialog: DialogInterface) -> Unit)? = null) = - positiveButton(android.R.string.ok, handler) + fun okButton(handler: ((dialog: DialogInterface) -> Unit)? = null) = + positiveButton(android.R.string.ok, handler) -inline fun AlertBuilder<*>.cancelButton(noinline handler: ((dialog: DialogInterface) -> Unit)? = null) = - negativeButton(android.R.string.cancel, handler) + fun cancelButton(handler: ((dialog: DialogInterface) -> Unit)? = null) = + negativeButton(android.R.string.cancel, handler) -inline fun AlertBuilder<*>.yesButton(noinline handler: ((dialog: DialogInterface) -> Unit)? = null) = - positiveButton(R.string.yes, handler) + fun yesButton(handler: ((dialog: DialogInterface) -> Unit)? = null) = + positiveButton(R.string.yes, handler) -inline fun AlertBuilder<*>.noButton(noinline handler: ((dialog: DialogInterface) -> Unit)? = null) = - negativeButton(R.string.no, handler) \ No newline at end of file + fun noButton(handler: ((dialog: DialogInterface) -> Unit)? = null) = + negativeButton(R.string.no, handler) +} diff --git a/app/src/main/java/io/legado/app/lib/dialogs/AndroidAlertBuilder.kt b/app/src/main/java/io/legado/app/lib/dialogs/AndroidAlertBuilder.kt index 9bfcab298..cf53eac12 100644 --- a/app/src/main/java/io/legado/app/lib/dialogs/AndroidAlertBuilder.kt +++ b/app/src/main/java/io/legado/app/lib/dialogs/AndroidAlertBuilder.kt @@ -1,19 +1,3 @@ -/* - * Copyright 2016 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - package io.legado.app.lib.dialogs import android.content.Context @@ -22,12 +6,11 @@ import android.graphics.drawable.Drawable import android.view.KeyEvent import android.view.View import androidx.appcompat.app.AlertDialog +import io.legado.app.utils.applyTint import org.jetbrains.anko.internals.AnkoInternals import org.jetbrains.anko.internals.AnkoInternals.NO_GETTER import kotlin.DeprecationLevel.ERROR -val Android: AlertBuilderFactory = ::AndroidAlertBuilder - internal class AndroidAlertBuilder(override val ctx: Context) : AlertBuilder { private val builder = AlertDialog.Builder(ctx) @@ -91,15 +74,28 @@ internal class AndroidAlertBuilder(override val ctx: Context) : AlertBuilder onClicked?.invoke(dialog) } } - override fun neutralButton(buttonText: String, onClicked: ((dialog: DialogInterface) -> Unit)?) { + override fun neutralButton( + buttonText: String, + onClicked: ((dialog: DialogInterface) -> Unit)? + ) { builder.setNeutralButton(buttonText) { dialog, _ -> onClicked?.invoke(dialog) } } - override fun neutralButton(buttonTextResource: Int, onClicked: ((dialog: DialogInterface) -> Unit)?) { + override fun neutralButton( + buttonTextResource: Int, + onClicked: ((dialog: DialogInterface) -> Unit)? + ) { builder.setNeutralButton(buttonTextResource) { dialog, _ -> onClicked?.invoke(dialog) } } - override fun items(items: List, onItemSelected: (dialog: DialogInterface, index: Int) -> Unit) { + override fun onDismiss(handler: (dialog: DialogInterface) -> Unit) { + builder.setOnDismissListener(handler) + } + + override fun items( + items: List, + onItemSelected: (dialog: DialogInterface, index: Int) -> Unit + ) { builder.setItems(Array(items.size) { i -> items[i].toString() }) { dialog, which -> onItemSelected(dialog, which) } @@ -136,5 +132,5 @@ internal class AndroidAlertBuilder(override val ctx: Context) : AlertBuilder JsonPath.parse(json) - else -> JsonPath.parse(json) + companion object { + private val jsonRulePattern = Pattern.compile("(?<=\\{)\\$\\..+?(?=\\})") + + fun parse(json: Any): ReadContext { + return when (json) { + is ReadContext -> json + is String -> JsonPath.parse(json) + else -> JsonPath.parse(json) + } } - return this } + private var ctx: ReadContext = parse(json) + fun getString(rule: String): String? { if (TextUtils.isEmpty(rule)) return null var result = "" @@ -210,7 +215,4 @@ class AnalyzeByJSonPath { return result } - companion object { - private val jsonRulePattern = Pattern.compile("(?<=\\{)\\$\\..+?(?=\\})") - } } 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 4976bc14a..b6d41ad76 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 @@ -17,22 +17,22 @@ import java.util.* * 书源规则解析 */ @Keep -class AnalyzeByJSoup { +class AnalyzeByJSoup(doc: Any) { companion object { val validKeys = arrayOf("class", "id", "tag", "text", "children") - } - - private lateinit var element: Element - fun parse(doc: Any): AnalyzeByJSoup { - element = when (doc) { - is Element -> doc - is JXNode -> if (doc.isElement) doc.asElement() else Jsoup.parse(doc.toString()) - else -> Jsoup.parse(doc.toString()) + fun parse(doc: Any): Element { + return when (doc) { + is Element -> doc + is JXNode -> if (doc.isElement) doc.asElement() else Jsoup.parse(doc.toString()) + else -> Jsoup.parse(doc.toString()) + } } - return this + } + private var element: Element = parse(doc) + /** * 获取列表 */ 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 db3e5129a..5954ccdf2 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 @@ -11,18 +11,17 @@ import org.seimicrawler.xpath.JXNode import java.util.* @Keep -class AnalyzeByXPath { - private lateinit var jxNode: Any +class AnalyzeByXPath(doc: Any) { + private var jxNode: Any = parse(doc) - fun parse(doc: Any): AnalyzeByXPath { - jxNode = when (doc) { + private fun parse(doc: Any): Any { + return when (doc) { is JXNode -> if (doc.isElement) doc else strToJXDocument(doc.toString()) is Document -> JXDocument.create(doc) is Element -> JXDocument.create(Elements(doc)) is Elements -> JXDocument.create(doc) else -> strToJXDocument(doc.toString()) } - return this } private fun strToJXDocument(html: String): JXDocument { 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 5296196ce..82b521292 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 @@ -65,17 +65,14 @@ class AnalyzeRule(var book: BaseBook? = null) : JsExtensions { */ private fun getAnalyzeByXPath(o: Any): AnalyzeByXPath { return if (o != content) { - AnalyzeByXPath().parse(o) - } else getAnalyzeByXPath() - } - - private fun getAnalyzeByXPath(): AnalyzeByXPath { - if (analyzeByXPath == null || objectChangedXP) { - analyzeByXPath = AnalyzeByXPath() - analyzeByXPath?.parse(content!!) - objectChangedXP = false + AnalyzeByXPath(o) + } else { + if (analyzeByXPath == null || objectChangedXP) { + analyzeByXPath = AnalyzeByXPath(content!!) + objectChangedXP = false + } + analyzeByXPath!! } - return analyzeByXPath as AnalyzeByXPath } /** @@ -83,17 +80,14 @@ class AnalyzeRule(var book: BaseBook? = null) : JsExtensions { */ private fun getAnalyzeByJSoup(o: Any): AnalyzeByJSoup { return if (o != content) { - AnalyzeByJSoup().parse(o) - } else getAnalyzeByJSoup() - } - - private fun getAnalyzeByJSoup(): AnalyzeByJSoup { - if (analyzeByJSoup == null || objectChangedJS) { - analyzeByJSoup = AnalyzeByJSoup() - analyzeByJSoup?.parse(content!!) - objectChangedJS = false + AnalyzeByJSoup(o) + } else { + if (analyzeByJSoup == null || objectChangedJS) { + analyzeByJSoup = AnalyzeByJSoup(content!!) + objectChangedJS = false + } + analyzeByJSoup!! } - return analyzeByJSoup as AnalyzeByJSoup } /** @@ -101,17 +95,14 @@ class AnalyzeRule(var book: BaseBook? = null) : JsExtensions { */ private fun getAnalyzeByJSonPath(o: Any): AnalyzeByJSonPath { return if (o != content) { - AnalyzeByJSonPath().parse(o) - } else getAnalyzeByJSonPath() - } - - private fun getAnalyzeByJSonPath(): AnalyzeByJSonPath { - if (analyzeByJSonPath == null || objectChangedJP) { - analyzeByJSonPath = AnalyzeByJSonPath() - analyzeByJSonPath?.parse(content!!) - objectChangedJP = false + AnalyzeByJSonPath(o) + } else { + if (analyzeByJSonPath == null || objectChangedJP) { + analyzeByJSonPath = AnalyzeByJSonPath(content!!) + objectChangedJP = false + } + analyzeByJSonPath!! } - return analyzeByJSonPath as AnalyzeByJSonPath } /** @@ -124,6 +115,7 @@ class AnalyzeRule(var book: BaseBook? = null) : JsExtensions { return getStringList(ruleList, isUrl) } + @JvmOverloads fun getStringList(ruleList: List, isUrl: Boolean = false): List? { var result: Any? = null val content = this.content @@ -181,6 +173,7 @@ class AnalyzeRule(var book: BaseBook? = null) : JsExtensions { /** * 获取文本 */ + @JvmOverloads fun getString(ruleStr: String?, isUrl: Boolean = false): String { if (TextUtils.isEmpty(ruleStr)) return "" val ruleList = splitSourceRule(ruleStr) @@ -302,6 +295,33 @@ class AnalyzeRule(var book: BaseBook? = null) : JsExtensions { return ArrayList() } + fun getByteArray(ruleStr: String): ByteArray? { + if (ruleStr.isEmpty()) return null + val ruleList = splitSourceRule(ruleStr) + var result: Any? = null + content?.let { o -> + if (ruleList.isNotEmpty()) result = o + for (sourceRule in ruleList) { + putRule(sourceRule.putMap) + result?.let { + result = when (sourceRule.mode) { + Mode.Regex -> AnalyzeByRegex.getElements( + result.toString(), + sourceRule.rule.splitNotBlank("&&") + ) + Mode.Js -> evalJS(sourceRule.rule, result) + Mode.Json -> getAnalyzeByJSonPath(it).getList(sourceRule.rule) + Mode.XPath -> getAnalyzeByXPath(it).getElements(sourceRule.rule) + else -> getAnalyzeByJSoup(it).getElements(sourceRule.rule) + } + if (sourceRule.replaceRegex.isNotEmpty()) { + result = replaceRegex(result.toString(), sourceRule) + } + } + } + } + return result as? ByteArray + } /** * 保存变量 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 b4650d9f5..60ef3b8d6 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 @@ -45,6 +45,7 @@ class AnalyzeUrl( headerMapF: Map? = null ) : JsExtensions { companion object { + private val splitUrlRegex = Regex(",\\s*(?=\\{)") private val pagePattern = Pattern.compile("<(.*?)>") private val jsonType = MediaType.parse("application/json; charset=utf-8") } @@ -59,7 +60,6 @@ class AnalyzeUrl( private var charset: String? = null private var requestBody: RequestBody? = null private var method = RequestMethod.GET - private val splitUrlRegex = Regex(",\\s*(?=\\{)") private var proxy: String? = null init { diff --git a/app/src/main/java/io/legado/app/model/webBook/BookContent.kt b/app/src/main/java/io/legado/app/model/webBook/BookContent.kt index 50b895ec7..4285b4a2e 100644 --- a/app/src/main/java/io/legado/app/model/webBook/BookContent.kt +++ b/app/src/main/java/io/legado/app/model/webBook/BookContent.kt @@ -6,6 +6,7 @@ import io.legado.app.data.entities.Book import io.legado.app.data.entities.BookChapter import io.legado.app.data.entities.BookSource import io.legado.app.data.entities.rule.ContentRule +import io.legado.app.help.BookHelp import io.legado.app.model.Debug import io.legado.app.model.analyzeRule.AnalyzeRule import io.legado.app.model.analyzeRule.AnalyzeUrl @@ -33,6 +34,14 @@ object BookContent { val content = StringBuilder() val nextUrlList = arrayListOf(baseUrl) val contentRule = bookSource.getContentRule() + contentRule.font?.let { + //todo 获取字体 + val analyzeRule = AnalyzeRule(book) + analyzeRule.setContent(body).setBaseUrl(baseUrl) + analyzeRule.getByteArray(it)?.let { font -> + BookHelp.saveFont(book, bookChapter, font) + } + } var contentData = analyzeContent( book, baseUrl, body, contentRule, bookChapter, bookSource ) @@ -54,12 +63,10 @@ object BookContent { ruleUrl = nextUrl, book = book, headerMapF = bookSource.getHeaderMap() - ).getResponseAwait(bookSource.bookSourceUrl) - .body?.let { nextBody -> - contentData = - analyzeContent( - book, nextUrl, nextBody, contentRule, bookChapter, bookSource, false - ) + ).getResponseAwait(bookSource.bookSourceUrl).body?.let { nextBody -> + contentData = analyzeContent( + book, nextUrl, nextBody, contentRule, bookChapter, bookSource, false + ) nextUrl = if (contentData.nextUrl.isNotEmpty()) contentData.nextUrl[0] else "" content.append(contentData.content).append("\n") @@ -78,14 +85,12 @@ object BookContent { ruleUrl = item.nextUrl, book = book, headerMapF = bookSource.getHeaderMap() - ).getResponseAwait(bookSource.bookSourceUrl) - .body?.let { - contentData = - analyzeContent( - book, item.nextUrl, it, contentRule, bookChapter, bookSource, false - ) - item.content = contentData.content - } + ).getResponseAwait(bookSource.bookSourceUrl).body?.let { + contentData = analyzeContent( + book, item.nextUrl, it, contentRule, bookChapter, bookSource, false + ) + item.content = contentData.content + } } } for (item in contentDataList) { @@ -105,6 +110,9 @@ object BookContent { Debug.log(bookSource.bookSourceUrl, "└${bookChapter.title}") Debug.log(bookSource.bookSourceUrl, "┌获取正文内容") Debug.log(bookSource.bookSourceUrl, "└\n$contentStr") + if (contentStr.isNotBlank()) { + BookHelp.saveContent(book, bookChapter, contentStr) + } return contentStr } diff --git a/app/src/main/java/io/legado/app/service/AudioPlayService.kt b/app/src/main/java/io/legado/app/service/AudioPlayService.kt index d629f2ba8..340395096 100644 --- a/app/src/main/java/io/legado/app/service/AudioPlayService.kt +++ b/app/src/main/java/io/legado/app/service/AudioPlayService.kt @@ -24,7 +24,6 @@ import io.legado.app.constant.EventBus import io.legado.app.constant.IntentAction import io.legado.app.constant.Status import io.legado.app.data.entities.BookChapter -import io.legado.app.help.BookHelp import io.legado.app.help.IntentHelp import io.legado.app.help.MediaHelp import io.legado.app.model.analyzeRule.AnalyzeUrl @@ -284,23 +283,25 @@ class AudioPlayService : BaseService(), } private fun loadContent(chapter: BookChapter) { - AudioPlay.book?.let { book -> - AudioPlay.webBook?.getContent(book, chapter, scope = this) - ?.onSuccess(IO) { content -> + val book = AudioPlay.book + val webBook = AudioPlay.webBook + if (book != null && webBook != null) { + webBook.getContent(book, chapter, scope = this@AudioPlayService) + .onSuccess { content -> + removeLoading(chapter.index) if (content.isEmpty()) { withContext(Main) { toast("未获取到资源链接") } - removeLoading(chapter.index) } else { - BookHelp.saveContent(book, chapter, content) contentLoadFinish(chapter, content) - removeLoading(chapter.index) } - }?.onError { + }.onError { contentLoadFinish(chapter, it.localizedMessage ?: toString()) removeLoading(chapter.index) } + } else { + toast("book or source is null") } } diff --git a/app/src/main/java/io/legado/app/service/CacheBookService.kt b/app/src/main/java/io/legado/app/service/CacheBookService.kt index 0ef8a2ea2..c0d7d0c98 100644 --- a/app/src/main/java/io/legado/app/service/CacheBookService.kt +++ b/app/src/main/java/io/legado/app/service/CacheBookService.kt @@ -20,7 +20,6 @@ import io.legado.app.help.coroutine.Coroutine import io.legado.app.model.webBook.WebBook import io.legado.app.service.help.CacheBook import io.legado.app.utils.postEvent -import kotlinx.coroutines.Dispatchers.IO import kotlinx.coroutines.asCoroutineDispatcher import kotlinx.coroutines.isActive import org.jetbrains.anko.toast @@ -197,8 +196,7 @@ class CacheBookService : BaseService() { CacheBook.addLog("getContentError${it.localizedMessage}") updateNotification("getContentError${it.localizedMessage}") } - .onSuccess(IO) { content -> - BookHelp.saveContent(book, bookChapter, content) + .onSuccess { synchronized(this@CacheBookService) { downloadCount[book.bookUrl]?.increaseSuccess() downloadCount[book.bookUrl]?.increaseFinished() @@ -221,7 +219,7 @@ class CacheBookService : BaseService() { downloadCount.remove(book.bookUrl) } } - }.onFinally(IO) { + }.onFinally { postDownloading(true) } } else { diff --git a/app/src/main/java/io/legado/app/service/help/CacheBook.kt b/app/src/main/java/io/legado/app/service/help/CacheBook.kt index 3e96bd616..1c69ac09c 100644 --- a/app/src/main/java/io/legado/app/service/help/CacheBook.kt +++ b/app/src/main/java/io/legado/app/service/help/CacheBook.kt @@ -7,11 +7,9 @@ import io.legado.app.R import io.legado.app.constant.IntentAction import io.legado.app.data.entities.Book import io.legado.app.data.entities.BookChapter -import io.legado.app.help.BookHelp import io.legado.app.model.webBook.WebBook import io.legado.app.service.CacheBookService import io.legado.app.utils.msg -import kotlinx.coroutines.Dispatchers.IO import java.util.concurrent.ConcurrentHashMap import java.util.concurrent.CopyOnWriteArraySet @@ -76,10 +74,7 @@ object CacheBook { } downloadMap[book.bookUrl]?.add(chapter.index) webBook.getContent(book, chapter) - .onSuccess(IO) { content -> - if (content.isNotBlank()) { - BookHelp.saveContent(book, chapter, content) - } + .onSuccess { content -> if (ReadBook.book?.bookUrl == book.bookUrl) { ReadBook.contentLoadFinish( book, diff --git a/app/src/main/java/io/legado/app/ui/about/AboutFragment.kt b/app/src/main/java/io/legado/app/ui/about/AboutFragment.kt index da1b22d60..68ff8d0fa 100644 --- a/app/src/main/java/io/legado/app/ui/about/AboutFragment.kt +++ b/app/src/main/java/io/legado/app/ui/about/AboutFragment.kt @@ -11,7 +11,6 @@ import io.legado.app.App import io.legado.app.R import io.legado.app.lib.dialogs.alert import io.legado.app.ui.widget.dialog.TextDialog -import io.legado.app.utils.applyTint import io.legado.app.utils.openUrl import io.legado.app.utils.sendMail import io.legado.app.utils.sendToClip @@ -85,7 +84,7 @@ class AboutFragment : PreferenceFragmentCompat() { } } } - }.show().applyTint() + }.show() } private fun joinQQGroup(key: String): Boolean { diff --git a/app/src/main/java/io/legado/app/ui/about/ReadRecordActivity.kt b/app/src/main/java/io/legado/app/ui/about/ReadRecordActivity.kt index e8e83ebf9..8e93743c7 100644 --- a/app/src/main/java/io/legado/app/ui/about/ReadRecordActivity.kt +++ b/app/src/main/java/io/legado/app/ui/about/ReadRecordActivity.kt @@ -9,9 +9,6 @@ import io.legado.app.base.adapter.ItemViewHolder import io.legado.app.base.adapter.SimpleRecyclerAdapter import io.legado.app.data.entities.ReadRecordShow import io.legado.app.lib.dialogs.alert -import io.legado.app.lib.dialogs.noButton -import io.legado.app.lib.dialogs.okButton -import io.legado.app.utils.applyTint import kotlinx.android.synthetic.main.activity_read_record.* import kotlinx.android.synthetic.main.item_read_record.* import kotlinx.android.synthetic.main.item_read_record.view.* @@ -41,7 +38,7 @@ class ReadRecordActivity : BaseActivity(R.layout.activity_read_record) { initData() } noButton() - }.show().applyTint() + }.show() } } @@ -83,7 +80,7 @@ class ReadRecordActivity : BaseActivity(R.layout.activity_read_record) { } } noButton() - }.show().applyTint() + }.show() } } } diff --git a/app/src/main/java/io/legado/app/ui/association/ImportBookSourceActivity.kt b/app/src/main/java/io/legado/app/ui/association/ImportBookSourceActivity.kt index 666916c7e..f31a8badc 100644 --- a/app/src/main/java/io/legado/app/ui/association/ImportBookSourceActivity.kt +++ b/app/src/main/java/io/legado/app/ui/association/ImportBookSourceActivity.kt @@ -1,38 +1,13 @@ package io.legado.app.ui.association -import android.annotation.SuppressLint -import android.content.Context -import android.content.DialogInterface import android.os.Bundle -import android.view.LayoutInflater -import android.view.MenuItem -import android.view.View -import android.view.ViewGroup -import androidx.appcompat.widget.Toolbar -import androidx.recyclerview.widget.LinearLayoutManager import io.legado.app.R -import io.legado.app.base.BaseDialogFragment import io.legado.app.base.VMBaseActivity -import io.legado.app.base.adapter.ItemViewHolder -import io.legado.app.base.adapter.SimpleRecyclerAdapter import io.legado.app.constant.Theme -import io.legado.app.data.entities.BookSource import io.legado.app.help.IntentDataHelp -import io.legado.app.help.SourceHelp import io.legado.app.lib.dialogs.alert -import io.legado.app.lib.dialogs.customView -import io.legado.app.lib.dialogs.noButton -import io.legado.app.lib.dialogs.okButton -import io.legado.app.ui.widget.text.AutoCompleteTextView -import io.legado.app.utils.applyTint -import io.legado.app.utils.getSize import io.legado.app.utils.getViewModel -import io.legado.app.utils.visible import kotlinx.android.synthetic.main.activity_translucence.* -import kotlinx.android.synthetic.main.dialog_edit_text.view.* -import kotlinx.android.synthetic.main.dialog_recycler_view.* -import kotlinx.android.synthetic.main.item_source_import.view.* -import org.jetbrains.anko.sdk27.listeners.onClick import org.jetbrains.anko.toast @@ -97,167 +72,14 @@ class ImportBookSourceActivity : VMBaseActivity( private fun errorDialog(msg: String) { alert(getString(R.string.error), msg) { okButton { } - }.show().applyTint().setOnDismissListener { - finish() - } - } - - private fun successDialog() { - val bundle = Bundle() - val allSourceKey = IntentDataHelp.putData(viewModel.allSources, "source") - bundle.putString("allSourceKey", allSourceKey) - val checkStatusKey = IntentDataHelp.putData(viewModel.sourceCheckState, "check") - bundle.putString("checkStatusKey", checkStatusKey) - val selectStatusKey = IntentDataHelp.putData(viewModel.selectStatus, "select") - bundle.putString("selectStatusKey", selectStatusKey) - SourcesDialog().apply { - arguments = bundle - }.show(supportFragmentManager, "SourceDialog") - } - - class SourcesDialog : BaseDialogFragment(), Toolbar.OnMenuItemClickListener { - - lateinit var adapter: SourcesAdapter - private var _groupName: String? = null - - override fun onStart() { - super.onStart() - val dm = requireActivity().getSize() - dialog?.window?.setLayout( - (dm.widthPixels * 0.9).toInt(), - ViewGroup.LayoutParams.WRAP_CONTENT - ) - } - - override fun onCreateView( - inflater: LayoutInflater, - container: ViewGroup?, - savedInstanceState: Bundle? - ): View? { - return inflater.inflate(R.layout.dialog_recycler_view, container) - } - - override fun onFragmentCreated(view: View, savedInstanceState: Bundle?) { - tool_bar.setTitle(R.string.import_book_source) - initMenu() - arguments?.let { - adapter = SourcesAdapter(requireContext()) - val allSources = - IntentDataHelp.getData>(it.getString("allSourceKey")) - adapter.sourceCheckState = - IntentDataHelp.getData>(it.getString("checkStatusKey"))!! - adapter.selectStatus = - IntentDataHelp.getData>(it.getString("selectStatusKey"))!! - - recycler_view.layoutManager = LinearLayoutManager(requireContext()) - recycler_view.adapter = adapter - adapter.setItems(allSources) - tv_cancel.visible() - tv_cancel.onClick { - dismiss() - } - tv_ok.visible() - tv_ok.onClick { - importSelect() - dismiss() - } + onDismiss { + finish() } - } - - private fun initMenu() { - tool_bar.setOnMenuItemClickListener(this) - tool_bar.inflateMenu(R.menu.import_source) - } - - @SuppressLint("InflateParams") - override fun onMenuItemClick(item: MenuItem): Boolean { - when (item.itemId) { - R.id.menu_new_group -> { - alert(R.string.diy_edit_source_group) { - var editText: AutoCompleteTextView? = null - customView { - layoutInflater.inflate(R.layout.dialog_edit_text, null).apply { - editText = edit_view - } - } - okButton { - editText?.text?.toString()?.let { group -> - _groupName = group - item.title = getString(R.string.diy_edit_source_group_title, _groupName) - } - } - noButton { } - }.show().applyTint() - } - R.id.menu_select_all -> { - adapter.selectStatus.forEachIndexed { index, b -> - if (!b) { - adapter.selectStatus[index] = true - } - } - adapter.notifyDataSetChanged() - } - R.id.menu_un_select_all -> { - adapter.selectStatus.forEachIndexed { index, b -> - if (b) { - adapter.selectStatus[index] = false - } - } - adapter.notifyDataSetChanged() - } - } - return false - } - - override fun onDismiss(dialog: DialogInterface) { - super.onDismiss(dialog) - activity?.finish() - } - - private fun importSelect() { - val selectSource = arrayListOf() - adapter.selectStatus.forEachIndexed { index, b -> - if (_groupName != null) { - adapter.getItem(index)!!.bookSourceGroup = _groupName - } - if (b) { - selectSource.add(adapter.getItem(index)!!) - } - } - SourceHelp.insertBookSource(*selectSource.toTypedArray()) - } - + }.show() } - class SourcesAdapter(context: Context) : - SimpleRecyclerAdapter(context, R.layout.item_source_import) { - - lateinit var sourceCheckState: ArrayList - lateinit var selectStatus: ArrayList - - override fun convert(holder: ItemViewHolder, item: BookSource, payloads: MutableList) { - holder.itemView.apply { - cb_source_name.isChecked = selectStatus[holder.layoutPosition] - cb_source_name.text = item.bookSourceName - tv_source_state.text = if (sourceCheckState[holder.layoutPosition]) { - "已存在" - } else { - "新书源" - } - - } - } - - override fun registerListener(holder: ItemViewHolder) { - holder.itemView.apply { - cb_source_name.setOnCheckedChangeListener { buttonView, isChecked -> - if (buttonView.isPressed) { - selectStatus[holder.layoutPosition] = isChecked - } - } - } - } - + private fun successDialog() { + ImportBookSourceDialog().show(supportFragmentManager, "SourceDialog") } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/association/ImportBookSourceDialog.kt b/app/src/main/java/io/legado/app/ui/association/ImportBookSourceDialog.kt new file mode 100644 index 000000000..ab667ffe2 --- /dev/null +++ b/app/src/main/java/io/legado/app/ui/association/ImportBookSourceDialog.kt @@ -0,0 +1,156 @@ +package io.legado.app.ui.association + +import android.annotation.SuppressLint +import android.content.Context +import android.content.DialogInterface +import android.os.Bundle +import android.view.LayoutInflater +import android.view.MenuItem +import android.view.View +import android.view.ViewGroup +import androidx.appcompat.widget.Toolbar +import androidx.recyclerview.widget.LinearLayoutManager +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.PreferKey +import io.legado.app.data.entities.BookSource +import io.legado.app.help.AppConfig +import io.legado.app.lib.dialogs.alert +import io.legado.app.ui.widget.text.AutoCompleteTextView +import io.legado.app.utils.getViewModelOfActivity +import io.legado.app.utils.putPrefBoolean +import io.legado.app.utils.visible +import kotlinx.android.synthetic.main.dialog_edit_text.view.* +import kotlinx.android.synthetic.main.dialog_recycler_view.* +import kotlinx.android.synthetic.main.item_source_import.view.* +import org.jetbrains.anko.sdk27.listeners.onClick + +/** + * 导入书源弹出窗口 + */ +class ImportBookSourceDialog : BaseDialogFragment(), Toolbar.OnMenuItemClickListener { + + val viewModel: ImportBookSourceViewModel + get() = getViewModelOfActivity(ImportBookSourceViewModel::class.java) + lateinit var adapter: SourcesAdapter + + override fun onStart() { + super.onStart() + dialog?.window?.setLayout( + ViewGroup.LayoutParams.MATCH_PARENT, + ViewGroup.LayoutParams.WRAP_CONTENT + ) + } + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + return inflater.inflate(R.layout.dialog_recycler_view, container) + } + + override fun onFragmentCreated(view: View, savedInstanceState: Bundle?) { + tool_bar.setTitle(R.string.import_book_source) + initMenu() + adapter = SourcesAdapter(requireContext()) + recycler_view.layoutManager = LinearLayoutManager(requireContext()) + recycler_view.adapter = adapter + adapter.setItems(viewModel.allSources) + tv_cancel.visible() + tv_cancel.onClick { + dismiss() + } + tv_ok.visible() + tv_ok.onClick { + viewModel.importSelect { + dismiss() + } + } + } + + private fun initMenu() { + tool_bar.setOnMenuItemClickListener(this) + tool_bar.inflateMenu(R.menu.import_source) + tool_bar.menu.findItem(R.id.menu_Keep_original_name)?.isChecked = AppConfig.importKeepName + } + + @SuppressLint("InflateParams") + override fun onMenuItemClick(item: MenuItem): Boolean { + when (item.itemId) { + R.id.menu_new_group -> { + alert(R.string.diy_edit_source_group) { + var editText: AutoCompleteTextView? = null + customView { + layoutInflater.inflate(R.layout.dialog_edit_text, null).apply { + editText = edit_view + } + } + okButton { + editText?.text?.toString()?.let { group -> + viewModel.groupName = group + item.title = getString(R.string.diy_edit_source_group_title, group) + } + } + noButton() + }.show() + } + R.id.menu_select_all -> { + viewModel.selectStatus.forEachIndexed { index, b -> + if (!b) { + viewModel.selectStatus[index] = true + } + } + adapter.notifyDataSetChanged() + } + R.id.menu_un_select_all -> { + viewModel.selectStatus.forEachIndexed { index, b -> + if (b) { + viewModel.selectStatus[index] = false + } + } + adapter.notifyDataSetChanged() + } + R.id.menu_Keep_original_name -> { + item.isChecked = !item.isChecked + putPrefBoolean(PreferKey.importKeepName, item.isChecked) + } + } + return false + } + + override fun onDismiss(dialog: DialogInterface) { + super.onDismiss(dialog) + activity?.finish() + } + + inner class SourcesAdapter(context: Context) : + SimpleRecyclerAdapter(context, R.layout.item_source_import) { + + override fun convert(holder: ItemViewHolder, item: BookSource, payloads: MutableList) { + holder.itemView.apply { + cb_source_name.isChecked = viewModel.selectStatus[holder.layoutPosition] + cb_source_name.text = item.bookSourceName + tv_source_state.text = if (viewModel.checkSources[holder.layoutPosition] != null) { + "已存在" + } else { + "新书源" + } + } + } + + override fun registerListener(holder: ItemViewHolder) { + holder.itemView.apply { + cb_source_name.setOnCheckedChangeListener { buttonView, isChecked -> + if (buttonView.isPressed) { + viewModel.selectStatus[holder.layoutPosition] = isChecked + } + } + } + } + + } + +} \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/association/ImportBookSourceViewModel.kt b/app/src/main/java/io/legado/app/ui/association/ImportBookSourceViewModel.kt index 6131d7bf4..431f1f8ea 100644 --- a/app/src/main/java/io/legado/app/ui/association/ImportBookSourceViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/association/ImportBookSourceViewModel.kt @@ -9,6 +9,8 @@ import io.legado.app.App import io.legado.app.R import io.legado.app.base.BaseViewModel import io.legado.app.data.entities.BookSource +import io.legado.app.help.AppConfig +import io.legado.app.help.SourceHelp import io.legado.app.help.http.HttpHelper import io.legado.app.help.storage.OldRule import io.legado.app.help.storage.Restore @@ -16,14 +18,41 @@ import io.legado.app.utils.* import java.io.File class ImportBookSourceViewModel(app: Application) : BaseViewModel(app) { - + var groupName: String? = null val errorLiveData = MutableLiveData() val successLiveData = MutableLiveData() val allSources = arrayListOf() - val sourceCheckState = arrayListOf() + val checkSources = arrayListOf() val selectStatus = arrayListOf() + + fun importSelect(finally: () -> Unit) { + execute { + val keepName = AppConfig.importKeepName + val selectSource = arrayListOf() + selectStatus.forEachIndexed { index, b -> + if (b) { + val source = allSources[index] + if (groupName != null) { + source.bookSourceGroup = groupName + } + if (keepName) { + checkSources[index]?.let { + source.bookSourceName = it.bookSourceName + source.bookSourceGroup = it.bookSourceGroup + } + } + selectSource.add(source) + } + } + SourceHelp.insertBookSource(*selectSource.toTypedArray()) + }.onFinally { + finally.invoke() + } + } + + fun importSourceFromFilePath(path: String) { execute { val content = if (path.isContentScheme()) { @@ -106,9 +135,9 @@ class ImportBookSourceViewModel(app: Application) : BaseViewModel(app) { private fun comparisonSource() { execute { allSources.forEach { - val has = App.db.bookSourceDao().getBookSource(it.bookSourceUrl) != null - sourceCheckState.add(has) - selectStatus.add(!has) + val has = App.db.bookSourceDao().getBookSource(it.bookSourceUrl) + checkSources.add(has) + selectStatus.add(has == null) } successLiveData.postValue(allSources.size) } diff --git a/app/src/main/java/io/legado/app/ui/association/ImportReplaceRuleActivity.kt b/app/src/main/java/io/legado/app/ui/association/ImportReplaceRuleActivity.kt index 12ae447d1..df4056854 100644 --- a/app/src/main/java/io/legado/app/ui/association/ImportReplaceRuleActivity.kt +++ b/app/src/main/java/io/legado/app/ui/association/ImportReplaceRuleActivity.kt @@ -8,9 +8,6 @@ import io.legado.app.constant.Theme import io.legado.app.data.entities.ReplaceRule import io.legado.app.help.IntentDataHelp import io.legado.app.lib.dialogs.alert -import io.legado.app.lib.dialogs.noButton -import io.legado.app.lib.dialogs.okButton -import io.legado.app.utils.applyTint import io.legado.app.utils.getViewModel import kotlinx.android.synthetic.main.activity_translucence.* import org.jetbrains.anko.toast @@ -76,9 +73,10 @@ class ImportReplaceRuleActivity : VMBaseActivity( private fun errorDialog(msg: String) { alert("导入出错", msg) { okButton { } - }.show().applyTint().setOnDismissListener { - finish() - } + onDismiss { + finish() + } + }.show() } private fun successDialog(allSource: ArrayList) { @@ -86,11 +84,10 @@ class ImportReplaceRuleActivity : VMBaseActivity( okButton { App.db.replaceRuleDao().insert(*allSource.toTypedArray()) } - noButton { - + noButton() + onDismiss { + finish() } - }.show().applyTint().setOnDismissListener { - finish() - } + }.show() } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/association/ImportRssSourceActivity.kt b/app/src/main/java/io/legado/app/ui/association/ImportRssSourceActivity.kt index 06c9d0155..722346e08 100644 --- a/app/src/main/java/io/legado/app/ui/association/ImportRssSourceActivity.kt +++ b/app/src/main/java/io/legado/app/ui/association/ImportRssSourceActivity.kt @@ -1,33 +1,13 @@ package io.legado.app.ui.association -import android.content.Context -import android.content.DialogInterface import android.os.Bundle -import android.view.LayoutInflater -import android.view.MenuItem -import android.view.View -import android.view.ViewGroup -import androidx.appcompat.widget.Toolbar -import androidx.recyclerview.widget.LinearLayoutManager import io.legado.app.R -import io.legado.app.base.BaseDialogFragment import io.legado.app.base.VMBaseActivity -import io.legado.app.base.adapter.ItemViewHolder -import io.legado.app.base.adapter.SimpleRecyclerAdapter import io.legado.app.constant.Theme -import io.legado.app.data.entities.RssSource import io.legado.app.help.IntentDataHelp -import io.legado.app.help.SourceHelp import io.legado.app.lib.dialogs.alert -import io.legado.app.lib.dialogs.okButton -import io.legado.app.utils.applyTint -import io.legado.app.utils.getSize import io.legado.app.utils.getViewModel -import io.legado.app.utils.visible import kotlinx.android.synthetic.main.activity_translucence.* -import kotlinx.android.synthetic.main.dialog_recycler_view.* -import kotlinx.android.synthetic.main.item_source_import.view.* -import org.jetbrains.anko.sdk27.listeners.onClick import org.jetbrains.anko.toast class ImportRssSourceActivity : VMBaseActivity( @@ -91,145 +71,14 @@ class ImportRssSourceActivity : VMBaseActivity( private fun errorDialog(msg: String) { alert(getString(R.string.error), msg) { okButton { } - }.show().applyTint().setOnDismissListener { - finish() - } - } - - private fun successDialog() { - val bundle = Bundle() - val allSourceKey = IntentDataHelp.putData(viewModel.allSources, "source") - bundle.putString("allSourceKey", allSourceKey) - val checkStatusKey = IntentDataHelp.putData(viewModel.sourceCheckState, "check") - bundle.putString("checkStatusKey", checkStatusKey) - val selectStatusKey = IntentDataHelp.putData(viewModel.selectStatus, "select") - bundle.putString("selectStatusKey", selectStatusKey) - SourcesDialog().apply { - arguments = bundle - }.show(supportFragmentManager, "SourceDialog") - } - - class SourcesDialog : BaseDialogFragment(), Toolbar.OnMenuItemClickListener { - - lateinit var adapter: SourcesAdapter - - override fun onStart() { - super.onStart() - val dm = requireActivity().getSize() - dialog?.window?.setLayout( - (dm.widthPixels * 0.9).toInt(), - ViewGroup.LayoutParams.WRAP_CONTENT - ) - } - - override fun onCreateView( - inflater: LayoutInflater, - container: ViewGroup?, - savedInstanceState: Bundle? - ): View? { - return inflater.inflate(R.layout.dialog_recycler_view, container) - } - - override fun onFragmentCreated(view: View, savedInstanceState: Bundle?) { - tool_bar.title = getString(R.string.import_rss_source) - initMenu() - arguments?.let { - adapter = SourcesAdapter(requireContext()) - val allSources = - IntentDataHelp.getData>(it.getString("allSourceKey")) - adapter.sourceCheckState = - IntentDataHelp.getData>(it.getString("checkStatusKey"))!! - adapter.selectStatus = - IntentDataHelp.getData>(it.getString("selectStatusKey"))!! - - recycler_view.layoutManager = LinearLayoutManager(requireContext()) - recycler_view.adapter = adapter - adapter.setItems(allSources) - tv_cancel.visible() - tv_cancel.onClick { - dismiss() - } - tv_ok.visible() - tv_ok.onClick { - importSelect() - dismiss() - } + onDismiss { + finish() } - } - - private fun initMenu() { - tool_bar.setOnMenuItemClickListener(this) - tool_bar.inflateMenu(R.menu.import_source) - } - - override fun onMenuItemClick(item: MenuItem): Boolean { - when (item.itemId) { - R.id.menu_select_all -> { - adapter.selectStatus.forEachIndexed { index, b -> - if (!b) { - adapter.selectStatus[index] = true - } - } - adapter.notifyDataSetChanged() - } - R.id.menu_un_select_all -> { - adapter.selectStatus.forEachIndexed { index, b -> - if (b) { - adapter.selectStatus[index] = false - } - } - adapter.notifyDataSetChanged() - } - } - return false - } - - override fun onDismiss(dialog: DialogInterface) { - super.onDismiss(dialog) - activity?.finish() - } - - private fun importSelect() { - val selectSource = arrayListOf() - adapter.selectStatus.forEachIndexed { index, b -> - if (b) { - selectSource.add(adapter.getItem(index)!!) - } - } - SourceHelp.insertRssSource(*selectSource.toTypedArray()) - } - + }.show() } - class SourcesAdapter(context: Context) : - SimpleRecyclerAdapter(context, R.layout.item_source_import) { - - lateinit var sourceCheckState: ArrayList - lateinit var selectStatus: ArrayList - - override fun convert(holder: ItemViewHolder, item: RssSource, payloads: MutableList) { - holder.itemView.apply { - cb_source_name.isChecked = selectStatus[holder.layoutPosition] - cb_source_name.text = item.sourceName - tv_source_state.text = if (sourceCheckState[holder.layoutPosition]) { - "已存在" - } else { - "新订阅源" - } - - } - } - - override fun registerListener(holder: ItemViewHolder) { - holder.itemView.apply { - cb_source_name.setOnCheckedChangeListener { buttonView, isChecked -> - if (buttonView.isPressed) { - selectStatus[holder.layoutPosition] = isChecked - } - } - } - } - + private fun successDialog() { + ImportRssSourceDialog().show(supportFragmentManager, "SourceDialog") } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/association/ImportRssSourceDialog.kt b/app/src/main/java/io/legado/app/ui/association/ImportRssSourceDialog.kt new file mode 100644 index 000000000..b3c53e5d5 --- /dev/null +++ b/app/src/main/java/io/legado/app/ui/association/ImportRssSourceDialog.kt @@ -0,0 +1,155 @@ +package io.legado.app.ui.association + +import android.annotation.SuppressLint +import android.content.Context +import android.content.DialogInterface +import android.os.Bundle +import android.view.LayoutInflater +import android.view.MenuItem +import android.view.View +import android.view.ViewGroup +import androidx.appcompat.widget.Toolbar +import androidx.recyclerview.widget.LinearLayoutManager +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.PreferKey +import io.legado.app.data.entities.RssSource +import io.legado.app.help.AppConfig +import io.legado.app.lib.dialogs.alert +import io.legado.app.ui.widget.text.AutoCompleteTextView +import io.legado.app.utils.getViewModelOfActivity +import io.legado.app.utils.putPrefBoolean +import io.legado.app.utils.visible +import kotlinx.android.synthetic.main.dialog_edit_text.view.* +import kotlinx.android.synthetic.main.dialog_recycler_view.* +import kotlinx.android.synthetic.main.item_source_import.view.* +import org.jetbrains.anko.sdk27.listeners.onClick + +/** + * 导入rss源弹出窗口 + */ +class ImportRssSourceDialog : BaseDialogFragment(), Toolbar.OnMenuItemClickListener { + + val viewModel: ImportRssSourceViewModel + get() = getViewModelOfActivity(ImportRssSourceViewModel::class.java) + lateinit var adapter: SourcesAdapter + + override fun onStart() { + super.onStart() + dialog?.window?.setLayout( + ViewGroup.LayoutParams.MATCH_PARENT, + ViewGroup.LayoutParams.WRAP_CONTENT + ) + } + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + return inflater.inflate(R.layout.dialog_recycler_view, container) + } + + override fun onFragmentCreated(view: View, savedInstanceState: Bundle?) { + tool_bar.setTitle(R.string.import_rss_source) + initMenu() + adapter = SourcesAdapter(requireContext()) + recycler_view.layoutManager = LinearLayoutManager(requireContext()) + recycler_view.adapter = adapter + adapter.setItems(viewModel.allSources) + tv_cancel.visible() + tv_cancel.onClick { + dismiss() + } + tv_ok.visible() + tv_ok.onClick { + viewModel.importSelect { + dismiss() + } + } + } + + private fun initMenu() { + tool_bar.setOnMenuItemClickListener(this) + tool_bar.inflateMenu(R.menu.import_source) + tool_bar.menu.findItem(R.id.menu_Keep_original_name)?.isChecked = AppConfig.importKeepName + } + + @SuppressLint("InflateParams") + override fun onMenuItemClick(item: MenuItem): Boolean { + when (item.itemId) { + R.id.menu_new_group -> { + alert(R.string.diy_edit_source_group) { + var editText: AutoCompleteTextView? = null + customView { + layoutInflater.inflate(R.layout.dialog_edit_text, null).apply { + editText = edit_view + } + } + okButton { + editText?.text?.toString()?.let { group -> + viewModel.groupName = group + item.title = getString(R.string.diy_edit_source_group_title, group) + } + } + noButton() + }.show() + } + R.id.menu_select_all -> { + viewModel.selectStatus.forEachIndexed { index, b -> + if (!b) { + viewModel.selectStatus[index] = true + } + } + adapter.notifyDataSetChanged() + } + R.id.menu_un_select_all -> { + viewModel.selectStatus.forEachIndexed { index, b -> + if (b) { + viewModel.selectStatus[index] = false + } + } + adapter.notifyDataSetChanged() + } + R.id.menu_Keep_original_name -> { + item.isChecked = !item.isChecked + putPrefBoolean(PreferKey.importKeepName, item.isChecked) + } + } + return false + } + + override fun onDismiss(dialog: DialogInterface) { + super.onDismiss(dialog) + activity?.finish() + } + + inner class SourcesAdapter(context: Context) : + SimpleRecyclerAdapter(context, R.layout.item_source_import) { + + override fun convert(holder: ItemViewHolder, item: RssSource, payloads: MutableList) { + holder.itemView.apply { + cb_source_name.isChecked = viewModel.selectStatus[holder.layoutPosition] + cb_source_name.text = item.sourceName + tv_source_state.text = if (viewModel.checkSources[holder.layoutPosition] != null) { + "已存在" + } else { + "新订阅源" + } + } + } + + override fun registerListener(holder: ItemViewHolder) { + holder.itemView.apply { + cb_source_name.setOnCheckedChangeListener { buttonView, isChecked -> + if (buttonView.isPressed) { + viewModel.selectStatus[holder.layoutPosition] = isChecked + } + } + } + } + } + +} \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/association/ImportRssSourceViewModel.kt b/app/src/main/java/io/legado/app/ui/association/ImportRssSourceViewModel.kt index f187a3195..d9574e735 100644 --- a/app/src/main/java/io/legado/app/ui/association/ImportRssSourceViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/association/ImportRssSourceViewModel.kt @@ -9,21 +9,48 @@ import io.legado.app.App import io.legado.app.R import io.legado.app.base.BaseViewModel import io.legado.app.data.entities.RssSource +import io.legado.app.help.AppConfig +import io.legado.app.help.SourceHelp import io.legado.app.help.http.HttpHelper import io.legado.app.help.storage.Restore import io.legado.app.utils.* import java.io.File class ImportRssSourceViewModel(app: Application) : BaseViewModel(app) { - + var groupName: String? = null val errorLiveData = MutableLiveData() val successLiveData = MutableLiveData() val allSources = arrayListOf() - val sourceCheckState = arrayListOf() + val checkSources = arrayListOf() val selectStatus = arrayListOf() + fun importSelect(finally: () -> Unit) { + execute { + val keepName = AppConfig.importKeepName + val selectSource = arrayListOf() + selectStatus.forEachIndexed { index, b -> + if (b) { + val source = allSources[index] + if (groupName != null) { + source.sourceGroup = groupName + } + if (keepName) { + checkSources[index]?.let { + source.sourceName = it.sourceName + source.sourceGroup = it.sourceGroup + } + } + selectSource.add(source) + } + } + SourceHelp.insertRssSource(*selectSource.toTypedArray()) + }.onFinally { + finally.invoke() + } + } + fun importSourceFromFilePath(path: String) { execute { val content = if (path.isContentScheme()) { @@ -101,9 +128,9 @@ class ImportRssSourceViewModel(app: Application) : BaseViewModel(app) { private fun comparisonSource() { execute { allSources.forEach { - val has = App.db.rssSourceDao().getByKey(it.sourceUrl) != null - sourceCheckState.add(has) - selectStatus.add(!has) + val has = App.db.rssSourceDao().getByKey(it.sourceUrl) + checkSources.add(has) + selectStatus.add(has == null) } successLiveData.postValue(allSources.size) } 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 4e890ca35..424387f10 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 @@ -20,8 +20,6 @@ import io.legado.app.data.entities.Book import io.legado.app.help.BlurTransformation import io.legado.app.help.ImageLoader import io.legado.app.lib.dialogs.alert -import io.legado.app.lib.dialogs.noButton -import io.legado.app.lib.dialogs.okButton import io.legado.app.service.AudioPlayService import io.legado.app.service.help.AudioPlay import io.legado.app.ui.book.changesource.ChangeSourceDialog @@ -150,14 +148,14 @@ class AudioPlayActivity : override fun finish() { AudioPlay.book?.let { if (!AudioPlay.inBookshelf) { - this.alert(title = getString(R.string.add_to_shelf)) { + alert(title = getString(R.string.add_to_shelf)) { message = getString(R.string.check_add_bookshelf, it.name) okButton { AudioPlay.inBookshelf = true setResult(Activity.RESULT_OK) } noButton { viewModel.removeFromBookshelf { super.finish() } } - }.show().applyTint() + }.show() } else { super.finish() } diff --git a/app/src/main/java/io/legado/app/ui/book/arrange/ArrangeBookActivity.kt b/app/src/main/java/io/legado/app/ui/book/arrange/ArrangeBookActivity.kt index a1f64b9a4..41288e054 100644 --- a/app/src/main/java/io/legado/app/ui/book/arrange/ArrangeBookActivity.kt +++ b/app/src/main/java/io/legado/app/ui/book/arrange/ArrangeBookActivity.kt @@ -15,8 +15,6 @@ import io.legado.app.constant.PreferKey import io.legado.app.data.entities.Book import io.legado.app.data.entities.BookGroup import io.legado.app.lib.dialogs.alert -import io.legado.app.lib.dialogs.noButton -import io.legado.app.lib.dialogs.okButton import io.legado.app.lib.theme.ATH import io.legado.app.ui.book.group.GroupManageDialog import io.legado.app.ui.book.group.GroupSelectDialog @@ -24,7 +22,6 @@ import io.legado.app.ui.widget.SelectActionBar import io.legado.app.ui.widget.recycler.DragSelectTouchHelper import io.legado.app.ui.widget.recycler.ItemTouchCallback import io.legado.app.ui.widget.recycler.VerticalDivider -import io.legado.app.utils.applyTint import io.legado.app.utils.getPrefInt import io.legado.app.utils.getViewModel import kotlinx.android.synthetic.main.activity_arrange_book.* @@ -149,8 +146,8 @@ class ArrangeBookActivity : VMBaseActivity(R.layout.activi R.id.menu_del_selection -> alert(titleResource = R.string.draw, messageResource = R.string.sure_del) { okButton { viewModel.deleteBook(*adapter.selectedBooks()) } - noButton { } - }.show().applyTint() + noButton() + }.show() R.id.menu_update_enable -> viewModel.upCanUpdate(adapter.selectedBooks(), true) R.id.menu_update_disable -> @@ -210,7 +207,7 @@ class ArrangeBookActivity : VMBaseActivity(R.layout.activi okButton { viewModel.deleteBook(book) } - }.show().applyTint() + }.show() } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/book/cache/CacheActivity.kt b/app/src/main/java/io/legado/app/ui/book/cache/CacheActivity.kt index d9cf476c1..c52aee6ba 100644 --- a/app/src/main/java/io/legado/app/ui/book/cache/CacheActivity.kt +++ b/app/src/main/java/io/legado/app/ui/book/cache/CacheActivity.kt @@ -151,7 +151,7 @@ class CacheActivity : VMBaseActivity(R.layout.activity_download) val chapterCaches = hashSetOf() val cacheNames = BookHelp.getChapterFiles(book) App.db.bookChapterDao().getChapterList(book.bookUrl).forEach { chapter -> - if (cacheNames.contains(BookHelp.formatChapterName(chapter))) { + if (cacheNames.contains(chapter.getFileName())) { chapterCaches.add(chapter.url) } } diff --git a/app/src/main/java/io/legado/app/ui/book/changesource/ChangeSourceViewModel.kt b/app/src/main/java/io/legado/app/ui/book/changesource/ChangeSourceViewModel.kt index 1ed25cdfe..4076db17c 100644 --- a/app/src/main/java/io/legado/app/ui/book/changesource/ChangeSourceViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/book/changesource/ChangeSourceViewModel.kt @@ -157,7 +157,7 @@ class ChangeSourceViewModel(application: Application) : BaseViewModel(applicatio webBook.getBookInfo(book, this) .onSuccess { if (context.getPrefBoolean(PreferKey.changeSourceLoadToc)) { - loadChapter(webBook, book) + loadBookToc(webBook, book) } else { //从详情页里获取最新章节 book.latestChapterTitle = it.latestChapterTitle @@ -169,7 +169,7 @@ class ChangeSourceViewModel(application: Application) : BaseViewModel(applicatio } } - private fun loadChapter(webBook: WebBook, book: Book) { + private fun loadBookToc(webBook: WebBook, book: Book) { webBook.getChapterList(book, this) .onSuccess(IO) { chapters -> if (chapters.isNotEmpty()) { diff --git a/app/src/main/java/io/legado/app/ui/book/group/GroupManageDialog.kt b/app/src/main/java/io/legado/app/ui/book/group/GroupManageDialog.kt index 19d5c973e..3fa1e9f45 100644 --- a/app/src/main/java/io/legado/app/ui/book/group/GroupManageDialog.kt +++ b/app/src/main/java/io/legado/app/ui/book/group/GroupManageDialog.kt @@ -114,7 +114,7 @@ class GroupManageDialog : BaseDialogFragment(), Toolbar.OnMenuItemClickListener } } noButton() - }.show().applyTint().requestInputMethod() + }.show().requestInputMethod() } @SuppressLint("InflateParams") @@ -133,7 +133,7 @@ class GroupManageDialog : BaseDialogFragment(), Toolbar.OnMenuItemClickListener viewModel.upGroup(bookGroup.copy(groupName = editText?.text?.toString() ?: "")) } noButton() - }.show().applyTint().requestInputMethod() + }.show().requestInputMethod() } private fun deleteGroup(bookGroup: BookGroup) { @@ -142,7 +142,7 @@ class GroupManageDialog : BaseDialogFragment(), Toolbar.OnMenuItemClickListener viewModel.delGroup(bookGroup) } noButton() - }.show().applyTint() + }.show() } private class GroupDiffCallBack( diff --git a/app/src/main/java/io/legado/app/ui/book/group/GroupSelectDialog.kt b/app/src/main/java/io/legado/app/ui/book/group/GroupSelectDialog.kt index ab9e9829a..92acaa125 100644 --- a/app/src/main/java/io/legado/app/ui/book/group/GroupSelectDialog.kt +++ b/app/src/main/java/io/legado/app/ui/book/group/GroupSelectDialog.kt @@ -20,9 +20,6 @@ import io.legado.app.base.adapter.ItemViewHolder import io.legado.app.base.adapter.SimpleRecyclerAdapter import io.legado.app.data.entities.BookGroup import io.legado.app.lib.dialogs.alert -import io.legado.app.lib.dialogs.customView -import io.legado.app.lib.dialogs.noButton -import io.legado.app.lib.dialogs.yesButton import io.legado.app.lib.theme.accentColor import io.legado.app.lib.theme.backgroundColor import io.legado.app.lib.theme.primaryColor @@ -139,7 +136,7 @@ class GroupSelectDialog : BaseDialogFragment(), Toolbar.OnMenuItemClickListener } } noButton() - }.show().applyTint().requestInputMethod() + }.show().requestInputMethod() } @SuppressLint("InflateParams") @@ -158,7 +155,7 @@ class GroupSelectDialog : BaseDialogFragment(), Toolbar.OnMenuItemClickListener viewModel.upGroup(bookGroup.copy(groupName = editText?.text?.toString() ?: "")) } noButton() - }.show().applyTint().requestInputMethod() + }.show().requestInputMethod() } private inner class GroupAdapter(context: Context) : 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 fca961485..bfa3e963d 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 @@ -65,6 +65,7 @@ class BookInfoActivity : scroll_view.setBackgroundColor(backgroundColor) fl_action.setBackgroundColor(bottomBackground) tv_shelf.setTextColor(getPrimaryTextColor(ColorUtils.isColorLight(bottomBackground))) + tv_toc.text = getString(R.string.toc_s, getString(R.string.loading)) viewModel.bookData.observe(this, { showBook(it) }) viewModel.chapterListData.observe(this, { upLoading(false, it) }) viewModel.initData(intent) @@ -136,7 +137,6 @@ class BookInfoActivity : 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)) tv_intro.text = book.getDisplayIntro() upTvBookshelf() val kinds = book.getKindList() 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 141c690fb..c0ff1d3cd 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 @@ -161,7 +161,7 @@ class BookInfoViewModel(application: Application) : BaseViewModel(application) { ) book.durChapterTitle = chapters[book.durChapterIndex].title if (inBookshelf) { - App.db.bookDao().insert(book) + App.db.bookDao().update(book) App.db.bookChapterDao().insert(*chapters.toTypedArray()) } bookData.postValue(book) diff --git a/app/src/main/java/io/legado/app/ui/book/local/ImportBookAdapter.kt b/app/src/main/java/io/legado/app/ui/book/local/ImportBookAdapter.kt index 1874d3c58..e0af905ba 100644 --- a/app/src/main/java/io/legado/app/ui/book/local/ImportBookAdapter.kt +++ b/app/src/main/java/io/legado/app/ui/book/local/ImportBookAdapter.kt @@ -113,7 +113,7 @@ class ImportBookAdapter(context: Context, val callBack: CallBack) : getItem(holder.layoutPosition)?.let { if (it.isDir) { callBack.nextDoc(it.uri) - } else if (!bookFileNames.contains(it.uri.toString())) { + } else if (!bookFileNames.contains(it.name)) { if (!selectedUris.contains(it.uri.toString())) { selectedUris.add(it.uri.toString()) } else { 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 5414ba3e8..dc155cd10 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 @@ -4,9 +4,6 @@ import android.annotation.SuppressLint import android.app.Activity import android.content.Intent import android.content.res.Configuration -import android.graphics.Color -import android.graphics.drawable.ColorDrawable -import android.net.Uri import android.os.Bundle import android.os.Handler import android.os.Looper @@ -18,21 +15,15 @@ import androidx.core.view.size import com.jaredrummler.android.colorpicker.ColorPickerDialogListener import io.legado.app.BuildConfig import io.legado.app.R -import io.legado.app.base.VMBaseActivity import io.legado.app.constant.EventBus import io.legado.app.constant.PreferKey import io.legado.app.constant.Status import io.legado.app.data.entities.Book 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.Backup 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 -import io.legado.app.lib.theme.ATH import io.legado.app.lib.theme.accentColor import io.legado.app.receiver.TimeBatteryReceiver import io.legado.app.service.BaseReadAloudService @@ -48,7 +39,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.searchContent.SearchContentActivity -import io.legado.app.ui.book.source.edit.BookSourceEditActivity import io.legado.app.ui.book.toc.ChapterListActivity import io.legado.app.ui.login.SourceLogin import io.legado.app.ui.replace.ReplaceRuleActivity @@ -63,12 +53,11 @@ import kotlinx.coroutines.Dispatchers.Main import kotlinx.coroutines.delay import kotlinx.coroutines.launch import kotlinx.coroutines.withContext -import org.jetbrains.anko.sdk27.listeners.onClick import org.jetbrains.anko.startActivity import org.jetbrains.anko.startActivityForResult import org.jetbrains.anko.toast -class ReadBookActivity : VMBaseActivity(R.layout.activity_book_read), +class ReadBookActivity : ReadBookBaseActivity(), View.OnTouchListener, PageView.CallBack, TextActionMenu.CallBack, @@ -81,21 +70,17 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_boo TocRegexDialog.CallBack, ColorPickerDialogListener { private val requestCodeChapterList = 568 - private val requestCodeEditSource = 111 private val requestCodeReplace = 312 private val requestCodeSearchResult = 123 private var menu: Menu? = null private var textActionMenu: TextActionMenu? = null - override val viewModel: ReadBookViewModel - get() = getViewModel(ReadBookViewModel::class.java) - override val scope: CoroutineScope get() = this override val isInitFinish: Boolean get() = viewModel.isInitFinish override val isScroll: Boolean get() = page_view.isScroll private val mHandler = Handler(Looper.getMainLooper()) private val keepScreenRunnable: Runnable = - Runnable { ReadBookActivityHelp.keepScreenOn(window, false) } + Runnable { keepScreenOn(window, false) } private val autoPageRunnable: Runnable = Runnable { autoPagePlus() } override var autoPageProgress = 0 override var isAutoPage = false @@ -105,15 +90,12 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_boo override val pageFactory: TextPageFactory get() = page_view.pageFactory override val headerHeight: Int get() = page_view.curPage.headerHeight - override fun onCreate(savedInstanceState: Bundle?) { - ReadBook.msg = null - ReadBookActivityHelp.setOrientation(this) - super.onCreate(savedInstanceState) - } - override fun onActivityCreated(savedInstanceState: Bundle?) { - ReadBookActivityHelp.upLayoutInDisplayCutoutMode(window) - initView() + super.onActivityCreated(savedInstanceState) + cursor_left.setColorFilter(accentColor) + cursor_right.setColorFilter(accentColor) + cursor_left.setOnTouchListener(this) + cursor_right.setOnTouchListener(this) upScreenTimeOut() ReadBook.callBack = this ReadBook.titleDate.observe(this) { @@ -157,55 +139,6 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_boo } } - override fun upNavigationBarColor() { - when { - read_menu == null -> return - read_menu.isVisible -> { - ATH.setNavigationBarColorAuto(this) - } - ReadBookConfig.bg is ColorDrawable -> { - ATH.setNavigationBarColorAuto(this, ReadBookConfig.bgMeanColor) - } - else -> { - ATH.setNavigationBarColorAuto(this, Color.BLACK) - } - } - } - - /** - * 初始化View - */ - private fun initView() { - cursor_left.setColorFilter(accentColor) - cursor_right.setColorFilter(accentColor) - cursor_left.setOnTouchListener(this) - cursor_right.setOnTouchListener(this) - tv_chapter_name.onClick { - ReadBook.webBook?.let { - startActivityForResult( - requestCodeEditSource, - Pair("data", it.bookSource.bookSourceUrl) - ) - } - } - tv_chapter_url.onClick { - runCatching { - val url = tv_chapter_url.text.toString() - val intent = Intent(Intent.ACTION_VIEW) - intent.data = Uri.parse(url) - startActivity(intent) - } - } - } - - fun showPaddingConfig() { - PaddingConfigDialog().show(supportFragmentManager, "paddingConfig") - } - - fun showBgTextConfig() { - BgTextConfigDialog().show(supportFragmentManager, "bgTextConfig") - } - override fun onCompatCreateOptionsMenu(menu: Menu): Boolean { menuInflater.inflate(R.menu.read_book, menu) return super.onCompatCreateOptionsMenu(menu) @@ -257,8 +190,8 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_boo viewModel.refreshContent(it) } } - R.id.menu_download -> ReadBookActivityHelp.showDownloadDialog(this) - R.id.menu_add_bookmark -> ReadBookActivityHelp.showBookMark(this) + R.id.menu_download -> showDownloadDialog() + R.id.menu_add_bookmark -> showBookMark() R.id.menu_copy_text -> TextDialog.show(supportFragmentManager, ReadBook.curTextChapter?.getContent()) R.id.menu_update_toc -> ReadBook.book?.let { @@ -267,14 +200,14 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_boo R.id.menu_enable_replace -> ReadBook.book?.let { it.setUseReplaceRule(!it.getUseReplaceRule()) menu?.findItem(R.id.menu_enable_replace)?.isChecked = it.getUseReplaceRule() - onReplaceRuleSave() + viewModel.replaceRuleChanged() } R.id.menu_re_segment -> ReadBook.book?.let { it.setReSegment(!it.getReSegment()) menu?.findItem(R.id.menu_re_segment)?.isChecked = it.getReSegment() ReadBook.loadContent(false) } - R.id.menu_page_anim -> ReadBookActivityHelp.showPageAnimConfig(this) { + R.id.menu_page_anim -> showPageAnimConfig { page_view.upPageAnim() } R.id.menu_book_info -> ReadBook.book?.let { @@ -293,7 +226,8 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_boo Pair("loginUrl", it.loginUrl) ) } - R.id.menu_set_charset -> ReadBookActivityHelp.showCharsetConfig(this) + R.id.menu_set_charset -> showCharsetConfig() + R.id.menu_help -> showReadMenuHelp() } return super.onCompatOptionsItemSelected(item) } @@ -324,13 +258,13 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_boo */ override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean { when { - ReadBookActivityHelp.isPrevKey(this, keyCode) -> { + isPrevKey(keyCode) -> { if (keyCode != KeyEvent.KEYCODE_UNKNOWN) { page_view.pageDelegate?.keyTurnPage(PageDelegate.Direction.PREV) return true } } - ReadBookActivityHelp.isNextKey(this, keyCode) -> { + isNextKey(keyCode) -> { if (keyCode != KeyEvent.KEYCODE_UNKNOWN) { page_view.pageDelegate?.keyTurnPage(PageDelegate.Direction.NEXT) return true @@ -622,7 +556,7 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_boo viewModel.changeTo(book) } - override fun clickCenter() { + override fun showActionMenu() { when { BaseReadAloudService.isRun -> { showReadAloudDialog() @@ -636,6 +570,11 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_boo } } + override fun showReadMenuHelp() { + val text = String(assets.open("help/readMenuHelp.md").readBytes()) + TextDialog.show(supportFragmentManager, text, TextDialog.MD) + } + /** * 显示朗读菜单 */ @@ -647,6 +586,7 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_boo * 自动翻页 */ override fun autoPage() { + ReadAloud.stop(this) if (isAutoPage) { autoPageStop() } else { @@ -666,14 +606,18 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_boo private fun autoPagePlus() { mHandler.removeCallbacks(autoPageRunnable) - autoPageProgress++ - if (autoPageProgress >= ReadBookConfig.autoReadSpeed * 10) { - autoPageProgress = 0 - page_view.fillPage(PageDelegate.Direction.NEXT) + if (page_view.isScroll) { + page_view.curPage.scroll(-page_view.height / ReadBookConfig.autoReadSpeed / 50) } else { - page_view.invalidate() + autoPageProgress++ + if (autoPageProgress >= ReadBookConfig.autoReadSpeed * 50) { + autoPageProgress = 0 + page_view.fillPage(PageDelegate.Direction.NEXT) + } else { + page_view.invalidate() + } } - mHandler.postDelayed(autoPageRunnable, 100) + mHandler.postDelayed(autoPageRunnable, 20) } /** @@ -708,16 +652,6 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_boo } } - /** - * 替换规则变化 - */ - private fun onReplaceRuleSave() { - Coroutine.async { - BookHelp.upReplaceRules() - ReadBook.loadContent(resetPageOffset = false) - } - } - /** * 显示阅读样式配置 */ @@ -736,7 +670,7 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_boo * 更新状态栏,导航栏 */ override fun upSystemUiVisibility() { - ReadBookActivityHelp.upSystemUiVisibility(this, isInMultiWindow, !read_menu.isVisible) + upSystemUiVisibility(isInMultiWindow, !read_menu.isVisible) upNavigationBarColor() } @@ -744,6 +678,7 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_boo * 朗读按钮 */ override fun onClickReadAloud() { + autoPageStop() when { !BaseReadAloudService.isRun -> ReadBook.readAloud() BaseReadAloudService.pause -> ReadAloud.resume(this) @@ -784,7 +719,6 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_boo super.onActivityResult(requestCode, resultCode, data) if (resultCode == Activity.RESULT_OK) { when (requestCode) { - requestCodeEditSource -> viewModel.upBookSource() requestCodeChapterList -> data?.getIntExtra("index", ReadBook.durChapterIndex)?.let { index -> if (index != ReadBook.durChapterIndex) { @@ -840,23 +774,22 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_boo } } } - requestCodeReplace -> onReplaceRuleSave() + requestCodeReplace -> viewModel.replaceRuleChanged() } - } } override fun finish() { ReadBook.book?.let { if (!ReadBook.inBookshelf) { - this.alert(title = getString(R.string.add_to_shelf)) { + alert(title = getString(R.string.add_to_shelf)) { message = getString(R.string.check_add_bookshelf, it.name) okButton { ReadBook.inBookshelf = true setResult(Activity.RESULT_OK) } noButton { viewModel.removeFromBookshelf { super.finish() } } - }.show().applyTint() + }.show() } else { super.finish() } @@ -934,7 +867,7 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_boo read_menu.upBrightnessState() } observeEvent(EventBus.REPLACE_RULE_SAVE) { - onReplaceRuleSave() + viewModel.replaceRuleChanged() } } @@ -950,16 +883,16 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_boo */ override fun screenOffTimerStart() { if (screenTimeOut < 0) { - ReadBookActivityHelp.keepScreenOn(window, true) + keepScreenOn(window, true) return } val t = screenTimeOut - sysScreenOffTime if (t > 0) { mHandler.removeCallbacks(keepScreenRunnable) - ReadBookActivityHelp.keepScreenOn(window, true) + keepScreenOn(window, true) mHandler.postDelayed(keepScreenRunnable, screenTimeOut) } else { - ReadBookActivityHelp.keepScreenOn(window, false) + keepScreenOn(window, false) } } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/book/read/ReadBookActivityHelp.kt b/app/src/main/java/io/legado/app/ui/book/read/ReadBookBaseActivity.kt similarity index 62% rename from app/src/main/java/io/legado/app/ui/book/read/ReadBookActivityHelp.kt rename to app/src/main/java/io/legado/app/ui/book/read/ReadBookBaseActivity.kt index 6d2baa4ce..dbfdc8807 100644 --- a/app/src/main/java/io/legado/app/ui/book/read/ReadBookActivityHelp.kt +++ b/app/src/main/java/io/legado/app/ui/book/read/ReadBookBaseActivity.kt @@ -2,45 +2,134 @@ package io.legado.app.ui.book.read import android.annotation.SuppressLint import android.app.Activity -import android.content.Context +import android.content.Intent import android.content.pm.ActivityInfo +import android.graphics.Color +import android.graphics.drawable.ColorDrawable +import android.net.Uri import android.os.Build +import android.os.Bundle import android.view.* import android.widget.EditText +import androidx.core.view.isVisible import io.legado.app.App import io.legado.app.R +import io.legado.app.base.VMBaseActivity import io.legado.app.constant.PreferKey import io.legado.app.data.entities.Bookmark import io.legado.app.help.AppConfig +import io.legado.app.help.LocalConfig import io.legado.app.help.ReadBookConfig import io.legado.app.help.coroutine.Coroutine import io.legado.app.lib.dialogs.* import io.legado.app.lib.theme.ATH import io.legado.app.lib.theme.ThemeStore import io.legado.app.lib.theme.backgroundColor +import io.legado.app.lib.theme.bottomBackground import io.legado.app.service.help.CacheBook import io.legado.app.service.help.ReadBook +import io.legado.app.ui.book.read.config.BgTextConfigDialog +import io.legado.app.ui.book.read.config.ClickActionConfigDialog +import io.legado.app.ui.book.read.config.PaddingConfigDialog +import io.legado.app.ui.book.source.edit.BookSourceEditActivity import io.legado.app.ui.widget.text.AutoCompleteTextView -import io.legado.app.utils.applyTint import io.legado.app.utils.getPrefString +import io.legado.app.utils.getViewModel import io.legado.app.utils.requestInputMethod +import kotlinx.android.synthetic.main.activity_book_read.* import kotlinx.android.synthetic.main.dialog_download_choice.view.* import kotlinx.android.synthetic.main.dialog_edit_text.view.* -import org.jetbrains.anko.layoutInflater +import kotlinx.android.synthetic.main.view_read_menu.* +import org.jetbrains.anko.sdk27.listeners.onClick +import org.jetbrains.anko.startActivityForResult +abstract class ReadBookBaseActivity : + VMBaseActivity(R.layout.activity_book_read) { -object ReadBookActivityHelp { + override val viewModel: ReadBookViewModel + get() = getViewModel(ReadBookViewModel::class.java) + private val requestCodeEditSource = 111 + var bottomDialog = 0 + + override fun onCreate(savedInstanceState: Bundle?) { + ReadBook.msg = null + setOrientation() + upLayoutInDisplayCutoutMode() + super.onCreate(savedInstanceState) + } + + override fun onActivityCreated(savedInstanceState: Bundle?) { + initView() + if (LocalConfig.isFirstRead) { + showClickRegionalConfig() + } + } + + /** + * 初始化View + */ + private fun initView() { + tv_chapter_name.onClick { + ReadBook.webBook?.let { + startActivityForResult( + requestCodeEditSource, + Pair("data", it.bookSource.bookSourceUrl) + ) + } + } + tv_chapter_url.onClick { + runCatching { + val url = tv_chapter_url.text.toString() + val intent = Intent(Intent.ACTION_VIEW) + intent.data = Uri.parse(url) + startActivity(intent) + } + } + } + + override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { + super.onActivityResult(requestCode, resultCode, data) + if (resultCode == Activity.RESULT_OK) { + when (requestCode) { + requestCodeEditSource -> viewModel.upBookSource() + } + } + } + + fun showPaddingConfig() { + PaddingConfigDialog().show(supportFragmentManager, "paddingConfig") + } + + fun showBgTextConfig() { + BgTextConfigDialog().show(supportFragmentManager, "bgTextConfig") + } + + fun showClickRegionalConfig() { + ClickActionConfigDialog().show(supportFragmentManager, "clickActionConfig") + } + + /** + * 屏幕方向 + */ + @SuppressLint("SourceLockedOrientationActivity") + fun setOrientation() { + when (AppConfig.requestedDirection) { + "0" -> requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED + "1" -> requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT + "2" -> requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE + "3" -> requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_SENSOR + } + } /** * 更新状态栏,导航栏 */ fun upSystemUiVisibility( - activity: Activity, isInMultiWindow: Boolean, toolBarHide: Boolean = true ) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { - activity.window.insetsController?.let { + window.insetsController?.let { if (toolBarHide) { if (ReadBookConfig.hideStatusBar) { it.hide(WindowInsets.Type.statusBars()) @@ -54,20 +143,19 @@ object ReadBookActivityHelp { } } } - upSystemUiVisibilityO(activity, isInMultiWindow, toolBarHide) + upSystemUiVisibilityO(isInMultiWindow, toolBarHide) if (toolBarHide) { - ATH.setLightStatusBar(activity, ReadBookConfig.durConfig.curStatusIconDark()) + ATH.setLightStatusBar(this, ReadBookConfig.durConfig.curStatusIconDark()) } else { ATH.setLightStatusBarAuto( - activity, - ThemeStore.statusBarColor(activity, AppConfig.isTransparentStatusBar) + this, + ThemeStore.statusBarColor(this, AppConfig.isTransparentStatusBar) ) } } @Suppress("DEPRECATION") private fun upSystemUiVisibilityO( - activity: Activity, isInMultiWindow: Boolean, toolBarHide: Boolean = true ) { @@ -88,23 +176,23 @@ object ReadBookActivityHelp { flag = flag or View.SYSTEM_UI_FLAG_HIDE_NAVIGATION } } - activity.window.decorView.systemUiVisibility = flag + window.decorView.systemUiVisibility = flag } - /** - * 屏幕方向 - */ - @SuppressLint("SourceLockedOrientationActivity") - fun setOrientation(activity: Activity) = activity.apply { - when (AppConfig.requestedDirection) { - "0" -> requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED - "1" -> requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT - "2" -> requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE - "3" -> requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_SENSOR + override fun upNavigationBarColor() { + when { + read_menu == null -> return + read_menu.isVisible -> ATH.setNavigationBarColorAuto(this) + bottomDialog > 0 -> ATH.setNavigationBarColorAuto(this, bottomBackground) + ReadBookConfig.bg is ColorDrawable -> { + ATH.setNavigationBarColorAuto(this, ReadBookConfig.bgMeanColor) + } + else -> { + ATH.setNavigationBarColorAuto(this, Color.BLACK) + } } } - /** * 保持亮屏 */ @@ -119,7 +207,7 @@ object ReadBookActivityHelp { /** * 适配刘海 */ - fun upLayoutInDisplayCutoutMode(window: Window) { + private fun upLayoutInDisplayCutoutMode() { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P && AppConfig.readBodyToLh) { window.attributes = window.attributes.apply { layoutInDisplayCutoutMode = @@ -129,12 +217,13 @@ object ReadBookActivityHelp { } @SuppressLint("InflateParams") - fun showDownloadDialog(context: Context) { + fun showDownloadDialog() { ReadBook.book?.let { book -> - context.alert(titleResource = R.string.offline_cache) { + alert(titleResource = R.string.offline_cache) { var view: View? = null customView { - LayoutInflater.from(context).inflate(R.layout.dialog_download_choice, null) + LayoutInflater.from(this@ReadBookBaseActivity) + .inflate(R.layout.dialog_download_choice, null) .apply { view = this setBackgroundColor(context.backgroundColor) @@ -150,15 +239,15 @@ object ReadBookActivityHelp { } } noButton() - }.show().applyTint() + }.show() } } @SuppressLint("InflateParams") - fun showBookMark(context: Context) = with(context) { + fun showBookMark() { val book = ReadBook.book ?: return val textChapter = ReadBook.curTextChapter ?: return - context.alert(title = getString(R.string.bookmark_add)) { + alert(title = getString(R.string.bookmark_add)) { var editText: EditText? = null message = book.name + " • " + textChapter.title customView { @@ -184,11 +273,11 @@ object ReadBookActivityHelp { } } noButton() - }.show().applyTint().requestInputMethod() + }.show().requestInputMethod() } @SuppressLint("InflateParams") - fun showCharsetConfig(context: Context) = with(context) { + fun showCharsetConfig() { val charsets = arrayListOf("UTF-8", "GB2312", "GBK", "Unicode", "UTF-16", "UTF-16LE", "ASCII") alert(R.string.set_charset) { @@ -207,10 +296,10 @@ object ReadBookActivityHelp { } } cancelButton() - }.show().applyTint() + }.show() } - fun showPageAnimConfig(context: Context, success: () -> Unit) = with(context) { + fun showPageAnimConfig(success: () -> Unit) { val items = arrayListOf() items.add(getString(R.string.btn_default_s)) items.add(getString(R.string.page_anim_cover)) @@ -224,13 +313,13 @@ object ReadBookActivityHelp { } } - fun isPrevKey(context: Context, keyCode: Int): Boolean { - val prevKeysStr = context.getPrefString(PreferKey.prevKeys) + fun isPrevKey(keyCode: Int): Boolean { + val prevKeysStr = getPrefString(PreferKey.prevKeys) return prevKeysStr?.split(",")?.contains(keyCode.toString()) ?: false } - fun isNextKey(context: Context, keyCode: Int): Boolean { - val nextKeysStr = context.getPrefString(PreferKey.nextKeys) + fun isNextKey(keyCode: Int): Boolean { + val nextKeysStr = getPrefString(PreferKey.nextKeys) return nextKeysStr?.split(",")?.contains(keyCode.toString()) ?: false } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/book/read/ReadBookViewModel.kt b/app/src/main/java/io/legado/app/ui/book/read/ReadBookViewModel.kt index 648e9d483..64087032b 100644 --- a/app/src/main/java/io/legado/app/ui/book/read/ReadBookViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/book/read/ReadBookViewModel.kt @@ -271,6 +271,16 @@ class ReadBookViewModel(application: Application) : BaseViewModel(application) { } } + /** + * 替换规则变化 + */ + fun replaceRuleChanged() { + execute { + BookHelp.upReplaceRules() + ReadBook.loadContent(resetPageOffset = false) + } + } + override fun onCleared() { super.onCleared() if (BaseReadAloudService.pause) { diff --git a/app/src/main/java/io/legado/app/ui/book/read/ReadMenu.kt b/app/src/main/java/io/legado/app/ui/book/read/ReadMenu.kt index d1480ac81..b349fe629 100644 --- a/app/src/main/java/io/legado/app/ui/book/read/ReadMenu.kt +++ b/app/src/main/java/io/legado/app/ui/book/read/ReadMenu.kt @@ -13,6 +13,7 @@ import io.legado.app.App import io.legado.app.R import io.legado.app.constant.PreferKey import io.legado.app.help.AppConfig +import io.legado.app.help.LocalConfig import io.legado.app.help.ReadBookConfig import io.legado.app.lib.theme.* import io.legado.app.service.help.ReadBook @@ -29,7 +30,7 @@ class ReadMenu @JvmOverloads constructor( attrs: AttributeSet? = null ) : FrameLayout(context, attrs) { var cnaShowMenu: Boolean = false - private val callBack: CallBack? get() = activity as? CallBack + private val callBack: CallBack get() = activity as CallBack private lateinit var menuTopIn: Animation private lateinit var menuTopOut: Animation private lateinit var menuBottomIn: Animation @@ -166,19 +167,19 @@ class ReadMenu @JvmOverloads constructor( //搜索 fabSearch.onClick { runMenuOut { - callBack?.openSearchActivity(null) + callBack.openSearchActivity(null) } } //自动翻页 fabAutoPage.onClick { runMenuOut { - callBack?.autoPage() + callBack.autoPage() } } //替换 - fabReplaceRule.onClick { callBack?.openReplaceRule() } + fabReplaceRule.onClick { callBack.openReplaceRule() } //夜间模式 fabNightTheme.onClick { @@ -195,31 +196,31 @@ class ReadMenu @JvmOverloads constructor( //目录 ll_catalog.onClick { runMenuOut { - callBack?.openChapterList() + callBack.openChapterList() } } //朗读 ll_read_aloud.onClick { runMenuOut { - callBack?.onClickReadAloud() + callBack.onClickReadAloud() } } ll_read_aloud.onLongClick { - runMenuOut { callBack?.showReadAloudDialog() } + runMenuOut { callBack.showReadAloudDialog() } true } //界面 ll_font.onClick { runMenuOut { - callBack?.showReadStyle() + callBack.showReadStyle() } } //设置 ll_setting.onClick { runMenuOut { - callBack?.showMoreSetting() + callBack.showMoreSetting() } } } @@ -230,19 +231,19 @@ class ReadMenu @JvmOverloads constructor( menuBottomIn = AnimationUtilsSupport.loadAnimation(context, R.anim.anim_readbook_bottom_in) menuTopIn.setAnimationListener(object : Animation.AnimationListener { override fun onAnimationStart(animation: Animation) { - callBack?.upSystemUiVisibility() + callBack.upSystemUiVisibility() ll_brightness.visible(showBrightnessView) } override fun onAnimationEnd(animation: Animation) { vw_menu_bg.onClick { runMenuOut() } + val hasNavigationBar = ReadBookConfig.hideNavigationBar + && SystemUtils.isNavigationBarExist(activity) vwNavigationBar.layoutParams = vwNavigationBar.layoutParams.apply { - height = - if (ReadBookConfig.hideNavigationBar - && SystemUtils.isNavigationBarExist(activity) - ) - context.navigationBarHeight - else 0 + height = if (hasNavigationBar) context.navigationBarHeight else 0 + } + if (LocalConfig.isFirstReadMenuShow) { + callBack.showReadMenuHelp() } } @@ -264,7 +265,7 @@ class ReadMenu @JvmOverloads constructor( bottom_menu.invisible() cnaShowMenu = false onMenuOutEnd?.invoke() - callBack?.upSystemUiVisibility() + callBack.upSystemUiVisibility() } override fun onAnimationRepeat(animation: Animation) = Unit @@ -292,6 +293,7 @@ class ReadMenu @JvmOverloads constructor( fun showReadAloudDialog() fun upSystemUiVisibility() fun onClickReadAloud() + fun showReadMenuHelp() } } diff --git a/app/src/main/java/io/legado/app/ui/book/read/config/AutoReadDialog.kt b/app/src/main/java/io/legado/app/ui/book/read/config/AutoReadDialog.kt index fd2ef2151..9ec107b92 100644 --- a/app/src/main/java/io/legado/app/ui/book/read/config/AutoReadDialog.kt +++ b/app/src/main/java/io/legado/app/ui/book/read/config/AutoReadDialog.kt @@ -1,5 +1,6 @@ package io.legado.app.ui.book.read.config +import android.content.DialogInterface import android.os.Bundle import android.view.* import android.widget.SeekBar @@ -10,6 +11,7 @@ import io.legado.app.lib.theme.bottomBackground import io.legado.app.lib.theme.getPrimaryTextColor import io.legado.app.service.BaseReadAloudService import io.legado.app.service.help.ReadAloud +import io.legado.app.ui.book.read.ReadBookActivity import io.legado.app.utils.ColorUtils import kotlinx.android.synthetic.main.dialog_auto_read.* import org.jetbrains.anko.sdk27.listeners.onClick @@ -19,6 +21,7 @@ class AutoReadDialog : BaseDialogFragment() { override fun onStart() { super.onStart() + (activity as ReadBookActivity).bottomDialog++ dialog?.window?.let { it.clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND) it.setBackgroundDrawableResource(R.color.background) @@ -31,6 +34,11 @@ class AutoReadDialog : BaseDialogFragment() { } } + override fun onDismiss(dialog: DialogInterface) { + super.onDismiss(dialog) + (activity as ReadBookActivity).bottomDialog-- + } + override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, 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 3e99b8b08..99b8db65d 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 @@ -17,7 +17,7 @@ import io.legado.app.help.ReadBookConfig import io.legado.app.help.http.HttpHelper import io.legado.app.help.permission.Permissions import io.legado.app.help.permission.PermissionsCompat -import io.legado.app.lib.dialogs.* +import io.legado.app.lib.dialogs.alert import io.legado.app.lib.theme.bottomBackground import io.legado.app.lib.theme.getPrimaryTextColor import io.legado.app.lib.theme.getSecondaryTextColor @@ -50,6 +50,7 @@ class BgTextConfigDialog : BaseDialogFragment(), FilePickerDialog.CallBack { override fun onStart() { super.onStart() + (activity as ReadBookActivity).bottomDialog++ dialog?.window?.let { it.clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND) it.setBackgroundDrawableResource(R.color.background) @@ -79,6 +80,7 @@ class BgTextConfigDialog : BaseDialogFragment(), FilePickerDialog.CallBack { override fun onDismiss(dialog: DialogInterface) { super.onDismiss(dialog) ReadBookConfig.save() + (activity as ReadBookActivity).bottomDialog-- } private fun initView() { @@ -131,7 +133,7 @@ class BgTextConfigDialog : BaseDialogFragment(), FilePickerDialog.CallBack { } } cancelButton() - }.show().applyTint() + }.show() } sw_dark_status_icon.onCheckedChange { buttonView, isChecked -> if (buttonView?.isPressed == true) { @@ -283,8 +285,8 @@ class BgTextConfigDialog : BaseDialogFragment(), FilePickerDialog.CallBack { importNetConfig(url) } } - noButton { } - }.show().applyTint() + noButton() + }.show() } private fun importNetConfig(url: String) { diff --git a/app/src/main/java/io/legado/app/ui/book/read/config/ChineseConverter.kt b/app/src/main/java/io/legado/app/ui/book/read/config/ChineseConverter.kt index af8408284..dc8f36d67 100644 --- a/app/src/main/java/io/legado/app/ui/book/read/config/ChineseConverter.kt +++ b/app/src/main/java/io/legado/app/ui/book/read/config/ChineseConverter.kt @@ -10,7 +10,6 @@ import io.legado.app.help.AppConfig import io.legado.app.lib.dialogs.alert import io.legado.app.lib.theme.accentColor import io.legado.app.ui.widget.text.StrokeTextView -import io.legado.app.utils.applyTint import org.jetbrains.anko.sdk27.listeners.onClick class ChineseConverter(context: Context, attrs: AttributeSet?) : StrokeTextView(context, attrs) { @@ -45,7 +44,7 @@ class ChineseConverter(context: Context, attrs: AttributeSet?) : StrokeTextView( upUi(i) onChanged?.invoke() } - }.show().applyTint() + }.show() } fun onChanged(unit: () -> Unit) { diff --git a/app/src/main/java/io/legado/app/ui/book/read/config/ClickActionConfigDialog.kt b/app/src/main/java/io/legado/app/ui/book/read/config/ClickActionConfigDialog.kt new file mode 100644 index 000000000..55082400e --- /dev/null +++ b/app/src/main/java/io/legado/app/ui/book/read/config/ClickActionConfigDialog.kt @@ -0,0 +1,132 @@ +package io.legado.app.ui.book.read.config + +import android.content.DialogInterface +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.TextView +import io.legado.app.R +import io.legado.app.base.BaseDialogFragment +import io.legado.app.constant.PreferKey +import io.legado.app.help.AppConfig +import io.legado.app.lib.dialogs.selector +import io.legado.app.ui.book.read.ReadBookActivity +import io.legado.app.utils.getCompatColor +import io.legado.app.utils.putPrefInt +import kotlinx.android.synthetic.main.dialog_click_action_config.* +import org.jetbrains.anko.sdk27.listeners.onClick + +class ClickActionConfigDialog : BaseDialogFragment() { + + private val actions = linkedMapOf() + + override fun onStart() { + super.onStart() + (activity as ReadBookActivity).bottomDialog++ + dialog?.window?.let { + it.setBackgroundDrawableResource(R.color.transparent) + it.setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT) + } + } + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + return inflater.inflate(R.layout.dialog_click_action_config, container) + } + + override fun onDismiss(dialog: DialogInterface) { + super.onDismiss(dialog) + (activity as ReadBookActivity).bottomDialog-- + } + + override fun onFragmentCreated(view: View, savedInstanceState: Bundle?) { + view.setBackgroundColor(getCompatColor(R.color.translucent)) + actions[-1] = getString(R.string.non_action) + actions[0] = getString(R.string.menu) + actions[1] = getString(R.string.next_page) + actions[2] = getString(R.string.prev_page) + actions[3] = getString(R.string.next_chapter) + actions[4] = getString(R.string.previous_chapter) + initData() + initViewEvent() + } + + private fun initData() = with(AppConfig) { + tv_top_left.text = actions[clickActionTopLeft] + tv_top_center.text = actions[clickActionTopCenter] + tv_top_right.text = actions[clickActionTopRight] + tv_middle_left.text = actions[clickActionMiddleLeft] + tv_middle_right.text = actions[clickActionMiddleRight] + tv_bottom_left.text = actions[clickActionBottomLeft] + tv_bottom_center.text = actions[clickActionBottomCenter] + tv_bottom_right.text = actions[clickActionBottomRight] + } + + private fun initViewEvent() { + iv_close.onClick { + dismiss() + } + tv_top_left.onClick { + selectAction { action -> + putPrefInt(PreferKey.clickActionTopLeft, action) + (it as? TextView)?.text = actions[action] + } + } + tv_top_center.onClick { + selectAction { action -> + putPrefInt(PreferKey.clickActionTopCenter, action) + (it as? TextView)?.text = actions[action] + } + } + tv_top_right.onClick { + selectAction { action -> + putPrefInt(PreferKey.clickActionTopRight, action) + (it as? TextView)?.text = actions[action] + } + } + tv_middle_left.onClick { + selectAction { action -> + putPrefInt(PreferKey.clickActionMiddleLeft, action) + (it as? TextView)?.text = actions[action] + } + } + tv_middle_right.onClick { + selectAction { action -> + putPrefInt(PreferKey.clickActionMiddleRight, action) + (it as? TextView)?.text = actions[action] + } + } + tv_bottom_left.onClick { + selectAction { action -> + putPrefInt(PreferKey.clickActionBottomLeft, action) + (it as? TextView)?.text = actions[action] + } + } + tv_bottom_center.onClick { + selectAction { action -> + putPrefInt(PreferKey.clickActionBottomCenter, action) + (it as? TextView)?.text = actions[action] + } + } + tv_bottom_right.onClick { + selectAction { action -> + putPrefInt(PreferKey.clickActionBottomRight, action) + (it as? TextView)?.text = actions[action] + } + } + } + + private fun selectAction(success: (action: Int) -> Unit) { + selector( + getString(R.string.select_action), + actions.values.toList() + ) { _, index -> + success.invoke(actions.keys.toList()[index]) + } + } + +} \ 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 46fbbb215..b920e1784 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 @@ -1,6 +1,7 @@ package io.legado.app.ui.book.read.config import android.annotation.SuppressLint +import android.content.DialogInterface import android.content.SharedPreferences import android.os.Bundle import android.view.* @@ -14,7 +15,7 @@ import io.legado.app.constant.PreferKey import io.legado.app.help.ReadBookConfig import io.legado.app.lib.theme.ATH import io.legado.app.lib.theme.bottomBackground -import io.legado.app.ui.book.read.ReadBookActivityHelp +import io.legado.app.ui.book.read.ReadBookActivity import io.legado.app.utils.dp import io.legado.app.utils.getPrefBoolean import io.legado.app.utils.postEvent @@ -24,6 +25,7 @@ class MoreConfigDialog : DialogFragment() { override fun onStart() { super.onStart() + (activity as ReadBookActivity).bottomDialog++ dialog?.window?.let { it.clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND) it.setBackgroundDrawableResource(R.color.background) @@ -57,6 +59,11 @@ class MoreConfigDialog : DialogFragment() { .commit() } + override fun onDismiss(dialog: DialogInterface) { + super.onDismiss(dialog) + (activity as ReadBookActivity).bottomDialog-- + } + class ReadPreferenceFragment : BasePreferenceFragment(), SharedPreferences.OnSharedPreferenceChangeListener { @@ -101,9 +108,7 @@ class MoreConfigDialog : DialogFragment() { PreferKey.keepLight -> postEvent(key, true) PreferKey.textSelectAble -> postEvent(key, getPrefBoolean(key)) getString(R.string.pk_requested_direction) -> { - activity?.let { - ReadBookActivityHelp.setOrientation(it) - } + (activity as? ReadBookActivity)?.setOrientation() } PreferKey.textFullJustify, PreferKey.textBottomJustify -> { @@ -118,6 +123,9 @@ class MoreConfigDialog : DialogFragment() { override fun onPreferenceTreeClick(preference: Preference?): Boolean { when (preference?.key) { "customPageKey" -> PageKeyDialog(requireContext()).show() + "clickRegionalConfig" -> { + (activity as? ReadBookActivity)?.showClickRegionalConfig() + } } return super.onPreferenceTreeClick(preference) } diff --git a/app/src/main/java/io/legado/app/ui/book/read/config/ReadAloudConfigDialog.kt b/app/src/main/java/io/legado/app/ui/book/read/config/ReadAloudConfigDialog.kt index 6e5595bcd..d1de3f240 100644 --- a/app/src/main/java/io/legado/app/ui/book/read/config/ReadAloudConfigDialog.kt +++ b/app/src/main/java/io/legado/app/ui/book/read/config/ReadAloudConfigDialog.kt @@ -117,7 +117,6 @@ class ReadAloudConfigDialog : DialogFragment() { when (preference) { is ListPreference -> { val index = preference.findIndexOfValue(value) - // Set the summary to reflect the new value. preference.summary = if (index >= 0) preference.entries[index] else null } else -> { 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 ebd5bae64..a7020fb98 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 @@ -1,5 +1,6 @@ package io.legado.app.ui.book.read.config +import android.content.DialogInterface import android.os.Bundle import android.view.* import android.widget.SeekBar @@ -12,6 +13,7 @@ import io.legado.app.lib.theme.getPrimaryTextColor 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.read.ReadBookActivity import io.legado.app.utils.ColorUtils import io.legado.app.utils.getPrefBoolean import io.legado.app.utils.observeEvent @@ -24,6 +26,7 @@ class ReadAloudDialog : BaseDialogFragment() { override fun onStart() { super.onStart() + (activity as ReadBookActivity).bottomDialog++ dialog?.window?.let { it.clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND) it.setBackgroundDrawableResource(R.color.background) @@ -36,6 +39,11 @@ class ReadAloudDialog : BaseDialogFragment() { } } + override fun onDismiss(dialog: DialogInterface) { + super.onDismiss(dialog) + (activity as ReadBookActivity).bottomDialog-- + } + override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, 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 df5ad0474..7184c9384 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 @@ -35,6 +35,7 @@ class ReadStyleDialog : BaseDialogFragment(), FontSelectDialog.CallBack { override fun onStart() { super.onStart() + (activity as ReadBookActivity).bottomDialog++ dialog?.window?.let { it.clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND) it.setBackgroundDrawableResource(R.color.background) @@ -64,6 +65,7 @@ class ReadStyleDialog : BaseDialogFragment(), FontSelectDialog.CallBack { override fun onDismiss(dialog: DialogInterface) { super.onDismiss(dialog) ReadBookConfig.save() + (activity as ReadBookActivity).bottomDialog-- } private fun initView() { @@ -190,7 +192,7 @@ class ReadStyleDialog : BaseDialogFragment(), FontSelectDialog.CallBack { } } customView = rootView - }.show().applyTint() + }.show() } private fun changeBg(index: Int) { diff --git a/app/src/main/java/io/legado/app/ui/book/read/config/SpeakEngineDialog.kt b/app/src/main/java/io/legado/app/ui/book/read/config/SpeakEngineDialog.kt index 3649c0bbd..d08e78dfc 100644 --- a/app/src/main/java/io/legado/app/ui/book/read/config/SpeakEngineDialog.kt +++ b/app/src/main/java/io/legado/app/ui/book/read/config/SpeakEngineDialog.kt @@ -18,9 +18,6 @@ import io.legado.app.base.adapter.SimpleRecyclerAdapter import io.legado.app.constant.PreferKey import io.legado.app.data.entities.HttpTTS import io.legado.app.lib.dialogs.alert -import io.legado.app.lib.dialogs.cancelButton -import io.legado.app.lib.dialogs.customView -import io.legado.app.lib.dialogs.okButton import io.legado.app.lib.theme.primaryColor import io.legado.app.service.help.ReadAloud import io.legado.app.ui.widget.dialog.TextDialog @@ -29,7 +26,6 @@ import kotlinx.android.synthetic.main.dialog_http_tts_edit.view.* import kotlinx.android.synthetic.main.dialog_recycler_view.* import kotlinx.android.synthetic.main.item_http_tts.view.* import org.jetbrains.anko.sdk27.listeners.onClick -import java.io.File class SpeakEngineDialog : BaseDialogFragment(), Toolbar.OnMenuItemClickListener { @@ -128,11 +124,11 @@ class SpeakEngineDialog : BaseDialogFragment(), Toolbar.OnMenuItemClickListener } neutralButton(R.string.help) { val helpStr = String( - requireContext().assets.open("help${File.separator}httpTts.md").readBytes() + requireContext().assets.open("help/httpTTSHelp.md").readBytes() ) TextDialog.show(childFragmentManager, helpStr, TextDialog.MD) } - }.show().applyTint() + }.show() } inner class Adapter(context: Context) : diff --git a/app/src/main/java/io/legado/app/ui/book/read/config/TextFontWeightConverter.kt b/app/src/main/java/io/legado/app/ui/book/read/config/TextFontWeightConverter.kt index fbff59f3e..ae240846d 100644 --- a/app/src/main/java/io/legado/app/ui/book/read/config/TextFontWeightConverter.kt +++ b/app/src/main/java/io/legado/app/ui/book/read/config/TextFontWeightConverter.kt @@ -10,7 +10,6 @@ import io.legado.app.help.ReadBookConfig import io.legado.app.lib.dialogs.alert import io.legado.app.lib.theme.accentColor import io.legado.app.ui.widget.text.StrokeTextView -import io.legado.app.utils.applyTint import org.jetbrains.anko.sdk27.listeners.onClick class TextFontWeightConverter(context: Context, attrs: AttributeSet?) : StrokeTextView(context, attrs) { @@ -46,7 +45,7 @@ class TextFontWeightConverter(context: Context, attrs: AttributeSet?) : StrokeTe upUi(i) onChanged?.invoke() } - }.show().applyTint() + }.show() } fun onChanged(unit: () -> Unit) { 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 fb2055729..52d6eb7a9 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 @@ -21,9 +21,6 @@ import io.legado.app.base.adapter.ItemViewHolder import io.legado.app.base.adapter.SimpleRecyclerAdapter import io.legado.app.data.entities.TxtTocRule import io.legado.app.lib.dialogs.alert -import io.legado.app.lib.dialogs.cancelButton -import io.legado.app.lib.dialogs.customView -import io.legado.app.lib.dialogs.okButton import io.legado.app.lib.theme.backgroundColor import io.legado.app.lib.theme.primaryColor import io.legado.app.ui.widget.recycler.ItemTouchCallback @@ -167,7 +164,7 @@ class TocRegexDialog : BaseDialogFragment(), Toolbar.OnMenuItemClickListener { } } cancelButton() - }.show().applyTint() + }.show() } @SuppressLint("InflateParams") @@ -191,7 +188,7 @@ class TocRegexDialog : BaseDialogFragment(), Toolbar.OnMenuItemClickListener { } } cancelButton() - }.show().applyTint() + }.show() } inner class TocRegexAdapter(context: Context) : 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 c2e80b15c..86dc57d52 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 @@ -12,9 +12,7 @@ import io.legado.app.constant.PreferKey import io.legado.app.help.ReadBookConfig import io.legado.app.lib.theme.accentColor import io.legado.app.service.help.ReadBook -import io.legado.app.ui.book.read.page.entities.TextChar -import io.legado.app.ui.book.read.page.entities.TextLine -import io.legado.app.ui.book.read.page.entities.TextPage +import io.legado.app.ui.book.read.page.entities.* import io.legado.app.ui.book.read.page.provider.ChapterProvider import io.legado.app.ui.book.read.page.provider.ImageProvider import io.legado.app.ui.widget.dialog.PhotoDialog @@ -40,19 +38,21 @@ class ContentTextView(context: Context, attrs: AttributeSet?) : View(context, at private val visibleRect = RectF() private val selectStart = arrayOf(0, 0, 0) private val selectEnd = arrayOf(0, 0, 0) + private var textChapter: TextChapter? = null private var textPage: TextPage = TextPage() //滚动参数 private val pageFactory: TextPageFactory get() = callBack.pageFactory - private var pageOffset = 0f + private var pageOffset = 0 init { callBack = activity as CallBack contentDescription = textPage.text } - fun setContent(textPage: TextPage) { - this.textPage = textPage + fun setContent(pageData: PageData) { + this.textChapter = pageData.textChapter + this.textPage = pageData.textPage contentDescription = textPage.text invalidate() } @@ -139,7 +139,11 @@ class ContentTextView(context: Context, attrs: AttributeSet?) : View(context, at isTitle: Boolean, isReadAloud: Boolean, ) { - val textPaint = if (isTitle) ChapterProvider.titlePaint else ChapterProvider.contentPaint + val textPaint = if (isTitle) { + textChapter?.titlePaint ?: ChapterProvider.titlePaint + } else { + textChapter?.contentPaint ?: ChapterProvider.contentPaint + } textPaint.color = if (isReadAloud) context.accentColor else ReadBookConfig.textColor textChars.forEach { @@ -173,33 +177,33 @@ class ContentTextView(context: Context, attrs: AttributeSet?) : View(context, at /** * 滚动事件 */ - fun onScroll(mOffset: Float) { - if (mOffset == 0f) return + fun scroll(mOffset: Int) { + if (mOffset == 0) return pageOffset += mOffset if (!pageFactory.hasPrev() && pageOffset > 0) { - pageOffset = 0f + pageOffset = 0 } else if (!pageFactory.hasNext() && pageOffset < 0 && pageOffset + textPage.height < ChapterProvider.visibleHeight ) { - val offset = ChapterProvider.visibleHeight - textPage.height - pageOffset = min(0f, offset) + val offset = (ChapterProvider.visibleHeight - textPage.height).toInt() + pageOffset = min(0, offset) } else if (pageOffset > 0) { pageFactory.moveToPrev(false) - textPage = pageFactory.currentPage - pageOffset -= textPage.height + textPage = pageFactory.curData.textPage + pageOffset -= textPage.height.toInt() upView?.invoke(textPage) } else if (pageOffset < -textPage.height) { - pageOffset += textPage.height + pageOffset += textPage.height.toInt() pageFactory.moveToNext(false) - textPage = pageFactory.currentPage + textPage = pageFactory.curData.textPage upView?.invoke(textPage) } invalidate() } fun resetPageOffset() { - pageOffset = 0f + pageOffset = 0 } /** @@ -480,17 +484,17 @@ class ContentTextView(context: Context, attrs: AttributeSet?) : View(context, at private fun relativeOffset(relativePos: Int): Float { return when (relativePos) { - 0 -> pageOffset + 0 -> pageOffset.toFloat() 1 -> pageOffset + textPage.height - else -> pageOffset + textPage.height + pageFactory.nextPage.height + else -> pageOffset + textPage.height + pageFactory.nextData.textPage.height } } private fun relativePage(relativePos: Int): TextPage { return when (relativePos) { 0 -> textPage - 1 -> pageFactory.nextPage - else -> pageFactory.nextPagePlus + 1 -> pageFactory.nextData.textPage + else -> pageFactory.nextPlusData.textPage } } diff --git a/app/src/main/java/io/legado/app/ui/book/read/page/ContentView.kt b/app/src/main/java/io/legado/app/ui/book/read/page/ContentView.kt index 2b9d034e8..d94c30086 100644 --- a/app/src/main/java/io/legado/app/ui/book/read/page/ContentView.kt +++ b/app/src/main/java/io/legado/app/ui/book/read/page/ContentView.kt @@ -12,6 +12,7 @@ import io.legado.app.constant.AppConst.timeFormat import io.legado.app.help.ReadBookConfig import io.legado.app.help.ReadTipConfig import io.legado.app.service.help.ReadBook +import io.legado.app.ui.book.read.page.entities.PageData import io.legado.app.ui.book.read.page.entities.TextPage import io.legado.app.ui.book.read.page.provider.ChapterProvider import io.legado.app.ui.widget.BatteryView @@ -217,11 +218,12 @@ class ContentView(context: Context) : FrameLayout(context) { tvBattery?.setBattery(battery) } - fun setContent(textPage: TextPage, resetPageOffset: Boolean = true) { - setProgress(textPage) - if (resetPageOffset) + fun setContent(pageData: PageData, resetPageOffset: Boolean = true) { + setProgress(pageData.textPage) + if (resetPageOffset) { resetPageOffset() - content_text_view.setContent(textPage) + } + content_text_view.setContent(pageData) } fun resetPageOffset() { @@ -237,8 +239,8 @@ class ContentView(context: Context) : FrameLayout(context) { tvPageAndTotal?.text = "${index.plus(1)}/$pageSize $readProgress" } - fun onScroll(offset: Float) { - content_text_view.onScroll(offset) + fun scroll(offset: Int) { + content_text_view.scroll(offset) } fun upSelectAble(selectAble: Boolean) { 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 75fd79094..949ec848f 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 @@ -10,13 +10,13 @@ abstract class PageFactory(protected val dataSource: DataSource) { abstract fun moveToPrev(upContent: Boolean): Boolean - abstract val nextPage: DATA + abstract val nextData: DATA - abstract val prevPage: DATA + abstract val prevData: DATA - abstract val currentPage: DATA + abstract val curData: DATA - abstract val nextPagePlus: DATA + abstract val nextPlusData: DATA abstract fun hasNext(): Boolean 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 b502e20cd..9846bee77 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 @@ -10,6 +10,7 @@ import android.util.AttributeSet import android.view.MotionEvent import android.view.ViewConfiguration import android.widget.FrameLayout +import io.legado.app.help.AppConfig import io.legado.app.help.ReadBookConfig import io.legado.app.lib.theme.accentColor import io.legado.app.service.help.ReadBook @@ -71,7 +72,18 @@ class PageView(context: Context, attrs: AttributeSet) : private var firstCharIndex: Int = 0 val slopSquare by lazy { ViewConfiguration.get(context).scaledTouchSlop } + private val topLeftRectF = RectF(0F, 0F, width * 0.33f, height * 0.33f) + private val topCenterRectF = RectF(width * 0.33f, 0F, width * 0.66f, height * 0.33f) + private val topRightRectF = RectF(width * 0.36f, 0F, width.toFloat(), height * 0.33f) + private val middleLeftRectF = RectF(0F, height * 0.33f, width * 0.33f, height * 0.66f) private val centerRectF = RectF(width * 0.33f, height * 0.33f, width * 0.66f, height * 0.66f) + private val middleRightRectF = + RectF(width * 0.66f, height * 0.33f, width.toFloat(), height * 0.66f) + private val bottomLeftRectF = RectF(0F, height * 0.66f, width * 0.33f, height.toFloat()) + private val bottomCenterRectF = + RectF(width * 0.33f, height * 0.66f, width * 0.66f, height.toFloat()) + private val bottomRightRectF = + RectF(width * 0.66f, height * 0.66f, width.toFloat(), height.toFloat()) private val autoPageRect by lazy { Rect() } private val autoPagePint by lazy { Paint().apply { @@ -90,7 +102,15 @@ class PageView(context: Context, attrs: AttributeSet) : override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) { super.onSizeChanged(w, h, oldw, oldh) + topLeftRectF.set(0F, 0F, width * 0.33f, height * 0.33f) + topCenterRectF.set(width * 0.33f, 0F, width * 0.66f, height * 0.33f) + topRightRectF.set(width * 0.36f, 0F, width.toFloat(), height * 0.33f) + middleLeftRectF.set(0F, height * 0.33f, width * 0.33f, height * 0.66f) centerRectF.set(width * 0.33f, height * 0.33f, width * 0.66f, height * 0.66f) + middleRightRectF.set(width * 0.66f, height * 0.33f, width.toFloat(), height * 0.66f) + bottomLeftRectF.set(0F, height * 0.66f, width * 0.33f, height.toFloat()) + bottomCenterRectF.set(width * 0.33f, height * 0.66f, width * 0.66f, height.toFloat()) + bottomRightRectF.set(width * 0.66f, height * 0.66f, width.toFloat(), height.toFloat()) prevPage.x = -w.toFloat() pageDelegate?.setViewSize(w, h) if (oldw != 0 && oldh != 0) { @@ -101,10 +121,10 @@ class PageView(context: Context, attrs: AttributeSet) : override fun dispatchDraw(canvas: Canvas) { super.dispatchDraw(canvas) pageDelegate?.onDraw(canvas) - if (callBack.isAutoPage) { + if (callBack.isAutoPage && !isScroll) { nextPage.screenshot()?.let { val bottom = - page_view.height * callBack.autoPageProgress / (ReadBookConfig.autoReadSpeed * 10) + page_view.height * callBack.autoPageProgress / (ReadBookConfig.autoReadSpeed * 50) autoPageRect.set(0, 0, page_view.width, bottom) canvas.drawBitmap(it, autoPageRect, autoPageRect, null) canvas.drawRect( @@ -239,24 +259,49 @@ class PageView(context: Context, attrs: AttributeSet) : * 单击 */ private fun onSingleTapUp(): Boolean { - if (isTextSelected) { - isTextSelected = false - return true - } - if (centerRectF.contains(startX, startY)) { - if (!isAbortAnim) { - callBack.clickCenter() + when { + isTextSelected -> isTextSelected = false + centerRectF.contains(startX, startY) -> if (!isAbortAnim) { + click(AppConfig.clickActionMiddleCenter) + } + bottomCenterRectF.contains(startX, startY) -> { + click(AppConfig.clickActionBottomCenter) + } + bottomLeftRectF.contains(startX, startY) -> { + click(AppConfig.clickActionBottomLeft) + } + bottomRightRectF.contains(startX, startY) -> { + click(AppConfig.clickActionBottomRight) + } + middleLeftRectF.contains(startX, startY) -> { + click(AppConfig.clickActionMiddleLeft) + } + middleRightRectF.contains(startX, startY) -> { + click(AppConfig.clickActionMiddleRight) } - } else if (ReadBookConfig.clickTurnPage) { - if (startX > width / 2 || ReadBookConfig.clickAllNext) { - pageDelegate?.nextPageByAnim(defaultAnimationSpeed) - } else { - pageDelegate?.prevPageByAnim(defaultAnimationSpeed) + topLeftRectF.contains(startX, startY) -> { + click(AppConfig.clickActionTopLeft) + } + topCenterRectF.contains(startX, startY) -> { + click(AppConfig.clickActionTopCenter) + } + topRightRectF.contains(startX, startY) -> { + click(AppConfig.clickActionTopRight) } } return true } + private fun click(action: Int) { + when (action) { + 0 -> callBack.showActionMenu() + 1 -> pageDelegate?.nextPageByAnim(defaultAnimationSpeed) + 2 -> pageDelegate?.prevPageByAnim(defaultAnimationSpeed) + 3 -> ReadBook.moveToNextChapter(true) + 4 -> ReadBook.moveToPrevChapter(upContent = true, toLast = false) + } + } + /** * 选择文本 */ @@ -331,16 +376,16 @@ class PageView(context: Context, attrs: AttributeSet) : override fun upContent(relativePosition: Int, resetPageOffset: Boolean) { if (isScroll && !callBack.isAutoPage) { - curPage.setContent(pageFactory.currentPage, resetPageOffset) + curPage.setContent(pageFactory.curData, resetPageOffset) } else { curPage.resetPageOffset() when (relativePosition) { - -1 -> prevPage.setContent(pageFactory.prevPage) - 1 -> nextPage.setContent(pageFactory.nextPage) + -1 -> prevPage.setContent(pageFactory.prevData) + 1 -> nextPage.setContent(pageFactory.nextData) else -> { - curPage.setContent(pageFactory.currentPage) - nextPage.setContent(pageFactory.nextPage) - prevPage.setContent(pageFactory.prevPage) + curPage.setContent(pageFactory.curData) + nextPage.setContent(pageFactory.nextData) + prevPage.setContent(pageFactory.prevData) } } } @@ -408,7 +453,7 @@ class PageView(context: Context, attrs: AttributeSet) : val isInitFinish: Boolean val isAutoPage: Boolean val autoPageProgress: Int - fun clickCenter() + fun showActionMenu() fun screenOffTimerStart() fun showTextActionMenu() } 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 95917ae11..613f18707 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 @@ -1,9 +1,10 @@ package io.legado.app.ui.book.read.page import io.legado.app.service.help.ReadBook +import io.legado.app.ui.book.read.page.entities.PageData import io.legado.app.ui.book.read.page.entities.TextPage -class TextPageFactory(dataSource: DataSource) : PageFactory(dataSource) { +class TextPageFactory(dataSource: DataSource) : PageFactory(dataSource) { override fun hasPrev(): Boolean = with(dataSource) { return hasPrevChapter() || pageIndex > 0 @@ -57,74 +58,81 @@ class TextPageFactory(dataSource: DataSource) : PageFactory(dataSource false } - override val currentPage: TextPage + override val curData: PageData get() = with(dataSource) { ReadBook.msg?.let { - return@with TextPage(text = it).format() + return@with PageData(TextPage(text = it).format()) } currentChapter?.let { - return@with it.page(pageIndex) - ?: TextPage(title = it.title).format() + val page = it.page(pageIndex) ?: TextPage(title = it.title).format() + return@with PageData(page, it) } - return TextPage().format() + return PageData(TextPage().format()) } - override val nextPage: TextPage + override val nextData: PageData get() = with(dataSource) { ReadBook.msg?.let { - return@with TextPage(text = it).format() + return@with PageData(TextPage(text = it).format()) } currentChapter?.let { if (pageIndex < it.pageSize - 1) { - return@with it.page(pageIndex + 1)?.removePageAloudSpan() + val page = it.page(pageIndex + 1)?.removePageAloudSpan() ?: TextPage(title = it.title).format() + return@with PageData(page, it) } } if (!hasNextChapter()) { - return@with TextPage(text = "") + return@with PageData(TextPage(text = "")) } nextChapter?.let { - return@with it.page(0)?.removePageAloudSpan() + val page = it.page(0)?.removePageAloudSpan() ?: TextPage(title = it.title).format() + return@with PageData(page, it) } - return TextPage().format() + return PageData(TextPage().format()) } - override val prevPage: TextPage + override val prevData: PageData get() = with(dataSource) { ReadBook.msg?.let { - return@with TextPage(text = it).format() + return@with PageData(TextPage(text = it).format()) } if (pageIndex > 0) { currentChapter?.let { - return@with it.page(pageIndex - 1)?.removePageAloudSpan() + val page = it.page(pageIndex - 1)?.removePageAloudSpan() ?: TextPage(title = it.title).format() + return@with PageData(page, it) } } prevChapter?.let { - return@with it.lastPage?.removePageAloudSpan() + val page = it.lastPage?.removePageAloudSpan() ?: TextPage(title = it.title).format() + return@with PageData(page, it) } - return TextPage().format() + return PageData(TextPage().format()) } - override val nextPagePlus: TextPage + override val nextPlusData: PageData get() = with(dataSource) { currentChapter?.let { if (pageIndex < it.pageSize - 2) { - return@with it.page(pageIndex + 2)?.removePageAloudSpan() + val page = it.page(pageIndex + 2)?.removePageAloudSpan() ?: TextPage(title = it.title).format() + return@with PageData(page, it) } nextChapter?.let { nc -> if (pageIndex < it.pageSize - 1) { - return@with nc.page(0)?.removePageAloudSpan() + val page = nc.page(0)?.removePageAloudSpan() ?: TextPage(title = nc.title).format() + return@with PageData(page, nc) } - return@with nc.page(1)?.removePageAloudSpan() + val page = nc.page(1)?.removePageAloudSpan() ?: TextPage(title = nc.title).format() + return@with PageData(page, nc) } } - return TextPage().format() + return PageData(TextPage().format()) } } 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 30078de89..90736e081 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 @@ -41,7 +41,7 @@ class ScrollPageDelegate(pageView: PageView) : PageDelegate(pageView) { } override fun onScroll() { - curPage.onScroll(touchY - lastY) + curPage.scroll((touchY - lastY).toInt()) } override fun onDraw(canvas: Canvas) { diff --git a/app/src/main/java/io/legado/app/ui/book/read/page/entities/PageData.kt b/app/src/main/java/io/legado/app/ui/book/read/page/entities/PageData.kt new file mode 100644 index 000000000..3d9bec50c --- /dev/null +++ b/app/src/main/java/io/legado/app/ui/book/read/page/entities/PageData.kt @@ -0,0 +1,6 @@ +package io.legado.app.ui.book.read.page.entities + +data class PageData( + val textPage: TextPage, + val textChapter: TextChapter? = null +) \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/book/read/page/entities/TextChapter.kt b/app/src/main/java/io/legado/app/ui/book/read/page/entities/TextChapter.kt index 3f183830d..1cd9177c9 100644 --- a/app/src/main/java/io/legado/app/ui/book/read/page/entities/TextChapter.kt +++ b/app/src/main/java/io/legado/app/ui/book/read/page/entities/TextChapter.kt @@ -1,5 +1,6 @@ package io.legado.app.ui.book.read.page.entities +import android.text.TextPaint import kotlin.math.min data class TextChapter( @@ -9,7 +10,9 @@ data class TextChapter( val pages: List, val pageLines: List, val pageLengths: List, - val chaptersSize: Int + val chaptersSize: Int, + var titlePaint: TextPaint? = null, + var contentPaint: TextPaint? = null ) { fun page(index: Int): TextPage? { return pages.getOrNull(index) diff --git a/app/src/main/java/io/legado/app/ui/book/read/page/provider/ChapterProvider.kt b/app/src/main/java/io/legado/app/ui/book/read/page/provider/ChapterProvider.kt index 7ea1e428a..ea2eaa4e4 100644 --- a/app/src/main/java/io/legado/app/ui/book/read/page/provider/ChapterProvider.kt +++ b/app/src/main/java/io/legado/app/ui/book/read/page/provider/ChapterProvider.kt @@ -11,6 +11,7 @@ import io.legado.app.constant.AppPattern import io.legado.app.data.entities.Book import io.legado.app.data.entities.BookChapter import io.legado.app.help.AppConfig +import io.legado.app.help.BookHelp import io.legado.app.help.ReadBookConfig import io.legado.app.ui.book.read.page.entities.TextChapter import io.legado.app.ui.book.read.page.entities.TextChar @@ -57,6 +58,11 @@ object ChapterProvider { val pageLengths = arrayListOf() val stringBuilder = StringBuilder() var durY = 0f + var paint = Pair(titlePaint, contentPaint) + BookHelp.getFontPath(book, bookChapter)?.let { + val typeface = getTypeface(it) + paint = getPaint(typeface) + } textPages.add(TextPage()) contents.forEachIndexed { index, text -> val matcher = AppPattern.imgPattern.matcher(text) @@ -66,19 +72,18 @@ object ChapterProvider { src = NetworkUtils.getAbsoluteURL(bookChapter.url, src) } src?.let { - durY = - setTypeImage( - book, bookChapter, src, durY, textPages, imageStyle - ) + durY = setTypeImage( + book, bookChapter, src, durY, textPages, imageStyle + ) } } else { val isTitle = index == 0 + val textPaint = if (isTitle) paint.first else paint.second if (!(isTitle && ReadBookConfig.titleMode == 2)) { - durY = - setTypeText( - text, durY, textPages, pageLines, - pageLengths, stringBuilder, isTitle - ) + durY = setTypeText( + text, durY, textPages, pageLines, + pageLengths, stringBuilder, isTitle, textPaint + ) } } } @@ -106,7 +111,9 @@ object ChapterProvider { textPages, pageLines, pageLengths, - chapterSize + chapterSize, + paint.first, + paint.second ) } @@ -185,9 +192,9 @@ object ChapterProvider { pageLengths: ArrayList, stringBuilder: StringBuilder, isTitle: Boolean, + textPaint: TextPaint ): Float { var durY = if (isTitle) y + titleTopSpacing else y - val textPaint = if (isTitle) titlePaint else contentPaint val layout = StaticLayout( text, textPaint, visibleWidth, Layout.Alignment.ALIGN_NORMAL, 0f, 0f, true ) @@ -200,12 +207,7 @@ object ChapterProvider { if (lineIndex == 0 && layout.lineCount > 1 && !isTitle) { //第一行 textLine.text = words - addCharsToLineFirst( - textLine, - words.toStringArray(), - textPaint, - desiredWidth - ) + addCharsToLineFirst(textLine, words.toStringArray(), textPaint, desiredWidth) } else if (lineIndex == layout.lineCount - 1) { //最后一行 textLine.text = "$words\n" @@ -213,22 +215,11 @@ object ChapterProvider { val x = if (isTitle && ReadBookConfig.titleMode == 1) (visibleWidth - layout.getLineWidth(lineIndex)) / 2 else 0f - addCharsToLineLast( - textLine, - words.toStringArray(), - textPaint, - x - ) + addCharsToLineLast(textLine, words.toStringArray(), textPaint, x) } else { //中间行 textLine.text = words - addCharsToLineMiddle( - textLine, - words.toStringArray(), - textPaint, - desiredWidth, - 0f - ) + addCharsToLineMiddle(textLine, words.toStringArray(), textPaint, desiredWidth, 0f) } if (durY + textPaint.textHeight > visibleHeight) { //当前页面结束,设置各种值 @@ -264,33 +255,18 @@ object ChapterProvider { ) { var x = 0f if (!ReadBookConfig.textFullJustify) { - addCharsToLineLast( - textLine, - words, - textPaint, - x - ) + addCharsToLineLast(textLine, words, textPaint, x) return } val bodyIndent = ReadBookConfig.paragraphIndent val icw = StaticLayout.getDesiredWidth(bodyIndent, textPaint) / bodyIndent.length bodyIndent.toStringArray().forEach { val x1 = x + icw - textLine.addTextChar( - charData = it, - start = paddingLeft + x, - end = paddingLeft + x1 - ) + textLine.addTextChar(charData = it, start = paddingLeft + x, end = paddingLeft + x1) x = x1 } val words1 = words.copyOfRange(bodyIndent.length, words.size) - addCharsToLineMiddle( - textLine, - words1, - textPaint, - desiredWidth, - x - ) + addCharsToLineMiddle(textLine, words1, textPaint, desiredWidth, x) } /** @@ -304,12 +280,7 @@ object ChapterProvider { startX: Float, ) { if (!ReadBookConfig.textFullJustify) { - addCharsToLineLast( - textLine, - words, - textPaint, - startX - ) + addCharsToLineLast(textLine, words, textPaint, startX) return } val gapCount: Int = words.lastIndex @@ -318,17 +289,10 @@ object ChapterProvider { words.forEachIndexed { index, s -> val cw = StaticLayout.getDesiredWidth(s, textPaint) val x1 = if (index != words.lastIndex) (x + cw + d) else (x + cw) - textLine.addTextChar( - charData = s, - start = paddingLeft + x, - end = paddingLeft + x1 - ) + textLine.addTextChar(charData = s, start = paddingLeft + x, end = paddingLeft + x1) x = x1 } - exceed( - textLine, - words - ) + exceed(textLine, words) } /** @@ -344,17 +308,10 @@ object ChapterProvider { words.forEach { val cw = StaticLayout.getDesiredWidth(it, textPaint) val x1 = x + cw - textLine.addTextChar( - charData = it, - start = paddingLeft + x, - end = paddingLeft + x1 - ) + textLine.addTextChar(charData = it, start = paddingLeft + x, end = paddingLeft + x1) x = x1 } - exceed( - textLine, - words - ) + exceed(textLine, words) } /** @@ -378,8 +335,21 @@ object ChapterProvider { * 更新样式 */ fun upStyle() { - typeface = try { - val fontPath = ReadBookConfig.textFont + typeface = getTypeface(ReadBookConfig.textFont) + getPaint(typeface).let { + titlePaint = it.first + contentPaint = it.second + } + //间距 + lineSpacingExtra = ReadBookConfig.lineSpacingExtra + paragraphSpacing = ReadBookConfig.paragraphSpacing + titleTopSpacing = ReadBookConfig.titleTopSpacing.dp + titleBottomSpacing = ReadBookConfig.titleBottomSpacing.dp + upVisibleSize() + } + + private fun getTypeface(fontPath: String): Typeface { + return try { when { fontPath.isContentScheme() && Build.VERSION.SDK_INT >= Build.VERSION_CODES.O -> { val fd = App.INSTANCE.contentResolver @@ -402,6 +372,9 @@ object ChapterProvider { ReadBookConfig.save() Typeface.SANS_SERIF } + } + + private fun getPaint(typeface: Typeface): Pair { // 字体统一处理 val bold = Typeface.create(typeface, Typeface.BOLD) val normal = Typeface.create(typeface, Typeface.NORMAL) @@ -422,25 +395,20 @@ object ChapterProvider { } //标题 - titlePaint = TextPaint() - titlePaint.color = ReadBookConfig.textColor - titlePaint.letterSpacing = ReadBookConfig.letterSpacing - titlePaint.typeface = titleFont - titlePaint.textSize = with(ReadBookConfig) { textSize + titleSize }.sp.toFloat() - titlePaint.isAntiAlias = true + val tPaint = TextPaint() + tPaint.color = ReadBookConfig.textColor + tPaint.letterSpacing = ReadBookConfig.letterSpacing + tPaint.typeface = titleFont + tPaint.textSize = with(ReadBookConfig) { textSize + titleSize }.sp.toFloat() + tPaint.isAntiAlias = true //正文 - contentPaint = TextPaint() - contentPaint.color = ReadBookConfig.textColor - contentPaint.letterSpacing = ReadBookConfig.letterSpacing - contentPaint.typeface = textFont - contentPaint.textSize = ReadBookConfig.textSize.sp.toFloat() - contentPaint.isAntiAlias = true - //间距 - lineSpacingExtra = ReadBookConfig.lineSpacingExtra - paragraphSpacing = ReadBookConfig.paragraphSpacing - titleTopSpacing = ReadBookConfig.titleTopSpacing.dp - titleBottomSpacing = ReadBookConfig.titleBottomSpacing.dp - upVisibleSize() + val cPaint = TextPaint() + cPaint.color = ReadBookConfig.textColor + cPaint.letterSpacing = ReadBookConfig.letterSpacing + cPaint.typeface = textFont + cPaint.textSize = ReadBookConfig.textSize.sp.toFloat() + cPaint.isAntiAlias = true + return Pair(tPaint, cPaint) } /** diff --git a/app/src/main/java/io/legado/app/ui/book/searchContent/SearchContentActivity.kt b/app/src/main/java/io/legado/app/ui/book/searchContent/SearchContentActivity.kt index fe28e2373..6218c900f 100644 --- a/app/src/main/java/io/legado/app/ui/book/searchContent/SearchContentActivity.kt +++ b/app/src/main/java/io/legado/app/ui/book/searchContent/SearchContentActivity.kt @@ -122,7 +122,7 @@ class SearchContentActivity : observeEvent(EventBus.SAVE_CONTENT) { chapter -> viewModel.book?.bookUrl?.let { bookUrl -> if (chapter.bookUrl == bookUrl) { - adapter.cacheFileNames.add(BookHelp.formatChapterName(chapter)) + adapter.cacheFileNames.add(chapter.getFileName()) adapter.notifyItemChanged(chapter.index, true) } } @@ -143,7 +143,7 @@ class SearchContentActivity : App.db.bookChapterDao().getChapterList(viewModel.bookUrl).map { chapter -> val job = async(Dispatchers.IO) { if (isLocalBook - || adapter.cacheFileNames.contains(BookHelp.formatChapterName(chapter)) + || adapter.cacheFileNames.contains(chapter.getFileName()) ) { searchResults = searchChapter(newText, chapter) } diff --git a/app/src/main/java/io/legado/app/ui/book/source/edit/BookSourceEditActivity.kt b/app/src/main/java/io/legado/app/ui/book/source/edit/BookSourceEditActivity.kt index bf1eed674..136088f51 100644 --- a/app/src/main/java/io/legado/app/ui/book/source/edit/BookSourceEditActivity.kt +++ b/app/src/main/java/io/legado/app/ui/book/source/edit/BookSourceEditActivity.kt @@ -25,6 +25,7 @@ import io.legado.app.ui.book.source.debug.BookSourceDebugActivity import io.legado.app.ui.login.SourceLogin import io.legado.app.ui.qrcode.QrCodeActivity import io.legado.app.ui.widget.KeyboardToolPop +import io.legado.app.ui.widget.dialog.TextDialog import io.legado.app.utils.* import kotlinx.android.synthetic.main.activity_book_source_edit.* import org.jetbrains.anko.* @@ -63,7 +64,7 @@ class BookSourceEditActivity : override fun onCompatOptionsItemSelected(item: MenuItem): Boolean { when (item.itemId) { R.id.menu_save -> getSource().let { source -> - if (!source.equal(viewModel.bookSource ?: BookSource())){ + if (!source.equal(viewModel.bookSource ?: BookSource())) { source.lastUpdateTime = System.currentTimeMillis() } if (checkSource(source)) { @@ -81,7 +82,10 @@ class BookSourceEditActivity : R.id.menu_paste_source -> viewModel.pasteSource { upRecyclerView(it) } R.id.menu_qr_code_camera -> startActivityForResult(qrRequestCode) R.id.menu_share_str -> share(GSON.toJson(getSource())) - R.id.menu_share_qr -> shareWithQr(getString(R.string.share_book_source), GSON.toJson(getSource())) + R.id.menu_share_qr -> shareWithQr( + getString(R.string.share_book_source), + GSON.toJson(getSource()) + ) R.id.menu_rule_summary -> { try { val intent = Intent(Intent.ACTION_VIEW) @@ -138,7 +142,7 @@ class BookSourceEditActivity : negativeButton(R.string.no) { super.finish() } - }.show().applyTint() + }.show() } else { super.finish() } @@ -229,6 +233,7 @@ class BookSourceEditActivity : add(EditEntity("sourceRegex", cr?.sourceRegex, R.string.rule_source_regex)) add(EditEntity("replaceRegex", cr?.replaceRegex, R.string.rule_replace_regex)) add(EditEntity("imageStyle", cr?.imageStyle, R.string.rule_image_style)) + add(EditEntity("font", cr?.font, R.string.rule_font)) } //发现 val er = source?.getExploreRule() @@ -332,6 +337,7 @@ class BookSourceEditActivity : "sourceRegex" -> contentRule.sourceRegex = it.value "replaceRegex" -> contentRule.replaceRegex = it.value "imageStyle" -> contentRule.imageStyle = it.value + "font" -> contentRule.font = it.value } } source.ruleSearch = searchRule @@ -344,7 +350,7 @@ class BookSourceEditActivity : private fun checkSource(source: BookSource): Boolean { if (source.bookSourceUrl.isBlank() || source.bookSourceName.isBlank()) { - toast("书源名称和URL不能为空") + toast(R.string.non_null_name_url) return false } return true @@ -367,12 +373,28 @@ class BookSourceEditActivity : override fun sendText(text: String) { if (text == AppConst.keyboardToolChars[0]) { - insertText(AppConst.urlOption) + showHelpDialog() } else { insertText(text) } } + private fun showHelpDialog() { + val items = arrayListOf("插入URL参数", "书源教程", "正则教程") + selector(getString(R.string.help), items) { _, index -> + when (index) { + 0 -> insertText(AppConst.urlOption) + 1 -> openUrl("https://alanskycn.gitee.io/teachme/Rule/source.html") + 2 -> showRegexHelp() + } + } + } + + private fun showRegexHelp() { + val mdText = String(assets.open("help/regexHelp.md").readBytes()) + TextDialog.show(supportFragmentManager, mdText, TextDialog.MD) + } + private fun showKeyboardTopPopupWindow() { mSoftKeyboardTool?.let { if (it.isShowing) return diff --git a/app/src/main/java/io/legado/app/ui/book/source/edit/BookSourceEditAdapter.kt b/app/src/main/java/io/legado/app/ui/book/source/edit/BookSourceEditAdapter.kt index 163d66584..78905dccb 100644 --- a/app/src/main/java/io/legado/app/ui/book/source/edit/BookSourceEditAdapter.kt +++ b/app/src/main/java/io/legado/app/ui/book/source/edit/BookSourceEditAdapter.kt @@ -18,11 +18,9 @@ class BookSourceEditAdapter : RecyclerView.Adapter(R.layout.activity initLiveDataBookSource() initLiveDataGroup() initSelectActionBar() + if (LocalConfig.isFirstOpenBookSources) { + showHelp() + } } override fun onCompatCreateOptionsMenu(menu: Menu): Boolean { @@ -154,6 +159,7 @@ class BookSourceActivity : VMBaseActivity(R.layout.activity R.id.menu_disabled_group -> { search_view.setQuery(getString(R.string.disabled), true) } + R.id.menu_help -> showHelp() } if (item.groupId == R.id.source_group) { search_view.setQuery(item.title, true) @@ -226,6 +232,11 @@ class BookSourceActivity : VMBaseActivity(R.layout.activity }) } + private fun showHelp() { + val text = String(assets.open("help/bookSourcesHelp.md").readBytes()) + TextDialog.show(supportFragmentManager, text, TextDialog.MD) + } + private fun sortCheck(sortId: Int) { if (sort == sortId) { sortAscending += 1 @@ -260,8 +271,8 @@ class BookSourceActivity : VMBaseActivity(R.layout.activity override fun onClickMainAction() { alert(titleResource = R.string.draw, messageResource = R.string.sure_del) { okButton { viewModel.delSelection(adapter.getSelection()) } - noButton { } - }.show().applyTint() + noButton() + }.show() } private fun initSelectActionBar() { @@ -305,8 +316,8 @@ class BookSourceActivity : VMBaseActivity(R.layout.activity } CheckSource.start(this@BookSourceActivity, adapter.getSelection()) } - noButton { } - }.show().applyTint() + noButton() + }.show() } @SuppressLint("InflateParams") @@ -326,8 +337,8 @@ class BookSourceActivity : VMBaseActivity(R.layout.activity } } } - noButton { } - }.show().applyTint() + noButton() + }.show() } @SuppressLint("InflateParams") @@ -347,8 +358,8 @@ class BookSourceActivity : VMBaseActivity(R.layout.activity } } } - noButton { } - }.show().applyTint() + noButton() + }.show() } private fun upGroupMenu() { @@ -389,7 +400,7 @@ class BookSourceActivity : VMBaseActivity(R.layout.activity } } cancelButton() - }.show().applyTint() + }.show() } override fun observeLiveBus() { @@ -403,10 +414,8 @@ class BookSourceActivity : VMBaseActivity(R.layout.activity } } observeEvent(EventBus.CHECK_SOURCE_DONE) { - snackBar?.let { - it.dismiss() - snackBar = null - } + snackBar?.dismiss() + snackBar = null groups.map { group -> if (group.contains("失效")) { search_view.setQuery("失效", true) diff --git a/app/src/main/java/io/legado/app/ui/book/source/manage/GroupManageDialog.kt b/app/src/main/java/io/legado/app/ui/book/source/manage/GroupManageDialog.kt index 74777b264..6b9c10377 100644 --- a/app/src/main/java/io/legado/app/ui/book/source/manage/GroupManageDialog.kt +++ b/app/src/main/java/io/legado/app/ui/book/source/manage/GroupManageDialog.kt @@ -17,9 +17,6 @@ import io.legado.app.base.adapter.ItemViewHolder import io.legado.app.base.adapter.SimpleRecyclerAdapter import io.legado.app.constant.AppPattern import io.legado.app.lib.dialogs.alert -import io.legado.app.lib.dialogs.customView -import io.legado.app.lib.dialogs.noButton -import io.legado.app.lib.dialogs.yesButton import io.legado.app.lib.theme.backgroundColor import io.legado.app.lib.theme.primaryColor import io.legado.app.ui.widget.recycler.VerticalDivider @@ -99,7 +96,7 @@ class GroupManageDialog : DialogFragment(), Toolbar.OnMenuItemClickListener { } } noButton() - }.show().applyTint().requestInputMethod() + }.show().requestInputMethod() } @SuppressLint("InflateParams") @@ -118,7 +115,7 @@ class GroupManageDialog : DialogFragment(), Toolbar.OnMenuItemClickListener { viewModel.upGroup(group, editText?.text?.toString()) } noButton() - }.show().applyTint().requestInputMethod() + }.show().requestInputMethod() } private inner class GroupAdapter(context: Context) : diff --git a/app/src/main/java/io/legado/app/ui/book/toc/BookmarkFragment.kt b/app/src/main/java/io/legado/app/ui/book/toc/BookmarkFragment.kt index 3b5682f5e..16ec8f9ee 100644 --- a/app/src/main/java/io/legado/app/ui/book/toc/BookmarkFragment.kt +++ b/app/src/main/java/io/legado/app/ui/book/toc/BookmarkFragment.kt @@ -15,12 +15,8 @@ import io.legado.app.R import io.legado.app.base.VMBaseFragment import io.legado.app.data.entities.Bookmark import io.legado.app.lib.dialogs.alert -import io.legado.app.lib.dialogs.customView -import io.legado.app.lib.dialogs.noButton -import io.legado.app.lib.dialogs.yesButton import io.legado.app.lib.theme.ATH import io.legado.app.ui.widget.recycler.VerticalDivider -import io.legado.app.utils.applyTint import io.legado.app.utils.getViewModelOfActivity import io.legado.app.utils.requestInputMethod import kotlinx.android.synthetic.main.dialog_edit_text.view.* @@ -109,7 +105,7 @@ class BookmarkFragment : VMBaseFragment(R.layout.fragment_ neutralButton(R.string.delete) { App.db.bookmarkDao().delete(bookmark) } - }.show().applyTint().requestInputMethod() + }.show().requestInputMethod() } } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/book/toc/ChapterListAdapter.kt b/app/src/main/java/io/legado/app/ui/book/toc/ChapterListAdapter.kt index 9a994f7ca..a92d78f9d 100644 --- a/app/src/main/java/io/legado/app/ui/book/toc/ChapterListAdapter.kt +++ b/app/src/main/java/io/legado/app/ui/book/toc/ChapterListAdapter.kt @@ -6,7 +6,6 @@ import io.legado.app.R import io.legado.app.base.adapter.ItemViewHolder import io.legado.app.base.adapter.SimpleRecyclerAdapter import io.legado.app.data.entities.BookChapter -import io.legado.app.help.BookHelp import io.legado.app.lib.theme.accentColor import io.legado.app.utils.getCompatColor import io.legado.app.utils.visible @@ -22,8 +21,7 @@ class ChapterListAdapter(context: Context, val callback: Callback) : override fun convert(holder: ItemViewHolder, item: BookChapter, payloads: MutableList) { with(holder.itemView) { val isDur = callback.durChapterIndex() == item.index - val cached = callback.isLocalBook - || cacheFileNames.contains(BookHelp.formatChapterName(item)) + val cached = callback.isLocalBook || cacheFileNames.contains(item.getFileName()) if (payloads.isEmpty()) { if (isDur) { tv_chapter_name.setTextColor(context.accentColor) diff --git a/app/src/main/java/io/legado/app/ui/book/toc/ChapterListFragment.kt b/app/src/main/java/io/legado/app/ui/book/toc/ChapterListFragment.kt index 679b53238..ba20d22aa 100644 --- a/app/src/main/java/io/legado/app/ui/book/toc/ChapterListFragment.kt +++ b/app/src/main/java/io/legado/app/ui/book/toc/ChapterListFragment.kt @@ -110,7 +110,7 @@ class ChapterListFragment : VMBaseFragment(R.layout.fragme observeEvent(EventBus.SAVE_CONTENT) { chapter -> viewModel.book?.bookUrl?.let { bookUrl -> if (chapter.bookUrl == bookUrl) { - adapter.cacheFileNames.add(BookHelp.formatChapterName(chapter)) + adapter.cacheFileNames.add(chapter.getFileName()) adapter.notifyItemChanged(chapter.index, true) } } diff --git a/app/src/main/java/io/legado/app/ui/config/BackupConfigFragment.kt b/app/src/main/java/io/legado/app/ui/config/BackupConfigFragment.kt index 097148736..33b708d59 100644 --- a/app/src/main/java/io/legado/app/ui/config/BackupConfigFragment.kt +++ b/app/src/main/java/io/legado/app/ui/config/BackupConfigFragment.kt @@ -4,6 +4,9 @@ import android.content.Intent import android.content.SharedPreferences import android.os.Bundle import android.text.InputType +import android.view.Menu +import android.view.MenuInflater +import android.view.MenuItem import android.view.View import androidx.preference.EditTextPreference import androidx.preference.ListPreference @@ -11,11 +14,13 @@ import androidx.preference.Preference import io.legado.app.R import io.legado.app.base.BasePreferenceFragment import io.legado.app.constant.PreferKey +import io.legado.app.help.LocalConfig import io.legado.app.help.storage.Restore import io.legado.app.lib.dialogs.alert import io.legado.app.lib.theme.ATH import io.legado.app.lib.theme.accentColor import io.legado.app.ui.filepicker.FilePickerDialog +import io.legado.app.ui.widget.dialog.TextDialog import io.legado.app.utils.applyTint import io.legado.app.utils.getPrefString @@ -55,6 +60,28 @@ class BackupConfigFragment : BasePreferenceFragment(), super.onViewCreated(view, savedInstanceState) preferenceManager.sharedPreferences.registerOnSharedPreferenceChangeListener(this) ATH.applyEdgeEffectColor(listView) + setHasOptionsMenu(true) + if (LocalConfig.isFirstOpenBackup) { + showHelp() + } + } + + override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) { + super.onCreateOptionsMenu(menu, inflater) + inflater.inflate(R.menu.backup_restore, menu) + menu.applyTint(requireContext()) + } + + override fun onOptionsItemSelected(item: MenuItem): Boolean { + when (item.itemId) { + R.id.menu_help -> showHelp() + } + return super.onOptionsItemSelected(item) + } + + private fun showHelp() { + val text = String(requireContext().assets.open("help/webDavHelp.md").readBytes()) + TextDialog.show(childFragmentManager, text, TextDialog.MD) } override fun onDestroy() { @@ -126,11 +153,10 @@ class BackupConfigFragment : BasePreferenceFragment(), multiChoiceItems(Restore.ignoreTitle, checkedItems) { _, which, isChecked -> Restore.ignoreConfig[Restore.ignoreKeys[which]] = isChecked } - }.show() - .applyTint() - .setOnDismissListener { + onDismiss { Restore.saveIgnoreConfig() } + }.show() } override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { diff --git a/app/src/main/java/io/legado/app/ui/config/OtherConfigFragment.kt b/app/src/main/java/io/legado/app/ui/config/OtherConfigFragment.kt index 1a30c9267..5b3ab31f5 100644 --- a/app/src/main/java/io/legado/app/ui/config/OtherConfigFragment.kt +++ b/app/src/main/java/io/legado/app/ui/config/OtherConfigFragment.kt @@ -22,8 +22,6 @@ import io.legado.app.help.BookHelp import io.legado.app.help.permission.Permissions import io.legado.app.help.permission.PermissionsCompat import io.legado.app.lib.dialogs.alert -import io.legado.app.lib.dialogs.noButton -import io.legado.app.lib.dialogs.okButton import io.legado.app.lib.dialogs.selector import io.legado.app.lib.theme.ATH import io.legado.app.receiver.SharedReceiverActivity @@ -149,15 +147,17 @@ class OtherConfigFragment : BasePreferenceFragment(), } private fun clearCache() { - requireContext().alert(titleResource = R.string.clear_cache, - messageResource = R.string.sure_del) { + requireContext().alert( + titleResource = R.string.clear_cache, + messageResource = R.string.sure_del + ) { okButton { BookHelp.clearCache() FileUtils.deleteFile(requireActivity().cacheDir.absolutePath) toast(R.string.clear_cache_success) } noButton() - }.show().applyTint() + }.show() } private fun selectDefaultCover() { 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 31ddeae8b..045ddee39 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,9 +18,6 @@ import io.legado.app.help.AppConfig import io.legado.app.help.LauncherIconHelp import io.legado.app.help.ThemeConfig import io.legado.app.lib.dialogs.alert -import io.legado.app.lib.dialogs.customView -import io.legado.app.lib.dialogs.noButton -import io.legado.app.lib.dialogs.okButton import io.legado.app.lib.theme.ATH import io.legado.app.ui.widget.number.NumberPickerDialog import io.legado.app.ui.widget.prefs.ColorPreference @@ -195,8 +192,8 @@ class ThemeConfigFragment : BasePreferenceFragment(), } } } - noButton { } - }.show().applyTint() + noButton() + }.show() } private fun upTheme(isNightTheme: Boolean) { diff --git a/app/src/main/java/io/legado/app/ui/config/ThemeListDialog.kt b/app/src/main/java/io/legado/app/ui/config/ThemeListDialog.kt index 60a5486f7..1f3def447 100644 --- a/app/src/main/java/io/legado/app/ui/config/ThemeListDialog.kt +++ b/app/src/main/java/io/legado/app/ui/config/ThemeListDialog.kt @@ -13,8 +13,6 @@ import io.legado.app.base.adapter.ItemViewHolder import io.legado.app.base.adapter.SimpleRecyclerAdapter import io.legado.app.help.ThemeConfig import io.legado.app.lib.dialogs.alert -import io.legado.app.lib.dialogs.noButton -import io.legado.app.lib.dialogs.okButton import io.legado.app.lib.theme.primaryColor import io.legado.app.ui.widget.recycler.VerticalDivider import io.legado.app.utils.* @@ -88,7 +86,7 @@ class ThemeListDialog : BaseDialogFragment(), Toolbar.OnMenuItemClickListener { initData() } noButton() - }.show().applyTint() + }.show() } fun share(index: Int) { diff --git a/app/src/main/java/io/legado/app/ui/filepicker/FilePicker.kt b/app/src/main/java/io/legado/app/ui/filepicker/FilePicker.kt index d84706d0c..ada36f5ff 100644 --- a/app/src/main/java/io/legado/app/ui/filepicker/FilePicker.kt +++ b/app/src/main/java/io/legado/app/ui/filepicker/FilePicker.kt @@ -9,7 +9,6 @@ import io.legado.app.base.BaseActivity import io.legado.app.help.permission.Permissions import io.legado.app.help.permission.PermissionsCompat import io.legado.app.lib.dialogs.alert -import io.legado.app.utils.applyTint @Suppress("unused") object FilePicker { @@ -62,7 +61,7 @@ object FilePicker { } } } - }.show().applyTint() + }.show() } fun selectFolder( @@ -113,7 +112,7 @@ object FilePicker { } } } - }.show().applyTint() + }.show() } fun selectFile( @@ -171,7 +170,7 @@ object FilePicker { } } } - }.show().applyTint() + }.show() } fun selectFile( @@ -229,7 +228,7 @@ object FilePicker { } } } - }.show().applyTint() + }.show() } private fun createSelectFileIntent(): Intent { 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 59a5bd79c..66970d7cc 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 @@ -17,6 +17,7 @@ import io.legado.app.constant.EventBus import io.legado.app.constant.PreferKey import io.legado.app.help.AppConfig import io.legado.app.help.BookHelp +import io.legado.app.help.LocalConfig import io.legado.app.help.storage.Backup import io.legado.app.lib.theme.ATH import io.legado.app.lib.theme.elevation @@ -102,7 +103,10 @@ class MainActivity : VMBaseActivity(R.layout.activity_main), private fun upVersion() { if (getPrefInt(PreferKey.versionCode) != App.versionCode) { putPrefInt(PreferKey.versionCode, App.versionCode) - if (!BuildConfig.DEBUG) { + if (LocalConfig.isFirstOpenApp) { + val text = String(assets.open("help/appHelp.md").readBytes()) + TextDialog.show(supportFragmentManager, text, TextDialog.MD) + } else if (!BuildConfig.DEBUG) { val log = String(assets.open("updateLog.md").readBytes()) TextDialog.show(supportFragmentManager, log, TextDialog.MD, 5000, true) } 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 e1b37f31e..3a8d7138f 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 @@ -16,9 +16,6 @@ import io.legado.app.constant.AppConst import io.legado.app.constant.PreferKey import io.legado.app.data.entities.BookGroup import io.legado.app.lib.dialogs.alert -import io.legado.app.lib.dialogs.customView -import io.legado.app.lib.dialogs.noButton -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 @@ -145,7 +142,7 @@ class BookshelfFragment : VMBaseFragment(R.layout.fragment_b @SuppressLint("InflateParams") private fun configBookshelf() { - requireContext().alert(titleResource = R.string.bookshelf_layout) { + alert(titleResource = R.string.bookshelf_layout) { val bookshelfLayout = getPrefInt(PreferKey.bookshelfLayout) val bookshelfSort = getPrefInt(PreferKey.bookshelfSort) val root = LayoutInflater.from(requireContext()) @@ -171,7 +168,7 @@ class BookshelfFragment : VMBaseFragment(R.layout.fragment_b } } noButton() - }.show().applyTint() + }.show() } @SuppressLint("InflateParams") @@ -187,9 +184,9 @@ class BookshelfFragment : VMBaseFragment(R.layout.fragment_b editText?.text?.toString()?.let { viewModel.addBookByUrl(it) } - } - noButton { } - }.show().applyTint() + } + noButton() + }.show() } override fun onTabReselected(tab: TabLayout.Tab) { 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 967490d6a..8a7fb2016 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 @@ -50,7 +50,7 @@ class MyFragment : BaseFragment(R.layout.fragment_my_config), FilePickerDialog.C override fun onCompatOptionsItemSelected(item: MenuItem) { when (item.itemId) { R.id.menu_help -> { - val text = String(requireContext().assets.open("help/help.md").readBytes()) + val text = String(requireContext().assets.open("help/appHelp.md").readBytes()) TextDialog.show(childFragmentManager, text, TextDialog.MD) } } diff --git a/app/src/main/java/io/legado/app/ui/replace/GroupManageDialog.kt b/app/src/main/java/io/legado/app/ui/replace/GroupManageDialog.kt index 53e5d96a0..031c45b7e 100644 --- a/app/src/main/java/io/legado/app/ui/replace/GroupManageDialog.kt +++ b/app/src/main/java/io/legado/app/ui/replace/GroupManageDialog.kt @@ -17,9 +17,6 @@ import io.legado.app.base.adapter.ItemViewHolder import io.legado.app.base.adapter.SimpleRecyclerAdapter import io.legado.app.constant.AppPattern import io.legado.app.lib.dialogs.alert -import io.legado.app.lib.dialogs.customView -import io.legado.app.lib.dialogs.noButton -import io.legado.app.lib.dialogs.yesButton import io.legado.app.lib.theme.backgroundColor import io.legado.app.lib.theme.primaryColor import io.legado.app.ui.widget.recycler.VerticalDivider @@ -99,7 +96,7 @@ class GroupManageDialog : DialogFragment(), Toolbar.OnMenuItemClickListener { } } noButton() - }.show().applyTint().requestInputMethod() + }.show().requestInputMethod() } @SuppressLint("InflateParams") @@ -118,7 +115,7 @@ class GroupManageDialog : DialogFragment(), Toolbar.OnMenuItemClickListener { viewModel.upGroup(group, editText?.text?.toString()) } noButton() - }.show().applyTint().requestInputMethod() + }.show().requestInputMethod() } private inner class GroupAdapter(context: Context) : diff --git a/app/src/main/java/io/legado/app/ui/replace/ReplaceRuleActivity.kt b/app/src/main/java/io/legado/app/ui/replace/ReplaceRuleActivity.kt index e81b2dd4e..1507f163e 100644 --- a/app/src/main/java/io/legado/app/ui/replace/ReplaceRuleActivity.kt +++ b/app/src/main/java/io/legado/app/ui/replace/ReplaceRuleActivity.kt @@ -22,7 +22,7 @@ import io.legado.app.data.entities.ReplaceRule import io.legado.app.help.BookHelp import io.legado.app.help.IntentDataHelp import io.legado.app.help.coroutine.Coroutine -import io.legado.app.lib.dialogs.* +import io.legado.app.lib.dialogs.alert import io.legado.app.lib.theme.ATH import io.legado.app.lib.theme.primaryTextColor import io.legado.app.ui.association.ImportReplaceRuleActivity @@ -134,9 +134,8 @@ class ReplaceRuleActivity : private fun delSourceDialog() { alert(titleResource = R.string.draw, messageResource = R.string.sure_del) { okButton { viewModel.delSelection(adapter.getSelection()) } - noButton { } - } - .show().applyTint() + noButton() + }.show() } private fun observeReplaceRuleData(key: String? = null) { @@ -233,7 +232,7 @@ class ReplaceRuleActivity : } } cancelButton() - }.show().applyTint() + }.show() } override fun onQueryTextChange(newText: String?): Boolean { diff --git a/app/src/main/java/io/legado/app/ui/replace/edit/ReplaceEditActivity.kt b/app/src/main/java/io/legado/app/ui/replace/edit/ReplaceEditActivity.kt index d690a0b74..ee07a9244 100644 --- a/app/src/main/java/io/legado/app/ui/replace/edit/ReplaceEditActivity.kt +++ b/app/src/main/java/io/legado/app/ui/replace/edit/ReplaceEditActivity.kt @@ -22,6 +22,7 @@ import io.legado.app.utils.postEvent import kotlinx.android.synthetic.main.activity_replace_edit.* import org.jetbrains.anko.displayMetrics import org.jetbrains.anko.sdk27.listeners.onClick +import org.jetbrains.anko.selector import org.jetbrains.anko.toast import kotlin.math.abs @@ -64,8 +65,7 @@ class ReplaceEditActivity : upReplaceView(it) } iv_help.onClick { - val mdText = String(assets.open("help/regex.md").readBytes()) - TextDialog.show(supportFragmentManager, mdText, TextDialog.MD) + showRegexHelp() } } @@ -128,13 +128,26 @@ class ReplaceEditActivity : override fun sendText(text: String) { if (text == AppConst.keyboardToolChars[0]) { - val view = window?.decorView?.findFocus() - view?.clearFocus() + showHelpDialog() } else { insertText(text) } } + private fun showHelpDialog() { + val items = arrayListOf("正则教程") + selector(getString(R.string.help), items) { _, index -> + when (index) { + 0 -> showRegexHelp() + } + } + } + + private fun showRegexHelp() { + val mdText = String(assets.open("help/regexHelp.md").readBytes()) + TextDialog.show(supportFragmentManager, mdText, TextDialog.MD) + } + private fun showKeyboardTopPopupWindow() { mSoftKeyboardTool?.let { if (it.isShowing) return diff --git a/app/src/main/java/io/legado/app/ui/rss/read/ReadRssActivity.kt b/app/src/main/java/io/legado/app/ui/rss/read/ReadRssActivity.kt index 75e7bb108..c0112f050 100644 --- a/app/src/main/java/io/legado/app/ui/rss/read/ReadRssActivity.kt +++ b/app/src/main/java/io/legado/app/ui/rss/read/ReadRssActivity.kt @@ -16,6 +16,9 @@ import io.legado.app.base.VMBaseActivity import io.legado.app.lib.theme.DrawableUtils import io.legado.app.lib.theme.primaryTextColor import io.legado.app.service.help.Download +import io.legado.app.ui.association.ImportBookSourceActivity +import io.legado.app.ui.association.ImportReplaceRuleActivity +import io.legado.app.ui.association.ImportRssSourceActivity import io.legado.app.ui.filepicker.FilePicker import io.legado.app.ui.filepicker.FilePickerDialog import io.legado.app.utils.* @@ -107,11 +110,39 @@ class ReadRssActivity : VMBaseActivity(R.layout.activity_rss_r view: WebView?, request: WebResourceRequest? ): Boolean { - if (request?.url?.scheme == "http" || request?.url?.scheme == "https") { - return false - } - request?.url?.let { - openUrl(it) + request?.let { + if (it.url.scheme == "http" || it.url.scheme == "https") { + return false + } else if (it.url.scheme == "yuedu") { + when (it.url.host) { + "booksource" -> { + val intent = Intent( + this@ReadRssActivity, + ImportBookSourceActivity::class.java + ) + intent.data = it.url + startActivity(intent) + } + "rsssource" -> { + val intent = Intent( + this@ReadRssActivity, + ImportRssSourceActivity::class.java + ) + intent.data = it.url + startActivity(intent) + } + "replace" -> { + val intent = Intent( + this@ReadRssActivity, + ImportReplaceRuleActivity::class.java + ) + intent.data = it.url + startActivity(intent) + } + } + return true + } + openUrl(it.url) } return true } diff --git a/app/src/main/java/io/legado/app/ui/rss/source/edit/RssSourceEditActivity.kt b/app/src/main/java/io/legado/app/ui/rss/source/edit/RssSourceEditActivity.kt index cf21ca604..94396919d 100644 --- a/app/src/main/java/io/legado/app/ui/rss/source/edit/RssSourceEditActivity.kt +++ b/app/src/main/java/io/legado/app/ui/rss/source/edit/RssSourceEditActivity.kt @@ -20,6 +20,7 @@ import io.legado.app.lib.theme.ATH import io.legado.app.ui.qrcode.QrCodeActivity import io.legado.app.ui.rss.source.debug.RssSourceDebugActivity import io.legado.app.ui.widget.KeyboardToolPop +import io.legado.app.ui.widget.dialog.TextDialog import io.legado.app.utils.* import kotlinx.android.synthetic.main.activity_rss_source_edit.* import org.jetbrains.anko.* @@ -56,7 +57,7 @@ class RssSourceEditActivity : negativeButton(R.string.no) { super.finish() } - }.show().applyTint() + }.show() } else { super.finish() } @@ -187,12 +188,28 @@ class RssSourceEditActivity : override fun sendText(text: String) { if (text == AppConst.keyboardToolChars[0]) { - insertText(AppConst.urlOption) + showHelpDialog() } else { insertText(text) } } + private fun showHelpDialog() { + val items = arrayListOf("插入URL参数", "订阅源教程", "正则教程") + selector(getString(R.string.help), items) { _, index -> + when (index) { + 0 -> insertText(AppConst.urlOption) + 1 -> openUrl("https://alanskycn.gitee.io/teachme/Rule/rss.html") + 2 -> showRegexHelp() + } + } + } + + private fun showRegexHelp() { + val mdText = String(assets.open("help/regexHelp.md").readBytes()) + TextDialog.show(supportFragmentManager, mdText, TextDialog.MD) + } + private fun showKeyboardTopPopupWindow() { mSoftKeyboardTool?.let { if (it.isShowing) return diff --git a/app/src/main/java/io/legado/app/ui/rss/source/manage/GroupManageDialog.kt b/app/src/main/java/io/legado/app/ui/rss/source/manage/GroupManageDialog.kt index 0aeafc5f1..b0c84786d 100644 --- a/app/src/main/java/io/legado/app/ui/rss/source/manage/GroupManageDialog.kt +++ b/app/src/main/java/io/legado/app/ui/rss/source/manage/GroupManageDialog.kt @@ -17,9 +17,6 @@ import io.legado.app.base.adapter.ItemViewHolder import io.legado.app.base.adapter.SimpleRecyclerAdapter import io.legado.app.constant.AppPattern import io.legado.app.lib.dialogs.alert -import io.legado.app.lib.dialogs.customView -import io.legado.app.lib.dialogs.noButton -import io.legado.app.lib.dialogs.yesButton import io.legado.app.lib.theme.accentColor import io.legado.app.lib.theme.primaryColor import io.legado.app.ui.widget.recycler.VerticalDivider @@ -96,7 +93,7 @@ class GroupManageDialog : BaseDialogFragment(), Toolbar.OnMenuItemClickListener } } noButton() - }.show().applyTint().requestInputMethod() + }.show().requestInputMethod() } @SuppressLint("InflateParams") @@ -115,7 +112,7 @@ class GroupManageDialog : BaseDialogFragment(), Toolbar.OnMenuItemClickListener viewModel.upGroup(group, editText?.text?.toString()) } noButton() - }.show().applyTint().requestInputMethod() + }.show().requestInputMethod() } private inner class GroupAdapter(context: Context) : diff --git a/app/src/main/java/io/legado/app/ui/rss/source/manage/RssSourceActivity.kt b/app/src/main/java/io/legado/app/ui/rss/source/manage/RssSourceActivity.kt index 72241a105..98cebc35a 100644 --- a/app/src/main/java/io/legado/app/ui/rss/source/manage/RssSourceActivity.kt +++ b/app/src/main/java/io/legado/app/ui/rss/source/manage/RssSourceActivity.kt @@ -20,7 +20,7 @@ import io.legado.app.base.VMBaseActivity import io.legado.app.constant.AppPattern import io.legado.app.data.entities.RssSource import io.legado.app.help.IntentDataHelp -import io.legado.app.lib.dialogs.* +import io.legado.app.lib.dialogs.alert import io.legado.app.lib.theme.ATH import io.legado.app.lib.theme.primaryTextColor import io.legado.app.ui.association.ImportRssSourceActivity @@ -180,9 +180,8 @@ class RssSourceActivity : VMBaseActivity(R.layout.activity_r private fun delSourceDialog() { alert(titleResource = R.string.draw, messageResource = R.string.sure_del) { okButton { viewModel.delSelection(adapter.getSelection()) } - noButton { } - } - .show().applyTint() + noButton() + }.show() } private fun upGroupMenu() { @@ -243,7 +242,7 @@ class RssSourceActivity : VMBaseActivity(R.layout.activity_r } } cancelButton() - }.show().applyTint() + }.show() } override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { 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 5a8134c43..3c4716d56 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 @@ -28,6 +28,7 @@ import kotlinx.coroutines.Dispatchers.Main import kotlinx.coroutines.launch import java.io.File import java.util.* +import kotlin.collections.ArrayList class FontSelectDialog : BaseDialogFragment(), FilePickerDialog.CallBack, @@ -150,8 +151,7 @@ class FontSelectDialog : BaseDialogFragment(), fontItems.add(item) } } - fontItems.addAll(getLocalFonts()) - fontItems.sortedBy { it.name } + mergeFontItems(fontItems, getLocalFonts()) }.onSuccess { adapter?.setItems(it) }.onError { @@ -186,8 +186,7 @@ class FontSelectDialog : BaseDialogFragment(), ) ) } - fontItems.addAll(getLocalFonts()) - fontItems.sortedBy { it.name } + mergeFontItems(fontItems, getLocalFonts()) }.onSuccess { adapter?.setItems(it) }.onError { @@ -195,6 +194,27 @@ class FontSelectDialog : BaseDialogFragment(), } } + private fun mergeFontItems( + items1: ArrayList, + items2: ArrayList + ): ArrayList { + val items = ArrayList(items1) + items2.forEach { item2 -> + var isInFirst = false + items1.forEach for1@{ item1 -> + if (item2.name == item1.name) { + isInFirst = true + return@for1 + } + } + if (!isInFirst) { + items.add(item2) + } + } + items.sortBy { it.name } + return items + } + override fun onClick(docItem: DocItem) { execute { FileUtils.deleteFile(fontFolder.absolutePath) diff --git a/app/src/main/java/io/legado/app/ui/widget/text/StrokeTextView.kt b/app/src/main/java/io/legado/app/ui/widget/text/StrokeTextView.kt index 62f8f18f2..b992f772f 100644 --- a/app/src/main/java/io/legado/app/ui/widget/text/StrokeTextView.kt +++ b/app/src/main/java/io/legado/app/ui/widget/text/StrokeTextView.kt @@ -9,6 +9,7 @@ import io.legado.app.utils.ColorUtils import io.legado.app.utils.dp import io.legado.app.utils.getCompatColor +@Suppress("unused") open class StrokeTextView(context: Context, attrs: AttributeSet?) : AppCompatTextView(context, attrs) { @@ -40,7 +41,7 @@ open class StrokeTextView(context: Context, attrs: AttributeSet?) : .setSelectedStrokeColor(context.getCompatColor(R.color.accent)) .setPressedBgColor(context.getCompatColor(R.color.transparent30)) .create() - this.setTextColor( + setTextColor( Selector.colorBuild() .setDefaultColor(context.getCompatColor(R.color.secondaryText)) .setSelectedColor(context.getCompatColor(R.color.accent)) @@ -58,7 +59,7 @@ open class StrokeTextView(context: Context, attrs: AttributeSet?) : .setSelectedStrokeColor(context.accentColor) .setPressedBgColor(context.getCompatColor(R.color.transparent30)) .create() - this.setTextColor( + setTextColor( Selector.colorBuild() .setDefaultColor(context.getPrimaryTextColor(isLight)) .setSelectedColor(context.accentColor) @@ -75,7 +76,7 @@ open class StrokeTextView(context: Context, attrs: AttributeSet?) : .setSelectedStrokeColor(ThemeStore.accentColor(context)) .setPressedBgColor(context.getCompatColor(R.color.transparent30)) .create() - this.setTextColor( + setTextColor( Selector.colorBuild() .setDefaultColor(ThemeStore.textColorSecondary(context)) .setSelectedColor(ThemeStore.accentColor(context)) diff --git a/app/src/main/java/io/legado/app/utils/EncoderUtils.kt b/app/src/main/java/io/legado/app/utils/EncoderUtils.kt index 8d7b904f8..409cb802c 100644 --- a/app/src/main/java/io/legado/app/utils/EncoderUtils.kt +++ b/app/src/main/java/io/legado/app/utils/EncoderUtils.kt @@ -1,7 +1,6 @@ package io.legado.app.utils import android.util.Base64 -import java.nio.charset.StandardCharsets @Suppress("unused") object EncoderUtils { @@ -28,11 +27,7 @@ object EncoderUtils { @JvmOverloads fun base64Decode(str: String, flags: Int = Base64.DEFAULT): String { val bytes = Base64.decode(str, flags) - return try { - String(bytes, StandardCharsets.UTF_8) - } catch (e: Exception) { - String(bytes) - } + return String(bytes) } @JvmOverloads diff --git a/app/src/main/res/drawable/ic_baseline_close.xml b/app/src/main/res/drawable/ic_baseline_close.xml new file mode 100644 index 000000000..b8af066c7 --- /dev/null +++ b/app/src/main/res/drawable/ic_baseline_close.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/shape_translucent_card.xml b/app/src/main/res/drawable/shape_translucent_card.xml new file mode 100644 index 000000000..827bc335d --- /dev/null +++ b/app/src/main/res/drawable/shape_translucent_card.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/dialog_click_action_config.xml b/app/src/main/res/layout/dialog_click_action_config.xml new file mode 100644 index 000000000..af1c00029 --- /dev/null +++ b/app/src/main/res/layout/dialog_click_action_config.xml @@ -0,0 +1,167 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/view_preference.xml b/app/src/main/res/layout/view_preference.xml index 0fb402876..602619d51 100644 --- a/app/src/main/res/layout/view_preference.xml +++ b/app/src/main/res/layout/view_preference.xml @@ -8,7 +8,7 @@ android:paddingTop="10dp" android:paddingRight="16dp" android:paddingBottom="10dp" - android:minHeight="42dp" + android:minHeight="60dp" android:clickable="true" android:orientation="horizontal" android:gravity="center_vertical" diff --git a/app/src/main/res/menu/backup_restore.xml b/app/src/main/res/menu/backup_restore.xml new file mode 100644 index 000000000..02b6acbd0 --- /dev/null +++ b/app/src/main/res/menu/backup_restore.xml @@ -0,0 +1,13 @@ + + + + + + diff --git a/app/src/main/res/menu/book_source.xml b/app/src/main/res/menu/book_source.xml index 2e32f7c77..8bc90e484 100644 --- a/app/src/main/res/menu/book_source.xml +++ b/app/src/main/res/menu/book_source.xml @@ -102,5 +102,10 @@ android:title="@string/share_selected_source" app:showAsAction="never" /> + diff --git a/app/src/main/res/menu/import_source.xml b/app/src/main/res/menu/import_source.xml index 8a2971e3f..84dae94ca 100644 --- a/app/src/main/res/menu/import_source.xml +++ b/app/src/main/res/menu/import_source.xml @@ -20,4 +20,10 @@ android:title="@string/un_select_all" app:showAsAction="never" /> + + \ No newline at end of file diff --git a/app/src/main/res/menu/read_book.xml b/app/src/main/res/menu/read_book.xml index 98cbc1b5e..eb9aedd34 100644 --- a/app/src/main/res/menu/read_book.xml +++ b/app/src/main/res/menu/read_book.xml @@ -96,4 +96,9 @@ android:title="@string/book_info" app:showAsAction="never" /> + + diff --git a/app/src/main/res/values-zh-rHK/strings.xml b/app/src/main/res/values-zh-rHK/strings.xml index bec4e31cb..57f2f452a 100644 --- a/app/src/main/res/values-zh-rHK/strings.xml +++ b/app/src/main/res/values-zh-rHK/strings.xml @@ -197,7 +197,6 @@ 音量鍵翻頁 點擊翻頁 - 點擊總是翻下一頁 翻頁動畫 屏幕超時 返回 @@ -413,6 +412,7 @@ 正文下一頁 URL 規則 (nextContentUrl) webJs 資源正則 (sourceRegex) + 字體(font) 圖標 (sourceIcon) 列表規則 (ruleArticles) @@ -483,7 +483,7 @@ 未獲取到書名 輸入替換規則網址 搜索列表獲取成功%d - 書源名稱和 URL 不能為空 + 名稱和 URL 不能為空 圖庫 領支付寶紅包 沒有獲取到更新地址 @@ -780,5 +780,11 @@ 智能扫描 拷贝URL 没有书籍 + 保留原名 + 点击区域设置 + 关闭 + 下一页 + 上一页 + 无操作 diff --git a/app/src/main/res/values-zh-rTW/strings.xml b/app/src/main/res/values-zh-rTW/strings.xml index ed94c9143..438097813 100644 --- a/app/src/main/res/values-zh-rTW/strings.xml +++ b/app/src/main/res/values-zh-rTW/strings.xml @@ -197,7 +197,6 @@ 音量鍵翻頁 點擊翻頁 - 點擊總是翻下一頁 翻頁動畫 螢幕超時 返回 @@ -414,6 +413,7 @@ 正文下一頁URL規則(nextContentUrl) webJs 資源正則(sourceRegex) + 字體(font) 圖示(sourceIcon) 列表規則(ruleArticles) @@ -484,7 +484,7 @@ 未獲取到書名 輸入取代規則網址 搜尋列表獲取成功%d - 書源名稱和URL不能為空 + 名稱和URL不能為空 圖庫 領支付寶紅包 沒有獲取到更新地址 @@ -780,5 +780,11 @@ 智能扫描 拷贝URL 没有书籍 + 保留原名 + 点击区域设置 + 关闭 + 下一页 + 上一页 + 无操作 diff --git a/app/src/main/res/values-zh/strings.xml b/app/src/main/res/values-zh/strings.xml index 476ec42d9..7e5360666 100644 --- a/app/src/main/res/values-zh/strings.xml +++ b/app/src/main/res/values-zh/strings.xml @@ -199,7 +199,6 @@ 音量键翻页 点击翻页 - 点击总是翻下一页 翻页动画 屏幕超时 返回 @@ -419,6 +418,7 @@ 正文下一页URL规则(nextContentUrl) webJs 资源正则(sourceRegex) + 字体(font) 图标(sourceIcon) 列表规则(ruleArticles) @@ -490,7 +490,7 @@ 未获取到书名 输入替换规则网址 搜索列表获取成功%d - 书源名称和URL不能为空 + 名称和URL不能为空 图库 领支付宝红包 没有获取到更新地址 @@ -783,5 +783,11 @@ 智能扫描 拷贝URL 没有书籍 + 保留原名 + 点击区域设置 + 关闭 + 下一页 + 上一页 + 无操作 diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 4270818c8..adb2d20a5 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -200,7 +200,6 @@ Book Volume keys to turn page Tap screen to turn page - Tap screen always to next page Flip animation Keep screen awake Back @@ -423,6 +422,7 @@ 资源正则(sourceRegex) 替换规则(replaceRegex) 图片样式(imageStyle) + 字体(font) 图标(sourceIcon) 列表规则(ruleArticles) @@ -493,7 +493,7 @@ No bookName Input replacement rule URL Search list obtained successfully%d - Source name and URL cannot be empty + name and URL cannot be empty Gallery get AliPay red envelopes No update address @@ -786,5 +786,11 @@ 智能扫描 拷贝URL 没有书籍 + 保留原名 + 点击区域设置 + 关闭 + 下一页 + 上一页 + 无操作 diff --git a/app/src/main/res/xml/pref_config_read.xml b/app/src/main/res/xml/pref_config_read.xml index 7e2da9c1c..65b8c94e9 100644 --- a/app/src/main/res/xml/pref_config_read.xml +++ b/app/src/main/res/xml/pref_config_read.xml @@ -62,20 +62,6 @@ app:iconSpaceReserved="false" app:isBottomBackground="true" /> - - - - + +