diff --git a/.gitignore b/.gitignore index 700c700fe..e9f1bfd7b 100644 --- a/.gitignore +++ b/.gitignore @@ -13,3 +13,11 @@ node_modules/ /app/google /app/gradle.properties package-lock.json + +*__gen.go +*__ignore.go +*.swp +*.swo +~i_* +ig_* +zzzig_* diff --git a/app/build.gradle b/app/build.gradle index 24cbf4510..265d741ee 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -56,7 +56,7 @@ android { signingConfig signingConfigs.myConfig } applicationIdSuffix '.release' - minifyEnabled true + minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' } debug { @@ -66,7 +66,6 @@ android { applicationIdSuffix '.debug' versionNameSuffix 'debug' minifyEnabled false - proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } android.applicationVariants.all { variant -> variant.outputs.all { @@ -117,11 +116,11 @@ dependencies { implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" //fireBase - implementation 'com.google.firebase:firebase-core:17.4.1' + implementation 'com.google.firebase:firebase-core:17.4.3' implementation 'com.crashlytics.sdk.android:crashlytics:2.10.1' //androidX - implementation 'androidx.core:core-ktx:1.2.0' + implementation 'androidx.core:core-ktx:1.3.0' implementation 'androidx.appcompat:appcompat:1.1.0' implementation 'androidx.media:media:1.1.0' implementation 'androidx.preference:preference:1.1.1' @@ -154,7 +153,7 @@ dependencies { implementation 'com.jeremyliao:live-event-bus-x:1.5.7' //协程 - def coroutines_version = '1.3.3' + def coroutines_version = '1.3.7' implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutines_version" implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutines_version" @@ -199,8 +198,8 @@ dependencies { apply plugin: 'com.google.gms.google-services' -afterEvaluate { - for (Task task : project.tasks.matching { it.name.startsWith('crashlyticsUploadDeobs') }) { - task.enabled = false - } -} \ No newline at end of file +//afterEvaluate { +// for (Task task : project.tasks.matching { it.name.startsWith('crashlyticsUploadDeobs') }) { +// task.enabled = false +// } +//} \ No newline at end of file diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro index 1e8ab731b..b22ef10c7 100644 --- a/app/proguard-rules.pro +++ b/app/proguard-rules.pro @@ -58,14 +58,13 @@ # 保留我们使用的四大组件,自定义的Application等等这些类不被混淆 # 因为这些子类都有可能被外部调用 -keep public class * extends android.app.Activity --keep public class * extends android.app.Appliction +-keep public class * extends android.app.Application -keep public class * extends android.app.Service -keep public class * extends android.content.BroadcastReceiver -keep public class * extends android.content.ContentProvider -keep public class * extends android.app.backup.BackupAgentHelper -keep public class * extends android.preference.Preference -keep public class * extends android.view.View --keep public class com.android.vending.licensing.ILicensingService # 保留androidx下的所有类及其内部类 @@ -128,16 +127,11 @@ } # webView处理,项目中没有使用到webView忽略即可 --keepclassmembers class fqcn.of.javascript.interface.for.webview { - public *; -} --keepclassmembers class * extends android.webkit.webViewClient { +-keepclassmembers class * extends android.webkit.WebViewClient { + public void *(android.webkit.WebView, java.lang.String); public void *(android.webkit.WebView, java.lang.String, android.graphics.Bitmap); public boolean *(android.webkit.WebView, java.lang.String); } --keepclassmembers class * extends android.webkit.webViewClient { - public void *(android.webkit.webView, jav.lang.String); -} # 移除Log类打印各个等级日志的代码,打正式包的时候可以做为禁log使用,这里可以作为禁止log打印的功能使用 # 记得proguard-android.txt中一定不要加-dontoptimize才起作用 @@ -170,20 +164,20 @@ -dontwarn org.conscrypt.** -dontwarn com.jeremyliao.liveeventbus.** +-keep class com.google.gson.** { *; } +-keep class com.ke.gson.** { *; } -keep class com.jeremyliao.liveeventbus.** { *; } -keep class okhttp3.**{*;} -keep class okio.**{*;} -keep class com.hwangjr.rxbus.**{*;} -keep class org.conscrypt.**{*;} --keep class com.kunfei.bookshelf.widget.**{*;} --keep class com.kunfei.bookshelf.bean.**{*;} -keep class android.support.**{*;} -keep class me.grantland.widget.**{*;} -keep class de.hdodenhof.circleimageview.**{*;} -keep class tyrant.explosionfield.**{*;} -keep class tyrantgit.explosionfield.**{*;} -keep class freemarker.**{*;} --keep class com.gyf.barlibrary.* {*;} +-keep class com.gyf.barlibrary.** {*;} ##JSOUP -keep class org.jsoup.**{*;} -keep class **.xpath.**{*;} @@ -197,7 +191,7 @@ -dontwarn com.jayway.** -keep class com.fasterxml.**{*;} --keep class javax.swing..**{*;} +-keep class javax.swing.**{*;} -dontwarn javax.swing.** -keep class java.awt.**{*;} -dontwarn java.awt.** @@ -215,10 +209,10 @@ -dontwarn nl.siegmann.epublib.** -dontwarn org.xmlpull.** -keep class nl.siegmann.epublib.**{*;} --keep class javax.xml.**{*;} --keep class org.xmlpull.**{*;} +-keep class javax.xml**{*;} +-keep class org.xmlpull**{*;} --keep class org.simpleframework.xml.**{*;} +-keep class org.simpleframework.xml**{*;} -dontwarn org.simpleframework.xml.** -keepclassmembers class * { diff --git a/app/src/main/assets/18PlusList.txt b/app/src/main/assets/18PlusList.txt index 7776c3b14..dd800e91b 100644 --- a/app/src/main/assets/18PlusList.txt +++ b/app/src/main/assets/18PlusList.txt @@ -1,2 +1,3 @@ OGN5dS5jb20= -c2cwMC54eXo= \ No newline at end of file +c2cwMC54eXo= +aXRyYWZmaWNuZXQuY29t \ No newline at end of file diff --git a/app/src/main/assets/readConfig.json b/app/src/main/assets/readConfig.json index c26c81554..301a75705 100644 --- a/app/src/main/assets/readConfig.json +++ b/app/src/main/assets/readConfig.json @@ -7,9 +7,7 @@ "bgType": 0, "bgTypeNight": 0, "darkStatusIcon": true, - "textSize": 24, - "letterSpacing": 0, - "lineSpacingExtra": 10 + "darkStatusIconNight": false }, { "bgStr": "#DDC090", @@ -19,9 +17,7 @@ "bgType": 0, "bgTypeNight": 0, "darkStatusIcon": true, - "textSize": 24, - "letterSpacing": 0, - "lineSpacingExtra": 10 + "darkStatusIconNight": false }, { "bgStr": "#C2D8AA", @@ -31,9 +27,7 @@ "bgType": 0, "bgTypeNight": 0, "darkStatusIcon": false, - "textSize": 24, - "letterSpacing": 0, - "lineSpacingExtra": 10 + "darkStatusIconNight": false }, { "bgStr": "#DBB8E2", @@ -43,9 +37,7 @@ "bgType": 0, "bgTypeNight": 0, "darkStatusIcon": false, - "textSize": 24, - "letterSpacing": 0, - "lineSpacingExtra": 10 + "darkStatusIconNight": false }, { "bgStr": "#ABCEE0", @@ -55,8 +47,6 @@ "bgType": 0, "bgTypeNight": 0, "darkStatusIcon": false, - "textSize": 24, - "letterSpacing": 0, - "lineSpacingExtra": 10 + "darkStatusIconNight": false } ] \ No newline at end of file diff --git a/app/src/main/assets/updateLog.md b/app/src/main/assets/updateLog.md index 1033764f8..020f74ce3 100644 --- a/app/src/main/assets/updateLog.md +++ b/app/src/main/assets/updateLog.md @@ -3,6 +3,42 @@ * 请关注公众号[开源阅读]()支持我,同时关注合作公众号[小说拾遗](),阅读公众号小编。 * 新公众号[开源阅读]()已启用,[开源阅读软件]()备用 +**2020/06/13** +* 优化搜索 + +**2020/06/12** +* 修复分组变化的bug + +**2020/06/10** +* 正文字体的粗细选择增加可以选择细体(Android O生效) by hingbong +* 修复bug + +**2020/06/09** +* 修复从发现界面打开已在书架的书时,显示不对的问题 + +**2020/06/07** +* 优化书源检测,自定义搜索关键词 +* 失效书源如果校验为有效会去掉失效标志 + +**2020/06/06** +* 修复一些bug,包括从阅读界面退出后还是显示红色更新的bug + +**2020/06/03** +* zh-TW translation by david082321 +* 修复音频播放时播放速度调节会再下一章失效的bug + +**2020/05/31** +* 更新到android studio 4.0 +* 书源排序添加按url +* 去除朗读通知的进度条 +* 修复恢复问题,暂时去除混淆 + +**2020/05/24** +* 添加自动翻页速度调节 + +**2020/05/23** +* 添加文字两端对齐配置 + **2020/05/20** * Rss列表增加一种显示样式 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 175180a33..e8f29712c 100644 --- a/app/src/main/java/io/legado/app/constant/PreferKey.kt +++ b/app/src/main/java/io/legado/app/constant/PreferKey.kt @@ -44,4 +44,6 @@ object PreferKey { const val systemTypefaces = "system_typefaces" const val readBodyToLh = "readBodyToLh" const val einkMode = "isEInkMode" + const val textFullJustify = "textFullJustify" + const val autoReadSpeed = "autoReadSpeed" } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/data/entities/BaseBook.kt b/app/src/main/java/io/legado/app/data/entities/BaseBook.kt index 62d322b6c..31346a50c 100644 --- a/app/src/main/java/io/legado/app/data/entities/BaseBook.kt +++ b/app/src/main/java/io/legado/app/data/entities/BaseBook.kt @@ -4,7 +4,7 @@ import io.legado.app.utils.splitNotBlank interface BaseBook { var bookUrl: String - var variableMap: HashMap? + val variableMap: HashMap var kind: String? var wordCount: String? diff --git a/app/src/main/java/io/legado/app/data/entities/Book.kt b/app/src/main/java/io/legado/app/data/entities/Book.kt index fd96d137b..2889f1c99 100644 --- a/app/src/main/java/io/legado/app/data/entities/Book.kt +++ b/app/src/main/java/io/legado/app/data/entities/Book.kt @@ -71,15 +71,17 @@ data class Book( return bookUrl.hashCode() } - @Ignore + @delegate:Transient + @delegate:Ignore @IgnoredOnParcel - override var variableMap: HashMap? = null - get() { - if (field == null) { - field = GSON.fromJsonObject>(variable) ?: HashMap() - } - return field - } + override val variableMap by lazy { + GSON.fromJsonObject>(variable) ?: HashMap() + } + + override fun putVariable(key: String, value: String) { + variableMap[key] = value + variable = GSON.toJson(variableMap) + } @Ignore @IgnoredOnParcel @@ -97,11 +99,6 @@ data class Book( fun getDisplayIntro() = if (customIntro.isNullOrEmpty()) intro else customIntro - override fun putVariable(key: String, value: String) { - variableMap?.put(key, value) - variable = GSON.toJson(variableMap) - } - fun fileCharset(): Charset { return charset(charset ?: "UTF-8") } diff --git a/app/src/main/java/io/legado/app/data/entities/BookSource.kt b/app/src/main/java/io/legado/app/data/entities/BookSource.kt index 1cb9a0269..62026ef7b 100644 --- a/app/src/main/java/io/legado/app/data/entities/BookSource.kt +++ b/app/src/main/java/io/legado/app/data/entities/BookSource.kt @@ -1,6 +1,7 @@ package io.legado.app.data.entities import android.os.Parcelable +import android.text.TextUtils import androidx.room.* import io.legado.app.App import io.legado.app.constant.AppConst @@ -8,10 +9,7 @@ import io.legado.app.constant.AppConst.userAgent import io.legado.app.constant.BookType import io.legado.app.data.entities.rule.* import io.legado.app.help.JsExtensions -import io.legado.app.utils.ACache -import io.legado.app.utils.GSON -import io.legado.app.utils.fromJsonObject -import io.legado.app.utils.getPrefString +import io.legado.app.utils.* import kotlinx.android.parcel.Parcelize import java.util.* import javax.script.SimpleBindings @@ -105,6 +103,13 @@ data class BookSource( } } + fun removeGroup(group: String) { + bookSourceGroup?.splitNotBlank(",")?.toHashSet()?.let { + it.remove(group) + bookSourceGroup = TextUtils.join(",", it) + } + } + fun getExploreKinds(): ArrayList? { val exploreKinds = arrayListOf() exploreUrl?.let { @@ -179,7 +184,7 @@ data class BookSource( class Converters { @TypeConverter - fun exploreRuleToString(exploreRule: ExploreRule?): String { + fun exploreRuleToString(exploreRule: ExploreRule?): String? { return GSON.toJson(exploreRule) } @@ -189,7 +194,7 @@ data class BookSource( } @TypeConverter - fun searchRuleToString(searchRule: SearchRule): String { + fun searchRuleToString(searchRule: SearchRule?): String? { return GSON.toJson(searchRule) } @@ -199,7 +204,7 @@ data class BookSource( } @TypeConverter - fun bookInfoRuleToString(bookInfoRule: BookInfoRule): String { + fun bookInfoRuleToString(bookInfoRule: BookInfoRule?): String? { return GSON.toJson(bookInfoRule) } @@ -209,7 +214,7 @@ data class BookSource( } @TypeConverter - fun tocRuleToString(tocRule: TocRule): String { + fun tocRuleToString(tocRule: TocRule?): String? { return GSON.toJson(tocRule) } @@ -219,7 +224,7 @@ data class BookSource( } @TypeConverter - fun contentRuleToString(contentRule: ContentRule): String { + fun contentRuleToString(contentRule: ContentRule?): String? { return GSON.toJson(contentRule) } diff --git a/app/src/main/java/io/legado/app/data/entities/SearchBook.kt b/app/src/main/java/io/legado/app/data/entities/SearchBook.kt index 27f666547..eb7ea0c10 100644 --- a/app/src/main/java/io/legado/app/data/entities/SearchBook.kt +++ b/app/src/main/java/io/legado/app/data/entities/SearchBook.kt @@ -63,21 +63,19 @@ data class SearchBook( return other.originOrder - this.originOrder } - @Ignore + @delegate:Transient + @delegate:Ignore @IgnoredOnParcel - override var variableMap: HashMap? = null - get() { - if (field == null) { - field = GSON.fromJsonObject>(variable) ?: HashMap() - } - return field - } + override val variableMap by lazy { + GSON.fromJsonObject>(variable) ?: HashMap() + } override fun putVariable(key: String, value: String) { - variableMap?.put(key, value) + variableMap[key] = value variable = GSON.toJson(variableMap) } + @delegate:Transient @delegate:Ignore @IgnoredOnParcel val origins: LinkedHashSet by lazy { linkedSetOf(origin) } diff --git a/app/src/main/java/io/legado/app/help/AdapterDataObserverHeader.kt b/app/src/main/java/io/legado/app/help/AdapterDataObserverHeader.kt index 24f0c0f2b..1aeddeb95 100644 --- a/app/src/main/java/io/legado/app/help/AdapterDataObserverHeader.kt +++ b/app/src/main/java/io/legado/app/help/AdapterDataObserverHeader.kt @@ -3,8 +3,8 @@ package io.legado.app.help import androidx.recyclerview.widget.RecyclerView internal class AdapterDataObserverHeader( - var adapterDataObserver: RecyclerView.AdapterDataObserver, - var headerCount: Int + private var adapterDataObserver: RecyclerView.AdapterDataObserver, + private var headerCount: Int ) : RecyclerView.AdapterDataObserver() { override fun onChanged() { adapterDataObserver.onChanged() 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 ff4180081..9828bb3a1 100644 --- a/app/src/main/java/io/legado/app/help/ReadBookConfig.kt +++ b/app/src/main/java/io/legado/app/help/ReadBookConfig.kt @@ -59,6 +59,7 @@ object ReadBookConfig { val json = configFile.readText() return GSON.fromJsonArray(json) } catch (e: Exception) { + e.printStackTrace() } } return null @@ -103,6 +104,11 @@ object ReadBookConfig { } //配置写入读取 + var autoReadSpeed = App.INSTANCE.getPrefInt(PreferKey.autoReadSpeed, 46) + set(value) { + field = value + App.INSTANCE.putPrefInt(PreferKey.autoReadSpeed, value) + } var styleSelect = App.INSTANCE.getPrefInt(PreferKey.readStyleSelect) set(value) { field = value @@ -127,6 +133,7 @@ object ReadBookConfig { } var isScroll = pageAnim == 3 val clickTurnPage get() = App.INSTANCE.getPrefBoolean(PreferKey.clickTurnPage, true) + val textFullJustify get() = App.INSTANCE.getPrefBoolean(PreferKey.textFullJustify, true) var bodyIndentCount = App.INSTANCE.getPrefInt(PreferKey.bodyIndent, 2) set(value) { field = value @@ -141,7 +148,7 @@ object ReadBookConfig { private val config get() = if (shareLayout) getConfig(5) else durConfig - var textBold: Boolean + var textBold: Int get() = config.textBold set(value) { config.textBold = value @@ -288,11 +295,11 @@ object ReadBookConfig { private var darkStatusIconNight: Boolean = false,//晚上是否暗色状态栏 private var textColor: String = "#3E3D3B",//白天文字颜色 private var textColorNight: String = "#ADADAD",//夜间文字颜色 - var textBold: Boolean = false,//是否粗体字 + var textBold: Int = 0,//是否粗体字 0:正常, 1:粗体, 2:细体 var textSize: Int = 20,//文字大小 - var letterSpacing: Float = 0.5f,//字间距 + var letterSpacing: Float = 0.1f,//字间距 var lineSpacingExtra: Int = 12,//行间距 - var paragraphSpacing: Int = 12,//段距 + var paragraphSpacing: Int = 4,//段距 var titleMode: Int = 0,//标题居中 var titleSize: Int = 0, var titleTopSpacing: Int = 0, diff --git a/app/src/main/java/io/legado/app/help/http/CookieStore.kt b/app/src/main/java/io/legado/app/help/http/CookieStore.kt index d82a4b175..42634ede1 100644 --- a/app/src/main/java/io/legado/app/help/http/CookieStore.kt +++ b/app/src/main/java/io/legado/app/help/http/CookieStore.kt @@ -39,10 +39,6 @@ object CookieStore { App.db.cookieDao().delete(url) } - fun clearCookies() { - - } - private fun cookieToMap(cookie: String): MutableMap { val cookieMap = mutableMapOf() if (cookie.isBlank()) { diff --git a/app/src/main/java/io/legado/app/help/storage/Restore.kt b/app/src/main/java/io/legado/app/help/storage/Restore.kt index f174a6f5e..c92f408bd 100644 --- a/app/src/main/java/io/legado/app/help/storage/Restore.kt +++ b/app/src/main/java/io/legado/app/help/storage/Restore.kt @@ -126,6 +126,7 @@ object Restore { hideStatusBar = App.INSTANCE.getPrefBoolean(PreferKey.hideStatusBar) hideNavigationBar = App.INSTANCE.getPrefBoolean(PreferKey.hideNavigationBar) bodyIndentCount = App.INSTANCE.getPrefInt(PreferKey.bodyIndent, 2) + autoReadSpeed = App.INSTANCE.getPrefInt(PreferKey.autoReadSpeed, 46) } ChapterProvider.upStyle() ReadBook.loadContent(resetPageOffset = false) 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 986e7c4ed..fa56e85d0 100644 --- a/app/src/main/java/io/legado/app/service/AudioPlayService.kt +++ b/app/src/main/java/io/legado/app/service/AudioPlayService.kt @@ -63,6 +63,7 @@ class AudioPlayService : BaseService(), private val dsRunnable: Runnable = Runnable { doDs() } private var mpRunnable: Runnable = Runnable { upPlayProgress() } private var bookChapter: BookChapter? = null + private var playSpeed: Float = 1f override fun onCreate() { super.onCreate() @@ -95,7 +96,12 @@ class AudioPlayService : BaseService(), IntentAction.adjustSpeed -> upSpeed(intent.getFloatExtra("adjust", 1f)) IntentAction.addTimer -> addTimer() IntentAction.setTimer -> setTimer(intent.getIntExtra("minute", 0)) - IntentAction.adjustProgress -> adjustProgress(intent.getIntExtra("position", position)) + IntentAction.adjustProgress -> adjustProgress( + intent.getIntExtra( + "position", + position + ) + ) else -> stopSelf() } } @@ -140,14 +146,18 @@ class AudioPlayService : BaseService(), if (url.contains(".m3u8", false)) { stopSelf() } else { - AudioPlayService.pause = pause - handler.removeCallbacks(mpRunnable) - position = mediaPlayer.currentPosition - mediaPlayer.pause() - upMediaSessionPlaybackState(PlaybackStateCompat.STATE_PAUSED) - AudioPlay.status = Status.PAUSE - postEvent(EventBus.AUDIO_STATE, Status.PAUSE) - upNotification() + try { + AudioPlayService.pause = pause + handler.removeCallbacks(mpRunnable) + position = mediaPlayer.currentPosition + mediaPlayer.pause() + upMediaSessionPlaybackState(PlaybackStateCompat.STATE_PAUSED) + AudioPlay.status = Status.PAUSE + postEvent(EventBus.AUDIO_STATE, Status.PAUSE) + upNotification() + } catch (e: Exception) { + e.printStackTrace() + } } } @@ -174,12 +184,12 @@ class AudioPlayService : BaseService(), private fun upSpeed(adjust: Float) { kotlin.runCatching { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { - with(mediaPlayer) { - if (isPlaying) { - playbackParams = playbackParams.apply { speed += adjust } - } - postEvent(EventBus.AUDIO_SPEED, playbackParams.speed) + playSpeed += adjust + if (mediaPlayer.isPlaying) { + mediaPlayer.playbackParams = + mediaPlayer.playbackParams.apply { speed = playSpeed } } + postEvent(EventBus.AUDIO_SPEED, playSpeed) } } } @@ -189,7 +199,11 @@ class AudioPlayService : BaseService(), */ override fun onPrepared(mp: MediaPlayer?) { if (pause) return - mediaPlayer.start() + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + mediaPlayer.playbackParams = mediaPlayer.playbackParams.apply { speed = playSpeed } + } else { + mediaPlayer.start() + } mediaPlayer.seekTo(position) postEvent(EventBus.AUDIO_SIZE, mediaPlayer.duration) bookChapter?.let { @@ -506,7 +520,6 @@ class AudioPlayService : BaseService(), ) builder.setStyle( androidx.media.app.NotificationCompat.MediaStyle() - .setMediaSession(mediaSessionCompat?.sessionToken) .setShowActionsInCompactView(0, 1, 2) ) builder.setVisibility(NotificationCompat.VISIBILITY_PUBLIC) diff --git a/app/src/main/java/io/legado/app/service/BaseReadAloudService.kt b/app/src/main/java/io/legado/app/service/BaseReadAloudService.kt index 6dee23a92..7531b21bb 100644 --- a/app/src/main/java/io/legado/app/service/BaseReadAloudService.kt +++ b/app/src/main/java/io/legado/app/service/BaseReadAloudService.kt @@ -323,7 +323,6 @@ abstract class BaseReadAloudService : BaseService(), ) builder.setStyle( androidx.media.app.NotificationCompat.MediaStyle() - .setMediaSession(mediaSessionCompat.sessionToken) .setShowActionsInCompactView(0, 1, 2) ) builder.setVisibility(NotificationCompat.VISIBILITY_PUBLIC) diff --git a/app/src/main/java/io/legado/app/service/CheckSourceService.kt b/app/src/main/java/io/legado/app/service/CheckSourceService.kt index 896e7bb75..e6cbb5966 100644 --- a/app/src/main/java/io/legado/app/service/CheckSourceService.kt +++ b/app/src/main/java/io/legado/app/service/CheckSourceService.kt @@ -7,13 +7,11 @@ import io.legado.app.R import io.legado.app.base.BaseService import io.legado.app.constant.AppConst import io.legado.app.constant.IntentAction -import io.legado.app.data.entities.BookSource import io.legado.app.help.AppConfig import io.legado.app.help.IntentHelp import io.legado.app.help.coroutine.CompositeCoroutine -import io.legado.app.model.WebBook +import io.legado.app.service.help.CheckSource import io.legado.app.ui.book.source.manage.BookSourceActivity -import kotlinx.coroutines.Dispatchers.IO import kotlinx.coroutines.asCoroutineDispatcher import org.jetbrains.anko.toast import java.util.concurrent.Executors @@ -80,24 +78,15 @@ class CheckSourceService : BaseService() { if (source.searchUrl.isNullOrEmpty()) { onNext(sourceUrl) } else { - check(source) + CheckSource(source).check(this, searchPool) { + onNext(it) + } } } ?: onNext(sourceUrl) } } } - private fun check(source: BookSource) { - val webBook = WebBook(source) - tasks.add(webBook.searchBook("我的", scope = this, context = searchPool) - .onError(IO) { - source.addGroup("失效") - App.db.bookSourceDao().update(source) - }.onFinally(IO) { - onNext(source.bookSourceUrl) - }) - } - private fun onNext(sourceUrl: String) { synchronized(this) { check() diff --git a/app/src/main/java/io/legado/app/service/HttpReadAloudService.kt b/app/src/main/java/io/legado/app/service/HttpReadAloudService.kt index 7796ffce0..4c29f84ae 100644 --- a/app/src/main/java/io/legado/app/service/HttpReadAloudService.kt +++ b/app/src/main/java/io/legado/app/service/HttpReadAloudService.kt @@ -76,7 +76,9 @@ class HttpReadAloudService : BaseReadAloudService(), val file = getSpeakFile(index) file.writeBytes(bytes) if (index == nowSpeak) { - playAudio(FileInputStream(file).fd) + @Suppress("BlockingMethodInNonBlockingContext") + val fis = FileInputStream(file) + playAudio(fis.fd) } } } else { @@ -204,7 +206,7 @@ class HttpReadAloudService : BaseReadAloudService(), } else { nextChapter() } - }, 1000) + }, 100) return true } diff --git a/app/src/main/java/io/legado/app/service/TTSReadAloudService.kt b/app/src/main/java/io/legado/app/service/TTSReadAloudService.kt index 0517ca2fc..2d4b8bbde 100644 --- a/app/src/main/java/io/legado/app/service/TTSReadAloudService.kt +++ b/app/src/main/java/io/legado/app/service/TTSReadAloudService.kt @@ -42,9 +42,7 @@ class TTSReadAloudService : BaseReadAloudService(), TextToSpeech.OnInitListener private fun initTts() { ttsInitFinish = false - textToSpeech = TextToSpeech(this, this).apply { - setOnUtteranceProgressListener(ttsUtteranceListener) - } + textToSpeech = TextToSpeech(this, this) } override fun onDestroy() { @@ -55,6 +53,7 @@ class TTSReadAloudService : BaseReadAloudService(), TextToSpeech.OnInitListener override fun onInit(status: Int) { if (status == TextToSpeech.SUCCESS) { textToSpeech?.let { + it.setOnUtteranceProgressListener(ttsUtteranceListener) it.language = Locale.CHINA ttsInitFinish = true play() @@ -69,16 +68,20 @@ class TTSReadAloudService : BaseReadAloudService(), TextToSpeech.OnInitListener @Synchronized override fun play() { if (contentList.isNotEmpty() && ttsInitFinish && requestFocus()) { - MediaHelp.playSilentSound(this) super.play() - textToSpeech?.stop() - for (i in nowSpeak until contentList.size) { - textToSpeech?.speak( - contentList[i], - TextToSpeech.QUEUE_ADD, - null, - AppConst.APP_TAG + i - ) + execute { + MediaHelp.playSilentSound(this@TTSReadAloudService) + textToSpeech?.let { + it.speak("", TextToSpeech.QUEUE_FLUSH, null, null) + for (i in nowSpeak until contentList.size) { + it.speak( + contentList[i], + TextToSpeech.QUEUE_ADD, + null, + AppConst.APP_TAG + i + ) + } + } } } } diff --git a/app/src/main/java/io/legado/app/service/help/CheckSource.kt b/app/src/main/java/io/legado/app/service/help/CheckSource.kt index b0a33953b..5d8c6876b 100644 --- a/app/src/main/java/io/legado/app/service/help/CheckSource.kt +++ b/app/src/main/java/io/legado/app/service/help/CheckSource.kt @@ -2,34 +2,62 @@ package io.legado.app.service.help import android.content.Context import android.content.Intent +import io.legado.app.App import io.legado.app.R import io.legado.app.constant.IntentAction import io.legado.app.data.entities.BookSource +import io.legado.app.help.coroutine.Coroutine +import io.legado.app.model.WebBook import io.legado.app.service.CheckSourceService +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers import org.jetbrains.anko.toast +import kotlin.coroutines.CoroutineContext -object CheckSource { +class CheckSource(val source: BookSource) { - fun start(context: Context, sources: List) { - if (sources.isEmpty()) { - context.toast(R.string.non_select) - return - } - val selectedIds: ArrayList = arrayListOf() - sources.map { - selectedIds.add(it.bookSourceUrl) + companion object { + var keyword = "我的" + + fun start(context: Context, sources: List) { + if (sources.isEmpty()) { + context.toast(R.string.non_select) + return + } + val selectedIds: ArrayList = arrayListOf() + sources.map { + selectedIds.add(it.bookSourceUrl) + } + Intent(context, CheckSourceService::class.java).let { + it.action = IntentAction.start + it.putExtra("selectIds", selectedIds) + context.startService(it) + } } - Intent(context, CheckSourceService::class.java).let { - it.action = IntentAction.start - it.putExtra("selectIds", selectedIds) - context.startService(it) + + fun stop(context: Context) { + Intent(context, CheckSourceService::class.java).let { + it.action = IntentAction.stop + context.startService(it) + } } } - fun stop(context: Context) { - Intent(context, CheckSourceService::class.java).let { - it.action = IntentAction.stop - context.startService(it) - } + fun check( + scope: CoroutineScope, + context: CoroutineContext, + onNext: (sourceUrl: String) -> Unit + ): Coroutine<*> { + val webBook = WebBook(source) + return webBook.searchBook(keyword, scope = scope, context = context) + .onError(Dispatchers.IO) { + source.addGroup("失效") + App.db.bookSourceDao().update(source) + }.onSuccess(Dispatchers.IO) { + source.removeGroup("失效") + App.db.bookSourceDao().update(source) + }.onFinally(Dispatchers.IO) { + onNext(source.bookSourceUrl) + } } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/service/help/ReadBook.kt b/app/src/main/java/io/legado/app/service/help/ReadBook.kt index 4b196ec48..ef15098b0 100644 --- a/app/src/main/java/io/legado/app/service/help/ReadBook.kt +++ b/app/src/main/java/io/legado/app/service/help/ReadBook.kt @@ -1,11 +1,13 @@ package io.legado.app.service.help import androidx.lifecycle.MutableLiveData +import com.hankcs.hanlp.HanLP import io.legado.app.App import io.legado.app.R import io.legado.app.constant.BookType 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.IntentDataHelp import io.legado.app.help.coroutine.Coroutine @@ -38,7 +40,6 @@ object ReadBook { fun resetData(book: Book) { this.book = book - titleDate.postValue(book.name) durChapterIndex = book.durChapterIndex durPageIndex = book.durChapterPos isLocalBook = book.origin == BookType.local @@ -46,11 +47,11 @@ object ReadBook { prevTextChapter = null curTextChapter = null nextTextChapter = null + titleDate.postValue(book.name) upWebBook(book) } - fun upWebBook(book: Book?) { - book ?: return + fun upWebBook(book: Book) { webBook = if (book.origin == BookType.local) { null } else { @@ -292,6 +293,11 @@ object ReadBook { ) { Coroutine.async { if (chapter.index in durChapterIndex - 1..durChapterIndex + 1) { + chapter.title = when (AppConfig.chineseConverterType) { + 1 -> HanLP.convertToSimplifiedChinese(chapter.title) + 2 -> HanLP.convertToTraditionalChinese(chapter.title) + else -> chapter.title + } val contents = BookHelp.disposeContent( chapter.title, book!!.name, 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 3b56737cf..e44666349 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 @@ -47,6 +47,7 @@ class AboutFragment : PreferenceFragmentCompat() { "update_log" -> showUpdateLog() "check_update" -> openUrl(R.string.latest_release_url) "mail" -> sendMail() + "sourceRuleSummary" -> openUrl(R.string.source_rule_url) "git" -> openUrl(R.string.this_github_url) "home_page" -> openUrl(R.string.home_page_url) "license" -> requireContext().openUrl(licenseUrl) diff --git a/app/src/main/java/io/legado/app/ui/book/changesource/ChangeSourceAdapter.kt b/app/src/main/java/io/legado/app/ui/book/changesource/ChangeSourceAdapter.kt index 3a148a2c2..12e63a907 100644 --- a/app/src/main/java/io/legado/app/ui/book/changesource/ChangeSourceAdapter.kt +++ b/app/src/main/java/io/legado/app/ui/book/changesource/ChangeSourceAdapter.kt @@ -60,7 +60,6 @@ class ChangeSourceAdapter(context: Context, val callBack: CallBack) : when (it.itemId) { R.id.menu_disable_book_source -> { callBack.disableSource(searchBook) - removeItem(searchBook) } } true 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 e5adf9e85..da58200c5 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 @@ -2,6 +2,7 @@ package io.legado.app.ui.book.changesource import android.app.Application import android.os.Bundle +import android.os.Handler import androidx.lifecycle.MutableLiveData import io.legado.app.App import io.legado.app.R @@ -22,6 +23,7 @@ import java.util.concurrent.Executors class ChangeSourceViewModel(application: Application) : BaseViewModel(application) { private var searchPool = Executors.newFixedThreadPool(AppConfig.threadCount).asCoroutineDispatcher() + val handler = Handler() val searchStateData = MutableLiveData() val searchBooksLiveData = MutableLiveData>() var name: String = "" @@ -29,6 +31,9 @@ class ChangeSourceViewModel(application: Application) : BaseViewModel(applicatio private var task: Coroutine<*>? = null private var screenKey: String = "" private val searchBooks = hashSetOf() + private var postTime = 0L + private val sendRunnable = Runnable { upAdapter() } + fun initData(arguments: Bundle?) { arguments?.let { bundle -> @@ -55,9 +60,17 @@ class ChangeSourceViewModel(application: Application) : BaseViewModel(applicatio } } + @Synchronized private fun upAdapter() { - val books = searchBooks.toList() - searchBooksLiveData.postValue(books.sortedBy { it.originOrder }) + if (System.currentTimeMillis() >= postTime + 500) { + handler.removeCallbacks(sendRunnable) + postTime = System.currentTimeMillis() + val books = searchBooks.toList() + searchBooksLiveData.postValue(books.sortedBy { it.originOrder }) + } else { + handler.removeCallbacks(sendRunnable) + handler.postDelayed(sendRunnable, 500 - System.currentTimeMillis() + postTime) + } } private fun searchFinish(searchBook: SearchBook) { @@ -172,6 +185,7 @@ class ChangeSourceViewModel(application: Application) : BaseViewModel(applicatio App.db.bookSourceDao().update(source) } searchBooks.remove(searchBook) + upAdapter() } } diff --git a/app/src/main/java/io/legado/app/ui/book/changesource/DiffCallBack.kt b/app/src/main/java/io/legado/app/ui/book/changesource/DiffCallBack.kt index b0a8f19ef..142ab24c2 100644 --- a/app/src/main/java/io/legado/app/ui/book/changesource/DiffCallBack.kt +++ b/app/src/main/java/io/legado/app/ui/book/changesource/DiffCallBack.kt @@ -24,13 +24,11 @@ class DiffCallBack(private val oldItems: List, private val newItems: override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean { val oldItem = oldItems[oldItemPosition] val newItem = newItems[newItemPosition] - if (oldItem.originName != newItem.originName) { - return false - } - if (oldItem.latestChapterTitle != newItem.latestChapterTitle) { - return false + return when { + oldItem.originName != newItem.originName -> false + oldItem.latestChapterTitle != newItem.latestChapterTitle -> false + else -> true } - return true } override fun getChangePayload(oldItemPosition: Int, newItemPosition: Int): Any? { diff --git a/app/src/main/java/io/legado/app/ui/book/explore/ExploreShowActivity.kt b/app/src/main/java/io/legado/app/ui/book/explore/ExploreShowActivity.kt index 38eeffaf6..1d0fa4c80 100644 --- a/app/src/main/java/io/legado/app/ui/book/explore/ExploreShowActivity.kt +++ b/app/src/main/java/io/legado/app/ui/book/explore/ExploreShowActivity.kt @@ -74,7 +74,8 @@ class ExploreShowActivity : VMBaseActivity(R.layout.activi override fun showBookInfo(book: Book) { startActivity( - Pair("bookUrl", book.bookUrl) + Pair("name", book.name), + Pair("author", book.author) ) } } \ No newline at end of file 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 47dc6c33f..53b7366b9 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 @@ -12,6 +12,7 @@ import io.legado.app.help.BookHelp import io.legado.app.model.WebBook import io.legado.app.model.localBook.AnalyzeTxtFile import io.legado.app.model.localBook.LocalBook +import io.legado.app.service.help.ReadBook import kotlinx.coroutines.Dispatchers.IO class BookInfoViewModel(application: Application) : BaseViewModel(application) { @@ -22,13 +23,13 @@ class BookInfoViewModel(application: Application) : BaseViewModel(application) { fun initData(intent: Intent) { execute { - intent.getStringExtra("bookUrl")?.let { - App.db.bookDao().getBook(it)?.let { book -> - inBookshelf = true - setBook(book) - } ?: App.db.searchBookDao().getSearchBook(it)?.toBook()?.let { book -> - setBook(book) - } + val name = intent.getStringExtra("name") ?: "" + val author = intent.getStringExtra("author") ?: "" + App.db.bookDao().getBook(name, author)?.let { book -> + inBookshelf = true + setBook(book) + } ?: App.db.searchBookDao().getFirstByNameAuthor(name, author)?.toBook()?.let { book -> + setBook(book) } } } @@ -178,6 +179,9 @@ class BookInfoViewModel(application: Application) : BaseViewModel(application) { book.durChapterTitle = it.durChapterTitle } App.db.bookDao().insert(book) + if (ReadBook.book?.name == book.name && ReadBook.book?.author == book.author) { + ReadBook.book = book + } } }.onSuccess { success?.invoke() 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 6b267daa0..d5880a728 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 @@ -69,6 +69,7 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_boo ReadAloudDialog.CallBack, ChangeSourceDialog.CallBack, ReadBook.CallBack, + AutoReadDialog.CallBack, TocRegexDialog.CallBack, ReplaceEditDialog.CallBack, ColorPickerDialogListener { @@ -131,6 +132,7 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_boo override fun onPause() { super.onPause() + ReadBook.saveRead() timeBatteryReceiver?.let { unregisterReceiver(it) timeBatteryReceiver = null @@ -240,7 +242,10 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_boo onReplaceRuleSave() } R.id.menu_book_info -> ReadBook.book?.let { - startActivity(Pair("bookUrl", it.bookUrl)) + startActivity( + Pair("name", it.name), + Pair("author", it.author) + ) } R.id.menu_toc_regex -> TocRegexDialog.show( supportFragmentManager, @@ -518,6 +523,9 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_boo seek_read_page.progress = ReadBook.durPageIndex tv_pre.isEnabled = ReadBook.durChapterIndex != 0 tv_next.isEnabled = ReadBook.durChapterIndex != ReadBook.chapterSize - 1 + } ?: let { + tv_chapter_name.gone() + tv_chapter_url.gone() } } } @@ -547,10 +555,16 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_boo } override fun clickCenter() { - if (BaseReadAloudService.isRun) { - showReadAloudDialog() - } else { - read_menu.runMenuIn() + when { + BaseReadAloudService.isRun -> { + showReadAloudDialog() + } + isAutoPage -> { + AutoReadDialog().show(supportFragmentManager, "autoRead") + } + else -> { + read_menu.runMenuIn() + } } } @@ -569,12 +583,14 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_boo autoPageStop() } else { isAutoPage = true + page_view.upContent() + page_view.upContent(1) autoPagePlus() } read_menu.setAutoPage(isAutoPage) } - private fun autoPageStop() { + override fun autoPageStop() { isAutoPage = false mHandler.removeCallbacks(autoPageRunnable) page_view.upContent() @@ -583,7 +599,7 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_boo private fun autoPagePlus() { mHandler.removeCallbacks(autoPageRunnable) autoPageProgress++ - if (autoPageProgress >= 460) { + if (autoPageProgress >= ReadBookConfig.autoReadSpeed * 10) { autoPageProgress = 0 page_view.fillPage(PageDelegate.Direction.NEXT) } else { 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 a4755213d..e6d6b57e3 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 @@ -35,6 +35,10 @@ class ReadBookViewModel(application: Application) : BaseViewModel(application) { } ?: App.db.bookDao().lastReadBook?.let { initBook(it) } + }.onFinally { + if (ReadBook.inBookshelf) { + ReadBook.saveRead() + } } } @@ -59,11 +63,9 @@ class ReadBookViewModel(application: Application) : BaseViewModel(application) { } ReadBook.loadContent(resetPageOffset = true) } - if (ReadBook.inBookshelf) { - ReadBook.saveRead() - } } else { isInitFinish = true + ReadBook.book!!.group = book.group ReadBook.titleDate.postValue(book.name) ReadBook.upWebBook(book) if (!book.isLocalBook() && ReadBook.webBook == null) { 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 new file mode 100644 index 000000000..d465c7b7f --- /dev/null +++ b/app/src/main/java/io/legado/app/ui/book/read/config/AutoReadDialog.kt @@ -0,0 +1,100 @@ +package io.legado.app.ui.book.read.config + +import android.os.Bundle +import android.util.DisplayMetrics +import android.view.Gravity +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.SeekBar +import io.legado.app.R +import io.legado.app.base.BaseDialogFragment +import io.legado.app.help.ReadBookConfig +import io.legado.app.lib.theme.bottomBackground +import io.legado.app.service.BaseReadAloudService +import io.legado.app.service.help.ReadAloud +import io.legado.app.ui.book.read.Help +import kotlinx.android.synthetic.main.dialog_auto_read.* +import org.jetbrains.anko.sdk27.listeners.onClick + +class AutoReadDialog : BaseDialogFragment() { + var callBack: CallBack? = null + + override fun onStart() { + super.onStart() + val dm = DisplayMetrics() + activity?.let { + Help.upSystemUiVisibility(it) + it.windowManager?.defaultDisplay?.getMetrics(dm) + } + dialog?.window?.let { + it.setBackgroundDrawableResource(R.color.background) + it.decorView.setPadding(0, 0, 0, 0) + val attr = it.attributes + attr.dimAmount = 0.0f + attr.gravity = Gravity.BOTTOM + it.attributes = attr + it.setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT) + } + } + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + callBack = activity as? CallBack + return inflater.inflate(R.layout.dialog_auto_read, container) + } + + override fun onFragmentCreated(view: View, savedInstanceState: Bundle?) { + root_view.setBackgroundColor(requireContext().bottomBackground) + initOnChange() + initData() + initEvent() + } + + private fun initData() { + seek_auto_read.progress = ReadBookConfig.autoReadSpeed + } + + private fun initOnChange() { + seek_auto_read.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener { + override fun onProgressChanged(seekBar: SeekBar?, progress: Int, fromUser: Boolean) { + } + + override fun onStartTrackingTouch(seekBar: SeekBar?) = Unit + + override fun onStopTrackingTouch(seekBar: SeekBar?) { + ReadBookConfig.autoReadSpeed = seek_auto_read.progress + upTtsSpeechRate() + } + }) + } + + private fun initEvent() { + ll_main_menu.onClick { callBack?.showMenuBar(); dismiss() } + ll_setting.onClick { + ReadAloudConfigDialog().show(childFragmentManager, "readAloudConfigDialog") + } + ll_catalog.onClick { callBack?.openChapterList() } + ll_auto_page_stop.onClick { + callBack?.autoPageStop() + dismiss() + } + } + + private fun upTtsSpeechRate() { + ReadAloud.upTtsSpeechRate(requireContext()) + if (!BaseReadAloudService.pause) { + ReadAloud.pause(requireContext()) + ReadAloud.resume(requireContext()) + } + } + + interface CallBack { + fun showMenuBar() + fun openChapterList() + fun autoPageStop() + } +} \ 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 5d8ec5d82..7033b82d0 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 @@ -111,6 +111,9 @@ class MoreConfigDialog : DialogFragment() { Help.setOrientation(it) } } + PreferKey.textFullJustify -> { + postEvent(EventBus.UP_CONFIG, true) + } } } 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 19cad6738..38e96af50 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 @@ -103,9 +103,7 @@ class ReadStyleDialog : DialogFragment(), FontSelectDialog.CallBack { tv_title_mode.onClick { showTitleConfig() } - tv_text_bold.onClick { - ReadBookConfig.textBold = !ReadBookConfig.textBold - tv_text_bold.isSelected = ReadBookConfig.textBold + text_font_weight_converter.onChanged { postEvent(EventBus.UP_CONFIG, true) } tv_text_font.onClick { @@ -215,7 +213,6 @@ class ReadStyleDialog : DialogFragment(), FontSelectDialog.CallBack { private fun upStyle() { ReadBookConfig.let { - tv_text_bold.isSelected = it.textBold dsb_text_size.progress = it.textSize - 5 dsb_text_letter_spacing.progress = (it.letterSpacing * 100).toInt() + 50 dsb_line_size.progress = it.lineSpacingExtra 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 new file mode 100644 index 000000000..12f5243fa --- /dev/null +++ b/app/src/main/java/io/legado/app/ui/book/read/config/TextFontWeightConverter.kt @@ -0,0 +1,55 @@ +package io.legado.app.ui.book.read.config + +import android.content.Context +import android.text.Spannable +import android.text.SpannableString +import android.text.style.ForegroundColorSpan +import android.util.AttributeSet +import io.legado.app.R +import io.legado.app.help.AppConfig +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 org.jetbrains.anko.sdk27.listeners.onClick + +class TextFontWeightConverter(context: Context, attrs: AttributeSet?) : StrokeTextView(context, attrs) { + + private val spannableString = SpannableString("中/粗/细") + private var enabledSpan: ForegroundColorSpan = ForegroundColorSpan(context.accentColor) + private var onChanged: (() -> Unit)? = null + + init { + text = spannableString + if (!isInEditMode) { + upUi(ReadBookConfig.textBold) + } + onClick { + selectType() + } + } + + private fun upUi(type: Int) { + spannableString.removeSpan(enabledSpan) + when (type) { + 0 -> spannableString.setSpan(enabledSpan, 0, 1, Spannable.SPAN_INCLUSIVE_EXCLUSIVE) + 1 -> spannableString.setSpan(enabledSpan, 2, 3, Spannable.SPAN_INCLUSIVE_EXCLUSIVE) + 2 -> spannableString.setSpan(enabledSpan, 4, 5, Spannable.SPAN_INCLUSIVE_EXCLUSIVE) + } + text = spannableString + } + + private fun selectType() { + context.alert(titleResource = R.string.text_font_weight_converter) { + items(context.resources.getStringArray(R.array.text_font_weight).toList()) { _, i -> + ReadBookConfig.textBold = i + upUi(i) + onChanged?.invoke() + } + }.show() + } + + fun onChanged(unit: () -> Unit) { + onChanged = unit + } +} \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/book/read/config/TipConfigDialog.kt b/app/src/main/java/io/legado/app/ui/book/read/config/TipConfigDialog.kt index 2635b70b2..65bcfc7b6 100644 --- a/app/src/main/java/io/legado/app/ui/book/read/config/TipConfigDialog.kt +++ b/app/src/main/java/io/legado/app/ui/book/read/config/TipConfigDialog.kt @@ -25,12 +25,10 @@ class TipConfigDialog : BaseDialogFragment() { Help.upSystemUiVisibility(it) it.windowManager?.defaultDisplay?.getMetrics(dm) } - dialog?.window?.let { - val attr = it.attributes - attr.dimAmount = 0.0f - it.attributes = attr - it.setLayout((dm.widthPixels * 0.9).toInt(), ViewGroup.LayoutParams.WRAP_CONTENT) - } + dialog?.window?.setLayout( + ViewGroup.LayoutParams.MATCH_PARENT, + ViewGroup.LayoutParams.WRAP_CONTENT + ) } override fun onCreateView( diff --git a/app/src/main/java/io/legado/app/ui/book/read/page/ChapterProvider.kt b/app/src/main/java/io/legado/app/ui/book/read/page/ChapterProvider.kt index e0cee0b5c..15f3ac23c 100644 --- a/app/src/main/java/io/legado/app/ui/book/read/page/ChapterProvider.kt +++ b/app/src/main/java/io/legado/app/ui/book/read/page/ChapterProvider.kt @@ -6,6 +6,7 @@ import android.text.Layout import android.text.StaticLayout import android.text.TextPaint import android.text.TextUtils +import com.hankcs.hanlp.HanLP import io.legado.app.App import io.legado.app.constant.PreferKey import io.legado.app.data.entities.BookChapter @@ -78,6 +79,7 @@ object ChapterProvider { item.title = bookChapter.title item.upLinesPosition() } + return TextChapter( bookChapter.index, bookChapter.title, @@ -161,6 +163,10 @@ object ChapterProvider { desiredWidth: Float ) { var x = 0f + if (!ReadBookConfig.textFullJustify) { + addCharsToLineLast(textLine, words, textPaint, x) + return + } val bodyIndent = ReadBookConfig.bodyIndent val icw = StaticLayout.getDesiredWidth(bodyIndent, textPaint) / bodyIndent.length bodyIndent.toStringArray().forEach { @@ -186,6 +192,10 @@ object ChapterProvider { desiredWidth: Float, startX: Float ) { + if (!ReadBookConfig.textFullJustify) { + addCharsToLineLast(textLine, words, textPaint, startX) + return + } val gapCount: Int = words.length - 1 val d = (visibleWidth - desiredWidth) / gapCount var x = startX @@ -262,23 +272,37 @@ object ChapterProvider { App.INSTANCE.removePref(PreferKey.readBookFont) Typeface.SANS_SERIF } + // 字体统一处理 + val bold = Typeface.create(typeface, Typeface.BOLD) + val normal = Typeface.create(typeface, Typeface.NORMAL) + val (titleFont, textFont) = when (ReadBookConfig.textBold) { + 1 -> { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) + Pair(Typeface.create(typeface, 900, false), bold) + else + Pair(bold, bold) + } + 2 -> { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) + Pair(normal, Typeface.create(typeface, 300, false)) + else + Pair(normal, normal) + } + else -> Pair(bold, normal) + } + //标题 titlePaint = TextPaint() titlePaint.color = ReadBookConfig.durConfig.textColor() titlePaint.letterSpacing = ReadBookConfig.letterSpacing - titlePaint.typeface = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { - Typeface.create(typeface, if (ReadBookConfig.textBold) 900 else 700, false) - } else { - Typeface.create(typeface, Typeface.BOLD) - } + titlePaint.typeface = titleFont titlePaint.textSize = with(ReadBookConfig) { textSize + titleSize }.sp.toFloat() titlePaint.isAntiAlias = true //正文 contentPaint = TextPaint() contentPaint.color = ReadBookConfig.durConfig.textColor() contentPaint.letterSpacing = ReadBookConfig.letterSpacing - val style = if (ReadBookConfig.textBold) Typeface.BOLD else Typeface.NORMAL - contentPaint.typeface = Typeface.create(typeface, style) + contentPaint.typeface = textFont contentPaint.textSize = ReadBookConfig.textSize.sp.toFloat() contentPaint.isAntiAlias = true //间距 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 8058c0a04..8cf679114 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 @@ -207,11 +207,7 @@ class ContentView(context: Context) : FrameLayout(context) { @SuppressLint("SetTextI18n") fun setProgress(textPage: TextPage) = textPage.apply { - val title = when (AppConfig.chineseConverterType) { - 1 -> HanLP.convertToSimplifiedChinese(textPage.title) - 2 -> HanLP.convertToTraditionalChinese(textPage.title) - else -> textPage.title - } + val title = textPage.title tvTitle?.text = title tvPage?.text = "${index.plus(1)}/$pageSize" tvTotalProgress?.text = readProgress 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 ff93f113a..7b881006a 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 @@ -58,7 +58,8 @@ class PageView(context: Context, attrs: AttributeSet) : pageDelegate?.onDraw(canvas) if (callBack.isAutoPage) { nextPage.screenshot()?.let { - val bottom = page_view.height * callBack.autoPageProgress / 460 + val bottom = + page_view.height * callBack.autoPageProgress / (ReadBookConfig.autoReadSpeed * 10) autoPageRect.set(0, 0, page_view.width, bottom) canvas.drawBitmap(it, autoPageRect, autoPageRect, null) canvas.drawRect( @@ -118,9 +119,10 @@ class PageView(context: Context, attrs: AttributeSet) : } override fun upContent(relativePosition: Int, resetPageOffset: Boolean) { - if (ReadBookConfig.isScroll) { + if (ReadBookConfig.isScroll && !callBack.isAutoPage) { curPage.setContent(pageFactory.currentPage, resetPageOffset) } else { + curPage.resetPageOffset() when (relativePosition) { -1 -> prevPage.setContent(pageFactory.prevPage) 1 -> nextPage.setContent(pageFactory.nextPage) diff --git a/app/src/main/java/io/legado/app/ui/book/search/DiffCallBack.kt b/app/src/main/java/io/legado/app/ui/book/search/DiffCallBack.kt index b03e54fb7..4125489b8 100644 --- a/app/src/main/java/io/legado/app/ui/book/search/DiffCallBack.kt +++ b/app/src/main/java/io/legado/app/ui/book/search/DiffCallBack.kt @@ -18,64 +18,40 @@ class DiffCallBack(private val oldItems: List, private val newItems: override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean { val oldItem = oldItems[oldItemPosition] val newItem = newItems[newItemPosition] - if (oldItem.name != newItem.name) { - return false + return when { + oldItem.name != newItem.name -> false + oldItem.author != newItem.author -> false + else -> true } - if (oldItem.author != newItem.author) { - return false - } - return true } override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean { val oldItem = oldItems[oldItemPosition] val newItem = newItems[newItemPosition] - if (oldItem.origins.size != newItem.origins.size) { - return false - } - if (oldItem.coverUrl != newItem.coverUrl) { - return false - } - if (oldItem.kind != newItem.kind) { - return false - } - if (oldItem.latestChapterTitle != newItem.latestChapterTitle) { - return false + return when { + oldItem.origins.size != newItem.origins.size -> false + oldItem.coverUrl != newItem.coverUrl -> false + oldItem.kind != newItem.kind -> false + oldItem.latestChapterTitle != newItem.latestChapterTitle -> false + oldItem.intro != newItem.intro -> false + else -> true } - if (oldItem.intro != newItem.intro) { - return false - } - return true } override fun getChangePayload(oldItemPosition: Int, newItemPosition: Int): Any? { val payload = Bundle() val newItem = newItems[newItemPosition] val oldItem = oldItems[oldItemPosition] - if (oldItem.name != newItem.name) { - payload.putString("name", newItem.name) - } - if (oldItem.author != newItem.author) { - payload.putString("author", newItem.author) - } - if (oldItem.origins.size != newItem.origins.size) { + if (oldItem.name != newItem.name) payload.putString("name", newItem.name) + if (oldItem.author != newItem.author) payload.putString("author", newItem.author) + if (oldItem.origins.size != newItem.origins.size) payload.putInt("origins", newItem.origins.size) - } - if (oldItem.coverUrl != newItem.coverUrl) { - payload.putString("cover", newItem.coverUrl) - } - if (oldItem.kind != newItem.kind) { - payload.putString("kind", newItem.kind) - } - if (oldItem.latestChapterTitle != newItem.latestChapterTitle) { + if (oldItem.coverUrl != newItem.coverUrl) payload.putString("cover", newItem.coverUrl) + if (oldItem.kind != newItem.kind) payload.putString("kind", newItem.kind) + if (oldItem.latestChapterTitle != newItem.latestChapterTitle) payload.putString("last", newItem.latestChapterTitle) - } - if (oldItem.intro != newItem.intro) { - payload.putString("intro", newItem.intro) - } - if (payload.isEmpty) { - return null - } + if (oldItem.intro != newItem.intro) payload.putString("intro", newItem.intro) + if (payload.isEmpty) return null return payload } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/book/search/SearchActivity.kt b/app/src/main/java/io/legado/app/ui/book/search/SearchActivity.kt index 8b8fd82ad..fe30270df 100644 --- a/app/src/main/java/io/legado/app/ui/book/search/SearchActivity.kt +++ b/app/src/main/java/io/legado/app/ui/book/search/SearchActivity.kt @@ -8,7 +8,6 @@ import android.view.View.VISIBLE import androidx.appcompat.widget.SearchView import androidx.lifecycle.LiveData import androidx.lifecycle.Observer -import androidx.recyclerview.widget.DiffUtil import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView import com.google.android.flexbox.FlexboxLayoutManager @@ -53,7 +52,6 @@ class SearchActivity : VMBaseActivity(R.layout.activity_book_se private var menu: Menu? = null private var precisionSearchMenuItem: MenuItem? = null private var groups = linkedSetOf() - private var refreshTime = System.currentTimeMillis() override fun onActivityCreated(savedInstanceState: Bundle?) { initRecyclerView() @@ -185,14 +183,13 @@ class SearchActivity : VMBaseActivity(R.layout.activity_book_se upGroupMenu() }) viewModel.searchBookLiveData.observe(this, Observer { - upSearchItems(it, false) + upSearchItems(it) }) viewModel.isSearchLiveData.observe(this, Observer { if (it) { startSearch() } else { searchFinally() - upSearchItems(viewModel.searchBooks, true) } }) } @@ -288,14 +285,8 @@ class SearchActivity : VMBaseActivity(R.layout.activity_book_se * 更新搜索结果 */ @Synchronized - private fun upSearchItems(items: List, isMandatoryUpdate: Boolean) { - val searchItems = ArrayList(items) - if (isMandatoryUpdate || System.currentTimeMillis() - refreshTime > 500) { - refreshTime = System.currentTimeMillis() - val diffResult = - DiffUtil.calculateDiff(DiffCallBack(adapter.getItems(), searchItems)) - adapter.setItems(searchItems, diffResult) - } + private fun upSearchItems(items: List) { + adapter.setItems(items) } /** @@ -321,7 +312,10 @@ class SearchActivity : VMBaseActivity(R.layout.activity_book_se override fun showBookInfo(name: String, author: String) { viewModel.getSearchBook(name, author) { searchBook -> searchBook?.let { - startActivity(Pair("bookUrl", it.bookUrl)) + startActivity( + Pair("name", it.name), + Pair("author", it.author) + ) } } } @@ -331,7 +325,8 @@ class SearchActivity : VMBaseActivity(R.layout.activity_book_se */ override fun showBookInfo(book: Book) { startActivity( - Pair("bookUrl", book.bookUrl) + Pair("name", book.name), + Pair("author", book.author) ) } diff --git a/app/src/main/java/io/legado/app/ui/book/search/SearchViewModel.kt b/app/src/main/java/io/legado/app/ui/book/search/SearchViewModel.kt index ccfc5dd15..318937697 100644 --- a/app/src/main/java/io/legado/app/ui/book/search/SearchViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/book/search/SearchViewModel.kt @@ -1,6 +1,7 @@ package io.legado.app.ui.book.search import android.app.Application +import android.os.Handler import androidx.lifecycle.MutableLiveData import io.legado.app.App import io.legado.app.base.BaseViewModel @@ -12,15 +13,18 @@ import io.legado.app.utils.getPrefBoolean import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.isActive -class SearchViewModel(application: Application) : BaseViewModel(application) - , SearchBookModel.CallBack { +class SearchViewModel(application: Application) : BaseViewModel(application), + SearchBookModel.CallBack { + val handler = Handler() private val searchBookModel = SearchBookModel(this, this) var isSearchLiveData = MutableLiveData() var searchBookLiveData = MutableLiveData>() var searchKey: String = "" var isLoading = false - var searchBooks = arrayListOf() + private var searchBooks = arrayListOf() private var searchID = 0L + private var postTime = 0L + private val sendRunnable = Runnable { upAdapter() } /** * 开始搜索 @@ -36,6 +40,18 @@ class SearchViewModel(application: Application) : BaseViewModel(application) searchBookModel.search(searchID, searchKey) } + @Synchronized + private fun upAdapter() { + if (System.currentTimeMillis() >= postTime + 500) { + handler.removeCallbacks(sendRunnable) + postTime = System.currentTimeMillis() + searchBookLiveData.postValue(searchBooks) + } else { + handler.removeCallbacks(sendRunnable) + handler.postDelayed(sendRunnable, 500 - System.currentTimeMillis() + postTime) + } + } + override fun onSearchStart() { isSearchLiveData.postValue(true) } @@ -151,7 +167,7 @@ class SearchViewModel(application: Application) : BaseViewModel(application) }) if (!scope.isActive) return searchBooks = copyDataS - searchBookLiveData.postValue(copyDataS) + upAdapter() } } diff --git a/app/src/main/java/io/legado/app/ui/book/source/manage/BookSourceActivity.kt b/app/src/main/java/io/legado/app/ui/book/source/manage/BookSourceActivity.kt index 2b4a588c4..7273d512d 100644 --- a/app/src/main/java/io/legado/app/ui/book/source/manage/BookSourceActivity.kt +++ b/app/src/main/java/io/legado/app/ui/book/source/manage/BookSourceActivity.kt @@ -58,6 +58,7 @@ class BookSourceActivity : VMBaseActivity(R.layout.activity private var bookSourceLiveDate: LiveData>? = null private var groups = linkedSetOf() private var groupMenu: SubMenu? = null + private var sort = 0 override fun onActivityCreated(savedInstanceState: Bundle?) { initUriScheme() @@ -75,6 +76,8 @@ class BookSourceActivity : VMBaseActivity(R.layout.activity override fun onPrepareOptionsMenu(menu: Menu?): Boolean { groupMenu = menu?.findItem(R.id.menu_group)?.subMenu + groupMenu?.findItem(R.id.action_sort)?.subMenu + ?.setGroupCheckable(R.id.menu_group_sort, true, true) upGroupMenu() return super.onPrepareOptionsMenu(menu) } @@ -93,6 +96,26 @@ class BookSourceActivity : VMBaseActivity(R.layout.activity allowExtensions = arrayOf("txt", "json") ) R.id.menu_import_source_onLine -> showImportDialog() + R.id.menu_sort_manual -> { + item.isChecked = true + sort = 0 + initLiveDataBookSource(search_view.query?.toString()) + } + R.id.menu_sort_auto -> { + item.isChecked = true + sort = 2 + initLiveDataBookSource(search_view.query?.toString()) + } + R.id.menu_sort_pin_yin -> { + item.isChecked = true + sort = 3 + initLiveDataBookSource(search_view.query?.toString()) + } + R.id.menu_sort_url -> { + item.isChecked = true + sort = 4 + initLiveDataBookSource(search_view.query?.toString()) + } } if (item.groupId == R.id.source_group) { search_view.setQuery(item.title, true) @@ -105,14 +128,14 @@ class BookSourceActivity : VMBaseActivity(R.layout.activity when (it.path) { "/importonline" -> it.getQueryParameter("src")?.let { url -> Snackbar.make(title_bar, R.string.importing, Snackbar.LENGTH_INDEFINITE).show() - if (url.startsWith("http", false)){ + if (url.startsWith("http", false)) { viewModel.importSource(url) { msg -> title_bar.snackbar(msg) } - } - else{ - viewModel.importSourceFromFilePath(url){msg -> - title_bar.snackbar(msg)} + } else { + viewModel.importSourceFromFilePath(url) { msg -> + title_bar.snackbar(msg) + } } } else -> { @@ -150,10 +173,16 @@ class BookSourceActivity : VMBaseActivity(R.layout.activity } else { App.db.bookSourceDao().liveDataSearch("%$searchKey%") } - bookSourceLiveDate?.observe(this, Observer { + bookSourceLiveDate?.observe(this, Observer { data -> + val sourceList = when (sort) { + 1 -> data.sortedBy { it.weight } + 2 -> data.sortedBy { it.bookSourceName } + 3 -> data.sortedBy { it.bookSourceUrl } + else -> data + } val diffResult = DiffUtil - .calculateDiff(DiffCallBack(ArrayList(adapter.getItems()), it)) - adapter.setItems(it, diffResult) + .calculateDiff(DiffCallBack(ArrayList(adapter.getItems()), sourceList)) + adapter.setItems(sourceList, diffResult) upCountView() }) } @@ -204,13 +233,35 @@ class BookSourceActivity : VMBaseActivity(R.layout.activity R.id.menu_enable_explore -> viewModel.enableSelectExplore(adapter.getSelection()) R.id.menu_disable_explore -> viewModel.disableSelectExplore(adapter.getSelection()) R.id.menu_export_selection -> FilePicker.selectFolder(this, exportRequestCode) - R.id.menu_check_source -> CheckSource.start(this, adapter.getSelection()) + R.id.menu_check_source -> checkSource() R.id.menu_top_sel -> viewModel.topSource(*adapter.getSelection().toTypedArray()) R.id.menu_bottom_sel -> viewModel.bottomSource(*adapter.getSelection().toTypedArray()) } return true } + @SuppressLint("InflateParams") + private fun checkSource() { + alert(titleResource = R.string.search_book_key) { + var editText: AutoCompleteTextView? = null + customView { + layoutInflater.inflate(R.layout.dialog_edit_text, null).apply { + editText = edit_view + edit_view.setText(CheckSource.keyword) + } + } + okButton { + editText?.text?.toString()?.let { + if (it.isNotEmpty()) { + CheckSource.keyword = it + } + } + CheckSource.start(this@BookSourceActivity, adapter.getSelection()) + } + noButton { } + }.show().applyTint() + } + private fun upGroupMenu() { groupMenu?.removeGroup(R.id.source_group) groups.sortedWith(Collator.getInstance(java.util.Locale.CHINESE)) diff --git a/app/src/main/java/io/legado/app/ui/book/source/manage/BookSourceViewModel.kt b/app/src/main/java/io/legado/app/ui/book/source/manage/BookSourceViewModel.kt index c6dc63c8e..c0e255783 100644 --- a/app/src/main/java/io/legado/app/ui/book/source/manage/BookSourceViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/book/source/manage/BookSourceViewModel.kt @@ -158,10 +158,7 @@ class BookSourceViewModel(application: Application) : BaseViewModel(application) execute { val sources = App.db.bookSourceDao().getByGroup(group) sources.map { source -> - source.bookSourceGroup?.splitNotBlank(",")?.toHashSet()?.let { - it.remove(group) - source.bookSourceGroup = TextUtils.join(",", it) - } + source.removeGroup(group) } App.db.bookSourceDao().update(*sources.toTypedArray()) } diff --git a/app/src/main/java/io/legado/app/ui/config/FileAssociationViewModel.kt b/app/src/main/java/io/legado/app/ui/config/FileAssociationViewModel.kt index 02aab3668..4f897c791 100644 --- a/app/src/main/java/io/legado/app/ui/config/FileAssociationViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/config/FileAssociationViewModel.kt @@ -13,66 +13,73 @@ import io.legado.app.utils.readText import java.io.File class FileAssociationViewModel(application: Application) : BaseViewModel(application) { + fun dispatchIndent(uri: Uri): Intent? { - val url: String - //如果是普通的url,需要根据返回的内容判断是什么 - if (uri.scheme == "file" || uri.scheme == "content") { - val content = if (uri.scheme == "file") { - val file = File(uri.path.toString()) - if (file.exists()) { - file.readText() + try { + val url: String + //如果是普通的url,需要根据返回的内容判断是什么 + if (uri.scheme == "file" || uri.scheme == "content") { + val content = if (uri.scheme == "file") { + val file = File(uri.path.toString()) + if (file.exists()) { + file.readText() + } else { + null + } } else { - null + DocumentFile.fromSingleUri(context, uri)?.readText(context) } - } else { - DocumentFile.fromSingleUri(context, uri)?.readText(context) - } - var scheme = "" - if (content != null) { - if (content.isJsonObject() || content.isJsonArray()) { - //暂时根据文件内容判断属于什么 - when { - content.contains("bookSourceUrl") -> { - scheme = "booksource" - } - content.contains("sourceUrl") -> { - scheme = "rsssource" - } - content.contains("pattern") -> { - scheme = "replace" + var scheme = "" + if (content != null) { + if (content.isJsonObject() || content.isJsonArray()) { + //暂时根据文件内容判断属于什么 + when { + content.contains("bookSourceUrl") -> { + scheme = "booksource" + } + content.contains("sourceUrl") -> { + scheme = "rsssource" + } + content.contains("pattern") -> { + scheme = "replace" + } } } - } - if (TextUtils.isEmpty(scheme)) { - execute { - if (uri.scheme == "content"){ - LocalBook.importFile(uri.toString()) - }else{ - LocalBook.importFile(uri.path.toString()) + if (TextUtils.isEmpty(scheme)) { + execute { + if (uri.scheme == "content") { + LocalBook.importFile(uri.toString()) + } else { + LocalBook.importFile(uri.path.toString()) + } + toast("添加本地文件成功${uri.path}") } - toast("添加本地文件成功${uri.path}") + return null } + } else { + toast("文件不存在") return null } + // content模式下,需要传递完整的路径,方便后续解析 + url = if (uri.scheme == "content") { + "yuedu://${scheme}/importonline?src=$uri" + } else { + "yuedu://${scheme}/importonline?src=${uri.path}" + } + + } else if (uri.scheme == "yuedu") { + url = uri.toString() } else { - toast("文件不存在") - return null - } - // content模式下,需要传递完整的路径,方便后续解析 - url = if (uri.scheme == "content"){ - "yuedu://${scheme}/importonline?src=$uri" - }else{ - "yuedu://${scheme}/importonline?src=${uri.path}" + url = "yuedu://booksource/importonline?src=${uri.path}" } - - } else if (uri.scheme == "yuedu") { - url = uri.toString() - } else { - url = "yuedu://booksource/importonline?src=${uri.path}" + val data = Uri.parse(url) + val newIndent = Intent(Intent.ACTION_VIEW) + newIndent.data = data + return newIndent + } catch (e: Exception) { + e.printStackTrace() + toast(e.localizedMessage) + return null } - val data = Uri.parse(url) - val newIndent = Intent(Intent.ACTION_VIEW) - newIndent.data = data - return newIndent } } \ No newline at end of file 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 181ec0330..8664d2eab 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 @@ -26,13 +26,14 @@ import io.legado.app.ui.main.rss.RssFragment import io.legado.app.ui.widget.dialog.TextDialog import io.legado.app.utils.* import kotlinx.android.synthetic.main.activity_main.* +import org.jetbrains.anko.toast class MainActivity : VMBaseActivity(R.layout.activity_main), BottomNavigationView.OnNavigationItemSelectedListener, ViewPager.OnPageChangeListener by ViewPager.SimpleOnPageChangeListener() { override val viewModel: MainViewModel get() = getViewModel(MainViewModel::class.java) - + private var exitTime: Long = 0 private var pagePosition = 0 private val fragmentId = arrayOf(0, 1, 2, 3) private val fragmentMap = mapOf( @@ -105,8 +106,14 @@ class MainActivity : VMBaseActivity(R.layout.activity_main), return true } if (!BaseReadAloudService.pause) { - moveTaskToBack(true) - return true + if (System.currentTimeMillis() - exitTime > 2000) { + toast(R.string.double_click_exit) + exitTime = System.currentTimeMillis() + } else { + moveTaskToBack(true) + return true + } + return false } } } @@ -121,6 +128,15 @@ class MainActivity : VMBaseActivity(R.layout.activity_main), } } + override fun finish() { + if (System.currentTimeMillis() - exitTime > 2000) { + toast(R.string.double_click_exit) + exitTime = System.currentTimeMillis() + } else { + super.finish() + } + } + override fun onDestroy() { super.onDestroy() ReadAloud.stop(this) diff --git a/app/src/main/java/io/legado/app/ui/main/bookshelf/books/BooksAdapterGrid.kt b/app/src/main/java/io/legado/app/ui/main/bookshelf/books/BooksAdapterGrid.kt index 1438c4507..be725abe9 100644 --- a/app/src/main/java/io/legado/app/ui/main/bookshelf/books/BooksAdapterGrid.kt +++ b/app/src/main/java/io/legado/app/ui/main/bookshelf/books/BooksAdapterGrid.kt @@ -2,6 +2,7 @@ package io.legado.app.ui.main.bookshelf.books import android.content.Context import android.os.Bundle +import android.view.View import io.legado.app.R import io.legado.app.base.adapter.ItemViewHolder import io.legado.app.constant.BookType @@ -22,33 +23,30 @@ class BooksAdapterGrid(context: Context, private val callBack: CallBack) : ATH.applyBackgroundTint(this) tv_name.text = item.name iv_cover.load(item.getDisplayCover(), item.name, item.author) - if (item.origin != BookType.local && callBack.isUpdate(item.bookUrl)) { - bv_unread.invisible() - rl_loading.show() - } else { - rl_loading.hide() - bv_unread.setBadgeCount(item.getUnreadChapterNum()) - bv_unread.setHighlight(item.lastCheckCount > 0) - } + upRefresh(this, item) } else { bundle.keySet().map { when (it) { "name" -> tv_name.text = item.name "cover" -> iv_cover.load(item.getDisplayCover(), item.name, item.author) - "refresh" -> if (item.origin != BookType.local && callBack.isUpdate(item.bookUrl)) { - bv_unread.invisible() - rl_loading.show() - } else { - rl_loading.hide() - bv_unread.setBadgeCount(item.getUnreadChapterNum()) - bv_unread.setHighlight(item.lastCheckCount > 0) - } + "refresh" -> upRefresh(this, item) } } } } } + private fun upRefresh(itemView: View, item: Book) = with(itemView) { + if (item.origin != BookType.local && callBack.isUpdate(item.bookUrl)) { + bv_unread.invisible() + rl_loading.show() + } else { + rl_loading.hide() + bv_unread.setBadgeCount(item.getUnreadChapterNum()) + bv_unread.setHighlight(item.lastCheckCount > 0) + } + } + override fun registerListener(holder: ItemViewHolder) { holder.itemView.apply { onClick { diff --git a/app/src/main/java/io/legado/app/ui/main/bookshelf/books/BooksAdapterList.kt b/app/src/main/java/io/legado/app/ui/main/bookshelf/books/BooksAdapterList.kt index 755f55f20..7ed9a7d99 100644 --- a/app/src/main/java/io/legado/app/ui/main/bookshelf/books/BooksAdapterList.kt +++ b/app/src/main/java/io/legado/app/ui/main/bookshelf/books/BooksAdapterList.kt @@ -2,6 +2,7 @@ package io.legado.app.ui.main.bookshelf.books import android.content.Context import android.os.Bundle +import android.view.View import io.legado.app.R import io.legado.app.base.adapter.ItemViewHolder import io.legado.app.constant.BookType @@ -25,14 +26,7 @@ class BooksAdapterList(context: Context, private val callBack: CallBack) : tv_read.text = item.durChapterTitle tv_last.text = item.latestChapterTitle iv_cover.load(item.getDisplayCover(), item.name, item.author) - if (item.origin != BookType.local && callBack.isUpdate(item.bookUrl)) { - bv_unread.invisible() - rl_loading.show() - } else { - rl_loading.hide() - bv_unread.setBadgeCount(item.getUnreadChapterNum()) - bv_unread.setHighlight(item.lastCheckCount > 0) - } + upRefresh(this, item) } else { bundle.keySet().map { when (it) { @@ -41,20 +35,24 @@ class BooksAdapterList(context: Context, private val callBack: CallBack) : "dur" -> tv_read.text = item.durChapterTitle "last" -> tv_last.text = item.latestChapterTitle "cover" -> iv_cover.load(item.getDisplayCover(), item.name, item.author) - "refresh" -> if (item.origin != BookType.local && callBack.isUpdate(item.bookUrl)) { - bv_unread.invisible() - rl_loading.show() - } else { - rl_loading.hide() - bv_unread.setBadgeCount(item.getUnreadChapterNum()) - bv_unread.setHighlight(item.lastCheckCount > 0) - } + "refresh" -> upRefresh(this, item) } } } } } + private fun upRefresh(itemView: View, item: Book) = with(itemView) { + if (item.origin != BookType.local && callBack.isUpdate(item.bookUrl)) { + bv_unread.invisible() + rl_loading.show() + } else { + rl_loading.hide() + bv_unread.setHighlight(item.lastCheckCount > 0) + bv_unread.setBadgeCount(item.getUnreadChapterNum()) + } + } + override fun registerListener(holder: ItemViewHolder) { holder.itemView.apply { onClick { diff --git a/app/src/main/java/io/legado/app/ui/main/bookshelf/books/BooksDiffCallBack.kt b/app/src/main/java/io/legado/app/ui/main/bookshelf/books/BooksDiffCallBack.kt index 27954c634..0756daca5 100644 --- a/app/src/main/java/io/legado/app/ui/main/bookshelf/books/BooksDiffCallBack.kt +++ b/app/src/main/java/io/legado/app/ui/main/bookshelf/books/BooksDiffCallBack.kt @@ -16,54 +16,45 @@ class BooksDiffCallBack(private val oldItems: List, private val newItems: } override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean { - return oldItems[oldItemPosition].bookUrl == newItems[newItemPosition].bookUrl + val oldItem = oldItems[oldItemPosition] + val newItem = newItems[newItemPosition] + return oldItem.name == newItem.name + && oldItem.author == newItem.author } override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean { val oldItem = oldItems[oldItemPosition] val newItem = newItems[newItemPosition] - if (oldItem.name != newItem.name) - return false - if (oldItem.author != newItem.author) - return false - if (oldItem.durChapterTitle != newItem.durChapterTitle) - return false - if (oldItem.latestChapterTitle != newItem.latestChapterTitle) - return false - if (oldItem.lastCheckCount != newItem.lastCheckCount) - return false - if (oldItem.getDisplayCover() != newItem.getDisplayCover()) - return false - if (oldItem.getUnreadChapterNum() != newItem.getUnreadChapterNum()) - return false - return true + return when { + oldItem.durChapterTime != newItem.durChapterTime -> false + oldItem.name != newItem.name -> false + oldItem.author != newItem.author -> false + oldItem.durChapterTitle != newItem.durChapterTitle -> false + oldItem.latestChapterTitle != newItem.latestChapterTitle -> false + oldItem.lastCheckCount != newItem.lastCheckCount -> false + oldItem.getDisplayCover() != newItem.getDisplayCover() -> false + oldItem.getUnreadChapterNum() != newItem.getUnreadChapterNum() -> false + else -> true + } } override fun getChangePayload(oldItemPosition: Int, newItemPosition: Int): Any? { val oldItem = oldItems[oldItemPosition] val newItem = newItems[newItemPosition] val bundle = bundleOf() - if (oldItem.name != newItem.name) - bundle.putString("name", null) - if (oldItem.author != newItem.author) - bundle.putString("author", null) - if (oldItem.durChapterTitle != newItem.durChapterTitle) - bundle.putString("dur", null) - if (oldItem.latestChapterTitle != newItem.latestChapterTitle) - bundle.putString("last", null) - if (oldItem.getDisplayCover() != newItem.getDisplayCover()) - bundle.putString("cover", null) - if (oldItem.lastCheckCount != newItem.lastCheckCount) - bundle.putString("refresh", null) - if (oldItem.getUnreadChapterNum() != newItem.getUnreadChapterNum() + if (oldItem.name != newItem.name) bundle.putString("name", null) + if (oldItem.author != newItem.author) bundle.putString("author", null) + if (oldItem.durChapterTitle != newItem.durChapterTitle) bundle.putString("dur", null) + if (oldItem.latestChapterTitle != newItem.latestChapterTitle) bundle.putString("last", null) + if (oldItem.getDisplayCover() != newItem.getDisplayCover()) bundle.putString("cover", null) + if (oldItem.lastCheckCount != newItem.lastCheckCount + || oldItem.durChapterTime != newItem.durChapterTime + || oldItem.getUnreadChapterNum() != newItem.getUnreadChapterNum() || oldItem.lastCheckCount != newItem.lastCheckCount ) { bundle.putString("refresh", null) } - - if (bundle.isEmpty) { - return null - } + if (bundle.isEmpty) return null return bundle } diff --git a/app/src/main/java/io/legado/app/ui/main/bookshelf/books/BooksFragment.kt b/app/src/main/java/io/legado/app/ui/main/bookshelf/books/BooksFragment.kt index 29a8e1d9a..e061a510e 100644 --- a/app/src/main/java/io/legado/app/ui/main/bookshelf/books/BooksFragment.kt +++ b/app/src/main/java/io/legado/app/ui/main/bookshelf/books/BooksFragment.kt @@ -132,7 +132,10 @@ class BooksFragment : BaseFragment(R.layout.fragment_books), } override fun openBookInfo(book: Book) { - context?.startActivity(Pair("bookUrl", book.bookUrl)) + context?.startActivity( + Pair("name", book.name), + Pair("author", book.author) + ) } override fun isUpdate(bookUrl: String): Boolean { diff --git a/app/src/main/java/io/legado/app/ui/widget/prefs/PreferenceCategory.kt b/app/src/main/java/io/legado/app/ui/widget/prefs/PreferenceCategory.kt index 9cf6c2bfd..c150dbe56 100644 --- a/app/src/main/java/io/legado/app/ui/widget/prefs/PreferenceCategory.kt +++ b/app/src/main/java/io/legado/app/ui/widget/prefs/PreferenceCategory.kt @@ -12,7 +12,6 @@ import io.legado.app.help.AppConfig import io.legado.app.lib.theme.ColorUtils import io.legado.app.lib.theme.accentColor import io.legado.app.lib.theme.backgroundColor -import io.legado.app.utils.getCompatColor class PreferenceCategory(context: Context, attrs: AttributeSet) : PreferenceCategory(context, attrs) { @@ -28,12 +27,9 @@ class PreferenceCategory(context: Context, attrs: AttributeSet) : PreferenceCate val view = it.findViewById(R.id.preference_title) if (view is TextView) { // && !view.isInEditMode view.text = title - if (view.isInEditMode) { - view.setTextColor(context.getCompatColor(R.color.colorAccent)) - } else { - view.setBackgroundColor(context.backgroundColor) - view.setTextColor(context.accentColor) - } + if (view.isInEditMode) return + view.setBackgroundColor(context.backgroundColor) + view.setTextColor(context.accentColor) view.isVisible = title != null && title.isNotEmpty() val da = it.findViewById(R.id.preference_divider_above) diff --git a/app/src/main/java/io/legado/app/ui/widget/prefs/SwitchPreference.kt b/app/src/main/java/io/legado/app/ui/widget/prefs/SwitchPreference.kt index 2f6becfc2..41038169f 100644 --- a/app/src/main/java/io/legado/app/ui/widget/prefs/SwitchPreference.kt +++ b/app/src/main/java/io/legado/app/ui/widget/prefs/SwitchPreference.kt @@ -26,7 +26,7 @@ class SwitchPreference(context: Context, attrs: AttributeSet) : widgetLayoutResource, R.id.switchWidget ) - if (v is SwitchCompat) { + if (v is SwitchCompat && !v.isInEditMode) { ATH.setTint(v, context.accentColor) } super.onBindViewHolder(holder) diff --git a/app/src/main/java/io/legado/app/utils/GsonExtensions.kt b/app/src/main/java/io/legado/app/utils/GsonExtensions.kt index 773cd8030..b29b4e2b4 100644 --- a/app/src/main/java/io/legado/app/utils/GsonExtensions.kt +++ b/app/src/main/java/io/legado/app/utils/GsonExtensions.kt @@ -15,6 +15,7 @@ val GSON: Gson by lazy { object : TypeToken?>() {}.type, MapDeserializerDoubleAsIntFix() ) + .registerTypeAdapter(Int::class.java, IntJsonDeserializer()) .disableHtmlEscaping() .setPrettyPrinting() .create() @@ -22,7 +23,6 @@ val GSON: Gson by lazy { inline fun genericType(): Type = object : TypeToken() {}.type -@Throws(JsonSyntaxException::class) inline fun Gson.fromJsonObject(json: String?): T? {//可转成任意类型 return attempt { val result: T? = fromJson(json, genericType()) @@ -30,7 +30,6 @@ inline fun Gson.fromJsonObject(json: String?): T? {//可转成任意 }.value } -@Throws(JsonSyntaxException::class) inline fun Gson.fromJsonArray(json: String?): List? { return attempt { val result: List? = fromJson(json, ParameterizedTypeImpl(T::class.java)) @@ -46,6 +45,32 @@ class ParameterizedTypeImpl(private val clazz: Class<*>) : ParameterizedType { override fun getActualTypeArguments(): Array = arrayOf(clazz) } +/** + * int类型转化失败时跳过 + */ +class IntJsonDeserializer : JsonDeserializer { + + override fun deserialize( + json: JsonElement, + typeOfT: Type?, + context: JsonDeserializationContext? + ): Int? { + return when { + json.isJsonPrimitive -> { + val prim = json.asJsonPrimitive + if (prim.isNumber) { + prim.asNumber.toInt() + } else { + null + } + } + else -> null + } + } + +} + + /** * 修复Int变为Double的问题 */ @@ -62,20 +87,20 @@ class MapDeserializerDoubleAsIntFix : return read(jsonElement) as? Map } - fun read(`in`: JsonElement): Any? { + fun read(json: JsonElement): Any? { when { - `in`.isJsonArray -> { + json.isJsonArray -> { val list: MutableList = ArrayList() - val arr = `in`.asJsonArray + val arr = json.asJsonArray for (anArr in arr) { list.add(read(anArr)) } return list } - `in`.isJsonObject -> { + json.isJsonObject -> { val map: MutableMap = LinkedTreeMap() - val obj = `in`.asJsonObject + val obj = json.asJsonObject val entitySet = obj.entrySet() for ((key, value) in entitySet) { @@ -83,8 +108,8 @@ class MapDeserializerDoubleAsIntFix : } return map } - `in`.isJsonPrimitive -> { - val prim = `in`.asJsonPrimitive + json.isJsonPrimitive -> { + val prim = json.asJsonPrimitive when { prim.isBoolean -> { return prim.asBoolean diff --git a/app/src/main/res/layout/dialog_auto_read.xml b/app/src/main/res/layout/dialog_auto_read.xml new file mode 100644 index 000000000..c444d66bb --- /dev/null +++ b/app/src/main/res/layout/dialog_auto_read.xml @@ -0,0 +1,200 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/dialog_read_aloud.xml b/app/src/main/res/layout/dialog_read_aloud.xml index 504865171..422c1932b 100644 --- a/app/src/main/res/layout/dialog_read_aloud.xml +++ b/app/src/main/res/layout/dialog_read_aloud.xml @@ -273,7 +273,7 @@ android:layout_height="50dp" android:background="?android:attr/selectableItemBackgroundBorderless" android:clickable="true" - android:contentDescription="@string/interface_setting" + android:contentDescription="@string/to_backstage" android:focusable="true" android:orientation="vertical" android:paddingBottom="7dp"> diff --git a/app/src/main/res/layout/dialog_read_book_style.xml b/app/src/main/res/layout/dialog_read_book_style.xml index 9436e0f0a..b57705513 100644 --- a/app/src/main/res/layout/dialog_read_book_style.xml +++ b/app/src/main/res/layout/dialog_read_book_style.xml @@ -37,15 +37,14 @@ android:layout_height="wrap_content" android:layout_weight="1" /> - diff --git a/app/src/main/res/layout/view_preference_category.xml b/app/src/main/res/layout/view_preference_category.xml index 72cf9b5ca..6bdc58c5a 100644 --- a/app/src/main/res/layout/view_preference_category.xml +++ b/app/src/main/res/layout/view_preference_category.xml @@ -19,6 +19,7 @@ android:paddingLeft="16dp" android:layout_width="match_parent" android:layout_height="wrap_content" + android:textColor="@color/colorAccent" tools:ignore="RtlHardcoded,RtlSymmetry" /> - - - - - - + android:checkableBehavior="single"> + + + + + + + + + + diff --git a/app/src/main/res/values-zh-rHK/arrays.xml b/app/src/main/res/values-zh-rHK/arrays.xml index ebe6c25dd..b99ad1992 100644 --- a/app/src/main/res/values-zh-rHK/arrays.xml +++ b/app/src/main/res/values-zh-rHK/arrays.xml @@ -49,4 +49,9 @@ 系統等寬字體 + + 正常 + 粗體 + 細體 + \ No newline at end of file diff --git a/app/src/main/res/values-zh-rHK/strings.xml b/app/src/main/res/values-zh-rHK/strings.xml index 84b579b55..9dbf733dd 100644 --- a/app/src/main/res/values-zh-rHK/strings.xml +++ b/app/src/main/res/values-zh-rHK/strings.xml @@ -691,4 +691,14 @@ 隱藏頁脚 自動換源 置底 + 文字兩端對齊 + 自動翻頁速度 + 地址排序 + 文章字體轉換 + 請選擇備份路徑 + 其它 + legado-top + 本地和WebDav壹起備份 + 優先從WebDav恢復,失敗時從本地恢復 + 選擇舊版備份文件夾 diff --git a/app/src/main/res/values-zh-rTW/arrays.xml b/app/src/main/res/values-zh-rTW/arrays.xml new file mode 100644 index 000000000..4efd0c56f --- /dev/null +++ b/app/src/main/res/values-zh-rTW/arrays.xml @@ -0,0 +1,114 @@ + + + + @string/book_type_text + @string/book_type_audio + + + + 度小美 + 度小宇 + 度逍遙 + 度丫丫 + 度小嬌 + 度米朵 + 度博文 + 度小童 + 度小萌 + 百度騷男 + 百度評書 + 百度主持 + + + + @string/indent_0 + @string/indent_1 + @string/indent_2 + @string/indent_3 + @string/indent_4 + + + + .txt + .json + .xml + + + + @string/jf_convert_o + @string/jf_convert_j + @string/jf_convert_f + + + + 跟隨系統 + 亮色主題 + 暗色主題 + + + + 自動 + 黑色 + 白色 + 跟隨背景 + + + + 預設 + 1分鐘 + 2分鐘 + 3分鐘 + 常亮 + + + + @string/default_path + @string/sys_folder_picker + @string/app_folder_picker + + + + @string/screen_unspecified + @string/screen_portrait + @string/screen_landscape + @string/screen_sensor + + + + iconMain + icon1 + icon2 + icon3 + icon4 + icon5 + icon6 + + + + 關閉 + 繁體轉簡體 + 簡體轉繁體 + + + + 系統預設字體 + 系統襯線字體 + 系統等寬字體 + + + + + 標題 + 時間 + 電量 + 頁數 + 進度 + 頁數及進度 + + + + 正常 + 粗體 + 細體 + + diff --git a/app/src/main/res/values-zh-rTW/strings.xml b/app/src/main/res/values-zh-rTW/strings.xml new file mode 100644 index 000000000..8023644cf --- /dev/null +++ b/app/src/main/res/values-zh-rTW/strings.xml @@ -0,0 +1,705 @@ + + + 閱讀 + 閱讀·搜尋 + 閱讀需要存取記憶卡權限,請前往“設定”—“應用權限”—打開所需權限 + + + Home + 復原 + 匯入閱讀資料 + 建立子資料夾 + 建立legado資料夾作為備份資料夾 + 備份路徑 + 匯入舊版資料 + 匯入Github資料 + 淨化取代 + Send + + 提示 + 取消 + 確定 + 去設定 + 無法跳轉至設定介面 + + 點擊重試 + 正在載入 + 提醒 + 編輯 + 刪除 + 取代 + 取代淨化 + 配置取代淨化規則 + 暫無 + 啟用 + 取代淨化-搜尋 + 書架 + 收藏夾 + 收藏 + 已收藏 + 未收藏 + 訂閱 + 全部 + 最近閱讀 + 最後閱讀 + 更新日誌 + 書架還空著,先去添加吧! + 搜尋 + 下載 + 列表 + 網格三列 + 網格四列 + 網格五列 + 網格六列 + 書架布局 + 檢視 + 書城 + 添加本機 + 書源 + 書源管理 + 建立/匯入/編輯/管理書源 + 設定 + 主題設定 + 與介面/顏色相關的一些設定 + 其它設定 + 與功能相關的一些設定 + 關於 + 捐贈 + 退出 + 尚未儲存,是否繼續編輯 + 閱讀樣式設定 + 版本 + 本機 + 搜尋 + 來源: %s + 最近: %s + 書名 + 最新: %s + 是否將《%s》放入書架? + 共%s個Text文件 + 載入中… + 重試 + Web 服務 + 啟用Web服務 + web編輯書源 + http://%1$s:%2$d + 離線下載 + 離線下載 + 下載選擇的章節到本機 + 換源 + + \u3000\u3000這是一款使用Kotlin全新開發的開源的閱讀軟體,歡迎您的加入。關注公眾號[開源閱讀]! + + + 閱讀3.0下載網址:\nhttps://play.google.com/store/apps/details?id=io.legado.app + + Version %s + 自動重新整理 + 打開軟體時自動更新書籍 + 自動下載最新章節 + 更新書籍時自動下載最新章節 + 備份與復原 + WebDav設定 + WebDav設定/匯入舊版本資料 + 備份 + 復原 + 備份請給與儲存權限 + 復原請給與儲存權限 + 確認 + 取消 + 確認備份嗎? + 新備份會取代原有備份。\n備份資料夾YueDu + 確認復原嗎? + 復原書架會覆蓋現有書架。 + 備份成功 + 備份失敗 + 正在復原 + 復原成功 + 復原失敗 + 螢幕方向 + 跟隨感測器 + 橫向 + 豎向 + 跟隨系統 + 免責聲明 + 共%d章 + 介面 + 亮度 + 目錄 + 下一章 + 上一章 + 隱藏狀態欄 + 閱讀介面隱藏狀態欄 + 朗讀 + 正在朗讀 + 點擊打開閱讀介面 + 播放 + 正在播放 + 點擊打開播放介面 + 播放暫停 + 返回 + 重新整理 + 開始 + 停止 + 暫停 + 繼續 + 定時 + 朗讀暫停 + 正在朗讀(還剩%d分鐘) + 閱讀介面隱藏虛擬按鍵 + 隱藏導航欄 + 導航欄顏色 + GitHub + 評分 + 發送郵件 + 無法打開 + 分享失敗 + 無章節 + 添加網址 + 添加書籍網址 + 背景 + 作者 + 作者: %s + 朗讀停止 + 清除快取 + 成功清理快取 + 儲存 + 編輯源 + 編輯書源 + 禁用書源 + 建立書源 + 建立訂閱源 + 添加書籍 + 掃描 + 複製源 + 貼上源 + 源規則說明 + 檢查更新 + 掃描二維碼 + 掃描本機圖片 + 規則說明 + 分享 + 軟體分享 + 跟隨系統 + 添加 + 匯入書源 + 本機匯入 + 網路匯入 + 取代淨化 + 取代規則編輯 + 取代規則 + 取代為 + 封面 + + 音量鍵翻頁 + 點擊翻頁 + 點擊總是翻下一頁 + 翻頁動畫 + 螢幕超時 + 返回 + 選單 + 調節 + 滾動條 + 清除快取會刪除所有已儲存章節,是否確認刪除? + 書源共享 + 取代規則名稱 + 取代規則為空或者不滿足正規表示式要求 + 選擇操作 + 全選 + 全選(%1$d/%2$d) + 取消(%1$d/%2$d) + 深色模式 + 啟動頁 + 開始下載 + 取消下載 + 暫無任務 + 已下載 %1$d/%2$d + 匯入選擇書籍 + 更新和搜尋執行緒數,太多會卡頓 + 切換圖示 + 刪除書籍 + 開始閱讀 + 載入資料中… + 載入失敗,點擊重試 + 內容簡介 + 簡介:%s + 打開外部書籍 + 來源: %s + 本機匯入 + 匯入線上規則 + 檢查更新間隔 + 按閱讀時間 + 按更新時間 + 按書名 + 手動排序 + 閱讀方式 + 排版 + 刪除所選 + 是否確認刪除? + 預設字體 + 發現 + 發現管理 + 沒有內容,去書源裡自訂吧! + 刪除所有 + 搜尋歷史 + 清除 + 正文顯示標題 + 書源同步 + 無最新章節訊息 + 顯示時間和電量 + 顯示分隔線 + 深色狀態欄圖示 + 內容 + 複製內容 + 一鍵快取 + 這是一段測試文字\n\u3000\u3000只是讓你看看效果的 + 文字顏色和背景(長按自訂) + 沉浸式狀態欄 + 還剩%d章未下載 + 沒有選擇 + 長按輸入顏色值 + 載入中… + 追更區 + 養肥區 + 書籤 + 添加書籤 + 刪除 + 載入超時 + 關注:%s + 已複製 + 整理書架 + 這將會刪除所有書籍,請謹慎操作。 + 搜尋書源 + 搜尋訂閱源 + 搜尋(共%d個書源) + 目錄(%d) + 加粗 + 字體 + 文字 + 軟體首頁 + + + + + 邊距 + 上邊距 + 下邊距 + 左邊距 + 右邊距 + 校驗書源 + 校驗所選 + 進度 %1$d/%2$d + 請安裝並選擇中文TTS! + TTS初始化失敗! + 簡繁轉換 + 關閉 + 簡轉繁 + 繁轉簡 + 翻頁模式 + %1$d 項 + 記憶卡: + 加入書架 + 加入書架(%1$d) + 成功添加%1$d本書 + 請將字體檔案放到SD根目錄Fonts資料夾下重新選擇 + 預設字體 + 選擇字體 + 字號 + 行距 + 段距 + 置頂 + 置底 + 自動展開發現 + 預設展開第一組發現 + 目前執行緒數 %s + 朗讀語速 + 自動翻頁 + 停止自動翻頁 + 自動翻頁間隔 + 書籍訊息 + 書籍訊息編輯 + 預設打開書架 + 自動跳轉最近閱讀 + 取代範圍,選填書名或者源名 + 分組 + 內容快取路徑 + 清理快取 + 系統檔案選擇器 + 新版本 + 下載更新 + 朗讀時音量鍵翻頁 + Tip邊距跟隨邊距調整 + 允許更新 + 禁止更新 + 反選 + 搜尋書名、作者 + 書名、作者、URL + 常見問題 + 顯示所有發現 + 關閉則只顯示勾選源的發現 + 更新目錄 + Txt目錄正則 + 設定編碼 + 倒序-順序 + 排序 + 智慧排序 + 手動排序 + 拼音排序 + 滾動到頂部 + 滾動到底部 + 已讀: %s + 追更 + 養肥 + 完結 + 所有書籍 + 追更書籍 + 養肥書籍 + 完結書籍 + 本機書籍 + 狀態欄顏色透明 + 導航欄變色 + 導航欄根據夜間模式變化 + 放入書架 + 繼續閱讀 + 封面地址 + 覆蓋 + 滑動 + 模擬 + 滾動 + 無動畫 + 此書源使用了進階功能,請到捐贈裡點擊支付寶紅包搜尋碼領取紅包開啟。 + 後台更新換源最新章節 + 開啟則會在軟體打開1分鐘後開始更新 + 書架ToolBar自動隱藏 + 滾動書架時ToolBar自動隱藏與顯示 + 登入 + 登入%s + 成功 + 目前源沒有配置登入地址 + + + 源名稱(sourceName) + 源URL(sourceUrl) + 源分組(sourceGroup) + 分類Url + 登入URL(loginUrl) + 搜尋地址(url) + 發現地址規則(url) + 書籍列表規則(bookList) + 書名規則(name) + 詳情頁url規則(bookUrl) + 作者規則(author) + 分類規則(kind) + 簡介規則(intro) + 封面規則(coverUrl) + 最新章節規則(lastChapter) + 字數規則(wordCount) + 書籍URL正則(bookUrlPattern) + 預處理規則(bookInfoInit) + 目錄URL規則(tocUrl) + 目錄下一頁規則(nextTocUrl) + 目錄列表規則(chapterList) + 章節名稱規則(ChapterName) + 章節URL規則(chapterUrl) + VIP標識(isVip) + 更新時間(ChapterInfo) + 正文規則(content) + 正文下一頁URL規則(nextContentUrl) + webJs + 資源正則(sourceRegex) + + 圖示(sourceIcon) + 列表規則(ruleArticles) + 列表下一頁規則(ruleArticles) + 標題規則(ruleTitle) + guid規則(ruleGuid) + 時間規則(rulePubDate) + 類別規則(ruleCategories) + 描述規則(ruleDescription) + 圖片url規則(ruleImage) + 內容規則(ruleContent) + 樣式(style) + 連結規則(ruleLink) + + + + 沒有書源 + 書籍訊息獲取失敗 + 內容獲取失敗 + 目錄獲取失敗 + 瀏覽網站失敗:%s + 文件讀取失敗 + 載入目錄失敗 + 獲取資料失敗! + 載入失敗\n%s + 沒有網路 + 網路連接超時 + 資料解析失敗 + + + 請求頭(header) + 除錯源 + 二維碼匯入 + 掃描二維碼 + 選中時點擊可彈出選單 + 主題 + 主題模式 + 選擇主題模式 + 預設主題 + 復原主題為預設配色 + 加入QQ群 + 獲取背景圖片需儲存權限 + 輸入書源網址 + 刪除文件 + 刪除文件成功 + 確定刪除文件嗎? + 手機目錄 + 智慧匯入 + 發現 + 切換顯示樣式 + 匯入本機書籍需儲存權限 + 夜間模式 + E-Ink 模式 + 電子墨水屏模式 + 本軟體需要儲存權限來儲存備份書籍訊息 + 再按一次退出程式 + 匯入本機書籍需儲存權限 + 網路連接不可用 + + + 確認 + 是否確認刪除? + 是否刪除全部書籍? + 是否同時刪除已下載的書籍目錄? + 掃描二維碼需相機權限 + 朗讀正在執行,不能自動翻頁 + 輸入編碼 + TXT目錄規則 + 打開外部書籍需獲取儲存權限 + 未獲取到書名 + 輸入取代規則網址 + 搜尋列表獲取成功%d + 書源名稱和URL不能為空 + 圖庫 + 領支付寶紅包 + 沒有獲取到更新地址 + 正在打開首頁,成功自動返回主介面 + 登入成功後請點擊右上角圖示進行首頁訪問測試 + + + 使用正規表示式 + 縮排 + 無縮排 + 一字元縮排 + 二字元縮排 + 三字元縮排 + 四字元縮排 + 選擇資料夾 + 選擇文件 + 沒有發現,可以在書源裡添加。 + 復原預設 + 自訂快取路徑需要儲存權限 + 黑色 + 文章內容為空 + 正在換源請等待… + 目錄列表為空 + 字距 + + 基本 + 搜尋 + 發現 + 詳情 + 目錄 + 正文 + + E-Ink 模式 + 去除動畫,最佳化電紙書使用體驗 + Web服務 + web埠 + 目前埠 %s + 二維碼分享 + 字串分享 + wifi分享 + 請給於儲存權限 + 減速 + 加速 + 上一個 + 下一個 + 音樂 + 音訊 + 啟用 + 啟用JS + 載入BaseUrl + 全部書源 + 輸入不能為空 + 清空發現快取 + 編輯發現 + 切換軟體顯示在桌面的圖示 + 幫助 + 我的 + 閱讀 + %d%% + %d分鐘 + 自動亮度%s + 按頁朗讀 + 線上朗讀 + 背景圖片 + 背景顏色 + 文字顏色 + 選擇圖片 + 分組管理 + 分組選擇 + 編輯分組 + 移入分組 + 添加分組 + 建立取代 + 分組 + 分組: %s + 目錄: %s + 啟用發現 + 禁用發現 + 啟用所選 + 禁用所選 + 匯出所選 + 匯出 + 載入目錄 + TTS + WebDav 密碼 + 輸入你的WebDav授權密碼 + 輸入你的伺服器地址 + WebDav 伺服器地址 + WebDav 帳號 + 輸入你的WebDav帳號 + 訂閱源 + 編輯訂閱源 + 篩選 + 篩選發現 + 目前位置: + 精準搜尋 + 正在啟動服務 + + 文件選擇 + 資料夾選擇 + 我是有底線的 + Uri轉Path失敗 + 重新整理封面 + 封面換源 + 選擇本機圖片 + 類型: + 文字 + 音訊 + 後台 + 正在匯入 + 正在匯出 + 自訂翻頁按鍵 + 上一頁按鍵 + 下一頁按鍵 + 先將書籍加入書架 + 未分組 + 上一句 + 下一句 + 其它目錄 + 文字太多,生成二維碼失敗 + 分享RSS源 + 分享書源 + 自動切換夜間模式 + 夜間模式跟隨系統 + 上級 + 線上朗讀音色 + (%1$d/%2$d) + 顯示訂閱 + 服務已停止 + 正在啟動服務\n具體訊息查看通知欄 + 預設路徑 + 系統資料夾選擇器 + 自帶選擇器\n(Android10以上因權限限制可能無法使用) + Android10以上因權限限制可能無法讀寫文件 + 長按文字在操作選單中顯示閱讀·搜尋 + 文字操作顯示搜尋 + 記錄日誌 + 中文簡繁體轉換 + 圖示為向量圖示,Android8.0以前不支援 + 朗讀設定 + 主介面 + 長按選擇文字 + 頁首 + 正文 + 頁尾 + 文字選擇結束位置 + 文字選擇開始位置 + 共用布局 + 瀏覽器 + 匯入預設規則 + 名稱 + 正則 + 更多選單 + + + 系統內建字體樣式 + 刪除來源文件 + 預設一 + 預設二 + 預設三 + 標題 + 靠左 + 居中 + 隱藏 + 加入分組 + 儲存圖片 + 沒有預設路徑 + 設定分組 + 查看目錄 + 導航欄陰影 + 目前陰影大小(elevation): %s + 預設 + 主選單 + 點擊授予權限 + 閱讀需要存取記憶卡權限,請點擊下方的"授予權限"按鈕,或前往“設定”—“應用權限”—打開所需權限。如果授予權限後仍然不正常,請點擊右上角的“選擇資料夾”,使用系統資料夾選擇器。 + 全文朗讀中不能朗讀選中文字 + 擴展到瀏海 + 更新目錄中 + 全程響應耳機按鍵 + 即使退出軟體也響應耳機按鍵 + 開發人員 + 聯繫我們 + 開源許可 + 其它 + legado-top + 關注公眾號 + 微信 + 您的支援是我更新的動力 + 公眾號[開源閱讀] + 正在自動換源 + 點擊加入 + + 訊息 + 隱藏頁首 + 隱藏頁尾 + 切換布局 + + + 主色調 + 強調色 + 背景色 + 底部操作欄顏色 + 白天 + 白天,主色調 + 白天,強調色 + 白天,背景色 + 白天,底欄色 + 夜間 + 夜間,主色調 + 夜間,強調色 + 夜間,背景色 + 夜間,底欄色 + 自動換源 + 文字兩端對齊 + 自動翻頁速度 + 地址排序 + 文章字體轉換 + 請選擇備份路徑 + 本地和WebDav壹起備份 + 優先從WebDav恢復,失敗時從本地恢復 + 選擇舊版備份文件夾 + + diff --git a/app/src/main/res/values/arrays.xml b/app/src/main/res/values/arrays.xml index b1046096f..e8a99ff2a 100644 --- a/app/src/main/res/values/arrays.xml +++ b/app/src/main/res/values/arrays.xml @@ -106,4 +106,10 @@ 页数及进度 + + 正常 + 粗体 + 细体 + + \ No newline at end of file diff --git a/app/src/main/res/values/pref_key_value.xml b/app/src/main/res/values/pref_key_value.xml index 017bfe798..a2a2611cb 100644 --- a/app/src/main/res/values/pref_key_value.xml +++ b/app/src/main/res/values/pref_key_value.xml @@ -13,7 +13,7 @@ checkUpdate 开源阅读 - https://gitee.com/alanskycn/yuedu/blob/master/Rule/README.md + https://celeter.github.io/ https://github.com/gedoor/legado https://github.com/gedoor/legado/graphs/contributors https://gedoor.github.io/MyBookshelf/disclaimer.html diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 297a4c632..2d49fd471 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -11,6 +11,7 @@ 创建子文件夹 创建legado文件夹作为备份文件夹 备份路径 + 请选择备份路径 导入旧版数据 导入Github数据 净化替换 @@ -663,8 +664,8 @@ 开发人员 联系我们 开源许可 - 其它 - 开源阅读 + 其它 + 开源阅读 关注公众号 微信 您的支持是我更新的动力 @@ -676,6 +677,7 @@ 隐藏页眉 隐藏页脚 切换布局 + 文章字重切换 主色调 @@ -693,5 +695,10 @@ 夜间,背景色 夜间,底栏色 自动换源 - + 文字两端对齐 + 自动翻页速度 + 地址排序 + 本地和WebDav一起备份 + 优先从WebDav恢复,失败时从本地恢复 + 选择旧版备份文件夹 diff --git a/app/src/main/res/xml/about.xml b/app/src/main/res/xml/about.xml index 3c607cd9d..a5c5922e6 100644 --- a/app/src/main/res/xml/about.xml +++ b/app/src/main/res/xml/about.xml @@ -51,6 +51,12 @@ android:summary="@string/this_github_url" app:iconSpaceReserved="false" /> + + + app:iconSpaceReserved="false" + app:layout="@layout/view_preference_category"> + android:key="webDavCreateDir" + android:defaultValue="true" + android:title="@string/mkdirs" + android:summary="@string/mkdirs_description" + app:allowDividerAbove="false" + app:allowDividerBelow="false" + app:iconSpaceReserved="false" /> + app:iconSpaceReserved="false" + app:layout="@layout/view_preference_category"> + android:key="backupUri" + android:title="@string/backup_path" + android:summary="@string/select_backup_path" + app:iconSpaceReserved="false" /> + android:key="web_dav_backup" + android:title="@string/backup" + android:summary="@string/backup_summary" + app:iconSpaceReserved="false" /> + android:key="web_dav_restore" + android:title="@string/restore" + android:summary="@string/restore_summary" + app:iconSpaceReserved="false" /> + android:key="import_old" + android:title="@string/menu_import_old_version" + android:summary="@string/import_old_summary" + app:iconSpaceReserved="false" /> diff --git a/app/src/main/res/xml/pref_config_read.xml b/app/src/main/res/xml/pref_config_read.xml index 1ed0294e5..3b1e81f3c 100644 --- a/app/src/main/res/xml/pref_config_read.xml +++ b/app/src/main/res/xml/pref_config_read.xml @@ -36,6 +36,12 @@ android:key="hideNavigationBar" app:iconSpaceReserved="false" /> + +