2010-07-13 17:49:28 -04:00
|
|
|
package com.fsck.k9.activity;
|
|
|
|
|
|
|
|
import java.util.ArrayList;
|
|
|
|
import java.util.Collections;
|
2010-09-21 18:12:45 -04:00
|
|
|
import java.util.Comparator;
|
|
|
|
import java.util.EnumMap;
|
2010-10-08 02:18:30 -04:00
|
|
|
import java.util.Iterator;
|
2010-07-13 17:49:28 -04:00
|
|
|
import java.util.List;
|
2010-09-21 18:12:45 -04:00
|
|
|
import java.util.Map;
|
2010-07-13 17:49:28 -04:00
|
|
|
|
|
|
|
import android.app.AlertDialog;
|
|
|
|
import android.app.Dialog;
|
|
|
|
import android.content.Context;
|
|
|
|
import android.content.Intent;
|
2012-05-16 14:35:55 -04:00
|
|
|
import android.content.SharedPreferences.Editor;
|
2011-04-26 10:49:25 -04:00
|
|
|
import android.graphics.Color;
|
2010-07-13 17:49:28 -04:00
|
|
|
import android.graphics.Typeface;
|
|
|
|
import android.graphics.drawable.Drawable;
|
|
|
|
import android.os.Bundle;
|
|
|
|
import android.text.Spannable;
|
2010-08-30 10:37:34 -04:00
|
|
|
import android.text.SpannableStringBuilder;
|
2011-11-09 23:09:54 -05:00
|
|
|
import android.text.style.AbsoluteSizeSpan;
|
2011-04-26 10:49:25 -04:00
|
|
|
import android.text.style.ForegroundColorSpan;
|
2011-04-16 05:13:54 -04:00
|
|
|
import android.text.style.StyleSpan;
|
2010-07-13 17:49:28 -04:00
|
|
|
import android.util.Log;
|
|
|
|
import android.util.TypedValue;
|
|
|
|
import android.view.ContextMenu;
|
2011-06-04 16:57:03 -04:00
|
|
|
import android.view.ContextMenu.ContextMenuInfo;
|
2010-07-13 17:49:28 -04:00
|
|
|
import android.view.GestureDetector;
|
|
|
|
import android.view.KeyEvent;
|
|
|
|
import android.view.LayoutInflater;
|
|
|
|
import android.view.Menu;
|
|
|
|
import android.view.MenuItem;
|
|
|
|
import android.view.MotionEvent;
|
|
|
|
import android.view.View;
|
2011-06-04 16:57:03 -04:00
|
|
|
import android.view.View.OnClickListener;
|
2010-07-13 17:49:28 -04:00
|
|
|
import android.view.ViewGroup;
|
|
|
|
import android.view.Window;
|
2011-06-04 16:57:03 -04:00
|
|
|
import android.view.animation.Animation;
|
|
|
|
import android.view.animation.Animation.AnimationListener;
|
|
|
|
import android.view.animation.AnimationUtils;
|
2010-07-13 17:49:28 -04:00
|
|
|
import android.widget.AdapterView;
|
2011-06-04 16:57:03 -04:00
|
|
|
import android.widget.AdapterView.AdapterContextMenuInfo;
|
2010-07-13 17:49:28 -04:00
|
|
|
import android.widget.BaseAdapter;
|
|
|
|
import android.widget.CheckBox;
|
|
|
|
import android.widget.CompoundButton;
|
2011-06-04 16:57:03 -04:00
|
|
|
import android.widget.CompoundButton.OnCheckedChangeListener;
|
2010-07-13 17:49:28 -04:00
|
|
|
import android.widget.ImageButton;
|
|
|
|
import android.widget.ListView;
|
|
|
|
import android.widget.ProgressBar;
|
|
|
|
import android.widget.TextView;
|
|
|
|
import android.widget.Toast;
|
|
|
|
|
|
|
|
import com.fsck.k9.Account;
|
2012-04-08 22:29:08 -04:00
|
|
|
import com.fsck.k9.Account.SortType;
|
2010-07-13 17:49:28 -04:00
|
|
|
import com.fsck.k9.AccountStats;
|
2012-01-31 21:07:19 -05:00
|
|
|
import com.fsck.k9.BaseAccount;
|
2010-07-13 17:49:28 -04:00
|
|
|
import com.fsck.k9.FontSizes;
|
|
|
|
import com.fsck.k9.K9;
|
|
|
|
import com.fsck.k9.Preferences;
|
|
|
|
import com.fsck.k9.R;
|
2012-01-31 21:07:19 -05:00
|
|
|
import com.fsck.k9.SearchAccount;
|
2010-07-13 17:49:28 -04:00
|
|
|
import com.fsck.k9.SearchSpecification;
|
|
|
|
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;
|
2011-06-04 16:57:03 -04:00
|
|
|
import com.fsck.k9.controller.MessagingListener;
|
2010-10-03 06:56:16 -04:00
|
|
|
import com.fsck.k9.helper.MessageHelper;
|
2010-07-13 17:49:28 -04:00
|
|
|
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.LocalStore.LocalFolder;
|
2012-02-04 08:52:45 -05:00
|
|
|
import com.fsck.k9.mail.store.LocalStore.LocalMessage;
|
2011-06-04 16:57:03 -04:00
|
|
|
import com.fsck.k9.mail.store.StorageManager;
|
2010-12-28 04:11:10 -05:00
|
|
|
|
2010-07-13 17:49:28 -04:00
|
|
|
|
|
|
|
/**
|
|
|
|
* MessageList is the primary user interface for the program. This Activity
|
|
|
|
* shows a list of messages.
|
|
|
|
* From this Activity the user can perform all standard message operations.
|
|
|
|
*/
|
|
|
|
public class MessageList
|
2010-10-05 02:04:28 -04:00
|
|
|
extends K9Activity
|
2011-02-06 17:09:48 -05:00
|
|
|
implements OnClickListener, AdapterView.OnItemClickListener, AnimationListener {
|
2010-08-02 07:55:31 -04:00
|
|
|
|
2010-09-21 18:12:45 -04:00
|
|
|
/**
|
|
|
|
* Reverses the result of a {@link Comparator}.
|
2010-10-03 20:01:59 -04:00
|
|
|
*
|
2010-09-21 18:12:45 -04:00
|
|
|
* @param <T>
|
|
|
|
*/
|
2011-02-06 17:09:48 -05:00
|
|
|
public static class ReverseComparator<T> implements Comparator<T> {
|
2010-09-21 18:12:45 -04:00
|
|
|
private Comparator<T> mDelegate;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @param delegate
|
|
|
|
* Never <code>null</code>.
|
|
|
|
*/
|
2011-02-06 17:09:48 -05:00
|
|
|
public ReverseComparator(final Comparator<T> delegate) {
|
2010-09-21 18:12:45 -04:00
|
|
|
mDelegate = delegate;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2011-02-06 17:09:48 -05:00
|
|
|
public int compare(final T object1, final T object2) {
|
2010-09-21 18:12:45 -04:00
|
|
|
// arg1 & 2 are mixed up, this is done on purpose
|
|
|
|
return mDelegate.compare(object2, object1);
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Chains comparator to find a non-0 result.
|
2010-10-03 20:01:59 -04:00
|
|
|
*
|
2010-09-21 18:12:45 -04:00
|
|
|
* @param <T>
|
|
|
|
*/
|
2011-02-06 17:09:48 -05:00
|
|
|
public static class ComparatorChain<T> implements Comparator<T> {
|
2010-09-21 18:12:45 -04:00
|
|
|
|
|
|
|
private List<Comparator<T>> mChain;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @param chain
|
|
|
|
* Comparator chain. Never <code>null</code>.
|
|
|
|
*/
|
2011-02-06 17:09:48 -05:00
|
|
|
public ComparatorChain(final List<Comparator<T>> chain) {
|
2010-09-21 18:12:45 -04:00
|
|
|
mChain = chain;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2011-02-06 17:09:48 -05:00
|
|
|
public int compare(T object1, T object2) {
|
2010-09-21 18:12:45 -04:00
|
|
|
int result = 0;
|
2011-02-06 17:09:48 -05:00
|
|
|
for (final Comparator<T> comparator : mChain) {
|
2010-09-21 18:12:45 -04:00
|
|
|
result = comparator.compare(object1, object2);
|
2011-02-06 17:09:48 -05:00
|
|
|
if (result != 0) {
|
2010-09-21 18:12:45 -04:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
2010-10-03 20:01:59 -04:00
|
|
|
|
2010-09-21 18:12:45 -04:00
|
|
|
}
|
|
|
|
|
2011-02-06 17:09:48 -05:00
|
|
|
public static class AttachmentComparator implements Comparator<MessageInfoHolder> {
|
2010-09-21 18:12:45 -04:00
|
|
|
|
|
|
|
@Override
|
2011-02-06 17:09:48 -05:00
|
|
|
public int compare(MessageInfoHolder object1, MessageInfoHolder object2) {
|
2010-11-26 23:02:56 -05:00
|
|
|
return (object1.message.hasAttachments() ? 0 : 1) - (object2.message.hasAttachments() ? 0 : 1);
|
2010-09-21 18:12:45 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2011-02-06 17:09:48 -05:00
|
|
|
public static class FlaggedComparator implements Comparator<MessageInfoHolder> {
|
2010-09-21 18:12:45 -04:00
|
|
|
|
|
|
|
@Override
|
2011-02-06 17:09:48 -05:00
|
|
|
public int compare(MessageInfoHolder object1, MessageInfoHolder object2) {
|
2010-09-21 18:12:45 -04:00
|
|
|
return (object1.flagged ? 0 : 1) - (object2.flagged ? 0 : 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2011-02-06 17:09:48 -05:00
|
|
|
public static class UnreadComparator implements Comparator<MessageInfoHolder> {
|
2010-09-21 18:12:45 -04:00
|
|
|
|
|
|
|
@Override
|
2011-02-06 17:09:48 -05:00
|
|
|
public int compare(MessageInfoHolder object1, MessageInfoHolder object2) {
|
2010-09-21 18:12:45 -04:00
|
|
|
return (object1.read ? 1 : 0) - (object2.read ? 1 : 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2011-02-06 17:09:48 -05:00
|
|
|
public static class SenderComparator implements Comparator<MessageInfoHolder> {
|
2010-09-21 18:12:45 -04:00
|
|
|
|
|
|
|
@Override
|
2011-02-06 17:09:48 -05:00
|
|
|
public int compare(MessageInfoHolder object1, MessageInfoHolder object2) {
|
2010-09-21 18:12:45 -04:00
|
|
|
return object1.compareCounterparty.toLowerCase().compareTo(object2.compareCounterparty.toLowerCase());
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2011-02-06 17:09:48 -05:00
|
|
|
public static class DateComparator implements Comparator<MessageInfoHolder> {
|
2010-09-21 18:12:45 -04:00
|
|
|
|
|
|
|
@Override
|
2011-02-06 17:09:48 -05:00
|
|
|
public int compare(MessageInfoHolder object1, MessageInfoHolder object2) {
|
2010-09-21 18:12:45 -04:00
|
|
|
return object1.compareDate.compareTo(object2.compareDate);
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2012-03-11 18:48:56 -04:00
|
|
|
public static class ArrivalComparator implements Comparator<MessageInfoHolder> {
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public int compare(MessageInfoHolder object1, MessageInfoHolder object2) {
|
|
|
|
return object1.compareArrival.compareTo(object2.compareArrival);
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2011-02-06 17:09:48 -05:00
|
|
|
public static class SubjectComparator implements Comparator<MessageInfoHolder> {
|
2010-09-21 18:12:45 -04:00
|
|
|
|
|
|
|
@Override
|
2011-02-06 17:09:48 -05:00
|
|
|
public int compare(MessageInfoHolder arg0, MessageInfoHolder arg1) {
|
2010-09-21 18:12:45 -04:00
|
|
|
// XXX doesn't respect the Comparator contract since it alters the compared object
|
2011-02-06 17:09:48 -05:00
|
|
|
if (arg0.compareSubject == null) {
|
2010-11-26 23:03:06 -05:00
|
|
|
arg0.compareSubject = Utility.stripSubject(arg0.message.getSubject());
|
2010-09-21 18:12:45 -04:00
|
|
|
}
|
2011-02-06 17:09:48 -05:00
|
|
|
if (arg1.compareSubject == null) {
|
2010-11-26 23:03:06 -05:00
|
|
|
arg1.compareSubject = Utility.stripSubject(arg1.message.getSubject());
|
2010-09-21 18:12:45 -04:00
|
|
|
}
|
|
|
|
return arg0.compareSubject.compareToIgnoreCase(arg1.compareSubject);
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2010-08-02 07:55:31 -04:00
|
|
|
/**
|
|
|
|
* Immutable empty {@link Message} array
|
|
|
|
*/
|
|
|
|
private static final Message[] EMPTY_MESSAGE_ARRAY = new Message[0];
|
|
|
|
|
2010-07-13 17:49:28 -04:00
|
|
|
private static final int DIALOG_MARK_ALL_AS_READ = 1;
|
|
|
|
|
|
|
|
private static final int ACTIVITY_CHOOSE_FOLDER_MOVE = 1;
|
|
|
|
private static final int ACTIVITY_CHOOSE_FOLDER_COPY = 2;
|
|
|
|
|
|
|
|
private static final String EXTRA_ACCOUNT = "account";
|
|
|
|
private static final String EXTRA_FOLDER = "folder";
|
|
|
|
private static final String EXTRA_QUERY = "query";
|
|
|
|
private static final String EXTRA_QUERY_FLAGS = "queryFlags";
|
|
|
|
private static final String EXTRA_FORBIDDEN_FLAGS = "forbiddenFlags";
|
|
|
|
private static final String EXTRA_INTEGRATE = "integrate";
|
|
|
|
private static final String EXTRA_ACCOUNT_UUIDS = "accountUuids";
|
|
|
|
private static final String EXTRA_FOLDER_NAMES = "folderNames";
|
|
|
|
private static final String EXTRA_TITLE = "title";
|
|
|
|
private static final String EXTRA_LIST_POSITION = "listPosition";
|
2011-12-05 12:16:43 -05:00
|
|
|
private static final String EXTRA_RETURN_FROM_MESSAGE_VIEW = "returnFromMessageView";
|
2010-07-13 17:49:28 -04:00
|
|
|
|
2010-09-21 18:12:45 -04:00
|
|
|
/**
|
2012-04-08 17:17:06 -04:00
|
|
|
* Maps a {@link SortType} to a {@link Comparator} implementation.
|
2010-09-21 18:12:45 -04:00
|
|
|
*/
|
2012-04-08 17:17:06 -04:00
|
|
|
private static final Map<SortType, Comparator<MessageInfoHolder>> SORT_COMPARATORS;
|
2010-09-21 18:12:45 -04:00
|
|
|
|
2011-02-06 17:09:48 -05:00
|
|
|
static {
|
2010-09-21 18:12:45 -04:00
|
|
|
// fill the mapping at class time loading
|
|
|
|
|
2012-04-08 17:17:06 -04:00
|
|
|
final Map<SortType, Comparator<MessageInfoHolder>> map = new EnumMap<SortType, Comparator<MessageInfoHolder>>(SortType.class);
|
|
|
|
map.put(SortType.SORT_ATTACHMENT, new AttachmentComparator());
|
|
|
|
map.put(SortType.SORT_DATE, new DateComparator());
|
|
|
|
map.put(SortType.SORT_ARRIVAL, new ArrivalComparator());
|
|
|
|
map.put(SortType.SORT_FLAGGED, new FlaggedComparator());
|
|
|
|
map.put(SortType.SORT_SENDER, new SenderComparator());
|
|
|
|
map.put(SortType.SORT_SUBJECT, new SubjectComparator());
|
|
|
|
map.put(SortType.SORT_UNREAD, new UnreadComparator());
|
2010-09-21 18:12:45 -04:00
|
|
|
|
|
|
|
// make it immutable to prevent accidental alteration (content is immutable already)
|
|
|
|
SORT_COMPARATORS = Collections.unmodifiableMap(map);
|
|
|
|
}
|
|
|
|
|
2010-07-13 17:49:28 -04:00
|
|
|
private ListView mListView;
|
|
|
|
|
|
|
|
private boolean mTouchView = true;
|
2010-11-04 22:59:26 -04:00
|
|
|
private int mPreviewLines = 0;
|
|
|
|
|
2010-07-13 17:49:28 -04:00
|
|
|
|
|
|
|
private MessageListAdapter mAdapter;
|
2011-02-19 22:50:50 -05:00
|
|
|
private View mFooterView;
|
2010-07-13 17:49:28 -04:00
|
|
|
|
|
|
|
private FolderInfoHolder mCurrentFolder;
|
|
|
|
|
|
|
|
private LayoutInflater mInflater;
|
|
|
|
|
|
|
|
private MessagingController mController;
|
|
|
|
|
|
|
|
private Account mAccount;
|
|
|
|
private int mUnreadMessageCount = 0;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Stores the name of the folder that we want to open as soon as possible
|
|
|
|
* after load.
|
|
|
|
*/
|
|
|
|
private String mFolderName;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* If we're doing a search, this contains the query string.
|
|
|
|
*/
|
|
|
|
private String mQueryString;
|
|
|
|
private Flag[] mQueryFlags = null;
|
|
|
|
private Flag[] mForbiddenFlags = null;
|
|
|
|
private boolean mIntegrate = false;
|
|
|
|
private String[] mAccountUuids = null;
|
|
|
|
private String[] mFolderNames = null;
|
|
|
|
private String mTitle;
|
|
|
|
|
|
|
|
private MessageListHandler mHandler = new MessageListHandler();
|
|
|
|
|
2012-04-08 22:29:08 -04:00
|
|
|
private SortType mSortType = SortType.SORT_DATE;
|
|
|
|
private boolean mSortAscending = true;
|
|
|
|
private boolean mSortDateAscending = false;
|
2010-07-13 17:49:28 -04:00
|
|
|
|
|
|
|
private boolean mStars = true;
|
|
|
|
private boolean mCheckboxes = true;
|
|
|
|
private int mSelectedCount = 0;
|
|
|
|
|
|
|
|
private View mBatchButtonArea;
|
|
|
|
private ImageButton mBatchReadButton;
|
|
|
|
private ImageButton mBatchDeleteButton;
|
|
|
|
private ImageButton mBatchFlagButton;
|
2011-12-24 13:17:12 -05:00
|
|
|
private ImageButton mBatchArchiveButton;
|
|
|
|
private ImageButton mBatchMoveButton;
|
2010-07-13 17:49:28 -04:00
|
|
|
private ImageButton mBatchDoneButton;
|
|
|
|
|
|
|
|
private FontSizes mFontSizes = K9.getFontSizes();
|
|
|
|
|
|
|
|
private Bundle mState = null;
|
|
|
|
|
2011-06-04 16:57:03 -04:00
|
|
|
/**
|
|
|
|
* 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;
|
2010-08-17 22:49:13 -04:00
|
|
|
|
2010-10-05 02:04:28 -04:00
|
|
|
/* package visibility for faster inner class access */
|
|
|
|
MessageHelper mMessageHelper = MessageHelper.getInstance(this);
|
2010-10-03 06:56:16 -04:00
|
|
|
|
2010-11-13 16:40:56 -05:00
|
|
|
private StorageManager.StorageListener mStorageListener = new StorageListenerImplementation();
|
|
|
|
|
2011-02-06 17:09:48 -05:00
|
|
|
private final class StorageListenerImplementation implements StorageManager.StorageListener {
|
2010-11-13 16:40:56 -05:00
|
|
|
@Override
|
2011-02-06 17:09:48 -05:00
|
|
|
public void onUnmount(String providerId) {
|
|
|
|
if (mAccount != null && providerId.equals(mAccount.getLocalStorageProviderId())) {
|
|
|
|
runOnUiThread(new Runnable() {
|
2010-11-13 16:40:56 -05:00
|
|
|
@Override
|
2011-02-06 17:09:48 -05:00
|
|
|
public void run() {
|
2010-11-13 16:40:56 -05:00
|
|
|
onAccountUnavailable();
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2011-02-06 17:09:48 -05:00
|
|
|
public void onMount(String providerId) {
|
2010-11-13 16:40:56 -05:00
|
|
|
// no-op
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-02-06 17:09:48 -05:00
|
|
|
class MessageListHandler {
|
2011-06-04 16:57:03 -04:00
|
|
|
/**
|
|
|
|
* @param messages Never {@code null}.
|
|
|
|
*/
|
|
|
|
public void removeMessages(final List<MessageInfoHolder> messages) {
|
|
|
|
if (messages.isEmpty()) {
|
|
|
|
return;
|
|
|
|
}
|
2011-02-06 17:09:48 -05:00
|
|
|
runOnUiThread(new Runnable() {
|
2011-06-04 17:55:48 -04:00
|
|
|
@Override
|
2011-02-06 17:09:48 -05:00
|
|
|
public void run() {
|
|
|
|
for (MessageInfoHolder message : messages) {
|
|
|
|
if (message != null) {
|
|
|
|
if (mFolderName == null || (message.folder != null && message.folder.name.equals(mFolderName))) {
|
|
|
|
if (message.selected && mSelectedCount > 0) {
|
2010-07-13 17:49:28 -04:00
|
|
|
mSelectedCount--;
|
|
|
|
}
|
|
|
|
mAdapter.messages.remove(message);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
resetUnreadCountOnThread();
|
|
|
|
|
|
|
|
mAdapter.notifyDataSetChanged();
|
|
|
|
toggleBatchButtons();
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2011-06-04 16:57:03 -04:00
|
|
|
/**
|
|
|
|
* @param messages Never {@code null}.
|
|
|
|
*/
|
2011-02-06 17:09:48 -05:00
|
|
|
public void addMessages(final List<MessageInfoHolder> messages) {
|
2011-06-04 16:57:03 -04:00
|
|
|
if (messages.isEmpty()) {
|
|
|
|
return;
|
|
|
|
}
|
2010-07-13 17:49:28 -04:00
|
|
|
final boolean wasEmpty = mAdapter.messages.isEmpty();
|
2011-02-06 17:09:48 -05:00
|
|
|
runOnUiThread(new Runnable() {
|
2011-06-04 17:55:48 -04:00
|
|
|
@Override
|
2011-02-06 17:09:48 -05:00
|
|
|
public void run() {
|
|
|
|
for (final MessageInfoHolder message : messages) {
|
|
|
|
if (mFolderName == null || (message.folder != null && message.folder.name.equals(mFolderName))) {
|
2010-07-13 17:49:28 -04:00
|
|
|
int index;
|
2011-02-06 17:09:48 -05:00
|
|
|
synchronized (mAdapter.messages) {
|
2010-09-21 18:12:45 -04:00
|
|
|
index = Collections.binarySearch(mAdapter.messages, message, getComparator());
|
2010-07-13 17:49:28 -04:00
|
|
|
}
|
|
|
|
|
2011-02-06 17:09:48 -05:00
|
|
|
if (index < 0) {
|
2010-07-13 17:49:28 -04:00
|
|
|
index = (index * -1) - 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
mAdapter.messages.add(index, message);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-02-06 17:09:48 -05:00
|
|
|
if (wasEmpty) {
|
2010-07-13 17:49:28 -04:00
|
|
|
mListView.setSelection(0);
|
|
|
|
}
|
|
|
|
resetUnreadCountOnThread();
|
|
|
|
|
|
|
|
mAdapter.notifyDataSetChanged();
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2011-02-06 17:09:48 -05:00
|
|
|
private void resetUnreadCount() {
|
|
|
|
runOnUiThread(new Runnable() {
|
2011-06-04 17:55:48 -04:00
|
|
|
@Override
|
2011-02-06 17:09:48 -05:00
|
|
|
public void run() {
|
2010-07-13 17:49:28 -04:00
|
|
|
resetUnreadCountOnThread();
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2011-02-06 17:09:48 -05:00
|
|
|
private void resetUnreadCountOnThread() {
|
|
|
|
if (mQueryString != null) {
|
2010-07-13 17:49:28 -04:00
|
|
|
int unreadCount = 0;
|
2011-02-06 17:09:48 -05:00
|
|
|
synchronized (mAdapter.messages) {
|
|
|
|
for (MessageInfoHolder holder : mAdapter.messages) {
|
2010-07-13 17:49:28 -04:00
|
|
|
unreadCount += holder.read ? 0 : 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
mUnreadMessageCount = unreadCount;
|
|
|
|
refreshTitleOnThread();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-02-06 17:09:48 -05:00
|
|
|
private void sortMessages() {
|
2010-09-21 18:12:45 -04:00
|
|
|
final Comparator<MessageInfoHolder> chainComparator = getComparator();
|
|
|
|
|
2011-02-06 17:09:48 -05:00
|
|
|
runOnUiThread(new Runnable() {
|
2011-06-04 17:55:48 -04:00
|
|
|
@Override
|
2011-02-06 17:09:48 -05:00
|
|
|
public void run() {
|
|
|
|
synchronized (mAdapter.messages) {
|
2010-09-21 18:12:45 -04:00
|
|
|
Collections.sort(mAdapter.messages, chainComparator);
|
2010-07-13 17:49:28 -04:00
|
|
|
}
|
|
|
|
mAdapter.notifyDataSetChanged();
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2010-09-21 18:12:45 -04:00
|
|
|
/**
|
|
|
|
* @return The comparator to use to display messages in an ordered
|
|
|
|
* fashion. Never <code>null</code>.
|
|
|
|
*/
|
2011-02-06 17:09:48 -05:00
|
|
|
protected Comparator<MessageInfoHolder> getComparator() {
|
|
|
|
final List<Comparator<MessageInfoHolder>> chain = new ArrayList<Comparator<MessageInfoHolder>>(2 /* we add 2 comparators at most */);
|
2010-09-21 18:12:45 -04:00
|
|
|
|
|
|
|
{
|
|
|
|
// add the specified comparator
|
2012-04-08 22:29:08 -04:00
|
|
|
final Comparator<MessageInfoHolder> comparator = SORT_COMPARATORS.get(mSortType);
|
|
|
|
if (mSortAscending) {
|
2010-09-21 18:12:45 -04:00
|
|
|
chain.add(comparator);
|
2011-02-06 17:09:48 -05:00
|
|
|
} else {
|
2010-09-21 18:12:45 -04:00
|
|
|
chain.add(new ReverseComparator<MessageInfoHolder>(comparator));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
{
|
|
|
|
// add the date comparator if not already specified
|
2012-04-08 22:29:08 -04:00
|
|
|
if (mSortType != SortType.SORT_DATE && mSortType != SortType.SORT_ARRIVAL) {
|
2012-04-08 17:17:06 -04:00
|
|
|
final Comparator<MessageInfoHolder> comparator = SORT_COMPARATORS.get(SortType.SORT_DATE);
|
2012-04-08 22:29:08 -04:00
|
|
|
if (mSortDateAscending) {
|
2010-09-21 18:12:45 -04:00
|
|
|
chain.add(comparator);
|
2011-02-06 17:09:48 -05:00
|
|
|
} else {
|
2010-09-21 18:12:45 -04:00
|
|
|
chain.add(new ReverseComparator<MessageInfoHolder>(comparator));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// build the comparator chain
|
|
|
|
final Comparator<MessageInfoHolder> chainComparator = new ComparatorChain<MessageInfoHolder>(chain);
|
|
|
|
|
|
|
|
return chainComparator;
|
|
|
|
}
|
|
|
|
|
2011-02-06 17:09:48 -05:00
|
|
|
public void folderLoading(String folder, boolean loading) {
|
|
|
|
if (mCurrentFolder != null && mCurrentFolder.name.equals(folder)) {
|
2010-07-13 17:49:28 -04:00
|
|
|
mCurrentFolder.loading = loading;
|
|
|
|
}
|
2011-02-19 22:50:50 -05:00
|
|
|
runOnUiThread(new Runnable() {
|
|
|
|
@Override public void run() {
|
|
|
|
updateFooterView();
|
|
|
|
}
|
|
|
|
});
|
2010-07-13 17:49:28 -04:00
|
|
|
}
|
|
|
|
|
2011-02-06 17:09:48 -05:00
|
|
|
private void refreshTitle() {
|
|
|
|
runOnUiThread(new Runnable() {
|
2011-06-04 17:55:48 -04:00
|
|
|
@Override
|
2011-02-06 17:09:48 -05:00
|
|
|
public void run() {
|
2010-07-13 17:49:28 -04:00
|
|
|
refreshTitleOnThread();
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2011-02-06 17:09:48 -05:00
|
|
|
private void refreshTitleOnThread() {
|
2010-07-13 17:49:28 -04:00
|
|
|
setWindowTitle();
|
|
|
|
setWindowProgress();
|
|
|
|
}
|
|
|
|
|
2011-02-06 17:09:48 -05:00
|
|
|
private void setWindowProgress() {
|
2010-07-13 17:49:28 -04:00
|
|
|
int level = Window.PROGRESS_END;
|
|
|
|
|
2011-02-06 17:09:48 -05:00
|
|
|
if (mCurrentFolder != null && mCurrentFolder.loading && mAdapter.mListener.getFolderTotal() > 0) {
|
2010-09-02 20:56:19 -04:00
|
|
|
int divisor = mAdapter.mListener.getFolderTotal();
|
2011-02-06 17:09:48 -05:00
|
|
|
if (divisor != 0) {
|
2010-09-02 20:56:19 -04:00
|
|
|
level = (Window.PROGRESS_END / divisor) * (mAdapter.mListener.getFolderCompleted()) ;
|
2011-02-06 17:09:48 -05:00
|
|
|
if (level > Window.PROGRESS_END) {
|
2010-09-02 20:56:19 -04:00
|
|
|
level = Window.PROGRESS_END;
|
|
|
|
}
|
2010-07-13 17:49:28 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
getWindow().setFeatureInt(Window.FEATURE_PROGRESS, level);
|
|
|
|
}
|
|
|
|
|
2011-02-06 17:09:48 -05:00
|
|
|
private void setWindowTitle() {
|
2010-07-13 17:49:28 -04:00
|
|
|
String displayName;
|
|
|
|
|
2011-02-06 17:09:48 -05:00
|
|
|
if (mFolderName != null) {
|
2010-07-13 17:49:28 -04:00
|
|
|
displayName = mFolderName;
|
|
|
|
|
2011-04-05 05:12:06 -04:00
|
|
|
if (mAccount.getInboxFolderName().equalsIgnoreCase(displayName)) {
|
2010-07-13 17:49:28 -04:00
|
|
|
displayName = getString(R.string.special_mailbox_name_inbox);
|
2011-02-19 22:47:28 -05:00
|
|
|
} else if (mAccount.getOutboxFolderName().equals(displayName)) {
|
|
|
|
displayName = getString(R.string.special_mailbox_name_outbox);
|
2010-07-13 17:49:28 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
String dispString = mAdapter.mListener.formatHeader(MessageList.this, getString(R.string.message_list_title, mAccount.getDescription(), displayName), mUnreadMessageCount, getTimeFormat());
|
|
|
|
setTitle(dispString);
|
2011-02-06 17:09:48 -05:00
|
|
|
} else if (mQueryString != null) {
|
|
|
|
if (mTitle != null) {
|
2010-07-13 17:49:28 -04:00
|
|
|
String dispString = mAdapter.mListener.formatHeader(MessageList.this, mTitle, mUnreadMessageCount, getTimeFormat());
|
|
|
|
setTitle(dispString);
|
2011-02-06 17:09:48 -05:00
|
|
|
} else {
|
|
|
|
setTitle(getString(R.string.search_results) + ": " + mQueryString);
|
2010-07-13 17:49:28 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-02-06 17:09:48 -05:00
|
|
|
public void progress(final boolean progress) {
|
|
|
|
runOnUiThread(new Runnable() {
|
2011-06-04 17:55:48 -04:00
|
|
|
@Override
|
2011-02-06 17:09:48 -05:00
|
|
|
public void run() {
|
2010-07-13 17:49:28 -04:00
|
|
|
showProgressIndicator(progress);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
2011-02-28 16:55:34 -05:00
|
|
|
|
2011-12-05 12:16:43 -05:00
|
|
|
/**
|
|
|
|
* Show the message list that was used to open the {@link MessageView} for a message.
|
|
|
|
*
|
|
|
|
* <p>
|
|
|
|
* <strong>Note:</strong>
|
|
|
|
* The {@link MessageList} instance should still be around and all we do is bring it back to
|
|
|
|
* the front (see the activity flags).<br>
|
|
|
|
* Out of sheer paranoia we also set the extras that were used to create the original
|
|
|
|
* {@code MessageList} instance. Using those, the activity can be recreated in the unlikely
|
|
|
|
* case of it having been killed by the OS.
|
|
|
|
* </p>
|
|
|
|
*
|
|
|
|
* @param context
|
|
|
|
* The {@link Context} instance to invoke the {@link Context#startActivity(Intent)}
|
|
|
|
* method on.
|
|
|
|
* @param extras
|
|
|
|
* The extras used to create the original {@code MessageList} instance.
|
|
|
|
*
|
|
|
|
* @see MessageView#actionView(Context, MessageReference, ArrayList, Bundle)
|
|
|
|
*/
|
|
|
|
public static void actionHandleFolder(Context context, Bundle extras) {
|
|
|
|
Intent intent = new Intent(context, MessageList.class);
|
|
|
|
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
|
|
|
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
|
|
|
|
intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
|
|
|
|
intent.putExtras(extras);
|
|
|
|
intent.putExtra(EXTRA_RETURN_FROM_MESSAGE_VIEW, true);
|
|
|
|
context.startActivity(intent);
|
|
|
|
}
|
|
|
|
|
2011-02-06 17:09:48 -05:00
|
|
|
public static void actionHandleFolder(Context context, Account account, String folder) {
|
|
|
|
Intent intent = actionHandleFolderIntent(context, account, folder);
|
2010-07-13 17:49:28 -04:00
|
|
|
context.startActivity(intent);
|
|
|
|
}
|
|
|
|
|
2011-02-06 17:09:48 -05:00
|
|
|
public static Intent actionHandleFolderIntent(Context context, Account account, String folder) {
|
2010-07-13 17:49:28 -04:00
|
|
|
Intent intent = new Intent(context, MessageList.class);
|
2011-11-06 17:37:49 -05:00
|
|
|
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
|
|
|
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
|
|
|
|
intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
|
2010-07-13 17:49:28 -04:00
|
|
|
intent.putExtra(EXTRA_ACCOUNT, account.getUuid());
|
|
|
|
|
2011-02-06 17:09:48 -05:00
|
|
|
if (folder != null) {
|
2010-07-13 17:49:28 -04:00
|
|
|
intent.putExtra(EXTRA_FOLDER, folder);
|
|
|
|
}
|
|
|
|
return intent;
|
|
|
|
}
|
|
|
|
|
2011-02-06 17:09:48 -05:00
|
|
|
public static void actionHandle(Context context, String title, String queryString, boolean integrate, Flag[] flags, Flag[] forbiddenFlags) {
|
2010-07-13 17:49:28 -04:00
|
|
|
Intent intent = new Intent(context, MessageList.class);
|
|
|
|
intent.putExtra(EXTRA_QUERY, queryString);
|
2011-02-06 17:09:48 -05:00
|
|
|
if (flags != null) {
|
2010-07-13 17:49:28 -04:00
|
|
|
intent.putExtra(EXTRA_QUERY_FLAGS, Utility.combine(flags, ','));
|
|
|
|
}
|
2011-02-06 17:09:48 -05:00
|
|
|
if (forbiddenFlags != null) {
|
2010-07-13 17:49:28 -04:00
|
|
|
intent.putExtra(EXTRA_FORBIDDEN_FLAGS, Utility.combine(forbiddenFlags, ','));
|
|
|
|
}
|
|
|
|
intent.putExtra(EXTRA_INTEGRATE, integrate);
|
|
|
|
intent.putExtra(EXTRA_TITLE, title);
|
2011-11-06 17:37:49 -05:00
|
|
|
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
|
|
|
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
|
|
|
|
intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
|
2010-07-13 17:49:28 -04:00
|
|
|
context.startActivity(intent);
|
|
|
|
}
|
|
|
|
|
2012-01-31 21:07:19 -05:00
|
|
|
/**
|
|
|
|
* Creates and returns an intent that opens Unified Inbox or All Messages screen.
|
|
|
|
*/
|
|
|
|
public static Intent actionHandleAccountIntent(Context context, String title,
|
|
|
|
SearchSpecification searchSpecification) {
|
2010-07-13 17:49:28 -04:00
|
|
|
Intent intent = new Intent(context, MessageList.class);
|
|
|
|
intent.putExtra(EXTRA_QUERY, searchSpecification.getQuery());
|
2011-02-06 17:09:48 -05:00
|
|
|
if (searchSpecification.getRequiredFlags() != null) {
|
2010-07-13 17:49:28 -04:00
|
|
|
intent.putExtra(EXTRA_QUERY_FLAGS, Utility.combine(searchSpecification.getRequiredFlags(), ','));
|
|
|
|
}
|
2011-02-06 17:09:48 -05:00
|
|
|
if (searchSpecification.getForbiddenFlags() != null) {
|
2010-07-13 17:49:28 -04:00
|
|
|
intent.putExtra(EXTRA_FORBIDDEN_FLAGS, Utility.combine(searchSpecification.getForbiddenFlags(), ','));
|
|
|
|
}
|
|
|
|
intent.putExtra(EXTRA_INTEGRATE, searchSpecification.isIntegrate());
|
|
|
|
intent.putExtra(EXTRA_ACCOUNT_UUIDS, searchSpecification.getAccountUuids());
|
|
|
|
intent.putExtra(EXTRA_FOLDER_NAMES, searchSpecification.getFolderNames());
|
|
|
|
intent.putExtra(EXTRA_TITLE, title);
|
2011-11-06 17:37:49 -05:00
|
|
|
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
|
|
|
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
|
|
|
|
intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
|
2012-01-31 21:07:19 -05:00
|
|
|
|
|
|
|
return intent;
|
|
|
|
}
|
|
|
|
|
|
|
|
public static void actionHandle(Context context, String title,
|
|
|
|
SearchSpecification searchSpecification) {
|
|
|
|
Intent intent = actionHandleAccountIntent(context, title, searchSpecification);
|
2010-07-13 17:49:28 -04:00
|
|
|
context.startActivity(intent);
|
|
|
|
}
|
|
|
|
|
2010-08-03 01:46:35 -04:00
|
|
|
@Override
|
2011-02-06 17:09:48 -05:00
|
|
|
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
|
2011-04-30 23:34:17 -04:00
|
|
|
if (view == mFooterView) {
|
|
|
|
if (mCurrentFolder != null) {
|
|
|
|
mController.loadMoreMessages(mAccount, mFolderName, mAdapter.mListener);
|
|
|
|
}
|
2010-07-13 17:49:28 -04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
MessageInfoHolder message = (MessageInfoHolder) mAdapter.getItem(position);
|
2011-02-06 17:09:48 -05:00
|
|
|
if (mSelectedCount > 0) {
|
2010-07-13 17:49:28 -04:00
|
|
|
// In multiselect mode make sure that clicking on the item results
|
|
|
|
// in toggling the 'selected' checkbox.
|
2011-06-04 16:57:03 -04:00
|
|
|
setSelected(Collections.singletonList(message), !message.selected);
|
2011-02-06 17:09:48 -05:00
|
|
|
} else {
|
2010-07-13 17:49:28 -04:00
|
|
|
onOpenMessage(message);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2011-02-06 17:09:48 -05:00
|
|
|
public void onCreate(Bundle savedInstanceState) {
|
|
|
|
context = this;
|
2010-07-13 17:49:28 -04:00
|
|
|
super.onCreate(savedInstanceState);
|
2010-08-30 10:37:34 -04:00
|
|
|
|
2010-07-13 17:49:28 -04:00
|
|
|
mInflater = getLayoutInflater();
|
|
|
|
initializeLayout();
|
2011-11-06 17:37:49 -05:00
|
|
|
|
|
|
|
// Only set "touchable" when we're first starting up the activity.
|
|
|
|
// Otherwise we get force closes when the user toggles it midstream.
|
|
|
|
mTouchView = K9.messageListTouchable();
|
|
|
|
mPreviewLines = K9.messageListPreviewLines();
|
|
|
|
|
2011-12-05 12:16:43 -05:00
|
|
|
initializeMessageList(getIntent(), true);
|
Fix gesture detection
This commit addresses 2 issues:
1) Before, a general GestureDetector was registered on the highest level in K9Activity
This resulted in EVERY inherited activity to have a useless, unused gesture detector.
But more than that, in MessageList, a second GestureDetector was assigned to the ListView.
On every fling gesture, both detectors called the onSwipe() methods,
which technically did the following:
- The one directly assigned to the ListView would work corectly by mapping the
(local) event coordinates to the right entry in the ListView
- The global one worked on screen coordinates, so the onSwipe() method would
likely select the wrong ListView entry (system menu bar offset).
- For some reason this "worked" fine, and only the correct entry was selected,
despite two detectors used.
2) The gesture detection for the MessageView caused problems when the message
itself was scrollable, i.e. wide HTML mails. A fling gesture inside the WebView
would scroll the message, but also switch the message.
This commit fixes all those by doing the following:
- Don't register the GestureDetector in K9Activity, instead make the member variable
accessible by subclasses.
- In the subclasses that need a detector register it
- In K9Activity.dispatchTouchEvent() check for mGestureDetector being null
- For MessageList:
* Remove the duplicate gesture detector assigned to the ListView
* in the handleSwipe() methods: calclulate pixel offset of the ListView to make
it work using the global screen coordinates
- For MessageView: Limit sensitive area to the message header, to prevent interference
with the WebView scrolling
- Respect current behavior:
* Force-enable gestures for the MessageList
* Respect user setting in MessageView
- Make sure that after a successful swipe gesture, any pending action is cancelled, to
prevent unwanted things to happen (such as expanding the header after changing
the message, or a context menu popping up in the MessageList).
See http://code.google.com/p/android/issues/detail?id=8497
2012-04-30 19:56:06 -04:00
|
|
|
|
|
|
|
// Enable gesture detection for MessageLists
|
|
|
|
mGestureDetector = new GestureDetector(new MyGestureDetector(true));
|
2010-07-13 17:49:28 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2011-02-06 17:09:48 -05:00
|
|
|
public void onNewIntent(Intent intent) {
|
2010-07-13 17:49:28 -04:00
|
|
|
setIntent(intent); // onNewIntent doesn't autoset our "internal" intent
|
2011-12-05 12:16:43 -05:00
|
|
|
initializeMessageList(intent, false);
|
|
|
|
}
|
2010-07-13 17:49:28 -04:00
|
|
|
|
2011-12-05 12:16:43 -05:00
|
|
|
private void initializeMessageList(Intent intent, boolean create) {
|
|
|
|
boolean returnFromMessageView = intent.getBooleanExtra(
|
|
|
|
EXTRA_RETURN_FROM_MESSAGE_VIEW, false);
|
2010-07-13 17:49:28 -04:00
|
|
|
|
2011-12-05 12:16:43 -05:00
|
|
|
if (!create && returnFromMessageView) {
|
|
|
|
// We're returning from the MessageView activity with "Manage back button" enabled.
|
|
|
|
// So just leave the activity in the state it was left in.
|
2010-11-13 16:40:56 -05:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2011-12-05 12:16:43 -05:00
|
|
|
String accountUuid = intent.getStringExtra(EXTRA_ACCOUNT);
|
|
|
|
mAccount = Preferences.getPreferences(this).getAccount(accountUuid);
|
|
|
|
|
|
|
|
if (mAccount != null && !mAccount.isAvailable(this)) {
|
|
|
|
Log.i(K9.LOG_TAG, "not opening MessageList of unavailable account");
|
|
|
|
onAccountUnavailable();
|
2011-11-06 17:37:49 -05:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2011-12-05 12:16:43 -05:00
|
|
|
mFolderName = intent.getStringExtra(EXTRA_FOLDER);
|
|
|
|
mQueryString = intent.getStringExtra(EXTRA_QUERY);
|
2011-11-06 17:37:49 -05:00
|
|
|
|
2010-07-13 17:49:28 -04:00
|
|
|
String queryFlags = intent.getStringExtra(EXTRA_QUERY_FLAGS);
|
2011-02-06 17:09:48 -05:00
|
|
|
if (queryFlags != null) {
|
2010-07-13 17:49:28 -04:00
|
|
|
String[] flagStrings = queryFlags.split(",");
|
|
|
|
mQueryFlags = new Flag[flagStrings.length];
|
2011-02-06 17:09:48 -05:00
|
|
|
for (int i = 0; i < flagStrings.length; i++) {
|
2010-07-13 17:49:28 -04:00
|
|
|
mQueryFlags[i] = Flag.valueOf(flagStrings[i]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
String forbiddenFlags = intent.getStringExtra(EXTRA_FORBIDDEN_FLAGS);
|
2011-02-06 17:09:48 -05:00
|
|
|
if (forbiddenFlags != null) {
|
2010-07-13 17:49:28 -04:00
|
|
|
String[] flagStrings = forbiddenFlags.split(",");
|
|
|
|
mForbiddenFlags = new Flag[flagStrings.length];
|
2011-02-06 17:09:48 -05:00
|
|
|
for (int i = 0; i < flagStrings.length; i++) {
|
2010-07-13 17:49:28 -04:00
|
|
|
mForbiddenFlags[i] = Flag.valueOf(flagStrings[i]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
mIntegrate = intent.getBooleanExtra(EXTRA_INTEGRATE, false);
|
|
|
|
mAccountUuids = intent.getStringArrayExtra(EXTRA_ACCOUNT_UUIDS);
|
|
|
|
mFolderNames = intent.getStringArrayExtra(EXTRA_FOLDER_NAMES);
|
|
|
|
mTitle = intent.getStringExtra(EXTRA_TITLE);
|
|
|
|
|
|
|
|
// Take the initial folder into account only if we are *not* restoring
|
|
|
|
// the activity already.
|
2011-02-06 17:09:48 -05:00
|
|
|
if (mFolderName == null && mQueryString == null) {
|
2010-07-13 17:49:28 -04:00
|
|
|
mFolderName = mAccount.getAutoExpandFolderName();
|
|
|
|
}
|
|
|
|
|
|
|
|
mAdapter = new MessageListAdapter();
|
2011-01-18 19:36:15 -05:00
|
|
|
restorePreviousData();
|
2010-07-13 17:49:28 -04:00
|
|
|
|
2011-02-06 17:09:48 -05:00
|
|
|
if (mFolderName != null) {
|
2010-07-13 17:49:28 -04:00
|
|
|
mCurrentFolder = mAdapter.getFolder(mFolderName, mAccount);
|
|
|
|
}
|
|
|
|
|
2011-12-30 20:22:31 -05:00
|
|
|
// Hide "Load up to x more" footer for search views
|
|
|
|
mFooterView.setVisibility((mQueryString != null) ? View.GONE : View.VISIBLE);
|
|
|
|
|
2010-07-13 17:49:28 -04:00
|
|
|
mController = MessagingController.getInstance(getApplication());
|
|
|
|
mListView.setAdapter(mAdapter);
|
|
|
|
}
|
|
|
|
|
2011-02-06 17:09:48 -05:00
|
|
|
private void restorePreviousData() {
|
2011-06-04 19:16:34 -04:00
|
|
|
final ActivityState previousData = getLastNonConfigurationInstance();
|
2011-01-18 19:36:15 -05:00
|
|
|
|
2011-02-06 17:09:48 -05:00
|
|
|
if (previousData != null) {
|
2011-06-04 19:16:34 -04:00
|
|
|
mAdapter.messages.addAll(previousData.messages);
|
|
|
|
mActiveMessages = previousData.activeMessages;
|
2011-01-18 19:36:15 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-07-13 17:49:28 -04:00
|
|
|
@Override
|
2011-02-06 17:09:48 -05:00
|
|
|
public void onPause() {
|
2010-07-13 17:49:28 -04:00
|
|
|
super.onPause();
|
|
|
|
mController.removeListener(mAdapter.mListener);
|
|
|
|
saveListState();
|
2010-11-13 16:40:56 -05:00
|
|
|
|
|
|
|
StorageManager.getInstance(getApplication()).removeListener(mStorageListener);
|
2010-07-13 17:49:28 -04:00
|
|
|
}
|
|
|
|
|
2011-02-06 17:09:48 -05:00
|
|
|
public void saveListState() {
|
2010-07-13 17:49:28 -04:00
|
|
|
mState = new Bundle();
|
|
|
|
mState.putInt(EXTRA_LIST_POSITION, mListView.getSelectedItemPosition());
|
|
|
|
}
|
|
|
|
|
2011-02-06 17:09:48 -05:00
|
|
|
public void restoreListState() {
|
|
|
|
if (mState == null) {
|
2010-07-13 17:49:28 -04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
int pos = mState.getInt(EXTRA_LIST_POSITION, ListView.INVALID_POSITION);
|
|
|
|
|
2011-02-06 17:09:48 -05:00
|
|
|
if (pos >= mListView.getCount()) {
|
2010-07-13 17:49:28 -04:00
|
|
|
pos = mListView.getCount() - 1;
|
|
|
|
}
|
|
|
|
|
2011-02-06 17:09:48 -05:00
|
|
|
if (pos == ListView.INVALID_POSITION) {
|
2010-07-13 17:49:28 -04:00
|
|
|
mListView.setSelected(false);
|
2011-02-06 17:09:48 -05:00
|
|
|
} else {
|
2010-07-13 17:49:28 -04:00
|
|
|
mListView.setSelection(pos);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* On resume we refresh messages for the folder that is currently open.
|
|
|
|
* This guarantees that things like unread message count and read status
|
|
|
|
* are updated.
|
|
|
|
*/
|
|
|
|
@Override
|
2011-02-06 17:09:48 -05:00
|
|
|
public void onResume() {
|
2010-07-13 17:49:28 -04:00
|
|
|
super.onResume();
|
2011-04-12 08:16:22 -04:00
|
|
|
|
2011-02-06 17:09:48 -05:00
|
|
|
if (mAccount != null && !mAccount.isAvailable(this)) {
|
2010-11-13 16:40:56 -05:00
|
|
|
onAccountUnavailable();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
StorageManager.getInstance(getApplication()).addListener(mStorageListener);
|
|
|
|
|
2010-07-13 17:49:28 -04:00
|
|
|
mStars = K9.messageListStars();
|
|
|
|
mCheckboxes = K9.messageListCheckboxes();
|
|
|
|
|
|
|
|
mController.addListener(mAdapter.mListener);
|
2012-01-20 14:55:04 -05:00
|
|
|
|
2012-01-20 17:32:12 -05:00
|
|
|
Account[] accountsWithNotification;
|
2012-05-15 02:09:28 -04:00
|
|
|
|
|
|
|
Preferences prefs = Preferences.getPreferences(getApplicationContext());
|
|
|
|
Account account = getCurrentAccount(prefs);
|
|
|
|
|
|
|
|
if (account != null) {
|
|
|
|
accountsWithNotification = new Account[] { account };
|
|
|
|
mSortType = account.getSortType();
|
|
|
|
mSortAscending = account.isSortAscending(mSortType);
|
|
|
|
mSortDateAscending = account.isSortAscending(SortType.SORT_DATE);
|
2012-01-20 14:55:04 -05:00
|
|
|
} else {
|
2012-05-15 02:09:28 -04:00
|
|
|
accountsWithNotification = prefs.getAccounts();
|
|
|
|
mSortType = K9.getSortType();
|
2012-04-12 22:12:22 -04:00
|
|
|
mSortAscending = K9.isSortAscending(mSortType);
|
|
|
|
mSortDateAscending = K9.isSortAscending(SortType.SORT_DATE);
|
2012-01-20 14:55:04 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
for (Account accountWithNotification : accountsWithNotification) {
|
|
|
|
mController.notifyAccountCancel(this, accountWithNotification);
|
2010-10-23 11:19:56 -04:00
|
|
|
}
|
2010-07-13 17:49:28 -04:00
|
|
|
|
2011-02-06 17:09:48 -05:00
|
|
|
if (mAdapter.messages.isEmpty()) {
|
|
|
|
if (mFolderName != null) {
|
2010-10-08 02:18:30 -04:00
|
|
|
mController.listLocalMessages(mAccount, mFolderName, mAdapter.mListener);
|
2012-04-06 18:52:56 -04:00
|
|
|
// Hide the archive button if we don't have an archive folder.
|
|
|
|
if (!mAccount.hasArchiveFolder()) {
|
|
|
|
mBatchArchiveButton.setVisibility(View.GONE);
|
|
|
|
}
|
2011-02-06 17:09:48 -05:00
|
|
|
} else if (mQueryString != null) {
|
2010-10-23 11:19:56 -04:00
|
|
|
mController.searchLocalMessages(mAccountUuids, mFolderNames, null, mQueryString, mIntegrate, mQueryFlags, mForbiddenFlags, mAdapter.mListener);
|
2012-04-06 19:46:04 -04:00
|
|
|
// Don't show the archive button if this is a search.
|
|
|
|
mBatchArchiveButton.setVisibility(View.GONE);
|
2010-10-23 11:19:56 -04:00
|
|
|
}
|
|
|
|
|
2011-02-06 17:09:48 -05:00
|
|
|
} else {
|
2011-04-12 08:16:22 -04:00
|
|
|
// reread the selected date format preference in case it has changed
|
|
|
|
mMessageHelper.refresh();
|
|
|
|
|
2011-02-06 17:09:48 -05:00
|
|
|
new Thread() {
|
2010-10-23 11:19:56 -04:00
|
|
|
@Override
|
2011-02-06 17:09:48 -05:00
|
|
|
public void run() {
|
2010-10-23 11:19:56 -04:00
|
|
|
mAdapter.markAllMessagesAsDirty();
|
|
|
|
|
2011-02-06 17:09:48 -05:00
|
|
|
if (mFolderName != null) {
|
2010-10-21 16:49:36 -04:00
|
|
|
mController.listLocalMessagesSynchronous(mAccount, mFolderName, mAdapter.mListener);
|
2011-02-06 17:09:48 -05:00
|
|
|
} else if (mQueryString != null) {
|
2010-10-23 11:19:56 -04:00
|
|
|
mController.searchLocalMessagesSynchronous(mAccountUuids, mFolderNames, null, mQueryString, mIntegrate, mQueryFlags, mForbiddenFlags, mAdapter.mListener);
|
2010-10-21 16:49:36 -04:00
|
|
|
}
|
|
|
|
|
2010-07-13 17:49:28 -04:00
|
|
|
|
2010-10-23 11:19:56 -04:00
|
|
|
mAdapter.pruneDirtyMessages();
|
2011-02-06 17:09:48 -05:00
|
|
|
runOnUiThread(new Runnable() {
|
2011-06-04 17:55:48 -04:00
|
|
|
@Override
|
2011-02-06 17:09:48 -05:00
|
|
|
public void run() {
|
2010-10-23 11:19:56 -04:00
|
|
|
mAdapter.notifyDataSetChanged();
|
|
|
|
restoreListState();
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
2010-07-13 17:49:28 -04:00
|
|
|
|
2010-10-23 11:19:56 -04:00
|
|
|
}
|
|
|
|
.start();
|
2010-07-13 17:49:28 -04:00
|
|
|
}
|
2010-10-23 11:19:56 -04:00
|
|
|
|
2011-02-06 17:09:48 -05:00
|
|
|
if (mAccount != null && mFolderName != null) {
|
2010-10-23 11:19:56 -04:00
|
|
|
mController.getFolderUnreadMessageCount(mAccount, mFolderName, mAdapter.mListener);
|
2010-07-13 17:49:28 -04:00
|
|
|
}
|
|
|
|
mHandler.refreshTitle();
|
|
|
|
|
|
|
|
}
|
2011-02-06 17:09:48 -05:00
|
|
|
private void initializeLayout() {
|
2010-07-13 17:49:28 -04:00
|
|
|
requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
|
|
|
|
requestWindowFeature(Window.FEATURE_PROGRESS);
|
|
|
|
setContentView(R.layout.message_list);
|
|
|
|
|
|
|
|
mListView = (ListView) findViewById(R.id.message_list);
|
|
|
|
mListView.setScrollBarStyle(View.SCROLLBARS_OUTSIDE_INSET);
|
|
|
|
mListView.setLongClickable(true);
|
|
|
|
mListView.setFastScrollEnabled(true);
|
2011-07-19 10:37:19 -04:00
|
|
|
mListView.setScrollingCacheEnabled(false);
|
2010-07-13 17:49:28 -04:00
|
|
|
mListView.setOnItemClickListener(this);
|
2011-02-19 22:50:50 -05:00
|
|
|
mListView.addFooterView(getFooterView(mListView));
|
2010-07-13 17:49:28 -04:00
|
|
|
|
|
|
|
registerForContextMenu(mListView);
|
|
|
|
|
|
|
|
mBatchButtonArea = findViewById(R.id.batch_button_area);
|
|
|
|
mBatchReadButton = (ImageButton) findViewById(R.id.batch_read_button);
|
|
|
|
mBatchReadButton.setOnClickListener(this);
|
|
|
|
mBatchDeleteButton = (ImageButton) findViewById(R.id.batch_delete_button);
|
|
|
|
mBatchDeleteButton.setOnClickListener(this);
|
|
|
|
mBatchFlagButton = (ImageButton) findViewById(R.id.batch_flag_button);
|
|
|
|
mBatchFlagButton.setOnClickListener(this);
|
2011-12-24 13:17:12 -05:00
|
|
|
mBatchArchiveButton = (ImageButton) findViewById(R.id.batch_archive_button);
|
|
|
|
mBatchArchiveButton.setOnClickListener(this);
|
|
|
|
mBatchMoveButton = (ImageButton) findViewById(R.id.batch_move_button);
|
|
|
|
mBatchMoveButton.setOnClickListener(this);
|
2010-07-13 17:49:28 -04:00
|
|
|
mBatchDoneButton = (ImageButton) findViewById(R.id.batch_done_button);
|
|
|
|
mBatchDoneButton.setOnClickListener(this);
|
|
|
|
|
2011-12-24 13:17:12 -05:00
|
|
|
mBatchReadButton.setVisibility(K9.batchButtonsMarkRead() ? View.VISIBLE : View.GONE);
|
|
|
|
mBatchDeleteButton.setVisibility(K9.batchButtonsDelete() ? View.VISIBLE : View.GONE);
|
|
|
|
mBatchArchiveButton.setVisibility(K9.batchButtonsArchive() ? View.VISIBLE : View.GONE);
|
|
|
|
mBatchMoveButton.setVisibility(K9.batchButtonsMove() ? View.VISIBLE : View.GONE);
|
|
|
|
mBatchFlagButton.setVisibility(K9.batchButtonsFlag() ? View.VISIBLE : View.GONE);
|
|
|
|
mBatchDoneButton.setVisibility(K9.batchButtonsUnselect() ? View.VISIBLE : View.GONE);
|
2010-07-13 17:49:28 -04:00
|
|
|
}
|
|
|
|
|
2011-06-04 19:16:34 -04:00
|
|
|
/**
|
|
|
|
* Container for values to be kept while the device configuration is
|
|
|
|
* modified at runtime (keyboard, orientation, etc.) and Android restarts
|
|
|
|
* this activity.
|
|
|
|
*
|
|
|
|
* @see MessageList#onRetainNonConfigurationInstance()
|
|
|
|
* @see MessageList#getLastNonConfigurationInstance()
|
|
|
|
*/
|
|
|
|
static class ActivityState {
|
|
|
|
public List<MessageInfoHolder> messages;
|
|
|
|
public List<MessageInfoHolder> activeMessages;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* (non-Javadoc)
|
2011-06-13 19:49:06 -04:00
|
|
|
*
|
2011-09-27 00:03:13 -04:00
|
|
|
* Method overridden for proper typing within this class (the return type is
|
2011-06-04 19:16:34 -04:00
|
|
|
* more specific than the super implementation)
|
2011-06-13 19:49:06 -04:00
|
|
|
*
|
2011-06-04 19:16:34 -04:00
|
|
|
* @see android.app.Activity#onRetainNonConfigurationInstance()
|
|
|
|
*/
|
|
|
|
@Override
|
|
|
|
public ActivityState onRetainNonConfigurationInstance() {
|
|
|
|
final ActivityState state = new ActivityState();
|
|
|
|
state.messages = mAdapter.messages;
|
|
|
|
state.activeMessages = mActiveMessages;
|
|
|
|
return state;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* (non-Javadoc)
|
2011-06-13 19:49:06 -04:00
|
|
|
*
|
2011-09-27 00:03:13 -04:00
|
|
|
* Method overridden for proper typing within this class (the return type is
|
2011-06-04 19:16:34 -04:00
|
|
|
* more specific than the super implementation)
|
2011-06-13 19:49:06 -04:00
|
|
|
*
|
2011-06-04 19:16:34 -04:00
|
|
|
* @see android.app.Activity#getLastNonConfigurationInstance()
|
|
|
|
*/
|
2010-07-13 17:49:28 -04:00
|
|
|
@Override
|
2011-06-04 19:16:34 -04:00
|
|
|
public ActivityState getLastNonConfigurationInstance() {
|
|
|
|
return (ActivityState) super.getLastNonConfigurationInstance();
|
2010-07-13 17:49:28 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2011-02-06 17:09:48 -05:00
|
|
|
public void onBackPressed() {
|
|
|
|
if (K9.manageBack()) {
|
|
|
|
if (mQueryString == null) {
|
2010-07-13 17:49:28 -04:00
|
|
|
onShowFolderList();
|
2011-02-06 17:09:48 -05:00
|
|
|
} else {
|
2010-07-13 17:49:28 -04:00
|
|
|
onAccounts();
|
|
|
|
}
|
2011-02-06 17:09:48 -05:00
|
|
|
} else {
|
2011-11-09 23:34:34 -05:00
|
|
|
super.onBackPressed();
|
2010-07-13 17:49:28 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2011-02-06 17:09:48 -05:00
|
|
|
public boolean onKeyDown(int keyCode, KeyEvent event) {
|
2010-07-13 17:49:28 -04:00
|
|
|
// Shortcuts that work no matter what is selected
|
2011-02-06 17:09:48 -05:00
|
|
|
switch (keyCode) {
|
2010-08-29 22:16:20 -04:00
|
|
|
|
2011-02-06 17:09:48 -05:00
|
|
|
// messagelist is actually a K9Activity, not a K9ListActivity
|
|
|
|
// This saddens me greatly, but to support volume key navigation
|
|
|
|
// in MessageView, we implement this bit of wrapper code
|
|
|
|
case KeyEvent.KEYCODE_VOLUME_UP: {
|
|
|
|
if (K9.useVolumeKeysForListNavigationEnabled()) {
|
|
|
|
int currentPosition = mListView.getSelectedItemPosition();
|
|
|
|
if (currentPosition == AdapterView.INVALID_POSITION || mListView.isInTouchMode()) {
|
|
|
|
currentPosition = mListView.getFirstVisiblePosition();
|
2010-08-29 22:16:20 -04:00
|
|
|
}
|
2011-02-06 17:09:48 -05:00
|
|
|
if (currentPosition > 0) {
|
|
|
|
mListView.setSelection(currentPosition - 1);
|
2010-07-13 17:49:28 -04:00
|
|
|
}
|
2011-02-06 17:09:48 -05:00
|
|
|
return true;
|
2010-07-13 17:49:28 -04:00
|
|
|
}
|
2011-02-06 17:09:48 -05:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
case KeyEvent.KEYCODE_VOLUME_DOWN: {
|
|
|
|
if (K9.useVolumeKeysForListNavigationEnabled()) {
|
|
|
|
int currentPosition = mListView.getSelectedItemPosition();
|
|
|
|
if (currentPosition == AdapterView.INVALID_POSITION || mListView.isInTouchMode()) {
|
|
|
|
currentPosition = mListView.getFirstVisiblePosition();
|
2010-07-13 17:49:28 -04:00
|
|
|
}
|
2011-02-06 17:09:48 -05:00
|
|
|
|
|
|
|
if (currentPosition < mListView.getCount()) {
|
|
|
|
mListView.setSelection(currentPosition + 1);
|
2010-07-13 17:49:28 -04:00
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
2011-02-06 17:09:48 -05:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
case KeyEvent.KEYCODE_DPAD_LEFT: {
|
|
|
|
if (mBatchButtonArea.hasFocus()) {
|
|
|
|
return false;
|
|
|
|
} else {
|
2010-07-13 17:49:28 -04:00
|
|
|
return true;
|
|
|
|
}
|
2011-02-06 17:09:48 -05:00
|
|
|
}
|
|
|
|
case KeyEvent.KEYCODE_DPAD_RIGHT: {
|
|
|
|
if (mBatchButtonArea.hasFocus()) {
|
|
|
|
return false;
|
|
|
|
} else {
|
2010-07-13 17:49:28 -04:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
2011-02-06 17:09:48 -05:00
|
|
|
case KeyEvent.KEYCODE_C: {
|
|
|
|
onCompose();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
case KeyEvent.KEYCODE_Q: {
|
|
|
|
onShowFolderList();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
case KeyEvent.KEYCODE_O: {
|
|
|
|
onCycleSort();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
case KeyEvent.KEYCODE_I: {
|
2012-05-16 14:33:36 -04:00
|
|
|
changeSort(mSortType);
|
2011-02-06 17:09:48 -05:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
case KeyEvent.KEYCODE_H: {
|
|
|
|
Toast toast = Toast.makeText(this, R.string.message_list_help_key, Toast.LENGTH_LONG);
|
|
|
|
toast.show();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
2010-07-13 17:49:28 -04:00
|
|
|
|
2011-01-18 19:23:56 -05:00
|
|
|
boolean retval = true;
|
2010-07-13 17:49:28 -04:00
|
|
|
int position = mListView.getSelectedItemPosition();
|
2011-02-06 17:09:48 -05:00
|
|
|
try {
|
|
|
|
if (position >= 0) {
|
2010-07-13 17:49:28 -04:00
|
|
|
MessageInfoHolder message = (MessageInfoHolder) mAdapter.getItem(position);
|
|
|
|
|
2011-06-04 16:57:03 -04:00
|
|
|
final List<MessageInfoHolder> selection = getSelectionFromMessage(message);
|
|
|
|
|
2011-02-06 17:09:48 -05:00
|
|
|
if (message != null) {
|
|
|
|
switch (keyCode) {
|
|
|
|
case KeyEvent.KEYCODE_DEL: {
|
2011-06-04 16:57:03 -04:00
|
|
|
onDelete(selection);
|
2011-02-06 17:09:48 -05:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
case KeyEvent.KEYCODE_S: {
|
2011-06-04 16:57:03 -04:00
|
|
|
setSelected(selection, !message.selected);
|
2011-02-06 17:09:48 -05:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
case KeyEvent.KEYCODE_D: {
|
2011-06-04 16:57:03 -04:00
|
|
|
onDelete(selection);
|
2011-02-06 17:09:48 -05:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
case KeyEvent.KEYCODE_F: {
|
|
|
|
onForward(message);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
case KeyEvent.KEYCODE_A: {
|
|
|
|
onReplyAll(message);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
case KeyEvent.KEYCODE_R: {
|
|
|
|
onReply(message);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
case KeyEvent.KEYCODE_G: {
|
2011-06-04 16:57:03 -04:00
|
|
|
setFlag(selection, Flag.FLAGGED, !message.flagged);
|
2011-02-06 17:09:48 -05:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
case KeyEvent.KEYCODE_M: {
|
2011-06-04 16:57:03 -04:00
|
|
|
onMove(selection);
|
2011-02-06 17:09:48 -05:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
case KeyEvent.KEYCODE_V: {
|
2011-06-04 16:57:03 -04:00
|
|
|
onArchive(selection);
|
2011-02-06 17:09:48 -05:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
case KeyEvent.KEYCODE_Y: {
|
2011-06-04 16:57:03 -04:00
|
|
|
onCopy(selection);
|
2011-02-06 17:09:48 -05:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
case KeyEvent.KEYCODE_Z: {
|
2011-06-04 16:57:03 -04:00
|
|
|
setFlag(selection, Flag.SEEN, !message.read);
|
2011-02-06 17:09:48 -05:00
|
|
|
return true;
|
|
|
|
}
|
2010-07-13 17:49:28 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2011-02-06 17:09:48 -05:00
|
|
|
} finally {
|
2011-01-18 19:23:56 -05:00
|
|
|
retval = super.onKeyDown(keyCode, event);
|
2010-07-13 17:49:28 -04:00
|
|
|
}
|
2011-01-18 19:23:56 -05:00
|
|
|
return retval;
|
2010-07-13 17:49:28 -04:00
|
|
|
}
|
|
|
|
|
2010-08-29 22:16:20 -04:00
|
|
|
@Override
|
2011-02-06 17:09:48 -05:00
|
|
|
public boolean onKeyUp(int keyCode, KeyEvent event) {
|
2010-08-29 22:16:20 -04:00
|
|
|
// Swallow these events too to avoid the audible notification of a volume change
|
2011-02-06 17:09:48 -05:00
|
|
|
if (K9.useVolumeKeysForListNavigationEnabled()) {
|
|
|
|
if ((keyCode == KeyEvent.KEYCODE_VOLUME_UP) || (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN)) {
|
2010-08-29 22:16:20 -04:00
|
|
|
if (K9.DEBUG)
|
|
|
|
Log.v(K9.LOG_TAG, "Swallowed key up.");
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
2011-02-06 17:09:48 -05:00
|
|
|
return super.onKeyUp(keyCode, event);
|
2010-08-29 22:16:20 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-02-06 17:09:48 -05:00
|
|
|
private void onResendMessage(MessageInfoHolder message) {
|
2010-11-12 22:09:32 -05:00
|
|
|
MessageCompose.actionEditDraft(this, message.message.getFolder().getAccount(), message.message);
|
|
|
|
}
|
|
|
|
|
2011-02-06 17:09:48 -05:00
|
|
|
private void onOpenMessage(MessageInfoHolder message) {
|
|
|
|
if (message.folder.name.equals(message.message.getFolder().getAccount().getDraftsFolderName())) {
|
2010-07-13 17:49:28 -04:00
|
|
|
MessageCompose.actionEditDraft(this, message.message.getFolder().getAccount(), message.message);
|
2011-02-06 17:09:48 -05:00
|
|
|
} else {
|
2010-07-13 17:49:28 -04:00
|
|
|
// Need to get the list before the sort starts
|
|
|
|
ArrayList<MessageReference> messageRefs = new ArrayList<MessageReference>();
|
|
|
|
|
2011-02-06 17:09:48 -05:00
|
|
|
synchronized (mAdapter.messages) {
|
|
|
|
for (MessageInfoHolder holder : mAdapter.messages) {
|
2010-07-13 17:49:28 -04:00
|
|
|
MessageReference ref = holder.message.makeMessageReference();
|
|
|
|
messageRefs.add(ref);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
MessageReference ref = message.message.makeMessageReference();
|
|
|
|
Log.i(K9.LOG_TAG, "MessageList sending message " + ref);
|
|
|
|
|
2011-12-05 12:16:43 -05:00
|
|
|
MessageView.actionView(this, ref, messageRefs, getIntent().getExtras());
|
2010-07-13 17:49:28 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* We set read=true here for UI performance reasons. The actual value
|
|
|
|
* will get picked up on the refresh when the Activity is resumed but
|
|
|
|
* that may take a second or so and we don't want this to show and
|
|
|
|
* then go away. I've gone back and forth on this, and this gives a
|
|
|
|
* better UI experience, so I am putting it back in.
|
|
|
|
*/
|
2011-02-06 17:09:48 -05:00
|
|
|
if (!message.read) {
|
2010-07-13 17:49:28 -04:00
|
|
|
message.read = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-02-06 17:09:48 -05:00
|
|
|
private void onAccounts() {
|
2010-07-13 17:49:28 -04:00
|
|
|
Accounts.listAccounts(this);
|
|
|
|
finish();
|
|
|
|
}
|
|
|
|
|
2011-02-06 17:09:48 -05:00
|
|
|
private void onShowFolderList() {
|
2010-07-13 17:49:28 -04:00
|
|
|
FolderList.actionHandleAccount(this, mAccount);
|
|
|
|
finish();
|
|
|
|
}
|
|
|
|
|
2011-02-06 17:09:48 -05:00
|
|
|
private void onCompose() {
|
|
|
|
if (mQueryString != null) {
|
2010-07-13 17:49:28 -04:00
|
|
|
/*
|
|
|
|
* If we have a query string, we don't have an account to let
|
|
|
|
* compose start the default action.
|
|
|
|
*/
|
|
|
|
MessageCompose.actionCompose(this, null);
|
2011-02-06 17:09:48 -05:00
|
|
|
} else {
|
2010-07-13 17:49:28 -04:00
|
|
|
MessageCompose.actionCompose(this, mAccount);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-02-06 17:09:48 -05:00
|
|
|
private void onEditPrefs() {
|
2010-07-13 17:49:28 -04:00
|
|
|
Prefs.actionPrefs(this);
|
|
|
|
}
|
|
|
|
|
2011-02-06 17:09:48 -05:00
|
|
|
private void onEditAccount() {
|
2010-07-13 17:49:28 -04:00
|
|
|
AccountSettings.actionSettings(this, mAccount);
|
|
|
|
}
|
|
|
|
|
2012-04-08 22:29:08 -04:00
|
|
|
private void changeSort(SortType sortType) {
|
2012-05-16 14:33:36 -04:00
|
|
|
Boolean sortAscending = (mSortType == sortType) ? !mSortAscending : null;
|
|
|
|
changeSort(sortType, sortAscending);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Change the sort type and sort order used for the message list.
|
|
|
|
*
|
|
|
|
* @param sortType
|
|
|
|
* Specifies which field to use for sorting the message list.
|
|
|
|
* @param sortAscending
|
|
|
|
* Specifies the sort order. If this argument is {@code null} the default search order
|
|
|
|
* for the sort type is used.
|
|
|
|
*/
|
|
|
|
// FIXME: Don't save the changes in the UI thread
|
|
|
|
private void changeSort(SortType sortType, Boolean sortAscending) {
|
|
|
|
mSortType = sortType;
|
2012-05-15 02:09:28 -04:00
|
|
|
|
2012-05-16 14:33:36 -04:00
|
|
|
Preferences prefs = Preferences.getPreferences(getApplicationContext());
|
|
|
|
Account account = getCurrentAccount(prefs);
|
2012-05-15 02:09:28 -04:00
|
|
|
|
2012-05-16 14:33:36 -04:00
|
|
|
if (account != null) {
|
|
|
|
account.setSortType(mSortType);
|
|
|
|
|
|
|
|
if (sortAscending == null) {
|
2012-05-15 02:09:28 -04:00
|
|
|
mSortAscending = account.isSortAscending(mSortType);
|
2012-04-12 22:12:22 -04:00
|
|
|
} else {
|
2012-05-16 14:33:36 -04:00
|
|
|
mSortAscending = sortAscending;
|
|
|
|
}
|
|
|
|
account.setSortAscending(mSortType, mSortAscending);
|
|
|
|
mSortDateAscending = account.isSortAscending(SortType.SORT_DATE);
|
|
|
|
|
|
|
|
account.save(prefs);
|
|
|
|
} else {
|
|
|
|
K9.setSortType(mSortType);
|
2012-05-16 14:35:55 -04:00
|
|
|
|
2012-05-16 14:33:36 -04:00
|
|
|
if (sortAscending == null) {
|
|
|
|
mSortAscending = K9.isSortAscending(mSortType);
|
|
|
|
} else {
|
|
|
|
mSortAscending = sortAscending;
|
2012-04-11 01:08:49 -04:00
|
|
|
}
|
2012-05-16 14:33:36 -04:00
|
|
|
K9.setSortAscending(mSortType, mSortAscending);
|
|
|
|
mSortDateAscending = K9.isSortAscending(SortType.SORT_DATE);
|
|
|
|
|
|
|
|
Editor editor = prefs.getPreferences().edit();
|
|
|
|
K9.save(editor);
|
|
|
|
editor.commit();
|
2010-07-13 17:49:28 -04:00
|
|
|
}
|
2012-05-16 14:33:36 -04:00
|
|
|
|
|
|
|
reSort();
|
2010-07-13 17:49:28 -04:00
|
|
|
}
|
|
|
|
|
2011-02-06 17:09:48 -05:00
|
|
|
private void reSort() {
|
2012-04-08 22:29:08 -04:00
|
|
|
int toastString = mSortType.getToast(mSortAscending);
|
2010-07-13 17:49:28 -04:00
|
|
|
|
|
|
|
Toast toast = Toast.makeText(this, toastString, Toast.LENGTH_SHORT);
|
|
|
|
toast.show();
|
|
|
|
|
|
|
|
mHandler.sortMessages();
|
|
|
|
}
|
|
|
|
|
2011-02-06 17:09:48 -05:00
|
|
|
private void onCycleSort() {
|
2012-04-08 17:17:06 -04:00
|
|
|
SortType[] sorts = SortType.values();
|
2010-07-13 17:49:28 -04:00
|
|
|
int curIndex = 0;
|
|
|
|
|
2011-02-06 17:09:48 -05:00
|
|
|
for (int i = 0; i < sorts.length; i++) {
|
2012-04-08 22:29:08 -04:00
|
|
|
if (sorts[i] == mSortType) {
|
2010-07-13 17:49:28 -04:00
|
|
|
curIndex = i;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
curIndex++;
|
|
|
|
|
2011-02-06 17:09:48 -05:00
|
|
|
if (curIndex == sorts.length) {
|
2010-07-13 17:49:28 -04:00
|
|
|
curIndex = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
changeSort(sorts[curIndex]);
|
|
|
|
}
|
|
|
|
|
2011-06-04 16:57:03 -04:00
|
|
|
/**
|
|
|
|
* @param holders
|
|
|
|
* Never {@code null}.
|
|
|
|
*/
|
|
|
|
private void onDelete(final List<MessageInfoHolder> holders) {
|
|
|
|
final List<Message> messagesToRemove = new ArrayList<Message>();
|
|
|
|
for (MessageInfoHolder holder : holders) {
|
2011-07-23 18:44:18 -04:00
|
|
|
messagesToRemove.add(holder.message);
|
2010-07-13 17:49:28 -04:00
|
|
|
}
|
2011-06-04 16:57:03 -04:00
|
|
|
mHandler.removeMessages(holders);
|
|
|
|
mController.deleteMessages(messagesToRemove.toArray(EMPTY_MESSAGE_ARRAY), null);
|
2010-07-13 17:49:28 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2011-02-06 17:09:48 -05:00
|
|
|
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
|
2011-06-04 16:57:03 -04:00
|
|
|
if (resultCode != RESULT_OK) {
|
2010-07-13 17:49:28 -04:00
|
|
|
return;
|
2011-06-04 16:57:03 -04:00
|
|
|
}
|
2010-07-13 17:49:28 -04:00
|
|
|
|
2011-02-06 17:09:48 -05:00
|
|
|
switch (requestCode) {
|
|
|
|
case ACTIVITY_CHOOSE_FOLDER_MOVE:
|
|
|
|
case ACTIVITY_CHOOSE_FOLDER_COPY: {
|
2011-06-04 16:57:03 -04:00
|
|
|
if (data == null) {
|
2011-02-06 17:09:48 -05:00
|
|
|
return;
|
2011-06-04 16:57:03 -04:00
|
|
|
}
|
2010-07-13 17:49:28 -04:00
|
|
|
|
2011-02-06 17:09:48 -05:00
|
|
|
final String destFolderName = data.getStringExtra(ChooseFolder.EXTRA_NEW_FOLDER);
|
2010-07-13 17:49:28 -04:00
|
|
|
|
2011-06-04 16:57:03 -04:00
|
|
|
if (destFolderName != null) {
|
|
|
|
final List<MessageInfoHolder> holders = mActiveMessages;
|
|
|
|
|
|
|
|
mActiveMessages = null; // don't need it any more
|
2010-07-13 17:49:28 -04:00
|
|
|
|
2011-06-04 16:57:03 -04:00
|
|
|
final Account account = holders.get(0).message.getFolder().getAccount();
|
2011-02-06 17:09:48 -05:00
|
|
|
account.setLastSelectedFolderName(destFolderName);
|
2010-07-13 17:49:28 -04:00
|
|
|
|
2011-02-06 17:09:48 -05:00
|
|
|
switch (requestCode) {
|
|
|
|
case ACTIVITY_CHOOSE_FOLDER_MOVE:
|
2011-06-04 16:57:03 -04:00
|
|
|
move(holders, destFolderName);
|
2011-02-06 17:09:48 -05:00
|
|
|
break;
|
2010-07-13 17:49:28 -04:00
|
|
|
|
2011-02-06 17:09:48 -05:00
|
|
|
case ACTIVITY_CHOOSE_FOLDER_COPY:
|
2011-06-04 16:57:03 -04:00
|
|
|
copy(holders, destFolderName);
|
2011-02-06 17:09:48 -05:00
|
|
|
break;
|
2010-07-13 17:49:28 -04:00
|
|
|
}
|
|
|
|
}
|
2011-02-06 17:09:48 -05:00
|
|
|
break;
|
|
|
|
}
|
2010-07-13 17:49:28 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-02-06 17:09:48 -05:00
|
|
|
private void onReply(MessageInfoHolder holder) {
|
2010-07-27 08:10:09 -04:00
|
|
|
MessageCompose.actionReply(this, holder.message.getFolder().getAccount(), holder.message, false, null);
|
2010-07-13 17:49:28 -04:00
|
|
|
}
|
|
|
|
|
2011-02-06 17:09:48 -05:00
|
|
|
private void onReplyAll(MessageInfoHolder holder) {
|
2010-07-27 08:10:09 -04:00
|
|
|
MessageCompose.actionReply(this, holder.message.getFolder().getAccount(), holder.message, true, null);
|
2010-07-13 17:49:28 -04:00
|
|
|
}
|
|
|
|
|
2011-02-06 17:09:48 -05:00
|
|
|
private void onForward(MessageInfoHolder holder) {
|
2010-07-27 08:10:09 -04:00
|
|
|
MessageCompose.actionForward(this, holder.message.getFolder().getAccount(), holder.message, null);
|
2010-07-13 17:49:28 -04:00
|
|
|
}
|
|
|
|
|
2011-02-06 17:09:48 -05:00
|
|
|
private void onMarkAllAsRead(final Account account, final String folder) {
|
2011-03-31 23:34:27 -04:00
|
|
|
if (K9.confirmMarkAllAsRead()) {
|
|
|
|
showDialog(DIALOG_MARK_ALL_AS_READ);
|
|
|
|
} else {
|
|
|
|
markAllAsRead();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private void markAllAsRead() {
|
|
|
|
try {
|
|
|
|
mController.markAllMessagesRead(mAccount, mCurrentFolder.name);
|
|
|
|
|
|
|
|
synchronized (mAdapter.messages) {
|
|
|
|
for (MessageInfoHolder holder : mAdapter.messages) {
|
|
|
|
holder.read = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
mHandler.sortMessages();
|
|
|
|
} catch (Exception e) {
|
|
|
|
// Ignore
|
|
|
|
}
|
2010-07-13 17:49:28 -04:00
|
|
|
}
|
|
|
|
|
2011-02-06 17:09:48 -05:00
|
|
|
private void onExpunge(final Account account, String folderName) {
|
2010-07-13 17:49:28 -04:00
|
|
|
mController.expunge(account, folderName, null);
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2011-02-06 17:09:48 -05:00
|
|
|
public Dialog onCreateDialog(int id) {
|
|
|
|
switch (id) {
|
|
|
|
case DIALOG_MARK_ALL_AS_READ:
|
2011-03-31 21:17:47 -04:00
|
|
|
return ConfirmationDialog.create(this, id,
|
2011-04-12 08:16:22 -04:00
|
|
|
R.string.mark_all_as_read_dlg_title,
|
|
|
|
getString(R.string.mark_all_as_read_dlg_instructions_fmt,
|
|
|
|
mCurrentFolder.displayName),
|
|
|
|
R.string.okay_action,
|
|
|
|
R.string.cancel_action,
|
|
|
|
new Runnable() {
|
|
|
|
@Override
|
|
|
|
public void run() {
|
|
|
|
markAllAsRead();
|
|
|
|
}
|
|
|
|
});
|
2011-03-31 17:34:09 -04:00
|
|
|
case R.id.dialog_confirm_spam:
|
2011-03-31 21:17:47 -04:00
|
|
|
return ConfirmationDialog.create(this, id,
|
2011-04-12 08:16:22 -04:00
|
|
|
R.string.dialog_confirm_spam_title,
|
2011-06-04 19:35:11 -04:00
|
|
|
"" /* text is refreshed by #onPrepareDialog(int, Dialog) below */,
|
2011-04-12 08:16:22 -04:00
|
|
|
R.string.dialog_confirm_spam_confirm_button,
|
|
|
|
R.string.dialog_confirm_spam_cancel_button,
|
|
|
|
new Runnable() {
|
|
|
|
@Override
|
|
|
|
public void run() {
|
2011-06-04 16:57:03 -04:00
|
|
|
onSpamConfirmed(mActiveMessages);
|
2011-04-12 08:16:22 -04:00
|
|
|
// No further need for this reference
|
2011-06-04 16:57:03 -04:00
|
|
|
mActiveMessages = null;
|
2011-04-12 08:16:22 -04:00
|
|
|
}
|
2011-06-06 19:25:38 -04:00
|
|
|
}, new Runnable() {
|
|
|
|
@Override
|
|
|
|
public void run() {
|
|
|
|
// event for cancel, we don't need this reference any more
|
|
|
|
mActiveMessages = null;
|
|
|
|
}
|
2011-04-12 08:16:22 -04:00
|
|
|
});
|
2010-07-13 17:49:28 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
return super.onCreateDialog(id);
|
|
|
|
}
|
|
|
|
|
2011-06-06 19:15:04 -04:00
|
|
|
/*
|
|
|
|
* (non-Javadoc)
|
|
|
|
*
|
|
|
|
* Android happens to invoke this method even if the given dialog is not
|
|
|
|
* shown (eg. a dismissed dialog) as part of the automatic activity
|
|
|
|
* reloading following a configuration change (orientation, keyboard,
|
|
|
|
* locale, etc.).
|
|
|
|
*/
|
2010-07-13 17:49:28 -04:00
|
|
|
@Override
|
2011-06-04 19:35:11 -04:00
|
|
|
public void onPrepareDialog(final int id, final Dialog dialog) {
|
2011-02-06 17:09:48 -05:00
|
|
|
switch (id) {
|
|
|
|
case DIALOG_MARK_ALL_AS_READ: {
|
|
|
|
if (mCurrentFolder != null) {
|
|
|
|
((AlertDialog)dialog).setMessage(getString(R.string.mark_all_as_read_dlg_instructions_fmt,
|
|
|
|
mCurrentFolder.displayName));
|
2010-07-13 17:49:28 -04:00
|
|
|
}
|
2011-02-06 17:09:48 -05:00
|
|
|
break;
|
|
|
|
}
|
2011-06-04 19:35:11 -04:00
|
|
|
case R.id.dialog_confirm_spam: {
|
2011-06-06 19:15:04 -04:00
|
|
|
// mActiveMessages can be null if Android restarts the activity
|
|
|
|
// while this dialog is not actually shown (but was displayed at
|
|
|
|
// least once)
|
|
|
|
if (mActiveMessages != null) {
|
|
|
|
final int selectionSize = mActiveMessages.size();
|
|
|
|
final String message;
|
|
|
|
message = getResources().getQuantityString(R.plurals.dialog_confirm_spam_message, selectionSize,
|
2011-06-13 19:49:06 -04:00
|
|
|
Integer.valueOf(selectionSize));
|
2011-06-06 19:15:04 -04:00
|
|
|
((AlertDialog) dialog).setMessage(message);
|
|
|
|
}
|
2011-06-04 19:35:11 -04:00
|
|
|
break;
|
|
|
|
}
|
2011-02-06 17:09:48 -05:00
|
|
|
default: {
|
|
|
|
super.onPrepareDialog(id, dialog);
|
|
|
|
}
|
2010-07-13 17:49:28 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-02-06 17:09:48 -05:00
|
|
|
private void onToggleRead(MessageInfoHolder holder) {
|
2012-02-04 08:52:45 -05:00
|
|
|
LocalMessage message = holder.message;
|
|
|
|
Folder folder = message.getFolder();
|
|
|
|
Account account = folder.getAccount();
|
|
|
|
String folderName = folder.getName();
|
|
|
|
mController.setFlag(account, folderName, new Message[] { message }, Flag.SEEN, !holder.read);
|
2010-07-13 17:49:28 -04:00
|
|
|
holder.read = !holder.read;
|
|
|
|
mHandler.sortMessages();
|
|
|
|
}
|
|
|
|
|
2011-02-06 17:09:48 -05:00
|
|
|
private void onToggleFlag(MessageInfoHolder holder) {
|
2012-02-04 08:52:45 -05:00
|
|
|
LocalMessage message = holder.message;
|
|
|
|
Folder folder = message.getFolder();
|
|
|
|
Account account = folder.getAccount();
|
|
|
|
String folderName = folder.getName();
|
|
|
|
mController.setFlag(account, folderName, new Message[] { message }, Flag.FLAGGED, !holder.flagged);
|
2010-07-13 17:49:28 -04:00
|
|
|
holder.flagged = !holder.flagged;
|
|
|
|
mHandler.sortMessages();
|
|
|
|
}
|
|
|
|
|
2011-02-06 17:09:48 -05:00
|
|
|
private void checkMail(Account account, String folderName) {
|
2010-07-13 17:49:28 -04:00
|
|
|
mController.synchronizeMailbox(account, folderName, mAdapter.mListener, null);
|
|
|
|
mController.sendPendingMessages(account, mAdapter.mListener);
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2011-02-06 17:09:48 -05:00
|
|
|
public boolean onOptionsItemSelected(MenuItem item) {
|
2011-06-04 16:57:03 -04:00
|
|
|
final List<MessageInfoHolder> selection = getSelectionFromCheckboxes();
|
2010-07-13 17:49:28 -04:00
|
|
|
int itemId = item.getItemId();
|
2011-02-06 17:09:48 -05:00
|
|
|
switch (itemId) {
|
|
|
|
case R.id.compose: {
|
|
|
|
onCompose();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
case R.id.accounts: {
|
|
|
|
onAccounts();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
case R.id.set_sort_date: {
|
2012-04-08 17:17:06 -04:00
|
|
|
changeSort(SortType.SORT_DATE);
|
2011-02-06 17:09:48 -05:00
|
|
|
return true;
|
|
|
|
}
|
2012-03-11 18:48:56 -04:00
|
|
|
case R.id.set_sort_arrival: {
|
2012-04-08 17:17:06 -04:00
|
|
|
changeSort(SortType.SORT_ARRIVAL);
|
2012-03-11 18:48:56 -04:00
|
|
|
return true;
|
|
|
|
}
|
2011-02-06 17:09:48 -05:00
|
|
|
case R.id.set_sort_subject: {
|
2012-04-08 17:17:06 -04:00
|
|
|
changeSort(SortType.SORT_SUBJECT);
|
2011-02-06 17:09:48 -05:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
case R.id.set_sort_sender: {
|
2012-04-08 17:17:06 -04:00
|
|
|
changeSort(SortType.SORT_SENDER);
|
2011-02-06 17:09:48 -05:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
case R.id.set_sort_flag: {
|
2012-04-08 17:17:06 -04:00
|
|
|
changeSort(SortType.SORT_FLAGGED);
|
2011-02-06 17:09:48 -05:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
case R.id.set_sort_unread: {
|
2012-04-08 17:17:06 -04:00
|
|
|
changeSort(SortType.SORT_UNREAD);
|
2011-02-06 17:09:48 -05:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
case R.id.set_sort_attach: {
|
2012-04-08 17:17:06 -04:00
|
|
|
changeSort(SortType.SORT_ATTACHMENT);
|
2011-02-06 17:09:48 -05:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
case R.id.select_all:
|
|
|
|
case R.id.batch_select_all: {
|
|
|
|
setAllSelected(true);
|
|
|
|
toggleBatchButtons();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
case R.id.batch_deselect_all: {
|
|
|
|
setAllSelected(false);
|
|
|
|
toggleBatchButtons();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
case R.id.batch_delete_op: {
|
2011-06-04 16:57:03 -04:00
|
|
|
onDelete(selection);
|
2011-02-06 17:09:48 -05:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
case R.id.batch_mark_read_op: {
|
2011-06-04 16:57:03 -04:00
|
|
|
setFlag(selection, Flag.SEEN, true);
|
2011-02-06 17:09:48 -05:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
case R.id.batch_mark_unread_op: {
|
2011-06-04 16:57:03 -04:00
|
|
|
setFlag(selection, Flag.SEEN, false);
|
2011-02-06 17:09:48 -05:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
case R.id.batch_flag_op: {
|
2011-06-04 16:57:03 -04:00
|
|
|
setFlag(selection, Flag.FLAGGED, true);
|
2011-02-06 17:09:48 -05:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
case R.id.batch_unflag_op: {
|
2011-06-04 16:57:03 -04:00
|
|
|
setFlag(selection, Flag.FLAGGED, false);
|
2011-02-06 17:09:48 -05:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
case R.id.app_settings: {
|
|
|
|
onEditPrefs();
|
|
|
|
return true;
|
|
|
|
}
|
2010-07-13 17:49:28 -04:00
|
|
|
}
|
|
|
|
|
2011-02-06 17:09:48 -05:00
|
|
|
if (mQueryString != null) {
|
2010-07-13 17:49:28 -04:00
|
|
|
// None of the options after this point are "safe" for search results
|
|
|
|
//TODO: This is not true for "unread" and "starred" searches in regular folders
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2011-02-06 17:09:48 -05:00
|
|
|
switch (itemId) {
|
|
|
|
case R.id.check_mail: {
|
|
|
|
if (mFolderName != null) {
|
|
|
|
checkMail(mAccount, mFolderName);
|
2010-07-13 17:49:28 -04:00
|
|
|
}
|
2011-02-06 17:09:48 -05:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
case R.id.send_messages: {
|
|
|
|
mController.sendPendingMessages(mAccount, mAdapter.mListener);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
case R.id.list_folders: {
|
|
|
|
onShowFolderList();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
case R.id.mark_all_as_read: {
|
|
|
|
if (mFolderName != null) {
|
|
|
|
onMarkAllAsRead(mAccount, mFolderName);
|
2010-07-13 17:49:28 -04:00
|
|
|
}
|
2011-02-06 17:09:48 -05:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
case R.id.folder_settings: {
|
|
|
|
if (mFolderName != null) {
|
|
|
|
FolderSettings.actionSettings(this, mAccount, mFolderName);
|
2010-07-13 17:49:28 -04:00
|
|
|
}
|
2011-02-06 17:09:48 -05:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
case R.id.account_settings: {
|
|
|
|
onEditAccount();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
case R.id.batch_copy_op: {
|
2011-06-04 16:57:03 -04:00
|
|
|
onCopy(selection);
|
2011-02-06 17:09:48 -05:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
case R.id.batch_archive_op: {
|
2011-06-04 16:57:03 -04:00
|
|
|
onArchive(selection);
|
2011-02-06 17:09:48 -05:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
case R.id.batch_spam_op: {
|
2011-06-04 16:57:03 -04:00
|
|
|
onSpam(selection);
|
2011-02-06 17:09:48 -05:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
case R.id.batch_move_op: {
|
2011-06-04 16:57:03 -04:00
|
|
|
onMove(selection);
|
2011-02-06 17:09:48 -05:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
case R.id.expunge: {
|
|
|
|
if (mCurrentFolder != null) {
|
|
|
|
onExpunge(mAccount, mCurrentFolder.name);
|
2010-07-13 17:49:28 -04:00
|
|
|
}
|
2011-02-06 17:09:48 -05:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
default: {
|
|
|
|
return super.onOptionsItemSelected(item);
|
|
|
|
}
|
2010-07-13 17:49:28 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private final int[] batch_ops = { R.id.batch_copy_op, R.id.batch_delete_op, R.id.batch_flag_op,
|
|
|
|
R.id.batch_unflag_op, R.id.batch_mark_read_op, R.id.batch_mark_unread_op,
|
|
|
|
R.id.batch_archive_op, R.id.batch_spam_op, R.id.batch_move_op,
|
|
|
|
R.id.batch_select_all, R.id.batch_deselect_all
|
|
|
|
};
|
|
|
|
|
2011-02-06 17:09:48 -05:00
|
|
|
private void setOpsState(Menu menu, boolean state, boolean enabled) {
|
|
|
|
for (int id : batch_ops) {
|
2010-07-13 17:49:28 -04:00
|
|
|
menu.findItem(id).setVisible(state);
|
|
|
|
menu.findItem(id).setEnabled(enabled);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2011-02-06 17:09:48 -05:00
|
|
|
public boolean onPrepareOptionsMenu(Menu menu) {
|
2010-07-13 17:49:28 -04:00
|
|
|
boolean anySelected = anySelected();
|
|
|
|
|
|
|
|
menu.findItem(R.id.select_all).setVisible(! anySelected);
|
|
|
|
menu.findItem(R.id.batch_ops).setVisible(anySelected);
|
|
|
|
|
|
|
|
setOpsState(menu, true, anySelected);
|
|
|
|
|
2011-02-06 17:09:48 -05:00
|
|
|
if (mQueryString != null) {
|
2010-07-13 17:49:28 -04:00
|
|
|
menu.findItem(R.id.mark_all_as_read).setVisible(false);
|
|
|
|
menu.findItem(R.id.list_folders).setVisible(false);
|
|
|
|
menu.findItem(R.id.expunge).setVisible(false);
|
|
|
|
menu.findItem(R.id.batch_archive_op).setVisible(false);
|
|
|
|
menu.findItem(R.id.batch_spam_op).setVisible(false);
|
|
|
|
menu.findItem(R.id.batch_move_op).setVisible(false);
|
|
|
|
menu.findItem(R.id.batch_copy_op).setVisible(false);
|
|
|
|
menu.findItem(R.id.check_mail).setVisible(false);
|
|
|
|
menu.findItem(R.id.send_messages).setVisible(false);
|
2010-10-03 20:01:59 -04:00
|
|
|
menu.findItem(R.id.folder_settings).setVisible(false);
|
|
|
|
menu.findItem(R.id.account_settings).setVisible(false);
|
2011-02-06 17:09:48 -05:00
|
|
|
} else {
|
|
|
|
if (mCurrentFolder != null && mCurrentFolder.name.equals(mAccount.getOutboxFolderName())) {
|
2010-07-13 17:49:28 -04:00
|
|
|
menu.findItem(R.id.check_mail).setVisible(false);
|
2011-02-06 17:09:48 -05:00
|
|
|
} else {
|
2010-07-13 17:49:28 -04:00
|
|
|
menu.findItem(R.id.send_messages).setVisible(false);
|
|
|
|
}
|
|
|
|
|
2011-02-06 17:09:48 -05:00
|
|
|
if (mCurrentFolder != null && K9.ERROR_FOLDER_NAME.equals(mCurrentFolder.name)) {
|
2010-07-13 17:49:28 -04:00
|
|
|
menu.findItem(R.id.expunge).setVisible(false);
|
|
|
|
}
|
2012-04-06 17:45:44 -04:00
|
|
|
if (!mAccount.hasArchiveFolder()) {
|
2010-07-30 05:58:26 -04:00
|
|
|
menu.findItem(R.id.batch_archive_op).setVisible(false);
|
|
|
|
}
|
2012-04-11 03:19:18 -04:00
|
|
|
if (!mAccount.hasSpamFolder()) {
|
2010-07-30 05:58:26 -04:00
|
|
|
menu.findItem(R.id.batch_spam_op).setVisible(false);
|
|
|
|
}
|
2012-02-24 22:19:27 -05:00
|
|
|
|
|
|
|
if (!mController.isMoveCapable(mAccount)) {
|
|
|
|
// FIXME: Really we want to do this for all local-only folders
|
|
|
|
if (mCurrentFolder != null &&
|
|
|
|
!mAccount.getInboxFolderName().equals(mCurrentFolder.name)) {
|
|
|
|
menu.findItem(R.id.check_mail).setVisible(false);
|
|
|
|
}
|
|
|
|
menu.findItem(R.id.batch_archive_op).setVisible(false);
|
|
|
|
menu.findItem(R.id.batch_spam_op).setVisible(false);
|
|
|
|
menu.findItem(R.id.batch_move_op).setVisible(false);
|
|
|
|
menu.findItem(R.id.batch_copy_op).setVisible(false);
|
|
|
|
menu.findItem(R.id.expunge).setVisible(false);
|
|
|
|
}
|
2010-07-13 17:49:28 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
boolean newFlagState = computeBatchDirection(true);
|
|
|
|
boolean newReadState = computeBatchDirection(false);
|
|
|
|
menu.findItem(R.id.batch_flag_op).setVisible(newFlagState);
|
|
|
|
menu.findItem(R.id.batch_unflag_op).setVisible(!newFlagState);
|
|
|
|
menu.findItem(R.id.batch_mark_read_op).setVisible(newReadState);
|
|
|
|
menu.findItem(R.id.batch_mark_unread_op).setVisible(!newReadState);
|
|
|
|
menu.findItem(R.id.batch_deselect_all).setVisible(anySelected);
|
|
|
|
menu.findItem(R.id.batch_select_all).setEnabled(true);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2011-02-06 17:09:48 -05:00
|
|
|
public boolean onCreateOptionsMenu(Menu menu) {
|
2010-07-13 17:49:28 -04:00
|
|
|
super.onCreateOptionsMenu(menu);
|
|
|
|
getMenuInflater().inflate(R.menu.message_list_option, menu);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2011-02-06 17:09:48 -05:00
|
|
|
public boolean onContextItemSelected(MenuItem item) {
|
2010-07-13 17:49:28 -04:00
|
|
|
AdapterContextMenuInfo info = (AdapterContextMenuInfo) item.getMenuInfo();
|
2011-06-04 16:57:03 -04:00
|
|
|
final MessageInfoHolder holder = mSelectedMessage == null ? (MessageInfoHolder) mAdapter.getItem(info.position) : mSelectedMessage;
|
2010-07-14 14:39:57 -04:00
|
|
|
// don't need this anymore
|
2011-03-31 21:45:50 -04:00
|
|
|
mSelectedMessage = null;
|
2010-07-13 17:49:28 -04:00
|
|
|
|
2011-06-04 16:57:03 -04:00
|
|
|
final List<MessageInfoHolder> selection = getSelectionFromMessage(holder);
|
2011-02-06 17:09:48 -05:00
|
|
|
switch (item.getItemId()) {
|
|
|
|
case R.id.open: {
|
|
|
|
onOpenMessage(holder);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case R.id.select: {
|
2011-06-04 16:57:03 -04:00
|
|
|
setSelected(selection, true);
|
2011-02-06 17:09:48 -05:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
case R.id.deselect: {
|
2011-06-04 16:57:03 -04:00
|
|
|
setSelected(selection, false);
|
2011-02-06 17:09:48 -05:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
case R.id.delete: {
|
2011-06-04 16:57:03 -04:00
|
|
|
onDelete(selection);
|
2011-02-06 17:09:48 -05:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
case R.id.reply: {
|
|
|
|
onReply(holder);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case R.id.reply_all: {
|
|
|
|
onReplyAll(holder);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case R.id.forward: {
|
|
|
|
onForward(holder);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case R.id.send_again: {
|
|
|
|
onResendMessage(holder);
|
|
|
|
break;
|
2010-11-12 22:09:32 -05:00
|
|
|
|
2011-02-06 17:09:48 -05:00
|
|
|
}
|
|
|
|
case R.id.mark_as_read: {
|
|
|
|
onToggleRead(holder);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case R.id.flag: {
|
|
|
|
onToggleFlag(holder);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case R.id.archive: {
|
2011-06-04 16:57:03 -04:00
|
|
|
onArchive(selection);
|
2011-02-06 17:09:48 -05:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
case R.id.spam: {
|
2011-06-04 16:57:03 -04:00
|
|
|
onSpam(selection);
|
2011-02-06 17:09:48 -05:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
case R.id.move: {
|
2011-06-04 16:57:03 -04:00
|
|
|
onMove(selection);
|
2011-02-06 17:09:48 -05:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
case R.id.copy: {
|
2011-06-04 16:57:03 -04:00
|
|
|
onCopy(selection);
|
2011-02-06 17:09:48 -05:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
case R.id.send_alternate: {
|
|
|
|
onSendAlternate(mAccount, holder);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case R.id.same_sender: {
|
|
|
|
MessageList.actionHandle(MessageList.this,
|
2011-05-05 10:59:18 -04:00
|
|
|
"From " + holder.sender, holder.senderAddress, false,
|
2011-02-06 17:09:48 -05:00
|
|
|
null, null);
|
|
|
|
break;
|
|
|
|
}
|
2010-07-13 17:49:28 -04:00
|
|
|
}
|
|
|
|
return super.onContextItemSelected(item);
|
|
|
|
}
|
|
|
|
|
2011-02-06 17:09:48 -05:00
|
|
|
public void onSendAlternate(Account account, MessageInfoHolder holder) {
|
2010-07-13 17:49:28 -04:00
|
|
|
mController.sendAlternate(this, account, holder.message);
|
|
|
|
}
|
|
|
|
|
2011-02-06 17:09:48 -05:00
|
|
|
public void showProgressIndicator(boolean status) {
|
2010-07-13 17:49:28 -04:00
|
|
|
setProgressBarIndeterminateVisibility(status);
|
|
|
|
ProgressBar bar = (ProgressBar)mListView.findViewById(R.id.message_list_progress);
|
2011-02-06 17:09:48 -05:00
|
|
|
if (bar == null) {
|
2010-07-13 17:49:28 -04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
bar.setIndeterminate(true);
|
2011-02-06 17:09:48 -05:00
|
|
|
if (status) {
|
2010-07-13 17:49:28 -04:00
|
|
|
bar.setVisibility(ProgressBar.VISIBLE);
|
2011-02-06 17:09:48 -05:00
|
|
|
} else {
|
2010-07-13 17:49:28 -04:00
|
|
|
bar.setVisibility(ProgressBar.INVISIBLE);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-11-01 19:44:33 -04:00
|
|
|
@Override
|
|
|
|
protected void onSwipeRightToLeft(final MotionEvent e1, final MotionEvent e2) {
|
|
|
|
// Handle right-to-left as an un-select
|
|
|
|
handleSwipe(e1, false);
|
|
|
|
}
|
2010-07-13 17:49:28 -04:00
|
|
|
|
2011-11-01 19:44:33 -04:00
|
|
|
@Override
|
|
|
|
protected void onSwipeLeftToRight(final MotionEvent e1, final MotionEvent e2) {
|
|
|
|
// Handle left-to-right as a select.
|
|
|
|
handleSwipe(e1, true);
|
|
|
|
}
|
2010-07-13 17:49:28 -04:00
|
|
|
|
2011-11-01 19:44:33 -04:00
|
|
|
/**
|
|
|
|
* Handle a select or unselect swipe event
|
|
|
|
* @param downMotion Event that started the swipe
|
|
|
|
* @param selected true if this was an attempt to select (i.e. left to right).
|
|
|
|
*/
|
|
|
|
private void handleSwipe(final MotionEvent downMotion, final boolean selected) {
|
Fix gesture detection
This commit addresses 2 issues:
1) Before, a general GestureDetector was registered on the highest level in K9Activity
This resulted in EVERY inherited activity to have a useless, unused gesture detector.
But more than that, in MessageList, a second GestureDetector was assigned to the ListView.
On every fling gesture, both detectors called the onSwipe() methods,
which technically did the following:
- The one directly assigned to the ListView would work corectly by mapping the
(local) event coordinates to the right entry in the ListView
- The global one worked on screen coordinates, so the onSwipe() method would
likely select the wrong ListView entry (system menu bar offset).
- For some reason this "worked" fine, and only the correct entry was selected,
despite two detectors used.
2) The gesture detection for the MessageView caused problems when the message
itself was scrollable, i.e. wide HTML mails. A fling gesture inside the WebView
would scroll the message, but also switch the message.
This commit fixes all those by doing the following:
- Don't register the GestureDetector in K9Activity, instead make the member variable
accessible by subclasses.
- In the subclasses that need a detector register it
- In K9Activity.dispatchTouchEvent() check for mGestureDetector being null
- For MessageList:
* Remove the duplicate gesture detector assigned to the ListView
* in the handleSwipe() methods: calclulate pixel offset of the ListView to make
it work using the global screen coordinates
- For MessageView: Limit sensitive area to the message header, to prevent interference
with the WebView scrolling
- Respect current behavior:
* Force-enable gestures for the MessageList
* Respect user setting in MessageView
- Make sure that after a successful swipe gesture, any pending action is cancelled, to
prevent unwanted things to happen (such as expanding the header after changing
the message, or a context menu popping up in the MessageList).
See http://code.google.com/p/android/issues/detail?id=8497
2012-04-30 19:56:06 -04:00
|
|
|
int[] listPosition = new int[2];
|
|
|
|
mListView.getLocationOnScreen(listPosition);
|
|
|
|
int position = mListView.pointToPosition((int) downMotion.getRawX() - listPosition[0], (int) downMotion.getRawY() - listPosition[1]);
|
2011-11-01 19:44:33 -04:00
|
|
|
if (position != AdapterView.INVALID_POSITION) {
|
|
|
|
MessageInfoHolder msgInfoHolder = (MessageInfoHolder) mAdapter.getItem(position);
|
|
|
|
|
|
|
|
if (msgInfoHolder != null && msgInfoHolder.selected != selected) {
|
|
|
|
msgInfoHolder.selected = selected;
|
|
|
|
mSelectedCount += (selected ? 1 : -1);
|
|
|
|
mAdapter.notifyDataSetChanged();
|
|
|
|
toggleBatchButtons();
|
2010-07-13 17:49:28 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2011-02-06 17:09:48 -05:00
|
|
|
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
|
2010-07-13 17:49:28 -04:00
|
|
|
super.onCreateContextMenu(menu, v, menuInfo);
|
|
|
|
|
|
|
|
AdapterContextMenuInfo info = (AdapterContextMenuInfo) menuInfo;
|
|
|
|
MessageInfoHolder message = (MessageInfoHolder) mAdapter.getItem(info.position);
|
2010-07-14 14:39:57 -04:00
|
|
|
// remember which message was originally selected, in case the list changes while the
|
|
|
|
// dialog is up
|
|
|
|
mSelectedMessage = message;
|
2010-07-13 17:49:28 -04:00
|
|
|
|
2011-02-06 17:09:48 -05:00
|
|
|
if (message == null) {
|
2010-07-13 17:49:28 -04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
getMenuInflater().inflate(R.menu.message_list_context, menu);
|
|
|
|
|
2011-01-18 20:21:27 -05:00
|
|
|
menu.setHeaderTitle(message.message.getSubject());
|
2010-07-13 17:49:28 -04:00
|
|
|
|
2011-02-06 17:09:48 -05:00
|
|
|
if (message.read) {
|
2010-07-13 17:49:28 -04:00
|
|
|
menu.findItem(R.id.mark_as_read).setTitle(R.string.mark_as_unread_action);
|
|
|
|
}
|
|
|
|
|
2011-02-06 17:09:48 -05:00
|
|
|
if (message.flagged) {
|
2010-07-13 17:49:28 -04:00
|
|
|
menu.findItem(R.id.flag).setTitle(R.string.unflag_action);
|
|
|
|
}
|
|
|
|
|
|
|
|
Account account = message.message.getFolder().getAccount();
|
2011-02-06 17:09:48 -05:00
|
|
|
if (!mController.isCopyCapable(account)) {
|
2010-07-13 17:49:28 -04:00
|
|
|
menu.findItem(R.id.copy).setVisible(false);
|
|
|
|
}
|
|
|
|
|
2011-02-06 17:09:48 -05:00
|
|
|
if (!mController.isMoveCapable(account)) {
|
2010-07-13 17:49:28 -04:00
|
|
|
menu.findItem(R.id.move).setVisible(false);
|
|
|
|
menu.findItem(R.id.archive).setVisible(false);
|
|
|
|
menu.findItem(R.id.spam).setVisible(false);
|
|
|
|
}
|
|
|
|
|
2012-04-06 17:45:44 -04:00
|
|
|
if (!account.hasArchiveFolder()) {
|
2010-07-13 17:49:28 -04:00
|
|
|
menu.findItem(R.id.archive).setVisible(false);
|
|
|
|
}
|
2012-04-06 17:45:44 -04:00
|
|
|
|
2012-04-30 10:12:14 -04:00
|
|
|
if (!account.hasSpamFolder()) {
|
2010-07-13 17:49:28 -04:00
|
|
|
menu.findItem(R.id.spam).setVisible(false);
|
|
|
|
}
|
|
|
|
|
2011-02-06 17:09:48 -05:00
|
|
|
if (message.selected) {
|
2010-07-13 17:49:28 -04:00
|
|
|
menu.findItem(R.id.select).setVisible(false);
|
|
|
|
menu.findItem(R.id.deselect).setVisible(true);
|
2011-02-06 17:09:48 -05:00
|
|
|
} else {
|
2010-07-13 17:49:28 -04:00
|
|
|
menu.findItem(R.id.select).setVisible(true);
|
|
|
|
menu.findItem(R.id.deselect).setVisible(false);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-02-06 17:09:48 -05:00
|
|
|
class MessageListAdapter extends BaseAdapter {
|
2010-07-13 17:49:28 -04:00
|
|
|
private final List<MessageInfoHolder> messages = java.util.Collections.synchronizedList(new ArrayList<MessageInfoHolder>());
|
|
|
|
|
2011-02-06 17:09:48 -05:00
|
|
|
private final ActivityListener mListener = new ActivityListener() {
|
2010-07-13 17:49:28 -04:00
|
|
|
|
2010-07-13 19:59:14 -04:00
|
|
|
@Override
|
2011-02-13 19:53:50 -05:00
|
|
|
public void informUserOfStatus() {
|
2010-07-13 19:59:14 -04:00
|
|
|
mHandler.refreshTitle();
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2011-02-13 19:53:50 -05:00
|
|
|
public void synchronizeMailboxStarted(Account account, String folder) {
|
|
|
|
if (updateForMe(account, folder)) {
|
|
|
|
mHandler.progress(true);
|
|
|
|
mHandler.folderLoading(folder, true);
|
|
|
|
}
|
|
|
|
super.synchronizeMailboxStarted(account, folder);
|
2010-07-13 19:59:14 -04:00
|
|
|
}
|
|
|
|
|
2010-07-13 17:49:28 -04:00
|
|
|
@Override
|
|
|
|
public void synchronizeMailboxFinished(Account account, String folder,
|
2011-02-06 17:09:48 -05:00
|
|
|
int totalMessagesInMailbox, int numNewMessages) {
|
2010-07-13 17:49:28 -04:00
|
|
|
|
2011-02-06 17:09:48 -05:00
|
|
|
if (updateForMe(account, folder)) {
|
2010-07-13 17:49:28 -04:00
|
|
|
mHandler.progress(false);
|
|
|
|
mHandler.folderLoading(folder, false);
|
|
|
|
mHandler.sortMessages();
|
|
|
|
}
|
2011-02-13 19:53:50 -05:00
|
|
|
super.synchronizeMailboxFinished(account, folder, totalMessagesInMailbox, numNewMessages);
|
2010-07-13 17:49:28 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2011-02-06 17:09:48 -05:00
|
|
|
public void synchronizeMailboxFailed(Account account, String folder, String message) {
|
2010-07-13 17:49:28 -04:00
|
|
|
|
2011-02-06 17:09:48 -05:00
|
|
|
if (updateForMe(account, folder)) {
|
2010-07-13 17:49:28 -04:00
|
|
|
mHandler.progress(false);
|
|
|
|
mHandler.folderLoading(folder, false);
|
|
|
|
mHandler.sortMessages();
|
|
|
|
}
|
2011-02-13 19:53:50 -05:00
|
|
|
super.synchronizeMailboxFailed(account, folder, message);
|
2010-07-13 17:49:28 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2011-02-06 17:09:48 -05:00
|
|
|
public void synchronizeMailboxAddOrUpdateMessage(Account account, String folder, Message message) {
|
2010-07-13 17:49:28 -04:00
|
|
|
addOrUpdateMessage(account, folder, message, true);
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2011-02-06 17:09:48 -05:00
|
|
|
public void synchronizeMailboxRemovedMessage(Account account, String folder, Message message) {
|
2010-07-13 17:49:28 -04:00
|
|
|
MessageInfoHolder holder = getMessage(message);
|
2011-02-06 17:09:48 -05:00
|
|
|
if (holder == null) {
|
2010-07-13 17:49:28 -04:00
|
|
|
Log.w(K9.LOG_TAG, "Got callback to remove non-existent message with UID " + message.getUid());
|
2011-02-06 17:09:48 -05:00
|
|
|
} else {
|
2011-06-04 16:57:03 -04:00
|
|
|
removeMessages(Collections.singletonList(holder));
|
2010-07-13 17:49:28 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2011-02-06 17:09:48 -05:00
|
|
|
public void listLocalMessagesStarted(Account account, String folder) {
|
2011-02-13 19:53:50 -05:00
|
|
|
if ((mQueryString != null && folder == null) || (account != null && account.equals(mAccount))) {
|
2010-07-13 17:49:28 -04:00
|
|
|
mHandler.progress(true);
|
2011-02-06 17:09:48 -05:00
|
|
|
if (folder != null) {
|
2010-07-13 17:49:28 -04:00
|
|
|
mHandler.folderLoading(folder, true);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2011-02-06 17:09:48 -05:00
|
|
|
public void listLocalMessagesFailed(Account account, String folder, String message) {
|
2011-02-13 19:53:50 -05:00
|
|
|
if ((mQueryString != null && folder == null) || (account != null && account.equals(mAccount))) {
|
2010-07-13 17:49:28 -04:00
|
|
|
mHandler.sortMessages();
|
|
|
|
mHandler.progress(false);
|
2011-02-06 17:09:48 -05:00
|
|
|
if (folder != null) {
|
2010-07-13 17:49:28 -04:00
|
|
|
mHandler.folderLoading(folder, false);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2011-02-06 17:09:48 -05:00
|
|
|
public void listLocalMessagesFinished(Account account, String folder) {
|
2011-02-13 19:53:50 -05:00
|
|
|
if ((mQueryString != null && folder == null) || (account != null && account.equals(mAccount))) {
|
2010-07-13 17:49:28 -04:00
|
|
|
mHandler.sortMessages();
|
|
|
|
mHandler.progress(false);
|
2011-02-06 17:09:48 -05:00
|
|
|
if (folder != null) {
|
2010-07-13 17:49:28 -04:00
|
|
|
mHandler.folderLoading(folder, false);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2011-02-06 17:09:48 -05:00
|
|
|
public void listLocalMessagesRemoveMessage(Account account, String folder, Message message) {
|
2010-07-13 17:49:28 -04:00
|
|
|
MessageInfoHolder holder = getMessage(message);
|
2011-02-06 17:09:48 -05:00
|
|
|
if (holder != null) {
|
2011-06-04 16:57:03 -04:00
|
|
|
removeMessages(Collections.singletonList(holder));
|
2010-07-13 17:49:28 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2011-02-06 17:09:48 -05:00
|
|
|
public void listLocalMessagesAddMessages(Account account, String folder, List<Message> messages) {
|
2010-07-13 17:49:28 -04:00
|
|
|
addOrUpdateMessages(account, folder, messages, false);
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2011-02-06 17:09:48 -05:00
|
|
|
public void listLocalMessagesUpdateMessage(Account account, String folder, Message message) {
|
2010-07-13 17:49:28 -04:00
|
|
|
addOrUpdateMessage(account, folder, message, false);
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2011-02-06 17:09:48 -05:00
|
|
|
public void searchStats(AccountStats stats) {
|
2010-07-13 17:49:28 -04:00
|
|
|
mUnreadMessageCount = stats.unreadMessageCount;
|
2011-02-13 19:53:50 -05:00
|
|
|
super.searchStats(stats);
|
2010-07-13 17:49:28 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2011-02-06 17:09:48 -05:00
|
|
|
public void folderStatusChanged(Account account, String folder, int unreadMessageCount) {
|
|
|
|
if (updateForMe(account, folder)) {
|
2010-07-13 17:49:28 -04:00
|
|
|
mUnreadMessageCount = unreadMessageCount;
|
|
|
|
}
|
2011-02-13 19:53:50 -05:00
|
|
|
super.folderStatusChanged(account, folder, unreadMessageCount);
|
2010-07-13 17:49:28 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2011-02-06 17:09:48 -05:00
|
|
|
public void messageUidChanged(Account account, String folder, String oldUid, String newUid) {
|
2010-07-13 17:49:28 -04:00
|
|
|
MessageReference ref = new MessageReference();
|
|
|
|
ref.accountUuid = account.getUuid();
|
|
|
|
ref.folderName = folder;
|
|
|
|
ref.uid = oldUid;
|
|
|
|
|
|
|
|
MessageInfoHolder holder = getMessage(ref);
|
2011-02-06 17:09:48 -05:00
|
|
|
if (holder != null) {
|
2010-07-13 17:49:28 -04:00
|
|
|
holder.uid = newUid;
|
|
|
|
holder.message.setUid(newUid);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2011-02-06 17:09:48 -05:00
|
|
|
private boolean updateForMe(Account account, String folder) {
|
|
|
|
if ((account.equals(mAccount) && mFolderName != null && folder.equals(mFolderName))) {
|
2010-07-13 17:49:28 -04:00
|
|
|
return true;
|
2011-02-06 17:09:48 -05:00
|
|
|
} else {
|
2010-07-13 17:49:28 -04:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private Drawable mAttachmentIcon;
|
|
|
|
private Drawable mAnsweredIcon;
|
|
|
|
|
2011-02-06 17:09:48 -05:00
|
|
|
MessageListAdapter() {
|
2011-01-17 12:25:00 -05:00
|
|
|
mAttachmentIcon = getResources().getDrawable(R.drawable.ic_email_attachment_small);
|
|
|
|
mAnsweredIcon = getResources().getDrawable(R.drawable.ic_email_answered_small);
|
2010-07-13 17:49:28 -04:00
|
|
|
}
|
|
|
|
|
2011-02-06 17:09:48 -05:00
|
|
|
public void markAllMessagesAsDirty() {
|
|
|
|
for (MessageInfoHolder holder : mAdapter.messages) {
|
2010-10-08 01:34:33 -04:00
|
|
|
holder.dirty = true;
|
|
|
|
}
|
|
|
|
}
|
2011-02-06 17:09:48 -05:00
|
|
|
public void pruneDirtyMessages() {
|
|
|
|
synchronized (mAdapter.messages) {
|
2010-11-04 21:16:35 -04:00
|
|
|
Iterator<MessageInfoHolder> iter = mAdapter.messages.iterator();
|
2011-02-06 17:09:48 -05:00
|
|
|
while (iter.hasNext()) {
|
2010-11-04 21:16:35 -04:00
|
|
|
MessageInfoHolder holder = iter.next();
|
2011-02-06 17:09:48 -05:00
|
|
|
if (holder.dirty) {
|
|
|
|
if (holder.selected) {
|
2010-11-04 21:16:35 -04:00
|
|
|
mSelectedCount--;
|
|
|
|
toggleBatchButtons();
|
|
|
|
}
|
2011-06-04 16:57:03 -04:00
|
|
|
mAdapter.removeMessages(Collections.singletonList(holder));
|
2010-10-08 02:18:45 -04:00
|
|
|
}
|
2010-10-08 01:34:33 -04:00
|
|
|
}
|
2010-11-04 22:59:21 -04:00
|
|
|
}
|
2010-10-08 01:34:33 -04:00
|
|
|
}
|
|
|
|
|
2011-06-04 16:57:03 -04:00
|
|
|
/**
|
|
|
|
* @param holders
|
|
|
|
* Never {@code null}.
|
|
|
|
*/
|
2011-02-06 17:09:48 -05:00
|
|
|
public void removeMessages(List<MessageInfoHolder> holders) {
|
2011-06-04 16:57:03 -04:00
|
|
|
mHandler.removeMessages(holders);
|
2010-07-13 17:49:28 -04:00
|
|
|
}
|
|
|
|
|
2011-02-06 17:09:48 -05:00
|
|
|
private void addOrUpdateMessage(Account account, String folderName, Message message, boolean verifyAgainstSearch) {
|
2010-07-13 17:49:28 -04:00
|
|
|
List<Message> messages = new ArrayList<Message>();
|
|
|
|
messages.add(message);
|
2010-10-03 06:56:16 -04:00
|
|
|
addOrUpdateMessages(account, folderName, messages, verifyAgainstSearch);
|
2010-07-13 17:49:28 -04:00
|
|
|
}
|
|
|
|
|
2011-02-06 17:09:48 -05:00
|
|
|
private void addOrUpdateMessages(final Account account, final String folderName, final List<Message> providedMessages, final boolean verifyAgainstSearch) {
|
2010-09-01 23:45:16 -04:00
|
|
|
// we copy the message list because the callback doesn't expect
|
2010-09-02 20:56:19 -04:00
|
|
|
// the callbacks to mutate it.
|
2010-09-01 23:45:16 -04:00
|
|
|
final List<Message> messages = new ArrayList<Message>(providedMessages);
|
|
|
|
|
2010-10-21 16:49:20 -04:00
|
|
|
boolean needsSort = false;
|
|
|
|
final List<MessageInfoHolder> messagesToAdd = new ArrayList<MessageInfoHolder>();
|
|
|
|
List<MessageInfoHolder> messagesToRemove = new ArrayList<MessageInfoHolder>();
|
|
|
|
List<Message> messagesToSearch = new ArrayList<Message>();
|
2010-07-13 17:49:28 -04:00
|
|
|
|
2010-10-21 16:49:20 -04:00
|
|
|
// cache field into local variable for faster access for JVM without JIT
|
|
|
|
final MessageHelper messageHelper = mMessageHelper;
|
2010-10-03 06:56:16 -04:00
|
|
|
|
2011-02-06 17:09:48 -05:00
|
|
|
for (Message message : messages) {
|
2010-10-21 16:49:20 -04:00
|
|
|
MessageInfoHolder m = getMessage(message);
|
2011-02-06 17:09:48 -05:00
|
|
|
if (message.isSet(Flag.DELETED)) {
|
|
|
|
if (m != null) {
|
2010-10-21 16:49:20 -04:00
|
|
|
messagesToRemove.add(m);
|
|
|
|
}
|
2011-02-06 17:09:48 -05:00
|
|
|
} else {
|
2010-10-21 16:49:20 -04:00
|
|
|
final Folder messageFolder = message.getFolder();
|
|
|
|
final Account messageAccount = messageFolder.getAccount();
|
2011-02-06 17:09:48 -05:00
|
|
|
if (m == null) {
|
|
|
|
if (updateForMe(account, folderName)) {
|
2010-10-21 16:49:20 -04:00
|
|
|
m = new MessageInfoHolder();
|
|
|
|
messageHelper.populate(m, message, new FolderInfoHolder(MessageList.this, messageFolder, messageAccount), messageAccount);
|
|
|
|
messagesToAdd.add(m);
|
2011-02-06 17:09:48 -05:00
|
|
|
} else {
|
|
|
|
if (mQueryString != null) {
|
|
|
|
if (verifyAgainstSearch) {
|
2010-10-21 16:49:20 -04:00
|
|
|
messagesToSearch.add(message);
|
2011-02-06 17:09:48 -05:00
|
|
|
} else {
|
2010-10-21 16:49:20 -04:00
|
|
|
m = new MessageInfoHolder();
|
|
|
|
messageHelper.populate(m, message, new FolderInfoHolder(MessageList.this, messageFolder, messageAccount), messageAccount);
|
|
|
|
messagesToAdd.add(m);
|
2010-08-30 23:58:33 -04:00
|
|
|
}
|
|
|
|
}
|
2010-07-13 17:49:28 -04:00
|
|
|
}
|
2011-02-06 17:09:48 -05:00
|
|
|
} else {
|
2010-10-21 16:49:20 -04:00
|
|
|
m.dirty = false; // as we reload the message, unset its dirty flag
|
|
|
|
messageHelper.populate(m, message, new FolderInfoHolder(MessageList.this, messageFolder, account), account);
|
|
|
|
needsSort = true;
|
2010-07-13 17:49:28 -04:00
|
|
|
}
|
2010-10-21 16:49:20 -04:00
|
|
|
}
|
|
|
|
}
|
2010-07-13 17:49:28 -04:00
|
|
|
|
2011-10-06 12:28:14 -04:00
|
|
|
if (!messagesToSearch.isEmpty()) {
|
2010-10-21 16:49:20 -04:00
|
|
|
mController.searchLocalMessages(mAccountUuids, mFolderNames, messagesToSearch.toArray(EMPTY_MESSAGE_ARRAY), mQueryString, mIntegrate, mQueryFlags, mForbiddenFlags,
|
2011-02-06 17:09:48 -05:00
|
|
|
new MessagingListener() {
|
2010-10-21 16:49:20 -04:00
|
|
|
@Override
|
2011-02-06 17:09:48 -05:00
|
|
|
public void listLocalMessagesAddMessages(Account account, String folder, List<Message> messages) {
|
2010-10-21 16:49:20 -04:00
|
|
|
addOrUpdateMessages(account, folder, messages, false);
|
2010-08-30 23:58:33 -04:00
|
|
|
}
|
2010-10-21 16:49:20 -04:00
|
|
|
});
|
|
|
|
}
|
2010-07-13 17:49:28 -04:00
|
|
|
|
2011-10-06 12:28:14 -04:00
|
|
|
if (!messagesToRemove.isEmpty()) {
|
2010-10-21 16:49:20 -04:00
|
|
|
removeMessages(messagesToRemove);
|
|
|
|
}
|
2010-07-13 17:49:28 -04:00
|
|
|
|
2011-10-06 12:28:14 -04:00
|
|
|
if (!messagesToAdd.isEmpty()) {
|
2010-10-21 16:49:20 -04:00
|
|
|
mHandler.addMessages(messagesToAdd);
|
|
|
|
}
|
|
|
|
|
2011-02-06 17:09:48 -05:00
|
|
|
if (needsSort) {
|
2010-10-21 16:49:20 -04:00
|
|
|
mHandler.sortMessages();
|
|
|
|
mHandler.resetUnreadCount();
|
|
|
|
}
|
2010-08-30 23:57:02 -04:00
|
|
|
}
|
2011-02-06 17:09:48 -05:00
|
|
|
public MessageInfoHolder getMessage(Message message) {
|
2010-10-16 04:27:58 -04:00
|
|
|
return getMessage(message.makeMessageReference());
|
2010-07-13 17:49:28 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
// XXX TODO - make this not use a for loop
|
2011-02-06 17:09:48 -05:00
|
|
|
public MessageInfoHolder getMessage(MessageReference messageReference) {
|
|
|
|
synchronized (mAdapter.messages) {
|
|
|
|
for (MessageInfoHolder holder : mAdapter.messages) {
|
2010-07-13 17:49:28 -04:00
|
|
|
/*
|
|
|
|
* 2010-06-21 - cketti
|
|
|
|
* Added null pointer check. Not sure what's causing 'holder'
|
|
|
|
* to be null. See log provided in issue 1749, comment #15.
|
2010-07-13 17:16:56 -04:00
|
|
|
*
|
2010-07-13 17:49:28 -04:00
|
|
|
* Please remove this comment once the cause was found and the
|
|
|
|
* bug(?) fixed.
|
|
|
|
*/
|
2011-02-06 17:09:48 -05:00
|
|
|
if ((holder != null) && holder.message.equalsReference(messageReference)) {
|
2010-07-13 17:49:28 -04:00
|
|
|
return holder;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
2011-02-06 17:09:48 -05:00
|
|
|
public FolderInfoHolder getFolder(String folder, Account account) {
|
2010-07-13 17:49:28 -04:00
|
|
|
LocalFolder local_folder = null;
|
2011-02-06 17:09:48 -05:00
|
|
|
try {
|
2010-07-13 17:49:28 -04:00
|
|
|
LocalStore localStore = account.getLocalStore();
|
|
|
|
local_folder = localStore.getFolder(folder);
|
2011-01-18 20:21:27 -05:00
|
|
|
return new FolderInfoHolder(context, local_folder, account);
|
2011-02-06 17:09:48 -05:00
|
|
|
} catch (Exception e) {
|
|
|
|
Log.e(K9.LOG_TAG, "getFolder(" + folder + ") goes boom: ", e);
|
2010-07-13 17:49:28 -04:00
|
|
|
return null;
|
2011-02-06 17:09:48 -05:00
|
|
|
} finally {
|
|
|
|
if (local_folder != null) {
|
2010-07-13 17:49:28 -04:00
|
|
|
local_folder.close();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-02-06 17:09:48 -05:00
|
|
|
private final OnClickListener flagClickListener = new OnClickListener() {
|
2011-06-04 17:55:48 -04:00
|
|
|
@Override
|
2011-02-06 17:09:48 -05:00
|
|
|
public void onClick(View v) {
|
2010-08-03 03:46:31 -04:00
|
|
|
// Perform action on clicks
|
|
|
|
MessageInfoHolder message = (MessageInfoHolder) getItem((Integer)v.getTag());
|
|
|
|
onToggleFlag(message);
|
2010-07-13 17:49:28 -04:00
|
|
|
}
|
2010-08-03 03:46:31 -04:00
|
|
|
};
|
2010-07-13 17:49:28 -04:00
|
|
|
|
2010-08-03 03:46:31 -04:00
|
|
|
@Override
|
2011-02-06 17:09:48 -05:00
|
|
|
public int getCount() {
|
2011-02-19 22:50:50 -05:00
|
|
|
return messages.size();
|
2010-07-13 17:49:28 -04:00
|
|
|
}
|
|
|
|
|
2010-08-03 01:46:35 -04:00
|
|
|
@Override
|
2011-02-06 17:09:48 -05:00
|
|
|
public long getItemId(int position) {
|
|
|
|
try {
|
|
|
|
MessageInfoHolder messageHolder = (MessageInfoHolder) getItem(position);
|
|
|
|
if (messageHolder != null) {
|
2011-01-18 20:21:27 -05:00
|
|
|
return messageHolder.message.getId();
|
2010-07-13 17:49:28 -04:00
|
|
|
}
|
2011-02-06 17:09:48 -05:00
|
|
|
} catch (Exception e) {
|
|
|
|
Log.i(K9.LOG_TAG, "getItemId(" + position + ") ", e);
|
2010-07-13 17:49:28 -04:00
|
|
|
}
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2011-02-06 17:09:48 -05:00
|
|
|
public Object getItem(long position) {
|
2010-07-13 17:49:28 -04:00
|
|
|
return getItem((int)position);
|
|
|
|
}
|
|
|
|
|
2010-08-03 01:46:35 -04:00
|
|
|
@Override
|
2011-02-06 17:09:48 -05:00
|
|
|
public Object getItem(int position) {
|
|
|
|
try {
|
|
|
|
synchronized (mAdapter.messages) {
|
|
|
|
if (position < mAdapter.messages.size()) {
|
2010-07-13 17:49:28 -04:00
|
|
|
return mAdapter.messages.get(position);
|
|
|
|
}
|
|
|
|
}
|
2011-02-06 17:09:48 -05:00
|
|
|
} catch (Exception e) {
|
2010-07-13 17:49:28 -04:00
|
|
|
Log.e(K9.LOG_TAG, "getItem(" + position + "), but folder.messages.size() = " + mAdapter.messages.size(), e);
|
|
|
|
}
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
2010-08-03 01:46:35 -04:00
|
|
|
@Override
|
2011-02-06 17:09:48 -05:00
|
|
|
public View getView(int position, View convertView, ViewGroup parent) {
|
2010-07-13 17:49:28 -04:00
|
|
|
MessageInfoHolder message = (MessageInfoHolder) getItem(position);
|
|
|
|
View view;
|
|
|
|
|
2011-02-06 17:09:48 -05:00
|
|
|
if ((convertView != null) && (convertView.getId() == R.layout.message_list_item)) {
|
2010-07-13 17:49:28 -04:00
|
|
|
view = convertView;
|
2011-02-06 17:09:48 -05:00
|
|
|
} else {
|
|
|
|
if (mTouchView) {
|
2010-07-13 17:49:28 -04:00
|
|
|
view = mInflater.inflate(R.layout.message_list_item_touchable, parent, false);
|
|
|
|
view.setId(R.layout.message_list_item);
|
2011-02-06 17:09:48 -05:00
|
|
|
} else {
|
2010-07-13 17:49:28 -04:00
|
|
|
view = mInflater.inflate(R.layout.message_list_item, parent, false);
|
|
|
|
view.setId(R.layout.message_list_item);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
MessageViewHolder holder = (MessageViewHolder) view.getTag();
|
|
|
|
|
2011-02-06 17:09:48 -05:00
|
|
|
if (holder == null) {
|
2010-07-13 17:49:28 -04:00
|
|
|
holder = new MessageViewHolder();
|
|
|
|
holder.subject = (TextView) view.findViewById(R.id.subject);
|
|
|
|
holder.from = (TextView) view.findViewById(R.id.from);
|
|
|
|
holder.date = (TextView) view.findViewById(R.id.date);
|
|
|
|
holder.chip = view.findViewById(R.id.chip);
|
|
|
|
holder.preview = (TextView) view.findViewById(R.id.preview);
|
|
|
|
holder.selected = (CheckBox) view.findViewById(R.id.selected_checkbox);
|
|
|
|
holder.flagged = (CheckBox) view.findViewById(R.id.flagged);
|
|
|
|
|
2010-08-03 03:46:31 -04:00
|
|
|
holder.flagged.setOnClickListener(flagClickListener);
|
2010-07-13 17:49:28 -04:00
|
|
|
|
2011-02-06 17:09:48 -05:00
|
|
|
if (!mStars) {
|
2010-07-13 17:49:28 -04:00
|
|
|
holder.flagged.setVisibility(View.GONE);
|
|
|
|
}
|
|
|
|
|
2011-02-06 17:09:48 -05:00
|
|
|
if (mCheckboxes) {
|
2010-07-13 17:49:28 -04:00
|
|
|
holder.selected.setVisibility(View.VISIBLE);
|
|
|
|
}
|
|
|
|
|
2011-02-06 17:09:48 -05:00
|
|
|
if (holder.selected != null) {
|
2010-07-13 17:49:28 -04:00
|
|
|
holder.selected.setOnCheckedChangeListener(holder);
|
|
|
|
}
|
2012-01-11 20:18:41 -05:00
|
|
|
holder.subject.setTextSize(TypedValue.COMPLEX_UNIT_SP, mFontSizes.getMessageListSubject());
|
|
|
|
holder.date.setTextSize(TypedValue.COMPLEX_UNIT_SP, mFontSizes.getMessageListDate());
|
2010-11-06 20:30:17 -04:00
|
|
|
|
2011-02-06 17:09:48 -05:00
|
|
|
if (mTouchView) {
|
2010-11-06 20:30:17 -04:00
|
|
|
holder.preview.setLines(mPreviewLines);
|
2012-01-11 20:18:41 -05:00
|
|
|
holder.preview.setTextSize(TypedValue.COMPLEX_UNIT_SP, mFontSizes.getMessageListPreview());
|
2010-11-06 20:30:17 -04:00
|
|
|
|
2011-02-06 17:09:48 -05:00
|
|
|
} else {
|
2012-01-11 20:18:41 -05:00
|
|
|
holder.from.setTextSize(TypedValue.COMPLEX_UNIT_SP, mFontSizes.getMessageListSender());
|
2010-11-06 20:30:17 -04:00
|
|
|
}
|
2010-07-13 17:49:28 -04:00
|
|
|
|
|
|
|
view.setTag(holder);
|
|
|
|
}
|
|
|
|
|
2011-02-06 17:09:48 -05:00
|
|
|
if (message != null) {
|
2010-08-03 03:46:31 -04:00
|
|
|
bindView(position, view, holder, message);
|
2011-02-06 17:09:48 -05:00
|
|
|
} else {
|
2010-10-21 16:49:05 -04:00
|
|
|
// This branch code is triggered when the local store
|
|
|
|
// hands us an invalid message
|
2010-07-13 17:49:28 -04:00
|
|
|
|
|
|
|
holder.chip.getBackground().setAlpha(0);
|
2010-12-29 19:52:00 -05:00
|
|
|
holder.subject.setText(getString(R.string.general_no_subject));
|
2010-07-13 17:49:28 -04:00
|
|
|
holder.subject.setTypeface(null, Typeface.NORMAL);
|
2010-12-29 19:52:00 -05:00
|
|
|
String noSender = getString(R.string.general_no_sender);
|
2011-02-06 17:09:48 -05:00
|
|
|
if (holder.preview != null) {
|
2010-12-29 19:52:00 -05:00
|
|
|
holder.preview.setText(noSender, TextView.BufferType.SPANNABLE);
|
|
|
|
Spannable str = (Spannable) holder.preview.getText();
|
|
|
|
|
2011-04-16 05:13:54 -04:00
|
|
|
str.setSpan(new StyleSpan(Typeface.NORMAL),
|
2011-01-06 11:55:08 -05:00
|
|
|
0,
|
|
|
|
noSender.length(),
|
2011-04-16 05:13:54 -04:00
|
|
|
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
|
2011-11-09 23:09:54 -05:00
|
|
|
str.setSpan(new AbsoluteSizeSpan(mFontSizes.getMessageListSender(), true),
|
2011-04-16 05:13:54 -04:00
|
|
|
0,
|
|
|
|
noSender.length(),
|
|
|
|
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
|
2011-02-06 17:09:48 -05:00
|
|
|
} else {
|
2010-12-29 19:52:00 -05:00
|
|
|
holder.from.setText(noSender);
|
2010-07-13 17:49:28 -04:00
|
|
|
holder.from.setTypeface(null, Typeface.NORMAL);
|
|
|
|
holder.from.setCompoundDrawablesWithIntrinsicBounds(null, null, null, null);
|
|
|
|
}
|
|
|
|
|
2010-12-29 19:52:00 -05:00
|
|
|
holder.date.setText(getString(R.string.general_no_date));
|
2010-07-13 17:49:28 -04:00
|
|
|
|
|
|
|
//WARNING: Order of the next 2 lines matter
|
|
|
|
holder.position = -1;
|
|
|
|
holder.selected.setChecked(false);
|
|
|
|
|
2011-02-06 17:09:48 -05:00
|
|
|
if (!mCheckboxes) {
|
2010-07-13 17:49:28 -04:00
|
|
|
holder.selected.setVisibility(View.GONE);
|
|
|
|
}
|
|
|
|
holder.flagged.setChecked(false);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return view;
|
|
|
|
}
|
|
|
|
|
2010-08-03 03:46:31 -04:00
|
|
|
/**
|
|
|
|
* Associate model data to view object.
|
2010-08-17 22:48:55 -04:00
|
|
|
*
|
2010-08-03 03:46:31 -04:00
|
|
|
* @param position
|
|
|
|
* The position of the item within the adapter's data set of
|
|
|
|
* the item whose view we want.
|
|
|
|
* @param view
|
|
|
|
* Main view component to alter. Never <code>null</code>.
|
|
|
|
* @param holder
|
|
|
|
* Convenience view holder - eases access to <tt>view</tt>
|
|
|
|
* child views. Never <code>null</code>.
|
|
|
|
* @param message
|
|
|
|
* Never <code>null</code>.
|
|
|
|
*/
|
|
|
|
private void bindView(final int position, final View view, final MessageViewHolder holder,
|
2011-02-06 17:09:48 -05:00
|
|
|
final MessageInfoHolder message) {
|
2010-08-03 03:46:31 -04:00
|
|
|
holder.subject.setTypeface(null, message.read ? Typeface.NORMAL : Typeface.BOLD);
|
|
|
|
|
|
|
|
// XXX TODO there has to be some way to walk our view hierarchy and get this
|
2011-01-18 20:21:27 -05:00
|
|
|
holder.flagged.setTag(position);
|
2010-08-03 03:46:31 -04:00
|
|
|
holder.flagged.setChecked(message.flagged);
|
|
|
|
|
|
|
|
// So that the mSelectedCount is only incremented/decremented
|
|
|
|
// when a user checks the checkbox (vs code)
|
|
|
|
holder.position = -1;
|
|
|
|
holder.selected.setChecked(message.selected);
|
|
|
|
|
2011-02-06 17:09:48 -05:00
|
|
|
if (!mCheckboxes) {
|
2010-08-03 03:46:31 -04:00
|
|
|
holder.selected.setVisibility(message.selected ? View.VISIBLE : View.GONE);
|
|
|
|
}
|
|
|
|
|
2010-12-28 04:11:10 -05:00
|
|
|
|
|
|
|
|
|
|
|
holder.chip.setBackgroundDrawable(message.message.getFolder().getAccount().generateColorChip().drawable());
|
2010-12-06 20:22:35 -05:00
|
|
|
holder.chip.getBackground().setAlpha(message.read ? 127 : 255);
|
2010-08-03 03:46:31 -04:00
|
|
|
view.getBackground().setAlpha(message.downloaded ? 0 : 127);
|
|
|
|
|
2011-02-06 17:09:48 -05:00
|
|
|
if ((message.message.getSubject() == null) || message.message.getSubject().equals("")) {
|
2010-08-03 03:46:31 -04:00
|
|
|
holder.subject.setText(getText(R.string.general_no_subject));
|
2011-02-06 17:09:48 -05:00
|
|
|
} else {
|
2010-11-26 23:03:06 -05:00
|
|
|
holder.subject.setText(message.message.getSubject());
|
2010-08-03 03:46:31 -04:00
|
|
|
}
|
|
|
|
|
2010-11-29 20:04:24 -05:00
|
|
|
int senderTypeface = message.read ? Typeface.NORMAL : Typeface.BOLD;
|
2011-02-06 17:09:48 -05:00
|
|
|
if (holder.preview != null) {
|
2010-08-03 03:46:31 -04:00
|
|
|
/*
|
|
|
|
* In the touchable UI, we have previews. Otherwise, we
|
|
|
|
* have just a "from" line.
|
|
|
|
* Because text views can't wrap around each other(?) we
|
|
|
|
* compose a custom view containing the preview and the
|
|
|
|
* from.
|
|
|
|
*/
|
2010-10-21 16:48:45 -04:00
|
|
|
|
2010-12-29 19:52:00 -05:00
|
|
|
holder.preview.setText(new SpannableStringBuilder(recipientSigil(message))
|
2011-01-06 11:55:08 -05:00
|
|
|
.append(message.sender).append(" ").append(message.message.getPreview()),
|
|
|
|
TextView.BufferType.SPANNABLE);
|
2010-08-03 03:46:31 -04:00
|
|
|
Spannable str = (Spannable)holder.preview.getText();
|
|
|
|
|
2010-12-29 19:52:00 -05:00
|
|
|
// Create a span section for the sender, and assign the correct font size and weight.
|
2011-04-16 05:13:54 -04:00
|
|
|
str.setSpan(new StyleSpan(senderTypeface),
|
|
|
|
0,
|
|
|
|
message.sender.length() + 1,
|
|
|
|
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
|
2011-11-09 23:09:54 -05:00
|
|
|
str.setSpan(new AbsoluteSizeSpan(mFontSizes.getMessageListSender(), true),
|
2011-01-06 11:55:08 -05:00
|
|
|
0,
|
|
|
|
message.sender.length() + 1,
|
2011-04-16 05:13:54 -04:00
|
|
|
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
|
2011-04-26 10:49:25 -04:00
|
|
|
|
|
|
|
// set span for preview message.
|
|
|
|
str.setSpan(new ForegroundColorSpan(Color.rgb(128, 128, 128)), // How do I can specify the android.R.attr.textColorTertiary
|
|
|
|
message.sender.length() + 1,
|
|
|
|
str.length(),
|
|
|
|
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
|
2011-02-06 17:09:48 -05:00
|
|
|
} else {
|
|
|
|
holder.from.setText(new SpannableStringBuilder(recipientSigil(message)).append(message.sender));
|
2010-10-21 16:48:45 -04:00
|
|
|
|
2010-11-29 20:04:24 -05:00
|
|
|
holder.from.setTypeface(null, senderTypeface);
|
2010-08-03 03:46:31 -04:00
|
|
|
}
|
|
|
|
|
2010-10-13 06:53:08 -04:00
|
|
|
holder.date.setText(message.getDate(mMessageHelper));
|
2010-08-03 03:46:31 -04:00
|
|
|
holder.subject.setCompoundDrawablesWithIntrinsicBounds(
|
|
|
|
message.answered ? mAnsweredIcon : null, // left
|
|
|
|
null, // top
|
2010-11-26 23:02:56 -05:00
|
|
|
message.message.hasAttachments() ? mAttachmentIcon : null, // right
|
2010-08-03 03:46:31 -04:00
|
|
|
null); // bottom
|
|
|
|
holder.position = position;
|
|
|
|
}
|
|
|
|
|
2011-02-06 17:09:48 -05:00
|
|
|
private String recipientSigil(MessageInfoHolder message) {
|
|
|
|
if (message.message.toMe()) {
|
2010-10-24 23:21:08 -04:00
|
|
|
return getString(R.string.messagelist_sent_to_me_sigil);
|
2011-02-06 17:09:48 -05:00
|
|
|
} else if (message.message.ccMe()) {
|
2010-10-24 23:21:08 -04:00
|
|
|
return getString(R.string.messagelist_sent_cc_me_sigil);
|
2011-02-06 17:09:48 -05:00
|
|
|
} else {
|
2010-10-24 23:21:08 -04:00
|
|
|
return "";
|
2010-10-21 16:48:45 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-07-13 17:49:28 -04:00
|
|
|
|
|
|
|
|
|
|
|
@Override
|
2011-02-06 17:09:48 -05:00
|
|
|
public boolean hasStableIds() {
|
2010-07-13 17:49:28 -04:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2011-02-06 17:09:48 -05:00
|
|
|
public boolean isItemSelectable(int position) {
|
|
|
|
if (position < mAdapter.messages.size()) {
|
2010-07-13 17:49:28 -04:00
|
|
|
return true;
|
2011-02-06 17:09:48 -05:00
|
|
|
} else {
|
2010-07-13 17:49:28 -04:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
class MessageViewHolder
|
2011-02-06 17:09:48 -05:00
|
|
|
implements OnCheckedChangeListener {
|
2010-07-13 17:49:28 -04:00
|
|
|
public TextView subject;
|
|
|
|
public TextView preview;
|
|
|
|
public TextView from;
|
|
|
|
public TextView time;
|
|
|
|
public TextView date;
|
|
|
|
public CheckBox flagged;
|
|
|
|
public View chip;
|
|
|
|
public CheckBox selected;
|
|
|
|
public int position = -1;
|
|
|
|
|
2010-08-03 01:46:35 -04:00
|
|
|
@Override
|
2011-02-06 17:09:48 -05:00
|
|
|
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
|
|
|
|
if (position != -1) {
|
2010-07-13 17:49:28 -04:00
|
|
|
MessageInfoHolder message = (MessageInfoHolder) mAdapter.getItem(position);
|
2011-02-06 17:09:48 -05:00
|
|
|
if (message.selected != isChecked) {
|
|
|
|
if (isChecked) {
|
2010-07-13 17:49:28 -04:00
|
|
|
mSelectedCount++;
|
2011-02-06 17:09:48 -05:00
|
|
|
} else if (mSelectedCount > 0) {
|
2010-07-13 17:49:28 -04:00
|
|
|
mSelectedCount--;
|
|
|
|
}
|
|
|
|
|
|
|
|
// We must set the flag before showing the buttons as the
|
|
|
|
// buttons text depends on what is selected.
|
|
|
|
message.selected = isChecked;
|
2011-02-06 17:09:48 -05:00
|
|
|
if (!mCheckboxes) {
|
|
|
|
if (isChecked) {
|
2010-07-13 17:49:28 -04:00
|
|
|
selected.setVisibility(View.VISIBLE);
|
2011-02-06 17:09:48 -05:00
|
|
|
} else {
|
2010-07-13 17:49:28 -04:00
|
|
|
selected.setVisibility(View.GONE);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
toggleBatchButtons();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-02-19 22:50:50 -05:00
|
|
|
|
|
|
|
private View getFooterView(ViewGroup parent) {
|
|
|
|
if (mFooterView == null) {
|
|
|
|
mFooterView = mInflater.inflate(R.layout.message_list_item_footer, parent, false);
|
|
|
|
mFooterView.setId(R.layout.message_list_item_footer);
|
|
|
|
FooterViewHolder holder = new FooterViewHolder();
|
|
|
|
holder.progress = (ProgressBar) mFooterView.findViewById(R.id.message_list_progress);
|
|
|
|
holder.progress.setIndeterminate(true);
|
|
|
|
holder.main = (TextView) mFooterView.findViewById(R.id.main_text);
|
|
|
|
mFooterView.setTag(holder);
|
|
|
|
}
|
|
|
|
|
|
|
|
return mFooterView;
|
|
|
|
}
|
|
|
|
|
|
|
|
private void updateFooterView() {
|
|
|
|
FooterViewHolder holder = (FooterViewHolder) mFooterView.getTag();
|
|
|
|
|
|
|
|
if (mCurrentFolder != null && mAccount != null) {
|
|
|
|
if (mCurrentFolder.loading) {
|
|
|
|
holder.main.setText(getString(R.string.status_loading_more));
|
|
|
|
holder.progress.setVisibility(ProgressBar.VISIBLE);
|
|
|
|
} else {
|
|
|
|
if (!mCurrentFolder.lastCheckFailed) {
|
|
|
|
if (mAccount.getDisplayCount() == 0) {
|
|
|
|
holder.main.setText(getString(R.string.message_list_load_more_messages_action));
|
|
|
|
} else {
|
|
|
|
holder.main.setText(String.format(getString(R.string.load_more_messages_fmt), mAccount.getDisplayCount()));
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
holder.main.setText(getString(R.string.status_loading_more_failed));
|
|
|
|
}
|
|
|
|
holder.progress.setVisibility(ProgressBar.INVISIBLE);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
holder.progress.setVisibility(ProgressBar.INVISIBLE);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-02-06 17:09:48 -05:00
|
|
|
private void hideBatchButtons() {
|
|
|
|
if (mBatchButtonArea.getVisibility() != View.GONE) {
|
2010-11-07 14:40:42 -05:00
|
|
|
mBatchButtonArea.setVisibility(View.GONE);
|
|
|
|
mBatchButtonArea.startAnimation(
|
|
|
|
AnimationUtils.loadAnimation(this, R.anim.footer_disappear));
|
|
|
|
}
|
2010-07-13 17:49:28 -04:00
|
|
|
}
|
|
|
|
|
2011-02-06 17:09:48 -05:00
|
|
|
private void showBatchButtons() {
|
|
|
|
if (mBatchButtonArea.getVisibility() != View.VISIBLE) {
|
2010-11-07 14:40:42 -05:00
|
|
|
mBatchButtonArea.setVisibility(View.VISIBLE);
|
|
|
|
Animation animation = AnimationUtils.loadAnimation(this, R.anim.footer_appear);
|
|
|
|
animation.setAnimationListener(this);
|
|
|
|
mBatchButtonArea.startAnimation(animation);
|
|
|
|
}
|
2010-07-13 17:49:28 -04:00
|
|
|
}
|
|
|
|
|
2011-02-06 17:09:48 -05:00
|
|
|
private void toggleBatchButtons() {
|
2010-07-13 17:49:28 -04:00
|
|
|
|
2011-02-06 17:09:48 -05:00
|
|
|
runOnUiThread(new Runnable() {
|
2010-11-28 15:28:37 -05:00
|
|
|
@Override
|
2011-02-06 17:09:48 -05:00
|
|
|
public void run() {
|
2010-11-28 15:28:37 -05:00
|
|
|
|
2011-02-06 17:09:48 -05:00
|
|
|
if (mSelectedCount < 0) {
|
2010-11-28 15:28:37 -05:00
|
|
|
mSelectedCount = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int readButtonIconId;
|
|
|
|
int flagButtonIconId;
|
|
|
|
|
2011-02-06 17:09:48 -05:00
|
|
|
if (mSelectedCount == 0) {
|
2010-11-28 15:28:37 -05:00
|
|
|
readButtonIconId = R.drawable.ic_button_mark_read;
|
|
|
|
flagButtonIconId = R.drawable.ic_button_flag;
|
|
|
|
hideBatchButtons();
|
2011-02-06 17:09:48 -05:00
|
|
|
} else {
|
2010-11-28 15:28:37 -05:00
|
|
|
boolean newReadState = computeBatchDirection(false);
|
2011-02-06 17:09:48 -05:00
|
|
|
if (newReadState) {
|
2010-11-28 15:28:37 -05:00
|
|
|
readButtonIconId = R.drawable.ic_button_mark_read;
|
2011-02-06 17:09:48 -05:00
|
|
|
} else {
|
2010-11-28 15:28:37 -05:00
|
|
|
readButtonIconId = R.drawable.ic_button_mark_unread;
|
|
|
|
}
|
|
|
|
boolean newFlagState = computeBatchDirection(true);
|
2011-02-06 17:09:48 -05:00
|
|
|
if (newFlagState) {
|
2010-11-28 15:28:37 -05:00
|
|
|
flagButtonIconId = R.drawable.ic_button_flag;
|
2011-02-06 17:09:48 -05:00
|
|
|
} else {
|
2010-11-28 15:28:37 -05:00
|
|
|
flagButtonIconId = R.drawable.ic_button_unflag;
|
|
|
|
}
|
|
|
|
showBatchButtons();
|
|
|
|
}
|
|
|
|
|
|
|
|
mBatchReadButton.setImageResource(readButtonIconId);
|
|
|
|
mBatchFlagButton.setImageResource(flagButtonIconId);
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
});
|
2010-07-13 17:49:28 -04:00
|
|
|
}
|
|
|
|
|
2011-02-06 17:09:48 -05:00
|
|
|
static class FooterViewHolder {
|
2010-07-13 17:49:28 -04:00
|
|
|
public ProgressBar progress;
|
|
|
|
public TextView main;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-02-06 17:09:48 -05:00
|
|
|
private boolean computeBatchDirection(boolean flagged) {
|
2010-07-13 17:49:28 -04:00
|
|
|
boolean newState = false;
|
|
|
|
|
2011-02-06 17:09:48 -05:00
|
|
|
synchronized (mAdapter.messages) {
|
|
|
|
for (MessageInfoHolder holder : mAdapter.messages) {
|
|
|
|
if (holder.selected) {
|
|
|
|
if (flagged) {
|
|
|
|
if (!holder.flagged) {
|
2010-07-13 17:49:28 -04:00
|
|
|
newState = true;
|
|
|
|
break;
|
|
|
|
}
|
2011-02-06 17:09:48 -05:00
|
|
|
} else {
|
|
|
|
if (!holder.read) {
|
2010-07-13 17:49:28 -04:00
|
|
|
newState = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return newState;
|
|
|
|
}
|
|
|
|
|
2011-02-06 17:09:48 -05:00
|
|
|
private boolean anySelected() {
|
|
|
|
synchronized (mAdapter.messages) {
|
|
|
|
for (MessageInfoHolder holder : mAdapter.messages) {
|
|
|
|
if (holder.selected) {
|
2010-07-13 17:49:28 -04:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2010-08-03 01:46:35 -04:00
|
|
|
@Override
|
2011-02-06 17:09:48 -05:00
|
|
|
public void onClick(View v) {
|
2010-07-13 17:49:28 -04:00
|
|
|
boolean newState = false;
|
|
|
|
List<Message> messageList = new ArrayList<Message>();
|
|
|
|
List<MessageInfoHolder> removeHolderList = new ArrayList<MessageInfoHolder>();
|
|
|
|
|
2011-02-06 17:09:48 -05:00
|
|
|
if (v == mBatchDoneButton) {
|
2010-07-13 17:49:28 -04:00
|
|
|
setAllSelected(false);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2011-02-06 17:09:48 -05:00
|
|
|
if (v == mBatchFlagButton) {
|
2010-07-13 17:49:28 -04:00
|
|
|
newState = computeBatchDirection(true);
|
2011-02-06 17:09:48 -05:00
|
|
|
} else {
|
2010-07-13 17:49:28 -04:00
|
|
|
newState = computeBatchDirection(false);
|
|
|
|
}
|
|
|
|
|
2011-12-24 13:17:12 -05:00
|
|
|
if (v == mBatchArchiveButton) {
|
|
|
|
final List<MessageInfoHolder> selection = getSelectionFromCheckboxes();
|
|
|
|
onArchive(selection);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (v == mBatchMoveButton) {
|
|
|
|
final List<MessageInfoHolder> selection = getSelectionFromCheckboxes();
|
|
|
|
onMove(selection);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2011-02-06 17:09:48 -05:00
|
|
|
synchronized (mAdapter.messages) {
|
|
|
|
for (MessageInfoHolder holder : mAdapter.messages) {
|
|
|
|
if (holder.selected) {
|
|
|
|
if (v == mBatchDeleteButton) {
|
2010-07-13 17:49:28 -04:00
|
|
|
removeHolderList.add(holder);
|
2011-02-06 17:09:48 -05:00
|
|
|
} else if (v == mBatchFlagButton) {
|
2010-07-13 17:49:28 -04:00
|
|
|
holder.flagged = newState;
|
2011-02-06 17:09:48 -05:00
|
|
|
} else if (v == mBatchReadButton) {
|
2010-07-13 17:49:28 -04:00
|
|
|
holder.read = newState;
|
|
|
|
}
|
|
|
|
messageList.add(holder.message);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
mAdapter.removeMessages(removeHolderList);
|
|
|
|
|
2011-02-06 17:09:48 -05:00
|
|
|
if (!messageList.isEmpty()) {
|
|
|
|
if (v == mBatchDeleteButton) {
|
2010-08-02 07:55:31 -04:00
|
|
|
mController.deleteMessages(messageList.toArray(EMPTY_MESSAGE_ARRAY), null);
|
2010-07-13 17:49:28 -04:00
|
|
|
mSelectedCount = 0;
|
|
|
|
toggleBatchButtons();
|
2011-02-06 17:09:48 -05:00
|
|
|
} else {
|
2010-08-02 07:55:31 -04:00
|
|
|
mController.setFlag(messageList.toArray(EMPTY_MESSAGE_ARRAY), (v == mBatchReadButton ? Flag.SEEN : Flag.FLAGGED), newState);
|
2010-07-13 17:49:28 -04:00
|
|
|
}
|
2011-02-06 17:09:48 -05:00
|
|
|
} else {
|
2010-07-13 17:49:28 -04:00
|
|
|
// Should not happen
|
|
|
|
Toast.makeText(this, R.string.no_message_seletected_toast, Toast.LENGTH_SHORT).show();
|
|
|
|
}
|
|
|
|
mHandler.sortMessages();
|
|
|
|
}
|
|
|
|
|
2011-06-04 17:55:48 -04:00
|
|
|
@Override
|
2011-02-06 17:09:48 -05:00
|
|
|
public void onAnimationEnd(Animation animation) {
|
2010-11-07 14:40:42 -05:00
|
|
|
}
|
|
|
|
|
2011-06-04 17:55:48 -04:00
|
|
|
@Override
|
2011-02-06 17:09:48 -05:00
|
|
|
public void onAnimationRepeat(Animation animation) {
|
2010-11-07 14:40:42 -05:00
|
|
|
}
|
|
|
|
|
2011-06-04 17:55:48 -04:00
|
|
|
@Override
|
2011-02-06 17:09:48 -05:00
|
|
|
public void onAnimationStart(Animation animation) {
|
2010-11-07 14:40:42 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2011-02-06 17:09:48 -05:00
|
|
|
private void setAllSelected(boolean isSelected) {
|
2010-07-13 17:49:28 -04:00
|
|
|
mSelectedCount = 0;
|
2011-02-06 17:09:48 -05:00
|
|
|
synchronized (mAdapter.messages) {
|
|
|
|
for (MessageInfoHolder holder : mAdapter.messages) {
|
2010-07-13 17:49:28 -04:00
|
|
|
holder.selected = isSelected;
|
|
|
|
mSelectedCount += (isSelected ? 1 : 0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
mAdapter.notifyDataSetChanged();
|
|
|
|
toggleBatchButtons();
|
|
|
|
}
|
|
|
|
|
2011-06-04 16:57:03 -04:00
|
|
|
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);
|
|
|
|
}
|
2010-07-13 17:49:28 -04:00
|
|
|
}
|
|
|
|
mAdapter.notifyDataSetChanged();
|
|
|
|
toggleBatchButtons();
|
|
|
|
}
|
|
|
|
|
2011-06-04 16:57:03 -04:00
|
|
|
/**
|
|
|
|
* @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;
|
2010-07-13 17:49:28 -04:00
|
|
|
}
|
|
|
|
}
|
2011-06-04 16:57:03 -04:00
|
|
|
mController.setFlag(messageList, flag, newState);
|
2010-07-13 17:49:28 -04:00
|
|
|
mHandler.sortMessages();
|
|
|
|
}
|
|
|
|
|
2011-06-04 16:57:03 -04:00
|
|
|
/**
|
|
|
|
* Display the message move activity.
|
2011-06-13 19:49:06 -04:00
|
|
|
*
|
2011-06-04 16:57:03 -04:00
|
|
|
* @param holders
|
|
|
|
* Never {@code null}.
|
|
|
|
*/
|
|
|
|
private void onMove(final List<MessageInfoHolder> holders) {
|
|
|
|
if (!checkCopyOrMovePossible(holders, FolderOperation.MOVE)) {
|
|
|
|
return;
|
2010-07-13 17:49:28 -04:00
|
|
|
}
|
|
|
|
|
2011-06-04 16:57:03 -04:00
|
|
|
final Folder folder = holders.size() == 1 ? holders.get(0).message.getFolder() : mCurrentFolder.folder;
|
|
|
|
displayFolderChoice(ACTIVITY_CHOOSE_FOLDER_MOVE, folder, holders);
|
2010-07-13 17:49:28 -04:00
|
|
|
}
|
|
|
|
|
2011-06-04 16:57:03 -04:00
|
|
|
/**
|
|
|
|
* Display the message copy activity.
|
2011-06-13 19:49:06 -04:00
|
|
|
*
|
2011-06-04 16:57:03 -04:00
|
|
|
* @param holders
|
|
|
|
* Never {@code null}.
|
|
|
|
*/
|
|
|
|
private void onCopy(final List<MessageInfoHolder> holders) {
|
|
|
|
if (!checkCopyOrMovePossible(holders, FolderOperation.COPY)) {
|
2010-07-13 17:49:28 -04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2011-06-04 16:57:03 -04:00
|
|
|
final Folder folder = holders.size() == 1 ? holders.get(0).message.getFolder() : mCurrentFolder.folder;
|
|
|
|
displayFolderChoice(ACTIVITY_CHOOSE_FOLDER_COPY, folder, holders);
|
|
|
|
}
|
2010-07-13 17:49:28 -04:00
|
|
|
|
2011-06-04 16:57:03 -04:00
|
|
|
/**
|
|
|
|
* 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) {
|
2010-07-13 17:49:28 -04:00
|
|
|
final Intent intent = new Intent(this, ChooseFolder.class);
|
2011-06-04 16:57:03 -04:00
|
|
|
intent.putExtra(ChooseFolder.EXTRA_ACCOUNT, folder.getAccount().getUuid());
|
2010-07-13 17:49:28 -04:00
|
|
|
intent.putExtra(ChooseFolder.EXTRA_CUR_FOLDER, folder.getName());
|
|
|
|
intent.putExtra(ChooseFolder.EXTRA_SEL_FOLDER, folder.getAccount().getLastSelectedFolderName());
|
2011-06-04 16:57:03 -04:00
|
|
|
// remember the selected messages for #onActivityResult
|
|
|
|
mActiveMessages = holders;
|
|
|
|
startActivityForResult(intent, requestCode);
|
2010-07-13 17:49:28 -04:00
|
|
|
}
|
|
|
|
|
2011-06-04 16:57:03 -04:00
|
|
|
/**
|
|
|
|
* @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)) {
|
2010-07-13 17:49:28 -04:00
|
|
|
return;
|
|
|
|
}
|
2011-06-04 16:57:03 -04:00
|
|
|
// TODO one should separate messages by account and call move afterwards
|
|
|
|
// (because each account might have a specific Archive folder name)
|
|
|
|
move(holders, folderName);
|
|
|
|
}
|
2010-07-13 17:49:28 -04:00
|
|
|
|
2011-06-04 16:57:03 -04:00
|
|
|
/**
|
|
|
|
* @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);
|
2010-07-13 17:49:28 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-06-04 16:57:03 -04:00
|
|
|
/**
|
|
|
|
* @param holders
|
|
|
|
* Never {@code null}.
|
|
|
|
*/
|
|
|
|
private void onSpamConfirmed(final List<MessageInfoHolder> holders) {
|
|
|
|
final String folderName = holders.get(0).message.getFolder().getAccount().getSpamFolderName();
|
2011-02-06 17:09:48 -05:00
|
|
|
if (K9.FOLDER_NONE.equalsIgnoreCase(folderName)) {
|
2010-07-13 17:49:28 -04:00
|
|
|
return;
|
|
|
|
}
|
2011-06-04 16:57:03 -04:00
|
|
|
// TODO one should separate messages by account and call move afterwards
|
|
|
|
// (because each account might have a specific Spam folder name)
|
|
|
|
move(holders, folderName);
|
2010-07-13 17:49:28 -04:00
|
|
|
}
|
|
|
|
|
2011-06-04 16:57:03 -04:00
|
|
|
private static enum FolderOperation {
|
|
|
|
COPY, MOVE
|
2010-07-13 17:49:28 -04:00
|
|
|
}
|
|
|
|
|
2011-06-04 16:57:03 -04:00
|
|
|
/**
|
|
|
|
* Display an Toast message if any message isn't synchronized
|
2011-06-13 19:49:06 -04:00
|
|
|
*
|
2011-06-04 16:57:03 -04:00
|
|
|
* @param holders
|
|
|
|
* Never <code>null</code>.
|
2011-06-04 17:17:47 -04:00
|
|
|
* @param operation
|
|
|
|
* Never {@code null}.
|
2011-06-13 19:49:06 -04:00
|
|
|
*
|
2011-06-04 16:57:03 -04:00
|
|
|
* @return <code>true</code> if operation is possible
|
|
|
|
*/
|
|
|
|
private boolean checkCopyOrMovePossible(final List<MessageInfoHolder> holders, final FolderOperation operation) {
|
|
|
|
if (holders.isEmpty()) {
|
|
|
|
return false;
|
2010-07-13 17:49:28 -04:00
|
|
|
}
|
2011-06-04 16:57:03 -04:00
|
|
|
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,
|
2011-06-13 19:49:06 -04:00
|
|
|
Toast.LENGTH_LONG);
|
2011-06-04 16:57:03 -04:00
|
|
|
toast.show();
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
2010-07-13 17:49:28 -04:00
|
|
|
|
2011-06-04 16:57:03 -04:00
|
|
|
/**
|
|
|
|
* Helper method to get a List of message ready to be processed. This implementation will return a list containing the sole argument.
|
2011-06-13 19:49:06 -04:00
|
|
|
*
|
2011-06-04 16:57:03 -04:00
|
|
|
* @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;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Helper method to get a List of message ready to be processed. This implementation will iterate over messages and choose the checked ones.
|
2011-06-13 19:49:06 -04:00
|
|
|
*
|
2011-06-04 16:57:03 -04:00
|
|
|
* @return Never {@code null}.
|
|
|
|
*/
|
|
|
|
private List<MessageInfoHolder> getSelectionFromCheckboxes() {
|
|
|
|
final List<MessageInfoHolder> selection = new ArrayList<MessageInfoHolder>();
|
2011-02-06 17:09:48 -05:00
|
|
|
synchronized (mAdapter.messages) {
|
2011-06-04 16:57:03 -04:00
|
|
|
for (final MessageInfoHolder holder : mAdapter.messages) {
|
2011-02-06 17:09:48 -05:00
|
|
|
if (holder.selected) {
|
2011-06-04 16:57:03 -04:00
|
|
|
selection.add(holder);
|
2010-07-13 17:49:28 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2011-06-04 16:57:03 -04:00
|
|
|
return selection;
|
|
|
|
}
|
2010-07-13 17:49:28 -04:00
|
|
|
|
2011-06-04 16:57:03 -04:00
|
|
|
/**
|
|
|
|
* 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);
|
2010-07-13 17:49:28 -04:00
|
|
|
}
|
|
|
|
|
2011-06-04 16:57:03 -04:00
|
|
|
/**
|
|
|
|
* 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.
|
2011-06-13 19:49:06 -04:00
|
|
|
*
|
2011-06-04 16:57:03 -04:00
|
|
|
* @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)) {
|
2010-07-13 17:49:28 -04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2011-06-04 16:57:03 -04:00
|
|
|
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;
|
2010-07-13 17:49:28 -04:00
|
|
|
}
|
2011-06-04 16:57:03 -04:00
|
|
|
} else if (!account.equals(message.getFolder().getAccount())
|
2011-06-13 19:49:06 -04:00
|
|
|
|| !folderName.equals(message.getFolder().getName())) {
|
2011-06-04 16:57:03 -04:00
|
|
|
// make sure all messages come from the same account/folder?
|
|
|
|
return;
|
2010-07-13 17:49:28 -04:00
|
|
|
}
|
2011-06-04 16:57:03 -04:00
|
|
|
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,
|
2011-06-13 19:49:06 -04:00
|
|
|
Toast.LENGTH_LONG);
|
2011-06-04 16:57:03 -04:00
|
|
|
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,
|
2011-06-13 19:49:06 -04:00
|
|
|
null);
|
2011-06-04 16:57:03 -04:00
|
|
|
mHandler.removeMessages(holders);
|
|
|
|
} else {
|
|
|
|
mController.copyMessages(account, folderName, messages.toArray(new Message[messages.size()]), destination,
|
2011-06-13 19:49:06 -04:00
|
|
|
null);
|
2010-07-13 17:49:28 -04:00
|
|
|
}
|
|
|
|
}
|
2010-11-13 16:40:56 -05:00
|
|
|
|
2011-02-06 17:09:48 -05:00
|
|
|
protected void onAccountUnavailable() {
|
2010-11-13 16:40:56 -05:00
|
|
|
finish();
|
|
|
|
// TODO inform user about account unavailability using Toast
|
2010-11-18 04:08:40 -05:00
|
|
|
Accounts.listAccounts(this);
|
2010-11-13 16:40:56 -05:00
|
|
|
}
|
|
|
|
|
2012-05-15 02:09:28 -04:00
|
|
|
/**
|
|
|
|
* Return the currently "open" account if available.
|
|
|
|
*
|
|
|
|
* @param prefs
|
|
|
|
* A {@link Preferences} instance that might be used to retrieve the current
|
|
|
|
* {@link Account}.
|
|
|
|
*
|
|
|
|
* @return The {@code Account} all displayed messages belong to.
|
|
|
|
*/
|
|
|
|
private Account getCurrentAccount(Preferences prefs) {
|
|
|
|
Account account = null;
|
|
|
|
if (mQueryString != null && !mIntegrate && mAccountUuids != null &&
|
|
|
|
mAccountUuids.length == 1) {
|
|
|
|
String uuid = mAccountUuids[0];
|
|
|
|
account = prefs.getAccount(uuid);
|
|
|
|
} else if (mAccount != null) {
|
|
|
|
account = mAccount;
|
|
|
|
}
|
|
|
|
|
|
|
|
return account;
|
|
|
|
}
|
2010-07-13 17:49:28 -04:00
|
|
|
}
|