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
BIN
res/drawable-hdpi/ic_photo_camera_dark.png
Normal file
After Width: | Height: | Size: 636 B |
BIN
res/drawable-hdpi/ic_photo_camera_light.png
Normal file
After Width: | Height: | Size: 653 B |
BIN
res/drawable-mdpi/ic_photo_camera_dark.png
Normal file
After Width: | Height: | Size: 457 B |
BIN
res/drawable-mdpi/ic_photo_camera_light.png
Normal file
After Width: | Height: | Size: 469 B |
BIN
res/drawable-xhdpi/ic_photo_camera_dark.png
Normal file
After Width: | Height: | Size: 781 B |
BIN
res/drawable-xhdpi/ic_photo_camera_light.png
Normal file
After Width: | Height: | Size: 795 B |
BIN
res/drawable-xxhdpi/ic_photo_camera_dark.png
Normal file
After Width: | Height: | Size: 1.1 KiB |
BIN
res/drawable-xxhdpi/ic_photo_camera_light.png
Normal file
After Width: | Height: | Size: 1.1 KiB |
BIN
res/drawable-xxxhdpi/ic_photo_camera_dark.png
Normal file
After Width: | Height: | Size: 1.5 KiB |
BIN
res/drawable-xxxhdpi/ic_photo_camera_light.png
Normal file
After Width: | Height: | Size: 1.8 KiB |
@ -97,19 +97,37 @@
|
|||||||
android:contentDescription="@string/conversation_activity__compose_description"
|
android:contentDescription="@string/conversation_activity__compose_description"
|
||||||
android:textColor="?conversation_editor_text_color" />
|
android:textColor="?conversation_editor_text_color" />
|
||||||
|
|
||||||
<org.thoughtcrime.securesms.components.SendButton
|
<org.thoughtcrime.securesms.components.AnimatingToggle
|
||||||
android:id="@+id/send_button"
|
android:id="@+id/button_toggle"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="fill_parent"
|
android:layout_height="wrap_content">
|
||||||
android:layout_gravity="center_vertical"
|
|
||||||
android:background="@drawable/touch_highlight_background"
|
<ImageButton
|
||||||
android:contentDescription="@string/conversation_activity__send"
|
android:id="@+id/attach_button"
|
||||||
android:nextFocusLeft="@+id/embedded_text_editor"
|
android:layout_gravity="center_vertical"
|
||||||
android:padding="12dp"
|
android:background="@drawable/touch_highlight_background"
|
||||||
android:src="?conversation_transport_sms_indicator"
|
android:padding="12dp"
|
||||||
android:focusable="true"
|
android:src="?conversation_attach_file"
|
||||||
android:clickable="false"
|
android:contentDescription="@string/ConversationActivity_add_attachment"
|
||||||
android:enabled="false" />
|
android:nextFocusLeft="@+id/embedded_text_editor"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="fill_parent"/>
|
||||||
|
|
||||||
|
<org.thoughtcrime.securesms.components.SendButton
|
||||||
|
android:id="@+id/send_button"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="fill_parent"
|
||||||
|
android:layout_gravity="center_vertical"
|
||||||
|
android:background="@drawable/touch_highlight_background"
|
||||||
|
android:contentDescription="@string/conversation_activity__send"
|
||||||
|
android:nextFocusLeft="@+id/embedded_text_editor"
|
||||||
|
android:padding="12dp"
|
||||||
|
android:src="?conversation_transport_sms_indicator"
|
||||||
|
android:focusable="true"
|
||||||
|
android:clickable="false"
|
||||||
|
android:enabled="false" />
|
||||||
|
|
||||||
|
</org.thoughtcrime.securesms.components.AnimatingToggle>
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
|
@ -37,6 +37,7 @@
|
|||||||
<attr name="conversation_attach_video" format="reference"/>
|
<attr name="conversation_attach_video" format="reference"/>
|
||||||
<attr name="conversation_attach_sound" format="reference"/>
|
<attr name="conversation_attach_sound" format="reference"/>
|
||||||
<attr name="conversation_attach_contact_info" format="reference"/>
|
<attr name="conversation_attach_contact_info" format="reference"/>
|
||||||
|
<attr name="conversation_attach_photo" format="reference"/>
|
||||||
|
|
||||||
<attr name="conversation_item_background" format="reference"/>
|
<attr name="conversation_item_background" format="reference"/>
|
||||||
<attr name="conversation_item_received_background" format="reference" />
|
<attr name="conversation_item_received_background" format="reference" />
|
||||||
|
@ -50,6 +50,7 @@
|
|||||||
<string name="AttachmentManager_cant_open_media_selection">Can\'t find an app to select media.</string>
|
<string name="AttachmentManager_cant_open_media_selection">Can\'t find an app to select media.</string>
|
||||||
|
|
||||||
<!-- AttachmentTypeSelectorAdapter -->
|
<!-- AttachmentTypeSelectorAdapter -->
|
||||||
|
<string name="AttachmentTypeSelectorAdapter_take_photo">Take Photo</string>
|
||||||
<string name="AttachmentTypeSelectorAdapter_picture">Picture</string>
|
<string name="AttachmentTypeSelectorAdapter_picture">Picture</string>
|
||||||
<string name="AttachmentTypeSelectorAdapter_video">Video</string>
|
<string name="AttachmentTypeSelectorAdapter_video">Video</string>
|
||||||
<string name="AttachmentTypeSelectorAdapter_audio">Audio</string>
|
<string name="AttachmentTypeSelectorAdapter_audio">Audio</string>
|
||||||
|
@ -53,6 +53,7 @@
|
|||||||
<item name="conversation_attach_video">@drawable/ic_movie_creation_light</item>
|
<item name="conversation_attach_video">@drawable/ic_movie_creation_light</item>
|
||||||
<item name="conversation_attach_sound">@drawable/ic_volume_up_light</item>
|
<item name="conversation_attach_sound">@drawable/ic_volume_up_light</item>
|
||||||
<item name="conversation_attach_contact_info">@drawable/ic_account_box_light</item>
|
<item name="conversation_attach_contact_info">@drawable/ic_account_box_light</item>
|
||||||
|
<item name="conversation_attach_photo">@drawable/ic_photo_camera_light</item>
|
||||||
|
|
||||||
<item name="conversation_item_background">@drawable/conversation_item_background</item>
|
<item name="conversation_item_background">@drawable/conversation_item_background</item>
|
||||||
<item name="conversation_item_received_background">@color/conversation_item_received_background_light</item>
|
<item name="conversation_item_received_background">@color/conversation_item_received_background_light</item>
|
||||||
@ -188,6 +189,7 @@
|
|||||||
<item name="conversation_attach_video">@drawable/ic_movie_creation_dark</item>
|
<item name="conversation_attach_video">@drawable/ic_movie_creation_dark</item>
|
||||||
<item name="conversation_attach_sound">@drawable/ic_volume_up_dark</item>
|
<item name="conversation_attach_sound">@drawable/ic_volume_up_dark</item>
|
||||||
<item name="conversation_attach_contact_info">@drawable/ic_account_box_dark</item>
|
<item name="conversation_attach_contact_info">@drawable/ic_account_box_dark</item>
|
||||||
|
<item name="conversation_attach_photo">@drawable/ic_photo_camera_dark</item>
|
||||||
|
|
||||||
<item name="menu_new_conversation_icon">@drawable/ic_add_white_24dp</item>
|
<item name="menu_new_conversation_icon">@drawable/ic_add_white_24dp</item>
|
||||||
<item name="menu_group_icon">@drawable/ic_group_white_24dp</item>
|
<item name="menu_group_icon">@drawable/ic_group_white_24dp</item>
|
||||||
|
@ -24,7 +24,6 @@ import android.content.Intent;
|
|||||||
import android.content.IntentFilter;
|
import android.content.IntentFilter;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.AsyncTask;
|
import android.os.AsyncTask;
|
||||||
import android.os.Build;
|
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.provider.ContactsContract;
|
import android.provider.ContactsContract;
|
||||||
import android.support.annotation.NonNull;
|
import android.support.annotation.NonNull;
|
||||||
@ -44,6 +43,7 @@ import android.view.View.OnFocusChangeListener;
|
|||||||
import android.view.View.OnKeyListener;
|
import android.view.View.OnKeyListener;
|
||||||
import android.view.inputmethod.EditorInfo;
|
import android.view.inputmethod.EditorInfo;
|
||||||
import android.view.inputmethod.InputMethodManager;
|
import android.view.inputmethod.InputMethodManager;
|
||||||
|
import android.widget.ImageButton;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
@ -51,9 +51,9 @@ import com.afollestad.materialdialogs.AlertDialogWrapper;
|
|||||||
import com.google.protobuf.ByteString;
|
import com.google.protobuf.ByteString;
|
||||||
|
|
||||||
import org.thoughtcrime.securesms.TransportOptions.OnTransportChangedListener;
|
import org.thoughtcrime.securesms.TransportOptions.OnTransportChangedListener;
|
||||||
|
import org.thoughtcrime.securesms.components.AnimatingToggle;
|
||||||
import org.thoughtcrime.securesms.components.ComposeText;
|
import org.thoughtcrime.securesms.components.ComposeText;
|
||||||
import org.thoughtcrime.securesms.components.emoji.EmojiDrawer;
|
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.emoji.EmojiToggle;
|
||||||
import org.thoughtcrime.securesms.components.SendButton;
|
import org.thoughtcrime.securesms.components.SendButton;
|
||||||
import org.thoughtcrime.securesms.contacts.ContactAccessor;
|
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_AUDIO = 3;
|
||||||
private static final int PICK_CONTACT_INFO = 4;
|
private static final int PICK_CONTACT_INFO = 4;
|
||||||
private static final int GROUP_EDIT = 5;
|
private static final int GROUP_EDIT = 5;
|
||||||
|
private static final int CAPTURE_PHOTO = 6;
|
||||||
|
|
||||||
private MasterSecret masterSecret;
|
private MasterSecret masterSecret;
|
||||||
private ComposeText composeText;
|
private ComposeText composeText;
|
||||||
|
private AnimatingToggle buttonToggle;
|
||||||
private SendButton sendButton;
|
private SendButton sendButton;
|
||||||
|
private ImageButton attachButton;
|
||||||
private TextView charactersLeft;
|
private TextView charactersLeft;
|
||||||
private ConversationFragment fragment;
|
private ConversationFragment fragment;
|
||||||
|
|
||||||
@ -237,7 +240,8 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
|||||||
Log.w(TAG, "onActivityResult called: " + reqCode + ", " + resultCode + " , " + data);
|
Log.w(TAG, "onActivityResult called: " + reqCode + ", " + resultCode + " , " + data);
|
||||||
super.onActivityResult(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) {
|
switch (reqCode) {
|
||||||
case PICK_IMAGE:
|
case PICK_IMAGE:
|
||||||
addAttachmentImage(data.getData());
|
addAttachmentImage(data.getData());
|
||||||
@ -251,6 +255,11 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
|||||||
case PICK_CONTACT_INFO:
|
case PICK_CONTACT_INFO:
|
||||||
addAttachmentContactInfo(data.getData());
|
addAttachmentContactInfo(data.getData());
|
||||||
break;
|
break;
|
||||||
|
case CAPTURE_PHOTO:
|
||||||
|
if (attachmentManager.getCaptureFile() != null) {
|
||||||
|
addAttachmentImage(Uri.fromFile(attachmentManager.getCaptureFile()));
|
||||||
|
}
|
||||||
|
break;
|
||||||
case GROUP_EDIT:
|
case GROUP_EDIT:
|
||||||
this.recipients = RecipientFactory.getRecipientsForIds(this, data.getLongArrayExtra(GroupCreateActivity.GROUP_RECIPIENT_EXTRA), true);
|
this.recipients = RecipientFactory.getRecipientsForIds(this, data.getLongArrayExtra(GroupCreateActivity.GROUP_RECIPIENT_EXTRA), true);
|
||||||
initializeTitleBar();
|
initializeTitleBar();
|
||||||
@ -596,6 +605,8 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
|||||||
|
|
||||||
if (draftText == null && draftImage == null && draftAudio == null && draftVideo == null) {
|
if (draftText == null && draftImage == null && draftAudio == null && draftVideo == null) {
|
||||||
initializeDraftFromDatabase();
|
initializeDraftFromDatabase();
|
||||||
|
} else {
|
||||||
|
updateToggleButtonState();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -631,6 +642,8 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
|||||||
addAttachmentVideo(Uri.parse(draft.getValue()));
|
addAttachmentVideo(Uri.parse(draft.getValue()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
updateToggleButtonState();
|
||||||
}
|
}
|
||||||
}.execute();
|
}.execute();
|
||||||
}
|
}
|
||||||
@ -675,7 +688,9 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void initializeViews() {
|
private void initializeViews() {
|
||||||
|
buttonToggle = (AnimatingToggle)findViewById(R.id.button_toggle);
|
||||||
sendButton = (SendButton) findViewById(R.id.send_button);
|
sendButton = (SendButton) findViewById(R.id.send_button);
|
||||||
|
attachButton = (ImageButton) findViewById(R.id.attach_button);
|
||||||
composeText = (ComposeText) findViewById(R.id.embedded_text_editor);
|
composeText = (ComposeText) findViewById(R.id.embedded_text_editor);
|
||||||
charactersLeft = (TextView) findViewById(R.id.space_left);
|
charactersLeft = (TextView) findViewById(R.id.space_left);
|
||||||
emojiDrawer = Optional.absent();
|
emojiDrawer = Optional.absent();
|
||||||
@ -687,6 +702,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
|||||||
SendButtonListener sendButtonListener = new SendButtonListener();
|
SendButtonListener sendButtonListener = new SendButtonListener();
|
||||||
ComposeKeyPressedListener composeKeyPressedListener = new ComposeKeyPressedListener();
|
ComposeKeyPressedListener composeKeyPressedListener = new ComposeKeyPressedListener();
|
||||||
|
|
||||||
|
attachButton.setOnClickListener(new AttachButtonListener());
|
||||||
sendButton.setOnClickListener(sendButtonListener);
|
sendButton.setOnClickListener(sendButtonListener);
|
||||||
sendButton.setEnabled(true);
|
sendButton.setEnabled(true);
|
||||||
sendButton.addOnTransportChangedListener(new OnTransportChangedListener() {
|
sendButton.addOnTransportChangedListener(new OnTransportChangedListener() {
|
||||||
@ -775,6 +791,8 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
|||||||
private void addAttachment(int type) {
|
private void addAttachment(int type) {
|
||||||
Log.w("ComposeMessageActivity", "Selected: " + type);
|
Log.w("ComposeMessageActivity", "Selected: " + type);
|
||||||
switch (type) {
|
switch (type) {
|
||||||
|
case AttachmentTypeSelectorAdapter.TAKE_PHOTO:
|
||||||
|
attachmentManager.capturePhoto(this, CAPTURE_PHOTO); break;
|
||||||
case AttachmentTypeSelectorAdapter.ADD_IMAGE:
|
case AttachmentTypeSelectorAdapter.ADD_IMAGE:
|
||||||
AttachmentManager.selectImage(this, PICK_IMAGE); break;
|
AttachmentManager.selectImage(this, PICK_IMAGE); break;
|
||||||
case AttachmentTypeSelectorAdapter.ADD_VIDEO:
|
case AttachmentTypeSelectorAdapter.ADD_VIDEO:
|
||||||
@ -989,6 +1007,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
|||||||
}
|
}
|
||||||
|
|
||||||
fragment.scrollToBottom();
|
fragment.scrollToBottom();
|
||||||
|
attachmentManager.cleanup();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void sendMessage() {
|
private void sendMessage() {
|
||||||
@ -1081,6 +1100,13 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
|||||||
}.execute(message);
|
}.execute(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void updateToggleButtonState() {
|
||||||
|
if (composeText.getText().length() == 0 && !attachmentManager.isAttachmentPresent()) {
|
||||||
|
buttonToggle.display(attachButton);
|
||||||
|
} else {
|
||||||
|
buttonToggle.display(sendButton);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Listeners
|
// 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 {
|
private class ComposeKeyPressedListener implements OnKeyListener, OnClickListener, TextWatcher, OnFocusChangeListener {
|
||||||
|
|
||||||
|
int beforeLength;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onKey(View v, int keyCode, KeyEvent event) {
|
public boolean onKey(View v, int keyCode, KeyEvent event) {
|
||||||
if (event.getAction() == KeyEvent.ACTION_DOWN) {
|
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
|
@Override
|
||||||
public void afterTextChanged(Editable s) {
|
public void afterTextChanged(Editable s) {
|
||||||
calculateCharactersRemaining();
|
calculateCharactersRemaining();
|
||||||
|
|
||||||
|
if (composeText.getText().length() == 0 || beforeLength == 0) {
|
||||||
|
updateToggleButtonState();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@Override
|
|
||||||
public void beforeTextChanged(CharSequence s, int start, int count,int after) {}
|
|
||||||
@Override
|
@Override
|
||||||
public void onTextChanged(CharSequence s, int start, int before,int count) {}
|
public void onTextChanged(CharSequence s, int start, int before,int count) {}
|
||||||
|
|
||||||
@ -1176,5 +1220,6 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
|||||||
@Override
|
@Override
|
||||||
public void onAttachmentChanged() {
|
public void onAttachmentChanged() {
|
||||||
initializeSecurity();
|
initializeSecurity();
|
||||||
|
updateToggleButtonState();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
108
src/org/thoughtcrime/securesms/components/AnimatingToggle.java
Normal file
@ -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<getChildCount();i++) {
|
||||||
|
if (getChildAt(i).getVisibility() == View.VISIBLE) return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new AssertionError("No visible view?");
|
||||||
|
}
|
||||||
|
|
||||||
|
private int getViewIndex(View view) {
|
||||||
|
for (int i=0;i<getChildCount();i++) {
|
||||||
|
if (getChildAt(i) == view) return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new IllegalArgumentException("Not a parent of this view.");
|
||||||
|
}
|
||||||
|
|
||||||
|
private TranslateAnimation createTranslation(float startY, float endY) {
|
||||||
|
TranslateAnimation translateAnimation = new TranslateAnimation(Animation.RELATIVE_TO_SELF, 0.0f,
|
||||||
|
Animation.RELATIVE_TO_SELF, 0.0f,
|
||||||
|
Animation.RELATIVE_TO_SELF, startY,
|
||||||
|
Animation.RELATIVE_TO_SELF, endY);
|
||||||
|
|
||||||
|
translateAnimation.setDuration(SPEED_MILLIS);
|
||||||
|
|
||||||
|
return translateAnimation;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -23,6 +23,7 @@ import android.content.Intent;
|
|||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.provider.ContactsContract;
|
import android.provider.ContactsContract;
|
||||||
|
import android.provider.MediaStore;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.widget.Button;
|
import android.widget.Button;
|
||||||
@ -32,20 +33,23 @@ import org.thoughtcrime.securesms.R;
|
|||||||
import org.thoughtcrime.securesms.components.ThumbnailView;
|
import org.thoughtcrime.securesms.components.ThumbnailView;
|
||||||
import org.thoughtcrime.securesms.util.BitmapDecodingException;
|
import org.thoughtcrime.securesms.util.BitmapDecodingException;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
public class AttachmentManager {
|
public class AttachmentManager {
|
||||||
private final static String TAG = AttachmentManager.class.getSimpleName();
|
private final static String TAG = AttachmentManager.class.getSimpleName();
|
||||||
|
|
||||||
private final Context context;
|
private final Context context;
|
||||||
private final View attachmentView;
|
private final View attachmentView;
|
||||||
private final ThumbnailView thumbnail;
|
private final ThumbnailView thumbnail;
|
||||||
private final Button removeButton;
|
private final Button removeButton;
|
||||||
private final SlideDeck slideDeck;
|
private final SlideDeck slideDeck;
|
||||||
private final AttachmentListener attachmentListener;
|
private final AttachmentListener attachmentListener;
|
||||||
|
|
||||||
|
private File captureFile;
|
||||||
|
|
||||||
public AttachmentManager(Activity view, AttachmentListener listener) {
|
public AttachmentManager(Activity view, AttachmentListener listener) {
|
||||||
this.attachmentView = (View)view.findViewById(R.id.attachment_editor);
|
this.attachmentView = view.findViewById(R.id.attachment_editor);
|
||||||
this.thumbnail = (ThumbnailView)view.findViewById(R.id.attachment_thumbnail);
|
this.thumbnail = (ThumbnailView)view.findViewById(R.id.attachment_thumbnail);
|
||||||
this.removeButton = (Button)view.findViewById(R.id.remove_image_button);
|
this.removeButton = (Button)view.findViewById(R.id.remove_image_button);
|
||||||
this.slideDeck = new SlideDeck();
|
this.slideDeck = new SlideDeck();
|
||||||
@ -61,6 +65,11 @@ public class AttachmentManager {
|
|||||||
attachmentListener.onAttachmentChanged();
|
attachmentListener.onAttachmentChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void cleanup() {
|
||||||
|
if (captureFile != null) captureFile.delete();
|
||||||
|
captureFile = null;
|
||||||
|
}
|
||||||
|
|
||||||
public void setImage(Uri image) throws IOException, BitmapDecodingException {
|
public void setImage(Uri image) throws IOException, BitmapDecodingException {
|
||||||
setMedia(new ImageSlide(context, image));
|
setMedia(new ImageSlide(context, image));
|
||||||
}
|
}
|
||||||
@ -78,6 +87,7 @@ public class AttachmentManager {
|
|||||||
slideDeck.addSlide(slide);
|
slideDeck.addSlide(slide);
|
||||||
attachmentView.setVisibility(View.VISIBLE);
|
attachmentView.setVisibility(View.VISIBLE);
|
||||||
thumbnail.setImageResource(slide);
|
thumbnail.setImageResource(slide);
|
||||||
|
attachmentListener.onAttachmentChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isAttachmentPresent() {
|
public boolean isAttachmentPresent() {
|
||||||
@ -88,6 +98,24 @@ public class AttachmentManager {
|
|||||||
return slideDeck;
|
return slideDeck;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public File getCaptureFile() {
|
||||||
|
return captureFile;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void capturePhoto(Activity activity, int requestCode) {
|
||||||
|
try {
|
||||||
|
Intent captureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
|
||||||
|
|
||||||
|
if (captureIntent.resolveActivity(activity.getPackageManager()) != null) {
|
||||||
|
captureFile = File.createTempFile(String.valueOf(System.currentTimeMillis()), ".jpg", activity.getExternalFilesDir(null));
|
||||||
|
captureIntent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(captureFile));
|
||||||
|
activity.startActivityForResult(captureIntent, requestCode);
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
Log.w(TAG, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static void selectVideo(Activity activity, int requestCode) {
|
public static void selectVideo(Activity activity, int requestCode) {
|
||||||
selectMediaType(activity, "video/*", requestCode);
|
selectMediaType(activity, "video/*", requestCode);
|
||||||
}
|
}
|
||||||
@ -132,6 +160,7 @@ public class AttachmentManager {
|
|||||||
@Override
|
@Override
|
||||||
public void onClick(View v) {
|
public void onClick(View v) {
|
||||||
clear();
|
clear();
|
||||||
|
cleanup();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -37,6 +37,7 @@ public class AttachmentTypeSelectorAdapter extends ArrayAdapter<AttachmentTypeSe
|
|||||||
public static final int ADD_VIDEO = 2;
|
public static final int ADD_VIDEO = 2;
|
||||||
public static final int ADD_SOUND = 3;
|
public static final int ADD_SOUND = 3;
|
||||||
public static final int ADD_CONTACT_INFO = 4;
|
public static final int ADD_CONTACT_INFO = 4;
|
||||||
|
public static final int TAKE_PHOTO = 5;
|
||||||
|
|
||||||
private final Context context;
|
private final Context context;
|
||||||
|
|
||||||
@ -71,10 +72,11 @@ public class AttachmentTypeSelectorAdapter extends ArrayAdapter<AttachmentTypeSe
|
|||||||
|
|
||||||
private static List<IconListItem> getItemList(Context context) {
|
private static List<IconListItem> getItemList(Context context) {
|
||||||
List<IconListItem> data = new ArrayList<>(4);
|
List<IconListItem> 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_take_photo), ResUtil.getDrawableRes(context, R.attr.conversation_attach_photo), TAKE_PHOTO);
|
||||||
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_picture), ResUtil.getDrawableRes(context, R.attr.conversation_attach_image), ADD_IMAGE);
|
||||||
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_video), ResUtil.getDrawableRes(context, R.attr.conversation_attach_video), ADD_VIDEO);
|
||||||
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_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;
|
return data;
|
||||||
}
|
}
|
||||||
|