mirror of
https://github.com/moparisthebest/k-9
synced 2024-11-27 11:42:16 -05:00
MessageList refactoring to remove duplicate code paths.
Message operations should be more consistent now, regardless of how the messages are selected (long click, checkbox+Menu, future group selection). This is a backport of the modifications made on the issue258 branch, without the threading specific features (no new feature introduced).
This commit is contained in:
parent
5d85b7a508
commit
821a00e727
@ -22,33 +22,33 @@ import android.text.style.ForegroundColorSpan;
|
||||
import android.text.style.StyleSpan;
|
||||
import android.util.Log;
|
||||
import android.util.TypedValue;
|
||||
import android.view.animation.Animation;
|
||||
import android.view.animation.AnimationUtils;
|
||||
import android.view.animation.Animation.AnimationListener;
|
||||
import android.view.ContextMenu;
|
||||
import android.view.ContextMenu.ContextMenuInfo;
|
||||
import android.view.GestureDetector;
|
||||
import android.view.GestureDetector.SimpleOnGestureListener;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.view.View.OnClickListener;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.Window;
|
||||
import android.view.ContextMenu.ContextMenuInfo;
|
||||
import android.view.GestureDetector.SimpleOnGestureListener;
|
||||
import android.view.View.OnClickListener;
|
||||
import android.view.animation.Animation;
|
||||
import android.view.animation.Animation.AnimationListener;
|
||||
import android.view.animation.AnimationUtils;
|
||||
import android.widget.AdapterView;
|
||||
import android.widget.AdapterView.AdapterContextMenuInfo;
|
||||
import android.widget.BaseAdapter;
|
||||
import android.widget.CheckBox;
|
||||
import android.widget.CompoundButton;
|
||||
import android.widget.CompoundButton.OnCheckedChangeListener;
|
||||
import android.widget.ImageButton;
|
||||
import android.widget.ListView;
|
||||
import android.widget.ProgressBar;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
import android.widget.AdapterView.AdapterContextMenuInfo;
|
||||
import android.widget.CompoundButton.OnCheckedChangeListener;
|
||||
|
||||
import com.fsck.k9.Account;
|
||||
import com.fsck.k9.AccountStats;
|
||||
@ -61,16 +61,16 @@ import com.fsck.k9.activity.setup.AccountSettings;
|
||||
import com.fsck.k9.activity.setup.FolderSettings;
|
||||
import com.fsck.k9.activity.setup.Prefs;
|
||||
import com.fsck.k9.controller.MessagingController;
|
||||
import com.fsck.k9.controller.MessagingListener;
|
||||
import com.fsck.k9.controller.MessagingController.SORT_TYPE;
|
||||
import com.fsck.k9.controller.MessagingListener;
|
||||
import com.fsck.k9.helper.MessageHelper;
|
||||
import com.fsck.k9.helper.Utility;
|
||||
import com.fsck.k9.mail.Flag;
|
||||
import com.fsck.k9.mail.Folder;
|
||||
import com.fsck.k9.mail.Message;
|
||||
import com.fsck.k9.mail.store.LocalStore;
|
||||
import com.fsck.k9.mail.store.StorageManager;
|
||||
import com.fsck.k9.mail.store.LocalStore.LocalFolder;
|
||||
import com.fsck.k9.mail.store.StorageManager;
|
||||
|
||||
|
||||
/**
|
||||
@ -207,8 +207,6 @@ public class MessageList
|
||||
|
||||
private static final int ACTIVITY_CHOOSE_FOLDER_MOVE = 1;
|
||||
private static final int ACTIVITY_CHOOSE_FOLDER_COPY = 2;
|
||||
private static final int ACTIVITY_CHOOSE_FOLDER_MOVE_BATCH = 3;
|
||||
private static final int ACTIVITY_CHOOSE_FOLDER_COPY_BATCH = 4;
|
||||
|
||||
private static final String EXTRA_ACCOUNT = "account";
|
||||
private static final String EXTRA_FOLDER = "folder";
|
||||
@ -298,9 +296,21 @@ public class MessageList
|
||||
private FontSizes mFontSizes = K9.getFontSizes();
|
||||
|
||||
private Bundle mState = null;
|
||||
private MessageInfoHolder mSelectedMessage = null;
|
||||
|
||||
private Context context = null;
|
||||
/**
|
||||
* Remember the selection to be consistent between menu display and menu item
|
||||
* selection
|
||||
*/
|
||||
private MessageInfoHolder mSelectedMessage;
|
||||
|
||||
/**
|
||||
* Relevant messages for the current context when we have to remember the
|
||||
* chosen messages between user interactions (eg. Selecting a folder for
|
||||
* move operation)
|
||||
*/
|
||||
private List<MessageInfoHolder> mActiveMessages;
|
||||
|
||||
private Context context;
|
||||
|
||||
/* package visibility for faster inner class access */
|
||||
MessageHelper mMessageHelper = MessageHelper.getInstance(this);
|
||||
@ -327,7 +337,13 @@ public class MessageList
|
||||
}
|
||||
|
||||
class MessageListHandler {
|
||||
public void removeMessage(final List<MessageInfoHolder> messages) {
|
||||
/**
|
||||
* @param messages Never {@code null}.
|
||||
*/
|
||||
public void removeMessages(final List<MessageInfoHolder> messages) {
|
||||
if (messages.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
runOnUiThread(new Runnable() {
|
||||
public void run() {
|
||||
for (MessageInfoHolder message : messages) {
|
||||
@ -348,7 +364,13 @@ public class MessageList
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @param messages Never {@code null}.
|
||||
*/
|
||||
public void addMessages(final List<MessageInfoHolder> messages) {
|
||||
if (messages.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
final boolean wasEmpty = mAdapter.messages.isEmpty();
|
||||
runOnUiThread(new Runnable() {
|
||||
public void run() {
|
||||
@ -577,7 +599,7 @@ public class MessageList
|
||||
if (mSelectedCount > 0) {
|
||||
// In multiselect mode make sure that clicking on the item results
|
||||
// in toggling the 'selected' checkbox.
|
||||
setSelected(message, !message.selected);
|
||||
setSelected(Collections.singletonList(message), !message.selected);
|
||||
} else {
|
||||
onOpenMessage(message);
|
||||
}
|
||||
@ -913,18 +935,20 @@ public class MessageList
|
||||
if (position >= 0) {
|
||||
MessageInfoHolder message = (MessageInfoHolder) mAdapter.getItem(position);
|
||||
|
||||
final List<MessageInfoHolder> selection = getSelectionFromMessage(message);
|
||||
|
||||
if (message != null) {
|
||||
switch (keyCode) {
|
||||
case KeyEvent.KEYCODE_DEL: {
|
||||
onDelete(message, position);
|
||||
onDelete(selection);
|
||||
return true;
|
||||
}
|
||||
case KeyEvent.KEYCODE_S: {
|
||||
setSelected(message, !message.selected);
|
||||
setSelected(selection, !message.selected);
|
||||
return true;
|
||||
}
|
||||
case KeyEvent.KEYCODE_D: {
|
||||
onDelete(message, position);
|
||||
onDelete(selection);
|
||||
return true;
|
||||
}
|
||||
case KeyEvent.KEYCODE_F: {
|
||||
@ -940,23 +964,23 @@ public class MessageList
|
||||
return true;
|
||||
}
|
||||
case KeyEvent.KEYCODE_G: {
|
||||
onToggleFlag(message);
|
||||
setFlag(selection, Flag.FLAGGED, !message.flagged);
|
||||
return true;
|
||||
}
|
||||
case KeyEvent.KEYCODE_M: {
|
||||
onMove(message);
|
||||
onMove(selection);
|
||||
return true;
|
||||
}
|
||||
case KeyEvent.KEYCODE_V: {
|
||||
onArchive(message);
|
||||
onArchive(selection);
|
||||
return true;
|
||||
}
|
||||
case KeyEvent.KEYCODE_Y: {
|
||||
onCopy(message);
|
||||
onCopy(selection);
|
||||
return true;
|
||||
}
|
||||
case KeyEvent.KEYCODE_Z: {
|
||||
onToggleRead(message);
|
||||
setFlag(selection, Flag.SEEN, !message.read);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -1097,150 +1121,57 @@ public class MessageList
|
||||
reSort();
|
||||
}
|
||||
|
||||
private void onDelete(MessageInfoHolder holder, int position) {
|
||||
mAdapter.removeMessage(holder);
|
||||
mController.deleteMessages(new Message[] { holder.message }, null);
|
||||
}
|
||||
|
||||
private void onMove(MessageInfoHolder holder) {
|
||||
if (!mController.isMoveCapable(holder.message.getFolder().getAccount())) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!mController.isMoveCapable(holder.message)) {
|
||||
Toast toast = Toast.makeText(this, R.string.move_copy_cannot_copy_unsynced_message, Toast.LENGTH_LONG);
|
||||
toast.show();
|
||||
return;
|
||||
}
|
||||
|
||||
final Account account = holder.message.getFolder().getAccount();
|
||||
|
||||
Intent intent = new Intent(this, ChooseFolder.class);
|
||||
intent.putExtra(ChooseFolder.EXTRA_ACCOUNT, account.getUuid());
|
||||
intent.putExtra(ChooseFolder.EXTRA_CUR_FOLDER, holder.folder.name);
|
||||
intent.putExtra(ChooseFolder.EXTRA_SEL_FOLDER, account.getLastSelectedFolderName());
|
||||
intent.putExtra(ChooseFolder.EXTRA_MESSAGE, holder.message.makeMessageReference());
|
||||
startActivityForResult(intent, ACTIVITY_CHOOSE_FOLDER_MOVE);
|
||||
}
|
||||
|
||||
private void onArchive(MessageInfoHolder holder) {
|
||||
|
||||
if (!mController.isMoveCapable(holder.message)) {
|
||||
Toast toast = Toast.makeText(this, R.string.move_copy_cannot_copy_unsynced_message, Toast.LENGTH_LONG);
|
||||
toast.show();
|
||||
return;
|
||||
}
|
||||
|
||||
onMoveChosen(holder, holder.message.getFolder().getAccount().getArchiveFolderName());
|
||||
}
|
||||
|
||||
private void onSpam(MessageInfoHolder holder) {
|
||||
if (K9.confirmSpam()) {
|
||||
// The action handler needs this to move the message later
|
||||
mSelectedMessage = holder;
|
||||
showDialog(R.id.dialog_confirm_spam);
|
||||
} else {
|
||||
moveToSpamFolder(holder);
|
||||
/**
|
||||
* @param holders
|
||||
* Never {@code null}.
|
||||
*/
|
||||
private void onDelete(final List<MessageInfoHolder> holders) {
|
||||
// FIXME: removeMessage does it own check on the 'selected' field, we're duplicating the logic here...
|
||||
final List<Message> messagesToRemove = new ArrayList<Message>();
|
||||
for (MessageInfoHolder holder : holders) {
|
||||
if (holder.selected) {
|
||||
messagesToRemove.add(holder.message);
|
||||
}
|
||||
}
|
||||
|
||||
private void moveToSpamFolder(MessageInfoHolder holder) {
|
||||
if (!mController.isMoveCapable(holder.message)) {
|
||||
Toast toast = Toast.makeText(this, R.string.move_copy_cannot_copy_unsynced_message, Toast.LENGTH_LONG);
|
||||
toast.show();
|
||||
return;
|
||||
}
|
||||
onMoveChosen(holder, holder.message.getFolder().getAccount().getSpamFolderName());
|
||||
}
|
||||
|
||||
private void onCopy(MessageInfoHolder holder) {
|
||||
if (!mController.isCopyCapable(holder.message.getFolder().getAccount())) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!mController.isCopyCapable(holder.message)) {
|
||||
Toast toast = Toast.makeText(this, R.string.move_copy_cannot_copy_unsynced_message, Toast.LENGTH_LONG);
|
||||
toast.show();
|
||||
return;
|
||||
}
|
||||
|
||||
final Account account = holder.message.getFolder().getAccount();
|
||||
|
||||
Intent intent = new Intent(this, ChooseFolder.class);
|
||||
intent.putExtra(ChooseFolder.EXTRA_ACCOUNT, account.getUuid());
|
||||
intent.putExtra(ChooseFolder.EXTRA_CUR_FOLDER, holder.folder.name);
|
||||
intent.putExtra(ChooseFolder.EXTRA_SEL_FOLDER, account.getLastSelectedFolderName());
|
||||
intent.putExtra(ChooseFolder.EXTRA_MESSAGE, holder.message.makeMessageReference());
|
||||
startActivityForResult(intent, ACTIVITY_CHOOSE_FOLDER_COPY);
|
||||
mHandler.removeMessages(holders);
|
||||
mController.deleteMessages(messagesToRemove.toArray(EMPTY_MESSAGE_ARRAY), null);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||
if (resultCode != RESULT_OK)
|
||||
if (resultCode != RESULT_OK) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (requestCode) {
|
||||
case ACTIVITY_CHOOSE_FOLDER_MOVE:
|
||||
case ACTIVITY_CHOOSE_FOLDER_COPY: {
|
||||
if (data == null)
|
||||
if (data == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
final String destFolderName = data.getStringExtra(ChooseFolder.EXTRA_NEW_FOLDER);
|
||||
final MessageReference ref = data.getParcelableExtra(ChooseFolder.EXTRA_MESSAGE);
|
||||
final MessageInfoHolder m = mAdapter.getMessage(ref);
|
||||
|
||||
if ((destFolderName != null) && (m != null)) {
|
||||
final Account account = m.message.getFolder().getAccount();
|
||||
if (destFolderName != null) {
|
||||
final List<MessageInfoHolder> holders = mActiveMessages;
|
||||
|
||||
mActiveMessages = null; // don't need it any more
|
||||
|
||||
final Account account = holders.get(0).message.getFolder().getAccount();
|
||||
account.setLastSelectedFolderName(destFolderName);
|
||||
|
||||
switch (requestCode) {
|
||||
case ACTIVITY_CHOOSE_FOLDER_MOVE:
|
||||
onMoveChosen(m, destFolderName);
|
||||
move(holders, destFolderName);
|
||||
break;
|
||||
|
||||
case ACTIVITY_CHOOSE_FOLDER_COPY:
|
||||
onCopyChosen(m, destFolderName);
|
||||
copy(holders, destFolderName);
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ACTIVITY_CHOOSE_FOLDER_MOVE_BATCH:
|
||||
case ACTIVITY_CHOOSE_FOLDER_COPY_BATCH: {
|
||||
final String destFolderName = data.getStringExtra(ChooseFolder.EXTRA_NEW_FOLDER);
|
||||
final String accountUuid = data.getStringExtra(ChooseFolder.EXTRA_ACCOUNT);
|
||||
final Account account = Preferences.getPreferences(this).getAccount(accountUuid);
|
||||
|
||||
account.setLastSelectedFolderName(destFolderName);
|
||||
|
||||
switch (requestCode) {
|
||||
case ACTIVITY_CHOOSE_FOLDER_MOVE_BATCH:
|
||||
onMoveChosenBatch(destFolderName);
|
||||
break;
|
||||
|
||||
case ACTIVITY_CHOOSE_FOLDER_COPY_BATCH:
|
||||
onCopyChosenBatch(destFolderName);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void onMoveChosen(MessageInfoHolder holder, String folderName) {
|
||||
if (mController.isMoveCapable(holder.message.getFolder().getAccount()) && folderName != null) {
|
||||
if (K9.FOLDER_NONE.equalsIgnoreCase(folderName)) {
|
||||
return;
|
||||
}
|
||||
mAdapter.removeMessage(holder);
|
||||
mController.moveMessage(holder.message.getFolder().getAccount(), holder.message.getFolder().getName(), holder.message, folderName, null);
|
||||
}
|
||||
}
|
||||
|
||||
private void onCopyChosen(MessageInfoHolder holder, String folderName) {
|
||||
if (mController.isCopyCapable(holder.message.getFolder().getAccount()) && folderName != null) {
|
||||
mController.copyMessage(holder.message.getFolder().getAccount(),
|
||||
holder.message.getFolder().getName(), holder.message, folderName, null);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1308,9 +1239,9 @@ public class MessageList
|
||||
new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
moveToSpamFolder(mSelectedMessage);
|
||||
onSpamConfirmed(mActiveMessages);
|
||||
// No further need for this reference
|
||||
mSelectedMessage = null;
|
||||
mActiveMessages = null;
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -1353,6 +1284,7 @@ public class MessageList
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
final List<MessageInfoHolder> selection = getSelectionFromCheckboxes();
|
||||
int itemId = item.getItemId();
|
||||
switch (itemId) {
|
||||
case R.id.compose: {
|
||||
@ -1399,23 +1331,23 @@ public class MessageList
|
||||
return true;
|
||||
}
|
||||
case R.id.batch_delete_op: {
|
||||
deleteSelected();
|
||||
onDelete(selection);
|
||||
return true;
|
||||
}
|
||||
case R.id.batch_mark_read_op: {
|
||||
flagSelected(Flag.SEEN, true);
|
||||
setFlag(selection, Flag.SEEN, true);
|
||||
return true;
|
||||
}
|
||||
case R.id.batch_mark_unread_op: {
|
||||
flagSelected(Flag.SEEN, false);
|
||||
setFlag(selection, Flag.SEEN, false);
|
||||
return true;
|
||||
}
|
||||
case R.id.batch_flag_op: {
|
||||
flagSelected(Flag.FLAGGED, true);
|
||||
setFlag(selection, Flag.FLAGGED, true);
|
||||
return true;
|
||||
}
|
||||
case R.id.batch_unflag_op: {
|
||||
flagSelected(Flag.FLAGGED, false);
|
||||
setFlag(selection, Flag.FLAGGED, false);
|
||||
return true;
|
||||
}
|
||||
case R.id.app_settings: {
|
||||
@ -1462,19 +1394,19 @@ public class MessageList
|
||||
return true;
|
||||
}
|
||||
case R.id.batch_copy_op: {
|
||||
onCopyBatch();
|
||||
onCopy(selection);
|
||||
return true;
|
||||
}
|
||||
case R.id.batch_archive_op: {
|
||||
onArchiveBatch();
|
||||
onArchive(selection);
|
||||
return true;
|
||||
}
|
||||
case R.id.batch_spam_op: {
|
||||
onSpamBatch();
|
||||
onSpam(selection);
|
||||
return true;
|
||||
}
|
||||
case R.id.batch_move_op: {
|
||||
onMoveBatch();
|
||||
onMove(selection);
|
||||
return true;
|
||||
}
|
||||
case R.id.expunge: {
|
||||
@ -1564,28 +1496,26 @@ public class MessageList
|
||||
@Override
|
||||
public boolean onContextItemSelected(MenuItem item) {
|
||||
AdapterContextMenuInfo info = (AdapterContextMenuInfo) item.getMenuInfo();
|
||||
MessageInfoHolder holder = mSelectedMessage;
|
||||
final MessageInfoHolder holder = mSelectedMessage == null ? (MessageInfoHolder) mAdapter.getItem(info.position) : mSelectedMessage;
|
||||
// don't need this anymore
|
||||
mSelectedMessage = null;
|
||||
if (holder == null) {
|
||||
holder = (MessageInfoHolder) mAdapter.getItem(info.position);
|
||||
}
|
||||
|
||||
final List<MessageInfoHolder> selection = getSelectionFromMessage(holder);
|
||||
switch (item.getItemId()) {
|
||||
case R.id.open: {
|
||||
onOpenMessage(holder);
|
||||
break;
|
||||
}
|
||||
case R.id.select: {
|
||||
setSelected(holder, true);
|
||||
setSelected(selection, true);
|
||||
break;
|
||||
}
|
||||
case R.id.deselect: {
|
||||
setSelected(holder, false);
|
||||
setSelected(selection, false);
|
||||
break;
|
||||
}
|
||||
case R.id.delete: {
|
||||
onDelete(holder, info.position);
|
||||
onDelete(selection);
|
||||
break;
|
||||
}
|
||||
case R.id.reply: {
|
||||
@ -1614,19 +1544,19 @@ public class MessageList
|
||||
break;
|
||||
}
|
||||
case R.id.archive: {
|
||||
onArchive(holder);
|
||||
onArchive(selection);
|
||||
break;
|
||||
}
|
||||
case R.id.spam: {
|
||||
onSpam(holder);
|
||||
onSpam(selection);
|
||||
break;
|
||||
}
|
||||
case R.id.move: {
|
||||
onMove(holder);
|
||||
onMove(selection);
|
||||
break;
|
||||
}
|
||||
case R.id.copy: {
|
||||
onCopy(holder);
|
||||
onCopy(selection);
|
||||
break;
|
||||
}
|
||||
case R.id.send_alternate: {
|
||||
@ -1800,7 +1730,7 @@ public class MessageList
|
||||
if (holder == null) {
|
||||
Log.w(K9.LOG_TAG, "Got callback to remove non-existent message with UID " + message.getUid());
|
||||
} else {
|
||||
removeMessage(holder);
|
||||
removeMessages(Collections.singletonList(holder));
|
||||
}
|
||||
}
|
||||
|
||||
@ -1840,7 +1770,7 @@ public class MessageList
|
||||
public void listLocalMessagesRemoveMessage(Account account, String folder, Message message) {
|
||||
MessageInfoHolder holder = getMessage(message);
|
||||
if (holder != null) {
|
||||
removeMessage(holder);
|
||||
removeMessages(Collections.singletonList(holder));
|
||||
}
|
||||
}
|
||||
|
||||
@ -1914,22 +1844,18 @@ public class MessageList
|
||||
mSelectedCount--;
|
||||
toggleBatchButtons();
|
||||
}
|
||||
mAdapter.removeMessage(holder);
|
||||
mAdapter.removeMessages(Collections.singletonList(holder));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param holders
|
||||
* Never {@code null}.
|
||||
*/
|
||||
public void removeMessages(List<MessageInfoHolder> holders) {
|
||||
if (holders != null) {
|
||||
mHandler.removeMessage(holders);
|
||||
}
|
||||
}
|
||||
|
||||
public void removeMessage(MessageInfoHolder holder) {
|
||||
List<MessageInfoHolder> messages = new ArrayList<MessageInfoHolder>();
|
||||
messages.add(holder);
|
||||
removeMessages(messages);
|
||||
mHandler.removeMessages(holders);
|
||||
}
|
||||
|
||||
private void addOrUpdateMessage(Account account, String folderName, Message message, boolean verifyAgainstSearch) {
|
||||
@ -2558,171 +2484,291 @@ public class MessageList
|
||||
toggleBatchButtons();
|
||||
}
|
||||
|
||||
private void setSelected(MessageInfoHolder holder, boolean newState) {
|
||||
private void setSelected(final List<MessageInfoHolder> holders, final boolean newState) {
|
||||
for (final MessageInfoHolder holder : holders) {
|
||||
if (holder.selected != newState) {
|
||||
holder.selected = newState;
|
||||
mSelectedCount += (newState ? 1 : -1);
|
||||
}
|
||||
}
|
||||
mAdapter.notifyDataSetChanged();
|
||||
toggleBatchButtons();
|
||||
}
|
||||
|
||||
private void flagSelected(Flag flag, boolean newState) {
|
||||
List<Message> messageList = new ArrayList<Message>();
|
||||
synchronized (mAdapter.messages) {
|
||||
for (MessageInfoHolder holder : mAdapter.messages) {
|
||||
if (holder.selected) {
|
||||
messageList.add(holder.message);
|
||||
/**
|
||||
* @param holders
|
||||
* Messages to update. Never {@code null}.
|
||||
* @param flag
|
||||
* Flag to be updated on the specified messages. Never
|
||||
* {@code null}.
|
||||
* @param newState
|
||||
* State to set for the given flag.
|
||||
*/
|
||||
private void setFlag(final List<MessageInfoHolder> holders, final Flag flag, final boolean newState) {
|
||||
if (holders.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
final Message[] messageList = new Message[holders.size()];
|
||||
int i = 0;
|
||||
for (final Iterator<MessageInfoHolder> iterator = holders.iterator(); iterator.hasNext(); i++) {
|
||||
final MessageInfoHolder holder = iterator.next();
|
||||
messageList[i] = holder.message;
|
||||
if (flag == Flag.SEEN) {
|
||||
holder.read = newState;
|
||||
} else if (flag == Flag.FLAGGED) {
|
||||
holder.flagged = newState;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
mController.setFlag(messageList.toArray(EMPTY_MESSAGE_ARRAY), flag, newState);
|
||||
mController.setFlag(messageList, flag, newState);
|
||||
mHandler.sortMessages();
|
||||
}
|
||||
|
||||
private void deleteSelected() {
|
||||
List<Message> messageList = new ArrayList<Message>();
|
||||
List<MessageInfoHolder> removeHolderList = new ArrayList<MessageInfoHolder>();
|
||||
synchronized (mAdapter.messages) {
|
||||
for (MessageInfoHolder holder : mAdapter.messages) {
|
||||
if (holder.selected) {
|
||||
removeHolderList.add(holder);
|
||||
messageList.add(holder.message);
|
||||
}
|
||||
}
|
||||
}
|
||||
mAdapter.removeMessages(removeHolderList);
|
||||
|
||||
mController.deleteMessages(messageList.toArray(EMPTY_MESSAGE_ARRAY), null);
|
||||
mSelectedCount = 0;
|
||||
toggleBatchButtons();
|
||||
}
|
||||
|
||||
private void onMoveBatch() {
|
||||
if (!mController.isMoveCapable(mAccount)) {
|
||||
/**
|
||||
* Display the message move activity.
|
||||
*
|
||||
* @param holders
|
||||
* Never {@code null}.
|
||||
*/
|
||||
private void onMove(final List<MessageInfoHolder> holders) {
|
||||
if (!checkCopyOrMovePossible(holders, FolderOperation.MOVE)) {
|
||||
return;
|
||||
}
|
||||
|
||||
synchronized (mAdapter.messages) {
|
||||
for (MessageInfoHolder holder : mAdapter.messages) {
|
||||
if (holder.selected) {
|
||||
Message message = holder.message;
|
||||
if (!mController.isMoveCapable(message)) {
|
||||
Toast toast = Toast.makeText(this,
|
||||
R.string.move_copy_cannot_copy_unsynced_message, Toast.LENGTH_LONG);
|
||||
toast.show();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
final Folder folder = holders.size() == 1 ? holders.get(0).message.getFolder() : mCurrentFolder.folder;
|
||||
displayFolderChoice(ACTIVITY_CHOOSE_FOLDER_MOVE, folder, holders);
|
||||
}
|
||||
|
||||
final Folder folder = mCurrentFolder.folder;
|
||||
/**
|
||||
* Display the message copy activity.
|
||||
*
|
||||
* @param holders
|
||||
* Never {@code null}.
|
||||
*/
|
||||
private void onCopy(final List<MessageInfoHolder> holders) {
|
||||
if (!checkCopyOrMovePossible(holders, FolderOperation.COPY)) {
|
||||
return;
|
||||
}
|
||||
|
||||
final Folder folder = holders.size() == 1 ? holders.get(0).message.getFolder() : mCurrentFolder.folder;
|
||||
displayFolderChoice(ACTIVITY_CHOOSE_FOLDER_COPY, folder, holders);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to manage the invocation of
|
||||
* {@link #startActivityForResult(Intent, int)} for a folder operation
|
||||
* ({@link ChooseFolder} activity), while saving a list of associated
|
||||
* messages.
|
||||
*
|
||||
* @param requestCode
|
||||
* If >= 0, this code will be returned in onActivityResult() when
|
||||
* the activity exits.
|
||||
* @param folder
|
||||
* Never {@code null}.
|
||||
* @param holders
|
||||
* Messages to be affected by the folder operation. Never
|
||||
* {@code null}.
|
||||
* @see #startActivityForResult(Intent, int)
|
||||
*/
|
||||
private void displayFolderChoice(final int requestCode, final Folder folder, final List<MessageInfoHolder> holders) {
|
||||
final Intent intent = new Intent(this, ChooseFolder.class);
|
||||
intent.putExtra(ChooseFolder.EXTRA_ACCOUNT, mAccount.getUuid());
|
||||
intent.putExtra(ChooseFolder.EXTRA_ACCOUNT, folder.getAccount().getUuid());
|
||||
intent.putExtra(ChooseFolder.EXTRA_CUR_FOLDER, folder.getName());
|
||||
intent.putExtra(ChooseFolder.EXTRA_SEL_FOLDER, folder.getAccount().getLastSelectedFolderName());
|
||||
startActivityForResult(intent, ACTIVITY_CHOOSE_FOLDER_MOVE_BATCH);
|
||||
// remember the selected messages for #onActivityResult
|
||||
mActiveMessages = holders;
|
||||
startActivityForResult(intent, requestCode);
|
||||
}
|
||||
|
||||
private void onMoveChosenBatch(String folderName) {
|
||||
if (!mController.isMoveCapable(mAccount)) {
|
||||
return;
|
||||
}
|
||||
List<Message> messageList = new ArrayList<Message>();
|
||||
|
||||
List<MessageInfoHolder> removeHolderList = new ArrayList<MessageInfoHolder>();
|
||||
synchronized (mAdapter.messages) {
|
||||
for (MessageInfoHolder holder : mAdapter.messages) {
|
||||
if (holder.selected) {
|
||||
Message message = holder.message;
|
||||
if (!mController.isMoveCapable(message)) {
|
||||
Toast toast = Toast.makeText(this,
|
||||
R.string.move_copy_cannot_copy_unsynced_message, Toast.LENGTH_LONG);
|
||||
toast.show();
|
||||
return;
|
||||
}
|
||||
messageList.add(holder.message);
|
||||
removeHolderList.add(holder);
|
||||
}
|
||||
}
|
||||
}
|
||||
mAdapter.removeMessages(removeHolderList);
|
||||
|
||||
mController.moveMessages(mAccount, mCurrentFolder.name, messageList.toArray(EMPTY_MESSAGE_ARRAY), folderName, null);
|
||||
mSelectedCount = 0;
|
||||
toggleBatchButtons();
|
||||
}
|
||||
|
||||
private void onArchiveBatch() {
|
||||
String folderName = mAccount.getArchiveFolderName();
|
||||
/**
|
||||
* @param holders
|
||||
* Never {@code null}.
|
||||
*/
|
||||
private void onArchive(final List<MessageInfoHolder> holders) {
|
||||
final String folderName = holders.get(0).message.getFolder().getAccount().getArchiveFolderName();
|
||||
if (K9.FOLDER_NONE.equalsIgnoreCase(folderName)) {
|
||||
return;
|
||||
}
|
||||
onMoveChosenBatch(folderName);
|
||||
// TODO one should separate messages by account and call move afterwards
|
||||
// (because each account might have a specific Archive folder name)
|
||||
move(holders, folderName);
|
||||
}
|
||||
|
||||
private void onSpamBatch() {
|
||||
String folderName = mAccount.getSpamFolderName();
|
||||
/**
|
||||
* @param holders
|
||||
* Never {@code null}.
|
||||
*/
|
||||
private void onSpam(final List<MessageInfoHolder> holders) {
|
||||
if (K9.confirmSpam()) {
|
||||
// remember the message selection for #onCreateDialog(int)
|
||||
mActiveMessages = holders;
|
||||
showDialog(R.id.dialog_confirm_spam);
|
||||
} else {
|
||||
onSpamConfirmed(holders);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param holders
|
||||
* Never {@code null}.
|
||||
*/
|
||||
private void onSpamConfirmed(final List<MessageInfoHolder> holders) {
|
||||
final String folderName = holders.get(0).message.getFolder().getAccount().getSpamFolderName();
|
||||
if (K9.FOLDER_NONE.equalsIgnoreCase(folderName)) {
|
||||
return;
|
||||
}
|
||||
onMoveChosenBatch(folderName);
|
||||
// TODO one should separate messages by account and call move afterwards
|
||||
// (because each account might have a specific Spam folder name)
|
||||
move(holders, folderName);
|
||||
}
|
||||
|
||||
private void onCopyBatch() {
|
||||
if (!mController.isCopyCapable(mAccount)) {
|
||||
return;
|
||||
private static enum FolderOperation {
|
||||
COPY, MOVE
|
||||
}
|
||||
|
||||
synchronized (mAdapter.messages) {
|
||||
for (MessageInfoHolder holder : mAdapter.messages) {
|
||||
if (holder.selected) {
|
||||
Message message = holder.message;
|
||||
if (!mController.isCopyCapable(message)) {
|
||||
Toast toast = Toast.makeText(this,
|
||||
R.string.move_copy_cannot_copy_unsynced_message, Toast.LENGTH_LONG);
|
||||
/**
|
||||
* Display an Toast message if any message isn't synchronized
|
||||
*
|
||||
* @param holders
|
||||
* Never <code>null</code>.
|
||||
* @param move
|
||||
* <code>true</code> to check move availability,
|
||||
* <code>false</code> to check the copy availability
|
||||
*
|
||||
* @return <code>true</code> if operation is possible
|
||||
*/
|
||||
private boolean checkCopyOrMovePossible(final List<MessageInfoHolder> holders, final FolderOperation operation) {
|
||||
if (holders.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
boolean first = true;
|
||||
for (final MessageInfoHolder holder : holders) {
|
||||
final Message message = holder.message;
|
||||
if (first) {
|
||||
first = false;
|
||||
// account check
|
||||
final Account account = message.getFolder().getAccount();
|
||||
if ((operation == FolderOperation.MOVE && !mController.isMoveCapable(account)) || (operation == FolderOperation.COPY && !mController.isCopyCapable(account))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// message check
|
||||
if ((operation == FolderOperation.MOVE && !mController.isMoveCapable(message)) || (operation == FolderOperation.COPY && !mController.isCopyCapable(message))) {
|
||||
final Toast toast = Toast.makeText(this, R.string.move_copy_cannot_copy_unsynced_message,
|
||||
Toast.LENGTH_LONG);
|
||||
toast.show();
|
||||
return;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
final Folder folder = mCurrentFolder.folder;
|
||||
final Intent intent = new Intent(this, ChooseFolder.class);
|
||||
intent.putExtra(ChooseFolder.EXTRA_ACCOUNT, mAccount.getUuid());
|
||||
intent.putExtra(ChooseFolder.EXTRA_CUR_FOLDER, folder.getName());
|
||||
intent.putExtra(ChooseFolder.EXTRA_SEL_FOLDER, folder.getAccount().getLastSelectedFolderName());
|
||||
startActivityForResult(intent, ACTIVITY_CHOOSE_FOLDER_COPY_BATCH);
|
||||
/**
|
||||
* Helper method to get a List of message ready to be processed. This implementation will return a list containing the sole argument.
|
||||
*
|
||||
* @param holder Never {@code null}.
|
||||
* @return Never {@code null}.
|
||||
*/
|
||||
private List<MessageInfoHolder> getSelectionFromMessage(final MessageInfoHolder holder) {
|
||||
final List<MessageInfoHolder> selection = Collections.singletonList(holder);
|
||||
return selection;
|
||||
}
|
||||
|
||||
private void onCopyChosenBatch(String folderName) {
|
||||
if (!mController.isCopyCapable(mAccount)) {
|
||||
return;
|
||||
}
|
||||
|
||||
List<Message> messageList = new ArrayList<Message>();
|
||||
/**
|
||||
* Helper method to get a List of message ready to be processed. This implementation will iterate over messages and choose the checked ones.
|
||||
*
|
||||
* @return Never {@code null}.
|
||||
*/
|
||||
private List<MessageInfoHolder> getSelectionFromCheckboxes() {
|
||||
final List<MessageInfoHolder> selection = new ArrayList<MessageInfoHolder>();
|
||||
synchronized (mAdapter.messages) {
|
||||
for (MessageInfoHolder holder : mAdapter.messages) {
|
||||
for (final MessageInfoHolder holder : mAdapter.messages) {
|
||||
if (holder.selected) {
|
||||
Message message = holder.message;
|
||||
if (!mController.isCopyCapable(message)) {
|
||||
Toast toast = Toast.makeText(this,
|
||||
R.string.move_copy_cannot_copy_unsynced_message, Toast.LENGTH_LONG);
|
||||
toast.show();
|
||||
selection.add(holder);
|
||||
}
|
||||
}
|
||||
}
|
||||
return selection;
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy the specified messages to the specified folder.
|
||||
*
|
||||
* @param holders Never {@code null}.
|
||||
* @param destination Never {@code null}.
|
||||
*/
|
||||
private void copy(final List<MessageInfoHolder> holders, final String destination) {
|
||||
copyOrMove(holders, destination, FolderOperation.COPY);
|
||||
}
|
||||
|
||||
/**
|
||||
* Move the specified messages to the specified folder.
|
||||
*
|
||||
* @param holders Never {@code null}.
|
||||
* @param destination Never {@code null}.
|
||||
*/
|
||||
private void move(final List<MessageInfoHolder> holders, final String destination) {
|
||||
copyOrMove(holders, destination, FolderOperation.MOVE);
|
||||
}
|
||||
|
||||
/**
|
||||
* The underlying implementation for {@link #copy(List, String)} and
|
||||
* {@link #move(List, String)}. This method was added mainly because those 2
|
||||
* methods share common behavior.
|
||||
*
|
||||
* @param holders
|
||||
* Never {@code null}.
|
||||
* @param destination
|
||||
* Never {@code null}.
|
||||
* @param operation
|
||||
* Never {@code null}.
|
||||
*/
|
||||
private void copyOrMove(final List<MessageInfoHolder> holders, final String destination, final FolderOperation operation) {
|
||||
if (K9.FOLDER_NONE.equalsIgnoreCase(destination)) {
|
||||
return;
|
||||
}
|
||||
messageList.add(holder.message);
|
||||
|
||||
boolean first = true;
|
||||
Account account = null;
|
||||
String folderName = null;
|
||||
|
||||
final List<Message> messages = new ArrayList<Message>(holders.size());
|
||||
|
||||
for (final MessageInfoHolder holder : holders) {
|
||||
final Message message = holder.message;
|
||||
if (first) {
|
||||
first = false;
|
||||
folderName = message.getFolder().getName();
|
||||
account = message.getFolder().getAccount();
|
||||
if ((operation == FolderOperation.MOVE && !mController.isMoveCapable(account)) || (operation == FolderOperation.COPY && !mController.isCopyCapable(account))) {
|
||||
// account is not copy/move capable
|
||||
return;
|
||||
}
|
||||
} else if (!account.equals(message.getFolder().getAccount())
|
||||
|| !folderName.equals(message.getFolder().getName())) {
|
||||
// make sure all messages come from the same account/folder?
|
||||
return;
|
||||
}
|
||||
if ((operation == FolderOperation.MOVE && !mController.isMoveCapable(message)) || (operation == FolderOperation.COPY && !mController.isCopyCapable(message))) {
|
||||
final Toast toast = Toast.makeText(this, R.string.move_copy_cannot_copy_unsynced_message,
|
||||
Toast.LENGTH_LONG);
|
||||
toast.show();
|
||||
|
||||
// XXX return meaningful error value?
|
||||
|
||||
// message isn't synchronized
|
||||
return;
|
||||
}
|
||||
messages.add(message);
|
||||
}
|
||||
|
||||
if (operation == FolderOperation.MOVE) {
|
||||
mController.moveMessages(account, folderName, messages.toArray(new Message[messages.size()]), destination,
|
||||
null);
|
||||
mHandler.removeMessages(holders);
|
||||
} else {
|
||||
mController.copyMessages(account, folderName, messages.toArray(new Message[messages.size()]), destination,
|
||||
null);
|
||||
}
|
||||
mController.copyMessages(mAccount, mCurrentFolder.name, messageList.toArray(EMPTY_MESSAGE_ARRAY), folderName, null);
|
||||
}
|
||||
|
||||
protected void onAccountUnavailable() {
|
||||
|
Loading…
Reference in New Issue
Block a user