Use contextual action bar menu for conversation items.
BIN
res/drawable-hdpi/ic_action_copy_holo_dark.png
Normal file
After Width: | Height: | Size: 375 B |
BIN
res/drawable-hdpi/ic_action_copy_holo_light.png
Normal file
After Width: | Height: | Size: 381 B |
BIN
res/drawable-hdpi/ic_action_forward_holo_dark.png
Normal file
After Width: | Height: | Size: 442 B |
BIN
res/drawable-hdpi/ic_action_forward_holo_light.png
Normal file
After Width: | Height: | Size: 423 B |
BIN
res/drawable-hdpi/ic_action_save_holo_dark.png
Normal file
After Width: | Height: | Size: 394 B |
BIN
res/drawable-hdpi/ic_action_save_holo_light.png
Normal file
After Width: | Height: | Size: 398 B |
BIN
res/drawable-mdpi/ic_action_copy_holo_dark.png
Normal file
After Width: | Height: | Size: 284 B |
BIN
res/drawable-mdpi/ic_action_copy_holo_light.png
Normal file
After Width: | Height: | Size: 288 B |
BIN
res/drawable-mdpi/ic_action_forward_holo_dark.png
Normal file
After Width: | Height: | Size: 375 B |
BIN
res/drawable-mdpi/ic_action_forward_holo_light.png
Normal file
After Width: | Height: | Size: 372 B |
BIN
res/drawable-mdpi/ic_action_save_holo_dark.png
Normal file
After Width: | Height: | Size: 362 B |
BIN
res/drawable-mdpi/ic_action_save_holo_light.png
Normal file
After Width: | Height: | Size: 359 B |
BIN
res/drawable-xhdpi/ic_action_copy_holo_dark.png
Normal file
After Width: | Height: | Size: 351 B |
BIN
res/drawable-xhdpi/ic_action_copy_holo_light.png
Normal file
After Width: | Height: | Size: 353 B |
BIN
res/drawable-xhdpi/ic_action_forward_holo_dark.png
Normal file
After Width: | Height: | Size: 588 B |
BIN
res/drawable-xhdpi/ic_action_forward_holo_light.png
Normal file
After Width: | Height: | Size: 613 B |
BIN
res/drawable-xhdpi/ic_action_save_holo_dark.png
Normal file
After Width: | Height: | Size: 441 B |
BIN
res/drawable-xhdpi/ic_action_save_holo_light.png
Normal file
After Width: | Height: | Size: 451 B |
BIN
res/drawable-xxhdpi/ic_action_copy_holo_dark.png
Normal file
After Width: | Height: | Size: 464 B |
BIN
res/drawable-xxhdpi/ic_action_copy_holo_light.png
Normal file
After Width: | Height: | Size: 470 B |
BIN
res/drawable-xxhdpi/ic_action_forward_holo_dark.png
Normal file
After Width: | Height: | Size: 715 B |
BIN
res/drawable-xxhdpi/ic_action_forward_holo_light.png
Normal file
After Width: | Height: | Size: 713 B |
BIN
res/drawable-xxhdpi/ic_action_save_holo_dark.png
Normal file
After Width: | Height: | Size: 495 B |
BIN
res/drawable-xxhdpi/ic_action_save_holo_light.png
Normal file
After Width: | Height: | Size: 500 B |
5
res/drawable/conversation_item_background.xml
Normal file
@ -0,0 +1,5 @@
|
||||
<?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>
|
5
res/drawable/conversation_item_background_dark.xml
Normal file
@ -0,0 +1,5 @@
|
||||
<?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>
|
@ -4,6 +4,7 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingRight="10dip"
|
||||
android:orientation="vertical"
|
||||
android:background="?conversation_item_background"
|
||||
xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<TextView android:id="@+id/group_message_status"
|
||||
|
@ -4,7 +4,8 @@
|
||||
android:id="@+id/conversation_item"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal">
|
||||
android:orientation="horizontal"
|
||||
android:background="?conversation_item_background" >
|
||||
|
||||
<RelativeLayout android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
|
@ -1,18 +1,33 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<menu xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:title="@string/conversation_context__menu_copy_text"
|
||||
android:id="@+id/menu_context_copy" />
|
||||
<item android:title="@string/conversation_context__menu_message_details"
|
||||
android:id="@+id/menu_context_details"
|
||||
android:icon="?menu_info_icon"
|
||||
android:showAsAction="always" />
|
||||
|
||||
<item android:title="@string/conversation_context__menu_delete_message"
|
||||
android:id="@+id/menu_context_delete_message" />
|
||||
android:id="@+id/menu_context_delete_message"
|
||||
android:icon="?menu_trash_icon"
|
||||
android:showAsAction="always" />
|
||||
|
||||
<item android:title="@string/conversation_context__menu_message_details"
|
||||
android:id="@+id/menu_context_details" />
|
||||
<item android:title="@string/conversation_context__menu_copy_text"
|
||||
android:id="@+id/menu_context_copy"
|
||||
android:icon="?menu_copy_icon"
|
||||
android:showAsAction="always" />
|
||||
|
||||
<item android:title="@string/conversation_context__menu_forward_message"
|
||||
android:id="@+id/menu_context_forward" />
|
||||
android:id="@+id/menu_context_forward"
|
||||
android:icon="?menu_forward_icon"
|
||||
android:showAsAction="ifRoom" />
|
||||
|
||||
<item android:title="@string/conversation_context__menu_resend_message"
|
||||
android:id="@+id/menu_context_resend"
|
||||
android:visible="false" />
|
||||
android:visible="false"
|
||||
android:showAsAction="never" />
|
||||
|
||||
<item android:title="@string/conversation_context_image__save_attachment"
|
||||
android:id="@+id/menu_context_save_attachment"
|
||||
android:visible="false"
|
||||
android:icon="?menu_save_icon"
|
||||
android:showAsAction="always" />
|
||||
</menu>
|
||||
|
@ -1,6 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<menu xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:title="@string/conversation_context_image__save_attachment"
|
||||
android:id="@+id/menu_context_save_attachment" />
|
||||
</menu>
|
@ -32,6 +32,7 @@
|
||||
<attr name="conversation_emoji_toggle" format="reference"/>
|
||||
<attr name="conversation_keyboard_toggle" format="reference"/>
|
||||
|
||||
<attr name="conversation_item_background" format="reference"/>
|
||||
<attr name="conversation_item_received_background" format="reference" />
|
||||
<attr name="conversation_item_received_triangle_background" format="reference" />
|
||||
<attr name="conversation_item_sent_background" format="reference" />
|
||||
@ -69,6 +70,10 @@
|
||||
<attr name="menu_split_icon" format="reference" />
|
||||
<attr name="menu_accept_icon" format="reference" />
|
||||
<attr name="menu_refresh_directory" format="reference" />
|
||||
<attr name="menu_copy_icon" format="reference" />
|
||||
<attr name="menu_info_icon" format="reference" />
|
||||
<attr name="menu_forward_icon" format="reference" />
|
||||
<attr name="menu_save_icon" format="reference" />
|
||||
|
||||
<declare-styleable name="ForegroundImageView">
|
||||
<attr name="android:foreground" />
|
||||
|
@ -47,6 +47,7 @@
|
||||
<item name="conversation_emoji_toggle">@drawable/ic_emoji_dark</item>
|
||||
<item name="conversation_keyboard_toggle">@drawable/ic_ime_dark</item>
|
||||
|
||||
<item name="conversation_item_background">@drawable/conversation_item_background</item>
|
||||
<item name="conversation_item_received_background">@drawable/conversation_item_received_shape</item>
|
||||
<item name="conversation_item_received_triangle_background">@drawable/conversation_item_received_triangle_shape</item>
|
||||
<item name="conversation_item_sent_background">@drawable/conversation_item_sent_shape</item>
|
||||
@ -74,6 +75,10 @@
|
||||
<item name="menu_split_icon">@drawable/ic_menu_split_holo_light</item>
|
||||
<item name="menu_accept_icon">@drawable/ic_menu_accept_holo_light</item>
|
||||
<item name="menu_refresh_directory">@drawable/ic_menu_refresh_holo_light</item>
|
||||
<item name="menu_copy_icon">@drawable/ic_action_copy_holo_light</item>
|
||||
<item name="menu_info_icon">@drawable/ic_dialog_info_holo_light</item>
|
||||
<item name="menu_forward_icon">@drawable/ic_action_forward_holo_light</item>
|
||||
<item name="menu_save_icon">@drawable/ic_action_save_holo_light</item>
|
||||
</style>
|
||||
|
||||
<style name="TextSecure.LightTheme.NavigationDrawer"
|
||||
@ -110,6 +115,7 @@
|
||||
<item name="contact_selection_label_text">#66eeeeee</item>
|
||||
<item name="conversation_selection_header_text">#66eeeeee</item>
|
||||
|
||||
<item name="conversation_item_background">@drawable/conversation_item_background_dark</item>
|
||||
<item name="conversation_item_received_background">@drawable/conversation_item_received_shape_dark</item>
|
||||
<item name="conversation_item_received_triangle_background">@drawable/conversation_item_received_triangle_shape_dark</item>
|
||||
<item name="conversation_item_sent_background">@drawable/conversation_item_sent_shape_dark</item>
|
||||
@ -150,6 +156,10 @@
|
||||
<item name="menu_split_icon">@drawable/ic_menu_split_holo_dark</item>
|
||||
<item name="menu_accept_icon">@drawable/ic_menu_accept_holo_dark</item>
|
||||
<item name="menu_refresh_directory">@drawable/ic_menu_refresh_holo_dark</item>
|
||||
<item name="menu_copy_icon">@drawable/ic_action_copy_holo_dark</item>
|
||||
<item name="menu_info_icon">@drawable/ic_dialog_info_holo_dark</item>
|
||||
<item name="menu_forward_icon">@drawable/ic_action_forward_holo_dark</item>
|
||||
<item name="menu_save_icon">@drawable/ic_action_save_holo_dark</item>
|
||||
</style>
|
||||
|
||||
<style name="TextSecure.DarkTheme.NavigationDrawer"
|
||||
|
@ -8,7 +8,6 @@ import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.database.Cursor;
|
||||
import android.media.MediaScannerConnection;
|
||||
import android.net.Uri;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Bundle;
|
||||
import android.os.Environment;
|
||||
@ -17,17 +16,20 @@ import android.support.v4.app.LoaderManager;
|
||||
import android.support.v4.content.Loader;
|
||||
import android.text.ClipboardManager;
|
||||
import android.util.Log;
|
||||
import android.view.ContextMenu;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.support.v4.widget.CursorAdapter;
|
||||
import android.webkit.MimeTypeMap;
|
||||
import android.widget.AdapterView;
|
||||
import android.widget.ListView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.actionbarsherlock.app.SherlockListFragment;
|
||||
import com.actionbarsherlock.view.ActionMode;
|
||||
import com.actionbarsherlock.view.Menu;
|
||||
import com.actionbarsherlock.view.MenuInflater;
|
||||
import com.actionbarsherlock.view.MenuItem;
|
||||
|
||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||
import org.thoughtcrime.securesms.database.loaders.ConversationLoader;
|
||||
@ -63,6 +65,7 @@ public class ConversationFragment extends SherlockListFragment
|
||||
private MasterSecret masterSecret;
|
||||
private Recipients recipients;
|
||||
private long threadId;
|
||||
private ActionMode actionMode;
|
||||
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle bundle) {
|
||||
@ -75,49 +78,7 @@ public class ConversationFragment extends SherlockListFragment
|
||||
|
||||
initializeResources();
|
||||
initializeListAdapter();
|
||||
registerForContextMenu(getListView());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreateContextMenu (ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
|
||||
android.view.MenuInflater inflater = this.getSherlockActivity().getMenuInflater();
|
||||
menu.clear();
|
||||
|
||||
inflater.inflate(R.menu.conversation_context, menu);
|
||||
|
||||
MessageRecord messageRecord = getMessageRecord();
|
||||
|
||||
if (messageRecord.isFailed()) {
|
||||
MenuItem resend = menu.findItem(R.id.menu_context_resend);
|
||||
resend.setVisible(true);
|
||||
}
|
||||
|
||||
if (messageRecord.isMms() && !messageRecord.isMmsNotification()) {
|
||||
try {
|
||||
if (((MediaMmsMessageRecord)messageRecord).getSlideDeck().get().containsMediaSlide()) {
|
||||
inflater.inflate(R.menu.conversation_context_image, menu);
|
||||
}
|
||||
} catch (InterruptedException ie) {
|
||||
Log.w(TAG, ie);
|
||||
} catch (ExecutionException ee) {
|
||||
Log.w(TAG, ee);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onContextItemSelected(android.view.MenuItem item) {
|
||||
MessageRecord messageRecord = getMessageRecord();
|
||||
switch(item.getItemId()) {
|
||||
case R.id.menu_context_copy: handleCopyMessage(messageRecord); return true;
|
||||
case R.id.menu_context_delete_message: handleDeleteMessage(messageRecord); return true;
|
||||
case R.id.menu_context_details: handleDisplayDetails(messageRecord); return true;
|
||||
case R.id.menu_context_forward: handleForwardMessage(messageRecord); return true;
|
||||
case R.id.menu_context_resend: handleResendMessage(messageRecord); return true;
|
||||
case R.id.menu_context_save_attachment:handleSaveAttachment(messageRecord); return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
initializeContextualActionBar();
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -126,6 +87,75 @@ public class ConversationFragment extends SherlockListFragment
|
||||
this.listener = (ConversationFragmentListener)activity;
|
||||
}
|
||||
|
||||
private void initializeResources() {
|
||||
String recipientIds = this.getActivity().getIntent().getStringExtra("recipients");
|
||||
|
||||
this.masterSecret = this.getActivity().getIntent().getParcelableExtra("master_secret");
|
||||
this.recipients = RecipientFactory.getRecipientsForIds(getActivity(), recipientIds, true);
|
||||
this.threadId = this.getActivity().getIntent().getLongExtra("thread_id", -1);
|
||||
}
|
||||
|
||||
private void initializeListAdapter() {
|
||||
if (this.recipients != null && this.threadId != -1) {
|
||||
this.setListAdapter(new ConversationAdapter(getActivity(), masterSecret,
|
||||
new FailedIconClickHandler(),
|
||||
(!this.recipients.isSingleRecipient()) || this.recipients.isGroupRecipient(),
|
||||
DirectoryHelper.isPushDestination(getActivity(), this.recipients)));
|
||||
getListView().setRecyclerListener((ConversationAdapter)getListAdapter());
|
||||
getLoaderManager().initLoader(0, null, this);
|
||||
}
|
||||
}
|
||||
|
||||
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 = getSherlockActivity().startActionMode(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());
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
if (messageRecord.isFailed()) resend.setVisible(true);
|
||||
else resend.setVisible(false);
|
||||
|
||||
if (messageRecord.isMms() && !messageRecord.isMmsNotification()) {
|
||||
try {
|
||||
if (((MediaMmsMessageRecord)messageRecord).getSlideDeck().get().containsMediaSlide()) {
|
||||
saveAttachment.setVisible(true);
|
||||
} else {
|
||||
saveAttachment.setVisible(false);
|
||||
}
|
||||
} catch (InterruptedException ie) {
|
||||
Log.w(TAG, ie);
|
||||
} catch (ExecutionException ee) {
|
||||
Log.w(TAG, ee);
|
||||
}
|
||||
} else {
|
||||
saveAttachment.setVisible(false);
|
||||
}
|
||||
}
|
||||
|
||||
private MessageRecord getMessageRecord() {
|
||||
Cursor cursor = ((CursorAdapter)getListAdapter()).getCursor();
|
||||
ConversationItem conversationItem = (ConversationItem)(((ConversationAdapter)getListAdapter()).newView(getActivity(), cursor, null));
|
||||
@ -246,25 +276,6 @@ public class ConversationFragment extends SherlockListFragment
|
||||
builder.show();
|
||||
}
|
||||
|
||||
private void initializeResources() {
|
||||
String recipientIds = this.getActivity().getIntent().getStringExtra("recipients");
|
||||
|
||||
this.masterSecret = this.getActivity().getIntent().getParcelableExtra("master_secret");
|
||||
this.recipients = RecipientFactory.getRecipientsForIds(getActivity(), recipientIds, true);
|
||||
this.threadId = this.getActivity().getIntent().getLongExtra("thread_id", -1);
|
||||
}
|
||||
|
||||
private void initializeListAdapter() {
|
||||
if (this.recipients != null && this.threadId != -1) {
|
||||
this.setListAdapter(new ConversationAdapter(getActivity(), masterSecret,
|
||||
new FailedIconClickHandler(),
|
||||
(!this.recipients.isSingleRecipient()) || this.recipients.isGroupRecipient(),
|
||||
DirectoryHelper.isPushDestination(getActivity(), this.recipients)));
|
||||
getListView().setRecyclerListener((ConversationAdapter)getListAdapter());
|
||||
getLoaderManager().initLoader(0, null, this);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Loader<Cursor> onCreateLoader(int arg0, Bundle arg1) {
|
||||
return new ConversationLoader(getActivity(), threadId);
|
||||
@ -293,6 +304,69 @@ public class ConversationFragment extends SherlockListFragment
|
||||
public void setComposeText(String text);
|
||||
}
|
||||
|
||||
private ActionMode.Callback actionModeCallback = new 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);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onPrepareActionMode(ActionMode actionMode, Menu menu) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@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);
|
||||
}
|
||||
}
|
||||
actionMode = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
|
||||
MessageRecord messageRecord = getMessageRecord();
|
||||
|
||||
switch(item.getItemId()) {
|
||||
case R.id.menu_context_copy:
|
||||
handleCopyMessage(messageRecord);
|
||||
actionMode.finish();
|
||||
return true;
|
||||
case R.id.menu_context_delete_message:
|
||||
handleDeleteMessage(messageRecord);
|
||||
actionMode.finish();
|
||||
return true;
|
||||
case R.id.menu_context_details:
|
||||
handleDisplayDetails(messageRecord);
|
||||
actionMode.finish();
|
||||
return true;
|
||||
case R.id.menu_context_forward:
|
||||
handleForwardMessage(messageRecord);
|
||||
actionMode.finish();
|
||||
return true;
|
||||
case R.id.menu_context_resend:
|
||||
handleResendMessage(messageRecord);
|
||||
actionMode.finish();
|
||||
return true;
|
||||
case R.id.menu_context_save_attachment:
|
||||
handleSaveAttachment(messageRecord);
|
||||
actionMode.finish();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
private class SaveAttachmentTask extends AsyncTask<MediaMmsMessageRecord, Void, Integer> {
|
||||
|
||||
private static final int SUCCESS = 0;
|
||||
|