Refactor UniFile, allow all image format, Resolve #529 (#543)

* Refactor UniFile, allow all image format, Resolve #529

* Refine

---------

Co-authored-by: GG Bond <whatever@tagkong.com>
This commit is contained in:
Vladimir DostoyevskiyandGG Bond authored and GitHub committed 2023-12-26 14:50:28 +00:00
1 parent 719dddeab9
commit f79aa2350c
8 files changed
+48 -194

No files matched your search

@@ -40,9 +40,3 @@ abstract class PageLoader2 : PageLoader() {
*/
abstract fun save(index: Int, dir: UniFile, filename: String): UniFile?
}
val SUPPORT_IMAGE_EXTENSIONS = arrayOf(
".jpg",
".png",
".gif",
)
@@ -26,7 +26,6 @@ import com.hippo.ehviewer.client.getImageKey
import com.hippo.ehviewer.coil.read
import com.hippo.ehviewer.coil.suspendEdit
import com.hippo.ehviewer.download.downloadLocation
import com.hippo.ehviewer.gallery.SUPPORT_IMAGE_EXTENSIONS
import com.hippo.ehviewer.image.Image.UniFileSource
import com.hippo.ehviewer.util.FileUtils
import com.hippo.ehviewer.util.sendTo
@@ -72,7 +71,7 @@ class SpiderDen(mGalleryInfo: GalleryInfo) {
val key = getImageKey(mGid, index)
return runCatching {
sCache.read(key) {
val extension = fixExtension("." + metadata.toFile().readText())
val extension = "." + metadata.toFile().readText()
val file = dir.createFile(perFilename(index, extension)) ?: return false
file.openFileDescriptor("w").use { outFd ->
ParcelFileDescriptor.open(data.toFile(), MODE_READ_WRITE).use {
@@ -117,7 +116,7 @@ class SpiderDen(mGalleryInfo: GalleryInfo) {
private fun findDownloadFileForIndex(index: Int, extension: String): UniFile? {
val dir = downloadDir ?: return null
val ext = fixExtension(".$extension")
val ext = ".$extension"
return dir.createFile(perFilename(index, ext))
}
@@ -233,8 +232,6 @@ class SpiderDen(mGalleryInfo: GalleryInfo) {
}
}
private val COMPAT_IMAGE_EXTENSIONS = SUPPORT_IMAGE_EXTENSIONS + ".jpeg"
/**
* @param extension with dot
*/
@@ -242,15 +239,9 @@ fun perFilename(index: Int, extension: String?): String {
return String.format(Locale.US, "%08d%s", index + 1, extension)
}
/**
* @param extension with dot
*/
private fun fixExtension(extension: String): String {
return extension.takeIf { SUPPORT_IMAGE_EXTENSIONS.contains(it) } ?: SUPPORT_IMAGE_EXTENSIONS[0]
}
private fun findImageFile(dir: UniFile, index: Int): UniFile? {
return COMPAT_IMAGE_EXTENSIONS.firstNotNullOfOrNull { dir.findFile(perFilename(index, it)) }
val head = perFilename(index, ".")
return dir.findFirst { name -> name.startsWith(head) }
}
suspend fun GalleryInfo.putToDownloadDir(): String {
@@ -1,37 +0,0 @@
/*
* Copyright 2016 Hippo Seven
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.hippo.unifile
/**
* An interface for filtering [UniFile] objects based on their names
* or the directory they reside in.
*
* @see UniFile
*
* @see UniFile.listFiles
*/
interface FilenameFilter {
/**
* Indicates if a specific filename matches this filter.
*
* @param dir the directory in which the `filename` was found.
* @param filename the name of the file in `dir` to test.
* @return `true` if the filename matches the filter
* and can be included in the list, `false`
* otherwise.
*/
fun accept(dir: UniFile?, filename: String?): Boolean
}
@@ -18,44 +18,28 @@ package com.hippo.unifile
import android.content.Context
import android.graphics.ImageDecoder
import android.net.Uri
import android.os.ParcelFileDescriptor
import java.io.IOException
internal class MediaFile(context: Context, override val uri: Uri) : UniFile(null) {
private val mContext: Context
private val mContext = context.applicationContext
init {
mContext = context.applicationContext
}
override fun createFile(displayName: String) = null
override fun createFile(displayName: String): UniFile? {
return null
}
override fun createDirectory(displayName: String): UniFile? {
return null
}
override fun createDirectory(displayName: String) = null
override val name: String?
get() = MediaContract.getName(mContext, uri)
override val type: String?
get() = MediaContract.getType(mContext, uri)
override val isDirectory: Boolean
get() = false
override val isDirectory = false
override val isFile: Boolean
get() = DocumentsContractApi19.isFile(mContext, uri)
override fun lastModified(): Long {
return MediaContract.lastModified(mContext, uri)
}
override fun lastModified() = MediaContract.lastModified(mContext, uri)
override fun length(): Long {
return MediaContract.length(mContext, uri)
}
override fun length() = MediaContract.length(mContext, uri)
override fun canRead(): Boolean {
return isFile
}
override fun canRead() = isFile
override fun canWrite(): Boolean {
try {
@@ -67,48 +51,28 @@ internal class MediaFile(context: Context, override val uri: Uri) : UniFile(null
return true
}
override fun ensureDir(): Boolean {
return false
}
override fun ensureDir() = false
override fun ensureFile(): Boolean {
return isFile
}
override fun ensureFile() = isFile
override fun subFile(displayName: String): UniFile? {
return null
}
override fun subFile(displayName: String) = null
override fun delete(): Boolean {
return false
}
override fun delete() = false
override fun exists(): Boolean {
return isFile
}
override fun exists() = isFile
override fun listFiles(): Array<UniFile>? {
return null
}
override fun listFiles() = null
override fun listFiles(filter: FilenameFilter?): Array<UniFile>? {
return null
}
override fun findFirst(filter: (String) -> Boolean) = null
override fun findFile(displayName: String): UniFile? {
return null
}
override fun findFile(displayName: String) = null
override fun renameTo(displayName: String): Boolean {
return false
}
override fun renameTo(displayName: String) = false
override val imageSource: ImageDecoder.Source
get() = Contracts.getImageSource(mContext, uri)
override fun openFileDescriptor(mode: String): ParcelFileDescriptor {
return Contracts.openFileDescriptor(mContext, uri, mode)
}
override fun openFileDescriptor(mode: String) = Contracts.openFileDescriptor(mContext, uri, mode)
companion object {
fun isMediaUri(context: Context, uri: Uri): Boolean {
@@ -119,18 +119,10 @@ internal class RawFile(parent: UniFile?, var mFile: File) : UniFile(parent) {
return files.map { RawFile(this, it) }.toTypedArray()
}
override fun listFiles(filter: FilenameFilter?): Array<UniFile>? {
if (filter == null) {
return listFiles()
}
val files = mFile.listFiles() ?: return null
val results = ArrayList<UniFile>()
for (file in files) {
if (filter.accept(this, file.name)) {
results.add(RawFile(this, file))
}
}
return results.toTypedArray<UniFile>()
override fun findFirst(filter: (String) -> Boolean) = mFile.listFiles { _, name ->
filter(name)
}?.firstOrNull()?.let {
RawFile(this, it)
}
override fun findFile(displayName: String): UniFile? {
@@ -18,23 +18,13 @@ package com.hippo.unifile
import android.content.Context
import android.graphics.ImageDecoder
import android.net.Uri
import android.os.ParcelFileDescriptor
internal class SingleDocumentFile(parent: UniFile?, context: Context, override val uri: Uri) :
UniFile(parent) {
private val mContext: Context
class SingleDocumentFile(parent: UniFile?, context: Context, override val uri: Uri) : UniFile(parent) {
private val mContext = context.applicationContext
init {
mContext = context.applicationContext
}
override fun createFile(displayName: String) = null
override fun createFile(displayName: String): UniFile? {
return null
}
override fun createDirectory(displayName: String): UniFile? {
return null
}
override fun createDirectory(displayName: String) = null
override val name: String?
get() = DocumentsContractApi19.getName(mContext, uri)
@@ -45,62 +35,34 @@ internal class SingleDocumentFile(parent: UniFile?, context: Context, override v
override val isFile: Boolean
get() = DocumentsContractApi19.isFile(mContext, uri)
override fun lastModified(): Long {
return DocumentsContractApi19.lastModified(mContext, uri)
}
override fun lastModified() = DocumentsContractApi19.lastModified(mContext, uri)
override fun length(): Long {
return DocumentsContractApi19.length(mContext, uri)
}
override fun length() = DocumentsContractApi19.length(mContext, uri)
override fun canRead(): Boolean {
return DocumentsContractApi19.canRead(mContext, uri)
}
override fun canRead() = DocumentsContractApi19.canRead(mContext, uri)
override fun canWrite(): Boolean {
return DocumentsContractApi19.canWrite(mContext, uri)
}
override fun canWrite() = DocumentsContractApi19.canWrite(mContext, uri)
override fun ensureDir(): Boolean {
return isDirectory
}
override fun ensureDir() = isDirectory
override fun ensureFile(): Boolean {
return isFile
}
override fun ensureFile() = isFile
override fun subFile(displayName: String): UniFile? {
return null
}
override fun subFile(displayName: String) = null
override fun delete(): Boolean {
return DocumentsContractApi19.delete(mContext, uri)
}
override fun delete() = DocumentsContractApi19.delete(mContext, uri)
override fun exists(): Boolean {
return DocumentsContractApi19.exists(mContext, uri)
}
override fun exists() = DocumentsContractApi19.exists(mContext, uri)
override fun listFiles(): Array<UniFile>? {
return null
}
override fun listFiles() = null
override fun listFiles(filter: FilenameFilter?): Array<UniFile>? {
return null
}
override fun findFirst(filter: (String) -> Boolean) = null
override fun findFile(displayName: String): UniFile? {
return null
}
override fun findFile(displayName: String) = null
override fun renameTo(displayName: String): Boolean {
return false
}
override fun renameTo(displayName: String) = false
override val imageSource: ImageDecoder.Source
get() = Contracts.getImageSource(mContext, uri)
override fun openFileDescriptor(mode: String): ParcelFileDescriptor {
return Contracts.openFileDescriptor(mContext, uri, mode)
}
override fun openFileDescriptor(mode: String) = Contracts.openFileDescriptor(mContext, uri, mode)
}
@@ -199,19 +199,15 @@ internal class TreeDocumentFile : UniFile {
return result.map { TreeDocumentFile(this, mContext, it, getFilenameForUri(it)) }.toTypedArray()
}
override fun listFiles(filter: FilenameFilter?): Array<UniFile> {
if (filter == null) {
return listFiles()
}
override fun findFirst(filter: (String) -> Boolean): UniFile? {
val result = DocumentsContractApi21.listFiles(mContext, uri)
val results = ArrayList<UniFile>()
for (uri in result) {
val name = getFilenameForUri(uri)
if (filter.accept(this, name)) {
results.add(TreeDocumentFile(this, mContext, uri, name))
if (name != null && filter(name)) {
return TreeDocumentFile(this, mContext, uri, name)
}
}
return results.toTypedArray<UniFile>()
return null
}
override fun findFile(displayName: String): UniFile? {
@@ -205,15 +205,7 @@ abstract class UniFile internal constructor(private val parent: UniFile?) {
*/
abstract fun listFiles(): Array<UniFile>?
/**
* Gets a list of the files in the directory represented by this file. This
* list is then filtered through a FilenameFilter and the names of files
* with matching names are returned as an array of strings.
*
* @param filter the filter to match names against, may be `null`.
* @return an array of files or `null`.
*/
abstract fun listFiles(filter: FilenameFilter?): Array<UniFile>?
abstract fun findFirst(filter: (String) -> Boolean): UniFile?
/**
* Test there is a file with the display name in the directory.