diff --git a/app/src/main/java/io/legado/app/ui/association/FileAssociationActivity.kt b/app/src/main/java/io/legado/app/ui/association/FileAssociationActivity.kt index bc279421f..b6b6e240f 100644 --- a/app/src/main/java/io/legado/app/ui/association/FileAssociationActivity.kt +++ b/app/src/main/java/io/legado/app/ui/association/FileAssociationActivity.kt @@ -102,41 +102,38 @@ 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!! - 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() } } + 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() } } + viewModel.importBook(Uri.fromFile(file)) } - viewModel.importBook(Uri.fromFile(file)) } } }.onFailure { diff --git a/app/src/main/java/io/legado/app/ui/book/group/GroupEditDialog.kt b/app/src/main/java/io/legado/app/ui/book/group/GroupEditDialog.kt index 34afb7c16..4ce3075c1 100644 --- a/app/src/main/java/io/legado/app/ui/book/group/GroupEditDialog.kt +++ b/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.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() 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) } } diff --git a/app/src/main/java/io/legado/app/ui/book/info/edit/BookInfoEditActivity.kt b/app/src/main/java/io/legado/app/ui/book/info/edit/BookInfoEditActivity.kt index 1e01e27fa..e6605bee4 100644 --- a/app/src/main/java/io/legado/app/ui/book/info/edit/BookInfoEditActivity.kt +++ b/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.utils.* import io.legado.app.utils.viewbindingdelegate.viewBinding +import java.io.FileOutputStream class BookInfoEditActivity : VMBaseActivity(), @@ -101,11 +102,15 @@ class BookInfoEditActivity : } 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) + } } } diff --git a/app/src/main/java/io/legado/app/ui/book/local/ImportBookAdapter.kt b/app/src/main/java/io/legado/app/ui/book/local/ImportBookAdapter.kt index 91d35d437..ac5b9152a 100644 --- a/app/src/main/java/io/legado/app/ui/book/local/ImportBookAdapter.kt +++ b/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() 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 diff --git a/app/src/main/java/io/legado/app/ui/book/local/ImportBookViewModel.kt b/app/src/main/java/io/legado/app/ui/book/local/ImportBookViewModel.kt index 6d0e61bcd..5efef485b 100644 --- a/app/src/main/java/io/legado/app/ui/book/local/ImportBookViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/book/local/ImportBookViewModel.kt @@ -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 }) diff --git a/app/src/main/java/io/legado/app/ui/book/read/config/BgTextConfigDialog.kt b/app/src/main/java/io/legado/app/ui/book/read/config/BgTextConfigDialog.kt index 78e4326e4..e1cd8a329 100644 --- a/app/src/main/java/io/legado/app/ui/book/read/config/BgTextConfigDialog.kt +++ b/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 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) diff --git a/app/src/main/java/io/legado/app/ui/config/CoverConfigFragment.kt b/app/src/main/java/io/legado/app/ui/config/CoverConfigFragment.kt index 2fefefdc6..eca0334dd 100644 --- a/app/src/main/java/io/legado/app/ui/config/CoverConfigFragment.kt +++ b/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.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() } diff --git a/app/src/main/java/io/legado/app/ui/config/ThemeConfigFragment.kt b/app/src/main/java/io/legado/app/ui/config/ThemeConfigFragment.kt index 901a828cd..d143ac8e1 100644 --- a/app/src/main/java/io/legado/app/ui/config/ThemeConfigFragment.kt +++ b/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.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() } diff --git a/app/src/main/java/io/legado/app/ui/config/WelcomeConfigFragment.kt b/app/src/main/java/io/legado/app/ui/config/WelcomeConfigFragment.kt index 2c29cbe68..60d205b4c 100644 --- a/app/src/main/java/io/legado/app/ui/config/WelcomeConfigFragment.kt +++ b/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.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) } } diff --git a/app/src/main/java/io/legado/app/utils/DocumentExtensions.kt b/app/src/main/java/io/legado/app/utils/DocumentExtensions.kt index 6ff50ad10..a9c959549 100644 --- a/app/src/main/java/io/legado/app/utils/DocumentExtensions.kt +++ b/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 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) ) } diff --git a/app/src/main/java/io/legado/app/utils/UriExtensions.kt b/app/src/main/java/io/legado/app/utils/UriExtensions.kt index 4453834a5..97e25e403 100644 --- a/app/src/main/java/io/legado/app/utils/UriExtensions.kt +++ b/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.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()