Auto cache clean
This commit is contained in:
@@ -38,7 +38,7 @@ android {
|
|||||||
minSdkVersion 16
|
minSdkVersion 16
|
||||||
targetSdkVersion 30
|
targetSdkVersion 30
|
||||||
versionCode 61
|
versionCode 61
|
||||||
versionName "5.1.2"
|
versionName "5.1.2-alpha1"
|
||||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||||
vectorDrawables.useSupportLibrary = true
|
vectorDrawables.useSupportLibrary = true
|
||||||
}
|
}
|
||||||
@@ -90,6 +90,7 @@ dependencies {
|
|||||||
implementation "androidx.constraintlayout:constraintlayout:2.0.1"
|
implementation "androidx.constraintlayout:constraintlayout:2.0.1"
|
||||||
implementation "androidx.gridlayout:gridlayout:1.0.0"
|
implementation "androidx.gridlayout:gridlayout:1.0.0"
|
||||||
implementation "androidx.biometric:biometric:1.0.1"
|
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"
|
implementation "com.daimajia.swipelayout:library:1.2.0@aar"
|
||||||
|
|
||||||
@@ -125,7 +126,7 @@ dependencies {
|
|||||||
implementation "ru.noties.markwon:core:3.1.0"
|
implementation "ru.noties.markwon:core:3.1.0"
|
||||||
|
|
||||||
implementation "xyz.quaver:libpupil:1.7.2"
|
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"
|
implementation "xyz.quaver:floatingsearchview:1.0.7"
|
||||||
|
|
||||||
testImplementation "junit:junit:4.13"
|
testImplementation "junit:junit:4.13"
|
||||||
|
|||||||
@@ -12,7 +12,7 @@
|
|||||||
"filters": [],
|
"filters": [],
|
||||||
"properties": [],
|
"properties": [],
|
||||||
"versionCode": 61,
|
"versionCode": 61,
|
||||||
"versionName": "5.1.1-hotfix3",
|
"versionName": "5.1.2-alpha1",
|
||||||
"enabled": true,
|
"enabled": true,
|
||||||
"outputFile": "app-release.apk"
|
"outputFile": "app-release.apk"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -61,9 +61,18 @@ class GalleryBlockAdapter(private val galleries: List<Int>) : RecyclerSwipeAdapt
|
|||||||
var thin: Boolean = Preferences["thin"]
|
var thin: Boolean = Preferences["thin"]
|
||||||
|
|
||||||
inner class GalleryViewHolder(val view: View) : RecyclerView.ViewHolder(view) {
|
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)
|
val cache = Cache.getInstance(context, galleryID)
|
||||||
|
|
||||||
CoroutineScope(Dispatchers.Main).launch {
|
CoroutineScope(Dispatchers.Main).launch {
|
||||||
@@ -116,9 +125,13 @@ class GalleryBlockAdapter(private val galleries: List<Int>) : RecyclerSwipeAdapt
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun bind(galleryID: Int) {
|
fun bind(galleryID: Int) {
|
||||||
|
this.galleryID = galleryID
|
||||||
|
|
||||||
val cache = Cache.getInstance(view.context, galleryID)
|
val cache = Cache.getInstance(view.context, galleryID)
|
||||||
|
|
||||||
val galleryBlock = cache.metadata.galleryBlock ?: return
|
val galleryBlock = runBlocking {
|
||||||
|
cache.getGalleryBlock()
|
||||||
|
} ?: return
|
||||||
|
|
||||||
with(view) {
|
with(view) {
|
||||||
val resources = context.resources
|
val resources = context.resources
|
||||||
@@ -162,13 +175,6 @@ class GalleryBlockAdapter(private val galleries: List<Int>) : RecyclerSwipeAdapt
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
CoroutineScope(Dispatchers.Main).launch {
|
|
||||||
while (updateAll && update) {
|
|
||||||
updateProgress(context, galleryID)
|
|
||||||
delay(1000)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
galleryblock_title.text = galleryBlock.title
|
galleryblock_title.text = galleryBlock.title
|
||||||
with(galleryblock_artist) {
|
with(galleryblock_artist) {
|
||||||
text = artists.joinToString { it.wordCapitalize() }
|
text = artists.joinToString { it.wordCapitalize() }
|
||||||
@@ -377,13 +383,6 @@ class GalleryBlockAdapter(private val galleries: List<Int>) : RecyclerSwipeAdapt
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onViewDetachedFromWindow(holder: RecyclerView.ViewHolder) {
|
|
||||||
super.onViewDetachedFromWindow(holder)
|
|
||||||
|
|
||||||
if (holder is GalleryViewHolder)
|
|
||||||
holder.update = false
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getItemCount() =
|
override fun getItemCount() =
|
||||||
galleries.size +
|
galleries.size +
|
||||||
(if (showNext) 1 else 0) +
|
(if (showNext) 1 else 0) +
|
||||||
|
|||||||
@@ -62,7 +62,14 @@ class ReaderAdapter(
|
|||||||
|
|
||||||
class ViewHolder(val view: View) : RecyclerView.ViewHolder(view) {
|
class ViewHolder(val view: View) : RecyclerView.ViewHolder(view) {
|
||||||
fun clear() {
|
fun clear() {
|
||||||
view.image.ssiv?.recycle()
|
view.image.mainView.let {
|
||||||
|
when (it) {
|
||||||
|
is SubsamplingScaleImageView ->
|
||||||
|
it.recycle()
|
||||||
|
is SimpleDraweeView ->
|
||||||
|
it.controller = null
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -42,6 +42,7 @@ import xyz.quaver.pupil.R
|
|||||||
import xyz.quaver.pupil.client
|
import xyz.quaver.pupil.client
|
||||||
import xyz.quaver.pupil.interceptors
|
import xyz.quaver.pupil.interceptors
|
||||||
import xyz.quaver.pupil.ui.ReaderActivity
|
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.Cache
|
||||||
import xyz.quaver.pupil.util.downloader.DownloadManager
|
import xyz.quaver.pupil.util.downloader.DownloadManager
|
||||||
import xyz.quaver.pupil.util.ellipsize
|
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 {
|
fun download(galleryID: Int, priority: Boolean = false, startId: Int? = null): Job = CoroutineScope(Dispatchers.IO).launch {
|
||||||
|
cleanCache(this@DownloadService)
|
||||||
|
|
||||||
if (progress.containsKey(galleryID))
|
if (progress.containsKey(galleryID))
|
||||||
cancel(galleryID)
|
cancel(galleryID)
|
||||||
|
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ import xyz.quaver.io.util.deleteRecursively
|
|||||||
import xyz.quaver.pupil.R
|
import xyz.quaver.pupil.R
|
||||||
import xyz.quaver.pupil.histories
|
import xyz.quaver.pupil.histories
|
||||||
import xyz.quaver.pupil.util.byteToString
|
import xyz.quaver.pupil.util.byteToString
|
||||||
|
import xyz.quaver.pupil.util.downloader.Cache
|
||||||
import xyz.quaver.pupil.util.downloader.DownloadManager
|
import xyz.quaver.pupil.util.downloader.DownloadManager
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
|
||||||
@@ -61,6 +62,8 @@ class ManageStorageFragment : PreferenceFragmentCompat(), Preference.OnPreferenc
|
|||||||
if (dir.exists())
|
if (dir.exists())
|
||||||
dir.deleteRecursively()
|
dir.deleteRecursively()
|
||||||
|
|
||||||
|
Cache.instances.clear()
|
||||||
|
|
||||||
summary = context.getString(R.string.settings_storage_usage, byteToString(0))
|
summary = context.getString(R.string.settings_storage_usage, byteToString(0))
|
||||||
CoroutineScope(Dispatchers.IO).launch {
|
CoroutineScope(Dispatchers.IO).launch {
|
||||||
var size = 0L
|
var size = 0L
|
||||||
|
|||||||
@@ -186,7 +186,7 @@ class Cache private constructor(context: Context, val galleryID: Int) : ContextW
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun getImage(index: Int): FileX? =
|
fun getImage(index: Int): FileX? =
|
||||||
metadata.imageList?.get(index)?.let { findFile(it) }
|
metadata.imageList?.getOrNull(index)?.let { findFile(it) }
|
||||||
|
|
||||||
@Suppress("BlockingMethodInNonBlockingContext")
|
@Suppress("BlockingMethodInNonBlockingContext")
|
||||||
fun putImage(index: Int, fileName: String, data: ByteArray) {
|
fun putImage(index: Int, fileName: String, data: ByteArray) {
|
||||||
|
|||||||
@@ -19,35 +19,63 @@
|
|||||||
package xyz.quaver.pupil.util
|
package xyz.quaver.pupil.util
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.os.storage.StorageManager
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import androidx.core.content.ContextCompat
|
import kotlinx.coroutines.Dispatchers
|
||||||
import androidx.core.net.toUri
|
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.File
|
||||||
import java.io.FileOutputStream
|
|
||||||
import java.lang.reflect.Array
|
|
||||||
import java.net.URL
|
|
||||||
|
|
||||||
@Suppress("DEPRECATION")
|
val mutex = Mutex()
|
||||||
@Deprecated("Use downloader.Cache instead")
|
fun cleanCache(context: Context) = CoroutineScope(Dispatchers.IO).launch {
|
||||||
fun getCachedGallery(context: Context, galleryID: Int) =
|
if (mutex.isLocked) return@launch
|
||||||
File(getDownloadDirectory(context), galleryID.toString()).let {
|
|
||||||
if (it.exists())
|
mutex.withLock {
|
||||||
it
|
val cacheFolder = File(context.cacheDir, "imageCache")
|
||||||
else
|
val downloadManager = DownloadManager.getInstance(context)
|
||||||
File(context.cacheDir, "imageCache/$galleryID")
|
|
||||||
|
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()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val limit = (Preferences.get<String>("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)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
@Suppress("DEPRECATION")
|
|
||||||
@Deprecated("Use downloader.Cache instead")
|
|
||||||
fun getDownloadDirectory(context: Context) =
|
|
||||||
Preferences.get<String>("dl_location").let {
|
|
||||||
if (it.isNotEmpty() && !it.startsWith("content"))
|
|
||||||
File(it)
|
|
||||||
else
|
|
||||||
context.getExternalFilesDir(null)!!
|
|
||||||
}
|
|
||||||
|
|
||||||
@Suppress("DEPRECATION")
|
|
||||||
@Deprecated("Use FileX instead")
|
|
||||||
fun File.isParentOf(another: File) =
|
|
||||||
another.absolutePath.startsWith(this.absolutePath)
|
|
||||||
@@ -150,4 +150,6 @@
|
|||||||
<string name="camera_denied">カメラ権限が拒否されているため、まばたき検知使用できません</string>
|
<string name="camera_denied">カメラ権限が拒否されているため、まばたき検知使用できません</string>
|
||||||
<string name="no_camera">この機器には前面カメラが装着されていません</string>
|
<string name="no_camera">この機器には前面カメラが装着されていません</string>
|
||||||
<string name="error">エラー</string>
|
<string name="error">エラー</string>
|
||||||
|
<string name="settings_cache_limit">キャッシュサイズ制限</string>
|
||||||
|
<string name="settings_cache_unlimited">制限なし</string>
|
||||||
</resources>
|
</resources>
|
||||||
@@ -150,4 +150,6 @@
|
|||||||
<string name="camera_denied">카메라 권한이 거부되었기 때문에 눈 깜빡임 감지가 불가능합니다</string>
|
<string name="camera_denied">카메라 권한이 거부되었기 때문에 눈 깜빡임 감지가 불가능합니다</string>
|
||||||
<string name="no_camera">이 장치에는 전면 카메라가 없습니다</string>
|
<string name="no_camera">이 장치에는 전면 카메라가 없습니다</string>
|
||||||
<string name="error">오류</string>
|
<string name="error">오류</string>
|
||||||
|
<string name="settings_cache_limit">캐시 크기 제한</string>
|
||||||
|
<string name="settings_cache_unlimited">무제한</string>
|
||||||
</resources>
|
</resources>
|
||||||
@@ -58,4 +58,24 @@
|
|||||||
<item>SOCKS</item>
|
<item>SOCKS</item>
|
||||||
</string-array>
|
</string-array>
|
||||||
|
|
||||||
|
<string-array name="cache_size">
|
||||||
|
<item>0</item>
|
||||||
|
<item>1</item>
|
||||||
|
<item>2</item>
|
||||||
|
<item>4</item>
|
||||||
|
<item>8</item>
|
||||||
|
<item>16</item>
|
||||||
|
<item>32</item>
|
||||||
|
</string-array>
|
||||||
|
|
||||||
|
<string-array name="cache_size_text">
|
||||||
|
<item>@string/settings_cache_unlimited</item>
|
||||||
|
<item>1G</item>
|
||||||
|
<item>2G</item>
|
||||||
|
<item>4G</item>
|
||||||
|
<item>8G</item>
|
||||||
|
<item>16G</item>
|
||||||
|
<item>32G</item>
|
||||||
|
</string-array>
|
||||||
|
|
||||||
</resources>
|
</resources>
|
||||||
@@ -161,6 +161,9 @@
|
|||||||
<string name="settings_download_folder_available">%s available</string>
|
<string name="settings_download_folder_available">%s available</string>
|
||||||
<string name="settings_download_folder_custom">Custom Location</string>
|
<string name="settings_download_folder_custom">Custom Location</string>
|
||||||
<string name="settings_download_folder_not_writable">This folder is not writable. Please select another folder.</string>
|
<string name="settings_download_folder_not_writable">This folder is not writable. Please select another folder.</string>
|
||||||
|
<string name="settings_cache_limit">Cache Limit</string>
|
||||||
|
<string name="settings_cache_unlimited">Unlimited</string>
|
||||||
|
<string name="settings_nomedia_title">Hide image from gallery</string>
|
||||||
<string name="settings_low_quality">Low quality images</string>
|
<string name="settings_low_quality">Low quality images</string>
|
||||||
<string name="settings_low_quality_summary">Load low quality images to improve load speed and data usage</string>
|
<string name="settings_low_quality_summary">Load low quality images to improve load speed and data usage</string>
|
||||||
|
|
||||||
@@ -179,7 +182,6 @@
|
|||||||
<string name="settings_security_mode_summary">Enable security mode to make the screen invisible on recent app window</string>
|
<string name="settings_security_mode_summary">Enable security mode to make the screen invisible on recent app window</string>
|
||||||
<string name="settings_dark_mode_title">Dark mode</string>
|
<string name="settings_dark_mode_title">Dark mode</string>
|
||||||
<string name="settings_dark_mode_summary">Protect yourself against light attacks!</string>
|
<string name="settings_dark_mode_summary">Protect yourself against light attacks!</string>
|
||||||
<string name="settings_nomedia_title">Hide image from gallery</string>
|
|
||||||
<string name="settings_import_old_galleries">Import old galleries</string>
|
<string name="settings_import_old_galleries">Import old galleries</string>
|
||||||
<string name="settings_user_id">User ID</string>
|
<string name="settings_user_id">User ID</string>
|
||||||
<string name="settings_user_id_toast">User ID is copied to clipboard</string>
|
<string name="settings_user_id_toast">User ID is copied to clipboard</string>
|
||||||
|
|||||||
@@ -44,6 +44,14 @@
|
|||||||
app:key="download_folder"
|
app:key="download_folder"
|
||||||
app:title="@string/settings_download_folder"/>
|
app:title="@string/settings_download_folder"/>
|
||||||
|
|
||||||
|
<ListPreference
|
||||||
|
app:key="cache_limit"
|
||||||
|
app:title="@string/settings_cache_limit"
|
||||||
|
app:entries="@array/cache_size_text"
|
||||||
|
app:entryValues="@array/cache_size"
|
||||||
|
app:defaultValue="8"
|
||||||
|
app:useSimpleSummaryProvider="true"/>
|
||||||
|
|
||||||
<SwitchPreferenceCompat
|
<SwitchPreferenceCompat
|
||||||
app:key="nomedia"
|
app:key="nomedia"
|
||||||
app:title="@string/settings_nomedia_title"/>
|
app:title="@string/settings_nomedia_title"/>
|
||||||
|
|||||||
Reference in New Issue
Block a user