This commit is contained in:
kunfei 2020-02-09 09:37:03 +08:00
parent 7c2a5b28e7
commit 55c74c7565
6 changed files with 186 additions and 218 deletions

View File

@ -19,10 +19,6 @@ object Backup {
val backupPath = App.INSTANCE.filesDir.absolutePath + File.separator + "backup"
val defaultPath by lazy {
FileUtils.getSdCardPath() + File.separator + "YueDu"
}
val legadoPath by lazy {
FileUtils.getSdCardPath() + File.separator + "YueDu3.0"
}

View File

@ -0,0 +1,149 @@
package io.legado.app.help.storage
import android.content.Context
import android.net.Uri
import androidx.documentfile.provider.DocumentFile
import io.legado.app.App
import io.legado.app.data.entities.BookSource
import io.legado.app.data.entities.ReplaceRule
import io.legado.app.help.coroutine.Coroutine
import io.legado.app.utils.DocumentUtils
import io.legado.app.utils.FileUtils
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import org.jetbrains.anko.toast
import java.io.File
object ImportOldData {
val yueDuPath by lazy {
FileUtils.getSdCardPath() + File.separator + "YueDu"
}
fun import(context: Context) {
GlobalScope.launch(Dispatchers.IO) {
try {// 导入书架
val shelfFile =
FileUtils.createFileIfNotExist(yueDuPath + File.separator + "myBookShelf.json")
val json = shelfFile.readText()
val importCount = importOldBookshelf(json)
withContext(Dispatchers.Main) {
context.toast("成功导入书籍${importCount}")
}
} catch (e: Exception) {
withContext(Dispatchers.Main) {
context.toast("导入书籍失败\n${e.localizedMessage}")
}
}
try {// Book source
val sourceFile =
FileUtils.createFileIfNotExist(yueDuPath + File.separator + "myBookSource.json")
val json = sourceFile.readText()
val importCount = importOldSource(json)
withContext(Dispatchers.Main) {
context.toast("成功导入书源${importCount}")
}
} catch (e: Exception) {
withContext(Dispatchers.Main) {
context.toast("导入源失败\n${e.localizedMessage}")
}
}
try {// Replace rules
val ruleFile =
FileUtils.createFileIfNotExist(yueDuPath + File.separator + "myBookReplaceRule.json")
val json = ruleFile.readText()
val importCount = importOldReplaceRule(json)
withContext(Dispatchers.Main) {
context.toast("成功导入替换规则${importCount}")
}
} catch (e: Exception) {
withContext(Dispatchers.Main) {
context.toast("导入替换规则失败\n${e.localizedMessage}")
}
}
}
}
fun importUri(uri: Uri) {
Coroutine.async {
DocumentFile.fromTreeUri(App.INSTANCE, uri)?.listFiles()?.forEach {
when (it.name) {
"myBookShelf.json" ->
try {
DocumentUtils.readText(App.INSTANCE, it.uri)?.let { json ->
val importCount = importOldBookshelf(json)
withContext(Dispatchers.Main) {
App.INSTANCE.toast("成功导入书籍${importCount}")
}
}
} catch (e: java.lang.Exception) {
withContext(Dispatchers.Main) {
App.INSTANCE.toast("导入书籍失败\n${e.localizedMessage}")
}
}
"myBookSource.json" ->
try {
DocumentUtils.readText(App.INSTANCE, it.uri)?.let { json ->
val importCount = importOldSource(json)
withContext(Dispatchers.Main) {
App.INSTANCE.toast("成功导入书源${importCount}")
}
}
} catch (e: Exception) {
withContext(Dispatchers.Main) {
App.INSTANCE.toast("导入源失败\n${e.localizedMessage}")
}
}
"myBookReplaceRule.json" ->
try {
DocumentUtils.readText(App.INSTANCE, it.uri)?.let { json ->
val importCount = importOldReplaceRule(json)
withContext(Dispatchers.Main) {
App.INSTANCE.toast("成功导入替换规则${importCount}")
}
}
} catch (e: Exception) {
withContext(Dispatchers.Main) {
App.INSTANCE.toast("导入替换规则失败\n${e.localizedMessage}")
}
}
}
}
}
}
fun importOldBookshelf(json: String): Int {
val books = OldBook.toNewBook(json)
App.db.bookDao().insert(*books.toTypedArray())
return books.size
}
fun importOldSource(json: String): Int {
val bookSources = mutableListOf<BookSource>()
val items: List<Map<String, Any>> = Restore.jsonPath.parse(json).read("$")
for (item in items) {
val jsonItem = Restore.jsonPath.parse(item)
OldRule.jsonToBookSource(jsonItem.jsonString())?.let {
bookSources.add(it)
}
}
App.db.bookSourceDao().insert(*bookSources.toTypedArray())
return bookSources.size
}
fun importOldReplaceRule(json: String): Int {
val replaceRules = mutableListOf<ReplaceRule>()
val items: List<Map<String, Any>> = Restore.jsonPath.parse(json).read("$")
for (item in items) {
val jsonItem = Restore.jsonPath.parse(item)
OldRule.jsonToReplaceRule(jsonItem.jsonString())?.let {
replaceRules.add(it)
}
}
App.db.replaceRuleDao().insert(*replaceRules.toTypedArray())
return replaceRules.size
}
}

View File

@ -13,12 +13,8 @@ import io.legado.app.data.entities.*
import io.legado.app.help.ReadBookConfig
import io.legado.app.utils.*
import kotlinx.coroutines.Dispatchers.IO
import kotlinx.coroutines.Dispatchers.Main
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import org.jetbrains.anko.defaultSharedPreferences
import org.jetbrains.anko.toast
import java.io.File
object Restore {
@ -109,81 +105,4 @@ object Restore {
return null
}
fun importYueDuData(context: Context) {
GlobalScope.launch(IO) {
try {// 导入书架
val shelfFile =
FileUtils.createFileIfNotExist(Backup.defaultPath + File.separator + "myBookShelf.json")
val json = shelfFile.readText()
val importCount = importOldBookshelf(json)
withContext(Main) {
context.toast("成功导入书籍${importCount}")
}
} catch (e: Exception) {
withContext(Main) {
context.toast("导入书籍失败\n${e.localizedMessage}")
}
}
try {// Book source
val sourceFile =
FileUtils.createFileIfNotExist(Backup.defaultPath + File.separator + "myBookSource.json")
val json = sourceFile.readText()
val importCount = importOldSource(json)
withContext(Main) {
context.toast("成功导入书源${importCount}")
}
} catch (e: Exception) {
withContext(Main) {
context.toast("导入源失败\n${e.localizedMessage}")
}
}
try {// Replace rules
val ruleFile =
FileUtils.createFileIfNotExist(Backup.defaultPath + File.separator + "myBookReplaceRule.json")
val json = ruleFile.readText()
val importCount = importOldReplaceRule(json)
withContext(Main) {
context.toast("成功导入替换规则${importCount}")
}
} catch (e: Exception) {
withContext(Main) {
context.toast("导入替换规则失败\n${e.localizedMessage}")
}
}
}
}
fun importOldBookshelf(json: String): Int {
val books = OldBook.toNewBook(json)
App.db.bookDao().insert(*books.toTypedArray())
return books.size
}
fun importOldSource(json: String): Int {
val bookSources = mutableListOf<BookSource>()
val items: List<Map<String, Any>> = jsonPath.parse(json).read("$")
for (item in items) {
val jsonItem = jsonPath.parse(item)
OldRule.jsonToBookSource(jsonItem.jsonString())?.let {
bookSources.add(it)
}
}
App.db.bookSourceDao().insert(*bookSources.toTypedArray())
return bookSources.size
}
fun importOldReplaceRule(json: String): Int {
val replaceRules = mutableListOf<ReplaceRule>()
val items: List<Map<String, Any>> = jsonPath.parse(json).read("$")
for (item in items) {
val jsonItem = jsonPath.parse(item)
OldRule.jsonToReplaceRule(jsonItem.jsonString())?.let {
replaceRules.add(it)
}
}
App.db.replaceRuleDao().insert(*replaceRules.toTypedArray())
return replaceRules.size
}
}

View File

@ -1,51 +1,26 @@
package io.legado.app.ui.config
import android.app.Activity.RESULT_OK
import android.content.Intent
import android.content.SharedPreferences
import android.net.Uri
import android.os.Build
import android.os.Bundle
import android.text.InputType
import android.view.View
import androidx.documentfile.provider.DocumentFile
import androidx.preference.EditTextPreference
import androidx.preference.ListPreference
import androidx.preference.Preference
import androidx.preference.PreferenceFragmentCompat
import io.legado.app.R
import io.legado.app.constant.PreferKey
import io.legado.app.help.IntentHelp
import io.legado.app.help.permission.Permissions
import io.legado.app.help.permission.PermissionsCompat
import io.legado.app.help.storage.Restore
import io.legado.app.lib.dialogs.alert
import io.legado.app.lib.dialogs.noButton
import io.legado.app.lib.dialogs.yesButton
import io.legado.app.lib.theme.ATH
import io.legado.app.lib.theme.accentColor
import io.legado.app.ui.filechooser.FileChooserDialog
import io.legado.app.utils.DocumentUtils
import io.legado.app.utils.LogUtils
import io.legado.app.utils.applyTint
import io.legado.app.utils.getPrefString
import kotlinx.coroutines.*
import kotlinx.coroutines.Dispatchers.IO
import org.jetbrains.anko.toast
import kotlin.coroutines.CoroutineContext
class BackupConfigFragment : PreferenceFragmentCompat(),
SharedPreferences.OnSharedPreferenceChangeListener,
FileChooserDialog.CallBack,
CoroutineScope {
private lateinit var job: Job
private val oldDataRequestCode = 11
override val coroutineContext: CoroutineContext
get() = job + Dispatchers.Main
FileChooserDialog.CallBack {
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
job = Job()
addPreferencesFromResource(R.xml.pref_config_backup)
findPreference<EditTextPreference>(PreferKey.webDavUrl)?.let {
it.setOnBindEditTextListener { editText ->
@ -80,7 +55,6 @@ class BackupConfigFragment : PreferenceFragmentCompat(),
override fun onDestroy() {
super.onDestroy()
preferenceManager.sharedPreferences.unregisterOnSharedPreferenceChangeListener(this)
job.cancel()
}
override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences?, key: String?) {
@ -132,107 +106,11 @@ class BackupConfigFragment : PreferenceFragmentCompat(),
PreferKey.backupPath -> BackupRestoreUi.selectBackupFolder(this)
"web_dav_backup" -> BackupRestoreUi.backup(this)
"web_dav_restore" -> BackupRestoreUi.restore(this)
"import_old" -> importOldData()
"import_old" -> BackupRestoreUi.importOldData(this)
}
return super.onPreferenceTreeClick(preference)
}
private fun importOldData() {
try {
val intent = Intent(Intent.ACTION_OPEN_DOCUMENT_TREE)
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
startActivityForResult(intent, oldDataRequestCode)
} catch (e: Exception) {
needInstallApps {
alert(title = "导入") {
message = "是否导入旧版本数据"
yesButton {
PermissionsCompat.Builder(this@BackupConfigFragment)
.addPermissions(*Permissions.Group.STORAGE)
.rationale(R.string.tip_perm_request_storage)
.onGranted {
Restore.importYueDuData(requireContext())
}
.request()
}
noButton {
}
}.show().applyTint()
}
}
}
private fun importOldData(uri: Uri) {
launch(IO) {
DocumentFile.fromTreeUri(requireContext(), uri)?.listFiles()?.forEach {
when (it.name) {
"myBookShelf.json" ->
try {
DocumentUtils.readText(requireContext(), it.uri)?.let { json ->
val importCount = Restore.importOldBookshelf(json)
withContext(Dispatchers.Main) {
requireContext().toast("成功导入书籍${importCount}")
}
}
} catch (e: java.lang.Exception) {
withContext(Dispatchers.Main) {
requireContext().toast("导入书籍失败\n${e.localizedMessage}")
}
}
"myBookSource.json" ->
try {
DocumentUtils.readText(requireContext(), it.uri)?.let { json ->
val importCount = Restore.importOldSource(json)
withContext(Dispatchers.Main) {
requireContext().toast("成功导入书源${importCount}")
}
}
} catch (e: Exception) {
withContext(Dispatchers.Main) {
requireContext().toast("导入源失败\n${e.localizedMessage}")
}
}
"myBookReplaceRule.json" ->
try {
DocumentUtils.readText(requireContext(), it.uri)?.let { json ->
val importCount = Restore.importOldReplaceRule(json)
withContext(Dispatchers.Main) {
requireContext().toast("成功导入替换规则${importCount}")
}
}
} catch (e: Exception) {
withContext(Dispatchers.Main) {
requireContext().toast("导入替换规则失败\n${e.localizedMessage}")
}
}
}
}
}
}
private fun needInstallApps(callback: () -> Unit) {
fun canRequestPackageInstalls(): Boolean {
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.P) {
return requireContext().packageManager.canRequestPackageInstalls()
}
return true
}
if (!canRequestPackageInstalls()) {
alert(title = "开启权限提示") {
message = "需要打开「安装外部来源应用」权限才能导入旧版数据,请去设置中开启"
yesButton {
IntentHelp.toInstallUnknown(requireContext())
}
noButton {
}
}.show().applyTint()
} else {
LogUtils.d("xxx", "import old")
callback()
}
}
override fun onFilePicked(requestCode: Int, currentPath: String) {
BackupRestoreUi.onFilePicked(requestCode, currentPath)
}
@ -240,11 +118,5 @@ class BackupConfigFragment : PreferenceFragmentCompat(),
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
BackupRestoreUi.onActivityResult(requestCode, resultCode, data)
when (requestCode) {
oldDataRequestCode ->
if (resultCode == RESULT_OK) data?.data?.let { uri ->
importOldData(uri)
}
}
}
}

View File

@ -13,10 +13,14 @@ import io.legado.app.help.coroutine.Coroutine
import io.legado.app.help.permission.Permissions
import io.legado.app.help.permission.PermissionsCompat
import io.legado.app.help.storage.Backup
import io.legado.app.help.storage.ImportOldData
import io.legado.app.help.storage.Restore
import io.legado.app.help.storage.WebDavHelp
import io.legado.app.lib.dialogs.alert
import io.legado.app.lib.dialogs.noButton
import io.legado.app.lib.dialogs.yesButton
import io.legado.app.ui.filechooser.FileChooserDialog
import io.legado.app.utils.applyTint
import io.legado.app.utils.getPrefString
import io.legado.app.utils.isContentPath
import io.legado.app.utils.toast
@ -27,6 +31,7 @@ object BackupRestoreUi {
private const val backupSelectRequestCode = 22
private const val restoreSelectRequestCode = 33
private const val oldDataRequestCode = 11
fun backup(fragment: Fragment) {
val backupPath = AppConfig.backupPath
@ -163,6 +168,29 @@ object BackupRestoreUi {
}.show()
}
fun importOldData(fragment: Fragment) {
try {
val intent = Intent(Intent.ACTION_OPEN_DOCUMENT_TREE)
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
fragment.startActivityForResult(intent, oldDataRequestCode)
} catch (e: Exception) {
fragment.alert(title = "导入") {
message = "是否导入旧版本数据"
yesButton {
PermissionsCompat.Builder(fragment)
.addPermissions(*Permissions.Group.STORAGE)
.rationale(R.string.tip_perm_request_storage)
.onGranted {
ImportOldData.import(fragment.requireContext())
}
.request()
}
noButton {
}
}.show().applyTint()
}
}
fun onFilePicked(requestCode: Int, currentPath: String) {
when (requestCode) {
backupSelectRequestCode -> {
@ -214,6 +242,10 @@ object BackupRestoreUi {
}
}
}
oldDataRequestCode ->
if (resultCode == RESULT_OK) data?.data?.let { uri ->
ImportOldData.importUri(uri)
}
}
}

View File

@ -8,7 +8,7 @@ import io.legado.app.base.BaseViewModel
import io.legado.app.data.entities.ReplaceRule
import io.legado.app.help.http.HttpHelper
import io.legado.app.help.storage.Backup
import io.legado.app.help.storage.Restore
import io.legado.app.help.storage.ImportOldData
import io.legado.app.utils.FileUtils
import io.legado.app.utils.GSON
import io.legado.app.utils.isAbsUrl
@ -22,10 +22,10 @@ class ReplaceRuleViewModel(application: Application) : BaseViewModel(application
execute {
if (text.isAbsUrl()) {
HttpHelper.simpleGet(text)?.let {
Restore.importOldReplaceRule(it)
ImportOldData.importOldReplaceRule(it)
}
} else {
Restore.importOldReplaceRule(text)
ImportOldData.importOldReplaceRule(text)
}
}.onError {
showMsg(it.localizedMessage ?: "ERROR")