Merge pull request #7 from gedoor/master

up
pull/68/head
口口吕 5 years ago committed by GitHub
commit 10493a4836
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 10
      app/src/main/assets/updateLog.md
  2. 5
      app/src/main/java/io/legado/app/data/AppDatabase.kt
  3. 25
      app/src/main/java/io/legado/app/help/storage/Backup.kt
  4. 26
      app/src/main/java/io/legado/app/help/storage/Restore.kt
  5. 21
      app/src/main/java/io/legado/app/help/storage/WebDavHelp.kt
  6. 8
      app/src/main/java/io/legado/app/ui/book/read/page/ContentView.kt
  7. 84
      app/src/main/java/io/legado/app/ui/config/WebDavConfigFragment.kt
  8. 105
      app/src/main/java/io/legado/app/ui/main/MainActivity.kt
  9. 126
      app/src/main/java/io/legado/app/ui/main/my/MyFragment.kt

@ -1,8 +1,14 @@
## 更新日志 ## 更新日志
* 旧版数据导入教程: * 旧版数据导入教程:
* 先在旧版阅读(2.x)中进行备份,然后在新版阅读(3.x)【我的】->【备份与恢复】,选择【导入旧版本数据】,提示存储权限,选择允许即可导入成功。 * 先在旧版阅读(2.x)中进行备份,然后在新版阅读(3.x)【我的】->【备份与恢复】,选择【导入旧版本数据】。
* 注意:由于安卓10更改了权限策略,还需要给「允许安装其他应用」的权限才能导入源。MIUI11也需要此权限。
**2020/01/07**
* 修复备份问题
**2020/01/06**
* 适配Android 10 权限
* 备份恢复不再需要存储权限
**2020/01/03** **2020/01/03**
* 适配Android 10 权限 * 适配Android 10 权限

@ -7,7 +7,10 @@ import androidx.room.RoomDatabase
import androidx.sqlite.db.SupportSQLiteDatabase import androidx.sqlite.db.SupportSQLiteDatabase
import io.legado.app.data.dao.* import io.legado.app.data.dao.*
import io.legado.app.data.entities.* import io.legado.app.data.entities.*
import io.legado.app.help.storage.Backup
import io.legado.app.help.storage.Restore import io.legado.app.help.storage.Restore
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
@Database( @Database(
@ -28,7 +31,7 @@ abstract class AppDatabase : RoomDatabase() {
.fallbackToDestructiveMigration() .fallbackToDestructiveMigration()
.addCallback(object : Callback() { .addCallback(object : Callback() {
override fun onDestructiveMigration(db: SupportSQLiteDatabase) { override fun onDestructiveMigration(db: SupportSQLiteDatabase) {
Restore.restore() GlobalScope.launch { Restore.restore(Backup.backupPath) }
} }
}) })
.build() .build()

@ -9,13 +9,15 @@ import io.legado.app.help.ReadBookConfig
import io.legado.app.utils.DocumentUtils import io.legado.app.utils.DocumentUtils
import io.legado.app.utils.FileUtils import io.legado.app.utils.FileUtils
import io.legado.app.utils.GSON import io.legado.app.utils.GSON
import kotlinx.coroutines.Dispatchers.IO
import kotlinx.coroutines.withContext
import org.jetbrains.anko.defaultSharedPreferences import org.jetbrains.anko.defaultSharedPreferences
import java.io.File import java.io.File
object Backup { object Backup {
private val backupPath = App.INSTANCE.filesDir.absolutePath + File.separator + "backup" val backupPath = App.INSTANCE.filesDir.absolutePath + File.separator + "backup"
val defaultPath by lazy { val defaultPath by lazy {
FileUtils.getSdCardPath() + File.separator + "YueDu" FileUtils.getSdCardPath() + File.separator + "YueDu"
@ -29,7 +31,7 @@ object Backup {
legadoPath + File.separator + "Export" legadoPath + File.separator + "Export"
} }
private val backupFileNames by lazy { val backupFileNames by lazy {
arrayOf( arrayOf(
"bookshelf.json", "bookshelf.json",
"bookGroup.json", "bookGroup.json",
@ -41,7 +43,8 @@ object Backup {
) )
} }
fun backup(context: Context, uri: Uri?) { suspend fun backup(context: Context, uri: Uri?) {
withContext(IO) {
App.db.bookDao().allBooks.let { App.db.bookDao().allBooks.let {
if (it.isNotEmpty()) { if (it.isNotEmpty()) {
val json = GSON.toJson(it) val json = GSON.toJson(it)
@ -57,7 +60,8 @@ object Backup {
App.db.bookSourceDao().all.let { App.db.bookSourceDao().all.let {
if (it.isNotEmpty()) { if (it.isNotEmpty()) {
val json = GSON.toJson(it) val json = GSON.toJson(it)
FileHelp.getFile(backupPath + File.separator + "bookSource.json").writeText(json) FileHelp.getFile(backupPath + File.separator + "bookSource.json")
.writeText(json)
} }
} }
App.db.rssSourceDao().all.let { App.db.rssSourceDao().all.let {
@ -69,7 +73,8 @@ object Backup {
App.db.replaceRuleDao().all.let { App.db.replaceRuleDao().all.let {
if (it.isNotEmpty()) { if (it.isNotEmpty()) {
val json = GSON.toJson(it) val json = GSON.toJson(it)
FileHelp.getFile(backupPath + File.separator + "replaceRule.json").writeText(json) FileHelp.getFile(backupPath + File.separator + "replaceRule.json")
.writeText(json)
} }
} }
GSON.toJson(ReadBookConfig.configList)?.let { GSON.toJson(ReadBookConfig.configList)?.let {
@ -97,11 +102,13 @@ object Backup {
copyBackup() copyBackup()
} }
} }
}
private fun copyBackup(context: Context, uri: Uri) { private fun copyBackup(context: Context, uri: Uri) {
DocumentFile.fromTreeUri(context, uri)?.let { treeDoc -> DocumentFile.fromTreeUri(context, uri)?.let { treeDoc ->
for (fileName in backupFileNames) { for (fileName in backupFileNames) {
treeDoc.createFile("text/plain", fileName)?.let { doc -> val doc = treeDoc.findFile(fileName) ?: treeDoc.createFile("", fileName)
doc?.let {
DocumentUtils.writeText( DocumentUtils.writeText(
context, context,
FileHelp.getFile(backupPath + File.separator + fileName).readText(), FileHelp.getFile(backupPath + File.separator + fileName).readText(),
@ -113,9 +120,13 @@ object Backup {
} }
private fun copyBackup() { private fun copyBackup() {
try {
for (fileName in backupFileNames) { for (fileName in backupFileNames) {
FileHelp.getFile(backupPath + File.separator + "bookshelf.json") FileHelp.getFile(backupPath + File.separator + "bookshelf.json")
.copyTo(FileHelp.getFile(legadoPath + File.separator + "bookshelf.json")) .copyTo(FileHelp.getFile(legadoPath + File.separator + "bookshelf.json"), true)
}
} catch (e: Exception) {
e.printStackTrace()
} }
} }
} }

@ -1,13 +1,14 @@
package io.legado.app.help.storage package io.legado.app.help.storage
import android.content.Context import android.content.Context
import android.net.Uri
import android.util.Log import android.util.Log
import androidx.documentfile.provider.DocumentFile
import com.jayway.jsonpath.Configuration import com.jayway.jsonpath.Configuration
import com.jayway.jsonpath.JsonPath import com.jayway.jsonpath.JsonPath
import com.jayway.jsonpath.Option import com.jayway.jsonpath.Option
import com.jayway.jsonpath.ParseContext import com.jayway.jsonpath.ParseContext
import io.legado.app.App import io.legado.app.App
import io.legado.app.R
import io.legado.app.constant.AppConst import io.legado.app.constant.AppConst
import io.legado.app.data.entities.* import io.legado.app.data.entities.*
import io.legado.app.help.FileHelp import io.legado.app.help.FileHelp
@ -19,9 +20,7 @@ import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import org.jetbrains.anko.defaultSharedPreferences import org.jetbrains.anko.defaultSharedPreferences
import org.jetbrains.anko.doAsync
import org.jetbrains.anko.toast import org.jetbrains.anko.toast
import org.jetbrains.anko.uiThread
import java.io.File import java.io.File
object Restore { object Restore {
@ -33,8 +32,24 @@ object Restore {
) )
} }
fun restore(path: String = Backup.defaultPath) { suspend fun restore(context: Context, uri: Uri) {
doAsync { withContext(IO) {
DocumentFile.fromTreeUri(context, uri)?.listFiles()?.forEach { doc ->
for (fileName in Backup.backupFileNames) {
if (doc.name == fileName) {
DocumentUtils.readText(context, doc.uri)?.let {
FileHelp.getFile(Backup.backupPath + File.separator + fileName)
.writeText(it)
}
}
}
}
}
restore(Backup.backupPath)
}
suspend fun restore(path: String) {
withContext(IO) {
try { try {
val file = FileHelp.getFile(path + File.separator + "bookshelf.json") val file = FileHelp.getFile(path + File.separator + "bookshelf.json")
val json = file.readText() val json = file.readText()
@ -104,7 +119,6 @@ object Restore {
} }
edit.commit() edit.commit()
} }
uiThread { App.INSTANCE.toast(R.string.restore_success) }
} }
} }

@ -4,13 +4,14 @@ import android.content.Context
import io.legado.app.App import io.legado.app.App
import io.legado.app.help.FileHelp import io.legado.app.help.FileHelp
import io.legado.app.help.ReadBookConfig import io.legado.app.help.ReadBookConfig
import io.legado.app.help.coroutine.Coroutine
import io.legado.app.lib.webdav.WebDav import io.legado.app.lib.webdav.WebDav
import io.legado.app.lib.webdav.http.HttpAuth import io.legado.app.lib.webdav.http.HttpAuth
import io.legado.app.utils.ZipUtils import io.legado.app.utils.ZipUtils
import io.legado.app.utils.getPrefString import io.legado.app.utils.getPrefString
import org.jetbrains.anko.doAsync import kotlinx.coroutines.Dispatchers.IO
import kotlinx.coroutines.withContext
import org.jetbrains.anko.selector import org.jetbrains.anko.selector
import org.jetbrains.anko.uiThread
import java.io.File import java.io.File
import java.text.SimpleDateFormat import java.text.SimpleDateFormat
import java.util.* import java.util.*
@ -54,28 +55,26 @@ object WebDavHelp {
return names return names
} }
fun showRestoreDialog(context: Context) { suspend fun showRestoreDialog(context: Context): Boolean {
doAsync { val names = withContext(IO) { getWebDavFileNames() }
val names = getWebDavFileNames() return if (names.isNotEmpty()) {
if (names.isNotEmpty()) {
uiThread {
context.selector(title = "选择恢复文件", items = names) { _, index -> context.selector(title = "选择恢复文件", items = names) { _, index ->
if (index in 0 until names.size) { if (index in 0 until names.size) {
restoreWebDav(names[index]) restoreWebDav(names[index])
} }
} }
} true
} else { } else {
Restore.restore() false
}
} }
} }
private fun restoreWebDav(name: String) { private fun restoreWebDav(name: String) {
doAsync { Coroutine.async {
getWebDavUrl()?.let { getWebDavUrl()?.let {
val file = WebDav(it + "legado/" + name) val file = WebDav(it + "legado/" + name)
file.downloadTo(zipFilePath, true) file.downloadTo(zipFilePath, true)
@Suppress("BlockingMethodInNonBlockingContext")
ZipUtils.unzipFile(zipFilePath, unzipFilesPath) ZipUtils.unzipFile(zipFilePath, unzipFilesPath)
Restore.restore(unzipFilesPath) Restore.restore(unzipFilesPath)
} }

@ -17,6 +17,7 @@ import io.legado.app.utils.*
import kotlinx.android.synthetic.main.view_book_page.view.* import kotlinx.android.synthetic.main.view_book_page.view.*
import org.jetbrains.anko.matchParent import org.jetbrains.anko.matchParent
import org.jetbrains.anko.sdk27.listeners.onScrollChange import org.jetbrains.anko.sdk27.listeners.onScrollChange
import java.io.File
import java.util.* import java.util.*
@ -83,10 +84,15 @@ class ContentView : FrameLayout {
} }
context.getPrefString(PreferKey.readBookFont)?.let { context.getPrefString(PreferKey.readBookFont)?.let {
if (it.isNotEmpty()) { if (it.isNotEmpty()) {
val file = File(it)
if (file.exists()) {
content_text_view.typeface = Typeface.createFromFile(it) content_text_view.typeface = Typeface.createFromFile(it)
return@let
} else { } else {
content_text_view.typeface = Typeface.DEFAULT context.putPrefString(PreferKey.readBookFont, "")
}
} }
content_text_view.typeface = Typeface.DEFAULT
} }
} }

@ -34,10 +34,10 @@ import kotlin.coroutines.CoroutineContext
class WebDavConfigFragment : PreferenceFragmentCompat(), class WebDavConfigFragment : PreferenceFragmentCompat(),
Preference.OnPreferenceChangeListener, Preference.OnPreferenceChangeListener,
CoroutineScope { CoroutineScope {
lateinit var job: Job private lateinit var job: Job
private val oldDataRequestCode = 23156 private val oldDataRequestCode = 11
private val backupSelectRequestCode = 4567489 private val backupSelectRequestCode = 22
private val restoreSelectRequestCode = 654872 private val restoreSelectRequestCode = 33
override val coroutineContext: CoroutineContext override val coroutineContext: CoroutineContext
get() = job + Dispatchers.Main get() = job + Dispatchers.Main
@ -116,13 +116,7 @@ class WebDavConfigFragment : PreferenceFragmentCompat(),
override fun onPreferenceTreeClick(preference: Preference?): Boolean { override fun onPreferenceTreeClick(preference: Preference?): Boolean {
when (preference?.key) { when (preference?.key) {
"web_dav_backup" -> backup() "web_dav_backup" -> backup()
"web_dav_restore" -> PermissionsCompat.Builder(this) "web_dav_restore" -> restore()
.addPermissions(*Permissions.Group.STORAGE)
.rationale(R.string.tip_perm_request_storage)
.onGranted {
WebDavHelp.showRestoreDialog(requireContext())
}
.request()
"import_old" -> importOldData() "import_old" -> importOldData()
} }
return super.onPreferenceTreeClick(preference) return super.onPreferenceTreeClick(preference)
@ -130,16 +124,18 @@ class WebDavConfigFragment : PreferenceFragmentCompat(),
private fun backup() { private fun backup() {
val backupPath = getPrefString(PreferKey.backupPath) val backupPath = getPrefString(PreferKey.backupPath)
if (backupPath?.isEmpty() == true) { if (backupPath?.isNotEmpty() == true) {
selectBackupFolder()
} else {
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) {
launch {
Backup.backup(requireContext(), uri) Backup.backup(requireContext(), uri)
}
} else { } else {
selectBackupFolder() selectBackupFolder()
} }
} else {
selectBackupFolder()
} }
} }
@ -152,7 +148,50 @@ class WebDavConfigFragment : PreferenceFragmentCompat(),
PermissionsCompat.Builder(this) PermissionsCompat.Builder(this)
.addPermissions(*Permissions.Group.STORAGE) .addPermissions(*Permissions.Group.STORAGE)
.rationale(R.string.tip_perm_request_storage) .rationale(R.string.tip_perm_request_storage)
.onGranted { Backup.backup(requireContext(), null) } .onGranted {
launch {
Backup.backup(requireContext(), null)
}
}
.request()
}
}
fun restore() {
launch {
if (!WebDavHelp.showRestoreDialog(requireContext())) {
val backupPath = getPrefString(PreferKey.backupPath)
if (backupPath?.isNotEmpty() == true) {
val uri = Uri.parse(backupPath)
val doc = DocumentFile.fromTreeUri(requireContext(), uri)
if (doc?.canWrite() == true) {
Restore.restore(requireContext(), uri)
toast(R.string.restore_success)
} else {
selectBackupFolder()
}
} else {
selectRestoreFolder()
}
}
}
}
private fun selectRestoreFolder() {
try {
val intent = Intent(Intent.ACTION_OPEN_DOCUMENT_TREE)
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
startActivityForResult(intent, restoreSelectRequestCode)
} catch (e: java.lang.Exception) {
PermissionsCompat.Builder(this)
.addPermissions(*Permissions.Group.STORAGE)
.rationale(R.string.tip_perm_request_storage)
.onGranted {
launch {
Restore.restore(Backup.legadoPath)
toast(R.string.restore_success)
}
}
.request() .request()
} }
} }
@ -267,9 +306,24 @@ class WebDavConfigFragment : PreferenceFragmentCompat(),
Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION
) )
putPrefString(PreferKey.backupPath, uri.toString()) putPrefString(PreferKey.backupPath, uri.toString())
launch {
Backup.backup(requireContext(), uri) Backup.backup(requireContext(), uri)
} }
} }
} }
restoreSelectRequestCode -> if (resultCode == RESULT_OK) {
data?.data?.let { uri ->
requireContext().contentResolver.takePersistableUriPermission(
uri,
Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION
)
putPrefString(PreferKey.backupPath, uri.toString())
launch {
Restore.restore(requireContext(), uri)
toast(R.string.restore_success)
}
}
}
}
} }
} }

@ -1,7 +1,5 @@
package io.legado.app.ui.main package io.legado.app.ui.main
import android.app.Activity
import android.content.Intent
import android.net.Uri import android.net.Uri
import android.os.Bundle import android.os.Bundle
import android.view.KeyEvent import android.view.KeyEvent
@ -18,11 +16,7 @@ import io.legado.app.R
import io.legado.app.base.VMBaseActivity import io.legado.app.base.VMBaseActivity
import io.legado.app.constant.Bus import io.legado.app.constant.Bus
import io.legado.app.constant.PreferKey import io.legado.app.constant.PreferKey
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.Backup
import io.legado.app.help.storage.Restore
import io.legado.app.help.storage.WebDavHelp
import io.legado.app.lib.theme.ATH import io.legado.app.lib.theme.ATH
import io.legado.app.service.BaseReadAloudService import io.legado.app.service.BaseReadAloudService
import io.legado.app.service.help.ReadAloud import io.legado.app.service.help.ReadAloud
@ -33,15 +27,11 @@ import io.legado.app.ui.main.my.MyFragment
import io.legado.app.ui.main.rss.RssFragment import io.legado.app.ui.main.rss.RssFragment
import io.legado.app.utils.* import io.legado.app.utils.*
import kotlinx.android.synthetic.main.activity_main.* import kotlinx.android.synthetic.main.activity_main.*
import kotlinx.coroutines.Dispatchers.IO
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
class MainActivity : VMBaseActivity<MainViewModel>(R.layout.activity_main), class MainActivity : VMBaseActivity<MainViewModel>(R.layout.activity_main),
BottomNavigationView.OnNavigationItemSelectedListener, BottomNavigationView.OnNavigationItemSelectedListener,
ViewPager.OnPageChangeListener by ViewPager.SimpleOnPageChangeListener() { ViewPager.OnPageChangeListener by ViewPager.SimpleOnPageChangeListener() {
private val backupSelectRequestCode = 4567489
private val restoreSelectRequestCode = 654872
override val viewModel: MainViewModel override val viewModel: MainViewModel
get() = getViewModel(MainViewModel::class.java) get() = getViewModel(MainViewModel::class.java)
@ -127,9 +117,7 @@ class MainActivity : VMBaseActivity<MainViewModel>(R.layout.activity_main),
override fun finish() { override fun finish() {
if (!BuildConfig.DEBUG) { if (!BuildConfig.DEBUG) {
launch { launch {
withContext(IO) {
backup() backup()
}
super.finish() super.finish()
} }
} else { } else {
@ -137,6 +125,19 @@ class MainActivity : VMBaseActivity<MainViewModel>(R.layout.activity_main),
} }
} }
private suspend fun backup() {
val backupPath = getPrefString(PreferKey.backupPath)
if (backupPath?.isNotEmpty() == true) {
val uri = Uri.parse(backupPath)
val doc = DocumentFile.fromTreeUri(this, uri)
if (doc?.canWrite() == true) {
Backup.backup(this@MainActivity, uri)
}
} else {
Backup.backup(this@MainActivity, null)
}
}
override fun onDestroy() { override fun onDestroy() {
super.onDestroy() super.onDestroy()
ReadAloud.stop(this) ReadAloud.stop(this)
@ -156,86 +157,6 @@ class MainActivity : VMBaseActivity<MainViewModel>(R.layout.activity_main),
} }
} }
fun backup() {
val backupPath = getPrefString(PreferKey.backupPath)
if (backupPath?.isEmpty() == true) {
selectBackupFolder()
} else {
val uri = Uri.parse(backupPath)
val doc = DocumentFile.fromTreeUri(this, uri)
if (doc?.canWrite() == true) {
Backup.backup(this, uri)
} else {
selectBackupFolder()
}
}
}
fun restore() {
PermissionsCompat.Builder(this)
.addPermissions(*Permissions.Group.STORAGE)
.rationale(R.string.tip_perm_request_storage)
.onGranted { WebDavHelp.showRestoreDialog(this) }
.request()
}
fun restore(uri: Uri) {
}
private fun selectBackupFolder() {
try {
val intent = Intent(Intent.ACTION_OPEN_DOCUMENT_TREE)
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
startActivityForResult(intent, backupSelectRequestCode)
} catch (e: java.lang.Exception) {
PermissionsCompat.Builder(this)
.addPermissions(*Permissions.Group.STORAGE)
.rationale(R.string.tip_perm_request_storage)
.onGranted { Backup.backup(this, null) }
.request()
}
}
private fun selectRestoreFolder() {
try {
val intent = Intent(Intent.ACTION_OPEN_DOCUMENT_TREE)
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
startActivityForResult(intent, restoreSelectRequestCode)
} catch (e: java.lang.Exception) {
PermissionsCompat.Builder(this)
.addPermissions(*Permissions.Group.STORAGE)
.rationale(R.string.tip_perm_request_storage)
.onGranted { Restore.restore() }
.request()
}
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
when (requestCode) {
backupSelectRequestCode -> if (resultCode == Activity.RESULT_OK) {
data?.data?.let { uri ->
contentResolver.takePersistableUriPermission(
uri,
Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION
)
putPrefString(PreferKey.backupPath, uri.toString())
Backup.backup(this, uri)
}
}
restoreSelectRequestCode -> if (resultCode == Activity.RESULT_OK) {
data?.data?.let { uri ->
contentResolver.takePersistableUriPermission(
uri,
Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION
)
putPrefString(PreferKey.backupPath, uri.toString())
}
}
}
}
private inner class TabFragmentPageAdapter internal constructor(fm: FragmentManager) : private inner class TabFragmentPageAdapter internal constructor(fm: FragmentManager) :
FragmentStatePagerAdapter(fm, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT) { FragmentStatePagerAdapter(fm, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT) {

@ -1,10 +1,14 @@
package io.legado.app.ui.main.my package io.legado.app.ui.main.my
import android.app.Activity
import android.content.Intent
import android.content.SharedPreferences import android.content.SharedPreferences
import android.net.Uri
import android.os.Bundle import android.os.Bundle
import android.view.Menu import android.view.Menu
import android.view.MenuItem import android.view.MenuItem
import android.view.View import android.view.View
import androidx.documentfile.provider.DocumentFile
import androidx.preference.Preference import androidx.preference.Preference
import androidx.preference.PreferenceFragmentCompat import androidx.preference.PreferenceFragmentCompat
import androidx.preference.SwitchPreference import androidx.preference.SwitchPreference
@ -12,7 +16,13 @@ import io.legado.app.App
import io.legado.app.R import io.legado.app.R
import io.legado.app.base.BaseFragment import io.legado.app.base.BaseFragment
import io.legado.app.constant.Bus import io.legado.app.constant.Bus
import io.legado.app.constant.PreferKey
import io.legado.app.help.BookHelp import io.legado.app.help.BookHelp
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.Restore
import io.legado.app.help.storage.WebDavHelp
import io.legado.app.lib.theme.ATH import io.legado.app.lib.theme.ATH
import io.legado.app.service.WebService import io.legado.app.service.WebService
import io.legado.app.ui.about.AboutActivity import io.legado.app.ui.about.AboutActivity
@ -20,13 +30,15 @@ import io.legado.app.ui.about.DonateActivity
import io.legado.app.ui.book.source.manage.BookSourceActivity import io.legado.app.ui.book.source.manage.BookSourceActivity
import io.legado.app.ui.config.ConfigActivity import io.legado.app.ui.config.ConfigActivity
import io.legado.app.ui.config.ConfigViewModel import io.legado.app.ui.config.ConfigViewModel
import io.legado.app.ui.main.MainActivity
import io.legado.app.ui.replacerule.ReplaceRuleActivity import io.legado.app.ui.replacerule.ReplaceRuleActivity
import io.legado.app.utils.* import io.legado.app.utils.*
import kotlinx.android.synthetic.main.view_title_bar.* import kotlinx.android.synthetic.main.view_title_bar.*
import kotlinx.coroutines.launch
import org.jetbrains.anko.startActivity import org.jetbrains.anko.startActivity
class MyFragment : BaseFragment(R.layout.fragment_my_config) { class MyFragment : BaseFragment(R.layout.fragment_my_config) {
private val backupSelectRequestCode = 22
private val restoreSelectRequestCode = 33
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
setSupportToolbar(toolbar) setSupportToolbar(toolbar)
@ -43,13 +55,113 @@ class MyFragment : BaseFragment(R.layout.fragment_my_config) {
override fun onCompatOptionsItemSelected(item: MenuItem) { override fun onCompatOptionsItemSelected(item: MenuItem) {
when (item.itemId) { when (item.itemId) {
R.id.menu_help -> startActivity<AboutActivity>() R.id.menu_help -> startActivity<AboutActivity>()
R.id.menu_backup -> { R.id.menu_backup -> backup()
val activity = activity as? MainActivity R.id.menu_restore -> restore()
activity?.backup() }
}
private fun backup() {
val backupPath = getPrefString(PreferKey.backupPath)
if (backupPath?.isNotEmpty() == true) {
val uri = Uri.parse(backupPath)
val doc = DocumentFile.fromTreeUri(requireContext(), uri)
if (doc?.canWrite() == true) {
launch {
Backup.backup(requireContext(), uri)
}
} else {
selectBackupFolder()
}
} else {
selectBackupFolder()
}
}
private fun selectBackupFolder() {
try {
val intent = Intent(Intent.ACTION_OPEN_DOCUMENT_TREE)
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
startActivityForResult(intent, backupSelectRequestCode)
} catch (e: java.lang.Exception) {
PermissionsCompat.Builder(this)
.addPermissions(*Permissions.Group.STORAGE)
.rationale(R.string.tip_perm_request_storage)
.onGranted {
launch {
Backup.backup(requireContext(), null)
}
}
.request()
}
}
fun restore() {
launch {
if (!WebDavHelp.showRestoreDialog(requireContext())) {
val backupPath = getPrefString(PreferKey.backupPath)
if (backupPath?.isNotEmpty() == true) {
val uri = Uri.parse(backupPath)
val doc = DocumentFile.fromTreeUri(requireContext(), uri)
if (doc?.canWrite() == true) {
Restore.restore(requireContext(), uri)
toast(R.string.restore_success)
} else {
selectBackupFolder()
}
} else {
selectRestoreFolder()
}
}
}
}
private fun selectRestoreFolder() {
try {
val intent = Intent(Intent.ACTION_OPEN_DOCUMENT_TREE)
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
startActivityForResult(intent, restoreSelectRequestCode)
} catch (e: java.lang.Exception) {
PermissionsCompat.Builder(this)
.addPermissions(*Permissions.Group.STORAGE)
.rationale(R.string.tip_perm_request_storage)
.onGranted {
launch {
Restore.restore(Backup.legadoPath)
toast(R.string.restore_success)
}
}
.request()
}
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
when (requestCode) {
backupSelectRequestCode -> if (resultCode == Activity.RESULT_OK) {
data?.data?.let { uri ->
requireContext().contentResolver.takePersistableUriPermission(
uri,
Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION
)
putPrefString(PreferKey.backupPath, uri.toString())
launch {
Backup.backup(requireContext(), uri)
}
}
}
restoreSelectRequestCode -> if (resultCode == Activity.RESULT_OK) {
data?.data?.let { uri ->
requireContext().contentResolver.takePersistableUriPermission(
uri,
Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION
)
putPrefString(PreferKey.backupPath, uri.toString())
launch {
Restore.restore(requireContext(), uri)
toast(R.string.restore_success)
}
} }
R.id.menu_restore -> {
val activity = activity as? MainActivity
activity?.restore()
} }
} }
} }

Loading…
Cancel
Save