kunfei há 4 anos atrás
pai
commit
6e90ac64d1

+ 24 - 27
app/src/main/java/io/legado/app/ui/association/FileAssociationActivity.kt

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

+ 6 - 3
app/src/main/java/io/legado/app/ui/book/group/GroupEditDialog.kt

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

+ 10 - 5
app/src/main/java/io/legado/app/ui/book/info/edit/BookInfoEditActivity.kt

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

+ 1 - 1
app/src/main/java/io/legado/app/ui/book/local/ImportBookAdapter.kt

@@ -52,7 +52,7 @@ class ImportBookAdapter(context: Context, val callBack: CallBack) :
                     llBrief.visible()
                     llBrief.visible()
                     tvTag.text = item.name.substringAfterLast(".")
                     tvTag.text = item.name.substringAfterLast(".")
                     tvSize.text = ConvertUtils.formatFileSize(item.size)
                     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())
                     cbSelect.isChecked = selectedUris.contains(item.toString())
                 }
                 }
                 tvName.text = item.name
                 tvName.text = item.name

+ 1 - 1
app/src/main/java/io/legado/app/ui/book/local/ImportBookViewModel.kt

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

+ 6 - 3
app/src/main/java/io/legado/app/ui/book/read/config/BgTextConfigDialog.kt

@@ -35,6 +35,7 @@ import io.legado.app.utils.*
 import io.legado.app.utils.viewbindingdelegate.viewBinding
 import io.legado.app.utils.viewbindingdelegate.viewBinding
 
 
 import java.io.File
 import java.io.File
+import java.io.FileOutputStream
 
 
 class BgTextConfigDialog : BaseDialogFragment(R.layout.dialog_read_bg_text) {
 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) {
     private fun setBgFromUri(uri: Uri) {
-        readUri(uri) { name, bytes ->
+        readUri(uri) { fileDoc, inputStream ->
             var file = requireContext().externalFiles
             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.durConfig.setCurBg(2, file.absolutePath)
             ReadBookConfig.upBg()
             ReadBookConfig.upBg()
             postEvent(EventBus.UP_CONFIG, false)
             postEvent(EventBus.UP_CONFIG, false)

+ 6 - 3
app/src/main/java/io/legado/app/ui/config/CoverConfigFragment.kt

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

+ 6 - 3
app/src/main/java/io/legado/app/ui/config/ThemeConfigFragment.kt

@@ -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.prefs.ColorPreference
 import io.legado.app.ui.widget.seekbar.SeekBarChangeListener
 import io.legado.app.ui.widget.seekbar.SeekBarChangeListener
 import io.legado.app.utils.*
 import io.legado.app.utils.*
+import java.io.FileOutputStream
 
 
 
 
 @Suppress("SameParameterValue")
 @Suppress("SameParameterValue")
@@ -298,10 +299,12 @@ class ThemeConfigFragment : BasePreferenceFragment(),
     }
     }
 
 
     private fun setBgFromUri(uri: Uri, preferenceKey: String, success: () -> Unit) {
     private fun setBgFromUri(uri: Uri, preferenceKey: String, success: () -> Unit) {
-        readUri(uri) { name, bytes ->
+        readUri(uri) { fileDoc, inputStream ->
             var file = requireContext().externalFiles
             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)
             putPrefString(preferenceKey, file.absolutePath)
             success()
             success()
         }
         }

+ 6 - 3
app/src/main/java/io/legado/app/ui/config/WelcomeConfigFragment.kt

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

+ 5 - 6
app/src/main/java/io/legado/app/utils/DocumentExtensions.kt

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

+ 28 - 14
app/src/main/java/io/legado/app/utils/UriExtensions.kt

@@ -10,32 +10,41 @@ import io.legado.app.exception.NoStackTraceException
 import io.legado.app.lib.permission.Permissions
 import io.legado.app.lib.permission.Permissions
 import io.legado.app.lib.permission.PermissionsCompat
 import io.legado.app.lib.permission.PermissionsCompat
 import java.io.File
 import java.io.File
+import java.io.FileInputStream
+import java.io.InputStream
 
 
 fun Uri.isContentScheme() = this.scheme == "content"
 fun Uri.isContentScheme() = this.scheme == "content"
 
 
 /**
 /**
  * 读取URI
  * 读取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
     uri ?: return
     try {
     try {
         if (uri.isContentScheme()) {
         if (uri.isContentScheme()) {
             val doc = DocumentFile.fromSingleUri(this, uri)
             val doc = DocumentFile.fromSingleUri(this, uri)
             doc ?: throw NoStackTraceException("未获取到文件")
             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 {
         } else {
             PermissionsCompat.Builder(this)
             PermissionsCompat.Builder(this)
                 .addPermissions(
                 .addPermissions(
                     Permissions.READ_EXTERNAL_STORAGE,
                     Permissions.READ_EXTERNAL_STORAGE,
                     Permissions.WRITE_EXTERNAL_STORAGE
                     Permissions.WRITE_EXTERNAL_STORAGE
                 )
                 )
-                .rationale(R.string.bg_image_per)
+                .rationale(R.string.get_storage_per)
                 .onGranted {
                 .onGranted {
                     RealPathUtil.getPath(this, uri)?.let { path ->
                     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()
                 .request()
@@ -49,26 +58,31 @@ fun AppCompatActivity.readUri(uri: Uri?, success: (name: String, bytes: ByteArra
 /**
 /**
  * 读取URI
  * 读取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
     uri ?: return
     try {
     try {
         if (uri.isContentScheme()) {
         if (uri.isContentScheme()) {
             val doc = DocumentFile.fromSingleUri(requireContext(), uri)
             val doc = DocumentFile.fromSingleUri(requireContext(), uri)
             doc ?: throw NoStackTraceException("未获取到文件")
             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 {
         } else {
             PermissionsCompat.Builder(this)
             PermissionsCompat.Builder(this)
                 .addPermissions(
                 .addPermissions(
                     Permissions.READ_EXTERNAL_STORAGE,
                     Permissions.READ_EXTERNAL_STORAGE,
                     Permissions.WRITE_EXTERNAL_STORAGE
                     Permissions.WRITE_EXTERNAL_STORAGE
                 )
                 )
-                .rationale(R.string.bg_image_per)
+                .rationale(R.string.get_storage_per)
                 .onGranted {
                 .onGranted {
                     RealPathUtil.getPath(requireContext(), uri)?.let { path ->
                     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()
                 .request()