Show an overlay on image attachments that failed to load

This commit is contained in:
Grishka 2024-09-13 00:47:04 +03:00
parent f5961c8077
commit eda1526830
7 changed files with 101 additions and 3 deletions

View File

@ -700,6 +700,10 @@ public abstract class BaseStatusListFragment<T extends DisplayItemsParent> exten
anim.start();
}
public void retryFailedImages(){
imgLoader.retryFailedRequests();
}
protected class DisplayItemsAdapter extends UsableRecyclerView.Adapter<BindableViewHolder<StatusDisplayItem>> implements ImageLoaderRecyclerAdapter{
public DisplayItemsAdapter(){

View File

@ -9,6 +9,7 @@ import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.LayerDrawable;
import android.text.TextUtils;
import android.util.Log;
import android.util.Pair;
import android.view.Gravity;
import android.view.View;
@ -110,6 +111,7 @@ public class MediaGridStatusDisplayItem extends StatusDisplayItem{
private static final ColorDrawable drawableForWhenThereIsNoBlurhash=new ColorDrawable(0xffffffff);
private final TextView hideSensitiveButton;
private final TextView sensitiveText;
private boolean thereAreFailedImages;
public Holder(Activity activity, ViewGroup parent){
super(new FrameLayoutThatOnlyMeasuresFirstChild(activity));
@ -143,6 +145,7 @@ public class MediaGridStatusDisplayItem extends StatusDisplayItem{
@Override
public void onBind(MediaGridStatusDisplayItem item){
thereAreFailedImages=false;
wrapper.setPadding(0, 0, 0, item.inset ? 0 : V.dp(8));
layout.setTiledLayout(item.tiledLayout);
@ -220,9 +223,23 @@ public class MediaGridStatusDisplayItem extends StatusDisplayItem{
controllers.get(index).clearImage();
}
@Override
public void onImageLoadingFailed(int index, Throwable error){
controllers.get(index).showFailedOverlay();
thereAreFailedImages=true;
}
private void onViewClick(View v){
int index=(Integer)v.getTag();
((PhotoViewerHost) item.parentFragment).openPhotoViewer(item.parentID, item.status, index, this);
if(thereAreFailedImages){
for(MediaAttachmentViewController controller:controllers){
if(controller.isFailedOverlayShown()){
controller.clearImage();
}
}
item.parentFragment.retryFailedImages();
}
}
private void onAltTextClick(View v){

View File

@ -11,7 +11,6 @@ import android.view.ViewGroup;
import org.joinmastodon.android.R;
import org.joinmastodon.android.api.session.AccountSessionManager;
import org.joinmastodon.android.fragments.BaseStatusListFragment;
import org.joinmastodon.android.fragments.StatusListFragment;
import org.joinmastodon.android.fragments.ThreadFragment;
import org.joinmastodon.android.model.Account;
import org.joinmastodon.android.model.Attachment;
@ -35,7 +34,7 @@ import me.grishka.appkit.views.UsableRecyclerView;
public abstract class StatusDisplayItem{
public final String parentID;
public final BaseStatusListFragment parentFragment;
public final BaseStatusListFragment<?> parentFragment;
public boolean inset;
public int index;
@ -45,7 +44,7 @@ public abstract class StatusDisplayItem{
public static final int FLAG_MEDIA_FORCE_HIDDEN=1 << 3;
public static final int FLAG_NO_HEADER=1 << 4;
public StatusDisplayItem(String parentID, BaseStatusListFragment parentFragment){
public StatusDisplayItem(String parentID, BaseStatusListFragment<?> parentFragment){
this.parentID=parentID;
this.parentFragment=parentFragment;
}

View File

@ -16,6 +16,8 @@ import org.joinmastodon.android.ui.displayitems.MediaGridStatusDisplayItem;
import org.joinmastodon.android.ui.drawables.BlurhashCrossfadeDrawable;
import org.joinmastodon.android.ui.drawables.PlayIconDrawable;
import me.grishka.appkit.utils.V;
public class MediaAttachmentViewController{
public final View view;
public final MediaGridStatusDisplayItem.GridItemType type;
@ -23,6 +25,8 @@ public class MediaAttachmentViewController{
public final View altButton;
public final TextView duration;
public final View playButton;
public final View failedOverlay;
public final View failedText;
private BlurhashCrossfadeDrawable crossfadeDrawable=new BlurhashCrossfadeDrawable();
private final Context context;
private boolean didClear;
@ -39,6 +43,8 @@ public class MediaAttachmentViewController{
altButton=view.findViewById(R.id.alt_button);
duration=view.findViewById(R.id.duration);
playButton=view.findViewById(R.id.play_button);
failedOverlay=view.findViewById(R.id.failed_overlay);
failedText=view.findViewById(R.id.failed_text);
this.type=type;
this.context=context;
if(playButton!=null){
@ -65,6 +71,11 @@ public class MediaAttachmentViewController{
duration.setText(UiUtils.formatMediaDuration((int)attachment.getDuration()));
}
didClear=false;
if(failedOverlay!=null){
V.cancelVisibilityAnimation(failedOverlay);
failedOverlay.setVisibility(View.GONE);
failedText.setVisibility(status.mediaAttachments.size()>1 ? View.GONE : View.VISIBLE);
}
}
public void setImage(Drawable drawable){
@ -76,11 +87,27 @@ public class MediaAttachmentViewController{
photo.setImageDrawable(null);
photo.setImageDrawable(crossfadeDrawable);
}
if(failedOverlay!=null && failedOverlay.getVisibility()!=View.GONE){
V.setVisibilityAnimated(failedOverlay, View.GONE);
}
}
public void clearImage(){
crossfadeDrawable.setCrossfadeAlpha(1f);
crossfadeDrawable.setImageDrawable(null);
didClear=true;
if(failedOverlay!=null && failedOverlay.getVisibility()!=View.GONE){
V.setVisibilityAnimated(failedOverlay, View.GONE);
}
}
public void showFailedOverlay(){
if(failedOverlay!=null){
V.setVisibilityAnimated(failedOverlay, View.VISIBLE);
}
}
public boolean isFailedOverlayShown(){
return failedOverlay!=null && failedOverlay.getVisibility()!=View.GONE;
}
}

View File

@ -0,0 +1,20 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="64dp"
android:height="64dp"
android:viewportWidth="64"
android:viewportHeight="64">
<path
android:pathData="M28,11L25,15L31,23L25,31L31,39L25,47L28,51H5V11H28Z"
android:fillColor="#000000"
android:fillAlpha="0.4" />
<path
android:pathData="M2.2,53.8C3,54.6 3.933,55 5,55L31,55L28,51H5V11H28L31,7H5C3.933,7 3,7.4 2.2,8.2C1.4,9 1,9.933 1,11V51C1,52.067 1.4,53 2.2,53.8ZM28.397,35.529L22.733,42.867L16.533,34.4L8.733,44.533H26.85L31,39L28.397,35.529Z"
android:fillColor="#000000" />
<path
android:pathData="M43.449,11.897L39.571,15.052L43.457,24.266L35.7,30.577L39.586,39.791L31.829,46.102L33.772,50.709L50.268,54.821L59.944,16.01L43.449,11.897Z"
android:fillColor="#000000"
android:fillAlpha="0.4" />
<path
android:pathData="M47.328,8.742L43.449,11.897L59.944,16.01L50.268,54.821L33.772,50.709L35.716,55.316L49.3,58.703C50.335,58.961 51.337,58.798 52.307,58.216C53.277,57.633 53.891,56.824 54.149,55.789L63.826,16.977C64.084,15.942 63.921,14.94 63.339,13.97C62.756,13 61.947,12.387 60.912,12.128L47.328,8.742ZM34.221,44.156L48.274,47.66L41.926,32.611L37.9,35.794L39.586,39.791L34.221,44.156Z"
android:fillColor="#000000" />
</vector>

View File

@ -15,4 +15,34 @@
<include layout="@layout/alt_text_badge"
android:id="@+id/alt_button"/>
<LinearLayout
android:id="@+id/failed_overlay"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:background="#33000000"
android:gravity="center"
android:visibility="gone"
tools:visibility="visible">
<View
android:layout_width="64dp"
android:layout_height="64dp"
android:background="@drawable/broken_media"
android:backgroundTint="#fff"/>
<TextView
android:id="@+id/failed_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="16dp"
android:layout_marginTop="20dp"
android:minHeight="16dp"
android:gravity="center"
android:textColor="#fff"
android:textAppearance="@style/m3_label_medium"
android:text="@string/cant_load_image"/>
</LinearLayout>
</FrameLayout>

View File

@ -777,4 +777,5 @@
<string name="donation_server_error">We are sorry, an error occurred and we have not been able to process your donation.\n\nPlease retry in a few minutes.</string>
<string name="settings_donate">Donate to Mastodon</string>
<string name="settings_manage_donations">Manage donations</string>
<string name="cant_load_image">Couldnt load image</string>
</resources>