BIN
res/drawable-hdpi/ic_camera_white_36dp.png
Normal file
After Width: | Height: | Size: 1009 B |
BIN
res/drawable-hdpi/ic_headset_white_36dp.png
Normal file
After Width: | Height: | Size: 683 B |
BIN
res/drawable-hdpi/ic_image_white_36dp.png
Normal file
After Width: | Height: | Size: 474 B |
BIN
res/drawable-hdpi/ic_local_movies_white_36dp.png
Normal file
After Width: | Height: | Size: 259 B |
BIN
res/drawable-hdpi/ic_person_white_36dp.png
Normal file
After Width: | Height: | Size: 460 B |
BIN
res/drawable-mdpi/ic_camera_white_36dp.png
Normal file
After Width: | Height: | Size: 705 B |
BIN
res/drawable-mdpi/ic_headset_white_36dp.png
Normal file
After Width: | Height: | Size: 457 B |
BIN
res/drawable-mdpi/ic_image_white_36dp.png
Normal file
After Width: | Height: | Size: 351 B |
BIN
res/drawable-mdpi/ic_local_movies_white_36dp.png
Normal file
After Width: | Height: | Size: 215 B |
BIN
res/drawable-mdpi/ic_person_white_36dp.png
Normal file
After Width: | Height: | Size: 360 B |
BIN
res/drawable-xhdpi/ic_camera_white_36dp.png
Normal file
After Width: | Height: | Size: 1.2 KiB |
BIN
res/drawable-xhdpi/ic_headset_white_36dp.png
Normal file
After Width: | Height: | Size: 797 B |
BIN
res/drawable-xhdpi/ic_image_white_36dp.png
Normal file
After Width: | Height: | Size: 614 B |
BIN
res/drawable-xhdpi/ic_local_movies_white_36dp.png
Normal file
After Width: | Height: | Size: 231 B |
BIN
res/drawable-xhdpi/ic_person_white_36dp.png
Normal file
After Width: | Height: | Size: 548 B |
BIN
res/drawable-xxhdpi/ic_camera_white_36dp.png
Normal file
After Width: | Height: | Size: 1.9 KiB |
BIN
res/drawable-xxhdpi/ic_headset_white_36dp.png
Normal file
After Width: | Height: | Size: 1.2 KiB |
BIN
res/drawable-xxhdpi/ic_image_white_36dp.png
Normal file
After Width: | Height: | Size: 938 B |
BIN
res/drawable-xxhdpi/ic_local_movies_white_36dp.png
Normal file
After Width: | Height: | Size: 334 B |
BIN
res/drawable-xxhdpi/ic_person_white_36dp.png
Normal file
After Width: | Height: | Size: 974 B |
BIN
res/drawable-xxxhdpi/ic_camera_white_36dp.png
Normal file
After Width: | Height: | Size: 2.5 KiB |
BIN
res/drawable-xxxhdpi/ic_headset_white_36dp.png
Normal file
After Width: | Height: | Size: 1.6 KiB |
BIN
res/drawable-xxxhdpi/ic_image_white_36dp.png
Normal file
After Width: | Height: | Size: 1.2 KiB |
BIN
res/drawable-xxxhdpi/ic_local_movies_white_36dp.png
Normal file
After Width: | Height: | Size: 374 B |
BIN
res/drawable-xxxhdpi/ic_person_white_36dp.png
Normal file
After Width: | Height: | Size: 1.0 KiB |
171
res/layout/attachment_type_selector.xml
Normal file
@ -0,0 +1,171 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:background="?attachment_type_selector_background"
|
||||||
|
android:elevation="4dp"
|
||||||
|
android:padding="16dp">
|
||||||
|
|
||||||
|
<LinearLayout android:orientation="horizontal"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:weightSum="4">
|
||||||
|
|
||||||
|
<LinearLayout android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:gravity="center"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<org.thoughtcrime.securesms.components.CircleColorImageView
|
||||||
|
android:id="@+id/gallery_button"
|
||||||
|
android:layout_width="60dp"
|
||||||
|
android:layout_height="60dp"
|
||||||
|
android:src="@drawable/ic_image_white_36dp"
|
||||||
|
android:scaleType="center"
|
||||||
|
android:elevation="4dp"
|
||||||
|
app:circleColor="@color/purple_400"/>
|
||||||
|
|
||||||
|
<TextView android:layout_marginTop="10dp"
|
||||||
|
style="@style/AttachmentTypeLabel"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/attachment_type_selector__image"/>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<LinearLayout android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:gravity="center"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<org.thoughtcrime.securesms.components.CircleColorImageView
|
||||||
|
android:id="@+id/audio_button"
|
||||||
|
android:layout_width="60dp"
|
||||||
|
android:layout_height="60dp"
|
||||||
|
android:src="@drawable/ic_headset_white_36dp"
|
||||||
|
android:scaleType="center"
|
||||||
|
android:elevation="4dp"
|
||||||
|
app:circleColor="@color/orange_400"/>
|
||||||
|
|
||||||
|
<TextView android:layout_marginTop="10dp"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
style="@style/AttachmentTypeLabel"
|
||||||
|
android:text="@string/attachment_type_selector__audio"/>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<LinearLayout android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:gravity="center"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<org.thoughtcrime.securesms.components.CircleColorImageView
|
||||||
|
android:id="@+id/video_button"
|
||||||
|
android:layout_width="60dp"
|
||||||
|
android:layout_height="60dp"
|
||||||
|
android:src="@drawable/ic_local_movies_white_36dp"
|
||||||
|
android:scaleType="center"
|
||||||
|
android:elevation="4dp"
|
||||||
|
|
||||||
|
app:circleColor="@color/red_400"/>
|
||||||
|
|
||||||
|
<TextView android:layout_marginTop="10dp"
|
||||||
|
style="@style/AttachmentTypeLabel"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/attachment_type_selector__video"/>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<LinearLayout android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:gravity="center"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:layout_weight="1">
|
||||||
|
|
||||||
|
<org.thoughtcrime.securesms.components.CircleColorImageView
|
||||||
|
android:id="@+id/contact_button"
|
||||||
|
android:layout_width="60dp"
|
||||||
|
android:layout_height="60dp"
|
||||||
|
android:src="@drawable/ic_person_white_36dp"
|
||||||
|
android:scaleType="center"
|
||||||
|
android:elevation="4dp"
|
||||||
|
app:circleColor="@color/blue_400"/>
|
||||||
|
|
||||||
|
<TextView android:layout_marginTop="10dp"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
style="@style/AttachmentTypeLabel"
|
||||||
|
android:text="@string/attachment_type_selector__contact"/>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<LinearLayout android:orientation="horizontal"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="16dp"
|
||||||
|
android:weightSum="4">
|
||||||
|
|
||||||
|
<LinearLayout android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:gravity="center"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<org.thoughtcrime.securesms.components.CircleColorImageView
|
||||||
|
android:id="@+id/camera_button"
|
||||||
|
android:layout_width="60dp"
|
||||||
|
android:layout_height="60dp"
|
||||||
|
android:src="@drawable/ic_camera_white_36dp"
|
||||||
|
android:scaleType="center"
|
||||||
|
android:elevation="4dp"
|
||||||
|
app:circleColor="@color/green_400"/>
|
||||||
|
|
||||||
|
<TextView android:layout_marginTop="10dp"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
style="@style/AttachmentTypeLabel"
|
||||||
|
android:text="@string/attachment_type_selector__camera"/>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<LinearLayout android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:gravity="center"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:layout_marginLeft="16dp">
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
|
||||||
|
<LinearLayout android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:gravity="center"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:layout_marginLeft="16dp">
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<LinearLayout android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:gravity="center"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:layout_marginLeft="16dp">
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</LinearLayout>
|
@ -1,6 +1,7 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
<attr name="theme_type" format="string"/>
|
<attr name="theme_type" format="string"/>
|
||||||
|
<attr name="attachment_type_selector_background" format="color"/>
|
||||||
<attr name="conversation_list_item_background_selected" format="reference"/>
|
<attr name="conversation_list_item_background_selected" format="reference"/>
|
||||||
<attr name="conversation_list_item_background_read" format="reference"/>
|
<attr name="conversation_list_item_background_read" format="reference"/>
|
||||||
<attr name="conversation_list_item_background_unread" format="reference"/>
|
<attr name="conversation_list_item_background_unread" format="reference"/>
|
||||||
@ -139,4 +140,8 @@
|
|||||||
<attr name="tintColor" format="color" />
|
<attr name="tintColor" format="color" />
|
||||||
</declare-styleable>
|
</declare-styleable>
|
||||||
|
|
||||||
|
<declare-styleable name="CircleColorImageView">
|
||||||
|
<attr name="circleColor" format="color"/>
|
||||||
|
</declare-styleable>
|
||||||
|
|
||||||
</resources>
|
</resources>
|
||||||
|
@ -561,6 +561,13 @@
|
|||||||
<string name="SingleRecipientNotificationBuilder_new_signal_message">New Signal message</string>
|
<string name="SingleRecipientNotificationBuilder_new_signal_message">New Signal message</string>
|
||||||
<string name="SingleRecipientNotificationBuilder_contents_hidden">Contents hidden</string>
|
<string name="SingleRecipientNotificationBuilder_contents_hidden">Contents hidden</string>
|
||||||
|
|
||||||
|
<!-- attachment_type_selector -->
|
||||||
|
<string name="attachment_type_selector__image">Image</string>
|
||||||
|
<string name="attachment_type_selector__audio">Audio</string>
|
||||||
|
<string name="attachment_type_selector__video">Video</string>
|
||||||
|
<string name="attachment_type_selector__contact">Contact</string>
|
||||||
|
<string name="attachment_type_selector__camera">Camera</string>
|
||||||
|
|
||||||
<!-- change_passphrase_activity -->
|
<!-- change_passphrase_activity -->
|
||||||
<string name="change_passphrase_activity__old_passphrase">OLD PASSPHRASE:</string>
|
<string name="change_passphrase_activity__old_passphrase">OLD PASSPHRASE:</string>
|
||||||
<string name="change_passphrase_activity__new_passphrase">NEW PASSPHRASE:</string>
|
<string name="change_passphrase_activity__new_passphrase">NEW PASSPHRASE:</string>
|
||||||
|
@ -196,6 +196,10 @@
|
|||||||
<item name="android:contentDescription">@string/conversation_activity__compose_description</item>
|
<item name="android:contentDescription">@string/conversation_activity__compose_description</item>
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
|
<style name="AttachmentTypeLabel">
|
||||||
|
<item name="android:textColor">#ff999999</item>
|
||||||
|
</style>
|
||||||
|
|
||||||
<!-- RedPhone -->
|
<!-- RedPhone -->
|
||||||
|
|
||||||
<!-- Buttons in the main "button row" of the in-call onscreen touch UI. -->
|
<!-- Buttons in the main "button row" of the in-call onscreen touch UI. -->
|
||||||
|
@ -85,6 +85,7 @@
|
|||||||
<item name="colorAccent">@color/textsecure_primary_dark</item>
|
<item name="colorAccent">@color/textsecure_primary_dark</item>
|
||||||
<item name="android:windowBackground">@color/gray5</item>
|
<item name="android:windowBackground">@color/gray5</item>
|
||||||
<!--<item name="android:windowContentOverlay">@drawable/compat_actionbar_shadow_background</item>-->
|
<!--<item name="android:windowContentOverlay">@drawable/compat_actionbar_shadow_background</item>-->
|
||||||
|
<item name="attachment_type_selector_background">@color/white</item>
|
||||||
<item name="conversation_list_item_background_selected">@drawable/list_selected_holo_light</item>
|
<item name="conversation_list_item_background_selected">@drawable/list_selected_holo_light</item>
|
||||||
<item name="conversation_list_item_background_unread">@drawable/conversation_list_item_unread_background</item>
|
<item name="conversation_list_item_background_unread">@drawable/conversation_list_item_unread_background</item>
|
||||||
<item name="conversation_list_item_background_read">@drawable/conversation_list_item_background</item>
|
<item name="conversation_list_item_background_read">@drawable/conversation_list_item_background</item>
|
||||||
@ -190,6 +191,7 @@
|
|||||||
|
|
||||||
<style name="TextSecure.DarkTheme" parent="@style/Theme.AppCompat">
|
<style name="TextSecure.DarkTheme" parent="@style/Theme.AppCompat">
|
||||||
<item name="theme_type">dark</item>
|
<item name="theme_type">dark</item>
|
||||||
|
<item name="attachment_type_selector_background">@color/gray95</item>
|
||||||
<item name="actionBarStyle">@style/TextSecure.DarkActionBar</item>
|
<item name="actionBarStyle">@style/TextSecure.DarkActionBar</item>
|
||||||
<item name="actionBarTabBarStyle">@style/TextSecure.DarkActionBar.TabBar</item>
|
<item name="actionBarTabBarStyle">@style/TextSecure.DarkActionBar.TabBar</item>
|
||||||
<item name="actionBarPopupTheme">@style/ThemeOverlay.AppCompat.Dark</item>
|
<item name="actionBarPopupTheme">@style/ThemeOverlay.AppCompat.Dark</item>
|
||||||
|
@ -62,6 +62,7 @@ import org.thoughtcrime.securesms.TransportOptions.OnTransportChangedListener;
|
|||||||
import org.thoughtcrime.securesms.audio.AudioSlidePlayer;
|
import org.thoughtcrime.securesms.audio.AudioSlidePlayer;
|
||||||
import org.thoughtcrime.securesms.color.MaterialColor;
|
import org.thoughtcrime.securesms.color.MaterialColor;
|
||||||
import org.thoughtcrime.securesms.components.AnimatingToggle;
|
import org.thoughtcrime.securesms.components.AnimatingToggle;
|
||||||
|
import org.thoughtcrime.securesms.components.AttachmentTypeSelector;
|
||||||
import org.thoughtcrime.securesms.components.ComposeText;
|
import org.thoughtcrime.securesms.components.ComposeText;
|
||||||
import org.thoughtcrime.securesms.components.InputAwareLayout;
|
import org.thoughtcrime.securesms.components.InputAwareLayout;
|
||||||
import org.thoughtcrime.securesms.components.KeyboardAwareLinearLayout.OnKeyboardShownListener;
|
import org.thoughtcrime.securesms.components.KeyboardAwareLinearLayout.OnKeyboardShownListener;
|
||||||
@ -181,14 +182,14 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
|||||||
private View composeBubble;
|
private View composeBubble;
|
||||||
private ReminderView reminderView;
|
private ReminderView reminderView;
|
||||||
|
|
||||||
private AttachmentTypeSelectorAdapter attachmentAdapter;
|
private AttachmentTypeSelector attachmentTypeSelector;
|
||||||
private AttachmentManager attachmentManager;
|
private AttachmentManager attachmentManager;
|
||||||
private BroadcastReceiver securityUpdateReceiver;
|
private BroadcastReceiver securityUpdateReceiver;
|
||||||
private BroadcastReceiver groupUpdateReceiver;
|
private BroadcastReceiver groupUpdateReceiver;
|
||||||
private EmojiDrawer emojiDrawer;
|
private EmojiDrawer emojiDrawer;
|
||||||
private EmojiToggle emojiToggle;
|
private EmojiToggle emojiToggle;
|
||||||
protected HidingImageButton quickAttachmentToggle;
|
protected HidingImageButton quickAttachmentToggle;
|
||||||
private QuickAttachmentDrawer quickAttachmentDrawer;
|
private QuickAttachmentDrawer quickAttachmentDrawer;
|
||||||
|
|
||||||
private Recipients recipients;
|
private Recipients recipients;
|
||||||
private long threadId;
|
private long threadId;
|
||||||
@ -673,8 +674,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
|||||||
|
|
||||||
private void handleAddAttachment() {
|
private void handleAddAttachment() {
|
||||||
if (this.isMmsEnabled || isSecureText) {
|
if (this.isMmsEnabled || isSecureText) {
|
||||||
new AlertDialogWrapper.Builder(this).setAdapter(attachmentAdapter, new AttachmentTypeListener())
|
attachmentTypeSelector.show(this, attachButton);
|
||||||
.show();
|
|
||||||
} else {
|
} else {
|
||||||
handleManualMmsRequired();
|
handleManualMmsRequired();
|
||||||
}
|
}
|
||||||
@ -865,8 +865,8 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
|||||||
composeBubble.getBackground().setColorFilter(defaultColor, PorterDuff.Mode.MULTIPLY);
|
composeBubble.getBackground().setColorFilter(defaultColor, PorterDuff.Mode.MULTIPLY);
|
||||||
colors.recycle();
|
colors.recycle();
|
||||||
|
|
||||||
attachmentAdapter = new AttachmentTypeSelectorAdapter(this);
|
attachmentTypeSelector = new AttachmentTypeSelector(this, new AttachmentTypeListener());
|
||||||
attachmentManager = new AttachmentManager(this, this);
|
attachmentManager = new AttachmentManager(this, this);
|
||||||
|
|
||||||
SendButtonListener sendButtonListener = new SendButtonListener();
|
SendButtonListener sendButtonListener = new SendButtonListener();
|
||||||
ComposeKeyPressedListener composeKeyPressedListener = new ComposeKeyPressedListener();
|
ComposeKeyPressedListener composeKeyPressedListener = new ComposeKeyPressedListener();
|
||||||
@ -1348,11 +1348,10 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
|||||||
|
|
||||||
// Listeners
|
// Listeners
|
||||||
|
|
||||||
private class AttachmentTypeListener implements DialogInterface.OnClickListener {
|
private class AttachmentTypeListener implements AttachmentTypeSelector.AttachmentClickedListener {
|
||||||
@Override
|
@Override
|
||||||
public void onClick(DialogInterface dialog, int which) {
|
public void onClick(int type) {
|
||||||
addAttachment(attachmentAdapter.buttonToCommand(which));
|
addAttachment(type);
|
||||||
dialog.dismiss();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -0,0 +1,243 @@
|
|||||||
|
package org.thoughtcrime.securesms.components;
|
||||||
|
|
||||||
|
import android.animation.Animator;
|
||||||
|
import android.annotation.TargetApi;
|
||||||
|
import android.app.Activity;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.graphics.drawable.BitmapDrawable;
|
||||||
|
import android.os.Build;
|
||||||
|
import android.support.annotation.NonNull;
|
||||||
|
import android.support.annotation.Nullable;
|
||||||
|
import android.util.Pair;
|
||||||
|
import android.view.Gravity;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewAnimationUtils;
|
||||||
|
import android.view.ViewTreeObserver;
|
||||||
|
import android.view.animation.Animation;
|
||||||
|
import android.view.animation.AnimationSet;
|
||||||
|
import android.view.animation.OvershootInterpolator;
|
||||||
|
import android.view.animation.ScaleAnimation;
|
||||||
|
import android.view.animation.TranslateAnimation;
|
||||||
|
import android.widget.ImageView;
|
||||||
|
import android.widget.LinearLayout;
|
||||||
|
import android.widget.PopupWindow;
|
||||||
|
|
||||||
|
import org.thoughtcrime.securesms.R;
|
||||||
|
import org.thoughtcrime.securesms.util.ViewUtil;
|
||||||
|
|
||||||
|
public class AttachmentTypeSelector extends PopupWindow {
|
||||||
|
|
||||||
|
public static final int ADD_IMAGE = 1;
|
||||||
|
public static final int ADD_VIDEO = 2;
|
||||||
|
public static final int ADD_SOUND = 3;
|
||||||
|
public static final int ADD_CONTACT_INFO = 4;
|
||||||
|
public static final int TAKE_PHOTO = 5;
|
||||||
|
|
||||||
|
private static final int ANIMATION_DURATION = 300;
|
||||||
|
|
||||||
|
private static final String TAG = AttachmentTypeSelector.class.getSimpleName();
|
||||||
|
|
||||||
|
private final @NonNull ImageView imageButton;
|
||||||
|
private final @NonNull ImageView audioButton;
|
||||||
|
private final @NonNull ImageView videoButton;
|
||||||
|
private final @NonNull ImageView contactButton;
|
||||||
|
private final @NonNull ImageView cameraButton;
|
||||||
|
|
||||||
|
private @Nullable View currentAnchor;
|
||||||
|
private @Nullable AttachmentClickedListener listener;
|
||||||
|
|
||||||
|
public AttachmentTypeSelector(@NonNull Context context, @Nullable AttachmentClickedListener listener) {
|
||||||
|
super(context);
|
||||||
|
|
||||||
|
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
||||||
|
LinearLayout layout = (LinearLayout) inflater.inflate(R.layout.attachment_type_selector, null, true);
|
||||||
|
|
||||||
|
this.listener = listener;
|
||||||
|
this.imageButton = ViewUtil.findById(layout, R.id.gallery_button);
|
||||||
|
this.audioButton = ViewUtil.findById(layout, R.id.audio_button);
|
||||||
|
this.videoButton = ViewUtil.findById(layout, R.id.video_button);
|
||||||
|
this.contactButton = ViewUtil.findById(layout, R.id.contact_button);
|
||||||
|
this.cameraButton = ViewUtil.findById(layout, R.id.camera_button);
|
||||||
|
|
||||||
|
this.imageButton.setOnClickListener(new PropagatingClickListener(ADD_IMAGE));
|
||||||
|
this.audioButton.setOnClickListener(new PropagatingClickListener(ADD_SOUND));
|
||||||
|
this.videoButton.setOnClickListener(new PropagatingClickListener(ADD_VIDEO));
|
||||||
|
this.contactButton.setOnClickListener(new PropagatingClickListener(ADD_CONTACT_INFO));
|
||||||
|
this.cameraButton.setOnClickListener(new PropagatingClickListener(TAKE_PHOTO));
|
||||||
|
|
||||||
|
setContentView(layout);
|
||||||
|
setWidth(LinearLayout.LayoutParams.MATCH_PARENT);
|
||||||
|
setHeight(LinearLayout.LayoutParams.WRAP_CONTENT);
|
||||||
|
setBackgroundDrawable(new BitmapDrawable());
|
||||||
|
setAnimationStyle(0);
|
||||||
|
setInputMethodMode(PopupWindow.INPUT_METHOD_NOT_NEEDED);
|
||||||
|
setFocusable(true);
|
||||||
|
setTouchable(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void show(@NonNull Activity activity, final @NonNull View anchor) {
|
||||||
|
this.currentAnchor = anchor;
|
||||||
|
|
||||||
|
int screenHeight = activity.getWindowManager().getDefaultDisplay().getHeight();
|
||||||
|
showAtLocation(anchor, Gravity.NO_GRAVITY, 0, screenHeight - getHeight());
|
||||||
|
|
||||||
|
getContentView().getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
|
||||||
|
@Override
|
||||||
|
public void onGlobalLayout() {
|
||||||
|
getContentView().getViewTreeObserver().removeGlobalOnLayoutListener(this);
|
||||||
|
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||||
|
animateWindowInCircular(anchor, getContentView());
|
||||||
|
} else {
|
||||||
|
animateWindowInTranslate(getContentView());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||||
|
animateButtonIn(imageButton, ANIMATION_DURATION / 2);
|
||||||
|
animateButtonIn(cameraButton, ANIMATION_DURATION / 2);
|
||||||
|
|
||||||
|
animateButtonIn(audioButton, ANIMATION_DURATION / 3);
|
||||||
|
animateButtonIn(videoButton, ANIMATION_DURATION / 4);
|
||||||
|
animateButtonIn(contactButton, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void dismiss() {
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||||
|
animateWindowOutCircular(currentAnchor, getContentView());
|
||||||
|
} else {
|
||||||
|
animateWindowOutTranslate(getContentView());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setListener(@Nullable AttachmentClickedListener listener) {
|
||||||
|
this.listener = listener;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void animateButtonIn(View button, int delay) {
|
||||||
|
AnimationSet animation = new AnimationSet(true);
|
||||||
|
Animation scale = new ScaleAnimation(0.0f, 1.0f, 0.0f, 1.0f,
|
||||||
|
Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.0f);
|
||||||
|
|
||||||
|
animation.addAnimation(scale);
|
||||||
|
animation.setInterpolator(new OvershootInterpolator(1));
|
||||||
|
animation.setDuration(ANIMATION_DURATION);
|
||||||
|
animation.setStartOffset(delay);
|
||||||
|
button.startAnimation(animation);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
|
||||||
|
private void animateWindowInCircular(@Nullable View anchor, @NonNull View contentView) {
|
||||||
|
Pair<Integer, Integer> coordinates = getClickOrigin(anchor, contentView);
|
||||||
|
Animator animator = ViewAnimationUtils.createCircularReveal(contentView,
|
||||||
|
coordinates.first,
|
||||||
|
coordinates.second,
|
||||||
|
0,
|
||||||
|
Math.max(contentView.getWidth(), contentView.getHeight()));
|
||||||
|
animator.setDuration(ANIMATION_DURATION);
|
||||||
|
animator.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void animateWindowInTranslate(@NonNull View contentView) {
|
||||||
|
Animation animation = new TranslateAnimation(0, 0, contentView.getHeight(), 0);
|
||||||
|
animation.setDuration(ANIMATION_DURATION);
|
||||||
|
|
||||||
|
getContentView().startAnimation(animation);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
|
||||||
|
private void animateWindowOutCircular(@Nullable View anchor, @NonNull View contentView) {
|
||||||
|
Pair<Integer, Integer> coordinates = getClickOrigin(anchor, contentView);
|
||||||
|
Animator animator = ViewAnimationUtils.createCircularReveal(getContentView(),
|
||||||
|
coordinates.first,
|
||||||
|
coordinates.second,
|
||||||
|
Math.max(getContentView().getWidth(), getContentView().getHeight()),
|
||||||
|
0);
|
||||||
|
|
||||||
|
animator.setDuration(ANIMATION_DURATION);
|
||||||
|
animator.addListener(new Animator.AnimatorListener() {
|
||||||
|
@Override
|
||||||
|
public void onAnimationStart(Animator animation) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onAnimationEnd(Animator animation) {
|
||||||
|
AttachmentTypeSelector.super.dismiss();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onAnimationCancel(Animator animation) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onAnimationRepeat(Animator animation) {
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
animator.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void animateWindowOutTranslate(@NonNull View contentView) {
|
||||||
|
Animation animation = new TranslateAnimation(0, 0, 0, contentView.getTop() + contentView.getHeight());
|
||||||
|
animation.setDuration(ANIMATION_DURATION);
|
||||||
|
animation.setAnimationListener(new Animation.AnimationListener() {
|
||||||
|
@Override
|
||||||
|
public void onAnimationStart(Animation animation) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onAnimationEnd(Animation animation) {
|
||||||
|
AttachmentTypeSelector.super.dismiss();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onAnimationRepeat(Animation animation) {
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
getContentView().startAnimation(animation);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Pair<Integer, Integer> getClickOrigin(@Nullable View anchor, @NonNull View contentView) {
|
||||||
|
if (anchor == null) return new Pair<>(0, 0);
|
||||||
|
|
||||||
|
final int[] anchorCoordinates = new int[2];
|
||||||
|
anchor.getLocationOnScreen(anchorCoordinates);
|
||||||
|
anchorCoordinates[0] += anchor.getWidth() / 2;
|
||||||
|
anchorCoordinates[1] += anchor.getHeight() / 2;
|
||||||
|
|
||||||
|
final int[] contentCoordinates = new int[2];
|
||||||
|
contentView.getLocationOnScreen(contentCoordinates);
|
||||||
|
|
||||||
|
int x = anchorCoordinates[0] - contentCoordinates[0];
|
||||||
|
int y = anchorCoordinates[1] - contentCoordinates[1];
|
||||||
|
|
||||||
|
return new Pair<>(x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
private class PropagatingClickListener implements View.OnClickListener {
|
||||||
|
|
||||||
|
private final int type;
|
||||||
|
|
||||||
|
private PropagatingClickListener(int type) {
|
||||||
|
this.type = type;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
animateWindowOutTranslate(getContentView());
|
||||||
|
|
||||||
|
if (listener != null) listener.onClick(type);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface AttachmentClickedListener {
|
||||||
|
public void onClick(int type);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,40 @@
|
|||||||
|
package org.thoughtcrime.securesms.components;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.res.TypedArray;
|
||||||
|
import android.graphics.Color;
|
||||||
|
import android.graphics.ColorFilter;
|
||||||
|
import android.graphics.PorterDuff;
|
||||||
|
import android.graphics.drawable.Drawable;
|
||||||
|
import android.util.AttributeSet;
|
||||||
|
import android.widget.ImageView;
|
||||||
|
|
||||||
|
import org.thoughtcrime.securesms.R;
|
||||||
|
|
||||||
|
public class CircleColorImageView extends ImageView {
|
||||||
|
|
||||||
|
public CircleColorImageView(Context context) {
|
||||||
|
this(context, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public CircleColorImageView(Context context, AttributeSet attrs) {
|
||||||
|
this(context, attrs, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public CircleColorImageView(Context context, AttributeSet attrs, int defStyleAttr) {
|
||||||
|
super(context, attrs, defStyleAttr);
|
||||||
|
|
||||||
|
int circleColor = Color.WHITE;
|
||||||
|
|
||||||
|
if (attrs != null) {
|
||||||
|
TypedArray typedArray = context.getTheme().obtainStyledAttributes(attrs, R.styleable.CircleColorImageView, 0, 0);
|
||||||
|
circleColor = typedArray.getColor(R.styleable.CircleColorImageView_circleColor, Color.WHITE);
|
||||||
|
typedArray.recycle();
|
||||||
|
}
|
||||||
|
|
||||||
|
Drawable circle = context.getResources().getDrawable(R.drawable.circle_tintable);
|
||||||
|
circle.setColorFilter(circleColor, PorterDuff.Mode.SRC_IN);
|
||||||
|
|
||||||
|
setBackgroundDrawable(circle);
|
||||||
|
}
|
||||||
|
}
|