diff --git a/res/values/strings.xml b/res/values/strings.xml
index 612befadf4..d4850af9e1 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -118,7 +118,7 @@
Transport: %1$s\nSent/Received: %2$s
Sender: %1$s\nTransport: %2$s\nSent: %3$s\nReceived: %4$s
Confirm message delete
- Are you sure that you want to permanently delete this message?
+ Are you sure that you want to permanently delete all selected messages?
Save to storage?
Saving this media to storage will allow any other apps on your phone to access it.\n\nContinue?
Error while saving attachment to storage!
@@ -130,6 +130,8 @@
PUSH
MMS
SMS
+ Deleting...
+ Deleting messages...
Delete threads?
diff --git a/src/org/thoughtcrime/securesms/ConversationAdapter.java b/src/org/thoughtcrime/securesms/ConversationAdapter.java
index 291f4a64e2..4ab6830e44 100644
--- a/src/org/thoughtcrime/securesms/ConversationAdapter.java
+++ b/src/org/thoughtcrime/securesms/ConversationAdapter.java
@@ -35,7 +35,11 @@ import org.thoughtcrime.securesms.util.LRUCache;
import java.lang.ref.SoftReference;
import java.util.Collections;
+import java.util.HashSet;
import java.util.Map;
+import java.util.Set;
+
+import org.thoughtcrime.securesms.ConversationFragment.SelectionClickListener;
/**
* A cursor adapter for a conversation thread. Ultimately
@@ -55,19 +59,23 @@ public class ConversationAdapter extends CursorAdapter implements AbsListView.Re
public static final int MESSAGE_TYPE_INCOMING = 1;
public static final int MESSAGE_TYPE_GROUP_ACTION = 2;
- private final Handler failedIconClickHandler;
- private final Context context;
- private final MasterSecret masterSecret;
- private final boolean groupThread;
- private final boolean pushDestination;
- private final LayoutInflater inflater;
+ private final Set batchSelected = Collections.synchronizedSet(new HashSet());
- public ConversationAdapter(Context context, MasterSecret masterSecret,
+ private final SelectionClickListener selectionClickListener;
+ private final Handler failedIconClickHandler;
+ private final Context context;
+ private final MasterSecret masterSecret;
+ private final boolean groupThread;
+ private final boolean pushDestination;
+ private final LayoutInflater inflater;
+
+ public ConversationAdapter(Context context, MasterSecret masterSecret, SelectionClickListener selectionClickListener,
Handler failedIconClickHandler, boolean groupThread, boolean pushDestination)
{
super(context, null, 0);
this.context = context;
this.masterSecret = masterSecret;
+ this.selectionClickListener = selectionClickListener;
this.failedIconClickHandler = failedIconClickHandler;
this.groupThread = groupThread;
this.pushDestination = pushDestination;
@@ -81,7 +89,8 @@ public class ConversationAdapter extends CursorAdapter implements AbsListView.Re
String type = cursor.getString(cursor.getColumnIndexOrThrow(MmsSmsDatabase.TRANSPORT));
MessageRecord messageRecord = getMessageRecord(id, cursor, type);
- item.set(masterSecret, messageRecord, failedIconClickHandler, groupThread, pushDestination);
+ item.set(masterSecret, messageRecord, batchSelected, selectionClickListener,
+ failedIconClickHandler, groupThread, pushDestination);
}
@Override
@@ -158,6 +167,18 @@ public class ConversationAdapter extends CursorAdapter implements AbsListView.Re
this.getCursor().close();
}
+ public void toggleBatchSelected(MessageRecord messageRecord) {
+ if (batchSelected.contains(messageRecord)) {
+ batchSelected.remove(messageRecord);
+ } else {
+ batchSelected.add(messageRecord);
+ }
+ }
+
+ public Set getBatchSelected() {
+ return batchSelected;
+ }
+
@Override
public void onMovedToScrapHeap(View view) {
((ConversationItem)view).unbind();
diff --git a/src/org/thoughtcrime/securesms/ConversationFragment.java b/src/org/thoughtcrime/securesms/ConversationFragment.java
index 64d8652ae0..a87b2e628c 100644
--- a/src/org/thoughtcrime/securesms/ConversationFragment.java
+++ b/src/org/thoughtcrime/securesms/ConversationFragment.java
@@ -40,17 +40,23 @@ import org.thoughtcrime.securesms.sms.MessageSender;
import org.thoughtcrime.securesms.util.Dialogs;
import org.thoughtcrime.securesms.util.DirectoryHelper;
import org.thoughtcrime.securesms.util.FutureTaskListener;
+import org.thoughtcrime.securesms.util.ProgressDialogAsyncTask;
import org.thoughtcrime.securesms.util.SaveAttachmentTask;
import org.thoughtcrime.securesms.util.SaveAttachmentTask.Attachment;
import java.sql.Date;
import java.text.SimpleDateFormat;
+import java.util.LinkedList;
+import java.util.List;
public class ConversationFragment extends ListFragment
implements LoaderManager.LoaderCallbacks
{
private static final String TAG = ConversationFragment.class.getSimpleName();
+ private final ActionModeCallback actionModeCallback = new ActionModeCallback();
+ private final SelectionClickListener selectionClickListener = new SelectionClickListener();
+
private ConversationFragmentListener listener;
private MasterSecret masterSecret;
@@ -96,7 +102,7 @@ public class ConversationFragment extends ListFragment
private void initializeListAdapter() {
if (this.recipients != null && this.threadId != -1) {
- this.setListAdapter(new ConversationAdapter(getActivity(), masterSecret,
+ this.setListAdapter(new ConversationAdapter(getActivity(), masterSecret, selectionClickListener,
new FailedIconClickHandler(),
(!this.recipients.isSingleRecipient()) || this.recipients.isGroupRecipient(),
DirectoryHelper.isPushDestination(getActivity(), this.recipients)));
@@ -106,49 +112,50 @@ public class ConversationFragment extends ListFragment
}
private void initializeContextualActionBar() {
- getListView().setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {
- @Override
- public boolean onItemLongClick(AdapterView> parent, View view, int position, long id) {
- if (actionMode != null) {
- view.setSelected(true);
- return false;
- }
-
- actionMode = ((ActionBarActivity)getActivity()).startSupportActionMode(actionModeCallback);
- view.setSelected(true);
- return true;
- }
- });
-
- getListView().setOnItemClickListener(new AdapterView.OnItemClickListener() {
- @Override
- public void onItemClick(AdapterView> parent, View view, int position, long id) {
- if (actionMode != null) {
- view.setSelected(true);
- setCorrectMenuVisibility(getMessageRecord(), actionMode.getMenu());
- }
- }
- });
+ getListView().setOnItemClickListener(selectionClickListener);
+ getListView().setOnItemLongClickListener(selectionClickListener);
}
- private void setCorrectMenuVisibility(MessageRecord messageRecord, Menu menu) {
- MenuItem resend = menu.findItem(R.id.menu_context_resend);
- MenuItem saveAttachment = menu.findItem(R.id.menu_context_save_attachment);
+ private void setCorrectMenuVisibility(Menu menu) {
+ ConversationAdapter adapter = (ConversationAdapter) getListAdapter();
+ List messageRecords = getSelectedMessageRecords();
- if (messageRecord.isFailed()) resend.setVisible(true);
- else resend.setVisible(false);
+ if (actionMode != null && messageRecords.size() == 0) {
+ adapter.getBatchSelected().clear();
+ adapter.notifyDataSetChanged();
+ actionMode.finish();
+ return;
+ }
- if (messageRecord.isMms() && !messageRecord.isMmsNotification()) {
- saveAttachment.setVisible(((MediaMmsMessageRecord)messageRecord).containsMediaSlide());
+ if (messageRecords.size() > 1) {
+ menu.findItem(R.id.menu_context_forward).setVisible(false);
+ menu.findItem(R.id.menu_context_copy).setVisible(false);
+ menu.findItem(R.id.menu_context_details).setVisible(false);
+ menu.findItem(R.id.menu_context_save_attachment).setVisible(false);
+ menu.findItem(R.id.menu_context_resend).setVisible(false);
} else {
- saveAttachment.setVisible(false);
+ MessageRecord messageRecord = messageRecords.get(0);
+
+ menu.findItem(R.id.menu_context_resend).setVisible(messageRecord.isFailed());
+ menu.findItem(R.id.menu_context_save_attachment).setVisible(messageRecord.isMms() &&
+ !messageRecord.isMmsNotification() &&
+ ((MediaMmsMessageRecord)messageRecord).containsMediaSlide());
+
+ menu.findItem(R.id.menu_context_forward).setVisible(true);
+ menu.findItem(R.id.menu_context_details).setVisible(true);
+ menu.findItem(R.id.menu_context_copy).setVisible(true);
}
}
- private MessageRecord getMessageRecord() {
- Cursor cursor = ((CursorAdapter)getListAdapter()).getCursor();
- ConversationItem conversationItem = (ConversationItem)(((ConversationAdapter)getListAdapter()).newView(getActivity(), cursor, null));
- return conversationItem.getMessageRecord();
+ private MessageRecord getSelectedMessageRecord() {
+ List messageRecords = getSelectedMessageRecords();
+
+ if (messageRecords.size() == 1) return messageRecords.get(0);
+ else throw new AssertionError();
+ }
+
+ private List getSelectedMessageRecords() {
+ return new LinkedList<>(((ConversationAdapter)getListAdapter()).getBatchSelected());
}
public void reload(Recipients recipients, long threadId) {
@@ -177,23 +184,32 @@ public class ConversationFragment extends ListFragment
clipboard.setText(body);
}
- private void handleDeleteMessage(final MessageRecord message) {
- final long messageId = message.getId();
-
+ private void handleDeleteMessages(final List messageRecords) {
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
builder.setTitle(R.string.ConversationFragment_confirm_message_delete);
builder.setIcon(Dialogs.resolveIcon(getActivity(), R.attr.dialog_alert_icon));
builder.setCancelable(true);
- builder.setMessage(R.string.ConversationFragment_are_you_sure_you_want_to_permanently_delete_this_message);
-
+ builder.setMessage(R.string.ConversationFragment_are_you_sure_you_want_to_permanently_delete_all_selected_messages);
builder.setPositiveButton(R.string.yes, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
- if (message.isMms()) {
- DatabaseFactory.getMmsDatabase(getActivity()).delete(messageId);
- } else {
- DatabaseFactory.getSmsDatabase(getActivity()).deleteMessage(messageId);
- }
+ new ProgressDialogAsyncTask(getActivity(),
+ R.string.ConversationFragment_deleting,
+ R.string.ConversationFragment_deleting_messages)
+ {
+ @Override
+ protected Void doInBackground(MessageRecord... messageRecords) {
+ for (MessageRecord messageRecord : messageRecords) {
+ if (messageRecord.isMms()) {
+ DatabaseFactory.getMmsDatabase(getActivity()).delete(messageRecord.getId());
+ } else {
+ DatabaseFactory.getSmsDatabase(getActivity()).deleteMessage(messageRecord.getId());
+ }
+ }
+
+ return null;
+ }
+ }.execute(messageRecords.toArray(new MessageRecord[messageRecords.size()]));
}
});
@@ -312,16 +328,43 @@ public class ConversationFragment extends ListFragment
public void setComposeText(String text);
}
- private ActionMode.Callback actionModeCallback = new ActionMode.Callback() {
+ public class SelectionClickListener
+ implements AdapterView.OnItemLongClickListener, AdapterView.OnItemClickListener
+ {
+ @Override
+ public void onItemClick(AdapterView> parent, View view, int position, long id) {
+ if (actionMode != null && view instanceof ConversationItem) {
+ MessageRecord messageRecord = ((ConversationItem)view).getMessageRecord();
+ ((ConversationAdapter) getListAdapter()).toggleBatchSelected(messageRecord);
+ ((ConversationAdapter) getListAdapter()).notifyDataSetChanged();
+
+ setCorrectMenuVisibility(actionMode.getMenu());
+ }
+ }
+
+ @Override
+ public boolean onItemLongClick(AdapterView> parent, View view, int position, long id) {
+ if (actionMode == null && view instanceof ConversationItem) {
+ MessageRecord messageRecord = ((ConversationItem)view).getMessageRecord();
+ ((ConversationAdapter) getListAdapter()).toggleBatchSelected(messageRecord);
+ ((ConversationAdapter) getListAdapter()).notifyDataSetChanged();
+
+ actionMode = ((ActionBarActivity)getActivity()).startSupportActionMode(actionModeCallback);
+ return true;
+ }
+
+ return false;
+ }
+ }
+
+ private class ActionModeCallback implements ActionMode.Callback {
@Override
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
MenuInflater inflater = mode.getMenuInflater();
inflater.inflate(R.menu.conversation_context, menu);
- MessageRecord messageRecord = getMessageRecord();
- setCorrectMenuVisibility(messageRecord, menu);
-
+ setCorrectMenuVisibility(menu);
return true;
}
@@ -332,41 +375,37 @@ public class ConversationFragment extends ListFragment
@Override
public void onDestroyActionMode(ActionMode mode) {
- if (getListView() != null && getListView().getChildCount() > 0) {
- for (int i = 0; i < getListView().getChildCount(); i++){
- getListView().getChildAt(i).setSelected(false);
- }
- }
+ ((ConversationAdapter)getListAdapter()).getBatchSelected().clear();
+ ((ConversationAdapter)getListAdapter()).notifyDataSetChanged();
+
actionMode = null;
}
@Override
public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
- MessageRecord messageRecord = getMessageRecord();
-
switch(item.getItemId()) {
case R.id.menu_context_copy:
- handleCopyMessage(messageRecord);
+ handleCopyMessage(getSelectedMessageRecord());
actionMode.finish();
return true;
case R.id.menu_context_delete_message:
- handleDeleteMessage(messageRecord);
+ handleDeleteMessages(getSelectedMessageRecords());
actionMode.finish();
return true;
case R.id.menu_context_details:
- handleDisplayDetails(messageRecord);
+ handleDisplayDetails(getSelectedMessageRecord());
actionMode.finish();
return true;
case R.id.menu_context_forward:
- handleForwardMessage(messageRecord);
+ handleForwardMessage(getSelectedMessageRecord());
actionMode.finish();
return true;
case R.id.menu_context_resend:
- handleResendMessage(messageRecord);
+ handleResendMessage(getSelectedMessageRecord());
actionMode.finish();
return true;
case R.id.menu_context_save_attachment:
- handleSaveAttachment((MediaMmsMessageRecord)messageRecord);
+ handleSaveAttachment((MediaMmsMessageRecord)getSelectedMessageRecord());
actionMode.finish();
return true;
}
diff --git a/src/org/thoughtcrime/securesms/ConversationItem.java b/src/org/thoughtcrime/securesms/ConversationItem.java
index 27bef7c54d..4ad253a11a 100644
--- a/src/org/thoughtcrime/securesms/ConversationItem.java
+++ b/src/org/thoughtcrime/securesms/ConversationItem.java
@@ -25,10 +25,8 @@ import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.Color;
import android.graphics.drawable.ColorDrawable;
-import android.net.Uri;
import android.os.Handler;
import android.os.Message;
-import android.provider.Contacts.Intents;
import android.provider.ContactsContract;
import android.provider.ContactsContract.QuickContact;
import android.util.AttributeSet;
@@ -40,9 +38,10 @@ import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;
+import org.thoughtcrime.securesms.ConversationFragment.SelectionClickListener;
+import org.thoughtcrime.securesms.contacts.ContactPhotoFactory;
import org.thoughtcrime.securesms.crypto.MasterSecret;
import org.thoughtcrime.securesms.database.DatabaseFactory;
-import org.thoughtcrime.securesms.contacts.ContactPhotoFactory;
import org.thoughtcrime.securesms.database.MmsDatabase;
import org.thoughtcrime.securesms.database.SmsDatabase;
import org.thoughtcrime.securesms.database.model.MediaMmsMessageRecord;
@@ -61,6 +60,8 @@ import org.thoughtcrime.securesms.util.Emoji;
import org.thoughtcrime.securesms.util.FutureTaskListener;
import org.thoughtcrime.securesms.util.ListenableFutureTask;
+import java.util.Set;
+
/**
* A view that displays an individual conversation item within a conversation
* thread. Used by ComposeMessageActivity's ListActivity via a ConversationAdapter.
@@ -81,13 +82,13 @@ public class ConversationItem extends LinearLayout {
R.attr.conversation_item_sent_push_pending_background,
R.attr.conversation_item_sent_push_pending_triangle_background};
- private final static int SENT_PUSH = 0;
- private final static int SENT_PUSH_TRIANGLE = 1;
- private final static int SENT_SMS = 2;
- private final static int SENT_SMS_TRIANGLE = 3;
- private final static int SENT_SMS_PENDING = 4;
- private final static int SENT_SMS_PENDING_TRIANGLE = 5;
- private final static int SENT_PUSH_PENDING = 6;
+ private final static int SENT_PUSH = 0;
+ private final static int SENT_PUSH_TRIANGLE = 1;
+ private final static int SENT_SMS = 2;
+ private final static int SENT_SMS_TRIANGLE = 3;
+ private final static int SENT_SMS_PENDING = 4;
+ private final static int SENT_SMS_PENDING_TRIANGLE = 5;
+ private final static int SENT_PUSH_PENDING = 6;
private final static int SENT_PUSH_PENDING_TRIANGLE = 7;
private Handler failedIconHandler;
@@ -108,19 +109,21 @@ public class ConversationItem extends LinearLayout {
private View triangleTick;
private ImageView pendingIndicator;
- private View mmsContainer;
- private ImageView mmsThumbnail;
- private Button mmsDownloadButton;
- private TextView mmsDownloadingLabel;
- private ListenableFutureTask slideDeck;
- private FutureTaskListener slideDeckListener;
- private TypedArray backgroundDrawables;
+ private Set batchSelected;
+ private SelectionClickListener selectionClickListener;
+ private View mmsContainer;
+ private ImageView mmsThumbnail;
+ private Button mmsDownloadButton;
+ private TextView mmsDownloadingLabel;
+ private ListenableFutureTask slideDeck;
+ private FutureTaskListener slideDeckListener;
+ private TypedArray backgroundDrawables;
- private final FailedIconClickListener failedIconClickListener = new FailedIconClickListener();
- private final MmsDownloadClickListener mmsDownloadClickListener = new MmsDownloadClickListener();
+ private final FailedIconClickListener failedIconClickListener = new FailedIconClickListener();
+ private final MmsDownloadClickListener mmsDownloadClickListener = new MmsDownloadClickListener();
private final MmsPreferencesClickListener mmsPreferencesClickListener = new MmsPreferencesClickListener();
- private final ClickListener clickListener = new ClickListener();
- private final Handler handler = new Handler();
+ private final ClickListener clickListener = new ClickListener();
+ private final Handler handler = new Handler();
private final Context context;
public ConversationItem(Context context) {
@@ -157,19 +160,23 @@ public class ConversationItem extends LinearLayout {
setOnClickListener(clickListener);
if (failedImage != null) failedImage.setOnClickListener(failedIconClickListener);
if (mmsDownloadButton != null) mmsDownloadButton.setOnClickListener(mmsDownloadClickListener);
+ if (mmsThumbnail != null) mmsThumbnail.setOnLongClickListener(new MultiSelectLongClickListener());
}
public void set(MasterSecret masterSecret, MessageRecord messageRecord,
+ Set batchSelected, SelectionClickListener selectionClickListener,
Handler failedIconHandler, boolean groupThread, boolean pushDestination)
{
+ this.masterSecret = masterSecret;
+ this.messageRecord = messageRecord;
+ this.batchSelected = batchSelected;
+ this.selectionClickListener = selectionClickListener;
+ this.failedIconHandler = failedIconHandler;
+ this.groupThread = groupThread;
+ this.pushDestination = pushDestination;
- this.messageRecord = messageRecord;
- this.masterSecret = masterSecret;
- this.failedIconHandler = failedIconHandler;
- this.groupThread = groupThread;
- this.pushDestination = pushDestination;
-
- setBackgroundDrawables(messageRecord);
+ setConversationBackgroundDrawables(messageRecord);
+ setSelectionBackgroundDrawables(messageRecord);
setBodyText(messageRecord);
if (!messageRecord.isGroupAction()) {
@@ -211,33 +218,57 @@ public class ConversationItem extends LinearLayout {
/// MessageRecord Attribute Parsers
- private void setBackgroundDrawables(MessageRecord messageRecord) {
+ private void setConversationBackgroundDrawables(MessageRecord messageRecord) {
if (conversationParent != null && backgroundDrawables != null) {
if (messageRecord.isOutgoing()) {
final int background;
final int triangleBackground;
if (messageRecord.isPending() && pushDestination && !messageRecord.isForcedSms()) {
- background = SENT_PUSH_PENDING;
+ background = SENT_PUSH_PENDING;
triangleBackground = SENT_PUSH_PENDING_TRIANGLE;
} else if (messageRecord.isPending() || messageRecord.isPendingSmsFallback()) {
- background = SENT_SMS_PENDING;
+ background = SENT_SMS_PENDING;
triangleBackground = SENT_SMS_PENDING_TRIANGLE;
} else if (messageRecord.isPush()) {
- background = SENT_PUSH;
+ background = SENT_PUSH;
triangleBackground = SENT_PUSH_TRIANGLE;
} else {
- background = SENT_SMS;
+ background = SENT_SMS;
triangleBackground = SENT_SMS_TRIANGLE;
}
+
setViewBackgroundWithoutResettingPadding(conversationParent, backgroundDrawables.getResourceId(background, -1));
setViewBackgroundWithoutResettingPadding(triangleTick, backgroundDrawables.getResourceId(triangleBackground, -1));
}
}
}
+ private void setSelectionBackgroundDrawables(MessageRecord messageRecord) {
+ int[] attributes = new int[]{R.attr.conversation_list_item_background_selected,
+ R.attr.conversation_item_background};
+
+ TypedArray drawables = context.obtainStyledAttributes(attributes);
+
+ if (batchSelected.contains(messageRecord)) {
+ setBackgroundDrawable(drawables.getDrawable(0));
+ } else {
+ setBackgroundDrawable(drawables.getDrawable(1));
+ }
+
+ drawables.recycle();
+ }
+
private void setBodyText(MessageRecord messageRecord) {
- bodyText.setText(Emoji.getInstance(context).emojify(messageRecord.getDisplayBody(), new Emoji.InvalidatingPageLoadedListener(bodyText)),
- TextView.BufferType.SPANNABLE);
+ bodyText.setClickable(false);
+ bodyText.setFocusable(false);
+ bodyText.setText(Emoji.getInstance(context).emojify(messageRecord.getDisplayBody(),
+ new Emoji.InvalidatingPageLoadedListener(bodyText)),
+ TextView.BufferType.SPANNABLE);
+
+ if (bodyText.isClickable() && bodyText.isFocusable()) {
+ bodyText.setOnLongClickListener(new MultiSelectLongClickListener());
+ bodyText.setOnClickListener(new MultiSelectLongClickListener());
+ }
}
private void setContactPhoto(MessageRecord messageRecord) {
@@ -365,12 +396,6 @@ public class ConversationItem extends LinearLayout {
if (slide.hasImage()) {
slide.setThumbnailOn(mmsThumbnail);
mmsThumbnail.setOnClickListener(new ThumbnailClickListener(slide));
- mmsThumbnail.setOnLongClickListener(new OnLongClickListener() {
- @Override
- public boolean onLongClick(View v) {
- return false;
- }
- });
mmsThumbnail.setVisibility(View.VISIBLE);
return;
}
@@ -474,7 +499,9 @@ public class ConversationItem extends LinearLayout {
}
public void onClick(View v) {
- if (MediaPreviewActivity.isContentTypeSupported(slide.getContentType())) {
+ if (!batchSelected.isEmpty()) {
+ selectionClickListener.onItemClick(null, ConversationItem.this, -1, -1);
+ } else if (MediaPreviewActivity.isContentTypeSupported(slide.getContentType())) {
Intent intent = new Intent(context, MediaPreviewActivity.class);
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
intent.setDataAndType(slide.getUri(), slide.getContentType());
@@ -545,6 +572,19 @@ public class ConversationItem extends LinearLayout {
}
}
+ private class MultiSelectLongClickListener implements OnLongClickListener, OnClickListener {
+ @Override
+ public boolean onLongClick(View view) {
+ selectionClickListener.onItemLongClick(null, ConversationItem.this, -1, -1);
+ return true;
+ }
+
+ @Override
+ public void onClick(View view) {
+ selectionClickListener.onItemClick(null, ConversationItem.this, -1, -1);
+ }
+ }
+
private void handleMessageApproval() {
final int title;
final int message;
diff --git a/src/org/thoughtcrime/securesms/database/model/MessageRecord.java b/src/org/thoughtcrime/securesms/database/model/MessageRecord.java
index 491644e865..f8f9a0fc80 100644
--- a/src/org/thoughtcrime/securesms/database/model/MessageRecord.java
+++ b/src/org/thoughtcrime/securesms/database/model/MessageRecord.java
@@ -182,4 +182,15 @@ public abstract class MessageRecord extends DisplayRecord {
return spannable;
}
+
+ public boolean equals(Object other) {
+ return other != null &&
+ other instanceof MessageRecord &&
+ ((MessageRecord) other).getId() == getId() &&
+ ((MessageRecord) other).isMms() == isMms();
+ }
+
+ public int hashCode() {
+ return (int)getId();
+ }
}