From 8e60d107feb356e1ac3b7f50abafb61fbad350ab Mon Sep 17 00:00:00 2001 From: Grishka Date: Wed, 18 Jan 2023 20:09:27 +0300 Subject: [PATCH] Allow viewing alt text on images closes #100 --- .../displayitems/PhotoStatusDisplayItem.java | 112 ++++++++++++++++++ .../android/ui/views/NestableScrollView.java | 59 +++++++++ .../res/drawable/bg_image_alt_overlay.xml | 5 + .../res/drawable/ic_baseline_close_24.xml | 5 + .../main/res/layout/display_item_photo.xml | 59 +++++++++ 5 files changed, 240 insertions(+) create mode 100644 mastodon/src/main/java/org/joinmastodon/android/ui/views/NestableScrollView.java create mode 100644 mastodon/src/main/res/drawable/bg_image_alt_overlay.xml create mode 100644 mastodon/src/main/res/drawable/ic_baseline_close_24.xml diff --git a/mastodon/src/main/java/org/joinmastodon/android/ui/displayitems/PhotoStatusDisplayItem.java b/mastodon/src/main/java/org/joinmastodon/android/ui/displayitems/PhotoStatusDisplayItem.java index 964f57b4f3..300077c24d 100644 --- a/mastodon/src/main/java/org/joinmastodon/android/ui/displayitems/PhotoStatusDisplayItem.java +++ b/mastodon/src/main/java/org/joinmastodon/android/ui/displayitems/PhotoStatusDisplayItem.java @@ -1,7 +1,18 @@ package org.joinmastodon.android.ui.displayitems; +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; +import android.animation.AnimatorSet; +import android.animation.ObjectAnimator; import android.app.Activity; +import android.text.TextUtils; +import android.view.View; import android.view.ViewGroup; +import android.view.ViewTreeObserver; +import android.widget.FrameLayout; +import android.widget.ImageButton; +import android.widget.ScrollView; +import android.widget.TextView; import org.joinmastodon.android.R; import org.joinmastodon.android.fragments.BaseStatusListFragment; @@ -10,6 +21,7 @@ import org.joinmastodon.android.ui.PhotoLayoutHelper; import me.grishka.appkit.imageloader.requests.UrlImageLoaderRequest; +import me.grishka.appkit.utils.CubicBezierInterpolator; public class PhotoStatusDisplayItem extends ImageStatusDisplayItem{ public PhotoStatusDisplayItem(String parentID, Status status, Attachment photo, BaseStatusListFragment parentFragment, int index, int totalPhotos, PhotoLayoutHelper.TiledLayoutResult tiledLayout, PhotoLayoutHelper.TiledLayoutResult.Tile thisTile){ @@ -23,9 +35,109 @@ public Type getType(){ } public static class Holder extends ImageStatusDisplayItem.Holder{ + private final FrameLayout altTextWrapper; + private final TextView altTextButton; + private final View altTextScroller; + private final ImageButton altTextClose; + private final TextView altText; + + private boolean altTextShown; + private AnimatorSet currentAnim; public Holder(Activity activity, ViewGroup parent){ super(activity, R.layout.display_item_photo, parent); + altTextWrapper=findViewById(R.id.alt_text_wrapper); + altTextButton=findViewById(R.id.alt_button); + altTextScroller=findViewById(R.id.alt_text_scroller); + altTextClose=findViewById(R.id.alt_text_close); + altText=findViewById(R.id.alt_text); + + altTextButton.setOnClickListener(this::onShowHideClick); + altTextClose.setOnClickListener(this::onShowHideClick); +// altTextScroller.setNestedScrollingEnabled(true); + } + + @Override + public void onBind(ImageStatusDisplayItem item){ + super.onBind(item); + altTextShown=false; + if(currentAnim!=null) + currentAnim.cancel(); + altTextScroller.setVisibility(View.GONE); + altTextClose.setVisibility(View.GONE); + altTextButton.setVisibility(View.VISIBLE); + if(TextUtils.isEmpty(item.attachment.description)){ + altTextWrapper.setVisibility(View.GONE); + }else{ + altTextWrapper.setVisibility(View.VISIBLE); + altText.setText(item.attachment.description); + } + } + + private void onShowHideClick(View v){ + boolean show=v.getId()==R.id.alt_button; + + if(altTextShown==show) + return; + if(currentAnim!=null) + currentAnim.cancel(); + + altTextShown=show; + if(show){ + altTextScroller.setVisibility(View.VISIBLE); + altTextClose.setVisibility(View.VISIBLE); + }else{ + altTextButton.setVisibility(View.VISIBLE); + // Hide these views temporarily so FrameLayout measures correctly + altTextScroller.setVisibility(View.GONE); + altTextClose.setVisibility(View.GONE); + } + + // This is the current size... + int prevLeft=altTextWrapper.getLeft(); + int prevRight=altTextWrapper.getRight(); + int prevTop=altTextWrapper.getTop(); + altTextWrapper.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener(){ + @Override + public boolean onPreDraw(){ + altTextWrapper.getViewTreeObserver().removeOnPreDrawListener(this); + + // ...and this is after the layout pass, right now the FrameLayout has its final size, but we animate that change + if(!show){ + // Show these views again so they're visible for the duration of the animation. + // No one would notice they were missing during measure/layout. + altTextScroller.setVisibility(View.VISIBLE); + altTextClose.setVisibility(View.VISIBLE); + } + AnimatorSet set=new AnimatorSet(); + set.playTogether( + ObjectAnimator.ofInt(altTextWrapper, "left", prevLeft, altTextWrapper.getLeft()), + ObjectAnimator.ofInt(altTextWrapper, "right", prevRight, altTextWrapper.getRight()), + ObjectAnimator.ofInt(altTextWrapper, "top", prevTop, altTextWrapper.getTop()), + ObjectAnimator.ofFloat(altTextButton, View.ALPHA, show ? 1f : 0f, show ? 0f : 1f), + ObjectAnimator.ofFloat(altTextScroller, View.ALPHA, show ? 0f : 1f, show ? 1f : 0f), + ObjectAnimator.ofFloat(altTextClose, View.ALPHA, show ? 0f : 1f, show ? 1f : 0f) + ); + set.setDuration(300); + set.setInterpolator(CubicBezierInterpolator.DEFAULT); + set.addListener(new AnimatorListenerAdapter(){ + @Override + public void onAnimationEnd(Animator animation){ + if(show){ + altTextButton.setVisibility(View.GONE); + }else{ + altTextScroller.setVisibility(View.GONE); + altTextClose.setVisibility(View.GONE); + } + currentAnim=null; + } + }); + set.start(); + currentAnim=set; + + return true; + } + }); } } } diff --git a/mastodon/src/main/java/org/joinmastodon/android/ui/views/NestableScrollView.java b/mastodon/src/main/java/org/joinmastodon/android/ui/views/NestableScrollView.java new file mode 100644 index 0000000000..c4ccfbf8e2 --- /dev/null +++ b/mastodon/src/main/java/org/joinmastodon/android/ui/views/NestableScrollView.java @@ -0,0 +1,59 @@ +package org.joinmastodon.android.ui.views; + +import android.content.Context; +import android.util.AttributeSet; +import android.util.Log; +import android.view.MotionEvent; +import android.view.ViewConfiguration; +import android.widget.ScrollView; + +public class NestableScrollView extends ScrollView{ + private float downY, touchslop; + private boolean didDisallow; + + public NestableScrollView(Context context){ + super(context); + init(); + } + + public NestableScrollView(Context context, AttributeSet attrs){ + super(context, attrs); + init(); + } + + public NestableScrollView(Context context, AttributeSet attrs, int defStyleAttr){ + super(context, attrs, defStyleAttr); + init(); + } + + public NestableScrollView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes){ + super(context, attrs, defStyleAttr, defStyleRes); + init(); + } + + private void init(){ + touchslop=ViewConfiguration.get(getContext()).getScaledTouchSlop(); + } + + @Override + public boolean onTouchEvent(MotionEvent ev){ + Log.d("111", "onTouchEvent: "+ev); + if(ev.getAction()==MotionEvent.ACTION_DOWN){ + if(canScrollVertically(-1) || canScrollVertically(1)){ + getParent().requestDisallowInterceptTouchEvent(true); + didDisallow=true; + }else{ + didDisallow=false; + } + downY=ev.getY(); + }else if(didDisallow && ev.getAction()==MotionEvent.ACTION_MOVE){ + if(Math.abs(downY-ev.getY())>=touchslop){ + if(!canScrollVertically((int)(downY-ev.getY()))){ + didDisallow=false; + getParent().requestDisallowInterceptTouchEvent(false); + } + } + } + return super.onTouchEvent(ev); + } +} diff --git a/mastodon/src/main/res/drawable/bg_image_alt_overlay.xml b/mastodon/src/main/res/drawable/bg_image_alt_overlay.xml new file mode 100644 index 0000000000..56dc6e3930 --- /dev/null +++ b/mastodon/src/main/res/drawable/bg_image_alt_overlay.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/mastodon/src/main/res/drawable/ic_baseline_close_24.xml b/mastodon/src/main/res/drawable/ic_baseline_close_24.xml new file mode 100644 index 0000000000..844b6b62ef --- /dev/null +++ b/mastodon/src/main/res/drawable/ic_baseline_close_24.xml @@ -0,0 +1,5 @@ + + + diff --git a/mastodon/src/main/res/layout/display_item_photo.xml b/mastodon/src/main/res/layout/display_item_photo.xml index 9c4c05ca82..00b0bd176d 100644 --- a/mastodon/src/main/res/layout/display_item_photo.xml +++ b/mastodon/src/main/res/layout/display_item_photo.xml @@ -1,5 +1,6 @@ @@ -10,4 +11,62 @@ android:layout_gravity="center" android:scaleType="centerCrop"/> + + + + + + + + + + + + + + + + + + + \ No newline at end of file