mirror of
https://github.com/oxen-io/session-android.git
synced 2023-12-14 02:53:01 +01:00
migrate conversation list to RecyclerView
fixes #2488 fixes #2333 // FREEBIE
This commit is contained in:
parent
cbcd53a8a0
commit
99d3374d35
20 changed files with 293 additions and 282 deletions
|
@ -1,5 +1,4 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:state_enabled="true" android:state_selected="true"
|
||||
android:drawable="@drawable/list_selected_holo_light" />
|
||||
</selector>
|
||||
<item android:drawable="@color/textsecure_primary_alpha33" android:state_selected="true" />
|
||||
</selector>
|
|
@ -1,5 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:state_enabled="true" android:state_selected="true"
|
||||
android:drawable="@drawable/list_selected_holo_dark" />
|
||||
</selector>
|
|
@ -5,18 +5,12 @@
|
|||
android:layout_height="match_parent"
|
||||
android:orientation="vertical">
|
||||
|
||||
<ListView android:id="@android:id/list"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="1.0"
|
||||
android:drawSelectorOnTop="false"
|
||||
android:transcriptMode="normal"
|
||||
android:scrollbarAlwaysDrawVerticalTrack="false"
|
||||
android:scrollbarStyle="insideOverlay"
|
||||
android:stackFromBottom="true"
|
||||
android:fadingEdge="none"
|
||||
android:divider="@android:color/transparent"
|
||||
android:dividerHeight="0dp"
|
||||
android:cacheColorHint="?conversation_background" />
|
||||
<android.support.v7.widget.RecyclerView
|
||||
android:id="@android:id/list"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="1.0"
|
||||
android:scrollbars="vertical"
|
||||
android:cacheColorHint="?conversation_background" />
|
||||
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
|
|
|
@ -4,11 +4,9 @@
|
|||
android:layout_height="wrap_content"
|
||||
android:paddingRight="10dip"
|
||||
android:orientation="vertical"
|
||||
android:background="?conversation_item_background"
|
||||
android:background="@drawable/conversation_item_background"
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
xmlns:dots="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
xmlns:tools="http://schemas.android.com/tools">
|
||||
|
||||
<TextView android:id="@+id/group_message_status"
|
||||
android:layout_width="wrap_content"
|
||||
|
|
|
@ -2,12 +2,11 @@
|
|||
<org.thoughtcrime.securesms.ConversationItem
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:id="@+id/conversation_item"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:background="?conversation_item_background">
|
||||
android:background="@drawable/conversation_item_background">
|
||||
|
||||
<RelativeLayout android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
|
|
|
@ -133,7 +133,6 @@
|
|||
|
||||
<item name="quick_camera_icon">@drawable/quick_camera_light</item>
|
||||
|
||||
<item name="conversation_item_background">@drawable/conversation_item_background</item>
|
||||
<item name="conversation_item_sent_indicator_text_background">@drawable/conversation_item_sent_indicator_text_shape</item>
|
||||
|
||||
<item name="dialog_info_icon">@drawable/ic_info_outline_light</item>
|
||||
|
@ -204,7 +203,6 @@
|
|||
|
||||
<item name="conversation_group_member_name">#99ffffff</item>
|
||||
|
||||
<item name="conversation_item_background">@drawable/conversation_item_background_dark</item>
|
||||
<item name="conversation_item_bubble_background">#ff333333</item>
|
||||
<item name="conversation_item_sent_text_primary_color">#ffffffff</item>
|
||||
<item name="conversation_item_sent_text_secondary_color">#aaeeeeee</item>
|
||||
|
|
17
src/org/thoughtcrime/securesms/BindableConversationItem.java
Normal file
17
src/org/thoughtcrime/securesms/BindableConversationItem.java
Normal file
|
@ -0,0 +1,17 @@
|
|||
package org.thoughtcrime.securesms;
|
||||
|
||||
import android.support.annotation.NonNull;
|
||||
|
||||
import org.thoughtcrime.securesms.crypto.MasterSecret;
|
||||
import org.thoughtcrime.securesms.database.model.MessageRecord;
|
||||
|
||||
import java.util.Locale;
|
||||
import java.util.Set;
|
||||
|
||||
public interface BindableConversationItem extends Unbindable {
|
||||
void bind(@NonNull MasterSecret masterSecret,
|
||||
@NonNull MessageRecord messageRecord,
|
||||
@NonNull Locale locale,
|
||||
@NonNull Set<MessageRecord> batchSelected,
|
||||
boolean groupThread, boolean pushDestination);
|
||||
}
|
|
@ -1368,11 +1368,6 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
|||
public void onFocusChange(View v, boolean hasFocus) {}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setComposeText(String text) {
|
||||
this.composeText.setText(text);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setThreadId(long threadId) {
|
||||
this.threadId = threadId;
|
||||
|
|
|
@ -18,13 +18,18 @@ package org.thoughtcrime.securesms;
|
|||
|
||||
import android.content.Context;
|
||||
import android.database.Cursor;
|
||||
import android.support.annotation.LayoutRes;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.View.OnClickListener;
|
||||
import android.view.View.OnLongClickListener;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.AbsListView;
|
||||
import android.support.v4.widget.CursorAdapter;
|
||||
|
||||
import org.thoughtcrime.securesms.crypto.MasterSecret;
|
||||
import org.thoughtcrime.securesms.database.CursorRecyclerViewAdapter;
|
||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||
import org.thoughtcrime.securesms.database.MmsSmsColumns;
|
||||
import org.thoughtcrime.securesms.database.MmsSmsDatabase;
|
||||
|
@ -39,7 +44,7 @@ import java.util.Locale;
|
|||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.thoughtcrime.securesms.ConversationFragment.SelectionClickListener;
|
||||
import org.thoughtcrime.securesms.util.ViewUtil;
|
||||
|
||||
/**
|
||||
* A cursor adapter for a conversation thread. Ultimately
|
||||
|
@ -49,7 +54,9 @@ import org.thoughtcrime.securesms.ConversationFragment.SelectionClickListener;
|
|||
* @author Moxie Marlinspike
|
||||
*
|
||||
*/
|
||||
public class ConversationAdapter extends CursorAdapter implements AbsListView.RecyclerListener {
|
||||
public class ConversationAdapter <V extends View & BindableConversationItem>
|
||||
extends CursorRecyclerViewAdapter<ConversationAdapter.ViewHolder>
|
||||
{
|
||||
|
||||
private static final int MAX_CACHE_SIZE = 40;
|
||||
private final Map<String,SoftReference<MessageRecord>> messageRecordCache =
|
||||
|
@ -61,46 +68,46 @@ public class ConversationAdapter extends CursorAdapter implements AbsListView.Re
|
|||
|
||||
private final Set<MessageRecord> batchSelected = Collections.synchronizedSet(new HashSet<MessageRecord>());
|
||||
|
||||
private final SelectionClickListener selectionClickListener;
|
||||
private final Context context;
|
||||
private final ItemClickListener clickListener;
|
||||
private final MasterSecret masterSecret;
|
||||
private final Locale locale;
|
||||
private final boolean groupThread;
|
||||
private final boolean pushDestination;
|
||||
private final MmsSmsDatabase db;
|
||||
private final LayoutInflater inflater;
|
||||
|
||||
public ConversationAdapter(Context context, MasterSecret masterSecret, Locale locale,
|
||||
SelectionClickListener selectionClickListener, boolean groupThread,
|
||||
boolean pushDestination)
|
||||
{
|
||||
super(context, null, 0);
|
||||
this.context = context;
|
||||
this.masterSecret = masterSecret;
|
||||
this.locale = locale;
|
||||
this.selectionClickListener = selectionClickListener;
|
||||
this.groupThread = groupThread;
|
||||
this.pushDestination = pushDestination;
|
||||
this.inflater = LayoutInflater.from(context);
|
||||
protected static class ViewHolder extends RecyclerView.ViewHolder {
|
||||
public <V extends View & BindableConversationItem> ViewHolder(final @NonNull V itemView) {
|
||||
super(itemView);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public <V extends View & BindableConversationItem> V getView() {
|
||||
return (V)itemView;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bindView(View view, Context context, Cursor cursor) {
|
||||
long id = cursor.getLong(cursor.getColumnIndexOrThrow(SmsDatabase.ID));
|
||||
String type = cursor.getString(cursor.getColumnIndexOrThrow(MmsSmsDatabase.TRANSPORT));
|
||||
MessageRecord messageRecord = getMessageRecord(id, cursor, type);
|
||||
public interface ItemClickListener {
|
||||
void onItemClick(ConversationItem item);
|
||||
void onItemLongClick(ConversationItem item);
|
||||
}
|
||||
|
||||
switch (getItemViewType(cursor)) {
|
||||
case MESSAGE_TYPE_INCOMING:
|
||||
case MESSAGE_TYPE_OUTGOING:
|
||||
((ConversationItem) view).set(masterSecret, messageRecord, locale, batchSelected,
|
||||
selectionClickListener, groupThread, pushDestination);
|
||||
break;
|
||||
case MESSAGE_TYPE_UPDATE:
|
||||
((ConversationUpdateItem)view).set(messageRecord);
|
||||
break;
|
||||
default:
|
||||
throw new AssertionError("Unknown type!");
|
||||
}
|
||||
public ConversationAdapter(@NonNull Context context,
|
||||
@NonNull MasterSecret masterSecret,
|
||||
@NonNull Locale locale,
|
||||
@Nullable ItemClickListener clickListener,
|
||||
@Nullable Cursor cursor,
|
||||
boolean groupThread,
|
||||
boolean pushDestination)
|
||||
{
|
||||
super(context, cursor);
|
||||
this.masterSecret = masterSecret;
|
||||
this.locale = locale;
|
||||
this.clickListener = clickListener;
|
||||
this.groupThread = groupThread;
|
||||
this.pushDestination = pushDestination;
|
||||
this.inflater = LayoutInflater.from(context);
|
||||
this.db = DatabaseFactory.getMmsSmsDatabase(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -109,40 +116,50 @@ public class ConversationAdapter extends CursorAdapter implements AbsListView.Re
|
|||
super.changeCursor(cursor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public View newView(Context context, Cursor cursor, ViewGroup parent) {
|
||||
View view;
|
||||
@Override public void onBindViewHolder(ViewHolder viewHolder, @NonNull Cursor cursor) {
|
||||
long id = cursor.getLong(cursor.getColumnIndexOrThrow(SmsDatabase.ID));
|
||||
String type = cursor.getString(cursor.getColumnIndexOrThrow(MmsSmsDatabase.TRANSPORT));
|
||||
MessageRecord messageRecord = getMessageRecord(id, cursor, type);
|
||||
|
||||
int type = getItemViewType(cursor);
|
||||
viewHolder.getView().bind(masterSecret, messageRecord, locale, batchSelected, groupThread, pushDestination);
|
||||
}
|
||||
|
||||
switch (type) {
|
||||
case ConversationAdapter.MESSAGE_TYPE_OUTGOING:
|
||||
view = inflater.inflate(R.layout.conversation_item_sent, parent, false);
|
||||
break;
|
||||
case ConversationAdapter.MESSAGE_TYPE_INCOMING:
|
||||
view = inflater.inflate(R.layout.conversation_item_received, parent, false);
|
||||
break;
|
||||
case ConversationAdapter.MESSAGE_TYPE_UPDATE:
|
||||
view = inflater.inflate(R.layout.conversation_item_update, parent, false);
|
||||
break;
|
||||
default: throw new IllegalArgumentException("unsupported item view type given to ConversationAdapter");
|
||||
@Override public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
|
||||
final V itemView = ViewUtil.inflate(inflater, parent, getLayoutForViewType(viewType));
|
||||
if (viewType == MESSAGE_TYPE_INCOMING || viewType == MESSAGE_TYPE_OUTGOING) {
|
||||
itemView.setOnClickListener(new OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
if (clickListener != null) clickListener.onItemClick((ConversationItem)itemView);
|
||||
}
|
||||
});
|
||||
itemView.setOnLongClickListener(new OnLongClickListener() {
|
||||
@Override
|
||||
public boolean onLongClick(View view) {
|
||||
if (clickListener != null) clickListener.onItemLongClick((ConversationItem)itemView);
|
||||
return true;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return view;
|
||||
return new ViewHolder(itemView);
|
||||
}
|
||||
|
||||
@Override public void onViewRecycled(ViewHolder holder) {
|
||||
holder.getView().unbind();
|
||||
}
|
||||
|
||||
private @LayoutRes int getLayoutForViewType(int viewType) {
|
||||
switch (viewType) {
|
||||
case ConversationAdapter.MESSAGE_TYPE_OUTGOING: return R.layout.conversation_item_sent;
|
||||
case ConversationAdapter.MESSAGE_TYPE_INCOMING: return R.layout.conversation_item_received;
|
||||
case ConversationAdapter.MESSAGE_TYPE_UPDATE: return R.layout.conversation_item_update;
|
||||
default: throw new IllegalArgumentException("unsupported item view type given to ConversationAdapter");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getViewTypeCount() {
|
||||
return 3;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemViewType(int position) {
|
||||
Cursor cursor = (Cursor)getItem(position);
|
||||
return getItemViewType(cursor);
|
||||
}
|
||||
|
||||
private int getItemViewType(Cursor cursor) {
|
||||
public int getItemViewType(@NonNull Cursor cursor) {
|
||||
long id = cursor.getLong(cursor.getColumnIndexOrThrow(MmsSmsColumns.ID));
|
||||
String type = cursor.getString(cursor.getColumnIndexOrThrow(MmsSmsDatabase.TRANSPORT));
|
||||
MessageRecord messageRecord = getMessageRecord(id, cursor, type);
|
||||
|
@ -153,43 +170,33 @@ public class ConversationAdapter extends CursorAdapter implements AbsListView.Re
|
|||
}
|
||||
|
||||
private MessageRecord getMessageRecord(long messageId, Cursor cursor, String type) {
|
||||
SoftReference<MessageRecord> reference = messageRecordCache.get(type + messageId);
|
||||
|
||||
final SoftReference<MessageRecord> reference = messageRecordCache.get(type + messageId);
|
||||
if (reference != null) {
|
||||
MessageRecord record = reference.get();
|
||||
|
||||
if (record != null)
|
||||
return record;
|
||||
final MessageRecord record = reference.get();
|
||||
if (record != null) return record;
|
||||
}
|
||||
|
||||
MmsSmsDatabase.Reader reader = DatabaseFactory.getMmsSmsDatabase(context)
|
||||
.readerFor(cursor, masterSecret);
|
||||
|
||||
MessageRecord messageRecord = reader.getCurrent();
|
||||
|
||||
final MessageRecord messageRecord = db.readerFor(cursor, masterSecret).getCurrent();
|
||||
messageRecordCache.put(type + messageId, new SoftReference<>(messageRecord));
|
||||
|
||||
return messageRecord;
|
||||
}
|
||||
|
||||
public void close() {
|
||||
this.getCursor().close();
|
||||
getCursor().close();
|
||||
}
|
||||
|
||||
public void toggleBatchSelected(MessageRecord messageRecord) {
|
||||
if (batchSelected.contains(messageRecord)) {
|
||||
batchSelected.remove(messageRecord);
|
||||
} else {
|
||||
public void toggleSelection(MessageRecord messageRecord) {
|
||||
if (!batchSelected.remove(messageRecord)) {
|
||||
batchSelected.add(messageRecord);
|
||||
}
|
||||
}
|
||||
|
||||
public Set<MessageRecord> getBatchSelected() {
|
||||
return batchSelected;
|
||||
public void clearSelection() {
|
||||
batchSelected.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMovedToScrapHeap(View view) {
|
||||
((Unbindable) view).unbind();
|
||||
public Set<MessageRecord> getSelectedItems() {
|
||||
return Collections.unmodifiableSet(new HashSet<>(batchSelected));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,12 +8,13 @@ import android.database.Cursor;
|
|||
import android.os.AsyncTask;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.support.v4.app.ListFragment;
|
||||
import android.support.v4.app.Fragment;
|
||||
import android.support.v4.app.LoaderManager;
|
||||
import android.support.v4.content.Loader;
|
||||
import android.support.v4.widget.CursorAdapter;
|
||||
import android.support.v7.app.AppCompatActivity;
|
||||
import android.support.v7.view.ActionMode;
|
||||
import android.support.v7.widget.LinearLayoutManager;
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
import android.text.ClipboardManager;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
|
@ -24,12 +25,11 @@ import android.view.MenuItem;
|
|||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.Window;
|
||||
import android.widget.AdapterView;
|
||||
import android.widget.ListView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.afollestad.materialdialogs.AlertDialogWrapper;
|
||||
|
||||
import org.thoughtcrime.securesms.ConversationAdapter.ItemClickListener;
|
||||
import org.thoughtcrime.securesms.crypto.MasterSecret;
|
||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||
import org.thoughtcrime.securesms.database.MmsSmsDatabase;
|
||||
|
@ -45,21 +45,22 @@ 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 org.thoughtcrime.securesms.util.ServiceUtil;
|
||||
import org.thoughtcrime.securesms.util.ViewUtil;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Set;
|
||||
|
||||
public class ConversationFragment extends ListFragment
|
||||
public class ConversationFragment extends Fragment
|
||||
implements LoaderManager.LoaderCallbacks<Cursor>
|
||||
{
|
||||
private static final String TAG = ConversationFragment.class.getSimpleName();
|
||||
|
||||
private final ActionModeCallback actionModeCallback = new ActionModeCallback();
|
||||
private final SelectionClickListener selectionClickListener = new ConversationFragmentSelectionClickListener();
|
||||
private final ActionModeCallback actionModeCallback = new ActionModeCallback();
|
||||
private final ItemClickListener selectionClickListener = new ConversationFragmentItemClickListener();
|
||||
|
||||
private ConversationFragmentListener listener;
|
||||
|
||||
|
@ -68,6 +69,7 @@ public class ConversationFragment extends ListFragment
|
|||
private long threadId;
|
||||
private ActionMode actionMode;
|
||||
private Locale locale;
|
||||
private RecyclerView list;
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle icicle) {
|
||||
|
@ -78,16 +80,24 @@ public class ConversationFragment extends ListFragment
|
|||
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle bundle) {
|
||||
return inflater.inflate(R.layout.conversation_fragment, container, false);
|
||||
final View view = inflater.inflate(R.layout.conversation_fragment, container, false);
|
||||
list = ViewUtil.findById(view, android.R.id.list);
|
||||
return view;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityCreated(Bundle bundle) {
|
||||
super.onActivityCreated(bundle);
|
||||
|
||||
final LinearLayoutManager layoutManager = new LinearLayoutManager(getActivity());
|
||||
layoutManager.setOrientation(LinearLayoutManager.VERTICAL);
|
||||
layoutManager.setReverseLayout(true);
|
||||
list.setHasFixedSize(false);
|
||||
list.setScrollContainer(true);
|
||||
list.setLayoutManager(layoutManager);
|
||||
|
||||
initializeResources();
|
||||
initializeListAdapter();
|
||||
initializeContextualActionBar();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -100,8 +110,8 @@ public class ConversationFragment extends ListFragment
|
|||
public void onResume() {
|
||||
super.onResume();
|
||||
|
||||
if (getListAdapter() != null) {
|
||||
((ConversationAdapter) getListAdapter()).notifyDataSetChanged();
|
||||
if (list.getAdapter() != null) {
|
||||
list.getAdapter().notifyDataSetChanged();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -125,21 +135,15 @@ public class ConversationFragment extends ListFragment
|
|||
|
||||
private void initializeListAdapter() {
|
||||
if (this.recipients != null && this.threadId != -1) {
|
||||
this.setListAdapter(new ConversationAdapter(getActivity(), masterSecret, locale, selectionClickListener,
|
||||
(!this.recipients.isSingleRecipient()) || this.recipients.isGroupRecipient(),
|
||||
DirectoryHelper.isPushDestination(getActivity(), this.recipients)));
|
||||
getListView().setRecyclerListener((ConversationAdapter)getListAdapter());
|
||||
list.setAdapter(new ConversationAdapter(getActivity(), masterSecret, locale, selectionClickListener, null,
|
||||
(!this.recipients.isSingleRecipient()) || this.recipients.isGroupRecipient(),
|
||||
DirectoryHelper.isPushDestination(getActivity(), this.recipients)));
|
||||
getLoaderManager().restartLoader(0, null, this);
|
||||
}
|
||||
}
|
||||
|
||||
private void initializeContextualActionBar() {
|
||||
getListView().setOnItemClickListener(selectionClickListener);
|
||||
getListView().setOnItemLongClickListener(selectionClickListener);
|
||||
}
|
||||
|
||||
private void setCorrectMenuVisibility(Menu menu) {
|
||||
List<MessageRecord> messageRecords = getSelectedMessageRecords();
|
||||
Set<MessageRecord> messageRecords = getListAdapter().getSelectedItems();
|
||||
|
||||
if (actionMode != null && messageRecords.size() == 0) {
|
||||
actionMode.finish();
|
||||
|
@ -152,7 +156,7 @@ public class ConversationFragment extends ListFragment
|
|||
menu.findItem(R.id.menu_context_save_attachment).setVisible(false);
|
||||
menu.findItem(R.id.menu_context_resend).setVisible(false);
|
||||
} else {
|
||||
MessageRecord messageRecord = messageRecords.get(0);
|
||||
MessageRecord messageRecord = messageRecords.iterator().next();
|
||||
|
||||
menu.findItem(R.id.menu_context_resend).setVisible(messageRecord.isFailed());
|
||||
menu.findItem(R.id.menu_context_save_attachment).setVisible(messageRecord.isMms() &&
|
||||
|
@ -165,15 +169,15 @@ public class ConversationFragment extends ListFragment
|
|||
}
|
||||
}
|
||||
|
||||
private MessageRecord getSelectedMessageRecord() {
|
||||
List<MessageRecord> messageRecords = getSelectedMessageRecords();
|
||||
|
||||
if (messageRecords.size() == 1) return messageRecords.get(0);
|
||||
else throw new AssertionError();
|
||||
private ConversationAdapter getListAdapter() {
|
||||
return (ConversationAdapter) list.getAdapter();
|
||||
}
|
||||
|
||||
private List<MessageRecord> getSelectedMessageRecords() {
|
||||
return new LinkedList<>(((ConversationAdapter)getListAdapter()).getBatchSelected());
|
||||
private MessageRecord getSelectedMessageRecord() {
|
||||
Set<MessageRecord> messageRecords = getListAdapter().getSelectedItems();
|
||||
|
||||
if (messageRecords.size() == 1) return messageRecords.iterator().next();
|
||||
else throw new AssertionError();
|
||||
}
|
||||
|
||||
public void reload(Recipients recipients, long threadId) {
|
||||
|
@ -186,17 +190,18 @@ public class ConversationFragment extends ListFragment
|
|||
}
|
||||
|
||||
public void scrollToBottom() {
|
||||
final ListView list = getListView();
|
||||
list.post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
list.setSelection(getListAdapter().getCount() - 1);
|
||||
list.stopScroll();
|
||||
list.smoothScrollToPosition(0);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void handleCopyMessage(final List<MessageRecord> messageRecords) {
|
||||
Collections.sort(messageRecords, new Comparator<MessageRecord>() {
|
||||
private void handleCopyMessage(final Set<MessageRecord> messageRecords) {
|
||||
List<MessageRecord> messageList = new LinkedList<>(messageRecords);
|
||||
Collections.sort(messageList, new Comparator<MessageRecord>() {
|
||||
@Override
|
||||
public int compare(MessageRecord lhs, MessageRecord rhs) {
|
||||
if (lhs.getDateReceived() < rhs.getDateReceived()) return -1;
|
||||
|
@ -209,7 +214,7 @@ public class ConversationFragment extends ListFragment
|
|||
ClipboardManager clipboard = (ClipboardManager) getActivity().getSystemService(Context.CLIPBOARD_SERVICE);
|
||||
boolean first = true;
|
||||
|
||||
for (MessageRecord messageRecord : messageRecords) {
|
||||
for (MessageRecord messageRecord : messageList) {
|
||||
String body = messageRecord.getDisplayBody().toString();
|
||||
|
||||
if (body != null) {
|
||||
|
@ -225,7 +230,7 @@ public class ConversationFragment extends ListFragment
|
|||
clipboard.setText(result);
|
||||
}
|
||||
|
||||
private void handleDeleteMessages(final List<MessageRecord> messageRecords) {
|
||||
private void handleDeleteMessages(final Set<MessageRecord> messageRecords) {
|
||||
AlertDialogWrapper.Builder builder = new AlertDialogWrapper.Builder(getActivity());
|
||||
builder.setTitle(R.string.ConversationFragment_confirm_message_delete);
|
||||
builder.setIconAttribute(R.attr.dialog_alert_icon);
|
||||
|
@ -319,53 +324,41 @@ public class ConversationFragment extends ListFragment
|
|||
|
||||
@Override
|
||||
public void onLoadFinished(Loader<Cursor> arg0, Cursor cursor) {
|
||||
if (getListAdapter() != null) {
|
||||
((CursorAdapter) getListAdapter()).changeCursor(cursor);
|
||||
if (list.getAdapter() != null) {
|
||||
getListAdapter().changeCursor(cursor);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoaderReset(Loader<Cursor> arg0) {
|
||||
if (getListAdapter() != null) {
|
||||
((CursorAdapter) getListAdapter()).changeCursor(null);
|
||||
if (list.getAdapter() != null) {
|
||||
getListAdapter().changeCursor(null);
|
||||
}
|
||||
}
|
||||
|
||||
public interface ConversationFragmentListener {
|
||||
public void setComposeText(String text);
|
||||
|
||||
public void setThreadId(long threadId);
|
||||
void setThreadId(long threadId);
|
||||
}
|
||||
|
||||
public interface SelectionClickListener extends
|
||||
AdapterView.OnItemLongClickListener, AdapterView.OnItemClickListener {}
|
||||
private class ConversationFragmentItemClickListener implements ItemClickListener {
|
||||
|
||||
private class ConversationFragmentSelectionClickListener
|
||||
implements SelectionClickListener
|
||||
{
|
||||
@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();
|
||||
@Override public void onItemClick(ConversationItem item) {
|
||||
if (actionMode != null) {
|
||||
MessageRecord messageRecord = item.getMessageRecord();
|
||||
((ConversationAdapter) list.getAdapter()).toggleSelection(messageRecord);
|
||||
list.getAdapter().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();
|
||||
@Override public void onItemLongClick(ConversationItem item) {
|
||||
if (actionMode == null) {
|
||||
((ConversationAdapter) list.getAdapter()).toggleSelection(item.getMessageRecord());
|
||||
list.getAdapter().notifyDataSetChanged();
|
||||
|
||||
actionMode = ((AppCompatActivity)getActivity()).startSupportActionMode(actionModeCallback);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -395,8 +388,8 @@ public class ConversationFragment extends ListFragment
|
|||
|
||||
@Override
|
||||
public void onDestroyActionMode(ActionMode mode) {
|
||||
((ConversationAdapter)getListAdapter()).getBatchSelected().clear();
|
||||
((ConversationAdapter)getListAdapter()).notifyDataSetChanged();
|
||||
((ConversationAdapter)list.getAdapter()).clearSelection();
|
||||
list.getAdapter().notifyDataSetChanged();
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
getActivity().getWindow().setStatusBarColor(statusBarColor);
|
||||
|
@ -409,11 +402,11 @@ public class ConversationFragment extends ListFragment
|
|||
public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
|
||||
switch(item.getItemId()) {
|
||||
case R.id.menu_context_copy:
|
||||
handleCopyMessage(getSelectedMessageRecords());
|
||||
handleCopyMessage(getListAdapter().getSelectedItems());
|
||||
actionMode.finish();
|
||||
return true;
|
||||
case R.id.menu_context_delete_message:
|
||||
handleDeleteMessages(getSelectedMessageRecords());
|
||||
handleDeleteMessages(getListAdapter().getSelectedItems());
|
||||
actionMode.finish();
|
||||
return true;
|
||||
case R.id.menu_context_details:
|
||||
|
@ -436,5 +429,5 @@ public class ConversationFragment extends ListFragment
|
|||
|
||||
return false;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,10 +23,10 @@ import android.content.Intent;
|
|||
import android.content.res.TypedArray;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.PorterDuff;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.os.Build;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.text.TextUtils;
|
||||
import android.text.util.Linkify;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.Log;
|
||||
import android.view.LayoutInflater;
|
||||
|
@ -40,7 +40,6 @@ import android.widget.Toast;
|
|||
|
||||
import com.afollestad.materialdialogs.AlertDialogWrapper;
|
||||
|
||||
import org.thoughtcrime.securesms.ConversationFragment.SelectionClickListener;
|
||||
import org.thoughtcrime.securesms.components.AvatarImageView;
|
||||
import org.thoughtcrime.securesms.components.ThumbnailView;
|
||||
import org.thoughtcrime.securesms.crypto.MasterSecret;
|
||||
|
@ -74,7 +73,9 @@ import java.util.Set;
|
|||
*
|
||||
*/
|
||||
|
||||
public class ConversationItem extends LinearLayout implements Recipient.RecipientModifiedListener, Unbindable {
|
||||
public class ConversationItem extends LinearLayout
|
||||
implements Recipient.RecipientModifiedListener, BindableConversationItem
|
||||
{
|
||||
private final static String TAG = ConversationItem.class.getSimpleName();
|
||||
|
||||
private MessageRecord messageRecord;
|
||||
|
@ -97,16 +98,13 @@ public class ConversationItem extends LinearLayout implements Recipient.Recipien
|
|||
private View pendingIndicator;
|
||||
private ImageView pendingApprovalIndicator;
|
||||
|
||||
private StatusManager statusManager;
|
||||
private Set<MessageRecord> batchSelected;
|
||||
private SelectionClickListener selectionClickListener;
|
||||
private ThumbnailView mediaThumbnail;
|
||||
private Button mmsDownloadButton;
|
||||
private TextView mmsDownloadingLabel;
|
||||
private StatusManager statusManager;
|
||||
private Set<MessageRecord> batchSelected;
|
||||
private ThumbnailView mediaThumbnail;
|
||||
private Button mmsDownloadButton;
|
||||
private TextView mmsDownloadingLabel;
|
||||
|
||||
private int defaultBubbleColor;
|
||||
private Drawable selectedBackground;
|
||||
private Drawable normalBackground;
|
||||
private int defaultBubbleColor;
|
||||
|
||||
private final MmsDownloadClickListener mmsDownloadClickListener = new MmsDownloadClickListener();
|
||||
private final MmsPreferencesClickListener mmsPreferencesClickListener = new MmsPreferencesClickListener();
|
||||
|
@ -114,9 +112,8 @@ public class ConversationItem extends LinearLayout implements Recipient.Recipien
|
|||
private final Context context;
|
||||
|
||||
public ConversationItem(Context context) {
|
||||
super(context);
|
||||
this.context = context;
|
||||
}
|
||||
this(context, null);
|
||||
}
|
||||
|
||||
public ConversationItem(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
|
@ -131,7 +128,7 @@ public class ConversationItem extends LinearLayout implements Recipient.Recipien
|
|||
ViewGroup pendingIndicatorStub = (ViewGroup) findViewById(R.id.pending_indicator_stub);
|
||||
|
||||
if (pendingIndicatorStub != null) {
|
||||
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
||||
LayoutInflater inflater = LayoutInflater.from(context);
|
||||
if (Build.VERSION.SDK_INT >= 11) inflater.inflate(R.layout.conversation_item_pending_v11, pendingIndicatorStub, true);
|
||||
else inflater.inflate(R.layout.conversation_item_pending, pendingIndicatorStub, true);
|
||||
}
|
||||
|
@ -154,33 +151,33 @@ public class ConversationItem extends LinearLayout implements Recipient.Recipien
|
|||
this.statusManager = new StatusManager(pendingIndicator, sentIndicator, deliveredIndicator, failedIndicator, pendingApprovalIndicator);
|
||||
|
||||
setOnClickListener(clickListener);
|
||||
PassthroughClickListener passthroughClickListener = new PassthroughClickListener();
|
||||
if (mmsDownloadButton != null) mmsDownloadButton.setOnClickListener(mmsDownloadClickListener);
|
||||
if (mediaThumbnail != null) {
|
||||
mediaThumbnail.setThumbnailClickListener(new ThumbnailClickListener());
|
||||
mediaThumbnail.setOnLongClickListener(new MultiSelectLongClickListener());
|
||||
mediaThumbnail.setDownloadClickListener(new ThumbnailDownloadClickListener());
|
||||
}
|
||||
mediaThumbnail.setThumbnailClickListener(new ThumbnailClickListener());
|
||||
mediaThumbnail.setDownloadClickListener(new ThumbnailDownloadClickListener());
|
||||
mediaThumbnail.setOnLongClickListener(passthroughClickListener);
|
||||
bodyText.setOnLongClickListener(passthroughClickListener);
|
||||
bodyText.setOnClickListener(passthroughClickListener);
|
||||
}
|
||||
|
||||
public void set(@NonNull MasterSecret masterSecret,
|
||||
@NonNull MessageRecord messageRecord,
|
||||
@NonNull Locale locale,
|
||||
@NonNull Set<MessageRecord> batchSelected,
|
||||
@NonNull SelectionClickListener selectionClickListener,
|
||||
boolean groupThread, boolean pushDestination)
|
||||
@Override
|
||||
public void bind(@NonNull MasterSecret masterSecret,
|
||||
@NonNull MessageRecord messageRecord,
|
||||
@NonNull Locale locale,
|
||||
@NonNull Set<MessageRecord> batchSelected,
|
||||
boolean groupThread, boolean pushDestination)
|
||||
{
|
||||
this.masterSecret = masterSecret;
|
||||
this.messageRecord = messageRecord;
|
||||
this.locale = locale;
|
||||
this.batchSelected = batchSelected;
|
||||
this.selectionClickListener = selectionClickListener;
|
||||
this.groupThread = groupThread;
|
||||
this.pushDestination = pushDestination;
|
||||
this.recipient = messageRecord.getIndividualRecipient();
|
||||
|
||||
this.recipient.addListener(this);
|
||||
|
||||
setSelectionBackgroundDrawables(messageRecord);
|
||||
setSelectionState(messageRecord);
|
||||
setBodyText(messageRecord);
|
||||
setBubbleState(messageRecord, recipient);
|
||||
setStatusIcons(messageRecord);
|
||||
|
@ -198,8 +195,6 @@ public class ConversationItem extends LinearLayout implements Recipient.Recipien
|
|||
final TypedArray attrs = context.obtainStyledAttributes(attributes);
|
||||
|
||||
defaultBubbleColor = attrs.getColor(0, Color.WHITE);
|
||||
selectedBackground = attrs.getDrawable(1);
|
||||
normalBackground = attrs.getDrawable(2);
|
||||
attrs.recycle();
|
||||
}
|
||||
|
||||
|
@ -227,12 +222,11 @@ public class ConversationItem extends LinearLayout implements Recipient.Recipien
|
|||
}
|
||||
}
|
||||
|
||||
private void setSelectionBackgroundDrawables(MessageRecord messageRecord) {
|
||||
if (batchSelected.contains(messageRecord)) {
|
||||
setBackgroundDrawable(selectedBackground);
|
||||
} else {
|
||||
setBackgroundDrawable(normalBackground);
|
||||
}
|
||||
private void setSelectionState(MessageRecord messageRecord) {
|
||||
setSelected(batchSelected.contains(messageRecord));
|
||||
mediaThumbnail.setClickable(batchSelected.isEmpty());
|
||||
mediaThumbnail.setLongClickable(batchSelected.isEmpty());
|
||||
bodyText.setAutoLinkMask(batchSelected.isEmpty() ? Linkify.ALL : 0);
|
||||
}
|
||||
|
||||
private boolean isCaptionlessMms(MessageRecord messageRecord) {
|
||||
|
@ -255,11 +249,6 @@ public class ConversationItem extends LinearLayout implements Recipient.Recipien
|
|||
bodyText.setText(messageRecord.getDisplayBody());
|
||||
bodyText.setVisibility(View.VISIBLE);
|
||||
}
|
||||
|
||||
if (bodyText.isClickable() && bodyText.isFocusable()) {
|
||||
bodyText.setOnLongClickListener(new MultiSelectLongClickListener());
|
||||
bodyText.setOnClickListener(new MultiSelectLongClickListener());
|
||||
}
|
||||
}
|
||||
|
||||
private void setMediaAttributes(MessageRecord messageRecord) {
|
||||
|
@ -334,12 +323,9 @@ public class ConversationItem extends LinearLayout implements Recipient.Recipien
|
|||
|
||||
private void setEvents(MessageRecord messageRecord) {
|
||||
setClickable(batchSelected.isEmpty() &&
|
||||
(messageRecord.isFailed() ||
|
||||
(messageRecord.isFailed() ||
|
||||
messageRecord.isPendingInsecureSmsFallback() ||
|
||||
messageRecord.isBundleKeyExchange()));
|
||||
if (messageRecord.isFailed()) {
|
||||
setOnLongClickListener(new MultiSelectLongClickListener());
|
||||
}
|
||||
}
|
||||
|
||||
private void setGroupMessageStatus(MessageRecord messageRecord, Recipient recipient) {
|
||||
|
@ -410,7 +396,7 @@ public class ConversationItem extends LinearLayout implements Recipient.Recipien
|
|||
}
|
||||
|
||||
private class ThumbnailDownloadClickListener implements ThumbnailView.ThumbnailClickListener {
|
||||
@Override public void onClick(View v, Slide slide) {
|
||||
@Override public void onClick(View v, final Slide slide) {
|
||||
DatabaseFactory.getPartDatabase(context).setTransferState(messageRecord.getId(), slide.getPart().getPartId(), PartDatabase.TRANSFER_PROGRESS_STARTED);
|
||||
}
|
||||
}
|
||||
|
@ -430,10 +416,9 @@ public class ConversationItem extends LinearLayout implements Recipient.Recipien
|
|||
}
|
||||
|
||||
public void onClick(final View v, final Slide slide) {
|
||||
if (!batchSelected.isEmpty()) {
|
||||
selectionClickListener.onItemClick(null, ConversationItem.this, -1, -1);
|
||||
} else if (MediaPreviewActivity.isContentTypeSupported(slide.getContentType()) &&
|
||||
slide.getThumbnailUri() != null)
|
||||
if (batchSelected.isEmpty() &&
|
||||
MediaPreviewActivity.isContentTypeSupported(slide.getContentType()) &&
|
||||
slide.getThumbnailUri() != null)
|
||||
{
|
||||
Intent intent = new Intent(context, MediaPreviewActivity.class);
|
||||
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
|
||||
|
@ -483,11 +468,22 @@ public class ConversationItem extends LinearLayout implements Recipient.Recipien
|
|||
}
|
||||
}
|
||||
|
||||
private class PassthroughClickListener implements View.OnLongClickListener, View.OnClickListener {
|
||||
|
||||
@Override public boolean onLongClick(View v) {
|
||||
performLongClick();
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override public void onClick(View v) {
|
||||
performClick();
|
||||
}
|
||||
}
|
||||
private class ClickListener implements View.OnClickListener {
|
||||
public void onClick(View v) {
|
||||
if (messageRecord.isFailed() && !batchSelected.isEmpty()) {
|
||||
selectionClickListener.onItemClick(null, ConversationItem.this, -1, -1);
|
||||
} else if(messageRecord.isFailed()) {
|
||||
if (!batchSelected.isEmpty()) return;
|
||||
|
||||
if (messageRecord.isFailed()) {
|
||||
Intent intent = new Intent(context, MessageDetailsActivity.class);
|
||||
intent.putExtra(MessageDetailsActivity.MASTER_SECRET_EXTRA, masterSecret);
|
||||
intent.putExtra(MessageDetailsActivity.MESSAGE_ID_EXTRA, messageRecord.getId());
|
||||
|
@ -502,19 +498,6 @@ public class ConversationItem extends LinearLayout implements Recipient.Recipien
|
|||
}
|
||||
}
|
||||
|
||||
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;
|
||||
|
|
|
@ -100,8 +100,12 @@ public class ConversationListAdapter extends CursorRecyclerViewAdapter<Conversat
|
|||
parent, false), clickListener);
|
||||
}
|
||||
|
||||
@Override public void onViewRecycled(ViewHolder holder) {
|
||||
holder.getItem().unbind();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(ViewHolder viewHolder, Cursor cursor) {
|
||||
public void onBindViewHolder(ViewHolder viewHolder, @NonNull Cursor cursor) {
|
||||
ThreadDatabase.Reader reader = threadDatabase.readerFor(cursor, masterCipher);
|
||||
ThreadRecord record = reader.getCurrent();
|
||||
|
||||
|
|
|
@ -159,12 +159,6 @@ public class ConversationListFragment extends Fragment
|
|||
|
||||
private void initializeListAdapter() {
|
||||
list.setAdapter(new ConversationListAdapter(getActivity(), masterSecret, locale, null, this));
|
||||
list.setRecyclerListener(new RecyclerListener() {
|
||||
@Override
|
||||
public void onViewRecycled(ViewHolder holder) {
|
||||
((ConversationListItem)holder.itemView).unbind();
|
||||
}
|
||||
});
|
||||
getLoaderManager().restartLoader(0, null, this);
|
||||
}
|
||||
|
||||
|
|
|
@ -49,7 +49,7 @@ import static org.thoughtcrime.securesms.util.SpanUtil.color;
|
|||
*/
|
||||
|
||||
public class ConversationListItem extends RelativeLayout
|
||||
implements Recipients.RecipientsModifiedListener
|
||||
implements Recipients.RecipientsModifiedListener, Unbindable
|
||||
{
|
||||
private final static String TAG = ConversationListItem.class.getSimpleName();
|
||||
|
||||
|
@ -115,9 +115,9 @@ public class ConversationListItem extends RelativeLayout
|
|||
this.contactPhotoImage.setAvatar(recipients, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unbind() {
|
||||
if (this.recipients != null)
|
||||
this.recipients.removeListener(this);
|
||||
if (this.recipients != null) this.recipients.removeListener(this);
|
||||
}
|
||||
|
||||
private void setBatchState(boolean batch) {
|
||||
|
|
|
@ -2,20 +2,25 @@ package org.thoughtcrime.securesms;
|
|||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.View;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import org.thoughtcrime.securesms.crypto.MasterSecret;
|
||||
import org.thoughtcrime.securesms.database.model.MessageRecord;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.recipients.Recipients;
|
||||
import org.thoughtcrime.securesms.util.GroupUtil;
|
||||
import org.thoughtcrime.securesms.util.Util;
|
||||
|
||||
import java.util.Locale;
|
||||
import java.util.Set;
|
||||
|
||||
public class ConversationUpdateItem extends LinearLayout
|
||||
implements Recipients.RecipientsModifiedListener, Recipient.RecipientModifiedListener, Unbindable, View.OnClickListener
|
||||
implements Recipients.RecipientsModifiedListener, Recipient.RecipientModifiedListener, BindableConversationItem, View.OnClickListener
|
||||
{
|
||||
private static final String TAG = ConversationUpdateItem.class.getSimpleName();
|
||||
|
||||
|
@ -42,7 +47,17 @@ public class ConversationUpdateItem extends LinearLayout
|
|||
setOnClickListener(this);
|
||||
}
|
||||
|
||||
public void set(MessageRecord messageRecord) {
|
||||
@Override
|
||||
public void bind(@NonNull MasterSecret masterSecret,
|
||||
@NonNull MessageRecord messageRecord,
|
||||
@NonNull Locale locale,
|
||||
@NonNull Set<MessageRecord> batchSelected,
|
||||
boolean groupThread, boolean pushDestination)
|
||||
{
|
||||
bind(messageRecord);
|
||||
}
|
||||
|
||||
private void bind(@NonNull MessageRecord messageRecord) {
|
||||
this.messageRecord = messageRecord;
|
||||
this.sender = messageRecord.getIndividualRecipient();
|
||||
|
||||
|
@ -73,7 +88,7 @@ public class ConversationUpdateItem extends LinearLayout
|
|||
Util.runOnMain(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
set(messageRecord);
|
||||
bind(messageRecord);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
@ -19,6 +19,7 @@ package org.thoughtcrime.securesms;
|
|||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.database.Cursor;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
import android.text.TextUtils;
|
||||
import android.view.LayoutInflater;
|
||||
|
@ -64,7 +65,7 @@ public class ImageMediaAdapter extends CursorRecyclerViewAdapter<ViewHolder> {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(final ViewHolder viewHolder, final Cursor cursor) {
|
||||
public void onBindViewHolder(final ViewHolder viewHolder, final @NonNull Cursor cursor) {
|
||||
final ThumbnailView imageView = viewHolder.imageView;
|
||||
final ImageRecord imageRecord = ImageRecord.from(cursor);
|
||||
|
||||
|
|
|
@ -28,7 +28,6 @@ import android.view.LayoutInflater;
|
|||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.AdapterView;
|
||||
import android.widget.ListView;
|
||||
import android.widget.TextView;
|
||||
|
||||
|
@ -173,8 +172,8 @@ public class MessageDetailsActivity extends PassphraseRequiredActionBarActivity
|
|||
toFromRes = R.string.message_details_header__from;
|
||||
}
|
||||
toFrom.setText(toFromRes);
|
||||
conversationItem.set(masterSecret, messageRecord, dynamicLanguage.getCurrentLocale(),
|
||||
new HashSet<MessageRecord>(), new NullSelectionListener(),
|
||||
conversationItem.bind(masterSecret, messageRecord, dynamicLanguage.getCurrentLocale(),
|
||||
new HashSet<MessageRecord>(),
|
||||
recipients != messageRecord.getRecipients(),
|
||||
DirectoryHelper.isPushDestination(this, recipients));
|
||||
recipientsList.setAdapter(new MessageDetailsRecipientAdapter(this, masterSecret, messageRecord,
|
||||
|
@ -306,13 +305,4 @@ public class MessageDetailsActivity extends PassphraseRequiredActionBarActivity
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class NullSelectionListener implements ConversationFragment.SelectionClickListener {
|
||||
@Override
|
||||
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {}
|
||||
@Override
|
||||
public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,6 +19,7 @@ package org.thoughtcrime.securesms.database;
|
|||
import android.content.Context;
|
||||
import android.database.Cursor;
|
||||
import android.database.DataSetObserver;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
|
||||
/**
|
||||
|
@ -90,17 +91,34 @@ public abstract class CursorRecyclerViewAdapter<VH extends RecyclerView.ViewHold
|
|||
: 0;
|
||||
}
|
||||
|
||||
public abstract void onBindViewHolder(VH viewHolder, Cursor cursor);
|
||||
public abstract void onBindViewHolder(VH viewHolder, @NonNull Cursor cursor);
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(VH viewHolder, int position) {
|
||||
moveToPositionOrThrow(position);
|
||||
onBindViewHolder(viewHolder, cursor);
|
||||
}
|
||||
|
||||
@Override public int getItemViewType(int position) {
|
||||
moveToPositionOrThrow(position);
|
||||
return getItemViewType(cursor);
|
||||
}
|
||||
|
||||
public int getItemViewType(@NonNull Cursor cursor) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
private void assertActiveCursor() {
|
||||
if (!isActiveCursor()) {
|
||||
throw new IllegalStateException("this should only be called when the cursor is valid");
|
||||
}
|
||||
}
|
||||
|
||||
private void moveToPositionOrThrow(final int position) {
|
||||
assertActiveCursor();
|
||||
if (!cursor.moveToPosition(position)) {
|
||||
throw new IllegalStateException("couldn't move cursor to position " + position);
|
||||
}
|
||||
onBindViewHolder(viewHolder, cursor);
|
||||
}
|
||||
|
||||
private boolean isActiveCursor() {
|
||||
|
|
|
@ -56,7 +56,7 @@ public class MmsSmsDatabase extends Database {
|
|||
MmsSmsColumns.MISMATCHED_IDENTITIES,
|
||||
MmsDatabase.NETWORK_FAILURE, TRANSPORT};
|
||||
|
||||
String order = MmsSmsColumns.NORMALIZED_DATE_RECEIVED + " ASC";
|
||||
String order = MmsSmsColumns.NORMALIZED_DATE_RECEIVED + " DESC";
|
||||
|
||||
String selection = MmsSmsColumns.THREAD_ID + " = " + threadId;
|
||||
|
||||
|
|
|
@ -16,15 +16,18 @@
|
|||
*/
|
||||
package org.thoughtcrime.securesms.util;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.os.Build.VERSION;
|
||||
import android.os.Build.VERSION_CODES;
|
||||
import android.support.annotation.IdRes;
|
||||
import android.support.annotation.LayoutRes;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.v4.view.animation.FastOutSlowInInterpolator;
|
||||
import android.text.TextUtils;
|
||||
import android.text.TextUtils.TruncateAt;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.ViewStub;
|
||||
|
@ -110,4 +113,12 @@ public class ViewUtil {
|
|||
view.setVisibility(View.VISIBLE);
|
||||
view.startAnimation(animation);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <T extends View> T inflate(@NonNull LayoutInflater inflater,
|
||||
@NonNull ViewGroup parent,
|
||||
@LayoutRes int layoutResId)
|
||||
{
|
||||
return (T)(inflater.inflate(layoutResId, parent, false));
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue