From 77b8e62d6463aa0cc6c84fb355651be9d25f0973 Mon Sep 17 00:00:00 2001 From: cketti Date: Mon, 28 Jan 2013 16:15:03 +0100 Subject: [PATCH] Add hotkeys from MessageView to MessageList --- src/com/fsck/k9/activity/MessageList.java | 185 ++++++++++++++---- src/com/fsck/k9/activity/MessageView.java | 2 +- .../fsck/k9/fragment/MessageListFragment.java | 92 ++++++++- .../fsck/k9/fragment/MessageViewFragment.java | 17 +- 4 files changed, 240 insertions(+), 56 deletions(-) diff --git a/src/com/fsck/k9/activity/MessageList.java b/src/com/fsck/k9/activity/MessageList.java index 54bc7884c..709c7a3b2 100644 --- a/src/com/fsck/k9/activity/MessageList.java +++ b/src/com/fsck/k9/activity/MessageList.java @@ -356,22 +356,66 @@ public class MessageList extends K9FragmentActivity implements MessageListFragme } @Override - public boolean onKeyDown(int keyCode, KeyEvent event) { + public boolean dispatchKeyEvent(KeyEvent event) { + boolean ret = false; + if (KeyEvent.ACTION_DOWN == event.getAction()) { + ret = onCustomKeyDown(event.getKeyCode(), event); + } + if (!ret) { + ret = super.dispatchKeyEvent(event); + } + return ret; + } + + /** + * Handle hotkeys + * + *

+ * This method is called by {@link #dispatchKeyEvent(KeyEvent)} before any view had the chance + * to consume this key event. + *

+ * + * @param keyCode + * The value in {@code event.getKeyCode()}. + * @param event + * Description of the key event. + * + * @return {@code true} if this event was consumed. + */ + public boolean onCustomKeyDown(final int keyCode, final KeyEvent event) { // Shortcuts that work no matter what is selected switch (keyCode) { case KeyEvent.KEYCODE_VOLUME_UP: { - if (K9.useVolumeKeysForListNavigationEnabled()) { + if (mMessageViewFragment != null && mDisplayMode != DisplayMode.MESSAGE_LIST && + K9.useVolumeKeysForNavigationEnabled()) { + MessageReference ref = mMessageViewFragment.getMessageReference(); + if (ref != null) { + mMessageListFragment.openPrevious(ref); + } + return true; + } else if (mDisplayMode != DisplayMode.MESSAGE_VIEW && + K9.useVolumeKeysForListNavigationEnabled()) { mMessageListFragment.onMoveUp(); return true; } - return false; + + break; } case KeyEvent.KEYCODE_VOLUME_DOWN: { - if (K9.useVolumeKeysForListNavigationEnabled()) { + if (mMessageViewFragment != null && mDisplayMode != DisplayMode.MESSAGE_LIST && + K9.useVolumeKeysForNavigationEnabled()) { + MessageReference ref = mMessageViewFragment.getMessageReference(); + if (ref != null) { + mMessageListFragment.openNext(ref); + } + return true; + } else if (mDisplayMode != DisplayMode.MESSAGE_VIEW && + K9.useVolumeKeysForListNavigationEnabled()) { mMessageListFragment.onMoveDown(); return true; } - return false; + + break; } case KeyEvent.KEYCODE_C: { mMessageListFragment.onCompose(); @@ -389,50 +433,107 @@ public class MessageList extends K9FragmentActivity implements MessageListFragme mMessageListFragment.onReverseSort(); return true; } + case KeyEvent.KEYCODE_DEL: + case KeyEvent.KEYCODE_D: { + if (mDisplayMode == DisplayMode.MESSAGE_LIST) { + mMessageListFragment.onDelete(); + } else if (mMessageViewFragment != null) { + mMessageViewFragment.onDelete(); + } + return true; + } + case KeyEvent.KEYCODE_S: { + mMessageListFragment.toggleMessageSelect(); + return true; + } + case KeyEvent.KEYCODE_G: { + if (mDisplayMode == DisplayMode.MESSAGE_LIST) { + mMessageListFragment.onToggleFlagged(); + } else if (mMessageViewFragment != null) { + mMessageViewFragment.onToggleFlagged(); + } + return true; + } + case KeyEvent.KEYCODE_M: { + if (mDisplayMode == DisplayMode.MESSAGE_LIST) { + mMessageListFragment.onMove(); + } else if (mMessageViewFragment != null) { + mMessageViewFragment.onMove(); + } + return true; + } + case KeyEvent.KEYCODE_V: { + if (mDisplayMode == DisplayMode.MESSAGE_LIST) { + mMessageListFragment.onArchive(); + } else if (mMessageViewFragment != null) { + mMessageViewFragment.onArchive(); + } + return true; + } + case KeyEvent.KEYCODE_Y: { + if (mDisplayMode == DisplayMode.MESSAGE_LIST) { + mMessageListFragment.onCopy(); + } else if (mMessageViewFragment != null) { + mMessageViewFragment.onCopy(); + } + return true; + } + case KeyEvent.KEYCODE_Z: { + if (mDisplayMode == DisplayMode.MESSAGE_LIST) { + mMessageListFragment.onToggleRead(); + } else if (mMessageViewFragment != null) { + mMessageViewFragment.onToggleRead(); + } + return true; + } + case KeyEvent.KEYCODE_F: { + if (mMessageViewFragment != null) { + mMessageViewFragment.onForward(); + } + return true; + } + case KeyEvent.KEYCODE_A: { + if (mMessageViewFragment != null) { + mMessageViewFragment.onReplyAll(); + } + return true; + } + case KeyEvent.KEYCODE_R: { + if (mMessageViewFragment != null) { + mMessageViewFragment.onReply(); + } + return true; + } + case KeyEvent.KEYCODE_J: + case KeyEvent.KEYCODE_P: { + MessageReference ref = mMessageViewFragment.getMessageReference(); + if (ref != null) { + mMessageListFragment.openPrevious(ref); + } + return true; + } + case KeyEvent.KEYCODE_N: + case KeyEvent.KEYCODE_K: { + MessageReference ref = mMessageViewFragment.getMessageReference(); + if (ref != null) { + mMessageListFragment.openNext(ref); + } + return true; + } + /* FIXME + case KeyEvent.KEYCODE_Z: { + mMessageViewFragment.zoom(event); + return true; + }*/ case KeyEvent.KEYCODE_H: { Toast toast = Toast.makeText(this, R.string.message_list_help_key, Toast.LENGTH_LONG); toast.show(); return true; } + } - boolean retval = true; - try { - switch (keyCode) { - case KeyEvent.KEYCODE_DEL: - case KeyEvent.KEYCODE_D: { - mMessageListFragment.onDelete(); - return true; - } - case KeyEvent.KEYCODE_S: { - mMessageListFragment.toggleMessageSelect(); - return true; - } - case KeyEvent.KEYCODE_G: { - mMessageListFragment.onToggleFlagged(); - return true; - } - case KeyEvent.KEYCODE_M: { - mMessageListFragment.onMove(); - return true; - } - case KeyEvent.KEYCODE_V: { - mMessageListFragment.onArchive(); - return true; - } - case KeyEvent.KEYCODE_Y: { - mMessageListFragment.onCopy(); - return true; - } - case KeyEvent.KEYCODE_Z: { - mMessageListFragment.onToggleRead(); - return true; - } - } - } finally { - retval = super.onKeyDown(keyCode, event); - } - return retval; + return false; } @Override diff --git a/src/com/fsck/k9/activity/MessageView.java b/src/com/fsck/k9/activity/MessageView.java index 3ebd01ed4..469286162 100644 --- a/src/com/fsck/k9/activity/MessageView.java +++ b/src/com/fsck/k9/activity/MessageView.java @@ -318,7 +318,7 @@ public class MessageView extends K9FragmentActivity implements MessageViewFragme return true; } case KeyEvent.KEYCODE_G: { - mMessageViewFragment.onFlag(); + mMessageViewFragment.onToggleFlagged(); return true; } case KeyEvent.KEYCODE_M: { diff --git a/src/com/fsck/k9/fragment/MessageListFragment.java b/src/com/fsck/k9/fragment/MessageListFragment.java index 2666f3cd1..43b9931d9 100644 --- a/src/com/fsck/k9/fragment/MessageListFragment.java +++ b/src/com/fsck/k9/fragment/MessageListFragment.java @@ -431,6 +431,7 @@ public class MessageListFragment extends SherlockFragment implements OnItemClick private static final int ACTION_PROGRESS = 3; private static final int ACTION_REMOTE_SEARCH_FINISHED = 4; private static final int ACTION_GO_BACK = 5; + private static final int ACTION_OPEN_MESSAGE = 6; public void folderLoading(String folder, boolean loading) { @@ -469,6 +470,12 @@ public class MessageListFragment extends SherlockFragment implements OnItemClick sendMessage(msg); } + public void openMessage(MessageReference messageReference) { + android.os.Message msg = android.os.Message.obtain(this, ACTION_OPEN_MESSAGE, + messageReference); + sendMessage(msg); + } + @Override public void handleMessage(android.os.Message msg) { // The following messages don't need an attached activity. @@ -505,6 +512,11 @@ public class MessageListFragment extends SherlockFragment implements OnItemClick mFragmentListener.goBack(); break; } + case ACTION_OPEN_MESSAGE: { + MessageReference messageReference = (MessageReference) msg.obj; + mFragmentListener.openMessage(messageReference); + break; + } } } } @@ -663,22 +675,17 @@ public class MessageListFragment extends SherlockFragment implements OnItemClick if (mSelectedCount > 0) { toggleMessageSelect(position); } else { - Account account = getAccountFromCursor(cursor); - - long folderId = cursor.getLong(FOLDER_ID_COLUMN); - String folderName = getFolderNameById(account, folderId); - if (mThreadedList && cursor.getInt(THREAD_COUNT_COLUMN) > 1) { + Account account = getAccountFromCursor(cursor); + long folderId = cursor.getLong(FOLDER_ID_COLUMN); + String folderName = getFolderNameById(account, folderId); + // If threading is enabled and this item represents a thread, display the thread contents. long rootId = cursor.getLong(THREAD_ROOT_COLUMN); mFragmentListener.showThread(account, folderName, rootId); } else { // This item represents a message; just display the message. - MessageReference ref = new MessageReference(); - ref.accountUuid = account.getUuid(); - ref.folderName = folderName; - ref.uid = cursor.getString(UID_COLUMN); - onOpenMessage(ref); + openMessageAtPosition(listViewToAdapterPosition(position)); } } } @@ -1507,6 +1514,14 @@ public class MessageListFragment extends SherlockFragment implements OnItemClick return AdapterView.INVALID_POSITION; } + private int adapterToListViewPosition(int position) { + if (position >= 0 && position < mAdapter.getCount()) { + return position + 1; + } + + return AdapterView.INVALID_POSITION; + } + class MessageListActivityListener extends ActivityListener { @Override public void remoteSearchFailed(Account acct, String folder, final String err) { @@ -2750,6 +2765,63 @@ public class MessageListFragment extends SherlockFragment implements OnItemClick } } + public void openPrevious(MessageReference messageReference) { + int position = getPosition(messageReference); + if (position <= 0) { + return; + } + + openMessageAtPosition(position - 1); + } + + public void openNext(MessageReference messageReference) { + int position = getPosition(messageReference); + if (position < 0 || position == mAdapter.getCount() - 1) { + return; + } + + openMessageAtPosition(position + 1); + } + + private void openMessageAtPosition(int position) { + // Scroll message into view if necessary + int listViewPosition = adapterToListViewPosition(position); + if (listViewPosition != AdapterView.INVALID_POSITION && + (listViewPosition < mListView.getFirstVisiblePosition() || + listViewPosition > mListView.getLastVisiblePosition())) { + mListView.setSelection(listViewPosition); + } + + Cursor cursor = (Cursor) mAdapter.getItem(position); + MessageReference ref = new MessageReference(); + ref.accountUuid = cursor.getString(ACCOUNT_UUID_COLUMN); + ref.folderName = cursor.getString(FOLDER_NAME_COLUMN); + ref.uid = cursor.getString(UID_COLUMN); + + // For some reason the mListView.setSelection() above won't do anything when we call + // onOpenMessage() (and consequently mAdapter.notifyDataSetChanged()) right away. So we + // defer the call using MessageListHandler. + mHandler.openMessage(ref); + } + + private int getPosition(MessageReference messageReference) { + for (int i = 0, len = mAdapter.getCount(); i < len; i++) { + Cursor cursor = (Cursor) mAdapter.getItem(i); + + String accountUuid = cursor.getString(ACCOUNT_UUID_COLUMN); + String folderName = cursor.getString(FOLDER_NAME_COLUMN); + String uid = cursor.getString(UID_COLUMN); + + if (accountUuid.equals(messageReference.accountUuid) && + folderName.equals(messageReference.folderName) && + uid.equals(messageReference.uid)) { + return i; + } + } + + return -1; + } + public interface MessageListFragmentListener { void enableActionBarProgress(boolean enable); void setMessageListProgress(int level); diff --git a/src/com/fsck/k9/fragment/MessageViewFragment.java b/src/com/fsck/k9/fragment/MessageViewFragment.java index a736165cf..4d02dd07e 100644 --- a/src/com/fsck/k9/fragment/MessageViewFragment.java +++ b/src/com/fsck/k9/fragment/MessageViewFragment.java @@ -326,7 +326,7 @@ public class MessageViewFragment extends SherlockFragment implements OnClickList } } - public void onFlag() { + public void onToggleFlagged() { if (mMessage != null) { boolean newState = !mMessage.isSet(Flag.FLAGGED); mController.setFlag(mAccount, mMessage.getFolder().getName(), @@ -364,6 +364,10 @@ public class MessageViewFragment extends SherlockFragment implements OnClickList startRefileActivity(ACTIVITY_CHOOSE_FOLDER_COPY); } + public void onArchive() { + onRefile(mAccount.getArchiveFolderName()); + } + private void onToggleColors() { if (K9.getK9MessageViewTheme() == K9.THEME_DARK) { K9.setK9MessageViewTheme(K9.THEME_LIGHT); @@ -453,7 +457,7 @@ public class MessageViewFragment extends SherlockFragment implements OnClickList } } - private void onToggleRead() { + public void onToggleRead() { if (mMessage != null) { mController.setFlag(mAccount, mMessage.getFolder().getName(), new Message[] { mMessage }, Flag.SEEN, !mMessage.isSet(Flag.SEEN)); @@ -667,7 +671,7 @@ public class MessageViewFragment extends SherlockFragment implements OnClickList mMessageView.setOnFlagListener(new OnClickListener() { @Override public void onClick(View v) { - onFlag(); + onToggleFlagged(); } }); } @@ -898,6 +902,13 @@ public class MessageViewFragment extends SherlockFragment implements OnClickList /* do nothing */ } + /** + * Get the {@link MessageReference} of the currently displayed message. + */ + public MessageReference getMessageReference() { + return mMessageReference; + } + public interface MessageViewFragmentListener { public void onForward(Message mMessage, PgpData mPgpData);