|
@@ -4,12 +4,14 @@ import android.net.Uri
|
|
|
import android.os.Build
|
|
import android.os.Build
|
|
|
import android.os.Bundle
|
|
import android.os.Bundle
|
|
|
import androidx.activity.viewModels
|
|
import androidx.activity.viewModels
|
|
|
|
|
+import androidx.core.os.postDelayed
|
|
|
import androidx.documentfile.provider.DocumentFile
|
|
import androidx.documentfile.provider.DocumentFile
|
|
|
import androidx.lifecycle.lifecycleScope
|
|
import androidx.lifecycle.lifecycleScope
|
|
|
import io.legado.app.R
|
|
import io.legado.app.R
|
|
|
import io.legado.app.base.VMBaseActivity
|
|
import io.legado.app.base.VMBaseActivity
|
|
|
import io.legado.app.constant.AppLog
|
|
import io.legado.app.constant.AppLog
|
|
|
import io.legado.app.databinding.ActivityTranslucenceBinding
|
|
import io.legado.app.databinding.ActivityTranslucenceBinding
|
|
|
|
|
+import io.legado.app.exception.InvalidBooksDirException
|
|
|
import io.legado.app.help.config.AppConfig
|
|
import io.legado.app.help.config.AppConfig
|
|
|
import io.legado.app.lib.dialogs.alert
|
|
import io.legado.app.lib.dialogs.alert
|
|
|
import io.legado.app.lib.permission.Permissions
|
|
import io.legado.app.lib.permission.Permissions
|
|
@@ -17,6 +19,8 @@ import io.legado.app.lib.permission.PermissionsCompat
|
|
|
import io.legado.app.ui.book.read.ReadBookActivity
|
|
import io.legado.app.ui.book.read.ReadBookActivity
|
|
|
import io.legado.app.ui.file.HandleFileContract
|
|
import io.legado.app.ui.file.HandleFileContract
|
|
|
import io.legado.app.utils.FileUtils
|
|
import io.legado.app.utils.FileUtils
|
|
|
|
|
+import io.legado.app.utils.buildMainHandler
|
|
|
|
|
+import io.legado.app.utils.canRead
|
|
|
import io.legado.app.utils.checkWrite
|
|
import io.legado.app.utils.checkWrite
|
|
|
import io.legado.app.utils.getFile
|
|
import io.legado.app.utils.getFile
|
|
|
import io.legado.app.utils.isContentScheme
|
|
import io.legado.app.utils.isContentScheme
|
|
@@ -43,7 +47,7 @@ class FileAssociationActivity :
|
|
|
} ?: let {
|
|
} ?: let {
|
|
|
val storageHelp = String(assets.open("storageHelp.md").readBytes())
|
|
val storageHelp = String(assets.open("storageHelp.md").readBytes())
|
|
|
toastOnUi(storageHelp)
|
|
toastOnUi(storageHelp)
|
|
|
- viewModel.importBook(uri)
|
|
|
|
|
|
|
+ importBook(null, uri)
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
@@ -52,6 +56,10 @@ class FileAssociationActivity :
|
|
|
|
|
|
|
|
override val viewModel by viewModels<FileAssociationViewModel>()
|
|
override val viewModel by viewModels<FileAssociationViewModel>()
|
|
|
|
|
|
|
|
|
|
+ private val handler by lazy {
|
|
|
|
|
+ buildMainHandler()
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
|
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
|
|
binding.rotateLoading.visible()
|
|
binding.rotateLoading.visible()
|
|
|
viewModel.importBookLiveData.observe(this) { uri ->
|
|
viewModel.importBookLiveData.observe(this) { uri ->
|
|
@@ -114,21 +122,20 @@ class FileAssociationActivity :
|
|
|
noButton {
|
|
noButton {
|
|
|
finish()
|
|
finish()
|
|
|
}
|
|
}
|
|
|
|
|
+ onCancelled {
|
|
|
|
|
+ finish()
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
intent.data?.let { data ->
|
|
intent.data?.let { data ->
|
|
|
if (data.isContentScheme()) {
|
|
if (data.isContentScheme()) {
|
|
|
- viewModel.dispatchIndent(data)
|
|
|
|
|
|
|
+ if (data.canRead()) {
|
|
|
|
|
+ viewModel.dispatchIntent(data)
|
|
|
|
|
+ } else {
|
|
|
|
|
+ dispatchWithPermission(data)
|
|
|
|
|
+ }
|
|
|
} else if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.Q) {
|
|
} else if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.Q) {
|
|
|
- PermissionsCompat.Builder()
|
|
|
|
|
- .addPermissions(*Permissions.Group.STORAGE)
|
|
|
|
|
- .rationale(R.string.tip_perm_request_storage)
|
|
|
|
|
- .onGranted {
|
|
|
|
|
- viewModel.dispatchIndent(data)
|
|
|
|
|
- }.onDenied {
|
|
|
|
|
- toastOnUi("请求存储权限失败。")
|
|
|
|
|
- finish()
|
|
|
|
|
- }.request()
|
|
|
|
|
|
|
+ dispatchWithPermission(data)
|
|
|
} else {
|
|
} else {
|
|
|
toastOnUi("由于安卓系统限制,请使用系统文件管理重新打开。")
|
|
toastOnUi("由于安卓系统限制,请使用系统文件管理重新打开。")
|
|
|
finish()
|
|
finish()
|
|
@@ -136,6 +143,18 @@ class FileAssociationActivity :
|
|
|
} ?: finish()
|
|
} ?: finish()
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ private fun dispatchWithPermission(data: Uri) {
|
|
|
|
|
+ PermissionsCompat.Builder()
|
|
|
|
|
+ .addPermissions(*Permissions.Group.STORAGE)
|
|
|
|
|
+ .rationale(R.string.tip_perm_request_storage)
|
|
|
|
|
+ .onGranted {
|
|
|
|
|
+ viewModel.dispatchIntent(data)
|
|
|
|
|
+ }.onDenied {
|
|
|
|
|
+ toastOnUi("请求存储权限失败。")
|
|
|
|
|
+ finish()
|
|
|
|
|
+ }.request()
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
private fun importBook(uri: Uri) {
|
|
private fun importBook(uri: Uri) {
|
|
|
if (uri.isContentScheme()) {
|
|
if (uri.isContentScheme()) {
|
|
|
val treeUriStr = AppConfig.defaultBookTreeUri
|
|
val treeUriStr = AppConfig.defaultBookTreeUri
|
|
@@ -148,19 +167,21 @@ class FileAssociationActivity :
|
|
|
importBook(Uri.parse(treeUriStr), uri)
|
|
importBook(Uri.parse(treeUriStr), uri)
|
|
|
}
|
|
}
|
|
|
} else {
|
|
} else {
|
|
|
- viewModel.importBook(uri)
|
|
|
|
|
|
|
+ importBook(null, uri)
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- private fun importBook(treeUri: Uri, uri: Uri) {
|
|
|
|
|
|
|
+ private fun importBook(treeUri: Uri?, uri: Uri) {
|
|
|
lifecycleScope.launch {
|
|
lifecycleScope.launch {
|
|
|
runCatching {
|
|
runCatching {
|
|
|
withContext(IO) {
|
|
withContext(IO) {
|
|
|
- if (treeUri.isContentScheme()) {
|
|
|
|
|
|
|
+ if (treeUri == null) {
|
|
|
|
|
+ viewModel.importBook(uri)
|
|
|
|
|
+ } else if (treeUri.isContentScheme()) {
|
|
|
val treeDoc =
|
|
val treeDoc =
|
|
|
DocumentFile.fromTreeUri(this@FileAssociationActivity, treeUri)
|
|
DocumentFile.fromTreeUri(this@FileAssociationActivity, treeUri)
|
|
|
if (!treeDoc!!.checkWrite()) {
|
|
if (!treeDoc!!.checkWrite()) {
|
|
|
- throw SecurityException("请重新设置书籍保存位置\nPermission Denial")
|
|
|
|
|
|
|
+ throw InvalidBooksDirException("请重新设置书籍保存位置\nPermission Denial")
|
|
|
}
|
|
}
|
|
|
readUri(uri) { fileDoc, inputStream ->
|
|
readUri(uri) { fileDoc, inputStream ->
|
|
|
val name = fileDoc.name
|
|
val name = fileDoc.name
|
|
@@ -168,7 +189,7 @@ class FileAssociationActivity :
|
|
|
if (doc == null || fileDoc.lastModified > doc.lastModified()) {
|
|
if (doc == null || fileDoc.lastModified > doc.lastModified()) {
|
|
|
if (doc == null) {
|
|
if (doc == null) {
|
|
|
doc = treeDoc.createFile(FileUtils.getMimeType(name), name)
|
|
doc = treeDoc.createFile(FileUtils.getMimeType(name), name)
|
|
|
- ?: throw SecurityException("请重新设置书籍保存位置\nPermission Denial")
|
|
|
|
|
|
|
+ ?: throw InvalidBooksDirException("请重新设置书籍保存位置\nPermission Denial")
|
|
|
}
|
|
}
|
|
|
contentResolver.openOutputStream(doc.uri)!!.use { oStream ->
|
|
contentResolver.openOutputStream(doc.uri)!!.use { oStream ->
|
|
|
inputStream.copyTo(oStream)
|
|
inputStream.copyTo(oStream)
|
|
@@ -180,7 +201,7 @@ class FileAssociationActivity :
|
|
|
} else {
|
|
} else {
|
|
|
val treeFile = File(treeUri.path ?: treeUri.toString())
|
|
val treeFile = File(treeUri.path ?: treeUri.toString())
|
|
|
if (!treeFile.checkWrite()) {
|
|
if (!treeFile.checkWrite()) {
|
|
|
- throw SecurityException("请重新设置书籍保存位置\nPermission Denial")
|
|
|
|
|
|
|
+ throw InvalidBooksDirException("请重新设置书籍保存位置\nPermission Denial")
|
|
|
}
|
|
}
|
|
|
readUri(uri) { fileDoc, inputStream ->
|
|
readUri(uri) { fileDoc, inputStream ->
|
|
|
val name = fileDoc.name
|
|
val name = fileDoc.name
|
|
@@ -197,7 +218,7 @@ class FileAssociationActivity :
|
|
|
}
|
|
}
|
|
|
}.onFailure {
|
|
}.onFailure {
|
|
|
when (it) {
|
|
when (it) {
|
|
|
- is SecurityException -> localBookTreeSelect.launch {
|
|
|
|
|
|
|
+ is InvalidBooksDirException -> localBookTreeSelect.launch {
|
|
|
title = getString(R.string.select_book_folder)
|
|
title = getString(R.string.select_book_folder)
|
|
|
mode = HandleFileContract.DIR_SYS
|
|
mode = HandleFileContract.DIR_SYS
|
|
|
}
|
|
}
|
|
@@ -206,7 +227,9 @@ class FileAssociationActivity :
|
|
|
val msg = "导入书籍失败\n${it.localizedMessage}"
|
|
val msg = "导入书籍失败\n${it.localizedMessage}"
|
|
|
AppLog.put(msg, it)
|
|
AppLog.put(msg, it)
|
|
|
toastOnUi(msg)
|
|
toastOnUi(msg)
|
|
|
- finish()
|
|
|
|
|
|
|
+ handler.postDelayed(2000) {
|
|
|
|
|
+ finish()
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|