diff --git a/app/build.gradle b/app/build.gradle index 4d3d546e..f9067e23 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -38,7 +38,7 @@ android { minSdkVersion 16 targetSdkVersion 30 versionCode 61 - versionName "5.1.2" + versionName "5.1.2-alpha1" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" vectorDrawables.useSupportLibrary = true } @@ -90,6 +90,7 @@ dependencies { implementation "androidx.constraintlayout:constraintlayout:2.0.1" implementation "androidx.gridlayout:gridlayout:1.0.0" implementation "androidx.biometric:biometric:1.0.1" + implementation "androidx.work:work-runtime-ktx:2.4.0" implementation "com.daimajia.swipelayout:library:1.2.0@aar" @@ -125,7 +126,7 @@ dependencies { implementation "ru.noties.markwon:core:3.1.0" implementation "xyz.quaver:libpupil:1.7.2" - implementation "xyz.quaver:documentfilex:0.2.15" + implementation "xyz.quaver:documentfilex:0.3" implementation "xyz.quaver:floatingsearchview:1.0.7" testImplementation "junit:junit:4.13" diff --git a/app/release/output-metadata.json b/app/release/output-metadata.json index 5557886d..d1f76a9e 100644 --- a/app/release/output-metadata.json +++ b/app/release/output-metadata.json @@ -12,7 +12,7 @@ "filters": [], "properties": [], "versionCode": 61, - "versionName": "5.1.1-hotfix3", + "versionName": "5.1.2-alpha1", "enabled": true, "outputFile": "app-release.apk" } diff --git a/app/src/main/java/xyz/quaver/pupil/adapters/GalleryBlockAdapter.kt b/app/src/main/java/xyz/quaver/pupil/adapters/GalleryBlockAdapter.kt index 28f31f11..47bbe696 100644 --- a/app/src/main/java/xyz/quaver/pupil/adapters/GalleryBlockAdapter.kt +++ b/app/src/main/java/xyz/quaver/pupil/adapters/GalleryBlockAdapter.kt @@ -61,9 +61,18 @@ class GalleryBlockAdapter(private val galleries: List) : RecyclerSwipeAdapt var thin: Boolean = Preferences["thin"] inner class GalleryViewHolder(val view: View) : RecyclerView.ViewHolder(view) { - var update = true + private var galleryID: Int = 0 - private fun updateProgress(context: Context, galleryID: Int) { + init { + CoroutineScope(Dispatchers.Main).launch { + while (updateAll) { + updateProgress(view.context) + delay(1000) + } + } + } + + private fun updateProgress(context: Context) { val cache = Cache.getInstance(context, galleryID) CoroutineScope(Dispatchers.Main).launch { @@ -116,9 +125,13 @@ class GalleryBlockAdapter(private val galleries: List) : RecyclerSwipeAdapt } fun bind(galleryID: Int) { + this.galleryID = galleryID + val cache = Cache.getInstance(view.context, galleryID) - val galleryBlock = cache.metadata.galleryBlock ?: return + val galleryBlock = runBlocking { + cache.getGalleryBlock() + } ?: return with(view) { val resources = context.resources @@ -162,13 +175,6 @@ class GalleryBlockAdapter(private val galleries: List) : RecyclerSwipeAdapt } } - CoroutineScope(Dispatchers.Main).launch { - while (updateAll && update) { - updateProgress(context, galleryID) - delay(1000) - } - } - galleryblock_title.text = galleryBlock.title with(galleryblock_artist) { text = artists.joinToString { it.wordCapitalize() } @@ -377,13 +383,6 @@ class GalleryBlockAdapter(private val galleries: List) : RecyclerSwipeAdapt } } - override fun onViewDetachedFromWindow(holder: RecyclerView.ViewHolder) { - super.onViewDetachedFromWindow(holder) - - if (holder is GalleryViewHolder) - holder.update = false - } - override fun getItemCount() = galleries.size + (if (showNext) 1 else 0) + diff --git a/app/src/main/java/xyz/quaver/pupil/adapters/ReaderAdapter.kt b/app/src/main/java/xyz/quaver/pupil/adapters/ReaderAdapter.kt index f62199d1..ce47fb60 100644 --- a/app/src/main/java/xyz/quaver/pupil/adapters/ReaderAdapter.kt +++ b/app/src/main/java/xyz/quaver/pupil/adapters/ReaderAdapter.kt @@ -62,7 +62,14 @@ class ReaderAdapter( class ViewHolder(val view: View) : RecyclerView.ViewHolder(view) { fun clear() { - view.image.ssiv?.recycle() + view.image.mainView.let { + when (it) { + is SubsamplingScaleImageView -> + it.recycle() + is SimpleDraweeView -> + it.controller = null + } + } } } diff --git a/app/src/main/java/xyz/quaver/pupil/services/DownloadService.kt b/app/src/main/java/xyz/quaver/pupil/services/DownloadService.kt index 1fcacd4f..f6bc889f 100644 --- a/app/src/main/java/xyz/quaver/pupil/services/DownloadService.kt +++ b/app/src/main/java/xyz/quaver/pupil/services/DownloadService.kt @@ -42,6 +42,7 @@ import xyz.quaver.pupil.R import xyz.quaver.pupil.client import xyz.quaver.pupil.interceptors import xyz.quaver.pupil.ui.ReaderActivity +import xyz.quaver.pupil.util.cleanCache import xyz.quaver.pupil.util.downloader.Cache import xyz.quaver.pupil.util.downloader.DownloadManager import xyz.quaver.pupil.util.ellipsize @@ -295,6 +296,8 @@ class DownloadService : Service() { } fun download(galleryID: Int, priority: Boolean = false, startId: Int? = null): Job = CoroutineScope(Dispatchers.IO).launch { + cleanCache(this@DownloadService) + if (progress.containsKey(galleryID)) cancel(galleryID) diff --git a/app/src/main/java/xyz/quaver/pupil/ui/fragment/ManageStorageFragment.kt b/app/src/main/java/xyz/quaver/pupil/ui/fragment/ManageStorageFragment.kt index 9afdb6eb..628a7f9b 100644 --- a/app/src/main/java/xyz/quaver/pupil/ui/fragment/ManageStorageFragment.kt +++ b/app/src/main/java/xyz/quaver/pupil/ui/fragment/ManageStorageFragment.kt @@ -31,6 +31,7 @@ import xyz.quaver.io.util.deleteRecursively import xyz.quaver.pupil.R import xyz.quaver.pupil.histories import xyz.quaver.pupil.util.byteToString +import xyz.quaver.pupil.util.downloader.Cache import xyz.quaver.pupil.util.downloader.DownloadManager import java.io.File @@ -61,6 +62,8 @@ class ManageStorageFragment : PreferenceFragmentCompat(), Preference.OnPreferenc if (dir.exists()) dir.deleteRecursively() + Cache.instances.clear() + summary = context.getString(R.string.settings_storage_usage, byteToString(0)) CoroutineScope(Dispatchers.IO).launch { var size = 0L diff --git a/app/src/main/java/xyz/quaver/pupil/util/downloader/Cache.kt b/app/src/main/java/xyz/quaver/pupil/util/downloader/Cache.kt index dacd54ad..5c4aa5f1 100644 --- a/app/src/main/java/xyz/quaver/pupil/util/downloader/Cache.kt +++ b/app/src/main/java/xyz/quaver/pupil/util/downloader/Cache.kt @@ -186,7 +186,7 @@ class Cache private constructor(context: Context, val galleryID: Int) : ContextW } fun getImage(index: Int): FileX? = - metadata.imageList?.get(index)?.let { findFile(it) } + metadata.imageList?.getOrNull(index)?.let { findFile(it) } @Suppress("BlockingMethodInNonBlockingContext") fun putImage(index: Int, fileName: String, data: ByteArray) { diff --git a/app/src/main/java/xyz/quaver/pupil/util/file.kt b/app/src/main/java/xyz/quaver/pupil/util/file.kt index 7579f986..2df6e90e 100644 --- a/app/src/main/java/xyz/quaver/pupil/util/file.kt +++ b/app/src/main/java/xyz/quaver/pupil/util/file.kt @@ -19,35 +19,63 @@ package xyz.quaver.pupil.util import android.content.Context -import android.os.storage.StorageManager -import androidx.core.content.ContextCompat -import androidx.core.net.toUri +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import kotlinx.coroutines.sync.Mutex +import kotlinx.coroutines.sync.withLock +import xyz.quaver.pupil.histories +import xyz.quaver.pupil.util.downloader.Cache +import xyz.quaver.pupil.util.downloader.DownloadManager import java.io.File -import java.io.FileOutputStream -import java.lang.reflect.Array -import java.net.URL - -@Suppress("DEPRECATION") -@Deprecated("Use downloader.Cache instead") -fun getCachedGallery(context: Context, galleryID: Int) = - File(getDownloadDirectory(context), galleryID.toString()).let { - if (it.exists()) - it - else - File(context.cacheDir, "imageCache/$galleryID") - } -@Suppress("DEPRECATION") -@Deprecated("Use downloader.Cache instead") -fun getDownloadDirectory(context: Context) = - Preferences.get("dl_location").let { - if (it.isNotEmpty() && !it.startsWith("content")) - File(it) - else - context.getExternalFilesDir(null)!! - } +val mutex = Mutex() +fun cleanCache(context: Context) = CoroutineScope(Dispatchers.IO).launch { + if (mutex.isLocked) return@launch + + mutex.withLock { + val cacheFolder = File(context.cacheDir, "imageCache") + val downloadManager = DownloadManager.getInstance(context) + + cacheFolder.listFiles { file -> + val galleryID = file.name.toIntOrNull() ?: return@listFiles true + + !(downloadManager.downloadFolderMap.containsKey(galleryID) || histories.contains(galleryID)) + }?.forEach { + it.deleteRecursively() + } + + DownloadManager.getInstance(context).downloadFolderMap.keys.forEach { + val folder = File(cacheFolder, it.toString()) + + if (!downloadManager.isDownloading(it) && folder.exists()) { + folder.deleteRecursively() + } + } -@Suppress("DEPRECATION") -@Deprecated("Use FileX instead") -fun File.isParentOf(another: File) = - another.absolutePath.startsWith(this.absolutePath) \ No newline at end of file + val limit = (Preferences.get("cache_limit").toLongOrNull() ?: 0L)*1024*1024*1024 + + if (limit == 0L) return@withLock + + val cacheSize = { + var size = 0L + + cacheFolder.walk().forEach { + size += it.length() + } + + size + } + + if (cacheSize.invoke() > limit) + while (cacheSize.invoke() > limit/2) { + val caches = cacheFolder.list() ?: return@withLock + + (histories.firstOrNull { + caches.contains(it.toString()) && !downloadManager.isDownloading(it) + } ?: return@withLock).let { + Cache.delete(it) + } + } + } +} \ No newline at end of file diff --git a/app/src/main/res/values-ja/strings.xml b/app/src/main/res/values-ja/strings.xml index b814256d..ac6869c1 100644 --- a/app/src/main/res/values-ja/strings.xml +++ b/app/src/main/res/values-ja/strings.xml @@ -150,4 +150,6 @@ カメラ権限が拒否されているため、まばたき検知使用できません この機器には前面カメラが装着されていません エラー + キャッシュサイズ制限 + 制限なし \ No newline at end of file diff --git a/app/src/main/res/values-ko/strings.xml b/app/src/main/res/values-ko/strings.xml index c1ac6072..58979aec 100644 --- a/app/src/main/res/values-ko/strings.xml +++ b/app/src/main/res/values-ko/strings.xml @@ -150,4 +150,6 @@ 카메라 권한이 거부되었기 때문에 눈 깜빡임 감지가 불가능합니다 이 장치에는 전면 카메라가 없습니다 오류 + 캐시 크기 제한 + 무제한 \ No newline at end of file diff --git a/app/src/main/res/values/arrays.xml b/app/src/main/res/values/arrays.xml index 8e9b419a..69abcd7e 100644 --- a/app/src/main/res/values/arrays.xml +++ b/app/src/main/res/values/arrays.xml @@ -58,4 +58,24 @@ SOCKS + + 0 + 1 + 2 + 4 + 8 + 16 + 32 + + + + @string/settings_cache_unlimited + 1G + 2G + 4G + 8G + 16G + 32G + + \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 5248858b..53d185b4 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -161,6 +161,9 @@ %s available Custom Location This folder is not writable. Please select another folder. + Cache Limit + Unlimited + Hide image from gallery Low quality images Load low quality images to improve load speed and data usage @@ -179,7 +182,6 @@ Enable security mode to make the screen invisible on recent app window Dark mode Protect yourself against light attacks! - Hide image from gallery Import old galleries User ID User ID is copied to clipboard diff --git a/app/src/main/res/xml/root_preferences.xml b/app/src/main/res/xml/root_preferences.xml index 7a5e9cba..ff67535d 100644 --- a/app/src/main/res/xml/root_preferences.xml +++ b/app/src/main/res/xml/root_preferences.xml @@ -44,6 +44,14 @@ app:key="download_folder" app:title="@string/settings_download_folder"/> + +