From b95856ff843f1404d758d52fe869785f4f917928 Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 14 Oct 2022 21:03:10 +0800 Subject: [PATCH 01/30] =?UTF-8?q?=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../io/legado/app/help/coroutine/Coroutine.kt | 2 +- .../io/legado/app/utils/RegexExtensions.kt | 67 +++++++++++++------ 2 files changed, 49 insertions(+), 20 deletions(-) diff --git a/app/src/main/java/io/legado/app/help/coroutine/Coroutine.kt b/app/src/main/java/io/legado/app/help/coroutine/Coroutine.kt index 16c82fabd..72e87ed5f 100644 --- a/app/src/main/java/io/legado/app/help/coroutine/Coroutine.kt +++ b/app/src/main/java/io/legado/app/help/coroutine/Coroutine.kt @@ -145,7 +145,7 @@ class Coroutine( context: CoroutineContext, block: suspend CoroutineScope.() -> T ): Job { - return (scope + Dispatchers.Main).launch(start = startOption) { + return (scope.plus(Dispatchers.Main)).launch(start = startOption) { try { start?.let { dispatchVoidCallback(this, it) } ensureActive() diff --git a/app/src/main/java/io/legado/app/utils/RegexExtensions.kt b/app/src/main/java/io/legado/app/utils/RegexExtensions.kt index 23a3ea14c..f1a4a300f 100644 --- a/app/src/main/java/io/legado/app/utils/RegexExtensions.kt +++ b/app/src/main/java/io/legado/app/utils/RegexExtensions.kt @@ -1,35 +1,64 @@ package io.legado.app.utils +import android.util.Log +import androidx.core.os.postDelayed import com.script.SimpleBindings import io.legado.app.constant.AppConst import io.legado.app.exception.RegexTimeoutException +import io.legado.app.help.CrashHandler +import io.legado.app.help.coroutine.Coroutine +import kotlinx.coroutines.suspendCancellableCoroutine +import splitties.init.appCtx +import kotlin.coroutines.resume +import kotlin.coroutines.resumeWithException + +private val handler by lazy { buildMainHandler() } /** * 带有超时检测的正则替换 */ -fun CharSequence.replace(regex: Regex, replacement: String, timeout: Long): String { - val startTime = System.currentTimeMillis() - val charSequence = this +suspend fun CharSequence.replace(regex: Regex, replacement: String, timeout: Long): String { + val charSequence = this@replace val isJs = replacement.startsWith("@js:") val replacement1 = if (isJs) replacement.substring(4) else replacement - val pattern = regex.toPattern() - val matcher = pattern.matcher(charSequence) - val stringBuffer = StringBuffer() - while (matcher.find()) { - if (System.currentTimeMillis() - startTime > timeout) { - val timeoutMsg = "替换超时,将禁用替换规则" - throw RegexTimeoutException(timeoutMsg) + return suspendCancellableCoroutine { block -> + val coroutine = Coroutine.async { + try { + val pattern = regex.toPattern() + val matcher = pattern.matcher(charSequence) + val stringBuffer = StringBuffer() + while (matcher.find()) { + if (isJs) { + val bindings = SimpleBindings() + bindings["result"] = matcher.group() + val jsResult = + AppConst.SCRIPT_ENGINE.eval(replacement1, bindings).toString() + matcher.appendReplacement(stringBuffer, jsResult) + } else { + matcher.appendReplacement(stringBuffer, replacement1) + } + } + matcher.appendTail(stringBuffer) + Log.e("regex", "end") + block.resume(stringBuffer.toString()) + } catch (e: Exception) { + block.resumeWithException(e) + } } - if (isJs) { - val bindings = SimpleBindings() - bindings["result"] = matcher.group() - val jsResult = AppConst.SCRIPT_ENGINE.eval(replacement1, bindings).toString() - matcher.appendReplacement(stringBuffer, jsResult) - } else { - matcher.appendReplacement(stringBuffer, replacement1) + handler.postDelayed(timeout) { + if (coroutine.isActive) { + val timeoutMsg = "替换超时,3秒后还未结束将重启应用\n替换规则$regex\n替换内容:${this}" + val exception = RegexTimeoutException(timeoutMsg) + block.cancel(exception) + appCtx.longToastOnUi(timeoutMsg) + CrashHandler.saveCrashInfo2File(exception) + handler.postDelayed(3000) { + if (coroutine.isActive) { + appCtx.restart() + } + } + } } } - matcher.appendTail(stringBuffer) - return stringBuffer.toString() } From 6d4925f443565b22dd9a4a1a323f3a9604a0156f Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 14 Oct 2022 21:05:15 +0800 Subject: [PATCH 02/30] =?UTF-8?q?=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/src/main/assets/updateLog.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/app/src/main/assets/updateLog.md b/app/src/main/assets/updateLog.md index 5c0548e87..3e2e5c2d8 100644 --- a/app/src/main/assets/updateLog.md +++ b/app/src/main/assets/updateLog.md @@ -11,13 +11,14 @@ * 正文出现缺字漏字、内容缺失、排版错乱等情况,有可能是净化规则或简繁转换出现问题。 * 漫画源看书显示乱码,**阅读与其他软件的源并不通用**,请导入阅读的支持的漫画源! -**2022/10/13** +**2022/10/14** * 更新cronet: 106.0.5249.126 * 替换规则支持js,可以用js判断匹配到的内容决定替换为什么,匹配到的内容变量为result,替换为@js:开头则自动采用js判断替换内容 * 书架管理添加筛选功能 * 搜索支持搜索范围多分组和单书源设置 -* 书源管理界面书源菜单添加单书源搜索数据功能 +* 书源管理界面书源菜单添加单书源搜索书籍功能 +* 复web阅读时app未退出阅读界面导致的进度bug by Xwite **2022/10/09** From 9fe35a42f74e8338c7175761f516a764992a1bd0 Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 14 Oct 2022 21:43:10 +0800 Subject: [PATCH 03/30] =?UTF-8?q?=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 30d03a858..9cb481bd8 100644 --- a/gradle.properties +++ b/gradle.properties @@ -6,7 +6,7 @@ # http://www.gradle.org/docs/current/userguide/build_environment.html # Specifies the JVM arguments used for the daemon process. # The setting is particularly useful for tweaking memory settings. -org.gradle.jvmargs=-Xmx2048m +org.gradle.jvmargs=-Xmx3000m # When configured, Gradle will run in incubating parallel mode. # This option should only be used with decoupled projects. More details, visit # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects From 7ff2132bb9cfc04dfa23b426a9cae9bf604c26f6 Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 14 Oct 2022 22:47:55 +0800 Subject: [PATCH 04/30] =?UTF-8?q?=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/io/legado/app/ui/main/rss/RssFragment.kt | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/ui/main/rss/RssFragment.kt b/app/src/main/java/io/legado/app/ui/main/rss/RssFragment.kt index 427632170..4d0f74306 100644 --- a/app/src/main/java/io/legado/app/ui/main/rss/RssFragment.kt +++ b/app/src/main/java/io/legado/app/ui/main/rss/RssFragment.kt @@ -15,6 +15,7 @@ import io.legado.app.data.appDb import io.legado.app.data.entities.RssSource import io.legado.app.databinding.FragmentRssBinding import io.legado.app.databinding.ItemRssBinding +import io.legado.app.lib.dialogs.alert import io.legado.app.lib.theme.primaryColor import io.legado.app.lib.theme.primaryTextColor import io.legado.app.ui.rss.article.RssSortActivity @@ -179,7 +180,13 @@ class RssFragment : VMBaseFragment(R.layout.fragment_rss), } override fun del(rssSource: RssSource) { - viewModel.del(rssSource) + alert(R.string.draw) { + setMessage(getString(R.string.sure_del) + "\n" + rssSource.sourceName) + noButton() + yesButton { + viewModel.del(rssSource) + } + } } override fun disable(rssSource: RssSource) { From 5b0a580fc67f2fa684e845ed2832b144aef6df1f Mon Sep 17 00:00:00 2001 From: kunfei Date: Sat, 15 Oct 2022 11:17:58 +0800 Subject: [PATCH 05/30] =?UTF-8?q?=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../book/import/local/ImportBookActivity.kt | 65 ++++++++++--------- .../io/legado/app/utils/StringExtensions.kt | 4 +- 2 files changed, 36 insertions(+), 33 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/book/import/local/ImportBookActivity.kt b/app/src/main/java/io/legado/app/ui/book/import/local/ImportBookActivity.kt index 2eafcce82..c00ca0ecb 100644 --- a/app/src/main/java/io/legado/app/ui/book/import/local/ImportBookActivity.kt +++ b/app/src/main/java/io/legado/app/ui/book/import/local/ImportBookActivity.kt @@ -46,22 +46,19 @@ class ImportBookActivity : BaseImportBookActivity - if (uri.isContentScheme()) { - AppConfig.importBookPath = uri.toString() - initRootDoc(true) - } else { - AppConfig.importBookPath = uri.path - initRootDoc(true) - } + AppConfig.importBookPath = uri.toString() + initRootDoc(true) } } override fun onActivityCreated(savedInstanceState: Bundle?) { binding.titleBar.setTitle(R.string.book_local) launch { - setBookStorage() initView() initEvent() + if (setBookStorage() && AppConfig.importBookPath.isNullOrBlank()) { + AppConfig.importBookPath = AppConfig.defaultBookTreeUri + } initData() } } @@ -150,35 +147,43 @@ class ImportBookActivity : BaseImportBookActivity upPath() - lastPath.isNullOrEmpty() -> { + if (viewModel.rootDoc != null && !changedFolder) { + upPath() + } else { + val lastPath = AppConfig.importBookPath + if (lastPath.isNullOrBlank()) { binding.tvEmptyMsg.visible() selectFolder.launch() - } - lastPath.isContentScheme() -> { - val rootUri = Uri.parse(lastPath) - kotlin.runCatching { - val doc = DocumentFile.fromTreeUri(this, rootUri) - if (doc == null || doc.name.isNullOrEmpty()) { + } else { + val rootUri = if (lastPath.isUri()) { + Uri.parse(lastPath) + } else { + Uri.fromFile(File(lastPath)) + } + when { + rootUri.isContentScheme() -> { + kotlin.runCatching { + val doc = DocumentFile.fromTreeUri(this, rootUri) + if (doc == null || doc.name.isNullOrEmpty()) { + binding.tvEmptyMsg.visible() + selectFolder.launch() + } else { + viewModel.subDocs.clear() + viewModel.rootDoc = FileDoc.fromDocumentFile(doc) + upDocs(viewModel.rootDoc!!) + } + }.onFailure { + binding.tvEmptyMsg.visible() + selectFolder.launch() + } + } + Build.VERSION.SDK_INT > Build.VERSION_CODES.Q -> { binding.tvEmptyMsg.visible() selectFolder.launch() - } else { - viewModel.subDocs.clear() - viewModel.rootDoc = FileDoc.fromDocumentFile(doc) - upDocs(viewModel.rootDoc!!) } - }.onFailure { - binding.tvEmptyMsg.visible() - selectFolder.launch() + else -> initRootPath(rootUri.path!!) } } - Build.VERSION.SDK_INT > Build.VERSION_CODES.Q -> { - binding.tvEmptyMsg.visible() - selectFolder.launch() - } - else -> initRootPath(lastPath) } } diff --git a/app/src/main/java/io/legado/app/utils/StringExtensions.kt b/app/src/main/java/io/legado/app/utils/StringExtensions.kt index 1228907b5..f4f941047 100644 --- a/app/src/main/java/io/legado/app/utils/StringExtensions.kt +++ b/app/src/main/java/io/legado/app/utils/StringExtensions.kt @@ -17,9 +17,7 @@ fun String?.isContentScheme(): Boolean = this?.startsWith("content://") == true fun String.toEditable(): Editable = Editable.Factory.getInstance().newEditable(this) fun String.parseToUri(): Uri { - return if (isContentScheme()) { - Uri.parse(this) - } else { + return if (isUri()) Uri.parse(this) else { Uri.fromFile(File(this)) } } From 4b1f3863342e53efce2e3851c4f1927c8d56069c Mon Sep 17 00:00:00 2001 From: kunfei Date: Sat, 15 Oct 2022 11:28:19 +0800 Subject: [PATCH 06/30] =?UTF-8?q?=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/io/legado/app/ui/book/search/SearchActivity.kt | 8 ++++++++ 1 file changed, 8 insertions(+) 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 210b27160..948aac28b 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 @@ -400,6 +400,14 @@ class SearchActivity : VMBaseActivity Date: Sat, 15 Oct 2022 13:40:58 +0800 Subject: [PATCH 07/30] =?UTF-8?q?=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/src/main/assets/defaultData/directLinkUpload.json | 2 +- app/src/main/java/io/legado/app/lib/webdav/WebDav.kt | 4 ++-- app/src/main/java/io/legado/app/ui/book/search/SearchScope.kt | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/app/src/main/assets/defaultData/directLinkUpload.json b/app/src/main/assets/defaultData/directLinkUpload.json index 57dd4b0b6..b74237185 100644 --- a/app/src/main/assets/defaultData/directLinkUpload.json +++ b/app/src/main/assets/defaultData/directLinkUpload.json @@ -1,5 +1,5 @@ { - "uploadUrl": "http://sy.mgz6.cc/shuyuan,{\"method\":\"POST\",\"body\": {\"file\": \"fileRequest\"},\"type\": \"multipart/form-data\"}", + "uploadUrl": "https://sy.mgz6.cc/shuyuan,{\"method\":\"POST\",\"body\": {\"file\": \"fileRequest\"},\"type\": \"multipart/form-data\"}", "downloadUrlRule": "$.data@js:if (result == '') \n '' \n else \n 'https://shuyuan.mgz6.cc/shuyuan/' + result", "summary": "有效期2天" } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/lib/webdav/WebDav.kt b/app/src/main/java/io/legado/app/lib/webdav/WebDav.kt index d028d4953..8ceeafe93 100644 --- a/app/src/main/java/io/legado/app/lib/webdav/WebDav.kt +++ b/app/src/main/java/io/legado/app/lib/webdav/WebDav.kt @@ -358,9 +358,9 @@ open class WebDav(val path: String, val authorization: Authorization) { val exception = document.getElementsByTag("s:exception").firstOrNull()?.text() val message = document.getElementsByTag("s:message").firstOrNull()?.text() if (exception == "ObjectNotFound") { - throw ObjectNotFoundException(message ?: "$path doesn't exist") + throw ObjectNotFoundException(message ?: "$path doesn't exist. code:${response.code}") } - throw WebDavException(message ?: "未知错误") + throw WebDavException(message ?: "未知错误 code:${response.code}") } } diff --git a/app/src/main/java/io/legado/app/ui/book/search/SearchScope.kt b/app/src/main/java/io/legado/app/ui/book/search/SearchScope.kt index 3c2994efa..331161f09 100644 --- a/app/src/main/java/io/legado/app/ui/book/search/SearchScope.kt +++ b/app/src/main/java/io/legado/app/ui/book/search/SearchScope.kt @@ -54,9 +54,9 @@ data class SearchScope(private var scope: String) { } if (list.isEmpty()) { list.add("全部书源") + } + return list } - return list - } /** * 搜索范围书源 From c7e01ee3739f20bf8fa045a68b63e79959433533 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sat, 15 Oct 2022 13:52:43 +0800 Subject: [PATCH 08/30] =?UTF-8?q?=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/src/main/AndroidManifest.xml | 1 + .../main/java/io/legado/app/service/AudioPlayService.kt | 8 ++++++++ .../java/io/legado/app/service/BaseReadAloudService.kt | 8 ++++++++ app/src/main/java/io/legado/app/service/WebService.kt | 9 +++++++++ 4 files changed, 26 insertions(+) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 825360885..5a4dde7bd 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -4,6 +4,7 @@ package="io.legado.app"> + 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 8949774e9..a5354cabf 100644 --- a/app/src/main/java/io/legado/app/service/AudioPlayService.kt +++ b/app/src/main/java/io/legado/app/service/AudioPlayService.kt @@ -9,6 +9,7 @@ import android.graphics.BitmapFactory import android.media.AudioManager import android.net.Uri import android.os.Build +import android.os.PowerManager import android.support.v4.media.session.MediaSessionCompat import android.support.v4.media.session.PlaybackStateCompat import androidx.core.app.NotificationCompat @@ -36,6 +37,7 @@ import io.legado.app.utils.* import kotlinx.coroutines.* import kotlinx.coroutines.Dispatchers.Main import splitties.systemservices.audioManager +import splitties.systemservices.powerManager /** * 音频播放服务 @@ -61,6 +63,9 @@ class AudioPlayService : BaseService(), private set } + private val wakeLock by lazy { + powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "legado:webService") + } private val mFocusRequest: AudioFocusRequestCompat by lazy { MediaHelp.buildAudioFocusRequestCompat(this) } @@ -82,8 +87,10 @@ class AudioPlayService : BaseService(), private var upPlayProgressJob: Job? = null private var playSpeed: Float = 1f + @SuppressLint("WakelockTimeout") override fun onCreate() { super.onCreate() + wakeLock.acquire() isRun = true upNotification() exoPlayer.addListener(this) @@ -120,6 +127,7 @@ class AudioPlayService : BaseService(), override fun onDestroy() { super.onDestroy() + wakeLock.release() isRun = false abandonFocus() exoPlayer.release() 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 2a185fa1d..7547ad987 100644 --- a/app/src/main/java/io/legado/app/service/BaseReadAloudService.kt +++ b/app/src/main/java/io/legado/app/service/BaseReadAloudService.kt @@ -8,6 +8,7 @@ import android.content.Intent import android.content.IntentFilter import android.graphics.BitmapFactory import android.media.AudioManager +import android.os.PowerManager import android.support.v4.media.session.MediaSessionCompat import android.support.v4.media.session.PlaybackStateCompat import androidx.annotation.CallSuper @@ -30,6 +31,7 @@ import kotlinx.coroutines.delay import kotlinx.coroutines.isActive import kotlinx.coroutines.launch import splitties.systemservices.audioManager +import splitties.systemservices.powerManager /** * 朗读服务 @@ -55,6 +57,9 @@ abstract class BaseReadAloudService : BaseService(), } } + private val wakeLock by lazy { + powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "legado:readAloud") + } private val mFocusRequest: AudioFocusRequestCompat by lazy { MediaHelp.buildAudioFocusRequestCompat(this) } @@ -77,8 +82,10 @@ abstract class BaseReadAloudService : BaseService(), } } + @SuppressLint("WakelockTimeout") override fun onCreate() { super.onCreate() + wakeLock.acquire() isRun = true pause = false initMediaSession() @@ -90,6 +97,7 @@ abstract class BaseReadAloudService : BaseService(), override fun onDestroy() { super.onDestroy() + wakeLock.release() isRun = false pause = true abandonFocus() diff --git a/app/src/main/java/io/legado/app/service/WebService.kt b/app/src/main/java/io/legado/app/service/WebService.kt index c18c95f82..1f408e143 100644 --- a/app/src/main/java/io/legado/app/service/WebService.kt +++ b/app/src/main/java/io/legado/app/service/WebService.kt @@ -1,8 +1,10 @@ package io.legado.app.service +import android.annotation.SuppressLint import android.content.Context import android.content.Intent import android.os.Build +import android.os.PowerManager import androidx.core.app.NotificationCompat import io.legado.app.R import io.legado.app.base.BaseService @@ -14,6 +16,7 @@ import io.legado.app.receiver.NetworkChangedListener import io.legado.app.utils.* import io.legado.app.web.HttpServer import io.legado.app.web.WebSocketServer +import splitties.systemservices.powerManager import java.io.IOException @@ -33,6 +36,9 @@ class WebService : BaseService() { } + private val wakeLock by lazy { + powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "legado:webService") + } private var httpServer: HttpServer? = null private var webSocketServer: WebSocketServer? = null private var notificationContent = "" @@ -40,8 +46,10 @@ class WebService : BaseService() { NetworkChangedListener(this) } + @SuppressLint("WakelockTimeout") override fun onCreate() { super.onCreate() + wakeLock.acquire() isRun = true notificationContent = getString(R.string.service_starting) upNotification() @@ -73,6 +81,7 @@ class WebService : BaseService() { override fun onDestroy() { super.onDestroy() + wakeLock.release() networkChangedListener.unRegister() isRun = false if (httpServer?.isAlive == true) { From 7c29f4cdaf68d673dc102332f0dd89e80bbbcf02 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sat, 15 Oct 2022 20:29:40 +0800 Subject: [PATCH 09/30] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E6=9B=B4=E6=96=B0?= =?UTF-8?q?=E5=A4=B1=E8=B4=A5=E5=88=86=E7=BB=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/io/legado/app/constant/AppConst.kt | 1 + .../java/io/legado/app/constant/BookType.kt | 13 +++---- .../java/io/legado/app/data/AppDatabase.kt | 7 +++- .../java/io/legado/app/data/dao/BookDao.kt | 3 ++ .../io/legado/app/data/dao/BookGroupDao.kt | 1 + .../io/legado/app/help/book/BookExtensions.kt | 39 +++++++++++++++---- .../ui/book/manage/BookshelfManageActivity.kt | 1 + .../searchContent/SearchContentActivity.kt | 2 +- .../io/legado/app/ui/main/MainViewModel.kt | 6 +++ .../bookshelf/style1/books/BooksFragment.kt | 1 + 10 files changed, 56 insertions(+), 18 deletions(-) diff --git a/app/src/main/java/io/legado/app/constant/AppConst.kt b/app/src/main/java/io/legado/app/constant/AppConst.kt index 8a6339bdf..be8cd07e5 100644 --- a/app/src/main/java/io/legado/app/constant/AppConst.kt +++ b/app/src/main/java/io/legado/app/constant/AppConst.kt @@ -43,6 +43,7 @@ object AppConst { const val bookGroupAudioId = -3L const val bookGroupNetNoneId = -4L const val bookGroupLocalNoneId = -5L + const val bookGroupErrorId = -11L const val notificationIdRead = -1122391 const val notificationIdAudio = -1122392 diff --git a/app/src/main/java/io/legado/app/constant/BookType.kt b/app/src/main/java/io/legado/app/constant/BookType.kt index 15515981c..9b998d0e8 100644 --- a/app/src/main/java/io/legado/app/constant/BookType.kt +++ b/app/src/main/java/io/legado/app/constant/BookType.kt @@ -1,7 +1,5 @@ package io.legado.app.constant -import androidx.annotation.IntDef - /** * 以二进制位来区分,可能一本书籍包含多个类型,每一位代表一个类型,数值为2的n次方 * 以二进制位来区分,数据库查询更高效, 数值>=8和老版本类型区分开 @@ -12,6 +10,11 @@ object BookType { */ const val text = 0b1000 + /** + * 16 更新失败 + */ + const val updateError = 0b10000 + /** * 32 音频 */ @@ -32,12 +35,6 @@ object BookType { */ const val local = 0b100000000 - - @Target(AnnotationTarget.VALUE_PARAMETER) - @Retention(AnnotationRetention.SOURCE) - @IntDef(text, audio, image, webFile) - annotation class Type - /** * 本地书籍书源标志 */ diff --git a/app/src/main/java/io/legado/app/data/AppDatabase.kt b/app/src/main/java/io/legado/app/data/AppDatabase.kt index 01351d2eb..b826093b6 100644 --- a/app/src/main/java/io/legado/app/data/AppDatabase.kt +++ b/app/src/main/java/io/legado/app/data/AppDatabase.kt @@ -105,9 +105,14 @@ abstract class AppDatabase : RoomDatabase() { ) db.execSQL( """insert into book_groups(groupId, groupName, 'order', show) - select ${AppConst.bookGroupLocalNoneId}, '本地未分组', -8, 0 + select ${AppConst.bookGroupLocalNoneId}, '本地未分组', -6, 0 where not exists (select * from book_groups where groupId = ${AppConst.bookGroupLocalNoneId})""" ) + db.execSQL( + """insert into book_groups(groupId, groupName, 'order', show) + select ${AppConst.bookGroupErrorId}, '更新失败', -1, 1 + where not exists (select * from book_groups where groupId = ${AppConst.bookGroupErrorId})""" + ) db.execSQL("update book_sources set loginUi = null where loginUi = 'null'") db.execSQL("update rssSources set loginUi = null where loginUi = 'null'") db.execSQL("update httpTTS set loginUi = null where loginUi = 'null'") diff --git a/app/src/main/java/io/legado/app/data/dao/BookDao.kt b/app/src/main/java/io/legado/app/data/dao/BookDao.kt index 4dd905c33..082bfba0a 100644 --- a/app/src/main/java/io/legado/app/data/dao/BookDao.kt +++ b/app/src/main/java/io/legado/app/data/dao/BookDao.kt @@ -53,6 +53,9 @@ interface BookDao { @Query("SELECT * FROM books WHERE name like '%'||:key||'%' or author like '%'||:key||'%'") fun flowSearch(key: String): Flow> + @Query("SELECT * FROM books where type & ${BookType.updateError} > 0 order by durChapterTime desc") + fun flowUpdateError(): Flow> + @Query("SELECT * FROM books WHERE (`group` & :group) > 0") fun getBooksByGroup(group: Long): List diff --git a/app/src/main/java/io/legado/app/data/dao/BookGroupDao.kt b/app/src/main/java/io/legado/app/data/dao/BookGroupDao.kt index af3982275..5e1fe7684 100644 --- a/app/src/main/java/io/legado/app/data/dao/BookGroupDao.kt +++ b/app/src/main/java/io/legado/app/data/dao/BookGroupDao.kt @@ -25,6 +25,7 @@ interface BookGroupDao { or (groupId = -1 and show > 0) or (groupId = -2 and show > 0 and (select count(*) from books where type & ${BookType.local} > 0) > 0) or (groupId = -3 and show > 0 and (select count(*) from books where type & ${BookType.audio} > 0) > 0) + or (groupId = -11 and show > 0 and (select count(*) from books where type & ${BookType.updateError} > 0) > 0) or (groupId = -4 and show > 0 and ( select count(*) from books diff --git a/app/src/main/java/io/legado/app/help/book/BookExtensions.kt b/app/src/main/java/io/legado/app/help/book/BookExtensions.kt index 15b6c7912..179d09b35 100644 --- a/app/src/main/java/io/legado/app/help/book/BookExtensions.kt +++ b/app/src/main/java/io/legado/app/help/book/BookExtensions.kt @@ -1,3 +1,5 @@ +@file:Suppress("unused") + package io.legado.app.help.book import android.net.Uri @@ -6,12 +8,12 @@ import io.legado.app.constant.BookSourceType import io.legado.app.constant.BookType import io.legado.app.data.entities.Book import io.legado.app.data.entities.BookSource -import io.legado.app.help.config.AppConfig.defaultBookTreeUri import io.legado.app.exception.NoStackTraceException -import io.legado.app.utils.isContentScheme +import io.legado.app.help.config.AppConfig.defaultBookTreeUri import io.legado.app.utils.getFile -import java.io.File +import io.legado.app.utils.isContentScheme import splitties.init.appCtx +import java.io.File val Book.isAudio: Boolean @@ -54,11 +56,11 @@ val Book.isOnLineTxt: Boolean fun Book.getLocalUri(): Uri { if (isLocal) { - val originBookUri = if (bookUrl.isContentScheme()) { - Uri.parse(bookUrl) - } else { - Uri.fromFile(File(bookUrl)) - } + val originBookUri = if (bookUrl.isContentScheme()) { + Uri.parse(bookUrl) + } else { + Uri.fromFile(File(bookUrl)) + } //不同的设备书籍保存路径可能不一样 优先尝试寻找当前保存路径下的文件 defaultBookTreeUri ?: return originBookUri val treeUri = Uri.parse(defaultBookTreeUri) @@ -84,6 +86,27 @@ fun Book.getRemoteUrl(): String? { return null } +fun Book.setType(vararg types: Int) { + type = 0 + addType(*types) +} + +fun Book.addType(vararg types: Int) { + types.forEach { + type = type or it + } +} + +fun Book.removeType(vararg types: Int) { + types.forEach { + type = type and it.inv() + } +} + +fun Book.clearType() { + type = 0 +} + fun Book.upType() { if (type < 8) { type = when (type) { diff --git a/app/src/main/java/io/legado/app/ui/book/manage/BookshelfManageActivity.kt b/app/src/main/java/io/legado/app/ui/book/manage/BookshelfManageActivity.kt index b7b4d6302..62ee98767 100644 --- a/app/src/main/java/io/legado/app/ui/book/manage/BookshelfManageActivity.kt +++ b/app/src/main/java/io/legado/app/ui/book/manage/BookshelfManageActivity.kt @@ -184,6 +184,7 @@ class BookshelfManageActivity : AppConst.bookGroupAudioId -> appDb.bookDao.flowAudio() AppConst.bookGroupNetNoneId -> appDb.bookDao.flowNetNoGroup() AppConst.bookGroupLocalNoneId -> appDb.bookDao.flowLocalNoGroup() + AppConst.bookGroupErrorId -> appDb.bookDao.flowUpdateError() else -> appDb.bookDao.flowByGroup(viewModel.groupId) }.conflate().map { list -> val books = if (searchKey.isNullOrBlank()) { diff --git a/app/src/main/java/io/legado/app/ui/book/searchContent/SearchContentActivity.kt b/app/src/main/java/io/legado/app/ui/book/searchContent/SearchContentActivity.kt index 4b65b2695..477f273ac 100644 --- a/app/src/main/java/io/legado/app/ui/book/searchContent/SearchContentActivity.kt +++ b/app/src/main/java/io/legado/app/ui/book/searchContent/SearchContentActivity.kt @@ -193,7 +193,7 @@ class SearchContentActivity : } } - val isLocalBook: Boolean + private val isLocalBook: Boolean get() = viewModel.book?.isLocal == true override fun openSearchResult(searchResult: SearchResult, index: Int) { diff --git a/app/src/main/java/io/legado/app/ui/main/MainViewModel.kt b/app/src/main/java/io/legado/app/ui/main/MainViewModel.kt index b6629fa99..d09ef387d 100644 --- a/app/src/main/java/io/legado/app/ui/main/MainViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/main/MainViewModel.kt @@ -5,6 +5,7 @@ import androidx.lifecycle.viewModelScope import io.legado.app.base.BaseViewModel import io.legado.app.constant.AppConst import io.legado.app.constant.AppLog +import io.legado.app.constant.BookType import io.legado.app.constant.EventBus import io.legado.app.data.appDb import io.legado.app.data.entities.Book @@ -12,7 +13,9 @@ import io.legado.app.data.entities.BookSource import io.legado.app.help.AppWebDav import io.legado.app.help.DefaultData import io.legado.app.help.book.BookHelp +import io.legado.app.help.book.addType import io.legado.app.help.book.isLocal +import io.legado.app.help.book.removeType import io.legado.app.help.config.AppConfig import io.legado.app.help.config.LocalConfig import io.legado.app.model.CacheBook @@ -126,6 +129,7 @@ class MainViewModel(application: Application) : BaseViewModel(application) { WebBook.getBookInfoAwait(source, book) } val toc = WebBook.getChapterListAwait(source, book).getOrThrow() + book.removeType(BookType.updateError) if (book.bookUrl == bookUrl) { appDb.bookDao.update(book) } else { @@ -137,6 +141,8 @@ class MainViewModel(application: Application) : BaseViewModel(application) { appDb.bookChapterDao.insert(*toc.toTypedArray()) addDownload(source, book) }.onError(upTocPool) { + book.addType(BookType.updateError) + appDb.bookDao.update(book) AppLog.put("${book.name} 更新目录失败\n${it.localizedMessage}", it) }.onCancel(upTocPool) { upTocCancel(bookUrl) diff --git a/app/src/main/java/io/legado/app/ui/main/bookshelf/style1/books/BooksFragment.kt b/app/src/main/java/io/legado/app/ui/main/bookshelf/style1/books/BooksFragment.kt index 91fa9318a..a2a434497 100644 --- a/app/src/main/java/io/legado/app/ui/main/bookshelf/style1/books/BooksFragment.kt +++ b/app/src/main/java/io/legado/app/ui/main/bookshelf/style1/books/BooksFragment.kt @@ -118,6 +118,7 @@ class BooksFragment() : BaseFragment(R.layout.fragment_books), AppConst.bookGroupAudioId -> appDb.bookDao.flowAudio() AppConst.bookGroupNetNoneId -> appDb.bookDao.flowNetNoGroup() AppConst.bookGroupLocalNoneId -> appDb.bookDao.flowLocalNoGroup() + AppConst.bookGroupErrorId -> appDb.bookDao.flowUpdateError() else -> appDb.bookDao.flowByGroup(groupId) }.conflate().map { list -> when (getPrefInt(PreferKey.bookshelfSort)) { From 9311d7aeb9c3a28f0b91d83b64c244148b09e2fa Mon Sep 17 00:00:00 2001 From: kunfei Date: Sat, 15 Oct 2022 20:35:13 +0800 Subject: [PATCH 10/30] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E6=9B=B4=E6=96=B0?= =?UTF-8?q?=E5=A4=B1=E8=B4=A5=E5=88=86=E7=BB=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/io/legado/app/ui/book/info/BookInfoViewModel.kt | 2 ++ .../io/legado/app/ui/book/manage/BookshelfManageViewModel.kt | 3 +++ .../main/java/io/legado/app/ui/book/read/ReadBookViewModel.kt | 3 +++ 3 files changed, 8 insertions(+) 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 7b67229be..cf051edff 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 @@ -18,6 +18,7 @@ import io.legado.app.exception.NoStackTraceException import io.legado.app.help.book.BookHelp import io.legado.app.help.book.getRemoteUrl import io.legado.app.help.book.isLocal +import io.legado.app.help.book.removeType import io.legado.app.help.coroutine.Coroutine import io.legado.app.lib.webdav.ObjectNotFoundException import io.legado.app.model.BookCover @@ -236,6 +237,7 @@ class BookInfoViewModel(application: Application) : BaseViewModel(application) { bookSource = source bookData.value?.changeTo(book, toc) if (inBookshelf) { + book.removeType(BookType.updateError) appDb.bookDao.insert(book) appDb.bookChapterDao.insert(*toc.toTypedArray()) } diff --git a/app/src/main/java/io/legado/app/ui/book/manage/BookshelfManageViewModel.kt b/app/src/main/java/io/legado/app/ui/book/manage/BookshelfManageViewModel.kt index 341d612b0..a28561cad 100644 --- a/app/src/main/java/io/legado/app/ui/book/manage/BookshelfManageViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/book/manage/BookshelfManageViewModel.kt @@ -3,10 +3,12 @@ package io.legado.app.ui.book.manage import android.app.Application import androidx.compose.runtime.mutableStateOf import io.legado.app.base.BaseViewModel +import io.legado.app.constant.BookType import io.legado.app.data.appDb import io.legado.app.data.entities.Book import io.legado.app.data.entities.BookSource import io.legado.app.help.book.isLocal +import io.legado.app.help.book.removeType import io.legado.app.help.coroutine.Coroutine import io.legado.app.model.webBook.WebBook import io.legado.app.utils.toastOnUi @@ -58,6 +60,7 @@ class BookshelfManageViewModel(application: Application) : BaseViewModel(applica context.toastOnUi("获取目录出错\n${it.localizedMessage}") }.getOrNull()?.let { toc -> book.changeTo(newBook, toc) + book.removeType(BookType.updateError) appDb.bookDao.insert(newBook) appDb.bookChapterDao.insert(*toc.toTypedArray()) } 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 5b6444171..2743662d7 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 @@ -9,6 +9,7 @@ import androidx.lifecycle.viewModelScope import io.legado.app.R import io.legado.app.base.BaseViewModel import io.legado.app.constant.AppLog +import io.legado.app.constant.BookType import io.legado.app.constant.EventBus import io.legado.app.data.appDb import io.legado.app.data.entities.Book @@ -19,6 +20,7 @@ import io.legado.app.help.AppWebDav import io.legado.app.help.book.BookHelp import io.legado.app.help.book.ContentProcessor import io.legado.app.help.book.isLocal +import io.legado.app.help.book.removeType import io.legado.app.help.config.AppConfig import io.legado.app.help.coroutine.Coroutine import io.legado.app.model.ReadAloud @@ -215,6 +217,7 @@ class ReadBookViewModel(application: Application) : BaseViewModel(application) { changeSourceCoroutine = execute { ReadBook.upMsg(context.getString(R.string.loading)) ReadBook.book?.changeTo(book, toc) + book.removeType(BookType.updateError) appDb.bookDao.insert(book) appDb.bookChapterDao.insert(*toc.toTypedArray()) ReadBook.resetData(book) From 0ec80cddc3ace5d49df8ffa442158d3013691ae9 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sat, 15 Oct 2022 21:57:00 +0800 Subject: [PATCH 11/30] =?UTF-8?q?=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/src/main/java/io/legado/app/constant/BookType.kt | 9 +++++++++ .../main/java/io/legado/app/help/book/BookExtensions.kt | 6 +++--- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/io/legado/app/constant/BookType.kt b/app/src/main/java/io/legado/app/constant/BookType.kt index 9b998d0e8..9eb8bbbb1 100644 --- a/app/src/main/java/io/legado/app/constant/BookType.kt +++ b/app/src/main/java/io/legado/app/constant/BookType.kt @@ -1,5 +1,7 @@ package io.legado.app.constant +import androidx.annotation.IntDef + /** * 以二进制位来区分,可能一本书籍包含多个类型,每一位代表一个类型,数值为2的n次方 * 以二进制位来区分,数据库查询更高效, 数值>=8和老版本类型区分开 @@ -35,6 +37,13 @@ object BookType { */ const val local = 0b100000000 + + @Target(AnnotationTarget.VALUE_PARAMETER) + @Retention(AnnotationRetention.SOURCE) + @IntDef(text, updateError, audio, image, webFile, local) + annotation class Type + + /** * 本地书籍书源标志 */ diff --git a/app/src/main/java/io/legado/app/help/book/BookExtensions.kt b/app/src/main/java/io/legado/app/help/book/BookExtensions.kt index 179d09b35..42dc8f21b 100644 --- a/app/src/main/java/io/legado/app/help/book/BookExtensions.kt +++ b/app/src/main/java/io/legado/app/help/book/BookExtensions.kt @@ -86,18 +86,18 @@ fun Book.getRemoteUrl(): String? { return null } -fun Book.setType(vararg types: Int) { +fun Book.setType(@BookType.Type vararg types: Int) { type = 0 addType(*types) } -fun Book.addType(vararg types: Int) { +fun Book.addType(@BookType.Type vararg types: Int) { types.forEach { type = type or it } } -fun Book.removeType(vararg types: Int) { +fun Book.removeType(@BookType.Type vararg types: Int) { types.forEach { type = type and it.inv() } From 8b62aadd7904dca1a086c3f5e0588f391869ff69 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sat, 15 Oct 2022 21:58:15 +0800 Subject: [PATCH 12/30] =?UTF-8?q?=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/src/main/assets/updateLog.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/app/src/main/assets/updateLog.md b/app/src/main/assets/updateLog.md index 3e2e5c2d8..3998545d0 100644 --- a/app/src/main/assets/updateLog.md +++ b/app/src/main/assets/updateLog.md @@ -11,6 +11,10 @@ * 正文出现缺字漏字、内容缺失、排版错乱等情况,有可能是净化规则或简繁转换出现问题。 * 漫画源看书显示乱码,**阅读与其他软件的源并不通用**,请导入阅读的支持的漫画源! +**2022/10/15** + +* 添加更新失败分组 + **2022/10/14** * 更新cronet: 106.0.5249.126 From 0261da0abbc8f6dc57e20471065d7ff2fdf3b6fd Mon Sep 17 00:00:00 2001 From: kunfei Date: Sat, 15 Oct 2022 22:02:40 +0800 Subject: [PATCH 13/30] =?UTF-8?q?=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/src/main/java/io/legado/app/ui/book/search/SearchScope.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/ui/book/search/SearchScope.kt b/app/src/main/java/io/legado/app/ui/book/search/SearchScope.kt index 331161f09..fa2d100c3 100644 --- a/app/src/main/java/io/legado/app/ui/book/search/SearchScope.kt +++ b/app/src/main/java/io/legado/app/ui/book/search/SearchScope.kt @@ -71,7 +71,7 @@ data class SearchScope(private var scope: String) { } } else { scope.splitNotBlank(",").forEach { - list.addAll(appDb.bookSourceDao.getByGroup(it)) + list.addAll(appDb.bookSourceDao.getEnabledByGroup(it)) } } if (list.isEmpty()) { From 5014d48157c29b853f8fae7be4501ba600b45b21 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sat, 15 Oct 2022 22:16:53 +0800 Subject: [PATCH 14/30] =?UTF-8?q?=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/src/main/assets/updateLog.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/src/main/assets/updateLog.md b/app/src/main/assets/updateLog.md index 3998545d0..4a7aeae06 100644 --- a/app/src/main/assets/updateLog.md +++ b/app/src/main/assets/updateLog.md @@ -14,6 +14,8 @@ **2022/10/15** * 添加更新失败分组 +* web服务和朗读服务添加唤醒锁 +* 修复搜索禁用书源的bug **2022/10/14** From 8e9afa326f293f9304ebd88a7890070cb410f178 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sat, 15 Oct 2022 22:38:20 +0800 Subject: [PATCH 15/30] =?UTF-8?q?=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/io/legado/app/ui/book/search/SearchScopeDialog.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/ui/book/search/SearchScopeDialog.kt b/app/src/main/java/io/legado/app/ui/book/search/SearchScopeDialog.kt index 7824d8579..6277712d8 100644 --- a/app/src/main/java/io/legado/app/ui/book/search/SearchScopeDialog.kt +++ b/app/src/main/java/io/legado/app/ui/book/search/SearchScopeDialog.kt @@ -72,7 +72,7 @@ class SearchScopeDialog : BaseDialogFragment(R.layout.dialog_search_scope) { } private fun initOtherView() { - binding.rgScope.setOnCheckedChangeListener { group, checkedId -> + binding.rgScope.setOnCheckedChangeListener { _, checkedId -> binding.toolBar.menu.findItem(R.id.menu_screen)?.isVisible = checkedId == R.id.rb_source upData() } From ccbf61050998ef58d2dac3190d1686f89b9f87ee Mon Sep 17 00:00:00 2001 From: kunfei Date: Sat, 15 Oct 2022 22:50:51 +0800 Subject: [PATCH 16/30] =?UTF-8?q?=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/io/legado/app/help/source/BookSourceExtensions.kt | 7 +++++++ .../java/io/legado/app/ui/book/search/SearchScopeDialog.kt | 3 ++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/help/source/BookSourceExtensions.kt b/app/src/main/java/io/legado/app/help/source/BookSourceExtensions.kt index 30e32e364..bbe913021 100644 --- a/app/src/main/java/io/legado/app/help/source/BookSourceExtensions.kt +++ b/app/src/main/java/io/legado/app/help/source/BookSourceExtensions.kt @@ -75,4 +75,11 @@ suspend fun BookSource.clearExploreKindsCache() { aCache.remove(exploreKindsKey) exploreKindsMap.remove(getExploreKindsKey()) } +} + +fun BookSource.contains(word: String): Boolean { + return bookSourceName.contains(word) + || bookSourceUrl.contains(word) + || bookSourceGroup?.contains(word) == true + || bookSourceComment?.contains(word) == true } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/book/search/SearchScopeDialog.kt b/app/src/main/java/io/legado/app/ui/book/search/SearchScopeDialog.kt index 6277712d8..78fe0ca74 100644 --- a/app/src/main/java/io/legado/app/ui/book/search/SearchScopeDialog.kt +++ b/app/src/main/java/io/legado/app/ui/book/search/SearchScopeDialog.kt @@ -14,6 +14,7 @@ import io.legado.app.data.entities.BookSource import io.legado.app.databinding.DialogSearchScopeBinding import io.legado.app.databinding.ItemCheckBoxBinding import io.legado.app.databinding.ItemRadioButtonBinding +import io.legado.app.help.source.contains import io.legado.app.lib.theme.primaryColor import io.legado.app.utils.applyTint import io.legado.app.utils.setLayout @@ -117,7 +118,7 @@ class SearchScopeDialog : BaseDialogFragment(R.layout.dialog_search_scope) { if (binding.rbSource.isChecked) { sources.filter { source -> screenText?.let { screenText -> - source.bookSourceName.contains(screenText) + source.contains(screenText) } ?: true }.let { screenSources.clear() From e947ccab31b4fded317dd0d3520b657126e041eb Mon Sep 17 00:00:00 2001 From: kunfei Date: Sat, 15 Oct 2022 22:54:40 +0800 Subject: [PATCH 17/30] =?UTF-8?q?=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/io/legado/app/help/source/BookSourceExtensions.kt | 5 ++++- .../java/io/legado/app/ui/book/search/SearchScopeDialog.kt | 4 +--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/io/legado/app/help/source/BookSourceExtensions.kt b/app/src/main/java/io/legado/app/help/source/BookSourceExtensions.kt index bbe913021..946d6d42a 100644 --- a/app/src/main/java/io/legado/app/help/source/BookSourceExtensions.kt +++ b/app/src/main/java/io/legado/app/help/source/BookSourceExtensions.kt @@ -77,7 +77,10 @@ suspend fun BookSource.clearExploreKindsCache() { } } -fun BookSource.contains(word: String): Boolean { +fun BookSource.contains(word: String?): Boolean { + if (word.isNullOrEmpty()) { + return true + } return bookSourceName.contains(word) || bookSourceUrl.contains(word) || bookSourceGroup?.contains(word) == true diff --git a/app/src/main/java/io/legado/app/ui/book/search/SearchScopeDialog.kt b/app/src/main/java/io/legado/app/ui/book/search/SearchScopeDialog.kt index 78fe0ca74..8d7ff9fab 100644 --- a/app/src/main/java/io/legado/app/ui/book/search/SearchScopeDialog.kt +++ b/app/src/main/java/io/legado/app/ui/book/search/SearchScopeDialog.kt @@ -117,9 +117,7 @@ class SearchScopeDialog : BaseDialogFragment(R.layout.dialog_search_scope) { withContext(IO) { if (binding.rbSource.isChecked) { sources.filter { source -> - screenText?.let { screenText -> - source.contains(screenText) - } ?: true + source.contains(screenText) }.let { screenSources.clear() screenSources.addAll(it) From 1013f33cf641d83c4ce69bbbf2137e56d6b08368 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 16 Oct 2022 00:58:01 +0800 Subject: [PATCH 18/30] =?UTF-8?q?=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/io/legado/app/help/JsExtensions.kt | 2 +- .../legado/app/help/storage/ImportOldData.kt | 6 +- .../io/legado/app/utils/DocumentExtensions.kt | 68 ++++++------------- .../java/io/legado/app/utils/UriExtensions.kt | 20 ++++-- 4 files changed, 39 insertions(+), 57 deletions(-) diff --git a/app/src/main/java/io/legado/app/help/JsExtensions.kt b/app/src/main/java/io/legado/app/help/JsExtensions.kt index 7990165aa..40423239a 100644 --- a/app/src/main/java/io/legado/app/help/JsExtensions.kt +++ b/app/src/main/java/io/legado/app/help/JsExtensions.kt @@ -164,7 +164,7 @@ interface JsExtensions { fun importScript(path: String): String { val result = when { path.startsWith("http") -> cacheFile(path) ?: "" - path.isContentScheme() -> DocumentUtils.readText(appCtx, Uri.parse(path)) + path.isUri() -> Uri.parse(path).readText(appCtx) path.startsWith("/storage") -> FileUtils.readText(path) else -> readTxtFile(path) } diff --git a/app/src/main/java/io/legado/app/help/storage/ImportOldData.kt b/app/src/main/java/io/legado/app/help/storage/ImportOldData.kt index 414c1db19..015118ccb 100644 --- a/app/src/main/java/io/legado/app/help/storage/ImportOldData.kt +++ b/app/src/main/java/io/legado/app/help/storage/ImportOldData.kt @@ -19,7 +19,7 @@ object ImportOldData { when (doc.name) { "myBookShelf.json" -> kotlin.runCatching { - DocumentUtils.readText(context, doc.uri).let { json -> + doc.uri.readText(context).let { json -> val importCount = importOldBookshelf(json) context.toastOnUi("成功导入书籍${importCount}") } @@ -28,7 +28,7 @@ object ImportOldData { } "myBookSource.json" -> kotlin.runCatching { - DocumentUtils.readText(context, doc.uri).let { json -> + doc.uri.readText(context).let { json -> val importCount = importOldSource(json) context.toastOnUi("成功导入书源${importCount}") } @@ -37,7 +37,7 @@ object ImportOldData { } "myBookReplaceRule.json" -> kotlin.runCatching { - DocumentUtils.readText(context, doc.uri).let { json -> + doc.uri.readText(context).let { json -> val importCount = importOldReplaceRule(json) context.toastOnUi("成功导入替换规则${importCount}") } diff --git a/app/src/main/java/io/legado/app/utils/DocumentExtensions.kt b/app/src/main/java/io/legado/app/utils/DocumentExtensions.kt index 5e2411706..91aa16c58 100644 --- a/app/src/main/java/io/legado/app/utils/DocumentExtensions.kt +++ b/app/src/main/java/io/legado/app/utils/DocumentExtensions.kt @@ -53,44 +53,14 @@ object DocumentUtils { return parent } - @JvmStatic - @Throws(Exception::class) - fun writeText( - context: Context, - data: String, - fileUri: Uri, - charset: Charset = Charsets.UTF_8 - ): Boolean { - return writeBytes(context, data.toByteArray(charset), fileUri) - } - - @JvmStatic - @Throws(Exception::class) - fun writeBytes(context: Context, data: ByteArray, fileUri: Uri): Boolean { - context.contentResolver.openOutputStream(fileUri)?.let { - it.write(data) - it.close() - return true - } - return false - } - - @JvmStatic - @Throws(Exception::class) - fun readText(context: Context, uri: Uri): String { - return String(readBytes(context, uri)) - } - - @JvmStatic - @Throws(Exception::class) - fun readBytes(context: Context, uri: Uri): ByteArray { - context.contentResolver.openInputStream(uri)?.let { - val len: Int = it.available() - val buffer = ByteArray(len) - it.read(buffer) - it.close() - return buffer - } ?: throw NoStackTraceException("打开文件失败\n${uri}") + private val projection by lazy { + arrayOf( + DocumentsContract.Document.COLUMN_DOCUMENT_ID, + DocumentsContract.Document.COLUMN_DISPLAY_NAME, + DocumentsContract.Document.COLUMN_LAST_MODIFIED, + DocumentsContract.Document.COLUMN_SIZE, + DocumentsContract.Document.COLUMN_MIME_TYPE + ) } @Throws(Exception::class) @@ -104,13 +74,7 @@ object DocumentUtils { var cursor: Cursor? = null try { cursor = appCtx.contentResolver.query( - childrenUri, arrayOf( - DocumentsContract.Document.COLUMN_DOCUMENT_ID, - DocumentsContract.Document.COLUMN_DISPLAY_NAME, - DocumentsContract.Document.COLUMN_LAST_MODIFIED, - DocumentsContract.Document.COLUMN_SIZE, - DocumentsContract.Document.COLUMN_MIME_TYPE - ), null, null, DocumentsContract.Document.COLUMN_DISPLAY_NAME + childrenUri, projection, null, null, DocumentsContract.Document.COLUMN_DISPLAY_NAME ) cursor?.let { val ici = cursor.getColumnIndex(DocumentsContract.Document.COLUMN_DOCUMENT_ID) @@ -206,20 +170,26 @@ data class FileDoc( @Throws(Exception::class) fun DocumentFile.writeText(context: Context, data: String, charset: Charset = Charsets.UTF_8) { - DocumentUtils.writeText(context, data, this.uri, charset) + uri.writeText(context, data, charset) } @Throws(Exception::class) fun DocumentFile.writeBytes(context: Context, data: ByteArray) { - DocumentUtils.writeBytes(context, data, this.uri) + uri.writeBytes(context, data) } @Throws(Exception::class) fun DocumentFile.readText(context: Context): String { - return DocumentUtils.readText(context, this.uri) + return String(readBytes(context)) } @Throws(Exception::class) fun DocumentFile.readBytes(context: Context): ByteArray { - return DocumentUtils.readBytes(context, this.uri) + return context.contentResolver.openInputStream(uri)?.let { + val len: Int = it.available() + val buffer = ByteArray(len) + it.read(buffer) + it.close() + return buffer + } ?: throw NoStackTraceException("打开文件失败\n${uri}") } diff --git a/app/src/main/java/io/legado/app/utils/UriExtensions.kt b/app/src/main/java/io/legado/app/utils/UriExtensions.kt index aea7beff2..e5da25e27 100644 --- a/app/src/main/java/io/legado/app/utils/UriExtensions.kt +++ b/app/src/main/java/io/legado/app/utils/UriExtensions.kt @@ -13,6 +13,7 @@ import io.legado.app.lib.permission.PermissionsCompat import java.io.File import java.io.FileInputStream import java.io.InputStream +import java.nio.charset.Charset fun Uri.isContentScheme() = this.scheme == "content" @@ -100,7 +101,13 @@ fun Fragment.readUri(uri: Uri?, success: (fileDoc: FileDoc, inputStream: InputSt @Throws(Exception::class) fun Uri.readBytes(context: Context): ByteArray { return if (this.isContentScheme()) { - DocumentUtils.readBytes(context, this) + context.contentResolver.openInputStream(this)?.let { + val len: Int = it.available() + val buffer = ByteArray(len) + it.read(buffer) + it.close() + return buffer + } ?: throw NoStackTraceException("打开文件失败\n${this}") } else { val path = RealPathUtil.getPath(context, this) if (path?.isNotEmpty() == true) { @@ -124,7 +131,12 @@ fun Uri.writeBytes( byteArray: ByteArray ): Boolean { if (this.isContentScheme()) { - return DocumentUtils.writeBytes(context, byteArray, this) + context.contentResolver.openOutputStream(this)?.let { + it.write(byteArray) + it.close() + return true + } + return false } else { val path = RealPathUtil.getPath(context, this) if (path?.isNotEmpty() == true) { @@ -136,8 +148,8 @@ fun Uri.writeBytes( } @Throws(Exception::class) -fun Uri.writeText(context: Context, text: String): Boolean { - return writeBytes(context, text.toByteArray()) +fun Uri.writeText(context: Context, text: String, charset: Charset = Charsets.UTF_8): Boolean { + return writeBytes(context, text.toByteArray(charset)) } fun Uri.writeBytes( From 8d6ad941b21563b54f67d7a10e1e3c6dfd01f1ae Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 16 Oct 2022 01:16:45 +0800 Subject: [PATCH 19/30] =?UTF-8?q?=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../io/legado/app/help/book/BookExtensions.kt | 18 +++--------------- .../io/legado/app/utils/DocumentExtensions.kt | 17 +++++++++++++++++ 2 files changed, 20 insertions(+), 15 deletions(-) diff --git a/app/src/main/java/io/legado/app/help/book/BookExtensions.kt b/app/src/main/java/io/legado/app/help/book/BookExtensions.kt index 42dc8f21b..ae00aab20 100644 --- a/app/src/main/java/io/legado/app/help/book/BookExtensions.kt +++ b/app/src/main/java/io/legado/app/help/book/BookExtensions.kt @@ -3,16 +3,13 @@ package io.legado.app.help.book import android.net.Uri -import androidx.documentfile.provider.DocumentFile import io.legado.app.constant.BookSourceType import io.legado.app.constant.BookType import io.legado.app.data.entities.Book import io.legado.app.data.entities.BookSource import io.legado.app.exception.NoStackTraceException import io.legado.app.help.config.AppConfig.defaultBookTreeUri -import io.legado.app.utils.getFile -import io.legado.app.utils.isContentScheme -import splitties.init.appCtx +import io.legado.app.utils.* import java.io.File @@ -64,17 +61,8 @@ fun Book.getLocalUri(): Uri { //不同的设备书籍保存路径可能不一样 优先尝试寻找当前保存路径下的文件 defaultBookTreeUri ?: return originBookUri val treeUri = Uri.parse(defaultBookTreeUri) - return if (treeUri.isContentScheme()) { - DocumentFile.fromTreeUri(appCtx, treeUri)?.run { - findFile(originName)?.let { - if (it.exists()) it.uri else originBookUri - } ?: originBookUri - } ?: originBookUri - } else { - val treeFile = File(treeUri.path!!) - val file = treeFile.getFile(originName) - if (file.exists()) Uri.fromFile(file) else originBookUri - } + val treeFileDoc = FileDoc.fromUri(treeUri, true) + return treeFileDoc.find(originName)?.uri ?: originBookUri } throw NoStackTraceException("不是本地书籍") } diff --git a/app/src/main/java/io/legado/app/utils/DocumentExtensions.kt b/app/src/main/java/io/legado/app/utils/DocumentExtensions.kt index 91aa16c58..ef1bb1205 100644 --- a/app/src/main/java/io/legado/app/utils/DocumentExtensions.kt +++ b/app/src/main/java/io/legado/app/utils/DocumentExtensions.kt @@ -145,6 +145,10 @@ data class FileDoc( companion object { + fun fromUri(uri: Uri, isDir: Boolean, name: String = ""): FileDoc { + return FileDoc(name, isDir, 0, 0, uri) + } + fun fromDocumentFile(doc: DocumentFile): FileDoc { return FileDoc( name = doc.name ?: "", @@ -168,6 +172,19 @@ data class FileDoc( } } +fun FileDoc.list(filter: ((file: FileDoc) -> Boolean)? = null): ArrayList? { + if (isDir) { + return DocumentUtils.listFiles(uri, filter) + } + return null +} + +fun FileDoc.find(name: String): FileDoc? { + return list { + it.name == name + }?.firstOrNull() +} + @Throws(Exception::class) fun DocumentFile.writeText(context: Context, data: String, charset: Charset = Charsets.UTF_8) { uri.writeText(context, data, charset) From 7d21ff246ebdf7d5f6ec7ee7854161e3023ec513 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 16 Oct 2022 01:28:07 +0800 Subject: [PATCH 20/30] =?UTF-8?q?=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/io/legado/app/utils/DocumentExtensions.kt | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/io/legado/app/utils/DocumentExtensions.kt b/app/src/main/java/io/legado/app/utils/DocumentExtensions.kt index ef1bb1205..5a8fb7be6 100644 --- a/app/src/main/java/io/legado/app/utils/DocumentExtensions.kt +++ b/app/src/main/java/io/legado/app/utils/DocumentExtensions.kt @@ -145,8 +145,17 @@ data class FileDoc( companion object { - fun fromUri(uri: Uri, isDir: Boolean, name: String = ""): FileDoc { - return FileDoc(name, isDir, 0, 0, uri) + fun fromUri(uri: Uri, isDir: Boolean): FileDoc { + if (uri.isContentScheme()) { + val doc = if (isDir) { + DocumentFile.fromTreeUri(appCtx, uri)!! + } else { + DocumentFile.fromSingleUri(appCtx, uri)!! + } + return FileDoc(doc.name ?: "", true, doc.length(), doc.lastModified(), doc.uri) + } + val file = File(uri.path!!) + return FileDoc(file.name, isDir, file.length(), file.lastModified(), uri) } fun fromDocumentFile(doc: DocumentFile): FileDoc { From cc3a8625b5ba9a7a904e4f713a3217d974493c59 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 16 Oct 2022 08:06:52 +0800 Subject: [PATCH 21/30] =?UTF-8?q?=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../io/legado/app/ui/main/bookshelf/style2/BookshelfFragment2.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/java/io/legado/app/ui/main/bookshelf/style2/BookshelfFragment2.kt b/app/src/main/java/io/legado/app/ui/main/bookshelf/style2/BookshelfFragment2.kt index e6bfa36c8..ecfa099ad 100644 --- a/app/src/main/java/io/legado/app/ui/main/bookshelf/style2/BookshelfFragment2.kt +++ b/app/src/main/java/io/legado/app/ui/main/bookshelf/style2/BookshelfFragment2.kt @@ -130,6 +130,7 @@ class BookshelfFragment2 : BaseBookshelfFragment(R.layout.fragment_bookshelf1), AppConst.bookGroupAudioId -> appDb.bookDao.flowAudio() AppConst.bookGroupNetNoneId -> appDb.bookDao.flowNetNoGroup() AppConst.bookGroupLocalNoneId -> appDb.bookDao.flowLocalNoGroup() + AppConst.bookGroupErrorId -> appDb.bookDao.flowUpdateError() else -> appDb.bookDao.flowByGroup(groupId) }.conflate().map { list -> when (getPrefInt(PreferKey.bookshelfSort)) { From 6265daa5d966691fdf969d62072ffa469f124844 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 16 Oct 2022 10:28:14 +0800 Subject: [PATCH 22/30] =?UTF-8?q?=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../association/FileAssociationViewModel.kt | 19 ++++--------------- .../io/legado/app/utils/DocumentExtensions.kt | 17 +++++++++++++++++ .../java/io/legado/app/utils/UriExtensions.kt | 2 ++ 3 files changed, 23 insertions(+), 15 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/association/FileAssociationViewModel.kt b/app/src/main/java/io/legado/app/ui/association/FileAssociationViewModel.kt index 0f6a924e1..ca484936b 100644 --- a/app/src/main/java/io/legado/app/ui/association/FileAssociationViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/association/FileAssociationViewModel.kt @@ -2,16 +2,11 @@ package io.legado.app.ui.association import android.app.Application import android.net.Uri -import androidx.documentfile.provider.DocumentFile import androidx.lifecycle.MutableLiveData import io.legado.app.constant.AppLog import io.legado.app.constant.AppPattern.bookFileRegex -import io.legado.app.exception.NoStackTraceException import io.legado.app.model.localBook.LocalBook -import io.legado.app.utils.inputStream -import io.legado.app.utils.isJson -import io.legado.app.utils.printOnDebug -import java.io.File +import io.legado.app.utils.* class FileAssociationViewModel(application: Application) : BaseAssociationViewModel(application) { val importBookLiveData = MutableLiveData() @@ -24,15 +19,9 @@ class FileAssociationViewModel(application: Application) : BaseAssociationViewMo execute { lateinit var fileName: String //如果是普通的url,需要根据返回的内容判断是什么 - if (uri.scheme == "file" || uri.scheme == "content") { - fileName = if (uri.scheme == "file") { - val file = File(uri.path.toString()) - file.name - } else { - val file = DocumentFile.fromSingleUri(context, uri) - if (file?.exists() != true) throw NoStackTraceException("文件不存在") - file.name ?: "" - } + if (uri.isContentScheme() || uri.isFileScheme()) { + val fileDoc = FileDoc.fromUri(uri, false) + fileName = fileDoc.name kotlin.runCatching { if (uri.inputStream(context).isJson()) { importJson(uri) diff --git a/app/src/main/java/io/legado/app/utils/DocumentExtensions.kt b/app/src/main/java/io/legado/app/utils/DocumentExtensions.kt index 5a8fb7be6..7585d4b82 100644 --- a/app/src/main/java/io/legado/app/utils/DocumentExtensions.kt +++ b/app/src/main/java/io/legado/app/utils/DocumentExtensions.kt @@ -1,5 +1,6 @@ package io.legado.app.utils +import android.app.DownloadManager import android.content.Context import android.database.Cursor import android.net.Uri @@ -7,6 +8,7 @@ import android.provider.DocumentsContract import androidx.documentfile.provider.DocumentFile import io.legado.app.exception.NoStackTraceException import splitties.init.appCtx +import splitties.systemservices.downloadManager import java.io.File import java.nio.charset.Charset @@ -63,6 +65,9 @@ object DocumentUtils { ) } + /** + * DocumentFile 的 listFiles() 非常的慢,所以这里直接从数据库查询 + */ @Throws(Exception::class) fun listFiles(uri: Uri, filter: ((file: FileDoc) -> Boolean)? = null): ArrayList { if (!uri.isContentScheme()) { @@ -149,6 +154,18 @@ data class FileDoc( if (uri.isContentScheme()) { val doc = if (isDir) { DocumentFile.fromTreeUri(appCtx, uri)!! + } else if (uri.host == "downloads") { + val query = DownloadManager.Query() + query.setFilterById(uri.lastPathSegment!!.toLong()) + downloadManager.query(query).use { + if (it.moveToFirst()) { + val lUriColum = it.getColumnIndex(DownloadManager.COLUMN_LOCAL_URI) + val lUri = it.getString(lUriColum) + DocumentFile.fromSingleUri(appCtx, Uri.parse(lUri))!! + } else { + DocumentFile.fromSingleUri(appCtx, uri)!! + } + } } else { DocumentFile.fromSingleUri(appCtx, uri)!! } diff --git a/app/src/main/java/io/legado/app/utils/UriExtensions.kt b/app/src/main/java/io/legado/app/utils/UriExtensions.kt index e5da25e27..1c1fa6cc3 100644 --- a/app/src/main/java/io/legado/app/utils/UriExtensions.kt +++ b/app/src/main/java/io/legado/app/utils/UriExtensions.kt @@ -17,6 +17,8 @@ import java.nio.charset.Charset fun Uri.isContentScheme() = this.scheme == "content" +fun Uri.isFileScheme() = this.scheme == "file" + /** * 读取URI */ From a51348f70f52bfa05bd416f3fe7d98cc3dea8b78 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 16 Oct 2022 11:23:13 +0800 Subject: [PATCH 23/30] =?UTF-8?q?=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../book/import/local/ImportBookActivity.kt | 2 +- .../book/import/local/ImportBookViewModel.kt | 8 +- .../io/legado/app/ui/font/FontSelectDialog.kt | 8 +- .../io/legado/app/utils/DocumentExtensions.kt | 238 ------------------ .../java/io/legado/app/utils/DocumentUtils.kt | 58 +++++ .../io/legado/app/utils/FileDocExtensions.kt | 182 ++++++++++++++ .../io/legado/app/utils/FileExtensions.kt | 21 ++ .../java/io/legado/app/utils/FileUtils.kt | 3 +- 8 files changed, 271 insertions(+), 249 deletions(-) delete mode 100644 app/src/main/java/io/legado/app/utils/DocumentExtensions.kt create mode 100644 app/src/main/java/io/legado/app/utils/DocumentUtils.kt create mode 100644 app/src/main/java/io/legado/app/utils/FileDocExtensions.kt diff --git a/app/src/main/java/io/legado/app/ui/book/import/local/ImportBookActivity.kt b/app/src/main/java/io/legado/app/ui/book/import/local/ImportBookActivity.kt index c00ca0ecb..63e6bbc22 100644 --- a/app/src/main/java/io/legado/app/ui/book/import/local/ImportBookActivity.kt +++ b/app/src/main/java/io/legado/app/ui/book/import/local/ImportBookActivity.kt @@ -233,7 +233,7 @@ class ImportBookActivity : BaseImportBookActivity + val docList = fileDoc.list { item -> when { item.name.startsWith(".") -> false item.isDir -> true else -> item.name.matches(bookFileRegex) } } - dataCallback?.setItems(docList) + dataCallback?.setItems(docList!!) }.onError { context.toastOnUi("获取文件列表出错\n${it.localizedMessage}") } @@ -132,7 +132,7 @@ class ImportBookViewModel(application: Application) : BaseViewModel(application) } kotlin.runCatching { val list = ArrayList() - DocumentUtils.listFiles(fileDoc.uri).forEach { docItem -> + fileDoc.list()!!.forEach { docItem -> if (!scope.isActive) { finally?.invoke() return diff --git a/app/src/main/java/io/legado/app/ui/font/FontSelectDialog.kt b/app/src/main/java/io/legado/app/ui/font/FontSelectDialog.kt index 73b1de7e1..7bf5c364c 100644 --- a/app/src/main/java/io/legado/app/ui/font/FontSelectDialog.kt +++ b/app/src/main/java/io/legado/app/ui/font/FontSelectDialog.kt @@ -117,16 +117,16 @@ class FontSelectDialog : BaseDialogFragment(R.layout.dialog_font_select), private fun getLocalFonts(): ArrayList { val path = FileUtils.getPath(requireContext().externalFiles, "font") - return DocumentUtils.listFiles(path) { + return File(path).listFileDocs { it.name.matches(fontRegex) } } private fun loadFontFiles(doc: DocumentFile) { execute { - val fontItems = DocumentUtils.listFiles(doc.uri) { + val fontItems = doc.listFileDocs { it.name.matches(fontRegex) - } + }!! mergeFontItems(fontItems, getLocalFonts()) }.onSuccess { adapter.setItems(it) @@ -147,7 +147,7 @@ class FontSelectDialog : BaseDialogFragment(R.layout.dialog_font_select), private fun loadFontFiles(path: String) { execute { - val fontItems = DocumentUtils.listFiles(path) { + val fontItems = File(path).listFileDocs { it.name.matches(fontRegex) } mergeFontItems(fontItems, getLocalFonts()) diff --git a/app/src/main/java/io/legado/app/utils/DocumentExtensions.kt b/app/src/main/java/io/legado/app/utils/DocumentExtensions.kt deleted file mode 100644 index 7585d4b82..000000000 --- a/app/src/main/java/io/legado/app/utils/DocumentExtensions.kt +++ /dev/null @@ -1,238 +0,0 @@ -package io.legado.app.utils - -import android.app.DownloadManager -import android.content.Context -import android.database.Cursor -import android.net.Uri -import android.provider.DocumentsContract -import androidx.documentfile.provider.DocumentFile -import io.legado.app.exception.NoStackTraceException -import splitties.init.appCtx -import splitties.systemservices.downloadManager -import java.io.File -import java.nio.charset.Charset - - -@Suppress("MemberVisibilityCanBePrivate") -object DocumentUtils { - - fun exists(root: DocumentFile, fileName: String, vararg subDirs: String): Boolean { - val parent = getDirDocument(root, *subDirs) ?: return false - return parent.findFile(fileName)?.exists() ?: false - } - - fun delete(root: DocumentFile, fileName: String, vararg subDirs: String) { - val parent: DocumentFile? = createFolderIfNotExist(root, *subDirs) - parent?.findFile(fileName)?.delete() - } - - fun createFileIfNotExist( - root: DocumentFile, - fileName: String, - mimeType: String = "", - vararg subDirs: String - ): DocumentFile? { - val parent: DocumentFile? = createFolderIfNotExist(root, *subDirs) - return parent?.findFile(fileName) ?: parent?.createFile(mimeType, fileName) - } - - fun createFolderIfNotExist(root: DocumentFile, vararg subDirs: String): DocumentFile? { - var parent: DocumentFile? = root - for (subDirName in subDirs) { - val subDir = parent?.findFile(subDirName) - ?: parent?.createDirectory(subDirName) - parent = subDir - } - return parent - } - - fun getDirDocument(root: DocumentFile, vararg subDirs: String): DocumentFile? { - var parent = root - for (subDirName in subDirs) { - val subDir = parent.findFile(subDirName) - parent = subDir ?: return null - } - return parent - } - - private val projection by lazy { - arrayOf( - DocumentsContract.Document.COLUMN_DOCUMENT_ID, - DocumentsContract.Document.COLUMN_DISPLAY_NAME, - DocumentsContract.Document.COLUMN_LAST_MODIFIED, - DocumentsContract.Document.COLUMN_SIZE, - DocumentsContract.Document.COLUMN_MIME_TYPE - ) - } - - /** - * DocumentFile 的 listFiles() 非常的慢,所以这里直接从数据库查询 - */ - @Throws(Exception::class) - fun listFiles(uri: Uri, filter: ((file: FileDoc) -> Boolean)? = null): ArrayList { - if (!uri.isContentScheme()) { - return listFiles(uri.path!!, filter) - } - val childrenUri = DocumentsContract - .buildChildDocumentsUriUsingTree(uri, DocumentsContract.getDocumentId(uri)) - val docList = arrayListOf() - var cursor: Cursor? = null - try { - cursor = appCtx.contentResolver.query( - childrenUri, projection, null, null, DocumentsContract.Document.COLUMN_DISPLAY_NAME - ) - cursor?.let { - val ici = cursor.getColumnIndex(DocumentsContract.Document.COLUMN_DOCUMENT_ID) - val nci = cursor.getColumnIndex(DocumentsContract.Document.COLUMN_DISPLAY_NAME) - val sci = cursor.getColumnIndex(DocumentsContract.Document.COLUMN_SIZE) - val mci = cursor.getColumnIndex(DocumentsContract.Document.COLUMN_MIME_TYPE) - val dci = cursor.getColumnIndex(DocumentsContract.Document.COLUMN_LAST_MODIFIED) - if (cursor.moveToFirst()) { - do { - val item = FileDoc( - name = cursor.getString(nci), - isDir = cursor.getString(mci) == DocumentsContract.Document.MIME_TYPE_DIR, - size = cursor.getLong(sci), - lastModified = cursor.getLong(dci), - uri = DocumentsContract - .buildDocumentUriUsingTree(uri, cursor.getString(ici)) - ) - if (filter == null || filter.invoke(item)) { - docList.add(item) - } - } while (cursor.moveToNext()) - } - } - } finally { - cursor?.close() - } - return docList - } - - @Throws(Exception::class) - fun listFiles(path: String, filter: ((file: FileDoc) -> Boolean)? = null): ArrayList { - val docList = arrayListOf() - val file = File(path) - file.listFiles()?.forEach { - val item = FileDoc( - it.name, - it.isDirectory, - it.length(), - it.lastModified(), - Uri.fromFile(it) - ) - if (filter == null || filter.invoke(item)) { - docList.add(item) - } - } - return docList - } - -} - -data class FileDoc( - val name: String, - val isDir: Boolean, - val size: Long, - val lastModified: Long, - val uri: Uri -) { - - override fun toString(): String { - return if (uri.isContentScheme()) uri.toString() else uri.path!! - } - - val isContentScheme get() = uri.isContentScheme() - - fun readBytes(): ByteArray { - return uri.readBytes(appCtx) - } - - companion object { - - fun fromUri(uri: Uri, isDir: Boolean): FileDoc { - if (uri.isContentScheme()) { - val doc = if (isDir) { - DocumentFile.fromTreeUri(appCtx, uri)!! - } else if (uri.host == "downloads") { - val query = DownloadManager.Query() - query.setFilterById(uri.lastPathSegment!!.toLong()) - downloadManager.query(query).use { - if (it.moveToFirst()) { - val lUriColum = it.getColumnIndex(DownloadManager.COLUMN_LOCAL_URI) - val lUri = it.getString(lUriColum) - DocumentFile.fromSingleUri(appCtx, Uri.parse(lUri))!! - } else { - DocumentFile.fromSingleUri(appCtx, uri)!! - } - } - } else { - DocumentFile.fromSingleUri(appCtx, uri)!! - } - return FileDoc(doc.name ?: "", true, doc.length(), doc.lastModified(), doc.uri) - } - val file = File(uri.path!!) - return FileDoc(file.name, isDir, file.length(), file.lastModified(), uri) - } - - fun fromDocumentFile(doc: DocumentFile): FileDoc { - return FileDoc( - name = doc.name ?: "", - isDir = doc.isDirectory, - size = doc.length(), - lastModified = doc.lastModified(), - uri = doc.uri - ) - } - - fun fromFile(file: File): FileDoc { - return FileDoc( - name = file.name, - isDir = file.isDirectory, - size = file.length(), - lastModified = file.lastModified(), - uri = Uri.fromFile(file) - ) - } - - } -} - -fun FileDoc.list(filter: ((file: FileDoc) -> Boolean)? = null): ArrayList? { - if (isDir) { - return DocumentUtils.listFiles(uri, filter) - } - return null -} - -fun FileDoc.find(name: String): FileDoc? { - return list { - it.name == name - }?.firstOrNull() -} - -@Throws(Exception::class) -fun DocumentFile.writeText(context: Context, data: String, charset: Charset = Charsets.UTF_8) { - uri.writeText(context, data, charset) -} - -@Throws(Exception::class) -fun DocumentFile.writeBytes(context: Context, data: ByteArray) { - uri.writeBytes(context, data) -} - -@Throws(Exception::class) -fun DocumentFile.readText(context: Context): String { - return String(readBytes(context)) -} - -@Throws(Exception::class) -fun DocumentFile.readBytes(context: Context): ByteArray { - return context.contentResolver.openInputStream(uri)?.let { - val len: Int = it.available() - val buffer = ByteArray(len) - it.read(buffer) - it.close() - return buffer - } ?: throw NoStackTraceException("打开文件失败\n${uri}") -} diff --git a/app/src/main/java/io/legado/app/utils/DocumentUtils.kt b/app/src/main/java/io/legado/app/utils/DocumentUtils.kt new file mode 100644 index 000000000..e7e31d4cb --- /dev/null +++ b/app/src/main/java/io/legado/app/utils/DocumentUtils.kt @@ -0,0 +1,58 @@ +package io.legado.app.utils + +import android.provider.DocumentsContract +import androidx.documentfile.provider.DocumentFile + +@Suppress("MemberVisibilityCanBePrivate") +object DocumentUtils { + + fun exists(root: DocumentFile, fileName: String, vararg subDirs: String): Boolean { + val parent = getDirDocument(root, *subDirs) ?: return false + return parent.findFile(fileName)?.exists() ?: false + } + + fun delete(root: DocumentFile, fileName: String, vararg subDirs: String) { + val parent: DocumentFile? = createFolderIfNotExist(root, *subDirs) + parent?.findFile(fileName)?.delete() + } + + fun createFileIfNotExist( + root: DocumentFile, + fileName: String, + mimeType: String = "", + vararg subDirs: String + ): DocumentFile? { + val parent: DocumentFile? = createFolderIfNotExist(root, *subDirs) + return parent?.findFile(fileName) ?: parent?.createFile(mimeType, fileName) + } + + fun createFolderIfNotExist(root: DocumentFile, vararg subDirs: String): DocumentFile? { + var parent: DocumentFile? = root + for (subDirName in subDirs) { + val subDir = parent?.findFile(subDirName) + ?: parent?.createDirectory(subDirName) + parent = subDir + } + return parent + } + + fun getDirDocument(root: DocumentFile, vararg subDirs: String): DocumentFile? { + var parent = root + for (subDirName in subDirs) { + val subDir = parent.findFile(subDirName) + parent = subDir ?: return null + } + return parent + } + + val projection by lazy { + arrayOf( + DocumentsContract.Document.COLUMN_DOCUMENT_ID, + DocumentsContract.Document.COLUMN_DISPLAY_NAME, + DocumentsContract.Document.COLUMN_LAST_MODIFIED, + DocumentsContract.Document.COLUMN_SIZE, + DocumentsContract.Document.COLUMN_MIME_TYPE + ) + } + +} \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/utils/FileDocExtensions.kt b/app/src/main/java/io/legado/app/utils/FileDocExtensions.kt new file mode 100644 index 000000000..26225ec32 --- /dev/null +++ b/app/src/main/java/io/legado/app/utils/FileDocExtensions.kt @@ -0,0 +1,182 @@ +package io.legado.app.utils + +import android.app.DownloadManager +import android.content.Context +import android.database.Cursor +import android.net.Uri +import android.provider.DocumentsContract +import androidx.documentfile.provider.DocumentFile +import io.legado.app.exception.NoStackTraceException +import splitties.init.appCtx +import splitties.systemservices.downloadManager +import java.io.File +import java.nio.charset.Charset + + +data class FileDoc( + val name: String, + val isDir: Boolean, + val size: Long, + val lastModified: Long, + val uri: Uri +) { + + override fun toString(): String { + return if (uri.isContentScheme()) uri.toString() else uri.path!! + } + + val isContentScheme get() = uri.isContentScheme() + + fun readBytes(): ByteArray { + return uri.readBytes(appCtx) + } + + companion object { + + fun fromUri(uri: Uri, isDir: Boolean): FileDoc { + if (uri.isContentScheme()) { + val doc = if (isDir) { + DocumentFile.fromTreeUri(appCtx, uri)!! + } else if (uri.host == "downloads") { + val query = DownloadManager.Query() + query.setFilterById(uri.lastPathSegment!!.toLong()) + downloadManager.query(query).use { + if (it.moveToFirst()) { + val lUriColum = it.getColumnIndex(DownloadManager.COLUMN_LOCAL_URI) + val lUri = it.getString(lUriColum) + DocumentFile.fromSingleUri(appCtx, Uri.parse(lUri))!! + } else { + DocumentFile.fromSingleUri(appCtx, uri)!! + } + } + } else { + DocumentFile.fromSingleUri(appCtx, uri)!! + } + return FileDoc(doc.name ?: "", true, doc.length(), doc.lastModified(), doc.uri) + } + val file = File(uri.path!!) + return FileDoc(file.name, isDir, file.length(), file.lastModified(), uri) + } + + fun fromDocumentFile(doc: DocumentFile): FileDoc { + return FileDoc( + name = doc.name ?: "", + isDir = doc.isDirectory, + size = doc.length(), + lastModified = doc.lastModified(), + uri = doc.uri + ) + } + + fun fromFile(file: File): FileDoc { + return FileDoc( + name = file.name, + isDir = file.isDirectory, + size = file.length(), + lastModified = file.lastModified(), + uri = Uri.fromFile(file) + ) + } + + } +} + +/** + * 过滤器 + */ +typealias FileDocFilter = (file: FileDoc) -> Boolean + +/** + * 返回子文件列表,如果不是文件夹则返回null + */ +fun FileDoc.list(filter: FileDocFilter? = null): ArrayList? { + if (isDir) { + if (uri.isContentScheme()) { + /** + * DocumentFile 的 listFiles() 非常的慢,所以这里直接从数据库查询 + */ + val childrenUri = DocumentsContract + .buildChildDocumentsUriUsingTree(uri, DocumentsContract.getDocumentId(uri)) + val docList = arrayListOf() + var cursor: Cursor? = null + try { + cursor = appCtx.contentResolver.query( + childrenUri, + DocumentUtils.projection, + null, + null, + DocumentsContract.Document.COLUMN_DISPLAY_NAME + ) + cursor?.let { + val ici = cursor.getColumnIndex(DocumentsContract.Document.COLUMN_DOCUMENT_ID) + val nci = cursor.getColumnIndex(DocumentsContract.Document.COLUMN_DISPLAY_NAME) + val sci = cursor.getColumnIndex(DocumentsContract.Document.COLUMN_SIZE) + val mci = cursor.getColumnIndex(DocumentsContract.Document.COLUMN_MIME_TYPE) + val dci = cursor.getColumnIndex(DocumentsContract.Document.COLUMN_LAST_MODIFIED) + if (cursor.moveToFirst()) { + do { + val item = FileDoc( + name = cursor.getString(nci), + isDir = cursor.getString(mci) == DocumentsContract.Document.MIME_TYPE_DIR, + size = cursor.getLong(sci), + lastModified = cursor.getLong(dci), + uri = DocumentsContract.buildDocumentUriUsingTree( + uri, + cursor.getString(ici) + ) + ) + if (filter == null || filter.invoke(item)) { + docList.add(item) + } + } while (cursor.moveToNext()) + } + } + } finally { + cursor?.close() + } + return docList + } else { + return File(uri.path!!).listFileDocs(filter) + } + } + return null +} + +fun FileDoc.find(name: String): FileDoc? { + return list { + it.name == name + }?.firstOrNull() +} + +/** + * DocumentFile 的 listFiles() 非常的慢,尽量不要使用 + */ +fun DocumentFile.listFileDocs(filter: FileDocFilter? = null): ArrayList? { + return FileDoc.fromDocumentFile(this).list(filter) +} + +@Throws(Exception::class) +fun DocumentFile.writeText(context: Context, data: String, charset: Charset = Charsets.UTF_8) { + uri.writeText(context, data, charset) +} + +@Throws(Exception::class) +fun DocumentFile.writeBytes(context: Context, data: ByteArray) { + uri.writeBytes(context, data) +} + +@Throws(Exception::class) +fun DocumentFile.readText(context: Context): String { + return String(readBytes(context)) +} + +@Throws(Exception::class) +fun DocumentFile.readBytes(context: Context): ByteArray { + return context.contentResolver.openInputStream(uri)?.let { + val len: Int = it.available() + val buffer = ByteArray(len) + it.read(buffer) + it.close() + return buffer + } ?: throw NoStackTraceException("打开文件失败\n${uri}") +} diff --git a/app/src/main/java/io/legado/app/utils/FileExtensions.kt b/app/src/main/java/io/legado/app/utils/FileExtensions.kt index 31f03c04c..8c2c07f3a 100644 --- a/app/src/main/java/io/legado/app/utils/FileExtensions.kt +++ b/app/src/main/java/io/legado/app/utils/FileExtensions.kt @@ -1,5 +1,6 @@ package io.legado.app.utils +import android.net.Uri import java.io.File fun File.getFile(vararg subDirFiles: String): File { @@ -11,3 +12,23 @@ fun File.exists(vararg subDirFiles: String): Boolean { return getFile(*subDirFiles).exists() } +@Throws(Exception::class) +fun File.listFileDocs(filter: FileDocFilter? = null): ArrayList { + val docList = arrayListOf() + listFiles() + listFiles()?.forEach { + val item = FileDoc( + it.name, + it.isDirectory, + it.length(), + it.lastModified(), + Uri.fromFile(it) + ) + if (filter == null || filter.invoke(item)) { + docList.add(item) + } + } + return docList +} + + diff --git a/app/src/main/java/io/legado/app/utils/FileUtils.kt b/app/src/main/java/io/legado/app/utils/FileUtils.kt index 11fe7de72..4f6037d19 100644 --- a/app/src/main/java/io/legado/app/utils/FileUtils.kt +++ b/app/src/main/java/io/legado/app/utils/FileUtils.kt @@ -4,7 +4,6 @@ import android.os.Environment import android.webkit.MimeTypeMap import androidx.annotation.IntDef import splitties.init.appCtx - import java.io.* import java.nio.charset.Charset import java.text.SimpleDateFormat @@ -115,7 +114,7 @@ object FileUtils { const val BY_EXTENSION_DESC = 7 @IntDef(value = [BY_NAME_ASC, BY_NAME_DESC, BY_TIME_ASC, BY_TIME_DESC, BY_SIZE_ASC, BY_SIZE_DESC, BY_EXTENSION_ASC, BY_EXTENSION_DESC]) - @kotlin.annotation.Retention(AnnotationRetention.SOURCE) + @Retention(AnnotationRetention.SOURCE) annotation class SortType /** From 3524d653c7ad96d5cc10b305ca429b035ec9e692 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 16 Oct 2022 11:24:24 +0800 Subject: [PATCH 24/30] =?UTF-8?q?=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/src/main/java/io/legado/app/utils/FileDocExtensions.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/utils/FileDocExtensions.kt b/app/src/main/java/io/legado/app/utils/FileDocExtensions.kt index 26225ec32..abb8c82ae 100644 --- a/app/src/main/java/io/legado/app/utils/FileDocExtensions.kt +++ b/app/src/main/java/io/legado/app/utils/FileDocExtensions.kt @@ -52,7 +52,7 @@ data class FileDoc( } else { DocumentFile.fromSingleUri(appCtx, uri)!! } - return FileDoc(doc.name ?: "", true, doc.length(), doc.lastModified(), doc.uri) + return FileDoc(doc.name ?: "", isDir, doc.length(), doc.lastModified(), doc.uri) } val file = File(uri.path!!) return FileDoc(file.name, isDir, file.length(), file.lastModified(), uri) From 4a9ed6446471c82800af38d582685ac95dcef444 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 16 Oct 2022 11:33:29 +0800 Subject: [PATCH 25/30] =?UTF-8?q?=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/src/main/assets/updateLog.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/assets/updateLog.md b/app/src/main/assets/updateLog.md index 4a7aeae06..6e5338f8c 100644 --- a/app/src/main/assets/updateLog.md +++ b/app/src/main/assets/updateLog.md @@ -11,7 +11,7 @@ * 正文出现缺字漏字、内容缺失、排版错乱等情况,有可能是净化规则或简繁转换出现问题。 * 漫画源看书显示乱码,**阅读与其他软件的源并不通用**,请导入阅读的支持的漫画源! -**2022/10/15** +**2022/10/16** * 添加更新失败分组 * web服务和朗读服务添加唤醒锁 From ae74dc93c6cdf263bf16e739cd72e95466884fcb Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 16 Oct 2022 12:19:11 +0800 Subject: [PATCH 26/30] =?UTF-8?q?=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../io/legado/app/help/book/BookExtensions.kt | 2 +- .../io/legado/app/utils/FileDocExtensions.kt | 27 ++++++++++++++++--- 2 files changed, 24 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/io/legado/app/help/book/BookExtensions.kt b/app/src/main/java/io/legado/app/help/book/BookExtensions.kt index ae00aab20..3600881c7 100644 --- a/app/src/main/java/io/legado/app/help/book/BookExtensions.kt +++ b/app/src/main/java/io/legado/app/help/book/BookExtensions.kt @@ -62,7 +62,7 @@ fun Book.getLocalUri(): Uri { defaultBookTreeUri ?: return originBookUri val treeUri = Uri.parse(defaultBookTreeUri) val treeFileDoc = FileDoc.fromUri(treeUri, true) - return treeFileDoc.find(originName)?.uri ?: originBookUri + return treeFileDoc.find(originName, 5)?.uri ?: originBookUri } throw NoStackTraceException("不是本地书籍") } diff --git a/app/src/main/java/io/legado/app/utils/FileDocExtensions.kt b/app/src/main/java/io/legado/app/utils/FileDocExtensions.kt index abb8c82ae..8e4ef3948 100644 --- a/app/src/main/java/io/legado/app/utils/FileDocExtensions.kt +++ b/app/src/main/java/io/legado/app/utils/FileDocExtensions.kt @@ -142,10 +142,29 @@ fun FileDoc.list(filter: FileDocFilter? = null): ArrayList? { return null } -fun FileDoc.find(name: String): FileDoc? { - return list { - it.name == name - }?.firstOrNull() +/** + * 查找文档, 如果存在则返回文档,如果不存在返回空 + * @param name 文件名 + * @param depth 查找文件夹深度 + */ +fun FileDoc.find(name: String, depth: Int = 0): FileDoc? { + val list = list() + list?.forEach { + if (it.name == name) { + return it + } + } + if (depth > 0) { + list?.forEach { + if (it.isDir) { + val fileDoc = it.find(name, depth - 1) + if (fileDoc != null) { + return fileDoc + } + } + } + } + return null } /** From 095b70a0ddcb2e52ee6fd65a1fb3b997fb01b92b Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 16 Oct 2022 12:42:37 +0800 Subject: [PATCH 27/30] =?UTF-8?q?=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/src/main/assets/updateLog.md | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/assets/updateLog.md b/app/src/main/assets/updateLog.md index 6e5338f8c..bd386dbc3 100644 --- a/app/src/main/assets/updateLog.md +++ b/app/src/main/assets/updateLog.md @@ -16,6 +16,7 @@ * 添加更新失败分组 * web服务和朗读服务添加唤醒锁 * 修复搜索禁用书源的bug +* 修复本地书籍很慢的问题 **2022/10/14** From fcb004be2414d7912ec60445eb0e2f9dfac132ba Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 16 Oct 2022 12:50:59 +0800 Subject: [PATCH 28/30] =?UTF-8?q?=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../io/legado/app/ui/font/FontSelectDialog.kt | 32 +++++++------------ 1 file changed, 12 insertions(+), 20 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/font/FontSelectDialog.kt b/app/src/main/java/io/legado/app/ui/font/FontSelectDialog.kt index 7bf5c364c..09b887f06 100644 --- a/app/src/main/java/io/legado/app/ui/font/FontSelectDialog.kt +++ b/app/src/main/java/io/legado/app/ui/font/FontSelectDialog.kt @@ -24,6 +24,9 @@ import kotlinx.coroutines.Dispatchers.Main import kotlinx.coroutines.launch import java.io.File +/** + * 字体选择对话框 + */ class FontSelectDialog : BaseDialogFragment(R.layout.dialog_font_select), Toolbar.OnMenuItemClickListener, FontAdapter.CallBack { @@ -35,11 +38,11 @@ class FontSelectDialog : BaseDialogFragment(R.layout.dialog_font_select), } private val selectFontDir = registerForActivityResult(HandleFileContract()) { it.uri?.let { uri -> - if (uri.toString().isContentScheme()) { + if (uri.isContentScheme()) { putPrefString(PreferKey.fontFolder, uri.toString()) val doc = DocumentFile.fromTreeUri(requireContext(), uri) if (doc != null) { - loadFontFiles(doc) + loadFontFiles(FileDoc.fromDocumentFile(doc)) } else { RealPathUtil.getPath(requireContext(), uri)?.let { path -> loadFontFilesByPermission(path) @@ -75,7 +78,7 @@ class FontSelectDialog : BaseDialogFragment(R.layout.dialog_font_select), if (fontPath.isContentScheme()) { val doc = DocumentFile.fromTreeUri(requireContext(), Uri.parse(fontPath)) if (doc?.canRead() == true) { - loadFontFiles(doc) + loadFontFiles(FileDoc.fromDocumentFile(doc)) } else { openFolder() } @@ -122,35 +125,24 @@ class FontSelectDialog : BaseDialogFragment(R.layout.dialog_font_select), } } - private fun loadFontFiles(doc: DocumentFile) { - execute { - val fontItems = doc.listFileDocs { - it.name.matches(fontRegex) - }!! - mergeFontItems(fontItems, getLocalFonts()) - }.onSuccess { - adapter.setItems(it) - }.onError { - toastOnUi("getFontFiles:${it.localizedMessage}") - } - } - private fun loadFontFilesByPermission(path: String) { PermissionsCompat.Builder(this@FontSelectDialog) .addPermissions(*Permissions.Group.STORAGE) .rationale(R.string.tip_perm_request_storage) .onGranted { - loadFontFiles(path) + loadFontFiles( + FileDoc.fromFile(File(path)) + ) } .request() } - private fun loadFontFiles(path: String) { + private fun loadFontFiles(fileDoc: FileDoc) { execute { - val fontItems = File(path).listFileDocs { + val fontItems = fileDoc.list { it.name.matches(fontRegex) } - mergeFontItems(fontItems, getLocalFonts()) + mergeFontItems(fontItems!!, getLocalFonts()) }.onSuccess { adapter.setItems(it) }.onError { From 022c60af38557af8213b9558dd04a240706c62a0 Mon Sep 17 00:00:00 2001 From: Horis <821938089@qq.com> Date: Sun, 16 Oct 2022 13:09:30 +0800 Subject: [PATCH 29/30] =?UTF-8?q?=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../io/legado/app/data/dao/BookSourceDao.kt | 8 +++++++ .../app/ui/book/search/SearchActivity.kt | 3 +++ .../legado/app/ui/book/search/SearchScope.kt | 21 ++++++++++++++++--- .../app/ui/book/search/SearchScopeDialog.kt | 2 +- 4 files changed, 30 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/io/legado/app/data/dao/BookSourceDao.kt b/app/src/main/java/io/legado/app/data/dao/BookSourceDao.kt index 9e0ec4dbc..f0a689843 100644 --- a/app/src/main/java/io/legado/app/data/dao/BookSourceDao.kt +++ b/app/src/main/java/io/legado/app/data/dao/BookSourceDao.kt @@ -134,6 +134,9 @@ interface BookSourceDao { @get:Query("select distinct bookSourceGroup from book_sources where trim(bookSourceGroup) <> ''") val allGroupsUnProcessed: List + @get:Query("select distinct bookSourceGroup from book_sources where enabled = 1 and trim(bookSourceGroup) <> ''") + val allEnabledGroupsUnProcessed: List + @Query("select * from book_sources where bookSourceUrl = :key") fun getBookSource(key: String): BookSource? @@ -175,6 +178,11 @@ interface BookSourceDao { return dealGroups(allGroupsUnProcessed) } + val allEnabledGroups: List + get() { + return dealGroups(allEnabledGroupsUnProcessed) + } + fun flowGroups(): Flow> { return flowGroupsUnProcessed().map { list -> dealGroups(list) 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 948aac28b..fc94136ff 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 @@ -221,6 +221,9 @@ class SearchActivity : VMBaseActivity) : this(groups.joinToString(",")) - constructor(source: BookSource) : this("${source.bookSourceName}::${source.bookSourceUrl}") + constructor(source: BookSource) : this( + "${ + source.bookSourceName.replace("::", "") + }::${source.bookSourceUrl}" + ) override fun toString(): String { return scope } + val stateLiveData = MutableLiveData("") + fun update(scope: String) { this.scope = scope } @@ -70,12 +77,20 @@ data class SearchScope(private var scope: String) { } } } else { - scope.splitNotBlank(",").forEach { - list.addAll(appDb.bookSourceDao.getEnabledByGroup(it)) + val oldScope = scope.splitNotBlank(",") + val newScope = oldScope.filter { + val bookSources = appDb.bookSourceDao.getEnabledByGroup(it) + list.addAll(bookSources) + bookSources.isNotEmpty() + } + if (oldScope.size != newScope.size) { + update(newScope) + stateLiveData.postValue("") } } if (list.isEmpty()) { scope = "" + stateLiveData.postValue("") return appDb.bookSourceDao.allEnabled } return list.sortedBy { it.customOrder } diff --git a/app/src/main/java/io/legado/app/ui/book/search/SearchScopeDialog.kt b/app/src/main/java/io/legado/app/ui/book/search/SearchScopeDialog.kt index 8d7ff9fab..b478d6957 100644 --- a/app/src/main/java/io/legado/app/ui/book/search/SearchScopeDialog.kt +++ b/app/src/main/java/io/legado/app/ui/book/search/SearchScopeDialog.kt @@ -102,7 +102,7 @@ class SearchScopeDialog : BaseDialogFragment(R.layout.dialog_search_scope) { private fun initData() { launch { groups = withContext(IO) { - appDb.bookSourceDao.allGroups + appDb.bookSourceDao.allEnabledGroups } sources = withContext(IO) { appDb.bookSourceDao.allEnabled From 9cf0fdb83409328585581c93ebd093b097eea6ed Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 16 Oct 2022 13:22:39 +0800 Subject: [PATCH 30/30] =?UTF-8?q?=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/io/legado/app/utils/DocumentUtils.kt | 11 ---- .../io/legado/app/utils/FileDocExtensions.kt | 56 ++++++++++++++++++- 2 files changed, 55 insertions(+), 12 deletions(-) diff --git a/app/src/main/java/io/legado/app/utils/DocumentUtils.kt b/app/src/main/java/io/legado/app/utils/DocumentUtils.kt index e7e31d4cb..c2b93c61c 100644 --- a/app/src/main/java/io/legado/app/utils/DocumentUtils.kt +++ b/app/src/main/java/io/legado/app/utils/DocumentUtils.kt @@ -1,6 +1,5 @@ package io.legado.app.utils -import android.provider.DocumentsContract import androidx.documentfile.provider.DocumentFile @Suppress("MemberVisibilityCanBePrivate") @@ -45,14 +44,4 @@ object DocumentUtils { return parent } - val projection by lazy { - arrayOf( - DocumentsContract.Document.COLUMN_DOCUMENT_ID, - DocumentsContract.Document.COLUMN_DISPLAY_NAME, - DocumentsContract.Document.COLUMN_LAST_MODIFIED, - DocumentsContract.Document.COLUMN_SIZE, - DocumentsContract.Document.COLUMN_MIME_TYPE - ) - } - } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/utils/FileDocExtensions.kt b/app/src/main/java/io/legado/app/utils/FileDocExtensions.kt index 8e4ef3948..798262602 100644 --- a/app/src/main/java/io/legado/app/utils/FileDocExtensions.kt +++ b/app/src/main/java/io/legado/app/utils/FileDocExtensions.kt @@ -1,3 +1,5 @@ +@file:Suppress("unused") + package io.legado.app.utils import android.app.DownloadManager @@ -86,6 +88,16 @@ data class FileDoc( */ typealias FileDocFilter = (file: FileDoc) -> Boolean +private val projection by lazy { + arrayOf( + DocumentsContract.Document.COLUMN_DOCUMENT_ID, + DocumentsContract.Document.COLUMN_DISPLAY_NAME, + DocumentsContract.Document.COLUMN_LAST_MODIFIED, + DocumentsContract.Document.COLUMN_SIZE, + DocumentsContract.Document.COLUMN_MIME_TYPE + ) +} + /** * 返回子文件列表,如果不是文件夹则返回null */ @@ -102,7 +114,7 @@ fun FileDoc.list(filter: FileDocFilter? = null): ArrayList? { try { cursor = appCtx.contentResolver.query( childrenUri, - DocumentUtils.projection, + projection, null, null, DocumentsContract.Document.COLUMN_DISPLAY_NAME @@ -167,6 +179,48 @@ fun FileDoc.find(name: String, depth: Int = 0): FileDoc? { return null } +fun FileDoc.createFileIfNotExist( + fileName: String, + mimeType: String = "", + vararg subDirs: String +): FileDoc { + return if (uri.isContentScheme()) { + val documentFile = DocumentFile.fromTreeUri(appCtx, uri)!! + val tmp = DocumentUtils.createFileIfNotExist(documentFile, fileName, mimeType, *subDirs)!! + FileDoc.fromDocumentFile(tmp) + } else { + val path = FileUtils.getPath(uri.path!!, *subDirs) + File.separator + fileName + val tmp = FileUtils.createFileIfNotExist(path) + FileDoc.fromFile(tmp) + } +} + +fun FileDoc.createFolderIfNotExist( + vararg subDirs: String +): FileDoc { + return if (uri.isContentScheme()) { + val documentFile = DocumentFile.fromTreeUri(appCtx, uri)!! + val tmp = DocumentUtils.createFolderIfNotExist(documentFile, *subDirs)!! + FileDoc.fromDocumentFile(tmp) + } else { + val path = FileUtils.getPath(uri.path!!, *subDirs) + val tmp = FileUtils.createFolderIfNotExist(path) + FileDoc.fromFile(tmp) + } +} + +fun FileDoc.exists( + fileName: String, + vararg subDirs: String +): Boolean { + return if (uri.isContentScheme()) { + DocumentUtils.exists(DocumentFile.fromTreeUri(appCtx, uri)!!, fileName, *subDirs) + } else { + val path = FileUtils.getPath(uri.path!!, *subDirs) + File.separator + fileName + FileUtils.exist(path) + } +} + /** * DocumentFile 的 listFiles() 非常的慢,尽量不要使用 */