Use contextual action bar menu for conversation items.

This commit is contained in:
phenx-de 2014-06-12 19:22:57 +02:00 committed by Moxie Marlinspike
parent 5ae8a7a8c4
commit d8e6a93584
33 changed files with 189 additions and 79 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 375 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 381 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 442 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 423 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 394 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 398 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 284 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 288 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 375 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 372 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 362 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 359 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 351 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 353 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 588 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 613 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 441 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 451 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 464 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 470 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 715 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 713 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 495 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 500 B

View 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>

View 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>

View File

@ -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"

View File

@ -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"

View File

@ -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>

View File

@ -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>

View File

@ -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" />

View File

@ -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"

View File

@ -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;