From f79aa2350c7aa922000ea4e35e576b9d8757a8fe Mon Sep 17 00:00:00 2001 From: Vladimir Dostoyevskiy <99822064+VDostoyevskiy@users.noreply.github.com> Date: Tue, 26 Dec 2023 22:50:28 +0800 Subject: [PATCH] Refactor UniFile, allow all image format, Resolve #529 (#543) * Refactor UniFile, allow all image format, Resolve #529 * Refine --------- Co-authored-by: GG Bond --- .../com/hippo/ehviewer/gallery/PageLoader2.kt | 6 -- .../com/hippo/ehviewer/spider/SpiderDen.kt | 17 +---- .../com/hippo/unifile/FilenameFilter.kt | 37 ---------- .../kotlin/com/hippo/unifile/MediaFile.kt | 70 +++++------------- .../main/kotlin/com/hippo/unifile/RawFile.kt | 16 +--- .../com/hippo/unifile/SingleDocumentFile.kt | 74 +++++-------------- .../com/hippo/unifile/TreeDocumentFile.kt | 12 +-- .../main/kotlin/com/hippo/unifile/UniFile.kt | 10 +-- 8 files changed, 48 insertions(+), 194 deletions(-) delete mode 100644 app/src/main/kotlin/com/hippo/unifile/FilenameFilter.kt diff --git a/app/src/main/kotlin/com/hippo/ehviewer/gallery/PageLoader2.kt b/app/src/main/kotlin/com/hippo/ehviewer/gallery/PageLoader2.kt index 997e3185e..140fffd0c 100644 --- a/app/src/main/kotlin/com/hippo/ehviewer/gallery/PageLoader2.kt +++ b/app/src/main/kotlin/com/hippo/ehviewer/gallery/PageLoader2.kt @@ -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", -) diff --git a/app/src/main/kotlin/com/hippo/ehviewer/spider/SpiderDen.kt b/app/src/main/kotlin/com/hippo/ehviewer/spider/SpiderDen.kt index 26c9bd51f..91477c5f1 100644 --- a/app/src/main/kotlin/com/hippo/ehviewer/spider/SpiderDen.kt +++ b/app/src/main/kotlin/com/hippo/ehviewer/spider/SpiderDen.kt @@ -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 { diff --git a/app/src/main/kotlin/com/hippo/unifile/FilenameFilter.kt b/app/src/main/kotlin/com/hippo/unifile/FilenameFilter.kt deleted file mode 100644 index 3e29b7dc6..000000000 --- a/app/src/main/kotlin/com/hippo/unifile/FilenameFilter.kt +++ /dev/null @@ -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 -} diff --git a/app/src/main/kotlin/com/hippo/unifile/MediaFile.kt b/app/src/main/kotlin/com/hippo/unifile/MediaFile.kt index 85a6957b5..183757d18 100644 --- a/app/src/main/kotlin/com/hippo/unifile/MediaFile.kt +++ b/app/src/main/kotlin/com/hippo/unifile/MediaFile.kt @@ -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? { - return null - } + override fun listFiles() = null - override fun listFiles(filter: FilenameFilter?): Array? { - 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 { diff --git a/app/src/main/kotlin/com/hippo/unifile/RawFile.kt b/app/src/main/kotlin/com/hippo/unifile/RawFile.kt index b8b5da61a..dd61881ab 100644 --- a/app/src/main/kotlin/com/hippo/unifile/RawFile.kt +++ b/app/src/main/kotlin/com/hippo/unifile/RawFile.kt @@ -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? { - if (filter == null) { - return listFiles() - } - val files = mFile.listFiles() ?: return null - val results = ArrayList() - for (file in files) { - if (filter.accept(this, file.name)) { - results.add(RawFile(this, file)) - } - } - return results.toTypedArray() + override fun findFirst(filter: (String) -> Boolean) = mFile.listFiles { _, name -> + filter(name) + }?.firstOrNull()?.let { + RawFile(this, it) } override fun findFile(displayName: String): UniFile? { diff --git a/app/src/main/kotlin/com/hippo/unifile/SingleDocumentFile.kt b/app/src/main/kotlin/com/hippo/unifile/SingleDocumentFile.kt index 0fa880489..71a7ae684 100644 --- a/app/src/main/kotlin/com/hippo/unifile/SingleDocumentFile.kt +++ b/app/src/main/kotlin/com/hippo/unifile/SingleDocumentFile.kt @@ -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? { - return null - } + override fun listFiles() = null - override fun listFiles(filter: FilenameFilter?): Array? { - 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) } diff --git a/app/src/main/kotlin/com/hippo/unifile/TreeDocumentFile.kt b/app/src/main/kotlin/com/hippo/unifile/TreeDocumentFile.kt index 908fa1d3b..c631799b4 100644 --- a/app/src/main/kotlin/com/hippo/unifile/TreeDocumentFile.kt +++ b/app/src/main/kotlin/com/hippo/unifile/TreeDocumentFile.kt @@ -199,19 +199,15 @@ internal class TreeDocumentFile : UniFile { return result.map { TreeDocumentFile(this, mContext, it, getFilenameForUri(it)) }.toTypedArray() } - override fun listFiles(filter: FilenameFilter?): Array { - if (filter == null) { - return listFiles() - } + override fun findFirst(filter: (String) -> Boolean): UniFile? { val result = DocumentsContractApi21.listFiles(mContext, uri) - val results = ArrayList() 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() + return null } override fun findFile(displayName: String): UniFile? { diff --git a/app/src/main/kotlin/com/hippo/unifile/UniFile.kt b/app/src/main/kotlin/com/hippo/unifile/UniFile.kt index 771ef33e7..5ea728ca2 100644 --- a/app/src/main/kotlin/com/hippo/unifile/UniFile.kt +++ b/app/src/main/kotlin/com/hippo/unifile/UniFile.kt @@ -205,15 +205,7 @@ abstract class UniFile internal constructor(private val parent: UniFile?) { */ abstract fun listFiles(): Array? - /** - * 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? + abstract fun findFirst(filter: (String) -> Boolean): UniFile? /** * Test there is a file with the display name in the directory.