From 6e12d8e85aa5e1b408d60fcaf0a7c597325e45e5 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 12 Mar 2023 21:43:46 +0800 Subject: [PATCH 01/13] =?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 5f399f9a3..8985ed248 100644 --- a/app/src/main/assets/updateLog.md +++ b/app/src/main/assets/updateLog.md @@ -13,7 +13,7 @@ * 正文出现缺字漏字、内容缺失、排版错乱等情况,有可能是净化规则或简繁转换出现问题。 * 漫画源看书显示乱码,**阅读与其他软件的源并不通用**,请导入阅读的支持的漫画源! -**2023/03/11** +**2023/03/12** * 远程书籍添加webDav多配置 * 更新文件类书源详情页界面逻辑 From 868aa71caa91cd04d6af9a7707724703e54eb27e Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 12 Mar 2023 23:18:05 +0800 Subject: [PATCH 02/13] =?UTF-8?q?=E4=BC=98=E5=8C=96=E6=8E=92=E5=BA=8F?= =?UTF-8?q?=E5=8F=B7=E7=9B=B8=E5=90=8C=E5=AF=BC=E8=87=B4=E7=9A=84=E6=8E=92?= =?UTF-8?q?=E5=BA=8F=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/io/legado/app/data/dao/BookSourceDao.kt | 6 +++--- .../app/ui/book/source/manage/BookSourceActivity.kt | 4 ++-- .../ui/book/source/manage/BookSourceViewModel.kt | 13 +++++++++++++ 3 files changed, 18 insertions(+), 5 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 ccd2b13d8..35b384120 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 @@ -54,9 +54,6 @@ interface BookSourceDao { @Query("select * from book_sources where enabledExplore = 1 and trim(exploreUrl) <> '' order by customOrder asc") fun flowExplore(): Flow> -// @Query("select * from book_sources where enabledReview = 1 order by customOrder asc") -// fun flowReview(): Flow> - @Query("select * from book_sources where loginUrl is not null and loginUrl != ''") fun flowLogin(): Flow> @@ -161,6 +158,9 @@ interface BookSourceDao { @get:Query("select max(customOrder) from book_sources") val maxOrder: Int + @Query("select count(*) from (select customOrder, count(customOrder) from book_sources group by customOrder having count(customOrder) > 1)") + fun sameSortNumberSize(): Int + private fun dealGroups(list: List): List { val groups = linkedSetOf() list.forEach { diff --git a/app/src/main/java/io/legado/app/ui/book/source/manage/BookSourceActivity.kt b/app/src/main/java/io/legado/app/ui/book/source/manage/BookSourceActivity.kt index b461d1fd3..1f56d664f 100644 --- a/app/src/main/java/io/legado/app/ui/book/source/manage/BookSourceActivity.kt +++ b/app/src/main/java/io/legado/app/ui/book/source/manage/BookSourceActivity.kt @@ -58,6 +58,7 @@ class BookSourceActivity : VMBaseActivity() private val importRecordKey = "bookSourceRecordKey" private val adapter by lazy { BookSourceAdapter(this, this) } + private val itemTouchCallback by lazy { ItemTouchCallback(adapter) } private val searchView: SearchView by lazy { binding.titleBar.findViewById(R.id.search_view) } @@ -197,8 +198,6 @@ class BookSourceActivity : VMBaseActivity adapter.setItems(data, adapter.diffItemCallback) + itemTouchCallback.isCanDrag = sort == Sort.Default delay(500) } } diff --git a/app/src/main/java/io/legado/app/ui/book/source/manage/BookSourceViewModel.kt b/app/src/main/java/io/legado/app/ui/book/source/manage/BookSourceViewModel.kt index ad3e2e426..a4b1870df 100644 --- a/app/src/main/java/io/legado/app/ui/book/source/manage/BookSourceViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/book/source/manage/BookSourceViewModel.kt @@ -16,6 +16,19 @@ import java.io.FileOutputStream */ class BookSourceViewModel(application: Application) : BaseViewModel(application) { + init { + execute { + val sameSortNumberSize = appDb.bookSourceDao.sameSortNumberSize() + if (sameSortNumberSize > 0) { + val sources = appDb.bookSourceDao.all + sources.forEachIndexed { index, bookSource -> + bookSource.customOrder = index + appDb.bookSourceDao.update(bookSource) + } + } + } + } + fun topSource(vararg sources: BookSource) { execute { sources.sortBy { it.customOrder } From fe152079ce7e792e849d5cd0dd768a0bdae5b668 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 12 Mar 2023 23:45:00 +0800 Subject: [PATCH 03/13] =?UTF-8?q?=E4=BC=98=E5=8C=96=E6=8E=92=E5=BA=8F?= =?UTF-8?q?=E5=8F=B7=E7=9B=B8=E5=90=8C=E5=AF=BC=E8=87=B4=E7=9A=84=E6=8E=92?= =?UTF-8?q?=E5=BA=8F=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../app/base/adapter/RecyclerAdapter.kt | 2 +- .../io/legado/app/data/dao/BookSourceDao.kt | 3 --- .../book/source/manage/BookSourceActivity.kt | 4 +-- .../book/source/manage/BookSourceAdapter.kt | 26 +++++++++++-------- .../book/source/manage/BookSourceViewModel.kt | 24 +++++------------ 5 files changed, 24 insertions(+), 35 deletions(-) diff --git a/app/src/main/java/io/legado/app/base/adapter/RecyclerAdapter.kt b/app/src/main/java/io/legado/app/base/adapter/RecyclerAdapter.kt index 9043f679a..5ef66fbe5 100644 --- a/app/src/main/java/io/legado/app/base/adapter/RecyclerAdapter.kt +++ b/app/src/main/java/io/legado/app/base/adapter/RecyclerAdapter.kt @@ -321,7 +321,7 @@ abstract class RecyclerAdapter(protected val context: Co fun getItemByLayoutPosition(position: Int) = items.getOrNull(getActualPosition(position)) - fun getItems(): List = items + fun getItems(): List = items.toList() protected open fun getItemViewType(item: ITEM, position: Int) = 0 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 35b384120..66d0ebe0c 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 @@ -158,9 +158,6 @@ interface BookSourceDao { @get:Query("select max(customOrder) from book_sources") val maxOrder: Int - @Query("select count(*) from (select customOrder, count(customOrder) from book_sources group by customOrder having count(customOrder) > 1)") - fun sameSortNumberSize(): Int - private fun dealGroups(list: List): List { val groups = linkedSetOf() list.forEach { diff --git a/app/src/main/java/io/legado/app/ui/book/source/manage/BookSourceActivity.kt b/app/src/main/java/io/legado/app/ui/book/source/manage/BookSourceActivity.kt index 1f56d664f..f2ec893bb 100644 --- a/app/src/main/java/io/legado/app/ui/book/source/manage/BookSourceActivity.kt +++ b/app/src/main/java/io/legado/app/ui/book/source/manage/BookSourceActivity.kt @@ -596,8 +596,8 @@ class BookSourceActivity : VMBaseActivity) { + viewModel.upOrder(items) } override fun toTop(bookSource: BookSource) { diff --git a/app/src/main/java/io/legado/app/ui/book/source/manage/BookSourceAdapter.kt b/app/src/main/java/io/legado/app/ui/book/source/manage/BookSourceAdapter.kt index 745aa0996..d17c19b09 100644 --- a/app/src/main/java/io/legado/app/ui/book/source/manage/BookSourceAdapter.kt +++ b/app/src/main/java/io/legado/app/ui/book/source/manage/BookSourceAdapter.kt @@ -263,15 +263,11 @@ class BookSourceAdapter(context: Context, val callBack: CallBack) : val srcItem = getItem(srcPosition) val targetItem = getItem(targetPosition) if (srcItem != null && targetItem != null) { - if (srcItem.customOrder == targetItem.customOrder) { - callBack.upOrder() - } else { - val srcOrder = srcItem.customOrder - srcItem.customOrder = targetItem.customOrder - targetItem.customOrder = srcOrder - movedItems.add(srcItem) - movedItems.add(targetItem) - } + val srcOrder = srcItem.customOrder + srcItem.customOrder = targetItem.customOrder + targetItem.customOrder = srcOrder + movedItems.add(srcItem) + movedItems.add(targetItem) } swapItem(srcPosition, targetPosition) return true @@ -281,7 +277,15 @@ class BookSourceAdapter(context: Context, val callBack: CallBack) : override fun onClearView(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder) { if (movedItems.isNotEmpty()) { - callBack.update(*movedItems.toTypedArray()) + val sortNumberSet = hashSetOf() + movedItems.forEach { + sortNumberSet.add(it.customOrder) + } + if (movedItems.size > sortNumberSet.size) { + callBack.upOrder(getItems()) + } else { + callBack.update(*movedItems.toTypedArray()) + } movedItems.clear() } } @@ -319,7 +323,7 @@ class BookSourceAdapter(context: Context, val callBack: CallBack) : fun toBottom(bookSource: BookSource) fun searchBook(bookSource: BookSource) fun debug(bookSource: BookSource) - fun upOrder() + fun upOrder(items: List) fun upCountView() } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/book/source/manage/BookSourceViewModel.kt b/app/src/main/java/io/legado/app/ui/book/source/manage/BookSourceViewModel.kt index a4b1870df..c95bfa331 100644 --- a/app/src/main/java/io/legado/app/ui/book/source/manage/BookSourceViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/book/source/manage/BookSourceViewModel.kt @@ -16,19 +16,6 @@ import java.io.FileOutputStream */ class BookSourceViewModel(application: Application) : BaseViewModel(application) { - init { - execute { - val sameSortNumberSize = appDb.bookSourceDao.sameSortNumberSize() - if (sameSortNumberSize > 0) { - val sources = appDb.bookSourceDao.all - sources.forEachIndexed { index, bookSource -> - bookSource.customOrder = index - appDb.bookSourceDao.update(bookSource) - } - } - } - } - fun topSource(vararg sources: BookSource) { execute { sources.sortBy { it.customOrder } @@ -64,13 +51,14 @@ class BookSourceViewModel(application: Application) : BaseViewModel(application) execute { appDb.bookSourceDao.update(*bookSource) } } - fun upOrder() { + fun upOrder(items: List) { + if (items.isEmpty()) return execute { - val sources = appDb.bookSourceDao.all - for ((index: Int, source: BookSource) in sources.withIndex()) { - source.customOrder = index + 1 + val firstSortNumber = items[0].customOrder + items.forEachIndexed { index, bookSource -> + bookSource.customOrder = firstSortNumber + index + appDb.bookSourceDao.update(bookSource) } - appDb.bookSourceDao.update(*sources.toTypedArray()) } } From 5b7117597ae54e9cc0531b91fb62816bf857ea51 Mon Sep 17 00:00:00 2001 From: Xwite <1797350009@qq.com> Date: Mon, 13 Mar 2023 05:45:12 +0800 Subject: [PATCH 04/13] fix #2868 --- .../legado/app/model/localBook/LocalBook.kt | 20 ++++++------------- .../legado/app/utils/InputStreamExtensions.kt | 12 ----------- 2 files changed, 6 insertions(+), 26 deletions(-) diff --git a/app/src/main/java/io/legado/app/model/localBook/LocalBook.kt b/app/src/main/java/io/legado/app/model/localBook/LocalBook.kt index a83d7fc9a..6f4345a53 100644 --- a/app/src/main/java/io/legado/app/model/localBook/LocalBook.kt +++ b/app/src/main/java/io/legado/app/model/localBook/LocalBook.kt @@ -156,20 +156,13 @@ object LocalBook { * 导入本地文件 */ fun importFile(uri: Uri): Book { - val bookUrl: String - val updateTime: Long + val fileDoc = FileDoc.fromUri(uri) + val fileName = fileDoc.name + val bookUrl = fileDoc.toString() //这个变量不要修改,否则会导致读取不到缓存 - val fileName = if (uri.isContentScheme()) { - bookUrl = uri.toString() - val doc = DocumentFile.fromSingleUri(appCtx, uri)!! - updateTime = doc.lastModified() - doc.name!! - } else { - bookUrl = uri.path!! - val file = File(bookUrl) - updateTime = file.lastModified() - file.name - } + val updateTime = fileDoc.lastModified + //空文件不导入 + if (fileDoc.size == 0) throw EmptyFileException("Unexpected empty File") var book = appDb.bookDao.getBook(bookUrl) if (book == null) { val nameAuthor = analyzeNameAuthor(fileName) @@ -291,7 +284,6 @@ object LocalBook { fileName: String ): Uri { inputStream.use { - if (it.isEmpty()) throw EmptyFileException("Unexpected empty inputStream") val defaultBookTreeUri = AppConfig.defaultBookTreeUri if (defaultBookTreeUri.isNullOrBlank()) throw NoStackTraceException("没有设置书籍保存位置!") val treeUri = Uri.parse(defaultBookTreeUri) diff --git a/app/src/main/java/io/legado/app/utils/InputStreamExtensions.kt b/app/src/main/java/io/legado/app/utils/InputStreamExtensions.kt index ae5fa8dd9..e36814f8e 100644 --- a/app/src/main/java/io/legado/app/utils/InputStreamExtensions.kt +++ b/app/src/main/java/io/legado/app/utils/InputStreamExtensions.kt @@ -23,15 +23,3 @@ fun InputStream?.contains(str: String): Boolean { return scanner.findWithinHorizon(str, 0) != null } } - -fun InputStream?.isEmpty(): Boolean { - this ?: return true - return if (markSupported()) { - mark(0) - val isEmpty = read(ByteArray(1)) == -1 - reset() - isEmpty - } else { - available() == 0 - } -} From 936528f5194e65fccc3be52e6bc03cb69c8f84a0 Mon Sep 17 00:00:00 2001 From: Xwite <1797350009@qq.com> Date: Mon, 13 Mar 2023 05:56:56 +0800 Subject: [PATCH 05/13] fix #2868 --- .../main/java/io/legado/app/model/localBook/LocalBook.kt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/io/legado/app/model/localBook/LocalBook.kt b/app/src/main/java/io/legado/app/model/localBook/LocalBook.kt index 6f4345a53..0cc9845b6 100644 --- a/app/src/main/java/io/legado/app/model/localBook/LocalBook.kt +++ b/app/src/main/java/io/legado/app/model/localBook/LocalBook.kt @@ -157,12 +157,12 @@ object LocalBook { */ fun importFile(uri: Uri): Book { val fileDoc = FileDoc.fromUri(uri) - val fileName = fileDoc.name + val (fileName, _, fileSize, _, updateTime, _) = FileDoc.fromUri(uri) val bookUrl = fileDoc.toString() - //这个变量不要修改,否则会导致读取不到缓存 + //updateTime变量不要修改,否则会导致读取不到缓存 val updateTime = fileDoc.lastModified //空文件不导入 - if (fileDoc.size == 0) throw EmptyFileException("Unexpected empty File") + if (fileSize == 0L) throw EmptyFileException("Unexpected empty File") var book = appDb.bookDao.getBook(bookUrl) if (book == null) { val nameAuthor = analyzeNameAuthor(fileName) From a8f74133b091ff0c98e0cb5c15bb6ca49ec4d087 Mon Sep 17 00:00:00 2001 From: Xwite <1797350009@qq.com> Date: Mon, 13 Mar 2023 05:58:06 +0800 Subject: [PATCH 06/13] fix #2868 --- app/src/main/java/io/legado/app/model/localBook/LocalBook.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/io/legado/app/model/localBook/LocalBook.kt b/app/src/main/java/io/legado/app/model/localBook/LocalBook.kt index 0cc9845b6..bf6d51717 100644 --- a/app/src/main/java/io/legado/app/model/localBook/LocalBook.kt +++ b/app/src/main/java/io/legado/app/model/localBook/LocalBook.kt @@ -156,8 +156,8 @@ object LocalBook { * 导入本地文件 */ fun importFile(uri: Uri): Book { - val fileDoc = FileDoc.fromUri(uri) - val (fileName, _, fileSize, _, updateTime, _) = FileDoc.fromUri(uri) + val fileDoc = FileDoc.fromUri(uri, false) + val (fileName, _, fileSize, _, updateTime, _) = fileDoc val bookUrl = fileDoc.toString() //updateTime变量不要修改,否则会导致读取不到缓存 val updateTime = fileDoc.lastModified From 2ccc8b2fe40bbc6014550189943afe73c334165d Mon Sep 17 00:00:00 2001 From: Xwite <1797350009@qq.com> Date: Mon, 13 Mar 2023 06:00:27 +0800 Subject: [PATCH 07/13] fix #2868 --- app/src/main/java/io/legado/app/model/localBook/LocalBook.kt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/app/src/main/java/io/legado/app/model/localBook/LocalBook.kt b/app/src/main/java/io/legado/app/model/localBook/LocalBook.kt index bf6d51717..8d629dcb6 100644 --- a/app/src/main/java/io/legado/app/model/localBook/LocalBook.kt +++ b/app/src/main/java/io/legado/app/model/localBook/LocalBook.kt @@ -157,10 +157,9 @@ object LocalBook { */ fun importFile(uri: Uri): Book { val fileDoc = FileDoc.fromUri(uri, false) + //updateTime变量不要修改,否则会导致读取不到缓存 val (fileName, _, fileSize, _, updateTime, _) = fileDoc val bookUrl = fileDoc.toString() - //updateTime变量不要修改,否则会导致读取不到缓存 - val updateTime = fileDoc.lastModified //空文件不导入 if (fileSize == 0L) throw EmptyFileException("Unexpected empty File") var book = appDb.bookDao.getBook(bookUrl) From cc21e86cfa40ee3f0d0a9ec93d5159c70d84e099 Mon Sep 17 00:00:00 2001 From: Xwite <1797350009@qq.com> Date: Mon, 13 Mar 2023 06:07:55 +0800 Subject: [PATCH 08/13] [skip ci] --- .../java/io/legado/app/model/localBook/LocalBook.kt | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/io/legado/app/model/localBook/LocalBook.kt b/app/src/main/java/io/legado/app/model/localBook/LocalBook.kt index 8d629dcb6..7a41b7d3d 100644 --- a/app/src/main/java/io/legado/app/model/localBook/LocalBook.kt +++ b/app/src/main/java/io/legado/app/model/localBook/LocalBook.kt @@ -156,12 +156,12 @@ object LocalBook { * 导入本地文件 */ fun importFile(uri: Uri): Book { - val fileDoc = FileDoc.fromUri(uri, false) + val bookUrl: String //updateTime变量不要修改,否则会导致读取不到缓存 - val (fileName, _, fileSize, _, updateTime, _) = fileDoc - val bookUrl = fileDoc.toString() - //空文件不导入 - if (fileSize == 0L) throw EmptyFileException("Unexpected empty File") + val (fileName, _, _, _, updateTime, _) = FileDoc.fromUri(uri, false).apply { + if (size == 0L) throw EmptyFileException("Unexpected empty File") + bookUrl = toString() + } var book = appDb.bookDao.getBook(bookUrl) if (book == null) { val nameAuthor = analyzeNameAuthor(fileName) From 8c180717262c18ad9445d829b449354d0ecf51a9 Mon Sep 17 00:00:00 2001 From: Xwite <1797350009@qq.com> Date: Mon, 13 Mar 2023 06:11:10 +0800 Subject: [PATCH 09/13] [skip ci] --- app/src/main/java/io/legado/app/model/localBook/LocalBook.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/model/localBook/LocalBook.kt b/app/src/main/java/io/legado/app/model/localBook/LocalBook.kt index 7a41b7d3d..bb3274239 100644 --- a/app/src/main/java/io/legado/app/model/localBook/LocalBook.kt +++ b/app/src/main/java/io/legado/app/model/localBook/LocalBook.kt @@ -158,7 +158,7 @@ object LocalBook { fun importFile(uri: Uri): Book { val bookUrl: String //updateTime变量不要修改,否则会导致读取不到缓存 - val (fileName, _, _, _, updateTime, _) = FileDoc.fromUri(uri, false).apply { + val (fileName, _, _, updateTime, _) = FileDoc.fromUri(uri, false).apply { if (size == 0L) throw EmptyFileException("Unexpected empty File") bookUrl = toString() } From 3ac79b06e4c36654635bce3d7826f6c228562527 Mon Sep 17 00:00:00 2001 From: Xwite <1797350009@qq.com> Date: Mon, 13 Mar 2023 08:10:25 +0800 Subject: [PATCH 10/13] =?UTF-8?q?=E5=AE=9E=E7=8E=B0=E6=96=87=E4=BB=B6?= =?UTF-8?q?=E7=B1=BB=E4=B9=A6=E6=BA=90=E5=8E=8B=E7=BC=A9=E6=96=87=E4=BB=B6?= =?UTF-8?q?=E8=A7=A3=E5=8E=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/io/legado/app/constant/AppPattern.kt | 2 + .../app/ui/book/info/BookInfoActivity.kt | 27 ++++++- .../app/ui/book/info/BookInfoViewModel.kt | 29 ++++++-- .../java/io/legado/app/utils/ArchiveUtils.kt | 74 +++++++++++++++++++ app/src/main/res/values-es-rES/strings.xml | 1 + app/src/main/res/values-ja-rJP/strings.xml | 1 + app/src/main/res/values-pt-rBR/strings.xml | 1 + app/src/main/res/values-zh-rHK/strings.xml | 1 + app/src/main/res/values-zh-rTW/strings.xml | 1 + app/src/main/res/values-zh/strings.xml | 1 + app/src/main/res/values/strings.xml | 1 + 11 files changed, 132 insertions(+), 7 deletions(-) create mode 100644 app/src/main/java/io/legado/app/utils/ArchiveUtils.kt diff --git a/app/src/main/java/io/legado/app/constant/AppPattern.kt b/app/src/main/java/io/legado/app/constant/AppPattern.kt index 0e999f227..c979e12ce 100644 --- a/app/src/main/java/io/legado/app/constant/AppPattern.kt +++ b/app/src/main/java/io/legado/app/constant/AppPattern.kt @@ -24,6 +24,8 @@ object AppPattern { //本地书籍支持类型 val bookFileRegex = Regex(".*\\.(txt|epub|umd|pdf)", RegexOption.IGNORE_CASE) + //压缩文件支持类型 + val archiveFileRegex = Regex(".*\\.(zip|rar|7z)", RegexOption.IGNORE_CASE) /** * 所有标点 diff --git a/app/src/main/java/io/legado/app/ui/book/info/BookInfoActivity.kt b/app/src/main/java/io/legado/app/ui/book/info/BookInfoActivity.kt index 129bc38af..379ab6363 100644 --- a/app/src/main/java/io/legado/app/ui/book/info/BookInfoActivity.kt +++ b/app/src/main/java/io/legado/app/ui/book/info/BookInfoActivity.kt @@ -507,6 +507,13 @@ class BookInfoActivity : viewModel.importOrDownloadWebFile(webFile) { onClick?.invoke(it) } + } else if (webFile.isSupportDecompress) { + /* 解压筛选后再选择导入项 */ + viewModel.importOrDownloadWebFile(webFile) { uri -> + viewModel.deCompress(uri) { + showDecompressFileImportAlert(it) + } + } } else { alert( title = getString(R.string.draw), @@ -514,8 +521,8 @@ class BookInfoActivity : ) { neutralButton(R.string.open_fun) { /* download only */ - viewModel.importOrDownloadWebFile(webFile) { uri -> - openFileUri(uri, "*/*") + viewModel.importOrDownloadWebFile(webFile) { + openFileUri(it, "*/*") } } noButton() @@ -524,6 +531,22 @@ class BookInfoActivity : } } + private fun showDecompressFileImportAlert( + fileDocs: List + ) { + if (fileDocs.isEmpty()) { + toastOnUi(R.string.unsupport_archivefile_entry) + return + } + val selectorNames = fileDocs.map { it.name } + selector( + R.string.import_select_book, + selectorNames + ) { _, _, index -> + viewModel.importBook(fileDocs[index]) + } + } + private fun readBook(book: Book) { if (!viewModel.inBookshelf) { viewModel.saveBook(book) { 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 f73f7601d..aa325b73e 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 @@ -25,9 +25,7 @@ import io.legado.app.model.BookCover import io.legado.app.model.ReadBook import io.legado.app.model.localBook.LocalBook import io.legado.app.model.webBook.WebBook -import io.legado.app.utils.isContentScheme -import io.legado.app.utils.postEvent -import io.legado.app.utils.toastOnUi +import io.legado.app.utils.* import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers.IO @@ -242,7 +240,8 @@ class BookInfoViewModel(application: Application) : BaseViewModel(application) { book.downloadUrls!!.map { val mFileName = "${fileName}.${LocalBook.parseFileSuffix(it)}" val isSupportedFile = AppPattern.bookFileRegex.matches(mFileName) - WebFile(it, mFileName, isSupportedFile) + val isSupportDecompress = AppPattern.archiveFileRegex.matches(mFileName) + WebFile(it, mFileName, isSupportedFile, isSupportDecompress) } }.onError { context.toastOnUi("LoadWebFileError\n${it.localizedMessage}") @@ -251,6 +250,7 @@ class BookInfoViewModel(application: Application) : BaseViewModel(application) { } } + /* 导入或者下载在线文件 */ fun importOrDownloadWebFile(webFile: WebFile, success: ((T) -> Unit)?) { bookSource ?: return execute { @@ -272,6 +272,22 @@ class BookInfoViewModel(application: Application) : BaseViewModel(application) { } } + fun deCompress(archiveFileUri: Uri, onSuccess: (List) -> Unit) { + execute { + ArchiveUtils.deCompress(archiveFileUri).list { + AppPattern.bookFileRegex.matches(it.name) + } ?: emptyList() + }.onError { + context.toastOnUi("DeCompress Error:\n${it.localizedMessage}") + }.onSuccess { + onSuccess.invoke(it) + } + } + + fun importBook(fileDoc: FileDoc) { + LocalBook.importFile(fileDoc.uri).let { changeToLocalBook(it) } + } + fun changeTo(source: BookSource, book: Book, toc: List) { changeSourceCoroutine?.cancel() changeSourceCoroutine = execute { @@ -398,7 +414,10 @@ class BookInfoViewModel(application: Application) : BaseViewModel(application) { data class WebFile( val url: String, val name: String, - val isSupported: Boolean + // txt epub umd pdf等文件 + val isSupported: Boolean, + // 压缩包形式的txt epub umd pdf文件 + val isSupportDecompress: Boolean ) { override fun toString(): String { return name diff --git a/app/src/main/java/io/legado/app/utils/ArchiveUtils.kt b/app/src/main/java/io/legado/app/utils/ArchiveUtils.kt new file mode 100644 index 000000000..eb08550ab --- /dev/null +++ b/app/src/main/java/io/legado/app/utils/ArchiveUtils.kt @@ -0,0 +1,74 @@ +package io.legado.app.utils + +import android.net.Uri +import androidx.documentfile.provider.DocumentFile +import java.io.File +import java.util.regex.Pattern + +import splitties.init.appCtx + +/* 自动判断压缩文件后缀 然后再调用具体的实现 */ +object ArchiveUtils { + + // 临时目录 下次启动自动删除 + val TEMP_PATH: String by lazy { + appCtx.externalCache.getFile("ArchiveTemp").createFolderReplace().absolutePath + } + + val ZIP_REGEX = Regex(".*\\.zip", RegexOption.IGNORE_CASE) + val RAR_REGEX = Regex(".*\\.rar", RegexOption.IGNORE_CASE) + val SERVEZ_REGEX = Regex(".*\\.7z", RegexOption.IGNORE_CASE) + + fun deCompress( + archiveUri: Uri, + path: String? = TEMP_PATH + ): FileDoc { + return deCompress(FileDoc.fromUri(archiveUri, false), path) + } + + fun deCompress( + archivePath: String, + path: String? = TEMP_PATH + ): FileDoc { + return deCompress(Uri.parse(archivePath)), false), path) + } + + fun deCompress( + archiveFile: File, + path: String? = TEMP_PATH + ): FileDoc { + return deCompress(FileDoc.fromFile(archiveFile), path) + } + + fun deCompress( + archiveDoc: DocumentFile, + path: String? = TEMP_PATH + ): FileDoc { + return deCompress(FileDoc.fromDocumentFile(archiveDoc), path) + } + + fun deCompress( + archiveFileDoc: FileDoc, + path: String? = TEMP_PATH + ): FileDoc { + if (archiveFileDoc.isDir) throw IllegalArgumentException("Unexpected Folder input") + val name = archiveFileDoc.name + archiveFileDoc.uri.inputStream(appCtx).getOrThrow().use { + when { + ZIP_REGEX.matches(name) -> ZipUtils.unZipToPath(it, path) + RAR_REGEX.matches(name) -> RarUtils.unRarToPath(it, path) + SERVEZ_REGEX.matches(name) -> SevenZipUtils.un7zToPath(it, path) + else -> throw IllegalArgumentException("Unexpected archive format") + } + } + return getCacheFolderFileDoc(name, path) + } + + private fun getCacheFolderFileDoc( + archiveName: String, + workPath: String + ): FileDoc { + return FileDoc.fromUri(Uri.parse(workPath), true) + .createFolderIfNotExist(MD5Utils.md5Encode16(archiveName)) + } +} \ No newline at end of file diff --git a/app/src/main/res/values-es-rES/strings.xml b/app/src/main/res/values-es-rES/strings.xml index 4343c31e6..9f57dbfa3 100644 --- a/app/src/main/res/values-es-rES/strings.xml +++ b/app/src/main/res/values-es-rES/strings.xml @@ -1080,4 +1080,5 @@ 保留分组 服务器配置 Remote webDav url exists, Continue? + Cannot find supported files in archive diff --git a/app/src/main/res/values-ja-rJP/strings.xml b/app/src/main/res/values-ja-rJP/strings.xml index b7885f90e..0db86d8a4 100644 --- a/app/src/main/res/values-ja-rJP/strings.xml +++ b/app/src/main/res/values-ja-rJP/strings.xml @@ -1083,4 +1083,5 @@ 保留分组 服务器配置 Remote webDav url exists, Continue? + Cannot find supported files in archive diff --git a/app/src/main/res/values-pt-rBR/strings.xml b/app/src/main/res/values-pt-rBR/strings.xml index 859049346..17a8f285f 100644 --- a/app/src/main/res/values-pt-rBR/strings.xml +++ b/app/src/main/res/values-pt-rBR/strings.xml @@ -1083,4 +1083,5 @@ 保留分组 服务器配置 Remote webDav url exists, Continue? + Cannot find supported files in archive diff --git a/app/src/main/res/values-zh-rHK/strings.xml b/app/src/main/res/values-zh-rHK/strings.xml index 902830842..4e33cc53a 100644 --- a/app/src/main/res/values-zh-rHK/strings.xml +++ b/app/src/main/res/values-zh-rHK/strings.xml @@ -1080,4 +1080,5 @@ 保留分组 服务器配置 远程webDav链接已存在,是否继续 + 压缩文件内没有支持的文件 diff --git a/app/src/main/res/values-zh-rTW/strings.xml b/app/src/main/res/values-zh-rTW/strings.xml index d90258a84..91f3058a0 100644 --- a/app/src/main/res/values-zh-rTW/strings.xml +++ b/app/src/main/res/values-zh-rTW/strings.xml @@ -1082,4 +1082,5 @@ 保留分组 服务器配置 远程webDav链接已存在,是否继续 + 压缩文件内没有支持的文件 diff --git a/app/src/main/res/values-zh/strings.xml b/app/src/main/res/values-zh/strings.xml index cc4582ccc..5dacb47c1 100644 --- a/app/src/main/res/values-zh/strings.xml +++ b/app/src/main/res/values-zh/strings.xml @@ -1082,4 +1082,5 @@ 保留分组 服务器配置 远程webDav链接已存在,是否继续 + 压缩文件内没有支持的文件 diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index c4440b8a2..468fcb9db 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1083,4 +1083,5 @@ Keep group 服务器配置 Remote webDav url exists, Continue? + Cannot find supported files in archive From e540c4f3ed8e64495a63027cf87f72a20d645681 Mon Sep 17 00:00:00 2001 From: Xwite <1797350009@qq.com> Date: Mon, 13 Mar 2023 08:15:48 +0800 Subject: [PATCH 11/13] =?UTF-8?q?=E5=AE=9E=E7=8E=B0=E6=96=87=E4=BB=B6?= =?UTF-8?q?=E7=B1=BB=E4=B9=A6=E6=BA=90=E5=8E=8B=E7=BC=A9=E6=96=87=E4=BB=B6?= =?UTF-8?q?=E8=A7=A3=E5=8E=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/src/main/java/io/legado/app/utils/ArchiveUtils.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/utils/ArchiveUtils.kt b/app/src/main/java/io/legado/app/utils/ArchiveUtils.kt index eb08550ab..66fdabbdb 100644 --- a/app/src/main/java/io/legado/app/utils/ArchiveUtils.kt +++ b/app/src/main/java/io/legado/app/utils/ArchiveUtils.kt @@ -30,7 +30,7 @@ object ArchiveUtils { archivePath: String, path: String? = TEMP_PATH ): FileDoc { - return deCompress(Uri.parse(archivePath)), false), path) + return deCompress(Uri.parse(archivePath), path) } fun deCompress( From 340f537be02f2ac0a5f66d0ca2afa962712f2e22 Mon Sep 17 00:00:00 2001 From: Xwite <82232510+Xwite@users.noreply.github.com> Date: Mon, 13 Mar 2023 08:21:22 +0800 Subject: [PATCH 12/13] Update updateLog.md --- app/src/main/assets/updateLog.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/app/src/main/assets/updateLog.md b/app/src/main/assets/updateLog.md index 8985ed248..282edc7fd 100644 --- a/app/src/main/assets/updateLog.md +++ b/app/src/main/assets/updateLog.md @@ -13,6 +13,9 @@ * 正文出现缺字漏字、内容缺失、排版错乱等情况,有可能是净化规则或简繁转换出现问题。 * 漫画源看书显示乱码,**阅读与其他软件的源并不通用**,请导入阅读的支持的漫画源! +**2023/03/13** +* 文件类书源支持zip 7z rar4解压 + **2023/03/12** * 远程书籍添加webDav多配置 From 866e943d349077328a89e5d7479bfd1d5a776b50 Mon Sep 17 00:00:00 2001 From: Xwite <1797350009@qq.com> Date: Mon, 13 Mar 2023 08:27:32 +0800 Subject: [PATCH 13/13] =?UTF-8?q?=E5=AE=9E=E7=8E=B0=E6=96=87=E4=BB=B6?= =?UTF-8?q?=E7=B1=BB=E4=B9=A6=E6=BA=90=E5=8E=8B=E7=BC=A9=E6=96=87=E4=BB=B6?= =?UTF-8?q?=E8=A7=A3=E5=8E=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/src/main/java/io/legado/app/utils/ArchiveUtils.kt | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/io/legado/app/utils/ArchiveUtils.kt b/app/src/main/java/io/legado/app/utils/ArchiveUtils.kt index 66fdabbdb..1e1954a30 100644 --- a/app/src/main/java/io/legado/app/utils/ArchiveUtils.kt +++ b/app/src/main/java/io/legado/app/utils/ArchiveUtils.kt @@ -21,35 +21,35 @@ object ArchiveUtils { fun deCompress( archiveUri: Uri, - path: String? = TEMP_PATH + path: String = TEMP_PATH ): FileDoc { return deCompress(FileDoc.fromUri(archiveUri, false), path) } fun deCompress( archivePath: String, - path: String? = TEMP_PATH + path: String = TEMP_PATH ): FileDoc { return deCompress(Uri.parse(archivePath), path) } fun deCompress( archiveFile: File, - path: String? = TEMP_PATH + path: String = TEMP_PATH ): FileDoc { return deCompress(FileDoc.fromFile(archiveFile), path) } fun deCompress( archiveDoc: DocumentFile, - path: String? = TEMP_PATH + path: String = TEMP_PATH ): FileDoc { return deCompress(FileDoc.fromDocumentFile(archiveDoc), path) } fun deCompress( archiveFileDoc: FileDoc, - path: String? = TEMP_PATH + path: String = TEMP_PATH ): FileDoc { if (archiveFileDoc.isDir) throw IllegalArgumentException("Unexpected Folder input") val name = archiveFileDoc.name