Skip to content

Commit 5e9b9f4

Browse files
author
me
committed
Add customizable thumbnail cache management
Add user-configurable thumbnail cache size limits to give users more options for memory management. Glide's default thumbnail cache size is 250MB which is insufficient for larger galleries. This adds a new section in the settings menu to: - View current cache usage - Select from predefined cache size limits (250MB default, 500MB, 1GB, 2GB, 5GB) - Clear the thumbnail cache manually
1 parent 5630a4c commit 5e9b9f4

File tree

7 files changed

+245
-60
lines changed

7 files changed

+245
-60
lines changed
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
package org.fossify.gallery
2+
3+
import android.content.Context
4+
import android.graphics.drawable.PictureDrawable
5+
import com.bumptech.glide.Glide
6+
import com.bumptech.glide.GlideBuilder
7+
import com.bumptech.glide.Registry
8+
import com.bumptech.glide.annotation.GlideModule
9+
import com.bumptech.glide.load.DecodeFormat
10+
import com.bumptech.glide.load.engine.bitmap_recycle.LruBitmapPool
11+
import com.bumptech.glide.load.engine.cache.InternalCacheDiskCacheFactory
12+
import com.bumptech.glide.load.engine.cache.LruResourceCache
13+
import com.bumptech.glide.load.engine.cache.MemorySizeCalculator
14+
import com.bumptech.glide.module.AppGlideModule
15+
import com.bumptech.glide.request.RequestOptions
16+
import com.caverock.androidsvg.SVG
17+
import org.fossify.gallery.extensions.config
18+
import org.fossify.gallery.svg.SvgDecoder
19+
import org.fossify.gallery.svg.SvgDrawableTranscoder
20+
import java.io.InputStream
21+
22+
// This class is automatically discovered by Glide thanks to the @GlideModule annotation.
23+
// Merged functionality from original SvgModule and cache configuration.
24+
@GlideModule
25+
class MyAppGlideModule : AppGlideModule() {
26+
27+
override fun applyOptions(context: Context, builder: GlideBuilder) {
28+
// Set disk cache size based on user preference
29+
val diskCacheSizeBytes = context.config.getThumbnailCacheSizeBytes()
30+
builder.setDiskCache(InternalCacheDiskCacheFactory(context, GLIDE_CACHE_DIR, diskCacheSizeBytes))
31+
32+
// Apply Fossify's preferred format
33+
builder.setDefaultRequestOptions(RequestOptions().format(DecodeFormat.PREFER_ARGB_8888))
34+
35+
// Configure memory cache and bitmap pool sizes
36+
val calculator = MemorySizeCalculator.Builder(context)
37+
.setMemoryCacheScreens(2f)
38+
.setBitmapPoolScreens(3f)
39+
.build()
40+
41+
builder.setMemoryCache(LruResourceCache(calculator.memoryCacheSize.toLong()))
42+
builder.setBitmapPool(LruBitmapPool(calculator.bitmapPoolSize.toLong()))
43+
}
44+
45+
// Added from original SvgModule
46+
override fun registerComponents(context: Context, glide: Glide, registry: Registry) {
47+
registry.register(SVG::class.java, PictureDrawable::class.java, SvgDrawableTranscoder())
48+
.append(InputStream::class.java, SVG::class.java, SvgDecoder())
49+
}
50+
51+
// Disable manifest parsing to avoid potential conflicts
52+
override fun isManifestParsingEnabled(): Boolean {
53+
return false
54+
}
55+
56+
companion object {
57+
// Using Glide's default internal directory name allows calculating its size easily later
58+
const val GLIDE_CACHE_DIR = "image_manager_disk_cache"
59+
}
60+
}

app/src/main/kotlin/org/fossify/gallery/activities/SettingsActivity.kt

Lines changed: 83 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,15 @@ import android.content.Intent
66
import android.os.Bundle
77
import android.text.TextUtils
88
import android.widget.Toast
9+
import androidx.appcompat.app.AlertDialog
10+
import com.bumptech.glide.Glide
911
import com.google.gson.Gson
1012
import com.google.gson.reflect.TypeToken
1113
import org.fossify.commons.dialogs.*
1214
import org.fossify.commons.extensions.*
1315
import org.fossify.commons.helpers.*
1416
import org.fossify.commons.models.RadioItem
17+
import org.fossify.gallery.MyAppGlideModule
1518
import org.fossify.gallery.R
1619
import org.fossify.gallery.databinding.ActivitySettingsBinding
1720
import org.fossify.gallery.dialogs.*
@@ -49,6 +52,81 @@ class SettingsActivity : SimpleActivity() {
4952
setupSettingItems()
5053
}
5154

55+
private fun getGlideCacheDirSize(): Long {
56+
val cacheDir = File(cacheDir, MyAppGlideModule.GLIDE_CACHE_DIR)
57+
// Use the getProperSize function from the Commons library
58+
return cacheDir.getProperSize(true)
59+
}
60+
61+
private fun updateCurrentCacheUsageDisplay() {
62+
ensureBackgroundThread {
63+
val currentSize = getGlideCacheDirSize()
64+
val limitBytes = config.getThumbnailCacheSizeBytes()
65+
val limitString = limitBytes.formatSize()
66+
val displayString = "${currentSize.formatSize()} / $limitString Limit"
67+
68+
runOnUiThread {
69+
// Check if binding is still valid before accessing views
70+
if (!isDestroyed && !isFinishing) {
71+
binding.settingsClearThumbnailCacheSize.text = displayString
72+
}
73+
}
74+
}
75+
}
76+
77+
private fun clearThumbnailCache() {
78+
toast(R.string.clearing_cache)
79+
ensureBackgroundThread {
80+
Glide.get(applicationContext).clearDiskCache()
81+
runOnUiThread {
82+
if (!isDestroyed && !isFinishing) {
83+
toast(R.string.cache_cleared)
84+
updateCurrentCacheUsageDisplay()
85+
}
86+
}
87+
}
88+
}
89+
90+
private fun setupThumbnailCacheSettings() {
91+
val currentLimitBytes = config.getThumbnailCacheSizeBytes()
92+
binding.settingsThumbnailCacheSizeValue.text = currentLimitBytes.formatSize()
93+
94+
binding.settingsThumbnailCacheSizeHolder.setOnClickListener {
95+
val items = arrayListOf(
96+
RadioItem(CACHE_SIZE_AUTO, "${config.getSizeBytesFromPreference(CACHE_SIZE_AUTO).formatSize()} (${getString(R.string.default_text)})"),
97+
RadioItem(CACHE_SIZE_500, config.getSizeBytesFromPreference(CACHE_SIZE_500).formatSize()),
98+
RadioItem(CACHE_SIZE_1000, config.getSizeBytesFromPreference(CACHE_SIZE_1000).formatSize()),
99+
RadioItem(CACHE_SIZE_2000, config.getSizeBytesFromPreference(CACHE_SIZE_2000).formatSize()),
100+
RadioItem(CACHE_SIZE_5000, config.getSizeBytesFromPreference(CACHE_SIZE_5000).formatSize())
101+
)
102+
103+
RadioGroupDialog(this, items, config.thumbnailCacheSizePreference) {
104+
val newPreference = it as Int
105+
if (newPreference == config.thumbnailCacheSizePreference) return@RadioGroupDialog // No change
106+
107+
val oldPreference = config.thumbnailCacheSizePreference
108+
config.thumbnailCacheSizePreference = newPreference
109+
110+
val newLimitBytes = config.getThumbnailCacheSizeBytes()
111+
binding.settingsThumbnailCacheSizeValue.text = newLimitBytes.formatSize()
112+
updateCurrentCacheUsageDisplay()
113+
114+
val oldSizeBytes = config.getSizeBytesFromPreference(oldPreference)
115+
116+
// Clear cache only if the new limit is smaller *and* the old limit wasn't the largest size
117+
if (newLimitBytes < oldSizeBytes && oldPreference != CACHE_SIZE_5000) {
118+
clearThumbnailCache()
119+
toast(R.string.cache_limit_needs_restart)
120+
} else if (newLimitBytes > oldSizeBytes || (newPreference == CACHE_SIZE_5000 && oldPreference != CACHE_SIZE_5000)) {
121+
// Show restart hint only when increasing the limit or switching to the largest size
122+
toast(R.string.cache_limit_needs_restart)
123+
}
124+
}
125+
}
126+
127+
updateCurrentCacheUsageDisplay()
128+
}
129+
52130
private fun setupSettingItems() {
53131
setupCustomizeColors()
54132
setupUseEnglish()
@@ -100,7 +178,8 @@ class SettingsActivity : SimpleActivity() {
100178
setupShowRecycleBinLast()
101179
setupEmptyRecycleBin()
102180
updateTextColors(binding.settingsHolder)
103-
setupClearCache()
181+
setupClearThumbnailCacheItem()
182+
setupThumbnailCacheSettings()
104183
setupExportFavorites()
105184
setupImportFavorites()
106185
setupExportSettings()
@@ -723,21 +802,9 @@ class SettingsActivity : SimpleActivity() {
723802
}
724803
}
725804

726-
private fun setupClearCache() {
727-
ensureBackgroundThread {
728-
val size = cacheDir.getProperSize(true).formatSize()
729-
runOnUiThread {
730-
binding.settingsClearCacheSize.text = size
731-
}
732-
}
733-
734-
binding.settingsClearCacheHolder.setOnClickListener {
735-
ensureBackgroundThread {
736-
cacheDir.deleteRecursively()
737-
runOnUiThread {
738-
binding.settingsClearCacheSize.text = cacheDir.getProperSize(true).formatSize()
739-
}
740-
}
805+
private fun setupClearThumbnailCacheItem() {
806+
binding.settingsClearThumbnailCacheHolder.setOnClickListener {
807+
clearThumbnailCache()
741808
}
742809
}
743810

app/src/main/kotlin/org/fossify/gallery/helpers/Config.kt

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import android.content.res.Configuration
55
import android.os.Environment
66
import com.google.gson.Gson
77
import com.google.gson.reflect.TypeToken
8+
import org.fossify.commons.extensions.formatSize
89
import org.fossify.commons.helpers.*
910
import org.fossify.gallery.R
1011
import org.fossify.gallery.models.AlbumCover
@@ -583,4 +584,28 @@ class Config(context: Context) : BaseConfig(context) {
583584
var showPermissionRationale: Boolean
584585
get() = prefs.getBoolean(SHOW_PERMISSION_RATIONALE, false)
585586
set(showPermissionRationale) = prefs.edit().putBoolean(SHOW_PERMISSION_RATIONALE, showPermissionRationale).apply()
587+
588+
var thumbnailCacheSizePreference: Int
589+
get() = prefs.getInt(THUMBNAIL_CACHE_SIZE, CACHE_SIZE_AUTO)
590+
set(size) = prefs.edit().putInt(THUMBNAIL_CACHE_SIZE, size).apply()
591+
592+
fun getThumbnailCacheSizeBytes(): Long {
593+
return when (thumbnailCacheSizePreference) {
594+
CACHE_SIZE_500 -> 500 * 1024 * 1024L
595+
CACHE_SIZE_1000 -> 1024 * 1024 * 1024L
596+
CACHE_SIZE_2000 -> 2 * 1024 * 1024 * 1024L
597+
CACHE_SIZE_5000 -> 5 * 1024 * 1024 * 1024L
598+
else -> 250 * 1024 * 1024L // Default Auto/250MB if something unexpected is stored
599+
}
600+
}
601+
602+
// Helper function to get size in bytes directly from preference ID for comparison
603+
fun getSizeBytesFromPreference(preference: Int): Long {
604+
// Use a temporary preference value to reuse existing calculation logic
605+
val originalPreference = thumbnailCacheSizePreference
606+
thumbnailCacheSizePreference = preference
607+
val result = getThumbnailCacheSizeBytes()
608+
thumbnailCacheSizePreference = originalPreference
609+
return result
610+
}
586611
}

app/src/main/kotlin/org/fossify/gallery/helpers/Constants.kt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,14 @@ const val SEARCH_ALL_FILES_BY_DEFAULT = "search_all_files_by_default"
103103
const val LAST_EXPORTED_FAVORITES_FOLDER = "last_exported_favorites_folder"
104104
const val SHOW_PERMISSION_RATIONALE = "show_permission_rationale"
105105

106+
// thumbnail cache size
107+
const val THUMBNAIL_CACHE_SIZE = "thumbnail_cache_size_pref"
108+
const val CACHE_SIZE_AUTO = 0 // Glide's default disk cache size is 250MB. This value is used to match that default.
109+
const val CACHE_SIZE_500 = 500
110+
const val CACHE_SIZE_1000 = 1000
111+
const val CACHE_SIZE_2000 = 2000
112+
const val CACHE_SIZE_5000 = 5000
113+
106114
// slideshow
107115
const val SLIDESHOW_INTERVAL = "slideshow_interval"
108116
const val SLIDESHOW_INCLUDE_VIDEOS = "slideshow_include_videos"

app/src/main/kotlin/org/fossify/gallery/svg/SvgModule.kt

Lines changed: 0 additions & 21 deletions
This file was deleted.

app/src/main/res/layout/activity_settings.xml

Lines changed: 62 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -858,6 +858,68 @@
858858
android:id="@+id/settings_bottom_actions_divider"
859859
layout="@layout/divider" />
860860

861+
<include
862+
android:id="@+id/settings_cache_top_divider"
863+
layout="@layout/divider" />
864+
865+
<TextView
866+
android:id="@+id/settings_cache_label"
867+
style="@style/SettingsSectionLabelStyle"
868+
android:layout_width="match_parent"
869+
android:layout_height="wrap_content"
870+
android:text="@string/cache" />
871+
872+
<RelativeLayout
873+
android:id="@+id/settings_thumbnail_cache_size_holder"
874+
style="@style/SettingsHolderTextViewStyle"
875+
android:layout_width="match_parent"
876+
android:layout_height="wrap_content">
877+
878+
<org.fossify.commons.views.MyTextView
879+
android:id="@+id/settings_thumbnail_cache_size_label"
880+
style="@style/SettingsTextLabelStyle"
881+
android:layout_width="wrap_content"
882+
android:layout_height="wrap_content"
883+
android:text="@string/thumbnail_cache_size" />
884+
885+
<org.fossify.commons.views.MyTextView
886+
android:id="@+id/settings_thumbnail_cache_size_value"
887+
style="@style/SettingsTextValueStyle"
888+
android:layout_width="match_parent"
889+
android:layout_height="wrap_content"
890+
android:layout_below="@+id/settings_thumbnail_cache_size_label"
891+
tools:text="250 MB" />
892+
893+
</RelativeLayout>
894+
895+
<RelativeLayout
896+
android:id="@+id/settings_clear_thumbnail_cache_holder"
897+
style="@style/SettingsHolderTextViewStyle"
898+
android:layout_width="match_parent"
899+
android:layout_height="wrap_content"
900+
android:background="?attr/selectableItemBackground">
901+
902+
<org.fossify.commons.views.MyTextView
903+
android:id="@+id/settings_clear_thumbnail_cache_label"
904+
style="@style/SettingsTextLabelStyle"
905+
android:layout_width="wrap_content"
906+
android:layout_height="wrap_content"
907+
android:text="@string/clear_cache" />
908+
909+
<org.fossify.commons.views.MyTextView
910+
android:id="@+id/settings_clear_thumbnail_cache_size"
911+
style="@style/SettingsTextValueStyle"
912+
android:layout_width="match_parent"
913+
android:layout_height="wrap_content"
914+
android:layout_below="@+id/settings_clear_thumbnail_cache_label"
915+
tools:text="180 MB / 5 GB Limit" />
916+
917+
</RelativeLayout>
918+
919+
<include
920+
android:id="@+id/settings_cache_divider"
921+
layout="@layout/divider" />
922+
861923
<TextView
862924
android:id="@+id/settings_recycle_bin_label"
863925
style="@style/SettingsSectionLabelStyle"
@@ -944,29 +1006,6 @@
9441006
android:layout_height="wrap_content"
9451007
android:text="@string/migrating" />
9461008

947-
<RelativeLayout
948-
android:id="@+id/settings_clear_cache_holder"
949-
style="@style/SettingsHolderTextViewStyle"
950-
android:layout_width="match_parent"
951-
android:layout_height="wrap_content">
952-
953-
<org.fossify.commons.views.MyTextView
954-
android:id="@+id/settings_clear_cache_label"
955-
style="@style/SettingsTextLabelStyle"
956-
android:layout_width="wrap_content"
957-
android:layout_height="wrap_content"
958-
android:text="@string/clear_cache" />
959-
960-
<org.fossify.commons.views.MyTextView
961-
android:id="@+id/settings_clear_cache_size"
962-
style="@style/SettingsTextValueStyle"
963-
android:layout_width="match_parent"
964-
android:layout_height="wrap_content"
965-
android:layout_below="@+id/settings_clear_cache_label"
966-
tools:text="0 B" />
967-
968-
</RelativeLayout>
969-
9701009
<RelativeLayout
9711010
android:id="@+id/settings_export_favorites_holder"
9721011
style="@style/SettingsHolderTextViewOneLinerStyle"

app/src/main/res/values/strings.xml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -285,6 +285,13 @@
285285
<string name="faq_17_text">That stopped working due to the system changes that came with Android 11 too, the app cannot browse real folders anymore, it relies on the so called MediaStore at fetching data.</string>
286286
<string name="faq_18_title">Why do I see ads during video playback?</string>
287287
<string name="faq_18_text">Our apps have no ads whatsoever. If you see them during video playback, you must be using some other apps video player. Try finding your default video player in the device settings, then do a \"Clear defaults\" on it. The next time you invoke some video intent you will see an app picker prompt, where you can select what app you want to use.</string>
288+
<string name="cache">Cache</string>
289+
<string name="thumbnail_cache_size">Thumbnail cache size limit</string>
290+
<string name="current_thumbnail_cache_usage">Current thumbnail cache usage</string>
291+
<string name="clearing_cache">Clearing cache…</string>
292+
<string name="cache_cleared">Cache cleared</string>
293+
<string name="cache_limit_needs_restart">New cache limit might require an app restart to take full effect</string>
294+
<string name="default_text">Default</string>
288295
<!--
289296
Haven't found some strings? There's more at
290297
https://github.com/FossifyOrg/Commons/tree/master/commons/src/main/res

0 commit comments

Comments
 (0)