@@ -18,14 +18,14 @@ import io.legado.app.lib.webdav.WebDav
|
|||||||
import io.legado.app.lib.webdav.WebDavException
|
import io.legado.app.lib.webdav.WebDavException
|
||||||
import io.legado.app.lib.webdav.WebDavFile
|
import io.legado.app.lib.webdav.WebDavFile
|
||||||
import io.legado.app.utils.*
|
import io.legado.app.utils.*
|
||||||
|
import kotlinx.coroutines.*
|
||||||
import kotlinx.coroutines.Dispatchers.IO
|
import kotlinx.coroutines.Dispatchers.IO
|
||||||
import kotlinx.coroutines.Dispatchers.Main
|
import kotlinx.coroutines.Dispatchers.Main
|
||||||
import kotlinx.coroutines.runBlocking
|
|
||||||
import kotlinx.coroutines.withContext
|
|
||||||
import splitties.init.appCtx
|
import splitties.init.appCtx
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.text.SimpleDateFormat
|
import java.text.SimpleDateFormat
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
import kotlin.coroutines.coroutineContext
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* webDav初始化会访问网络,不要放到主线程
|
* webDav初始化会访问网络,不要放到主线程
|
||||||
@@ -102,6 +102,7 @@ object AppWebDav {
|
|||||||
suspend fun showRestoreDialog(context: Context) {
|
suspend fun showRestoreDialog(context: Context) {
|
||||||
val names = withContext(IO) { getBackupNames() }
|
val names = withContext(IO) { getBackupNames() }
|
||||||
if (names.isNotEmpty()) {
|
if (names.isNotEmpty()) {
|
||||||
|
coroutineContext.ensureActive()
|
||||||
withContext(Main) {
|
withContext(Main) {
|
||||||
context.selector(
|
context.selector(
|
||||||
title = context.getString(R.string.select_restore_file),
|
title = context.getString(R.string.select_restore_file),
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import io.legado.app.help.config.ThemeConfig
|
|||||||
import io.legado.app.help.coroutine.Coroutine
|
import io.legado.app.help.coroutine.Coroutine
|
||||||
import io.legado.app.utils.*
|
import io.legado.app.utils.*
|
||||||
import kotlinx.coroutines.Dispatchers.IO
|
import kotlinx.coroutines.Dispatchers.IO
|
||||||
|
import kotlinx.coroutines.ensureActive
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
import splitties.init.appCtx
|
import splitties.init.appCtx
|
||||||
import java.io.File
|
import java.io.File
|
||||||
@@ -75,6 +76,7 @@ object Backup {
|
|||||||
writeListToJson(appDb.bookSourceDao.all, "bookSource.json", backupPath)
|
writeListToJson(appDb.bookSourceDao.all, "bookSource.json", backupPath)
|
||||||
writeListToJson(appDb.rssSourceDao.all, "rssSources.json", backupPath)
|
writeListToJson(appDb.rssSourceDao.all, "rssSources.json", backupPath)
|
||||||
writeListToJson(appDb.rssStarDao.all, "rssStar.json", backupPath)
|
writeListToJson(appDb.rssStarDao.all, "rssStar.json", backupPath)
|
||||||
|
ensureActive()
|
||||||
writeListToJson(appDb.replaceRuleDao.all, "replaceRule.json", backupPath)
|
writeListToJson(appDb.replaceRuleDao.all, "replaceRule.json", backupPath)
|
||||||
writeListToJson(appDb.readRecordDao.all, "readRecord.json", backupPath)
|
writeListToJson(appDb.readRecordDao.all, "readRecord.json", backupPath)
|
||||||
writeListToJson(appDb.searchKeywordDao.all, "searchHistory.json", backupPath)
|
writeListToJson(appDb.searchKeywordDao.all, "searchHistory.json", backupPath)
|
||||||
@@ -82,6 +84,7 @@ object Backup {
|
|||||||
writeListToJson(appDb.txtTocRuleDao.all, "txtTocRule.json", backupPath)
|
writeListToJson(appDb.txtTocRuleDao.all, "txtTocRule.json", backupPath)
|
||||||
writeListToJson(appDb.httpTTSDao.all, "httpTTS.json", backupPath)
|
writeListToJson(appDb.httpTTSDao.all, "httpTTS.json", backupPath)
|
||||||
writeListToJson(appDb.keyboardAssistsDao.all, "keyboardAssists.json", backupPath)
|
writeListToJson(appDb.keyboardAssistsDao.all, "keyboardAssists.json", backupPath)
|
||||||
|
ensureActive()
|
||||||
GSON.toJson(ReadBookConfig.configList).let {
|
GSON.toJson(ReadBookConfig.configList).let {
|
||||||
FileUtils.createFileIfNotExist(backupPath + File.separator + ReadBookConfig.configFileName)
|
FileUtils.createFileIfNotExist(backupPath + File.separator + ReadBookConfig.configFileName)
|
||||||
.writeText(it)
|
.writeText(it)
|
||||||
@@ -98,6 +101,7 @@ object Backup {
|
|||||||
FileUtils.createFileIfNotExist(backupPath + File.separator + DirectLinkUpload.ruleFileName)
|
FileUtils.createFileIfNotExist(backupPath + File.separator + DirectLinkUpload.ruleFileName)
|
||||||
.writeText(GSON.toJson(it))
|
.writeText(GSON.toJson(it))
|
||||||
}
|
}
|
||||||
|
ensureActive()
|
||||||
Preferences.getSharedPreferences(appCtx, backupPath, "config")?.let { sp ->
|
Preferences.getSharedPreferences(appCtx, backupPath, "config")?.let { sp ->
|
||||||
val edit = sp.edit()
|
val edit = sp.edit()
|
||||||
appCtx.defaultSharedPreferences.all.forEach { (key, value) ->
|
appCtx.defaultSharedPreferences.all.forEach { (key, value) ->
|
||||||
@@ -113,6 +117,7 @@ object Backup {
|
|||||||
}
|
}
|
||||||
edit.commit()
|
edit.commit()
|
||||||
}
|
}
|
||||||
|
ensureActive()
|
||||||
when {
|
when {
|
||||||
path.isNullOrBlank() -> {
|
path.isNullOrBlank() -> {
|
||||||
copyBackup(context.getExternalFilesDir(null)!!, false)
|
copyBackup(context.getExternalFilesDir(null)!!, false)
|
||||||
|
|||||||
@@ -33,9 +33,10 @@ import io.legado.app.lib.prefs.fragment.PreferenceFragment
|
|||||||
import io.legado.app.lib.theme.primaryColor
|
import io.legado.app.lib.theme.primaryColor
|
||||||
import io.legado.app.ui.document.HandleFileContract
|
import io.legado.app.ui.document.HandleFileContract
|
||||||
import io.legado.app.ui.widget.dialog.TextDialog
|
import io.legado.app.ui.widget.dialog.TextDialog
|
||||||
|
import io.legado.app.ui.widget.dialog.WaitDialog
|
||||||
import io.legado.app.utils.*
|
import io.legado.app.utils.*
|
||||||
|
import kotlinx.coroutines.*
|
||||||
import kotlinx.coroutines.Dispatchers.Main
|
import kotlinx.coroutines.Dispatchers.Main
|
||||||
import kotlinx.coroutines.launch
|
|
||||||
import splitties.init.appCtx
|
import splitties.init.appCtx
|
||||||
import kotlin.collections.set
|
import kotlin.collections.set
|
||||||
|
|
||||||
@@ -44,6 +45,9 @@ class BackupConfigFragment : PreferenceFragment(),
|
|||||||
MenuProvider {
|
MenuProvider {
|
||||||
|
|
||||||
private val viewModel by activityViewModels<ConfigViewModel>()
|
private val viewModel by activityViewModels<ConfigViewModel>()
|
||||||
|
private val waitDialog by lazy { WaitDialog(requireContext()) }
|
||||||
|
private var backupJob: Job? = null
|
||||||
|
private var restoreJob: Job? = null
|
||||||
|
|
||||||
private val selectBackupPath = registerForActivityResult(HandleFileContract()) {
|
private val selectBackupPath = registerForActivityResult(HandleFileContract()) {
|
||||||
it.uri?.let { uri ->
|
it.uri?.let { uri ->
|
||||||
@@ -245,7 +249,13 @@ class BackupConfigFragment : PreferenceFragment(),
|
|||||||
val uri = Uri.parse(backupPath)
|
val uri = Uri.parse(backupPath)
|
||||||
val doc = DocumentFile.fromTreeUri(requireContext(), uri)
|
val doc = DocumentFile.fromTreeUri(requireContext(), uri)
|
||||||
if (doc?.canWrite() == true) {
|
if (doc?.canWrite() == true) {
|
||||||
|
waitDialog.setText("备份中…")
|
||||||
|
waitDialog.setOnCancelListener {
|
||||||
|
backupJob?.cancel()
|
||||||
|
}
|
||||||
|
waitDialog.show()
|
||||||
Coroutine.async {
|
Coroutine.async {
|
||||||
|
backupJob = coroutineContext[Job]
|
||||||
Backup.backup(requireContext(), backupPath)
|
Backup.backup(requireContext(), backupPath)
|
||||||
}.onSuccess {
|
}.onSuccess {
|
||||||
appCtx.toastOnUi(R.string.backup_success)
|
appCtx.toastOnUi(R.string.backup_success)
|
||||||
@@ -257,6 +267,8 @@ class BackupConfigFragment : PreferenceFragment(),
|
|||||||
it.localizedMessage
|
it.localizedMessage
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
}.onFinally(Main) {
|
||||||
|
waitDialog.dismiss()
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
backupDir.launch()
|
backupDir.launch()
|
||||||
@@ -272,7 +284,13 @@ class BackupConfigFragment : PreferenceFragment(),
|
|||||||
.addPermissions(*Permissions.Group.STORAGE)
|
.addPermissions(*Permissions.Group.STORAGE)
|
||||||
.rationale(R.string.tip_perm_request_storage)
|
.rationale(R.string.tip_perm_request_storage)
|
||||||
.onGranted {
|
.onGranted {
|
||||||
|
waitDialog.setText("备份中…")
|
||||||
|
waitDialog.setOnCancelListener {
|
||||||
|
backupJob?.cancel()
|
||||||
|
}
|
||||||
|
waitDialog.show()
|
||||||
Coroutine.async {
|
Coroutine.async {
|
||||||
|
backupJob = coroutineContext[Job]
|
||||||
AppConfig.backupPath = path
|
AppConfig.backupPath = path
|
||||||
Backup.backup(requireContext(), path)
|
Backup.backup(requireContext(), path)
|
||||||
}.onSuccess {
|
}.onSuccess {
|
||||||
@@ -280,13 +298,21 @@ class BackupConfigFragment : PreferenceFragment(),
|
|||||||
}.onError {
|
}.onError {
|
||||||
AppLog.put("备份出错\n${it.localizedMessage}", it)
|
AppLog.put("备份出错\n${it.localizedMessage}", it)
|
||||||
appCtx.toastOnUi(appCtx.getString(R.string.backup_fail, it.localizedMessage))
|
appCtx.toastOnUi(appCtx.getString(R.string.backup_fail, it.localizedMessage))
|
||||||
|
}.onFinally(Main) {
|
||||||
|
waitDialog.dismiss()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.request()
|
.request()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun restore() {
|
fun restore() {
|
||||||
|
waitDialog.setText(R.string.loading)
|
||||||
|
waitDialog.setOnCancelListener {
|
||||||
|
restoreJob?.cancel()
|
||||||
|
}
|
||||||
|
waitDialog.show()
|
||||||
Coroutine.async {
|
Coroutine.async {
|
||||||
|
restoreJob = coroutineContext[Job]
|
||||||
AppWebDav.showRestoreDialog(requireContext())
|
AppWebDav.showRestoreDialog(requireContext())
|
||||||
}.onError {
|
}.onError {
|
||||||
alert {
|
alert {
|
||||||
@@ -297,6 +323,8 @@ class BackupConfigFragment : PreferenceFragment(),
|
|||||||
}
|
}
|
||||||
cancelButton()
|
cancelButton()
|
||||||
}
|
}
|
||||||
|
}.onFinally(Main) {
|
||||||
|
waitDialog.dismiss()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user