Show error message when loading media fails

This commit is contained in:
Naveen Singh 2024-09-09 23:44:53 +05:30
parent cf000a6546
commit 642f0ccd06
No known key found for this signature in database
GPG key ID: 35F7D64346B28ED7
15 changed files with 152 additions and 32 deletions

View file

@ -309,6 +309,18 @@ open class VideoPlayerActivity : SimpleActivity(), SeekBar.OnSeekBarChangeListen
mVideoSize.y = videoSize.height mVideoSize.y = videoSize.height
setVideoSize() setVideoSize()
} }
override fun onPlayerErrorChanged(error: PlaybackException?) {
binding.errorMessageHolder.errorMessage.apply {
if (error != null) {
text = error.localizedMessage ?: getString(R.string.failed_to_load_media)
setTextColor(if (context.config.blackBackground) Color.WHITE else context.getProperTextColor())
fadeIn()
} else {
beGone()
}
}
}
}) })
} }

View file

@ -11,8 +11,10 @@ import android.view.Menu
import android.view.MotionEvent import android.view.MotionEvent
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.widget.ImageView
import android.widget.RelativeLayout import android.widget.RelativeLayout
import androidx.annotation.RequiresApi import androidx.annotation.RequiresApi
import androidx.appcompat.content.res.AppCompatResources
import androidx.recyclerview.widget.ItemTouchHelper import androidx.recyclerview.widget.ItemTouchHelper
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout import androidx.swiperefreshlayout.widget.SwipeRefreshLayout
@ -820,14 +822,18 @@ class DirectoryAdapter(
} }
activity.loadImage( activity.loadImage(
thumbnailType, type = thumbnailType,
directory.tmb, path = directory.tmb,
dirThumbnail, target = dirThumbnail,
scrollHorizontally, horizontalScroll = scrollHorizontally,
animateGifs, animateGifs = animateGifs,
cropThumbnails, cropThumbnails = cropThumbnails,
roundedCorners, roundCorners = roundedCorners,
directory.getKey() signature = directory.getKey(),
onError = {
dirThumbnail.scaleType = ImageView.ScaleType.CENTER
dirThumbnail.setImageDrawable(AppCompatResources.getDrawable(activity, R.drawable.ic_vector_warning_colored))
}
) )
} }

View file

@ -9,7 +9,9 @@ import android.os.Looper
import android.view.Menu import android.view.Menu
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.widget.ImageView
import android.widget.Toast import android.widget.Toast
import androidx.appcompat.content.res.AppCompatResources
import androidx.core.view.allViews import androidx.core.view.allViews
import com.bumptech.glide.Glide import com.bumptech.glide.Glide
import com.qtalk.recyclerviewfastscroller.RecyclerViewFastScroller import com.qtalk.recyclerviewfastscroller.RecyclerViewFastScroller
@ -681,7 +683,19 @@ class MediaAdapter(
if (loadImageInstantly) { if (loadImageInstantly) {
activity.loadImage( activity.loadImage(
medium.type, path, mediumThumbnail, scrollHorizontally, animateGifs, cropThumbnails, roundedCorners, medium.getKey(), rotatedImagePaths type = medium.type,
path = path,
target = mediumThumbnail,
horizontalScroll = scrollHorizontally,
animateGifs = animateGifs,
cropThumbnails = cropThumbnails,
roundCorners = roundedCorners,
signature = medium.getKey(),
skipMemoryCacheAtPaths = rotatedImagePaths,
onError = {
mediumThumbnail.scaleType = ImageView.ScaleType.CENTER
mediumThumbnail.setImageDrawable(AppCompatResources.getDrawable(activity, R.drawable.ic_vector_warning_colored))
}
) )
} else { } else {
mediumThumbnail.setImageDrawable(null) mediumThumbnail.setImageDrawable(null)
@ -690,8 +704,19 @@ class MediaAdapter(
val isVisible = visibleItemPaths.contains(medium.path) val isVisible = visibleItemPaths.contains(medium.path)
if (isVisible) { if (isVisible) {
activity.loadImage( activity.loadImage(
medium.type, path, mediumThumbnail, scrollHorizontally, animateGifs, cropThumbnails, roundedCorners, type = medium.type,
medium.getKey(), rotatedImagePaths path = path,
target = mediumThumbnail,
horizontalScroll = scrollHorizontally,
animateGifs = animateGifs,
cropThumbnails = cropThumbnails,
roundCorners = roundedCorners,
signature = medium.getKey(),
skipMemoryCacheAtPaths = rotatedImagePaths,
onError = {
mediumThumbnail.scaleType = ImageView.ScaleType.CENTER
mediumThumbnail.setImageDrawable(AppCompatResources.getDrawable(activity, R.drawable.ic_vector_warning_colored))
}
) )
} }
}, IMAGE_LOAD_DELAY) }, IMAGE_LOAD_DELAY)

View file

@ -482,13 +482,29 @@ fun Context.loadImage(
roundCorners: Int, roundCorners: Int,
signature: ObjectKey, signature: ObjectKey,
skipMemoryCacheAtPaths: ArrayList<String>? = null, skipMemoryCacheAtPaths: ArrayList<String>? = null,
onError: (() -> Unit)? = null
) { ) {
target.isHorizontalScrolling = horizontalScroll target.isHorizontalScrolling = horizontalScroll
if (type == TYPE_SVGS) { if (type == TYPE_SVGS) {
loadSVG(path, target, cropThumbnails, roundCorners, signature) loadSVG(
path = path,
target = target,
cropThumbnails = cropThumbnails,
roundCorners = roundCorners,
signature = signature
)
} else { } else {
val tryLoadingWithPicasso = type == TYPE_IMAGES && path.isPng() loadImageBase(
loadImageBase(path, target, cropThumbnails, roundCorners, signature, skipMemoryCacheAtPaths, animateGifs, tryLoadingWithPicasso) path = path,
target = target,
cropThumbnails = cropThumbnails,
roundCorners = roundCorners,
signature = signature,
skipMemoryCacheAtPaths = skipMemoryCacheAtPaths,
animate = animateGifs,
tryLoadingWithPicasso = type == TYPE_IMAGES && path.isPng(),
onError = onError
)
} }
} }
@ -524,6 +540,7 @@ fun Context.loadImageBase(
animate: Boolean = false, animate: Boolean = false,
tryLoadingWithPicasso: Boolean = false, tryLoadingWithPicasso: Boolean = false,
crossFadeDuration: Int = THUMBNAIL_FADE_DURATION_MS, crossFadeDuration: Int = THUMBNAIL_FADE_DURATION_MS,
onError: (() -> Unit)? = null
) { ) {
val options = RequestOptions() val options = RequestOptions()
.signature(signature) .signature(signature)
@ -571,10 +588,14 @@ fun Context.loadImageBase(
.set(WebpDownsampler.USE_SYSTEM_DECODER, false) // CVE-2023-4863 .set(WebpDownsampler.USE_SYSTEM_DECODER, false) // CVE-2023-4863
.transition(DrawableTransitionOptions.withCrossFade(crossFadeDuration)) .transition(DrawableTransitionOptions.withCrossFade(crossFadeDuration))
if (tryLoadingWithPicasso) {
builder = builder.listener(object : RequestListener<Drawable> { builder = builder.listener(object : RequestListener<Drawable> {
override fun onLoadFailed(e: GlideException?, model: Any?, targetBitmap: Target<Drawable>, isFirstResource: Boolean): Boolean { override fun onLoadFailed(e: GlideException?, model: Any?, targetBitmap: Target<Drawable>, isFirstResource: Boolean): Boolean {
if (tryLoadingWithPicasso) {
tryLoadingWithPicasso(path, target, cropThumbnails, roundCorners, signature) tryLoadingWithPicasso(path, target, cropThumbnails, roundCorners, signature)
} else {
onError?.invoke()
}
return true return true
} }
@ -584,11 +605,8 @@ fun Context.loadImageBase(
targetBitmap: Target<Drawable>, targetBitmap: Target<Drawable>,
dataSource: DataSource, dataSource: DataSource,
isFirstResource: Boolean, isFirstResource: Boolean,
): Boolean { ) = false
return false
}
}) })
}
builder.into(target) builder.into(target)
} }

View file

@ -518,6 +518,11 @@ class PhotoFragment : ViewPagerFragment() {
loadImage() loadImage()
// TODO: Implement panorama using a FOSS library // TODO: Implement panorama using a FOSS library
// checkIfPanorama() // checkIfPanorama()
} else {
binding.errorMessageHolder.errorMessage.apply {
setTextColor(if (context.config.blackBackground) Color.WHITE else context.getProperTextColor())
fadeIn()
}
} }
} }
}) })

View file

@ -2,6 +2,7 @@ package org.fossify.gallery.fragments
import android.annotation.SuppressLint import android.annotation.SuppressLint
import android.content.res.Configuration import android.content.res.Configuration
import android.graphics.Color
import android.graphics.Point import android.graphics.Point
import android.graphics.SurfaceTexture import android.graphics.SurfaceTexture
import android.net.Uri import android.net.Uri
@ -449,6 +450,20 @@ class VideoFragment : ViewPagerFragment(), TextureView.SurfaceTextureListener, S
mVideoSize.y = (videoSize.height / videoSize.pixelWidthHeightRatio).toInt() mVideoSize.y = (videoSize.height / videoSize.pixelWidthHeightRatio).toInt()
setVideoSize() setVideoSize()
} }
override fun onPlayerErrorChanged(error: PlaybackException?) {
binding.errorMessageHolder.errorMessage.apply {
if (error != null) {
binding.videoPlayOutline.beGone()
text = error.localizedMessage ?: getString(R.string.failed_to_load_media)
setTextColor(if (context.config.blackBackground) Color.WHITE else context.getProperTextColor())
fadeIn()
} else {
beGone()
binding.videoPlayOutline.beVisible()
}
}
}
}) })
} }

View file

@ -23,7 +23,7 @@ class MyGlideImageDecoder(val degrees: Int, val signature: ObjectKey) : ImageDec
.load(uri.toString().substringAfter("file://")) .load(uri.toString().substringAfter("file://"))
.apply(options) .apply(options)
.transform(RotateTransformation(-degrees)) .transform(RotateTransformation(-degrees))
.into(Target.SIZE_ORIGINAL, Target.SIZE_ORIGINAL) .submit(Target.SIZE_ORIGINAL, Target.SIZE_ORIGINAL)
return builder.get() return builder.get()
} }

View file

@ -0,0 +1,6 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="48dp" android:height="48dp" android:viewportWidth="512" android:viewportHeight="512">
<path android:fillColor="#f2a600" android:pathData="M241.06 137.78L130.47 358.96c-4.13 8.55-0.55 18.82 7.98 22.95 2.3 1.11 4.79 1.7 7.34 1.72h221.18c9.49-0.09 17.12-7.85 17.04-17.33a17.23 17.23 0 0 0-1.72-7.34L271.7 137.78a17.16 17.16 0 0 0-30.62 0"/>
<path android:fillColor="#ffcc32" android:pathData="M233.41 153.31L129.63 360.45c-3.89 8.02-0.53 17.67 7.49 21.57 2.11 1.02 4.42 1.57 6.76 1.62h207.36a16.06 16.06 0 0 0 15.91-16.21 16.16 16.16 0 0 0-1.66-6.98L261.92 153.31a15.83 15.83 0 0 0-21.12-7.38 15.95 15.95 0 0 0-7.38 7.38"/>
<path android:fillColor="#424242" android:pathData="M256.37 192.23c9.78 0 17.65 7.87 17.01 17.01l-7.23 102.08c-0.81 5.4-5.83 9.14-11.23 8.34a9.89 9.89 0 0 1-8.34-8.34l-7.23-102.08c-0.64-9.14 7.23-17.01 17.01-17.01m0 136.11c7.04 0 12.76 5.72 12.76 12.76s-5.72 12.76-12.76 12.76-12.76-5.72-12.76-12.76 5.72-12.76 12.76-12.76" android:strokeAlpha="0.2"/>
<path android:fillColor="#fff170" android:pathData="M233.41 168.83c-2.55 3.19-45.51 87.2-45.51 87.2s-3.83 6.38 1.49 10c4.89 3.4 9.36-0.64 11.27-3.83 1.91-3.19 40.83-78.48 42.32-82.09 1.28-3.98 0.38-8.32-2.34-11.48-2.76-2.55-5.53-2.13-7.23 0.21m-54.24 111.24a7.02 7.02 135 1 1 14.04 0 7.02 7.02 0 1 1-14.04 0"/>
</vector>

View file

@ -50,6 +50,10 @@
android:id="@+id/bottom_video_time_holder" android:id="@+id/bottom_video_time_holder"
layout="@layout/bottom_video_time_holder" /> layout="@layout/bottom_video_time_holder" />
<include
android:id="@+id/error_message_holder"
layout="@layout/layout_media_load_error" />
<TextView <TextView
android:id="@+id/slide_info" android:id="@+id/slide_info"
android:layout_width="wrap_content" android:layout_width="wrap_content"

View file

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/error_message"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:layout_marginHorizontal="@dimen/bigger_margin"
android:layout_toStartOf="@id/instant_next_item"
android:layout_toEndOf="@id/instant_prev_item"
android:alpha="0"
android:text="@string/failed_to_load_media"
android:textAlignment="center"
android:visibility="gone"
app:drawableTopCompat="@drawable/ic_vector_warning_colored"
tools:alpha="1"
tools:visibility="visible" />

View file

@ -32,6 +32,10 @@
android:layout_height="match_parent" android:layout_height="match_parent"
android:visibility="gone" /> android:visibility="gone" />
<include
android:id="@+id/error_message_holder"
layout="@layout/layout_media_load_error" />
<ImageView <ImageView
android:id="@+id/panorama_outline" android:id="@+id/panorama_outline"
android:layout_width="@dimen/play_outline_size_big" android:layout_width="@dimen/play_outline_size_big"

View file

@ -43,6 +43,10 @@
android:padding="20dp" android:padding="20dp"
android:src="@drawable/ic_play_outline_vector" /> android:src="@drawable/ic_play_outline_vector" />
<include
android:id="@+id/error_message_holder"
layout="@layout/layout_media_load_error" />
<ImageView <ImageView
android:id="@+id/panorama_outline" android:id="@+id/panorama_outline"
android:layout_width="@dimen/play_outline_size_big" android:layout_width="@dimen/play_outline_size_big"

View file

@ -10,7 +10,8 @@
<org.fossify.commons.views.MySquareImageView <org.fossify.commons.views.MySquareImageView
android:id="@+id/medium_thumbnail" android:id="@+id/medium_thumbnail"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" /> android:layout_height="match_parent"
tools:src="@mipmap/ic_launcher" />
<TextView <TextView
android:id="@+id/file_type" android:id="@+id/file_type"

View file

@ -16,7 +16,8 @@
<org.fossify.commons.views.MySquareImageView <org.fossify.commons.views.MySquareImageView
android:id="@+id/medium_thumbnail" android:id="@+id/medium_thumbnail"
android:layout_width="@dimen/list_view_folder_thumbnail_size" android:layout_width="@dimen/list_view_folder_thumbnail_size"
android:layout_height="@dimen/list_view_folder_thumbnail_size" /> android:layout_height="@dimen/list_view_folder_thumbnail_size"
tools:src="@mipmap/ic_launcher" />
<ImageView <ImageView
android:id="@+id/favorite" android:id="@+id/favorite"

View file

@ -34,6 +34,7 @@
<string name="reorder_by_dragging_pro">Reorder folders by dragging (Pro)</string> <string name="reorder_by_dragging_pro">Reorder folders by dragging (Pro)</string>
<string name="restore_to_path">Restoring to \'%s\'</string> <string name="restore_to_path">Restoring to \'%s\'</string>
<string name="full_storage_permission_required">Fossify Gallery needs full access to display all your photos and videos. Go to Settings > Permissions > Photos and videos > Allow all.</string> <string name="full_storage_permission_required">Fossify Gallery needs full access to display all your photos and videos. Go to Settings > Permissions > Photos and videos > Allow all.</string>
<string name="failed_to_load_media">Failed to load media.</string>
<!-- Filter --> <!-- Filter -->
<string name="filter_media">Filter media</string> <string name="filter_media">Filter media</string>