mirror of
https://github.com/gedoor/legado.git
synced 2024-07-06 23:47:49 +08:00
本地书籍无权限则保存到自己选定的文件夹
This commit is contained in:
parent
448e25c04d
commit
c3295483e4
@ -4,6 +4,7 @@
|
||||
package="io.legado.app">
|
||||
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
<uses-permission android:name="android.permission.ACCESS_MEDIA_LOCATION" />
|
||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
|
||||
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
|
||||
|
@ -90,6 +90,7 @@ object PreferKey {
|
||||
const val expandTextMenu = "expandTextMenu"
|
||||
const val doublePageHorizontal = "doublePageHorizontal"
|
||||
const val readUrlOpenInBrowser = "readUrlInBrowser"
|
||||
const val defaultBookTreeUri = "defaultBookTreeUri"
|
||||
|
||||
const val cPrimary = "colorPrimary"
|
||||
const val cAccent = "colorAccent"
|
||||
|
@ -133,6 +133,16 @@ object AppConfig : SharedPreferences.OnSharedPreferenceChangeListener {
|
||||
}
|
||||
}
|
||||
|
||||
var defaultBookTreeUri: String?
|
||||
get() = appCtx.getPrefString(PreferKey.defaultBookTreeUri)
|
||||
set(value) {
|
||||
if (value.isNullOrEmpty()) {
|
||||
appCtx.removePref(PreferKey.defaultBookTreeUri)
|
||||
} else {
|
||||
appCtx.putPrefString(PreferKey.defaultBookTreeUri, value)
|
||||
}
|
||||
}
|
||||
|
||||
val showDiscovery: Boolean
|
||||
get() = appCtx.getPrefBoolean(PreferKey.showDiscovery, true)
|
||||
|
||||
|
@ -1,90 +0,0 @@
|
||||
package io.legado.app.help
|
||||
|
||||
import android.content.ContentUris
|
||||
import android.content.ContentValues
|
||||
import android.net.Uri
|
||||
import android.os.Build
|
||||
import android.os.Environment
|
||||
import android.provider.MediaStore
|
||||
import androidx.core.content.FileProvider
|
||||
import androidx.documentfile.provider.DocumentFile
|
||||
import io.legado.app.constant.AppConst
|
||||
import io.legado.app.utils.FileDoc
|
||||
import io.legado.app.utils.FileUtils.getMimeType
|
||||
import splitties.init.appCtx
|
||||
import java.io.File
|
||||
import java.util.*
|
||||
|
||||
object BookMediaStore {
|
||||
private val DOWNLOAD_DIR =
|
||||
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS)
|
||||
|
||||
fun insertBook(doc: DocumentFile): Uri? {
|
||||
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
||||
val bookDetails = ContentValues().apply {
|
||||
put(MediaStore.Downloads.RELATIVE_PATH, "Download${File.separator}books")
|
||||
put(MediaStore.MediaColumns.DISPLAY_NAME, doc.name)
|
||||
put(MediaStore.MediaColumns.MIME_TYPE, getMimeType(doc.name!!))
|
||||
put(MediaStore.MediaColumns.SIZE, doc.length())
|
||||
}
|
||||
appCtx.contentResolver.insert(MediaStore.Downloads.EXTERNAL_CONTENT_URI, bookDetails)
|
||||
} else {
|
||||
val destinyFile = File(DOWNLOAD_DIR, doc.name!!)
|
||||
FileProvider.getUriForFile(appCtx, AppConst.authority, destinyFile)
|
||||
}?.also { uri ->
|
||||
appCtx.contentResolver.openOutputStream(uri).use { outputStream ->
|
||||
val brr = ByteArray(1024)
|
||||
var len: Int
|
||||
val bufferedInputStream = appCtx.contentResolver.openInputStream(doc.uri)!!
|
||||
while ((bufferedInputStream.read(brr, 0, brr.size).also { len = it }) != -1) {
|
||||
outputStream?.write(brr, 0, len)
|
||||
}
|
||||
outputStream?.flush()
|
||||
bufferedInputStream.close()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun getBook(name: String): FileDoc? {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
||||
val projection = arrayOf(
|
||||
MediaStore.Downloads._ID,
|
||||
MediaStore.Downloads.DISPLAY_NAME,
|
||||
MediaStore.Downloads.SIZE,
|
||||
MediaStore.Downloads.DATE_MODIFIED
|
||||
)
|
||||
val selection =
|
||||
"${MediaStore.Downloads.RELATIVE_PATH} like 'Download${File.separator}books${File.separator}%'"
|
||||
val sortOrder = "${MediaStore.Downloads.DISPLAY_NAME} ASC"
|
||||
appCtx.contentResolver.query(
|
||||
MediaStore.Downloads.EXTERNAL_CONTENT_URI,
|
||||
projection,
|
||||
selection,
|
||||
emptyArray(),
|
||||
sortOrder
|
||||
)?.use {
|
||||
val idColumn = it.getColumnIndex(projection[0])
|
||||
val nameColumn = it.getColumnIndex(projection[1])
|
||||
val sizeColumn = it.getColumnIndex(projection[2])
|
||||
val dateColumn = it.getColumnIndex(projection[3])
|
||||
if (it.moveToNext()) {
|
||||
val id = it.getLong(idColumn)
|
||||
return FileDoc(
|
||||
name = it.getString(nameColumn),
|
||||
isDir = false,
|
||||
size = it.getLong(sizeColumn),
|
||||
date = Date(it.getLong(dateColumn)),
|
||||
uri = ContentUris.withAppendedId(
|
||||
MediaStore.Downloads.EXTERNAL_CONTENT_URI,
|
||||
id
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -20,7 +20,7 @@ import java.io.FileOutputStream
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
|
||||
object Backup {
|
||||
object Backup : BackupRestore() {
|
||||
|
||||
val backupPath: String by lazy {
|
||||
appCtx.filesDir.getFile("backup").absolutePath
|
||||
@ -90,12 +90,14 @@ object Backup {
|
||||
Preferences.getSharedPreferences(appCtx, backupPath, "config")?.let { sp ->
|
||||
val edit = sp.edit()
|
||||
appCtx.defaultSharedPreferences.all.forEach { (key, value) ->
|
||||
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)
|
||||
if (keyIsNotIgnore(key)) {
|
||||
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()
|
||||
|
@ -0,0 +1,83 @@
|
||||
package io.legado.app.help.storage
|
||||
|
||||
import io.legado.app.R
|
||||
import io.legado.app.constant.PreferKey
|
||||
import io.legado.app.utils.FileUtils
|
||||
import io.legado.app.utils.GSON
|
||||
import io.legado.app.utils.fromJsonObject
|
||||
import splitties.init.appCtx
|
||||
|
||||
abstract class BackupRestore {
|
||||
|
||||
private val ignoreConfigPath = FileUtils.getPath(appCtx.filesDir, "restoreIgnore.json")
|
||||
val ignoreConfig: HashMap<String, Boolean> by lazy {
|
||||
val file = FileUtils.createFileIfNotExist(ignoreConfigPath)
|
||||
val json = file.readText()
|
||||
GSON.fromJsonObject<HashMap<String, Boolean>>(json) ?: hashMapOf()
|
||||
}
|
||||
|
||||
//忽略key
|
||||
val ignoreKeys = arrayOf(
|
||||
"readConfig",
|
||||
PreferKey.themeMode,
|
||||
PreferKey.bookshelfLayout,
|
||||
PreferKey.showRss,
|
||||
PreferKey.threadCount,
|
||||
PreferKey.defaultBookTreeUri
|
||||
)
|
||||
|
||||
//忽略标题
|
||||
val ignoreTitle = arrayOf(
|
||||
appCtx.getString(R.string.read_config),
|
||||
appCtx.getString(R.string.theme_mode),
|
||||
appCtx.getString(R.string.bookshelf_layout),
|
||||
appCtx.getString(R.string.show_rss),
|
||||
appCtx.getString(R.string.thread_count)
|
||||
)
|
||||
|
||||
//默认忽略keys
|
||||
private val ignorePrefKeys = arrayOf(
|
||||
PreferKey.themeMode,
|
||||
PreferKey.defaultCover,
|
||||
PreferKey.defaultCoverDark
|
||||
)
|
||||
|
||||
//阅读配置
|
||||
private val readPrefKeys = arrayOf(
|
||||
PreferKey.readStyleSelect,
|
||||
PreferKey.shareLayout,
|
||||
PreferKey.hideStatusBar,
|
||||
PreferKey.hideNavigationBar,
|
||||
PreferKey.autoReadSpeed
|
||||
)
|
||||
|
||||
|
||||
protected fun keyIsNotIgnore(key: String): Boolean {
|
||||
return when {
|
||||
ignorePrefKeys.contains(key) -> false
|
||||
readPrefKeys.contains(key) && ignoreReadConfig -> false
|
||||
PreferKey.themeMode == key && ignoreThemeMode -> false
|
||||
PreferKey.bookshelfLayout == key && ignoreBookshelfLayout -> false
|
||||
PreferKey.showRss == key && ignoreShowRss -> false
|
||||
PreferKey.threadCount == key && ignoreThreadCount -> false
|
||||
else -> true
|
||||
}
|
||||
}
|
||||
|
||||
protected val ignoreReadConfig: Boolean
|
||||
get() = ignoreConfig["readConfig"] == true
|
||||
private val ignoreThemeMode: Boolean
|
||||
get() = ignoreConfig[PreferKey.themeMode] == true
|
||||
private val ignoreBookshelfLayout: Boolean
|
||||
get() = ignoreConfig[PreferKey.bookshelfLayout] == true
|
||||
private val ignoreShowRss: Boolean
|
||||
get() = ignoreConfig[PreferKey.showRss] == true
|
||||
private val ignoreThreadCount: Boolean
|
||||
get() = ignoreConfig[PreferKey.threadCount] == true
|
||||
|
||||
fun saveIgnoreConfig() {
|
||||
val json = GSON.toJson(ignoreConfig)
|
||||
FileUtils.createFileIfNotExist(ignoreConfigPath).writeText(json)
|
||||
}
|
||||
|
||||
}
|
@ -24,47 +24,7 @@ import timber.log.Timber
|
||||
import java.io.File
|
||||
|
||||
|
||||
object Restore {
|
||||
private val ignoreConfigPath = FileUtils.getPath(appCtx.filesDir, "restoreIgnore.json")
|
||||
val ignoreConfig: HashMap<String, Boolean> by lazy {
|
||||
val file = FileUtils.createFileIfNotExist(ignoreConfigPath)
|
||||
val json = file.readText()
|
||||
GSON.fromJsonObject<HashMap<String, Boolean>>(json) ?: hashMapOf()
|
||||
}
|
||||
|
||||
//忽略key
|
||||
val ignoreKeys = arrayOf(
|
||||
"readConfig",
|
||||
PreferKey.themeMode,
|
||||
PreferKey.bookshelfLayout,
|
||||
PreferKey.showRss,
|
||||
PreferKey.threadCount
|
||||
)
|
||||
|
||||
//忽略标题
|
||||
val ignoreTitle = arrayOf(
|
||||
appCtx.getString(R.string.read_config),
|
||||
appCtx.getString(R.string.theme_mode),
|
||||
appCtx.getString(R.string.bookshelf_layout),
|
||||
appCtx.getString(R.string.show_rss),
|
||||
appCtx.getString(R.string.thread_count)
|
||||
)
|
||||
|
||||
//默认忽略keys
|
||||
private val ignorePrefKeys = arrayOf(
|
||||
PreferKey.themeMode,
|
||||
PreferKey.defaultCover,
|
||||
PreferKey.defaultCoverDark
|
||||
)
|
||||
|
||||
//阅读配置
|
||||
private val readPrefKeys = arrayOf(
|
||||
PreferKey.readStyleSelect,
|
||||
PreferKey.shareLayout,
|
||||
PreferKey.hideStatusBar,
|
||||
PreferKey.hideNavigationBar,
|
||||
PreferKey.autoReadSpeed
|
||||
)
|
||||
object Restore : BackupRestore() {
|
||||
|
||||
suspend fun restore(context: Context, path: String) {
|
||||
withContext(IO) {
|
||||
@ -229,34 +189,6 @@ object Restore {
|
||||
}
|
||||
}
|
||||
|
||||
private fun keyIsNotIgnore(key: String): Boolean {
|
||||
return when {
|
||||
ignorePrefKeys.contains(key) -> false
|
||||
readPrefKeys.contains(key) && ignoreReadConfig -> false
|
||||
PreferKey.themeMode == key && ignoreThemeMode -> false
|
||||
PreferKey.bookshelfLayout == key && ignoreBookshelfLayout -> false
|
||||
PreferKey.showRss == key && ignoreShowRss -> false
|
||||
PreferKey.threadCount == key && ignoreThreadCount -> false
|
||||
else -> true
|
||||
}
|
||||
}
|
||||
|
||||
private val ignoreReadConfig: Boolean
|
||||
get() = ignoreConfig["readConfig"] == true
|
||||
private val ignoreThemeMode: Boolean
|
||||
get() = ignoreConfig[PreferKey.themeMode] == true
|
||||
private val ignoreBookshelfLayout: Boolean
|
||||
get() = ignoreConfig[PreferKey.bookshelfLayout] == true
|
||||
private val ignoreShowRss: Boolean
|
||||
get() = ignoreConfig[PreferKey.showRss] == true
|
||||
private val ignoreThreadCount: Boolean
|
||||
get() = ignoreConfig[PreferKey.threadCount] == true
|
||||
|
||||
fun saveIgnoreConfig() {
|
||||
val json = GSON.toJson(ignoreConfig)
|
||||
FileUtils.createFileIfNotExist(ignoreConfigPath).writeText(json)
|
||||
}
|
||||
|
||||
private inline fun <reified T> fileToListT(path: String, fileName: String): List<T>? {
|
||||
try {
|
||||
val file = FileUtils.createFileIfNotExist(path + File.separator + fileName)
|
||||
|
@ -36,6 +36,8 @@ object Permissions {
|
||||
const val READ_EXTERNAL_STORAGE = "android.permission.READ_EXTERNAL_STORAGE"
|
||||
const val WRITE_EXTERNAL_STORAGE = "android.permission.WRITE_EXTERNAL_STORAGE"
|
||||
|
||||
const val ACCESS_MEDIA_LOCATION = "android.permission.ACCESS_MEDIA_LOCATION"
|
||||
|
||||
object Group {
|
||||
val STORAGE = arrayOf(READ_EXTERNAL_STORAGE, WRITE_EXTERNAL_STORAGE)
|
||||
|
||||
|
@ -20,6 +20,7 @@ import java.util.regex.Pattern
|
||||
import javax.script.SimpleBindings
|
||||
|
||||
object LocalBook {
|
||||
|
||||
private const val folderName = "bookTxt"
|
||||
val cacheFolder: File by lazy {
|
||||
FileUtils.createFolderIfNotExist(appCtx.externalFiles, folderName)
|
||||
|
@ -1,25 +1,60 @@
|
||||
package io.legado.app.ui.association
|
||||
|
||||
import android.net.Uri
|
||||
import android.os.Bundle
|
||||
import androidx.activity.viewModels
|
||||
import androidx.documentfile.provider.DocumentFile
|
||||
import io.legado.app.R
|
||||
import io.legado.app.base.VMBaseActivity
|
||||
import io.legado.app.databinding.ActivityTranslucenceBinding
|
||||
import io.legado.app.help.AppConfig
|
||||
import io.legado.app.lib.dialogs.alert
|
||||
import io.legado.app.lib.permission.Permissions
|
||||
import io.legado.app.lib.permission.PermissionsCompat
|
||||
import io.legado.app.ui.book.read.ReadBookActivity
|
||||
import io.legado.app.utils.showDialogFragment
|
||||
import io.legado.app.utils.startActivity
|
||||
import io.legado.app.utils.toastOnUi
|
||||
import io.legado.app.ui.document.HandleFileContract
|
||||
import io.legado.app.utils.*
|
||||
import io.legado.app.utils.viewbindingdelegate.viewBinding
|
||||
import kotlinx.coroutines.Dispatchers.IO
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
|
||||
class FileAssociationActivity :
|
||||
VMBaseActivity<ActivityTranslucenceBinding, FileAssociationViewModel>() {
|
||||
|
||||
private val localBookTreeSelect = registerForActivityResult(HandleFileContract()) {
|
||||
it.uri?.let { treeUri ->
|
||||
intent.data?.let { uri ->
|
||||
importBook(treeUri, uri)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override val binding by viewBinding(ActivityTranslucenceBinding::inflate)
|
||||
|
||||
override val viewModel by viewModels<FileAssociationViewModel>()
|
||||
|
||||
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
||||
binding.rotateLoading.show()
|
||||
viewModel.importBookLiveData.observe(this) { uri ->
|
||||
if (uri.isContentScheme()) {
|
||||
val treeUriStr = AppConfig.defaultBookTreeUri
|
||||
if (treeUriStr.isNullOrEmpty()) {
|
||||
localBookTreeSelect.launch {
|
||||
title = "选择保存书籍的文件夹"
|
||||
}
|
||||
} else {
|
||||
importBook(Uri.parse(treeUriStr), uri)
|
||||
}
|
||||
} else {
|
||||
PermissionsCompat.Builder(this)
|
||||
.addPermissions(*Permissions.Group.STORAGE)
|
||||
.rationale(R.string.tip_perm_request_storage)
|
||||
.onGranted {
|
||||
viewModel.importBook(uri)
|
||||
}.request()
|
||||
}
|
||||
}
|
||||
viewModel.onLineImportLive.observe(this) {
|
||||
startActivity<OnLineImportActivity> {
|
||||
data = it
|
||||
@ -38,23 +73,55 @@ class FileAssociationActivity :
|
||||
binding.rotateLoading.hide()
|
||||
showDialogFragment(ImportReplaceRuleDialog(it, true))
|
||||
}
|
||||
viewModel.errorLiveData.observe(this, {
|
||||
viewModel.errorLiveData.observe(this) {
|
||||
binding.rotateLoading.hide()
|
||||
toastOnUi(it)
|
||||
finish()
|
||||
})
|
||||
viewModel.openBookLiveData.observe(this, {
|
||||
}
|
||||
viewModel.openBookLiveData.observe(this) {
|
||||
binding.rotateLoading.hide()
|
||||
startActivity<ReadBookActivity> {
|
||||
putExtra("bookUrl", it)
|
||||
}
|
||||
finish()
|
||||
})
|
||||
}
|
||||
intent.data?.let { data ->
|
||||
viewModel.dispatchIndent(data, this::finallyDialog)
|
||||
}
|
||||
}
|
||||
|
||||
private fun importBook(treeUri: Uri, uri: Uri) {
|
||||
val treeDoc = DocumentFile.fromTreeUri(this, treeUri)
|
||||
val bookDoc = DocumentFile.fromSingleUri(this, uri)
|
||||
launch {
|
||||
runCatching {
|
||||
withContext(IO) {
|
||||
val name = bookDoc?.name!!
|
||||
val doc = treeDoc!!.findFile(name)
|
||||
if (doc != null) {
|
||||
viewModel.importBook(doc.uri)
|
||||
} else {
|
||||
val nDoc = treeDoc.createFile(FileUtils.getMimeType(name), name)!!
|
||||
contentResolver.openOutputStream(nDoc.uri)!!.use { oStream ->
|
||||
contentResolver.openInputStream(bookDoc.uri)!!.use { iStream ->
|
||||
val brr = ByteArray(1024)
|
||||
var len: Int
|
||||
while ((iStream.read(brr, 0, brr.size)
|
||||
.also { len = it }) != -1
|
||||
) {
|
||||
oStream.write(brr, 0, len)
|
||||
}
|
||||
oStream.flush()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}.onFailure {
|
||||
toastOnUi(it.localizedMessage)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun finallyDialog(title: String, msg: String) {
|
||||
alert(title, msg) {
|
||||
okButton()
|
||||
|
@ -1,30 +1,24 @@
|
||||
package io.legado.app.ui.association
|
||||
|
||||
import android.app.Application
|
||||
import android.app.RecoverableSecurityException
|
||||
import android.content.IntentSender
|
||||
import android.net.Uri
|
||||
import android.os.Build
|
||||
import androidx.documentfile.provider.DocumentFile
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import io.legado.app.help.BookMediaStore
|
||||
import io.legado.app.model.NoStackTraceException
|
||||
import io.legado.app.model.localBook.LocalBook
|
||||
import io.legado.app.utils.isContentScheme
|
||||
import io.legado.app.utils.isJson
|
||||
import io.legado.app.utils.readText
|
||||
import splitties.init.appCtx
|
||||
import timber.log.Timber
|
||||
import java.io.File
|
||||
|
||||
class FileAssociationViewModel(application: Application) : BaseAssociationViewModel(application) {
|
||||
val importBookLiveData = MutableLiveData<Uri>()
|
||||
val onLineImportLive = MutableLiveData<Uri>()
|
||||
val importBookSourceLive = MutableLiveData<String>()
|
||||
val importRssSourceLive = MutableLiveData<String>()
|
||||
val importReplaceRuleLive = MutableLiveData<String>()
|
||||
val openBookLiveData = MutableLiveData<String>()
|
||||
val errorLiveData = MutableLiveData<String>()
|
||||
val recoverErrorLiveData = MutableLiveData<IntentSender>()
|
||||
|
||||
@Suppress("BlockingMethodInNonBlockingContext")
|
||||
fun dispatchIndent(uri: Uri, finally: (title: String, msg: String) -> Unit) {
|
||||
@ -54,51 +48,19 @@ class FileAssociationViewModel(application: Application) : BaseAssociationViewMo
|
||||
else -> errorLiveData.postValue("格式不对")
|
||||
}
|
||||
} else {
|
||||
if (uri.isContentScheme()) {
|
||||
val doc = DocumentFile.fromSingleUri(appCtx, uri)!!
|
||||
val bookDoc = BookMediaStore.getBook(doc.name!!)
|
||||
if (bookDoc == null) {
|
||||
val bookUri = BookMediaStore.insertBook(doc)
|
||||
val book = LocalBook.importFile(bookUri!!)
|
||||
openBookLiveData.postValue(book.bookUrl)
|
||||
} else {
|
||||
if (doc.lastModified() > bookDoc.date.time) {
|
||||
context.contentResolver.openOutputStream(bookDoc.uri)
|
||||
.use { outputStream ->
|
||||
val brr = ByteArray(1024)
|
||||
var len: Int
|
||||
val bufferedInputStream =
|
||||
appCtx.contentResolver.openInputStream(doc.uri)!!
|
||||
while ((bufferedInputStream.read(brr, 0, brr.size)
|
||||
.also { len = it }) != -1
|
||||
) {
|
||||
outputStream?.write(brr, 0, len)
|
||||
}
|
||||
outputStream?.flush()
|
||||
bufferedInputStream.close()
|
||||
}
|
||||
}
|
||||
val book = LocalBook.importFile(bookDoc.uri)
|
||||
openBookLiveData.postValue(book.bookUrl)
|
||||
}
|
||||
} else {
|
||||
val book = LocalBook.importFile(uri)
|
||||
openBookLiveData.postValue(book.bookUrl)
|
||||
}
|
||||
importBookLiveData.postValue(uri)
|
||||
}
|
||||
} else {
|
||||
onLineImportLive.postValue(uri)
|
||||
}
|
||||
}.onError {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
||||
if (it is RecoverableSecurityException) {
|
||||
val intentSender = it.userAction.actionIntent.intentSender
|
||||
recoverErrorLiveData.postValue(intentSender)
|
||||
return@onError
|
||||
}
|
||||
}
|
||||
Timber.e(it)
|
||||
errorLiveData.postValue(it.localizedMessage)
|
||||
}
|
||||
}
|
||||
|
||||
fun importBook(uri: Uri) {
|
||||
val book = LocalBook.importFile(uri)
|
||||
openBookLiveData.postValue(book.bookUrl)
|
||||
}
|
||||
}
|
@ -207,7 +207,7 @@ class BackupConfigFragment : BasePreferenceFragment(),
|
||||
override fun onPreferenceTreeClick(preference: Preference?): Boolean {
|
||||
when (preference?.key) {
|
||||
PreferKey.backupPath -> selectBackupPath.launch()
|
||||
PreferKey.restoreIgnore -> restoreIgnore()
|
||||
PreferKey.restoreIgnore -> backupIgnore()
|
||||
"web_dav_backup" -> backup()
|
||||
"web_dav_restore" -> restore()
|
||||
"import_old" -> restoreOld.launch()
|
||||
@ -216,16 +216,16 @@ class BackupConfigFragment : BasePreferenceFragment(),
|
||||
}
|
||||
|
||||
|
||||
private fun restoreIgnore() {
|
||||
val checkedItems = BooleanArray(Restore.ignoreKeys.size) {
|
||||
Restore.ignoreConfig[Restore.ignoreKeys[it]] ?: false
|
||||
private fun backupIgnore() {
|
||||
val checkedItems = BooleanArray(Backup.ignoreKeys.size) {
|
||||
Backup.ignoreConfig[Backup.ignoreKeys[it]] ?: false
|
||||
}
|
||||
alert(R.string.restore_ignore) {
|
||||
multiChoiceItems(Restore.ignoreTitle, checkedItems) { _, which, isChecked ->
|
||||
Restore.ignoreConfig[Restore.ignoreKeys[which]] = isChecked
|
||||
multiChoiceItems(Backup.ignoreTitle, checkedItems) { _, which, isChecked ->
|
||||
Backup.ignoreConfig[Backup.ignoreKeys[which]] = isChecked
|
||||
}
|
||||
onDismiss {
|
||||
Restore.saveIgnoreConfig()
|
||||
Backup.saveIgnoreConfig()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user