pull/1738/head
kunfei 3 years ago
parent fa11028997
commit a3b9917c47
  1. 29
      app/src/main/java/io/legado/app/ui/association/FileAssociationActivity.kt
  2. 9
      app/src/main/java/io/legado/app/ui/book/group/GroupEditDialog.kt
  3. 11
      app/src/main/java/io/legado/app/ui/book/info/edit/BookInfoEditActivity.kt
  4. 2
      app/src/main/java/io/legado/app/ui/book/local/ImportBookAdapter.kt
  5. 2
      app/src/main/java/io/legado/app/ui/book/local/ImportBookViewModel.kt
  6. 9
      app/src/main/java/io/legado/app/ui/book/read/config/BgTextConfigDialog.kt
  7. 9
      app/src/main/java/io/legado/app/ui/config/CoverConfigFragment.kt
  8. 9
      app/src/main/java/io/legado/app/ui/config/ThemeConfigFragment.kt
  9. 9
      app/src/main/java/io/legado/app/ui/config/WelcomeConfigFragment.kt
  10. 11
      app/src/main/java/io/legado/app/utils/DocumentExtensions.kt
  11. 42
      app/src/main/java/io/legado/app/utils/UriExtensions.kt

@ -102,43 +102,40 @@ class FileAssociationActivity :
private fun importBook(treeUri: Uri, uri: Uri) {
launch {
runCatching {
if (treeUri.isContentScheme()) {
val treeDoc = DocumentFile.fromTreeUri(this@FileAssociationActivity, treeUri)
val bookDoc = DocumentFile.fromSingleUri(this@FileAssociationActivity, uri)
withContext(IO) {
val name = bookDoc?.name!!
if (treeUri.isContentScheme()) {
val treeDoc =
DocumentFile.fromTreeUri(this@FileAssociationActivity, treeUri)
readUri(uri) { fileDoc, inputStream ->
val name = fileDoc.name
var doc = treeDoc!!.findFile(name)
if (doc == null || bookDoc.lastModified() > doc.lastModified()) {
if (doc == null || fileDoc.lastModified > doc.lastModified()) {
if (doc == null) {
doc = treeDoc.createFile(FileUtils.getMimeType(name), name)
?: throw SecurityException("Permission Denial")
}
contentResolver.openOutputStream(doc.uri)!!.use { oStream ->
contentResolver.openInputStream(bookDoc.uri)!!.use { iStream ->
iStream.copyTo(oStream)
inputStream.copyTo(oStream)
oStream.flush()
}
}
}
viewModel.importBook(doc.uri)
}
} else {
val treeFile = File(treeUri.path!!)
val bookDoc = DocumentFile.fromSingleUri(this@FileAssociationActivity, uri)
withContext(IO) {
val name = bookDoc?.name!!
val treeFile = File(treeUri.path ?: treeUri.toString())
readUri(uri) { fileDoc, inputStream ->
val name = fileDoc.name
val file = treeFile.getFile(name)
if (!file.exists() || file.lastModified() < bookDoc.lastModified()) {
if (!file.exists() || fileDoc.lastModified > file.lastModified()) {
FileOutputStream(file).use { oStream ->
contentResolver.openInputStream(bookDoc.uri)!!.use { iStream ->
iStream.copyTo(oStream)
inputStream.copyTo(oStream)
oStream.flush()
}
}
}
viewModel.importBook(Uri.fromFile(file))
}
}
}
}.onFailure {
when (it) {
is SecurityException -> localBookTreeSelect.launch {

@ -13,6 +13,7 @@ import io.legado.app.lib.theme.primaryColor
import io.legado.app.utils.*
import io.legado.app.utils.viewbindingdelegate.viewBinding
import splitties.views.onClick
import java.io.FileOutputStream
class GroupEditDialog() : BaseDialogFragment(R.layout.dialog_book_group_edit) {
@ -26,10 +27,12 @@ class GroupEditDialog() : BaseDialogFragment(R.layout.dialog_book_group_edit) {
private val viewModel by viewModels<GroupViewModel>()
private var bookGroup: BookGroup? = null
val selectImage = registerForActivityResult(SelectImageContract()) {
readUri(it?.uri) { name, bytes ->
readUri(it?.uri) { fileDoc, inputStream ->
var file = requireContext().externalFiles
file = FileUtils.createFileIfNotExist(file, "covers", name)
file.writeBytes(bytes)
file = FileUtils.createFileIfNotExist(file, "covers", fileDoc.name)
FileOutputStream(file).use { outputStream ->
inputStream.copyTo(outputStream)
}
binding.ivCover.load(file.absolutePath)
}
}

@ -13,6 +13,7 @@ import io.legado.app.databinding.ActivityBookInfoEditBinding
import io.legado.app.ui.book.changecover.ChangeCoverDialog
import io.legado.app.utils.*
import io.legado.app.utils.viewbindingdelegate.viewBinding
import java.io.FileOutputStream
class BookInfoEditActivity :
VMBaseActivity<ActivityBookInfoEditBinding, BookInfoEditViewModel>(),
@ -101,12 +102,16 @@ class BookInfoEditActivity :
}
private fun coverChangeTo(uri: Uri) {
readUri(uri) { name, bytes ->
readUri(uri) { fileDoc, inputStream ->
inputStream.use {
var file = this.externalFiles
file = FileUtils.createFileIfNotExist(file, "covers", name)
file.writeBytes(bytes)
file = FileUtils.createFileIfNotExist(file, "covers", fileDoc.name)
FileOutputStream(file).use { outputStream ->
inputStream.copyTo(outputStream)
}
coverChangeTo(file.absolutePath)
}
}
}
}

@ -52,7 +52,7 @@ class ImportBookAdapter(context: Context, val callBack: CallBack) :
llBrief.visible()
tvTag.text = item.name.substringAfterLast(".")
tvSize.text = ConvertUtils.formatFileSize(item.size)
tvDate.text = AppConst.dateFormat.format(item.date)
tvDate.text = AppConst.dateFormat.format(item.lastModified)
cbSelect.isChecked = selectedUris.contains(item.toString())
}
tvName.text = item.name

@ -59,7 +59,7 @@ class ImportBookViewModel(application: Application) : BaseViewModel(application)
}.map { docList ->
when (sort) {
2 -> docList.sortedWith(
compareBy({ !it.isDir }, { it.date }, { it.name })
compareBy({ !it.isDir }, { it.lastModified }, { it.name })
)
1 -> docList.sortedWith(
compareBy({ !it.isDir }, { it.size }, { it.name })

@ -35,6 +35,7 @@ import io.legado.app.utils.*
import io.legado.app.utils.viewbindingdelegate.viewBinding
import java.io.File
import java.io.FileOutputStream
class BgTextConfigDialog : BaseDialogFragment(R.layout.dialog_read_bg_text) {
@ -350,10 +351,12 @@ class BgTextConfigDialog : BaseDialogFragment(R.layout.dialog_read_bg_text) {
}
private fun setBgFromUri(uri: Uri) {
readUri(uri) { name, bytes ->
readUri(uri) { fileDoc, inputStream ->
var file = requireContext().externalFiles
file = FileUtils.createFileIfNotExist(file, "bg", name)
file.writeBytes(bytes)
file = FileUtils.createFileIfNotExist(file, "bg", fileDoc.name)
FileOutputStream(file).use { outputStream ->
inputStream.copyTo(outputStream)
}
ReadBookConfig.durConfig.setCurBg(2, file.absolutePath)
ReadBookConfig.upBg()
postEvent(EventBus.UP_CONFIG, false)

@ -14,6 +14,7 @@ import io.legado.app.lib.theme.primaryColor
import io.legado.app.model.BookCover
import io.legado.app.ui.widget.prefs.SwitchPreference
import io.legado.app.utils.*
import java.io.FileOutputStream
class CoverConfigFragment : BasePreferenceFragment(),
SharedPreferences.OnSharedPreferenceChangeListener {
@ -138,10 +139,12 @@ class CoverConfigFragment : BasePreferenceFragment(),
}
private fun setCoverFromUri(preferenceKey: String, uri: Uri) {
readUri(uri) { name, bytes ->
readUri(uri) { fileDoc, inputStream ->
var file = requireContext().externalFiles
file = FileUtils.createFileIfNotExist(file, "covers", name)
file.writeBytes(bytes)
file = FileUtils.createFileIfNotExist(file, "covers", fileDoc.name)
FileOutputStream(file).use {
inputStream.copyTo(it)
}
putPrefString(preferenceKey, file.absolutePath)
BookCover.upDefaultCover()
}

@ -29,6 +29,7 @@ import io.legado.app.ui.widget.number.NumberPickerDialog
import io.legado.app.ui.widget.prefs.ColorPreference
import io.legado.app.ui.widget.seekbar.SeekBarChangeListener
import io.legado.app.utils.*
import java.io.FileOutputStream
@Suppress("SameParameterValue")
@ -298,10 +299,12 @@ class ThemeConfigFragment : BasePreferenceFragment(),
}
private fun setBgFromUri(uri: Uri, preferenceKey: String, success: () -> Unit) {
readUri(uri) { name, bytes ->
readUri(uri) { fileDoc, inputStream ->
var file = requireContext().externalFiles
file = FileUtils.createFileIfNotExist(file, preferenceKey, name)
file.writeBytes(bytes)
file = FileUtils.createFileIfNotExist(file, preferenceKey, fileDoc.name)
FileOutputStream(file).use {
inputStream.copyTo(it)
}
putPrefString(preferenceKey, file.absolutePath)
success()
}

@ -13,6 +13,7 @@ import io.legado.app.lib.dialogs.selector
import io.legado.app.lib.theme.primaryColor
import io.legado.app.model.BookCover
import io.legado.app.utils.*
import java.io.FileOutputStream
class WelcomeConfigFragment : BasePreferenceFragment(),
SharedPreferences.OnSharedPreferenceChangeListener {
@ -118,10 +119,12 @@ class WelcomeConfigFragment : BasePreferenceFragment(),
}
private fun setCoverFromUri(preferenceKey: String, uri: Uri) {
readUri(uri) { name, bytes ->
readUri(uri) { fileDoc, inputStream ->
var file = requireContext().externalFiles
file = FileUtils.createFileIfNotExist(file, "covers", name)
file.writeBytes(bytes)
file = FileUtils.createFileIfNotExist(file, "covers", fileDoc.name)
FileOutputStream(file).use {
inputStream.copyTo(it)
}
putPrefString(preferenceKey, file.absolutePath)
}
}

@ -9,7 +9,6 @@ import io.legado.app.exception.NoStackTraceException
import splitties.init.appCtx
import java.io.File
import java.nio.charset.Charset
import java.util.*
@Suppress("MemberVisibilityCanBePrivate")
@ -125,7 +124,7 @@ object DocumentUtils {
name = cursor.getString(nci),
isDir = cursor.getString(mci) == DocumentsContract.Document.MIME_TYPE_DIR,
size = cursor.getLong(sci),
date = Date(cursor.getLong(dci)),
lastModified = cursor.getLong(dci),
uri = DocumentsContract
.buildDocumentUriUsingTree(uri, cursor.getString(ici))
)
@ -150,7 +149,7 @@ object DocumentUtils {
it.name,
it.isDirectory,
it.length(),
Date(it.lastModified()),
it.lastModified(),
Uri.fromFile(it)
)
if (filter == null || filter.invoke(item)) {
@ -166,7 +165,7 @@ data class FileDoc(
val name: String,
val isDir: Boolean,
val size: Long,
val date: Date,
val lastModified: Long,
val uri: Uri
) {
@ -187,7 +186,7 @@ data class FileDoc(
name = doc.name ?: "",
isDir = doc.isDirectory,
size = doc.length(),
date = Date(doc.lastModified()),
lastModified = doc.lastModified(),
uri = doc.uri
)
}
@ -197,7 +196,7 @@ data class FileDoc(
name = file.name,
isDir = file.isDirectory,
size = file.length(),
date = Date(file.lastModified()),
lastModified = file.lastModified(),
uri = Uri.fromFile(file)
)
}

@ -10,32 +10,41 @@ import io.legado.app.exception.NoStackTraceException
import io.legado.app.lib.permission.Permissions
import io.legado.app.lib.permission.PermissionsCompat
import java.io.File
import java.io.FileInputStream
import java.io.InputStream
fun Uri.isContentScheme() = this.scheme == "content"
/**
* 读取URI
*/
fun AppCompatActivity.readUri(uri: Uri?, success: (name: String, bytes: ByteArray) -> Unit) {
fun AppCompatActivity.readUri(
uri: Uri?,
success: (fileDoc: FileDoc, inputStream: InputStream) -> Unit
) {
uri ?: return
try {
if (uri.isContentScheme()) {
val doc = DocumentFile.fromSingleUri(this, uri)
doc ?: throw NoStackTraceException("未获取到文件")
val name = doc.name ?: throw NoStackTraceException("未获取到文件名")
val fileBytes = DocumentUtils.readBytes(this, doc.uri)
success.invoke(name, fileBytes)
val fileDoc = FileDoc.fromDocumentFile(doc)
contentResolver.openInputStream(uri)!!.use { inputStream ->
success.invoke(fileDoc, inputStream)
}
} else {
PermissionsCompat.Builder(this)
.addPermissions(
Permissions.READ_EXTERNAL_STORAGE,
Permissions.WRITE_EXTERNAL_STORAGE
)
.rationale(R.string.bg_image_per)
.rationale(R.string.get_storage_per)
.onGranted {
RealPathUtil.getPath(this, uri)?.let { path ->
val imgFile = File(path)
success.invoke(imgFile.name, imgFile.readBytes())
val file = File(path)
val fileDoc = FileDoc.fromFile(file)
FileInputStream(file).use { inputStream ->
success.invoke(fileDoc, inputStream)
}
}
}
.request()
@ -49,26 +58,31 @@ fun AppCompatActivity.readUri(uri: Uri?, success: (name: String, bytes: ByteArra
/**
* 读取URI
*/
fun Fragment.readUri(uri: Uri?, success: (name: String, bytes: ByteArray) -> Unit) {
fun Fragment.readUri(uri: Uri?, success: (fileDoc: FileDoc, inputStream: InputStream) -> Unit) {
uri ?: return
try {
if (uri.isContentScheme()) {
val doc = DocumentFile.fromSingleUri(requireContext(), uri)
doc ?: throw NoStackTraceException("未获取到文件")
val name = doc.name ?: throw NoStackTraceException("未获取到文件名")
val fileBytes = DocumentUtils.readBytes(requireContext(), doc.uri)
success.invoke(name, fileBytes)
val fileDoc = FileDoc.fromDocumentFile(doc)
requireContext().contentResolver.openInputStream(uri)!!.use { inputStream ->
success.invoke(fileDoc, inputStream)
}
} else {
PermissionsCompat.Builder(this)
.addPermissions(
Permissions.READ_EXTERNAL_STORAGE,
Permissions.WRITE_EXTERNAL_STORAGE
)
.rationale(R.string.bg_image_per)
.rationale(R.string.get_storage_per)
.onGranted {
RealPathUtil.getPath(requireContext(), uri)?.let { path ->
val imgFile = File(path)
success.invoke(imgFile.name, imgFile.readBytes())
val file = File(path)
val fileDoc = FileDoc.fromFile(file)
FileInputStream(file).use { inputStream ->
success.invoke(fileDoc, inputStream)
}
}
}
.request()

Loading…
Cancel
Save