From 92b2da028644ecba9fb983fdc4fb914f0434eb29 Mon Sep 17 00:00:00 2001 From: Jake McGinty Date: Wed, 9 Sep 2015 18:05:21 -1000 Subject: [PATCH] download control details Closes #4063 // FREEBIE --- .../transfer_controls_background.9.png | Bin 0 -> 1122 bytes .../transfer_controls_background.9.png | Bin 0 -> 675 bytes .../transfer_controls_background.9.png | Bin 0 -> 1331 bytes .../transfer_controls_background.9.png | Bin 0 -> 2678 bytes .../transfer_controls_background.9.png | Bin 0 -> 2887 bytes res/layout/transfer_controls_view.xml | 23 ++-- res/values/dimens.xml | 3 + res/values/strings.xml | 5 + .../securesms/components/AnimatingToggle.java | 50 ++------- .../securesms/components/ThumbnailView.java | 39 ++++--- .../components/TransferControlView.java | 99 +++++++++++++++--- .../securesms/mms/AttachmentManager.java | 2 + .../securesms/mms/AudioSlide.java | 5 + .../securesms/mms/ImageSlide.java | 5 + src/org/thoughtcrime/securesms/mms/Slide.java | 2 + .../securesms/mms/VideoSlide.java | 5 + .../thoughtcrime/securesms/util/ViewUtil.java | 23 ++++ 17 files changed, 177 insertions(+), 84 deletions(-) create mode 100644 res/drawable-hdpi/transfer_controls_background.9.png create mode 100644 res/drawable-mdpi/transfer_controls_background.9.png create mode 100644 res/drawable-xhdpi/transfer_controls_background.9.png create mode 100644 res/drawable-xxhdpi/transfer_controls_background.9.png create mode 100644 res/drawable-xxxhdpi/transfer_controls_background.9.png diff --git a/res/drawable-hdpi/transfer_controls_background.9.png b/res/drawable-hdpi/transfer_controls_background.9.png new file mode 100644 index 0000000000000000000000000000000000000000..0e503fb5126da06dce91c323dbad158315ebee09 GIT binary patch literal 1122 zcmV-o1fBbdP)5xTqF@04tN@4Gxn ziwN-+e@(~vD)dU>t8|>d##?C8B2PN56~y^bZqPwo#C7gMuQ%MqbzG!_+^CH?rJNGW z{pE@B!)Wm>=&girqvJ1?C(8Y~BF+r)0=h@fLhgj4?8sLu@LgjlIzKW;$Bo*UR- zp3RuJbC4_iHFTnBp}KQ08)6SUd_Y&AlMY?M2k@Mpw23Y^lI0o9rsJkY40^rYXhWx- zj@lFSra^S^D9%7O+W>LrAU=S$E+6h3TsM&`#&c-L^H^O!@oQ)+ z(^@C7QiHZN<=J%*cMf8|y+k_jz|fjRUce1|iMWCK8pLuxy$x-1{CCRzs}m=1%5EY~ z@#LyRe+iN0#K>P-jaWh(+WNFsA=bwDw*5rDRU2E8$PH)-@t;_U=+Z$MMC^CmWr;kA zi$aK(cyd`H>bNe1cpdfSh$V#Fl|ke#LZ@U9t^QqOgx)Fl8$@*v+H#0!t9uNhH^Rr| z5c#+oHHb9DR|OHT(v(3|d!Qx7R|XMvSwvbiiGeI40+SdDBQ^~pJuiz$&l^O%EQ^R& z{wDsRq}OB-={4h7EBlmA|n|A{L9dr|(c8~MLc<^R)=|9?^bzkc~^H}Y5D z=KuR@AdP(RgW|9r1%pX<$hnnxf}VXr;0Oh zj#Hi$caqT@v@9jIic`fB&V~y=;ZG#|o(4jvr?_onj<2NNnG$gGt+>Bv+(PYGa0|7# zOKkOxa3bON`l%LUI|DD!*}MT!7v8Z!wW2A-=Dr*HhIhzrE&5aqB;GwmkJH)AK4Kno z+*BIGe3i)yw&SayH^m+}gemvHg^rs=o8SAmoC5H2s%?J88c!81iJgqbx+@(>rdg8? zlxK6(kBYkgPR#wN?_}SPYHaxMq`wqT%PsHY$=tNuno}D?NC$BVH#YQ~M!11XbP!=> z+$mYoIPL94lio&a?Z#=e=xut++iOeXw9y-`M!jiY(INsg{paxty~Z!m|ItK1i@x%v o)u_71g5L1-rkG-W5|=;bXWcO$rU7C$!~g&Q07*qoM6N<$f(1tlV3>w-km)L6;Sne|;n6B! zoaT}+(@SHQF_NWwY$pno*yy~6VU-Mtcq9w@(|-Ya2r$C>AnP`6$vm}y#&Ll1Q<>)z+N{)$w<6egCQdYhKvT|ekm{>&|u+lDX{Rk2E&pR z7?v~`tx18=+IQF&8@9y2w)IQ7DHJC0Qp&#h#l9}YzF@^}Npd#vXp8*M9_b&7Qa`O_ z{EWPAmjC-E>xWlliGT`Pi9kpZN-wI&FGFe7eNUN|S?c`%s#2%6xXTBOyDBKBW6wEk zufhfd0+9^}X)PO_HY&2oCAcjpuaW9j~k++}#^sQo^s>mNF5zi(?yYa035zD_ZXkoCbfKB{K0jgPg#Hru0s)Jv;$e&bm> zr&a2G-Rxy>HPwU+4}{0D#A~$uV|a1^nN-uiiCRDFgP?p_9|6oX%~4}&RWSen002ov JPDHLkV1lv>IE(-Q literal 0 HcmV?d00001 diff --git a/res/drawable-xhdpi/transfer_controls_background.9.png b/res/drawable-xhdpi/transfer_controls_background.9.png new file mode 100644 index 0000000000000000000000000000000000000000..8f4d75a97bec182fa32d18d2cf27683882e4415e GIT binary patch literal 1331 zcmeAS@N?(olHy`uVBq!ia0vp^(?OVn8A$3oT6!}uFbW3vgt!8^K%kgpOA z8bA^VG&MDWY@n33wlz;Didb@`4?z$bV-n3FvEX#ab-O#Cl7C5 zJ}uY8ir$$L4yoFBz zS?YiPx_Mr0{ZG4-r>{KaXK}7j72)|ITHdOBQDRGnt8!szY-frV?^~ltFO3(co+e+= zo_5~zotB8V!J-fy?>CFMdR9+ZvM!7F*_Bs9yZ-Rbxc-6r-6oT0frWRsbi7%_=fYXq zTKaX9z{%^vm#@k@tZ|HYxLy#_l(97MP|o!VCdp;S#j&6Ho#KMx zZ}BaTea*Y%melJa$8B>bu9JOI{QCVZr`EOi)`?z;c=>vf*_DjR^Va4_y3r^F0WuyjIGhe|z#eg^Iay z$JP(KPb0M zZ@lBiz~X3lx#g&9Vw&H?8Iqs=*S93TKlIHpd};gzr_;Nwjei_mt;JM+H_qA6;_)Y` z&VwhOnu;}VJpFo|#GTSAUzfy3A9iVQiOa?X2hOnCb8L}8S;bV>g>OEr>To(*b@Yg0 z+MY*`1kB?&3q2&(FR@VR4fm1>I;O45m-%?AV0+KUQ(eyACSOnAJjde6na`$AZR6)_ zINguWKceXS_urzr`^o?9KGpjN)Yk{ruTQGKAN*f_(ZBx{fgO;YOYo8MW#bNudX`ogYvSAEL6?A850e&_zPW%ydhRGlxh^VFX62k#jNzTdy$ zd(oBOPH$}0zSfxvRj)9pka&FG{qy^ivNr3rGFF}cS;<Xi|cUGK=US+=LrFmuC zr0G-URbOM@T%obPV#kLq_UWb3aRt?)pLgVE?7jH%=9=0U>AMcTN;eYOW@Q&Z%&6`E zed(cw`Eln=`LO$ocgugyeO8zk_hp^@WX==a{PQ(B{oUR(%F3IX_6c!b0A_RsPgg&e IbxsLQ0Nc1IRR910 literal 0 HcmV?d00001 diff --git a/res/drawable-xxhdpi/transfer_controls_background.9.png b/res/drawable-xxhdpi/transfer_controls_background.9.png new file mode 100644 index 0000000000000000000000000000000000000000..cdbc966d88dd808313cdaf3ad6db093500d2a433 GIT binary patch literal 2678 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 literal 0 HcmV?d00001 diff --git a/res/drawable-xxxhdpi/transfer_controls_background.9.png b/res/drawable-xxxhdpi/transfer_controls_background.9.png new file mode 100644 index 0000000000000000000000000000000000000000..4aad138cfd53822481adfb1e480f88d196e729d4 GIT binary patch literal 2887 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 literal 0 HcmV?d00001 diff --git a/res/layout/transfer_controls_view.xml b/res/layout/transfer_controls_view.xml index 2a8888929f..f696f9d681 100644 --- a/res/layout/transfer_controls_view.xml +++ b/res/layout/transfer_controls_view.xml @@ -4,19 +4,22 @@ - + \ No newline at end of file diff --git a/res/values/dimens.xml b/res/values/dimens.xml index a4666889bf..481601a441 100644 --- a/res/values/dimens.xml +++ b/res/values/dimens.xml @@ -34,4 +34,7 @@ 250dp 52dp + + 150dp + 70dp diff --git a/res/values/strings.xml b/res/values/strings.xml index c321f70f97..dac80e337b 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -384,6 +384,11 @@ Registration error TextSecure registration has encountered a problem. + + Image + Audio + Video + Received corrupted key exchange message! diff --git a/src/org/thoughtcrime/securesms/components/AnimatingToggle.java b/src/org/thoughtcrime/securesms/components/AnimatingToggle.java index 03a13f73b8..30b100b89a 100644 --- a/src/org/thoughtcrime/securesms/components/AnimatingToggle.java +++ b/src/org/thoughtcrime/securesms/components/AnimatingToggle.java @@ -3,7 +3,6 @@ package org.thoughtcrime.securesms.components; import android.content.Context; import android.support.annotation.NonNull; import android.support.annotation.Nullable; -import android.support.v4.view.animation.FastOutSlowInInterpolator; import android.util.AttributeSet; import android.view.View; import android.view.ViewGroup; @@ -12,21 +11,27 @@ import android.view.animation.AnimationUtils; import android.widget.FrameLayout; import org.thoughtcrime.securesms.R; +import org.thoughtcrime.securesms.util.ViewUtil; public class AnimatingToggle extends FrameLayout { private View current; + private final Animation inAnimation; + private final Animation outAnimation; + public AnimatingToggle(Context context) { - super(context); + this(context, null); } public AnimatingToggle(Context context, AttributeSet attrs) { - super(context, attrs); + this(context, attrs, 0); } public AnimatingToggle(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); + this.outAnimation = AnimationUtils.loadAnimation(getContext(), R.anim.animation_toggle_out); + this.inAnimation = AnimationUtils.loadAnimation(getContext(), R.anim.animation_toggle_in); } @Override @@ -43,45 +48,10 @@ public class AnimatingToggle extends FrameLayout { } public void display(@Nullable View view) { - display(view, true); - } - - protected void display(@Nullable View view, boolean animated) { if (view == current) return; - - if (animated) { - if (current != null) animateOut(current, AnimationUtils.loadAnimation(getContext(), R.anim.animation_toggle_out)); - if (view != null) animateIn(view, AnimationUtils.loadAnimation(getContext(), R.anim.animation_toggle_in)); - } else { - if (current != null) current.setVisibility(GONE); - if (view != null) view.setVisibility(VISIBLE); - } + if (current != null) ViewUtil.animateOut(current, outAnimation); + if (view != null) ViewUtil.animateIn(view, inAnimation); current = view; } - - private void animateOut(final View view, Animation animation) { - animation.setAnimationListener(new Animation.AnimationListener() { - @Override - public void onAnimationStart(Animation animation) { - } - - @Override - public void onAnimationEnd(Animation animation) { - view.setVisibility(View.GONE); - } - - @Override - public void onAnimationRepeat(Animation animation) { - } - }); - - view.startAnimation(animation); - } - - private void animateIn(View view, Animation animation) { - animation.setInterpolator(new FastOutSlowInInterpolator()); - view.setVisibility(View.VISIBLE); - view.startAnimation(animation); - } } diff --git a/src/org/thoughtcrime/securesms/components/ThumbnailView.java b/src/org/thoughtcrime/securesms/components/ThumbnailView.java index 33d5f41d30..c57616f0ce 100644 --- a/src/org/thoughtcrime/securesms/components/ThumbnailView.java +++ b/src/org/thoughtcrime/securesms/components/ThumbnailView.java @@ -91,7 +91,6 @@ public class ThumbnailView extends FrameLayout { private TransferControlView getTransferControls() { if (transferControls == null) transferControls = ViewUtil.inflateStub(this, R.id.transfer_controls_stub); - return transferControls; } @@ -99,9 +98,10 @@ public class ThumbnailView extends FrameLayout { this.backgroundColorHint = color; } - public void setImageResource(@Nullable MasterSecret masterSecret, - long id, long timestamp, - @NonNull ListenableFutureTask slideDeckFuture) + public void setImageResource(@Nullable MasterSecret masterSecret, + long id, + long timestamp, + @NonNull ListenableFutureTask slideDeckFuture) { if (this.slideDeckFuture != null && this.slideDeckListener != null) { this.slideDeckFuture.removeListener(this.slideDeckListener); @@ -126,15 +126,17 @@ public class ThumbnailView extends FrameLayout { Log.w(TAG, "Not re-loading slide " + slide.getPart().getPartId()); return; } + if (!isContextValid()) { Log.w(TAG, "Not loading slide, context is invalid"); return; } - Log.w(TAG, "loading part with id " + slide.getPart().getPartId() + ", progress " + slide.getTransferProgress()); + Log.w(TAG, "loading part with id " + slide.getPart().getPartId() + + ", progress " + slide.getTransferProgress()); this.slide = slide; - buildGlideRequest(slide, masterSecret).into(image); + loadInto(slide, masterSecret, image); if (this.slide.getTransferProgress() == PartDatabase.TRANSFER_PROGRESS_DONE) { setOnClickListener(new ThumbnailClickDispatcher()); @@ -145,7 +147,6 @@ public class ThumbnailView extends FrameLayout { if (!hideControls) { getTransferControls().setSlide(slide); getTransferControls().setDownloadClickListener(new DownloadClickDispatcher()); - getTransferControls().setVisibility(View.VISIBLE); } } @@ -189,29 +190,27 @@ public class ThumbnailView extends FrameLayout { !((Activity)getContext()).isDestroyed(); } - private GenericRequestBuilder buildGlideRequest(@NonNull Slide slide, - @Nullable MasterSecret masterSecret) + private void loadInto(@NonNull Slide slide, + @Nullable MasterSecret masterSecret, + @NonNull ImageView view) { - final GenericRequestBuilder builder; if (slide.getThumbnailUri() != null) { - builder = buildThumbnailGlideRequest(slide, masterSecret); + buildThumbnailGlideRequest(slide, masterSecret).into(view); + } else if (!slide.isInProgress()) { + buildPlaceholderGlideRequest(slide).into(view); } else { - builder = buildPlaceholderGlideRequest(slide); - } - - if (slide.getTransferProgress() != PartDatabase.TRANSFER_PROGRESS_DONE && !hideControls) { - return builder; - } else { - return builder.error(R.drawable.ic_missing_thumbnail_picture); + Glide.clear(view); } } private GenericRequestBuilder buildThumbnailGlideRequest(Slide slide, MasterSecret masterSecret) { - final GenericRequestBuilder builder; + if (slide.isDraft()) builder = buildDraftGlideRequest(slide, masterSecret); else builder = buildPartGlideRequest(slide, masterSecret); - return builder; + + if (slide.isInProgress()) return builder; + else return builder.error(R.drawable.ic_missing_thumbnail_picture); } private GenericRequestBuilder buildDraftGlideRequest(Slide slide, MasterSecret masterSecret) { diff --git a/src/org/thoughtcrime/securesms/components/TransferControlView.java b/src/org/thoughtcrime/securesms/components/TransferControlView.java index c2406e1b00..282a7ae6aa 100644 --- a/src/org/thoughtcrime/securesms/components/TransferControlView.java +++ b/src/org/thoughtcrime/securesms/components/TransferControlView.java @@ -3,9 +3,18 @@ package org.thoughtcrime.securesms.components; import android.content.Context; import android.support.annotation.NonNull; import android.support.annotation.Nullable; +import android.support.v4.view.animation.FastOutSlowInInterpolator; import android.util.AttributeSet; -import android.widget.ImageButton; +import android.view.View; +import android.view.ViewGroup; +import android.view.animation.AlphaAnimation; +import android.view.animation.Animation; +import android.widget.FrameLayout; +import android.widget.TextView; +import com.nineoldandroids.animation.Animator; +import com.nineoldandroids.animation.ValueAnimator; +import com.nineoldandroids.animation.ValueAnimator.AnimatorUpdateListener; import com.pnikosis.materialishprogress.ProgressWheel; import org.thoughtcrime.securesms.R; @@ -17,10 +26,18 @@ import org.thoughtcrime.securesms.util.ViewUtil; import de.greenrobot.event.EventBus; -public class TransferControlView extends AnimatingToggle { - private Slide slide; - private ProgressWheel progressWheel; - private ImageButton downloadButton; +public class TransferControlView extends FrameLayout { + private static final int TRANSITION_MS = 300; + + @Nullable private Slide slide; + @Nullable private View current; + + private final ProgressWheel progressWheel; + private final TextView downloadDetails; + private final Animation inAnimation; + private final Animation outAnimation; + private final int contractedWidth; + private final int expandedWidth; public TransferControlView(Context context) { this(context, null); @@ -33,8 +50,18 @@ public class TransferControlView extends AnimatingToggle { public TransferControlView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); inflate(context, R.layout.transfer_controls_view, this); - this.progressWheel = ViewUtil.findById(this, R.id.progress_wheel); - this.downloadButton = ViewUtil.findById(this, R.id.download_button); + setBackgroundResource(R.drawable.transfer_controls_background); + setVisibility(GONE); + this.progressWheel = ViewUtil.findById(this, R.id.progress_wheel); + this.downloadDetails = ViewUtil.findById(this, R.id.download_details); + this.contractedWidth = getResources().getDimensionPixelSize(R.dimen.transfer_controls_contracted_width); + this.expandedWidth = getResources().getDimensionPixelSize(R.dimen.transfer_controls_expanded_width); + this.outAnimation = new AlphaAnimation(1f, 0f); + this.inAnimation = new AlphaAnimation(0f, 1f); + this.outAnimation.setInterpolator(new FastOutSlowInInterpolator()); + this.inAnimation.setInterpolator(new FastOutSlowInInterpolator()); + this.outAnimation.setDuration(TRANSITION_MS); + this.inAnimation.setDuration(TRANSITION_MS); } @Override protected void onAttachedToWindow() { @@ -49,13 +76,13 @@ public class TransferControlView extends AnimatingToggle { public void setSlide(final @NonNull Slide slide) { this.slide = slide; - if (slide.getTransferProgress() == PartDatabase.TRANSFER_PROGRESS_STARTED) { showProgressSpinner(); } else if (slide.isPendingDownload()) { - display(downloadButton); + downloadDetails.setText(slide.getContentDescription()); + display(downloadDetails); } else { - display(null, false); + display(null); } } @@ -65,12 +92,57 @@ public class TransferControlView extends AnimatingToggle { } public void setDownloadClickListener(final @Nullable OnClickListener listener) { - downloadButton.setOnClickListener(listener); + downloadDetails.setOnClickListener(listener); } public void clear() { - display(null, false); - slide = null; + clearAnimation(); + setVisibility(GONE); + if (current != null) { + current.clearAnimation(); + current.setVisibility(GONE); + } + current = null; + slide = null; + } + + private void display(@Nullable final View view) { + final int sourceWidth = current == downloadDetails ? expandedWidth : contractedWidth; + final int targetWidth = view == downloadDetails ? expandedWidth : contractedWidth; + + if (current == view || current == null) { + ViewGroup.LayoutParams layoutParams = getLayoutParams(); + layoutParams.width = targetWidth; + setLayoutParams(layoutParams); + } else { + ViewUtil.animateOut(current, outAnimation); + Animator anim = getWidthAnimator(sourceWidth, targetWidth); + anim.start(); + } + + if (view == null) { + ViewUtil.animateOut(this, outAnimation); + } else { + ViewUtil.animateIn(this, inAnimation); + ViewUtil.animateIn(view, inAnimation); + } + + current = view; + } + + private Animator getWidthAnimator(final int from, final int to) { + final ValueAnimator anim = ValueAnimator.ofInt(from, to); + anim.addUpdateListener(new AnimatorUpdateListener() { + @Override public void onAnimationUpdate(ValueAnimator animation) { + final int val = (Integer)animation.getAnimatedValue(); + final ViewGroup.LayoutParams layoutParams = getLayoutParams(); + layoutParams.width = val; + setLayoutParams(layoutParams); + } + }); + anim.setInterpolator(new FastOutSlowInInterpolator()); + anim.setDuration(TRANSITION_MS); + return anim; } @SuppressWarnings("unused") @@ -79,7 +151,6 @@ public class TransferControlView extends AnimatingToggle { Util.runOnMain(new Runnable() { @Override public void run() { progressWheel.setInstantProgress(((float)event.progress) / event.total); - if (event.progress >= event.total) display(null); } }); } diff --git a/src/org/thoughtcrime/securesms/mms/AttachmentManager.java b/src/org/thoughtcrime/securesms/mms/AttachmentManager.java index e401918a55..3ede7180eb 100644 --- a/src/org/thoughtcrime/securesms/mms/AttachmentManager.java +++ b/src/org/thoughtcrime/securesms/mms/AttachmentManager.java @@ -33,6 +33,8 @@ import android.view.animation.AlphaAnimation; import android.view.animation.Animation; import android.widget.Toast; +import junit.framework.Assert; + import org.thoughtcrime.securesms.R; import org.thoughtcrime.securesms.components.ThumbnailView; import org.thoughtcrime.securesms.crypto.MasterSecret; diff --git a/src/org/thoughtcrime/securesms/mms/AudioSlide.java b/src/org/thoughtcrime/securesms/mms/AudioSlide.java index 78948e65c2..ef4850a7dd 100644 --- a/src/org/thoughtcrime/securesms/mms/AudioSlide.java +++ b/src/org/thoughtcrime/securesms/mms/AudioSlide.java @@ -20,6 +20,7 @@ import android.content.Context; import android.content.res.Resources.Theme; import android.net.Uri; import android.support.annotation.DrawableRes; +import android.support.annotation.NonNull; import org.thoughtcrime.securesms.R; import org.thoughtcrime.securesms.util.ResUtil; @@ -49,6 +50,10 @@ public class AudioSlide extends Slide { return true; } + @NonNull @Override public String getContentDescription() { + return context.getString(R.string.Slide_audio); + } + @Override public @DrawableRes int getPlaceholderRes(Theme theme) { return ResUtil.getDrawableRes(theme, R.attr.conversation_icon_attach_audio); diff --git a/src/org/thoughtcrime/securesms/mms/ImageSlide.java b/src/org/thoughtcrime/securesms/mms/ImageSlide.java index 5720a53074..875943dc3a 100644 --- a/src/org/thoughtcrime/securesms/mms/ImageSlide.java +++ b/src/org/thoughtcrime/securesms/mms/ImageSlide.java @@ -20,6 +20,7 @@ import android.content.Context; import android.content.res.Resources.Theme; import android.net.Uri; import android.support.annotation.DrawableRes; +import android.support.annotation.NonNull; import org.thoughtcrime.securesms.R; @@ -59,4 +60,8 @@ public class ImageSlide extends Slide { public boolean hasImage() { return true; } + + @NonNull @Override public String getContentDescription() { + return context.getString(R.string.Slide_image); + } } diff --git a/src/org/thoughtcrime/securesms/mms/Slide.java b/src/org/thoughtcrime/securesms/mms/Slide.java index f23ff2e653..2dd09a136f 100644 --- a/src/org/thoughtcrime/securesms/mms/Slide.java +++ b/src/org/thoughtcrime/securesms/mms/Slide.java @@ -63,6 +63,8 @@ public abstract class Slide { return false; } + public @NonNull String getContentDescription() { return ""; } + public PduPart getPart() { return part; } diff --git a/src/org/thoughtcrime/securesms/mms/VideoSlide.java b/src/org/thoughtcrime/securesms/mms/VideoSlide.java index 7140a3f795..d243d0c307 100644 --- a/src/org/thoughtcrime/securesms/mms/VideoSlide.java +++ b/src/org/thoughtcrime/securesms/mms/VideoSlide.java @@ -20,6 +20,7 @@ import android.content.Context; import android.content.res.Resources.Theme; import android.net.Uri; import android.support.annotation.DrawableRes; +import android.support.annotation.NonNull; import org.thoughtcrime.securesms.R; import org.thoughtcrime.securesms.util.ResUtil; @@ -53,4 +54,8 @@ public class VideoSlide extends Slide { public boolean hasVideo() { return true; } + + @NonNull @Override public String getContentDescription() { + return context.getString(R.string.Slide_video); + } } diff --git a/src/org/thoughtcrime/securesms/util/ViewUtil.java b/src/org/thoughtcrime/securesms/util/ViewUtil.java index 9f82db6625..130ec2b7ff 100644 --- a/src/org/thoughtcrime/securesms/util/ViewUtil.java +++ b/src/org/thoughtcrime/securesms/util/ViewUtil.java @@ -26,6 +26,7 @@ import android.text.TextUtils.TruncateAt; import android.view.View; import android.view.ViewGroup; import android.view.ViewStub; +import android.view.animation.Animation; import android.widget.TextView; public class ViewUtil { @@ -73,4 +74,26 @@ public class ViewUtil { public static T findById(@NonNull View parent, @IdRes int resId) { return (T) parent.findViewById(resId); } + + public static void animateOut(final @NonNull View view, final @NonNull Animation animation) { + if (view.getVisibility() == View.GONE) return; + + view.clearAnimation(); + animation.setAnimationListener(new Animation.AnimationListener() { + @Override public void onAnimationStart(Animation animation) {} + @Override public void onAnimationRepeat(Animation animation) {} + @Override public void onAnimationEnd(Animation animation) { + view.setVisibility(View.GONE); + } + }); + + view.startAnimation(animation); + } + + public static void animateIn(final @NonNull View view, final @NonNull Animation animation) { + if (view.getVisibility() == View.VISIBLE) return; + view.clearAnimation(); + view.setVisibility(View.VISIBLE); + view.startAnimation(animation); + } }