diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/settings/SettingsGeneralScreen.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/settings/SettingsGeneralScreen.kt
index 6aa94fa883c..279375ba047 100644
--- a/app/src/main/java/com/lagradost/cloudstream3/ui/settings/SettingsGeneralScreen.kt
+++ b/app/src/main/java/com/lagradost/cloudstream3/ui/settings/SettingsGeneralScreen.kt
@@ -114,6 +114,16 @@ object SettingsGeneralScreen : SearchableSettings {
}.sortedBy { fromTagToLanguageName(it) ?: it }
return persistentListOf(
+ Preference.PreferenceGroup(
+ title = stringResource(R.string.image_loading_options_title),
+ preferenceItems = persistentListOf(
+ Preference.PreferenceItem.ListPreference(
+ preference = settings.general.imageDecodingMode,
+ title = stringResource(R.string.image_decoding_title),
+ entries = mapOf("auto" to stringResource(R.string.image_decoding_automatic), "software" to stringResource(R.string.image_decoding_software)),
+ ),
+ ),
+ ),
Preference.PreferenceGroup(title = stringResource(R.string.extension_language), preferenceItems = persistentListOf(
Preference.PreferenceItem.ListPreference(
preference = settings.general.locale,
diff --git a/app/src/main/java/com/lagradost/cloudstream3/utils/ImageDecodingPreferenceInterceptor.kt b/app/src/main/java/com/lagradost/cloudstream3/utils/ImageDecodingPreferenceInterceptor.kt
new file mode 100644
index 00000000000..770b2e6da67
--- /dev/null
+++ b/app/src/main/java/com/lagradost/cloudstream3/utils/ImageDecodingPreferenceInterceptor.kt
@@ -0,0 +1,19 @@
+package com.lagradost.cloudstream3.utils
+
+import android.graphics.Bitmap
+import androidx.preference.PreferenceManager
+import coil3.intercept.Interceptor
+import coil3.request.ImageResult
+import coil3.request.allowHardware
+import coil3.request.bitmapConfig
+
+internal class ImageDecodingPreferenceInterceptor : Interceptor {
+ override suspend fun intercept(chain: Interceptor.Chain): ImageResult {
+ val request = chain.request
+ val softwareSelected = PreferenceManager.getDefaultSharedPreferences(request.context)
+ .getString("image_decoding_mode", "auto") == "software"
+ if (!softwareSelected || !request.allowHardware) return chain.proceed()
+ return chain.withRequest(request.newBuilder().allowHardware(false)
+ .bitmapConfig(Bitmap.Config.ARGB_8888).build()).proceed()
+ }
+}
diff --git a/app/src/main/java/com/lagradost/cloudstream3/utils/ImageModuleCoil.kt b/app/src/main/java/com/lagradost/cloudstream3/utils/ImageModuleCoil.kt
index 96193fe45f7..3ec67ae173d 100644
--- a/app/src/main/java/com/lagradost/cloudstream3/utils/ImageModuleCoil.kt
+++ b/app/src/main/java/com/lagradost/cloudstream3/utils/ImageModuleCoil.kt
@@ -26,6 +26,9 @@ import coil3.request.ImageRequest
import coil3.request.allowHardware
import coil3.request.bitmapConfig
import coil3.request.crossfade
+import coil3.request.error
+import coil3.request.fallback
+import coil3.request.placeholder
import coil3.util.DebugLogger
import com.lagradost.cloudstream3.BuildConfig
import com.lagradost.cloudstream3.USER_AGENT
@@ -58,6 +61,7 @@ object ImageLoader {
/** Pass interceptors with care, unnecessary passing tokens to servers
or image hosting services causes unauthorized exceptions **/
.components {
+ add(ImageDecodingPreferenceInterceptor())
add(OkHttpNetworkFetcherFactory(callFactory = { buildDefaultClient(context) }))
if (isBrokenHardware) {
add(BitmapFactoryDecoder.Factory())
@@ -98,13 +102,19 @@ object ImageLoader {
) {
// clear image to avoid loading & flickering issue at fast scrolling (~recycler view/lazy column)
this.dispose()
- if (imageData == null) return
+ if (imageData == null || (imageData is String && imageData.isBlank())) {
+ this.setImageResource(com.lagradost.cloudstream3.R.drawable.default_cover)
+ return
+ }
// setImageResource is better than coil3 on resources due to attr
if (imageData is Int) {
this.setImageResource(imageData); return
}
// headers can be overridden by extensions.
this.load(imageData, SingletonImageLoader.get(context)) {
+ placeholder { getImageFromDrawable(context, com.lagradost.cloudstream3.R.drawable.default_cover) }
+ error { getImageFromDrawable(context, com.lagradost.cloudstream3.R.drawable.default_cover) }
+ fallback { getImageFromDrawable(context, com.lagradost.cloudstream3.R.drawable.default_cover) }
this.httpHeaders(NetworkHeaders.Builder().also { headerBuilder ->
headerBuilder["User-Agent"] = USER_AGENT
headers?.forEach { (key, value) ->
diff --git a/app/src/main/res/values-es/image_loading_options.xml b/app/src/main/res/values-es/image_loading_options.xml
new file mode 100644
index 00000000000..3c0d2642d1f
--- /dev/null
+++ b/app/src/main/res/values-es/image_loading_options.xml
@@ -0,0 +1,7 @@
+
+ Carga de imágenes
+ Decodificación de imágenes
+ Automática
+ Compatibilidad por software
+ Choose software decoding for hardware compatibility problems. Automatic keeps the current image loader behavior.
+
diff --git a/app/src/main/res/values/image_loading_options.xml b/app/src/main/res/values/image_loading_options.xml
new file mode 100644
index 00000000000..7775e28ae71
--- /dev/null
+++ b/app/src/main/res/values/image_loading_options.xml
@@ -0,0 +1,9 @@
+
+ Image loading
+ Image decoding
+ Automatic
+ Software compatibility
+ Choose software decoding for hardware compatibility problems. Automatic keeps the current image loader behavior.
+ - @string/image_decoding_automatic
- @string/image_decoding_software
+ - auto
- software
+
diff --git a/app/src/main/res/xml/settings_general.xml b/app/src/main/res/xml/settings_general.xml
index f8b9b4f452f..ee4fe6c2b92 100644
--- a/app/src/main/res/xml/settings_general.xml
+++ b/app/src/main/res/xml/settings_general.xml
@@ -1,6 +1,9 @@
+
+
+