kunfei 3 лет назад
Родитель
Сommit
0624737725

+ 6 - 0
app/src/main/assets/updateLog.md

@@ -12,7 +12,13 @@
 * 正文出现缺字漏字、内容缺失、排版错乱等情况,有可能是净化规则或简繁转换出现问题。
 * 漫画源看书显示乱码,**阅读与其他软件的源并不通用**,请导入阅读的支持的漫画源!
 
+**2023/08/02**
+
+* 书签导出md格式
+* 优化进度同步,减少webDav下载次数
+
 **2023/07/30**
+
 * 更新cronet: 115.0.5790.138
 
 * 更新cronet: 115.0.5790.136

+ 16 - 1
app/src/main/java/io/legado/app/help/AppWebDav.kt

@@ -159,7 +159,7 @@ object AppWebDav {
     /**
      * 获取云端所有背景名称
      */
-    suspend fun getAllBgNames(): Result<List<WebDavFile>> {
+    suspend fun getAllBgWebDavFiles(): Result<List<WebDavFile>> {
         return kotlin.runCatching {
             if (!NetworkUtils.isAvailable())
                 throw NoStackTraceException("网络未连接")
@@ -170,6 +170,21 @@ object AppWebDav {
         }
     }
 
+    /**
+     * 上传背景图片
+     */
+    suspend fun upBgs(files: List<File>) {
+        val authorization = authorization ?: return
+        if (!NetworkUtils.isAvailable()) return
+    }
+
+    /**
+     * 下载背景图片
+     */
+    suspend fun downBgs(fileNames: String) {
+        val authorization = authorization ?: return
+        if (!NetworkUtils.isAvailable()) return
+    }
 
     suspend fun exportWebDav(byteArray: ByteArray, fileName: String) {
         if (!NetworkUtils.isAvailable()) return

+ 6 - 2
app/src/main/java/io/legado/app/help/coroutine/Coroutine.kt

@@ -113,7 +113,9 @@ class Coroutine<T>(
         return this@Coroutine
     }
 
-    // 如果协程被取消,有可能会不执行
+    /**
+     * 如果协程被取消,不执行
+     */
     fun onFinally(
         context: CoroutineContext? = null,
         block: suspend CoroutineScope.() -> Unit
@@ -187,7 +189,9 @@ class Coroutine<T>(
 
     private suspend inline fun dispatchVoidCallback(scope: CoroutineScope, callback: VoidCallback) {
         if (null == callback.context) {
-            callback.block.invoke(scope)
+            withContext(scope.coroutineContext) {
+                callback.block.invoke(scope)
+            }
         } else {
             withContext(scope.coroutineContext + callback.context) {
                 callback.block.invoke(this)

+ 94 - 93
app/src/main/java/io/legado/app/help/storage/Backup.kt

@@ -27,6 +27,7 @@ import java.io.FileOutputStream
 import java.text.SimpleDateFormat
 import java.util.*
 import java.util.concurrent.TimeUnit
+import kotlin.coroutines.coroutineContext
 
 /**
  * 备份
@@ -92,113 +93,113 @@ object Backup {
 
     suspend fun backup(context: Context, path: String?) {
         LocalConfig.lastBackup = System.currentTimeMillis()
-        withContext(IO) {
-            val aes = BackupAES()
-            FileUtils.delete(backupPath)
-            writeListToJson(appDb.bookDao.all, "bookshelf.json", backupPath)
-            writeListToJson(appDb.bookmarkDao.all, "bookmark.json", backupPath)
-            writeListToJson(appDb.bookGroupDao.all, "bookGroup.json", backupPath)
-            writeListToJson(appDb.bookSourceDao.all, "bookSource.json", backupPath)
-            writeListToJson(appDb.rssSourceDao.all, "rssSources.json", backupPath)
-            writeListToJson(appDb.rssStarDao.all, "rssStar.json", backupPath)
-            ensureActive()
-            writeListToJson(appDb.replaceRuleDao.all, "replaceRule.json", backupPath)
-            writeListToJson(appDb.readRecordDao.all, "readRecord.json", backupPath)
-            writeListToJson(appDb.searchKeywordDao.all, "searchHistory.json", backupPath)
-            writeListToJson(appDb.ruleSubDao.all, "sourceSub.json", backupPath)
-            writeListToJson(appDb.txtTocRuleDao.all, "txtTocRule.json", backupPath)
-            writeListToJson(appDb.httpTTSDao.all, "httpTTS.json", backupPath)
-            writeListToJson(appDb.keyboardAssistsDao.all, "keyboardAssists.json", backupPath)
-            writeListToJson(appDb.dictRuleDao.all, "dictRule.json", backupPath)
-            GSON.toJson(appDb.serverDao.all).let { json ->
-                aes.runCatching {
-                    encryptBase64(json)
-                }.getOrDefault(json).let {
-                    FileUtils.createFileIfNotExist(backupPath + File.separator + "servers.json")
-                        .writeText(it)
-                }
-            }
-            ensureActive()
-            GSON.toJson(ReadBookConfig.configList).let {
-                FileUtils.createFileIfNotExist(backupPath + File.separator + ReadBookConfig.configFileName)
-                    .writeText(it)
-            }
-            GSON.toJson(ReadBookConfig.shareConfig).let {
-                FileUtils.createFileIfNotExist(backupPath + File.separator + ReadBookConfig.shareConfigFileName)
-                    .writeText(it)
-            }
-            GSON.toJson(ThemeConfig.configList).let {
-                FileUtils.createFileIfNotExist(backupPath + File.separator + ThemeConfig.configFileName)
+        val aes = BackupAES()
+        FileUtils.delete(backupPath)
+        writeListToJson(appDb.bookDao.all, "bookshelf.json", backupPath)
+        writeListToJson(appDb.bookmarkDao.all, "bookmark.json", backupPath)
+        writeListToJson(appDb.bookGroupDao.all, "bookGroup.json", backupPath)
+        writeListToJson(appDb.bookSourceDao.all, "bookSource.json", backupPath)
+        writeListToJson(appDb.rssSourceDao.all, "rssSources.json", backupPath)
+        writeListToJson(appDb.rssStarDao.all, "rssStar.json", backupPath)
+        writeListToJson(appDb.replaceRuleDao.all, "replaceRule.json", backupPath)
+        writeListToJson(appDb.readRecordDao.all, "readRecord.json", backupPath)
+        writeListToJson(appDb.searchKeywordDao.all, "searchHistory.json", backupPath)
+        writeListToJson(appDb.ruleSubDao.all, "sourceSub.json", backupPath)
+        writeListToJson(appDb.txtTocRuleDao.all, "txtTocRule.json", backupPath)
+        writeListToJson(appDb.httpTTSDao.all, "httpTTS.json", backupPath)
+        writeListToJson(appDb.keyboardAssistsDao.all, "keyboardAssists.json", backupPath)
+        writeListToJson(appDb.dictRuleDao.all, "dictRule.json", backupPath)
+        GSON.toJson(appDb.serverDao.all).let { json ->
+            aes.runCatching {
+                encryptBase64(json)
+            }.getOrDefault(json).let {
+                FileUtils.createFileIfNotExist(backupPath + File.separator + "servers.json")
                     .writeText(it)
             }
-            DirectLinkUpload.getConfig()?.let {
-                FileUtils.createFileIfNotExist(backupPath + File.separator + DirectLinkUpload.ruleFileName)
-                    .writeText(GSON.toJson(it))
-            }
-            ensureActive()
-            appCtx.getSharedPreferences(backupPath, "config")?.let { sp ->
-                val edit = sp.edit()
-                appCtx.defaultSharedPreferences.all.forEach { (key, value) ->
-                    if (BackupConfig.keyIsNotIgnore(key)) {
-                        when (key) {
-                            PreferKey.webDavPassword -> {
-                                edit.putString(key, aes.runCatching {
-                                    encryptBase64(value.toString())
-                                }.getOrDefault(value.toString()))
-                            }
+        }
+        coroutineContext.ensureActive()
+        GSON.toJson(ReadBookConfig.configList).let {
+            FileUtils.createFileIfNotExist(backupPath + File.separator + ReadBookConfig.configFileName)
+                .writeText(it)
+        }
+        GSON.toJson(ReadBookConfig.shareConfig).let {
+            FileUtils.createFileIfNotExist(backupPath + File.separator + ReadBookConfig.shareConfigFileName)
+                .writeText(it)
+        }
+        GSON.toJson(ThemeConfig.configList).let {
+            FileUtils.createFileIfNotExist(backupPath + File.separator + ThemeConfig.configFileName)
+                .writeText(it)
+        }
+        DirectLinkUpload.getConfig()?.let {
+            FileUtils.createFileIfNotExist(backupPath + File.separator + DirectLinkUpload.ruleFileName)
+                .writeText(GSON.toJson(it))
+        }
+        coroutineContext.ensureActive()
+        appCtx.getSharedPreferences(backupPath, "config")?.let { sp ->
+            val edit = sp.edit()
+            appCtx.defaultSharedPreferences.all.forEach { (key, value) ->
+                if (BackupConfig.keyIsNotIgnore(key)) {
+                    when (key) {
+                        PreferKey.webDavPassword -> {
+                            edit.putString(key, aes.runCatching {
+                                encryptBase64(value.toString())
+                            }.getOrDefault(value.toString()))
+                        }
 
-                            else -> when (value) {
-                                is Int -> edit.putInt(key, value)
-                                is Boolean -> edit.putBoolean(key, value)
-                                is Long -> edit.putLong(key, value)
-                                is Float -> edit.putFloat(key, value)
-                                is String -> edit.putString(key, value)
-                            }
+                        else -> when (value) {
+                            is Int -> edit.putInt(key, value)
+                            is Boolean -> edit.putBoolean(key, value)
+                            is Long -> edit.putLong(key, value)
+                            is Float -> edit.putFloat(key, value)
+                            is String -> edit.putString(key, value)
                         }
                     }
                 }
-                edit.commit()
-            }
-            ensureActive()
-            val zipFileName = getNowZipFileName()
-            val paths = arrayListOf(*backupFileNames)
-            for (i in 0 until paths.size) {
-                paths[i] = backupPath + File.separator + paths[i]
             }
-            FileUtils.delete(zipFilePath)
-            FileUtils.delete(zipFilePath.replace("tmp_", ""))
-            val backupFileName = if (AppConfig.onlyLatestBackup) {
-                "backup.zip"
-            } else {
-                zipFileName
-            }
-            if (ZipUtils.zipFiles(paths, zipFilePath)) {
-                when {
-                    path.isNullOrBlank() -> {
-                        copyBackup(context.getExternalFilesDir(null)!!, backupFileName)
-                    }
+            edit.commit()
+        }
+        coroutineContext.ensureActive()
+        val zipFileName = getNowZipFileName()
+        val paths = arrayListOf(*backupFileNames)
+        for (i in 0 until paths.size) {
+            paths[i] = backupPath + File.separator + paths[i]
+        }
+        FileUtils.delete(zipFilePath)
+        FileUtils.delete(zipFilePath.replace("tmp_", ""))
+        val backupFileName = if (AppConfig.onlyLatestBackup) {
+            "backup.zip"
+        } else {
+            zipFileName
+        }
+        if (ZipUtils.zipFiles(paths, zipFilePath)) {
+            when {
+                path.isNullOrBlank() -> {
+                    copyBackup(context.getExternalFilesDir(null)!!, backupFileName)
+                }
 
-                    path.isContentScheme() -> {
-                        copyBackup(context, Uri.parse(path), backupFileName)
-                    }
+                path.isContentScheme() -> {
+                    copyBackup(context, Uri.parse(path), backupFileName)
+                }
 
-                    else -> {
-                        copyBackup(File(path), backupFileName)
-                    }
+                else -> {
+                    copyBackup(File(path), backupFileName)
                 }
-                AppWebDav.backUpWebDav(zipFileName)
             }
-            FileUtils.delete(backupPath)
-            FileUtils.delete(zipFilePath)
+            AppWebDav.backUpWebDav(zipFileName)
         }
+        FileUtils.delete(backupPath)
+        FileUtils.delete(zipFilePath)
     }
 
-    private fun writeListToJson(list: List<Any>, fileName: String, path: String) {
-        if (list.isNotEmpty()) {
-            val file = FileUtils.createFileIfNotExist(path + File.separator + fileName)
-            FileOutputStream(file).use { fos ->
-                BufferedOutputStream(fos, 64 * 1024).use {
-                    GSON.writeToOutputStream(it, list)
+    private suspend fun writeListToJson(list: List<Any>, fileName: String, path: String) {
+        coroutineContext.ensureActive()
+        withContext(IO) {
+            if (list.isNotEmpty()) {
+                val file = FileUtils.createFileIfNotExist(path + File.separator + fileName)
+                FileOutputStream(file).use { fos ->
+                    BufferedOutputStream(fos, 64 * 1024).use {
+                        GSON.writeToOutputStream(it, list)
+                    }
                 }
             }
         }

+ 1 - 1
app/src/main/java/io/legado/app/ui/book/search/SearchActivity.kt

@@ -269,7 +269,7 @@ class SearchActivity : VMBaseActivity<ActivityBookSearchBinding, SearchViewModel
         viewModel.searchBookLiveData.observe(this) {
             adapter.setItems(it)
         }
-        lifecycleScope.launch(IO) {
+        lifecycleScope.launch {
             appDb.bookSourceDao.flowEnabledGroups().collect {
                 groups = it
             }