From fe4e2fcadba812b8e6cd7db53c3a006f4b67b521 Mon Sep 17 00:00:00 2001 From: Moxie Marlinspike Date: Mon, 18 May 2015 10:26:32 -0700 Subject: [PATCH] Support for direct photo capture from app. Make the send button toggle to an attach button when the compose text and attachments are emmpty. Part of #520 Closes #3186 // FREEBIE --- res/drawable-hdpi/ic_photo_camera_dark.png | Bin 0 -> 636 bytes res/drawable-hdpi/ic_photo_camera_light.png | Bin 0 -> 653 bytes res/drawable-mdpi/ic_photo_camera_dark.png | Bin 0 -> 457 bytes res/drawable-mdpi/ic_photo_camera_light.png | Bin 0 -> 469 bytes res/drawable-xhdpi/ic_photo_camera_dark.png | Bin 0 -> 781 bytes res/drawable-xhdpi/ic_photo_camera_light.png | Bin 0 -> 795 bytes res/drawable-xxhdpi/ic_photo_camera_dark.png | Bin 0 -> 1123 bytes res/drawable-xxhdpi/ic_photo_camera_light.png | Bin 0 -> 1147 bytes res/drawable-xxxhdpi/ic_photo_camera_dark.png | Bin 0 -> 1504 bytes .../ic_photo_camera_light.png | Bin 0 -> 1851 bytes res/layout/conversation_activity.xml | 44 ++++--- res/values/attrs.xml | 1 + res/values/strings.xml | 1 + res/values/themes.xml | 2 + .../securesms/ConversationActivity.java | 55 ++++++++- .../securesms/components/AnimatingToggle.java | 108 ++++++++++++++++++ .../securesms/mms/AttachmentManager.java | 41 ++++++- .../mms/AttachmentTypeSelectorAdapter.java | 10 +- 18 files changed, 234 insertions(+), 28 deletions(-) create mode 100644 res/drawable-hdpi/ic_photo_camera_dark.png create mode 100644 res/drawable-hdpi/ic_photo_camera_light.png create mode 100644 res/drawable-mdpi/ic_photo_camera_dark.png create mode 100644 res/drawable-mdpi/ic_photo_camera_light.png create mode 100644 res/drawable-xhdpi/ic_photo_camera_dark.png create mode 100644 res/drawable-xhdpi/ic_photo_camera_light.png create mode 100644 res/drawable-xxhdpi/ic_photo_camera_dark.png create mode 100644 res/drawable-xxhdpi/ic_photo_camera_light.png create mode 100644 res/drawable-xxxhdpi/ic_photo_camera_dark.png create mode 100644 res/drawable-xxxhdpi/ic_photo_camera_light.png create mode 100644 src/org/thoughtcrime/securesms/components/AnimatingToggle.java diff --git a/res/drawable-hdpi/ic_photo_camera_dark.png b/res/drawable-hdpi/ic_photo_camera_dark.png new file mode 100644 index 0000000000000000000000000000000000000000..f937d64f377b22dc76d362fa8d1ce6112790cb2b GIT binary patch literal 636 zcmV-?0)zdDP)004R> z004l5008;`004mK004C`008P>0026e000+ooVrmw00002VoOIv0RM-N%)bBt010qN zS#tmY3ljhU3ljkVnw%H_00Hz#L_t(o!|j;8N&`U`C zVUBakVZiPg@l4eOd2QG}?bgcB!I36xziRPbh8d!#;!Bi6E!e&6D#|Q(=9Eg@GF`E| z2Mt(R&Z>ZU1UF&`A>NM7ApVHpXWQZQIS z7P2Sr2VKUh7z~y*+F{>JiW{q(4s56qu!7XVl8+lZb=>GkrMR`iZj41=&;Wrsqo1+D zCXK~H@H{&gi#<>Mj_5Bn%2mQxw6g1g`Yu6ICMELbB@sg)~HBu9>- zPfbySsWhpnMz-H;p}|(%ut8ozK|Rs$^%z_Z004R> z004l5008;`004mK004C`008P>0026e000+ooVrmw00002VoOIv0RM-N%)bBt010qN zS#tmY3ljhU3ljkVnw%H_00IR`L_t(o!|m8ROCwPf!0}}9jgO7rB87q=2&jW$Umigh5L!5218axJ_b5@+t1&74Ug;dHrY=Er@V zxi<+Cjf+GRYb4gjIvGc-)2fO6;0O~Ee@W_L+o6=fu%(4%zN8F>4GnCqCdyz~{XcA! zbDnB``B(8mmN6H$fTsq1gvVkKmf}I3G8i66`LU%~D1%|yk8Q+;ZThiHY*?m#%%eb# z9EF;fQ(ah@W2WhrCwiFSgmN6%HA8`0b(kA%Y>zf)WoYM66WgnLc`t(u&{OeCk^?R5 zT6&daiYq%yB`%q)=-sUbR+hPHW#8AjON-21IXZSMz1k0K-;p<*M#rXY`;>E-CTzxR zRLqlob>+mevT#b#u!6kEy?I~hvRTDwSkAT%hVG=a&C2Uw1C786QU^;R!`P`ajGk1A zODA?=Gy0+~5W|dZ|Lw%aZN^;meRd)lyMgW7(*94QTn*cd7Ip%tk8(AlQ;2V9m#hi0 zyxL`PAp@A8gFCHH%wg5Vp^G$WS%L3$^N;4o^Pr-4pQ9s`s_R&AD|1&JBOwDA>A-W! zEWPqXA9KzXsC1MoQ6x{EVn|Ig literal 0 HcmV?d00001 diff --git a/res/drawable-mdpi/ic_photo_camera_dark.png b/res/drawable-mdpi/ic_photo_camera_dark.png new file mode 100644 index 0000000000000000000000000000000000000000..aa3a3e571757b939c19df2a90507401cb2d44888 GIT binary patch literal 457 zcmV;)0XF`LP)004R> z004l5008;`004mK004C`008P>0026e000+ooVrmw00002VoOIv0RM-N%)bBt010qN zS#tmY3ljhU3ljkVnw%H_00BWsL_t(Y$K}>LZo)tmh2hf}QYB>~9zjBECIv;7fRMMs zLm-5Af$$DgQJP!WbLRga+kIH^o=XoqK15F0*t+&;v`3v*g|s zy5o&gdF9pwx*;GdFO>73G9EFe+2B!1LLRp9l2B|7#YyNdDFns%jOj6BZ4X7bIQzOd zbXeIy?>wf8Tw!4fMZZi7kC2clO@yctnL#c>JoCNZ+0jObt_c+5AX*0uz?KHWNgaC* z004R> z004l5008;`004mK004C`008P>0026e000+ooVrmw00002VoOIv0RM-N%)bBt010qN zS#tmY3ljhU3ljkVnw%H_00B)&L_t(Y$K}>NY63wR#_^|FO_h`henb#2lfoiL5ZNRA zuiyuYxVI4Z5P@wh6EG<~fErjNXv#^Gi0itWosErzw;PyWG4H(3jL>;X7X;n0z#P?r zTU+Rcml$I(JacUWT@jpQ42CC)X;2Z5FmZEIZSW{WAE9Aj2UC<2vKHb2e}CG$mf1#M-w61Hc*Iz zXdEyG!JXNT4}h&sE- z>IYSX!@EuUTL{r)d%!#(gll(?mXr{p#(;o;K2?OMoS3;^Mr2MoHX;??@(pb}GPG_& z0%VGjHB-9u@MA}830Vi*=3G&mKm12gsF3S93K<WdP)004R> z004l5008;`004mK004C`008P>0026e000+ooVrmw00002VoOIv0RM-N%)bBt010qN zS#tmY3ljhU3ljkVnw%H_00M`hft2b> zSEV3Gx9zH6OyWYbk*SEEAe(#yA&V{){SZE&J`nl|suHxJLh2*!zpKVO(V4k1xp&g` zo>}HBewq6?=iaffdh4+a$bbyU!eSnonAZh*k6irXoet0&8py^quT_Iy@q>1v&P$b` z7u0AszVTcY=qbnCC%*Ee6Oc`gP0mpr7wj;L69r1Ki_X|56$Y|3a{%_RgF!jsh(a)E zGZxTxFz7rMP(2tFR~V2s&?T#6N#kN;ezXZ^vN*k1}OE#{G2(i)q!M6<>ZoA362?US)wk zUrt3O=*%~jpYi3+tV2e8)4Qe)1N)9)M6fM=4aG^+%^WxKWIrcpqovvECnhF zL;Qb$dTz*WCiS=!XjJv2o)Hd|)kw~fuVkE(*CLoP=D!3<;Ub>Z*N>0U>*sgMhaqat8UXvO%k~bc@B7OROX2TDrzhs$1A> zOOyJLF^ZHZQDjtDS#o8yD^32Cbd&#qRjC;|;dM00000 LNkvXXu0mjf*Bf09 literal 0 HcmV?d00001 diff --git a/res/drawable-xhdpi/ic_photo_camera_light.png b/res/drawable-xhdpi/ic_photo_camera_light.png new file mode 100644 index 0000000000000000000000000000000000000000..62d83b253db2a6a8b087097a760a81fbf7d93394 GIT binary patch literal 795 zcmV+$1LXXPP)004R> z004l5008;`004mK004C`008P>0026e000+ooVrmw00002VoOIv0RM-N%)bBt010qN zS#tmY3ljhU3ljkVnw%H_00NUqL_t(&-tF1TN*hre$MIRT8FbrB#AZ`krK>`hft2b> zSEW#pZrfGCn8bzOY-B3p6J(P|5VGh((TDH?^@7kRs7la=3aOX0r>n*@qmwx?IWuW{ zI7@$!k8>{n|D3U~`fFGQWIzUFVF5y65EbaX5=ZchcTs>|(^Lcru6U&z^pYRS9D$(0 z3!R|n)H~t`1mAe33-pAejyVFsR~~f(N|0xRvpfBCC*z!LX0gLSX?CvqXRYhpj0Sx%AHeJpeApWYxk5QsVk8G>DWx-QlWy>snX zF|8Z4?8y)EkrU6~Ys@p?$y9ZMPCZNcDPL|)9Wd%y-gSK-*Tbm==8hSWl8d@P7t*;i z81QudjD4vWOokqncLc3SNjLPrE=lP%J)oSlvra-mN8D@W3wl7AR&G*hGmp3OSv?@9 zg9-CaT1pS-`p~N=fy&Yp{~w^fo3iUgJ)r~|)4ix?q!-FsDCbbx_C-CQRVg_i3YwGB z>$*xuvXva*plx~S3DY>Mt+SeJ9(j)8#JRO-c%y*p)TGiJr zmVB33hs^o9#!tFi*qpCPz0Wu$%9JTFChaV>vf7g-e@eN@f6LEkUW2BUI0Z#cPhJ$O zp5=XW3@fdjp1w-gS(MHtc{nU7>?|#p4VSD@AWI4xn-p1!tcMj32A%iYrRR1m zpv_>=Y%HLBFvw;va?a;=pB60A>_*Ia81{L}rpOkJ2$u3D`5PBp=DWQC8IS=PkOBSm Zpx@9fMcR%eOgjJo002ovPDHLkV1ic0Tq6Jg literal 0 HcmV?d00001 diff --git a/res/drawable-xxhdpi/ic_photo_camera_dark.png b/res/drawable-xxhdpi/ic_photo_camera_dark.png new file mode 100644 index 0000000000000000000000000000000000000000..5b96a4c6b9b08ba4021e48c0885ede21390cf743 GIT binary patch literal 1123 zcmV-p1f2VcP)004R> z004l5008;`004mK004C`008P>0026e000+ooVrmw00002VoOIv0RM-N%)bBt010qN zS#tmY3ljhU3ljkVnw%H_00Y}eL_t(|+U?v;OI1M_!13!F`Lak_NmPQ6D3t|}U^fXje$itBtdpOF9T{#!2`k__ zRd&_aHrThufCc|ba)83^h z=Y^@TS&9Q~z!V3dMF@MF<8GC3o^E>SrJDvya@@7FX|VMye_KU#G3}XGP@;6 za8k33L10R%zGexd}mF8?MbHNV=O4;&QU3uvNLAD z9!c)jf^zm7$z6M5226Y>O!~?n74pxU0DCVf8GfT#7~^C7us)%{fAtOfEENAc@xvNJ zDc5bDQJUh0Z43X_(^{~UaNl?1g)Is%PkP50TSC9UQoOKUJYkDtbk-;`NA^kNAX(Pp!=PhHB7NNlJU)5}yb|{giJV#G{9qshcLpyaj zdh08+`|ct=MtUCb7^#GpCLSa0)5^736#-azII2x&`CB{aIu)?_GY^OB8(Au3uB%(K zWaJeFFe90=vt6eHojvCn1{t2va3Jae;~{;Hkmr`8W$w@!6ETL_4+3&}v^~_uF5Z3B_2i?LLD||O_-ugyTRx;fGz~W#I=3oxy pU=HSB4(4DE=3oxyU=HT*`VEx=?glx4U9bQE002ovPDHLkV1mng2jKt! literal 0 HcmV?d00001 diff --git a/res/drawable-xxhdpi/ic_photo_camera_light.png b/res/drawable-xxhdpi/ic_photo_camera_light.png new file mode 100644 index 0000000000000000000000000000000000000000..d23e4b47a890e4d387812f94aed788a61df67499 GIT binary patch literal 1147 zcmV->1cdvEP)004R> z004l5008;`004mK004C`008P>0026e000+ooVrmw00002VoOIv0RM-N%)bBt010qN zS#tmY3ljhU3ljkVnw%H_00Z+$L_t(|+U?xWOO!zv!12{h(mWKMBKiS=p;#6ec8sXd zOiJ+VA^(KnTj(F4K{wHZ6t$MpUc{23Yn0WJWL5-%+8-cdpdQqXrb86*&g|~{&ilUm z&e-srpK(9F?>_U+%=2!F)Xt2QgE^RkIhcbvn1lU|11uplVu=GL!}c<##S#cUve#5t zHLtW;0>MkFO@yU+8j2+lOp-PYR>6bNEP>#jX|OwyumpnJCc%h|B@o;&1$I4Bmf$Dd zCcv)oBVw2!&y_e~6|^(PH?|}H;9+BnB_7eH2W#ZLaUgHxXb1|sz=rWGfnc5UL12xR zuzu4T{K6_MxC#G_w|-&mRtLh)VBf5RE&79PTL;_p2NM>CgE`p$3|nJ{ zaR%w9pFzf%VcmAv2X4|#rSumnIm0bJ+6dd`J|{}9nocrG-X_=tM}02|k43P%RTkJX z9f8-oovfG+d&5DkrTigsCc~zv(cY!l!*f$%Q|t=00kbOvEk@XzB3G-5Q*_Zo4_!1- zRphGWOoJ^K_->`?WYRMsuQS0_#q5?M#bM1d5*tii39m3;FypIg-Ajs2lVB5yQEJJQ z%)6_+eWy%;Z7ZhZ{k-#)JIy}Dl$|#Nc3*L|-ucdct+;9r&49_zgqcA3BU1h;6JQ?{ zB_rs^x+snDDS6mUsld+%hJBHWe{b@z=19u*WzQ%rNyFBp|MjF6EGu32jbvdn(!-P9 zamIJ4Utl&_*m&rA_9yB+BW06?4SI6Bv|-+dvY}*Q{hr(&ZJ75!eZaviyA_AcDjrQc zrFh8YUT>Fo)wFWIE=|xATCm5aP0)ffp6siUoFbo1{#o&sv@icPFl&wq&nSJ#!)B%Y zw!kpC3FWg13(b?#2zLYJ4@vo_%~(Naq!DVE4$uj_JA#IcSYUaMNn`BewNIAZyIrTz zC>YcB+Y`koHH`SU33n?pbvC+V+c3SR-2A-Amm-x=-M6OqP!=0(g+t1ZS;=LxeD^$M zJf>AD@W10ItEL@FK!y6L8a`Xascwc34mu^uBm3wexG#S2pp{+<=NYNet! z1gi{3wYdV{wNh~;WbxMGdtL0)A%ZwYOUb3tD|ZQ!j1H{o%; z_n=!DWsyw-=dA@Ys*>S;fyKcb%)uPY!5qxN9L&KS%)uPY!5l1D`~ovRT>h7Cr91!t N002ovPDHLkV1m`E9+3b5 literal 0 HcmV?d00001 diff --git a/res/drawable-xxxhdpi/ic_photo_camera_dark.png b/res/drawable-xxxhdpi/ic_photo_camera_dark.png new file mode 100644 index 0000000000000000000000000000000000000000..23a9c2efd07537d261952851094d5dbc47b2f753 GIT binary patch literal 1504 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 - + + + + + + + diff --git a/res/values/attrs.xml b/res/values/attrs.xml index 4676554e84..0d81e30bc2 100644 --- a/res/values/attrs.xml +++ b/res/values/attrs.xml @@ -37,6 +37,7 @@ + diff --git a/res/values/strings.xml b/res/values/strings.xml index e03e974f0e..098e948456 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -50,6 +50,7 @@ Can\'t find an app to select media. + Take Photo Picture Video Audio diff --git a/res/values/themes.xml b/res/values/themes.xml index b2af44d0ff..aa6eb50b24 100644 --- a/res/values/themes.xml +++ b/res/values/themes.xml @@ -53,6 +53,7 @@ @drawable/ic_movie_creation_light @drawable/ic_volume_up_light @drawable/ic_account_box_light + @drawable/ic_photo_camera_light @drawable/conversation_item_background @color/conversation_item_received_background_light @@ -188,6 +189,7 @@ @drawable/ic_movie_creation_dark @drawable/ic_volume_up_dark @drawable/ic_account_box_dark + @drawable/ic_photo_camera_dark @drawable/ic_add_white_24dp @drawable/ic_group_white_24dp diff --git a/src/org/thoughtcrime/securesms/ConversationActivity.java b/src/org/thoughtcrime/securesms/ConversationActivity.java index e4999e15e3..11ddd2618e 100644 --- a/src/org/thoughtcrime/securesms/ConversationActivity.java +++ b/src/org/thoughtcrime/securesms/ConversationActivity.java @@ -24,7 +24,6 @@ import android.content.Intent; import android.content.IntentFilter; import android.net.Uri; import android.os.AsyncTask; -import android.os.Build; import android.os.Bundle; import android.provider.ContactsContract; import android.support.annotation.NonNull; @@ -44,6 +43,7 @@ import android.view.View.OnFocusChangeListener; import android.view.View.OnKeyListener; import android.view.inputmethod.EditorInfo; import android.view.inputmethod.InputMethodManager; +import android.widget.ImageButton; import android.widget.TextView; import android.widget.Toast; @@ -51,9 +51,9 @@ import com.afollestad.materialdialogs.AlertDialogWrapper; import com.google.protobuf.ByteString; import org.thoughtcrime.securesms.TransportOptions.OnTransportChangedListener; +import org.thoughtcrime.securesms.components.AnimatingToggle; import org.thoughtcrime.securesms.components.ComposeText; import org.thoughtcrime.securesms.components.emoji.EmojiDrawer; -import org.thoughtcrime.securesms.components.emoji.EmojiProvider; import org.thoughtcrime.securesms.components.emoji.EmojiToggle; import org.thoughtcrime.securesms.components.SendButton; import org.thoughtcrime.securesms.contacts.ContactAccessor; @@ -136,10 +136,13 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity private static final int PICK_AUDIO = 3; private static final int PICK_CONTACT_INFO = 4; private static final int GROUP_EDIT = 5; + private static final int CAPTURE_PHOTO = 6; private MasterSecret masterSecret; private ComposeText composeText; + private AnimatingToggle buttonToggle; private SendButton sendButton; + private ImageButton attachButton; private TextView charactersLeft; private ConversationFragment fragment; @@ -237,7 +240,8 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity Log.w(TAG, "onActivityResult called: " + reqCode + ", " + resultCode + " , " + data); super.onActivityResult(reqCode, resultCode, data); - if (data == null || resultCode != RESULT_OK) return; + if ((data == null && reqCode != CAPTURE_PHOTO) || resultCode != RESULT_OK) return; + switch (reqCode) { case PICK_IMAGE: addAttachmentImage(data.getData()); @@ -251,6 +255,11 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity case PICK_CONTACT_INFO: addAttachmentContactInfo(data.getData()); break; + case CAPTURE_PHOTO: + if (attachmentManager.getCaptureFile() != null) { + addAttachmentImage(Uri.fromFile(attachmentManager.getCaptureFile())); + } + break; case GROUP_EDIT: this.recipients = RecipientFactory.getRecipientsForIds(this, data.getLongArrayExtra(GroupCreateActivity.GROUP_RECIPIENT_EXTRA), true); initializeTitleBar(); @@ -596,6 +605,8 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity if (draftText == null && draftImage == null && draftAudio == null && draftVideo == null) { initializeDraftFromDatabase(); + } else { + updateToggleButtonState(); } } @@ -631,6 +642,8 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity addAttachmentVideo(Uri.parse(draft.getValue())); } } + + updateToggleButtonState(); } }.execute(); } @@ -675,7 +688,9 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity } private void initializeViews() { + buttonToggle = (AnimatingToggle)findViewById(R.id.button_toggle); sendButton = (SendButton) findViewById(R.id.send_button); + attachButton = (ImageButton) findViewById(R.id.attach_button); composeText = (ComposeText) findViewById(R.id.embedded_text_editor); charactersLeft = (TextView) findViewById(R.id.space_left); emojiDrawer = Optional.absent(); @@ -687,6 +702,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity SendButtonListener sendButtonListener = new SendButtonListener(); ComposeKeyPressedListener composeKeyPressedListener = new ComposeKeyPressedListener(); + attachButton.setOnClickListener(new AttachButtonListener()); sendButton.setOnClickListener(sendButtonListener); sendButton.setEnabled(true); sendButton.addOnTransportChangedListener(new OnTransportChangedListener() { @@ -775,6 +791,8 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity private void addAttachment(int type) { Log.w("ComposeMessageActivity", "Selected: " + type); switch (type) { + case AttachmentTypeSelectorAdapter.TAKE_PHOTO: + attachmentManager.capturePhoto(this, CAPTURE_PHOTO); break; case AttachmentTypeSelectorAdapter.ADD_IMAGE: AttachmentManager.selectImage(this, PICK_IMAGE); break; case AttachmentTypeSelectorAdapter.ADD_VIDEO: @@ -989,6 +1007,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity } fragment.scrollToBottom(); + attachmentManager.cleanup(); } private void sendMessage() { @@ -1081,6 +1100,13 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity }.execute(message); } + private void updateToggleButtonState() { + if (composeText.getText().length() == 0 && !attachmentManager.isAttachmentPresent()) { + buttonToggle.display(attachButton); + } else { + buttonToggle.display(sendButton); + } + } // Listeners @@ -1124,7 +1150,17 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity } } + private class AttachButtonListener implements OnClickListener { + @Override + public void onClick(View v) { + handleAddAttachment(); + } + } + private class ComposeKeyPressedListener implements OnKeyListener, OnClickListener, TextWatcher, OnFocusChangeListener { + + int beforeLength; + @Override public boolean onKey(View v, int keyCode, KeyEvent event) { if (event.getAction() == KeyEvent.ACTION_DOWN) { @@ -1146,12 +1182,20 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity } } + @Override + public void beforeTextChanged(CharSequence s, int start, int count,int after) { + beforeLength = composeText.getText().length(); + } + @Override public void afterTextChanged(Editable s) { calculateCharactersRemaining(); + + if (composeText.getText().length() == 0 || beforeLength == 0) { + updateToggleButtonState(); + } } - @Override - public void beforeTextChanged(CharSequence s, int start, int count,int after) {} + @Override public void onTextChanged(CharSequence s, int start, int before,int count) {} @@ -1176,5 +1220,6 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity @Override public void onAttachmentChanged() { initializeSecurity(); + updateToggleButtonState(); } } diff --git a/src/org/thoughtcrime/securesms/components/AnimatingToggle.java b/src/org/thoughtcrime/securesms/components/AnimatingToggle.java new file mode 100644 index 0000000000..e88808ef8d --- /dev/null +++ b/src/org/thoughtcrime/securesms/components/AnimatingToggle.java @@ -0,0 +1,108 @@ +package org.thoughtcrime.securesms.components; + +import android.content.Context; +import android.support.annotation.NonNull; +import android.util.AttributeSet; +import android.view.View; +import android.view.ViewGroup; +import android.view.animation.Animation; +import android.view.animation.TranslateAnimation; +import android.widget.FrameLayout; + +public class AnimatingToggle extends FrameLayout { + + private static final int SPEED_MILLIS = 200; + + public AnimatingToggle(Context context) { + super(context); + } + + public AnimatingToggle(Context context, AttributeSet attrs) { + super(context, attrs); + } + + public AnimatingToggle(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + } + + @Override + public void addView(@NonNull View child, int index, ViewGroup.LayoutParams params) { + super.addView(child, index, params); + + if (getChildCount() == 1) child.setVisibility(View.VISIBLE); + else child.setVisibility(View.GONE); + } + + public void display(View view) { + if (view.getVisibility() == View.VISIBLE) return; + + int oldViewIndex = getVisibleViewIndex(); + int newViewIndex = getViewIndex(view); + + int sign; + + if (oldViewIndex < newViewIndex) sign = -1; + else sign = 1; + + TranslateAnimation oldViewAnimation = createTranslation(0.0f, sign * 1.0f); + TranslateAnimation newViewAnimation = createTranslation(sign * -1.0f, 0.0f); + + animateOut(oldViewIndex, oldViewAnimation); + animateIn(newViewIndex, newViewAnimation); + } + + private void animateOut(int viewIndex, TranslateAnimation animation) { + final View view = getChildAt(viewIndex); + + 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(int viewIndex, TranslateAnimation animation) { + final View view = getChildAt(viewIndex); + view.setVisibility(View.VISIBLE); + view.startAnimation(animation); + } + + private int getVisibleViewIndex() { + for (int i=0;i getItemList(Context context) { List data = new ArrayList<>(4); - addItem(data, context.getString(R.string.AttachmentTypeSelectorAdapter_picture), ResUtil.getDrawableRes(context, R.attr.conversation_attach_image), ADD_IMAGE); - addItem(data, context.getString(R.string.AttachmentTypeSelectorAdapter_video), ResUtil.getDrawableRes(context, R.attr.conversation_attach_video), ADD_VIDEO); - addItem(data, context.getString(R.string.AttachmentTypeSelectorAdapter_audio), ResUtil.getDrawableRes(context, R.attr.conversation_attach_sound), ADD_SOUND); - addItem(data, context.getString(R.string.AttachmentTypeSelectorAdapter_contact), ResUtil.getDrawableRes(context, R.attr.conversation_attach_contact_info), ADD_CONTACT_INFO); + addItem(data, context.getString(R.string.AttachmentTypeSelectorAdapter_take_photo), ResUtil.getDrawableRes(context, R.attr.conversation_attach_photo), TAKE_PHOTO); + addItem(data, context.getString(R.string.AttachmentTypeSelectorAdapter_picture), ResUtil.getDrawableRes(context, R.attr.conversation_attach_image), ADD_IMAGE); + addItem(data, context.getString(R.string.AttachmentTypeSelectorAdapter_video), ResUtil.getDrawableRes(context, R.attr.conversation_attach_video), ADD_VIDEO); + addItem(data, context.getString(R.string.AttachmentTypeSelectorAdapter_audio), ResUtil.getDrawableRes(context, R.attr.conversation_attach_sound), ADD_SOUND); + addItem(data, context.getString(R.string.AttachmentTypeSelectorAdapter_contact), ResUtil.getDrawableRes(context, R.attr.conversation_attach_contact_info), ADD_CONTACT_INFO); return data; }