mirror of
https://github.com/moparisthebest/k-9
synced 2025-01-12 06:08:25 -05:00
Restore behavior of unread/flagged filtered message list
The unread/flagged count/view for accounts now excludes special folders and only includes displayable folders as specified by the display class.
This commit is contained in:
parent
73757af680
commit
251428e963
@ -27,11 +27,18 @@ import com.fsck.k9.helper.Utility;
|
||||
import com.fsck.k9.mail.Address;
|
||||
import com.fsck.k9.mail.MessagingException;
|
||||
import com.fsck.k9.mail.Store;
|
||||
import com.fsck.k9.mail.Folder.FolderClass;
|
||||
import com.fsck.k9.mail.store.LocalStore;
|
||||
import com.fsck.k9.mail.store.StorageManager;
|
||||
import com.fsck.k9.mail.store.StorageManager.StorageProvider;
|
||||
import com.fsck.k9.provider.EmailProvider;
|
||||
import com.fsck.k9.provider.EmailProvider.StatsColumns;
|
||||
import com.fsck.k9.search.ConditionsTreeNode;
|
||||
import com.fsck.k9.search.LocalSearch;
|
||||
import com.fsck.k9.search.SqlQueryBuilder;
|
||||
import com.fsck.k9.search.SearchSpecification.Attribute;
|
||||
import com.fsck.k9.search.SearchSpecification.SearchCondition;
|
||||
import com.fsck.k9.search.SearchSpecification.Searchfield;
|
||||
import com.fsck.k9.view.ColorChip;
|
||||
|
||||
import java.util.HashMap;
|
||||
@ -783,10 +790,22 @@ public class Account implements BaseAccount {
|
||||
StatsColumns.FLAGGED_COUNT
|
||||
};
|
||||
|
||||
//TODO: Only count messages in folders that are displayed, exclude special folders like
|
||||
// Trash, Spam, Outbox, Drafts, Sent.
|
||||
// Create LocalSearch instance to exclude special folders (Trash, Drafts, Spam, Outbox,
|
||||
// Sent) and limit the search to displayable folders.
|
||||
LocalSearch search = new LocalSearch();
|
||||
excludeSpecialFolders(search);
|
||||
limitToDisplayableFolders(search);
|
||||
|
||||
Cursor cursor = cr.query(uri, projection, null, null, null);
|
||||
// Use the LocalSearch instance to create a WHERE clause to query the content provider
|
||||
StringBuilder query = new StringBuilder();
|
||||
List<String> queryArgs = new ArrayList<String>();
|
||||
ConditionsTreeNode conditions = search.getConditions();
|
||||
SqlQueryBuilder.buildWhereClause(this, conditions, query, queryArgs);
|
||||
|
||||
String selection = query.toString();
|
||||
String[] selectionArgs = queryArgs.toArray(new String[0]);
|
||||
|
||||
Cursor cursor = cr.query(uri, projection, selection, selectionArgs, null);
|
||||
try {
|
||||
if (cursor.moveToFirst()) {
|
||||
stats.unreadMessageCount = cursor.getInt(0);
|
||||
@ -1763,5 +1782,83 @@ public class Account implements BaseAccount {
|
||||
mRemoteSearchFullText = val;
|
||||
}
|
||||
|
||||
/**
|
||||
* Modify the supplied {@link LocalSearch} instance to limit the search to displayable folders.
|
||||
*
|
||||
* <p>
|
||||
* This method uses the current folder display mode to decide what folders to include/exclude.
|
||||
* </p>
|
||||
*
|
||||
* @param search
|
||||
* The {@code LocalSearch} instance to modify.
|
||||
*
|
||||
* @see #getFolderDisplayMode()
|
||||
*/
|
||||
public void limitToDisplayableFolders(LocalSearch search) {
|
||||
final Account.FolderMode displayMode = getFolderDisplayMode();
|
||||
|
||||
switch (displayMode) {
|
||||
case FIRST_CLASS: {
|
||||
// Count messages in the INBOX and non-special first class folders
|
||||
search.and(Searchfield.DISPLAY_CLASS, FolderClass.FIRST_CLASS.name(),
|
||||
Attribute.EQUALS);
|
||||
break;
|
||||
}
|
||||
case FIRST_AND_SECOND_CLASS: {
|
||||
// Count messages in the INBOX and non-special first and second class folders
|
||||
search.and(Searchfield.DISPLAY_CLASS, FolderClass.FIRST_CLASS.name(),
|
||||
Attribute.EQUALS);
|
||||
|
||||
// TODO: Create a proper interface for creating arbitrary condition trees
|
||||
SearchCondition searchCondition = new SearchCondition(Searchfield.DISPLAY_CLASS,
|
||||
Attribute.EQUALS, FolderClass.SECOND_CLASS.name());
|
||||
ConditionsTreeNode root = search.getConditions();
|
||||
if (root.mRight != null) {
|
||||
root.mRight.or(searchCondition);
|
||||
} else {
|
||||
search.or(searchCondition);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case NOT_SECOND_CLASS: {
|
||||
// Count messages in the INBOX and non-special non-second-class folders
|
||||
search.and(Searchfield.DISPLAY_CLASS, FolderClass.SECOND_CLASS.name(),
|
||||
Attribute.NOT_EQUALS);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
case ALL: {
|
||||
// Count messages in the INBOX and non-special folders
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Modify the supplied {@link LocalSearch} instance to exclude special folders.
|
||||
*
|
||||
* <p>
|
||||
* Currently the following folders are excluded:
|
||||
* <ul>
|
||||
* <li>Trash</li>
|
||||
* <li>Drafts</li>
|
||||
* <li>Spam</li>
|
||||
* <li>Outbox</li>
|
||||
* <li>Sent</li>
|
||||
* </ul>
|
||||
* The Inbox will always be included even if one of the special folders is configured to point
|
||||
* to the Inbox.
|
||||
* </p>
|
||||
*
|
||||
* @param search
|
||||
* The {@code LocalSearch} instance to modify.
|
||||
*/
|
||||
public void excludeSpecialFolders(LocalSearch search) {
|
||||
search.and(Searchfield.FOLDER, getTrashFolderName(), Attribute.NOT_EQUALS);
|
||||
search.and(Searchfield.FOLDER, getDraftsFolderName(), Attribute.NOT_EQUALS);
|
||||
search.and(Searchfield.FOLDER, getSpamFolderName(), Attribute.NOT_EQUALS);
|
||||
search.and(Searchfield.FOLDER, getOutboxFolderName(), Attribute.NOT_EQUALS);
|
||||
search.and(Searchfield.FOLDER, getSentFolderName(), Attribute.NOT_EQUALS);
|
||||
search.or(new SearchCondition(Searchfield.FOLDER, Attribute.EQUALS, getInboxFolderName()));
|
||||
}
|
||||
}
|
||||
|
@ -68,7 +68,6 @@ import com.fsck.k9.activity.setup.AccountSetupBasics;
|
||||
import com.fsck.k9.activity.setup.Prefs;
|
||||
import com.fsck.k9.activity.setup.WelcomeMessage;
|
||||
import com.fsck.k9.controller.MessagingController;
|
||||
import com.fsck.k9.controller.MessagingListener;
|
||||
import com.fsck.k9.helper.SizeFormatter;
|
||||
import com.fsck.k9.mail.Flag;
|
||||
import com.fsck.k9.mail.ServerSettings;
|
||||
@ -1759,6 +1758,10 @@ public class Accounts extends K9ListActivity implements OnItemClickListener {
|
||||
} else {
|
||||
search = new LocalSearch(searchTitle);
|
||||
search.addAccountUuid(account.getUuid());
|
||||
|
||||
Account realAccount = (Account) account;
|
||||
realAccount.excludeSpecialFolders(search);
|
||||
realAccount.limitToDisplayableFolders(search);
|
||||
}
|
||||
|
||||
search.and(Searchfield.FLAGGED, "1", Attribute.EQUALS);
|
||||
@ -1777,6 +1780,10 @@ public class Accounts extends K9ListActivity implements OnItemClickListener {
|
||||
} else {
|
||||
search = new LocalSearch(searchTitle);
|
||||
search.addAccountUuid(account.getUuid());
|
||||
|
||||
Account realAccount = (Account) account;
|
||||
realAccount.excludeSpecialFolders(search);
|
||||
realAccount.limitToDisplayableFolders(search);
|
||||
}
|
||||
|
||||
search.and(Searchfield.READ, "1", Attribute.NOT_EQUALS);
|
||||
|
@ -3452,9 +3452,7 @@ public class MessagingController implements Runnable {
|
||||
ConditionsTreeNode conditions = search.getConditions();
|
||||
SqlQueryBuilder.buildWhereClause(account, conditions, query, queryArgs);
|
||||
|
||||
// Make sure we don't use the empty string as selection
|
||||
String selection = (query.length() == 0) ? null : query.toString();
|
||||
|
||||
String selection = query.toString();
|
||||
String[] selectionArgs = queryArgs.toArray(EMPTY_STRING_ARRAY);
|
||||
|
||||
Uri uri = Uri.withAppendedPath(EmailProvider.CONTENT_URI,
|
||||
|
@ -6,4 +6,17 @@ public final class StringUtils {
|
||||
return string == null || string.length() == 0;
|
||||
}
|
||||
|
||||
public static boolean containsAny(String haystack, String[] needles) {
|
||||
if (haystack == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (String needle : needles) {
|
||||
if (haystack.contains(needle)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -75,6 +75,15 @@ public class Utility {
|
||||
return false;
|
||||
}
|
||||
|
||||
public static boolean arrayContainsAny(Object[] a, Object... o) {
|
||||
for (Object element : a) {
|
||||
if (arrayContains(o, element)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Combines the given array of Objects into a single String using
|
||||
* each Object's toString() method and the separator character
|
||||
|
@ -91,6 +91,27 @@ public class EmailProvider extends ContentProvider {
|
||||
InternalMessageColumns.MIME_TYPE
|
||||
};
|
||||
|
||||
private static final String[] FIXUP_MESSAGES_COLUMNS = {
|
||||
MessageColumns.ID
|
||||
};
|
||||
|
||||
private static final String[] FOLDERS_COLUMNS = {
|
||||
FolderColumns.ID,
|
||||
FolderColumns.NAME,
|
||||
FolderColumns.LAST_UPDATED,
|
||||
FolderColumns.UNREAD_COUNT,
|
||||
FolderColumns.VISIBLE_LIMIT,
|
||||
FolderColumns.STATUS,
|
||||
FolderColumns.PUSH_STATE,
|
||||
FolderColumns.LAST_PUSHED,
|
||||
FolderColumns.FLAGGED_COUNT,
|
||||
FolderColumns.INTEGRATE,
|
||||
FolderColumns.TOP_GROUP,
|
||||
FolderColumns.POLL_CLASS,
|
||||
FolderColumns.PUSH_CLASS,
|
||||
FolderColumns.DISPLAY_CLASS
|
||||
};
|
||||
|
||||
static {
|
||||
UriMatcher matcher = sUriMatcher;
|
||||
|
||||
@ -141,6 +162,23 @@ public class EmailProvider extends ContentProvider {
|
||||
public static final String MIME_TYPE = "mime_type";
|
||||
}
|
||||
|
||||
public interface FolderColumns {
|
||||
public static final String ID = "id";
|
||||
public static final String NAME = "name";
|
||||
public static final String LAST_UPDATED = "last_updated";
|
||||
public static final String UNREAD_COUNT = "unread_count";
|
||||
public static final String VISIBLE_LIMIT = "visible_limit";
|
||||
public static final String STATUS = "status";
|
||||
public static final String PUSH_STATE = "push_state";
|
||||
public static final String LAST_PUSHED = "last_pushed";
|
||||
public static final String FLAGGED_COUNT = "flagged_count";
|
||||
public static final String INTEGRATE = "integrate";
|
||||
public static final String TOP_GROUP = "top_group";
|
||||
public static final String POLL_CLASS = "poll_class";
|
||||
public static final String PUSH_CLASS = "push_class";
|
||||
public static final String DISPLAY_CLASS = "display_class";
|
||||
}
|
||||
|
||||
public interface StatsColumns {
|
||||
public static final String UNREAD_COUNT = "unread_count";
|
||||
public static final String FLAGGED_COUNT = "flagged_count";
|
||||
@ -151,6 +189,7 @@ public class EmailProvider extends ContentProvider {
|
||||
StatsColumns.FLAGGED_COUNT
|
||||
};
|
||||
|
||||
|
||||
private Preferences mPreferences;
|
||||
|
||||
|
||||
@ -267,8 +306,7 @@ public class EmailProvider extends ContentProvider {
|
||||
}
|
||||
|
||||
final Cursor cursor;
|
||||
//TODO: check projection and selection for folder columns
|
||||
if (Utility.arrayContains(projection, SpecialColumns.FOLDER_NAME)) {
|
||||
if (Utility.arrayContainsAny(projection, (Object[]) FOLDERS_COLUMNS)) {
|
||||
StringBuilder query = new StringBuilder();
|
||||
query.append("SELECT ");
|
||||
boolean first = true;
|
||||
@ -292,10 +330,10 @@ public class EmailProvider extends ContentProvider {
|
||||
query.append(" FROM messages m " +
|
||||
"LEFT JOIN folders f ON (m.folder_id = f.id) " +
|
||||
"WHERE ");
|
||||
query.append(SqlQueryBuilder.addPrefixToSelection(MESSAGES_COLUMNS,
|
||||
query.append(SqlQueryBuilder.addPrefixToSelection(FIXUP_MESSAGES_COLUMNS,
|
||||
"m.", where));
|
||||
query.append(" ORDER BY ");
|
||||
query.append(SqlQueryBuilder.addPrefixToSelection(MESSAGES_COLUMNS,
|
||||
query.append(SqlQueryBuilder.addPrefixToSelection(FIXUP_MESSAGES_COLUMNS,
|
||||
"m.", sortOrder));
|
||||
|
||||
cursor = db.rawQuery(query.toString(), selectionArgs);
|
||||
@ -356,8 +394,7 @@ public class EmailProvider extends ContentProvider {
|
||||
" FROM messages h JOIN messages m " +
|
||||
"ON (h.id = m.thread_root OR h.id = m.id) ");
|
||||
|
||||
//TODO: check projection and selection for folder columns
|
||||
if (Utility.arrayContains(projection, SpecialColumns.FOLDER_NAME)) {
|
||||
if (Utility.arrayContainsAny(projection, (Object[]) FOLDERS_COLUMNS)) {
|
||||
query.append("LEFT JOIN folders f ON (m.folder_id = f.id) ");
|
||||
}
|
||||
|
||||
@ -424,13 +461,14 @@ public class EmailProvider extends ContentProvider {
|
||||
|
||||
// Table selection
|
||||
sql.append(" FROM messages");
|
||||
if (selection != null && selection.contains(SpecialColumns.INTEGRATE)) {
|
||||
|
||||
if (StringUtils.containsAny(selection, FOLDERS_COLUMNS)) {
|
||||
sql.append(" JOIN folders ON (folders.id = messages.folder_id)");
|
||||
}
|
||||
|
||||
// WHERE clause
|
||||
sql.append(" WHERE (deleted=0 AND (empty IS NULL OR empty!=1))");
|
||||
if (selection != null) {
|
||||
if (!StringUtils.isNullOrEmpty(selection)) {
|
||||
sql.append(" AND (");
|
||||
sql.append(selection);
|
||||
sql.append(")");
|
||||
|
@ -80,7 +80,8 @@ public interface SearchSpecification extends Parcelable {
|
||||
ID,
|
||||
INTEGRATE,
|
||||
READ,
|
||||
FLAGGED
|
||||
FLAGGED,
|
||||
DISPLAY_CLASS
|
||||
}
|
||||
|
||||
|
||||
|
@ -7,6 +7,7 @@ import com.fsck.k9.mail.MessagingException;
|
||||
import com.fsck.k9.mail.Folder.OpenMode;
|
||||
import com.fsck.k9.mail.store.LocalStore;
|
||||
import com.fsck.k9.mail.store.LocalStore.LocalFolder;
|
||||
import com.fsck.k9.search.SearchSpecification.Attribute;
|
||||
import com.fsck.k9.search.SearchSpecification.SearchCondition;
|
||||
import com.fsck.k9.search.SearchSpecification.Searchfield;
|
||||
|
||||
@ -29,7 +30,11 @@ public class SqlQueryBuilder {
|
||||
case FOLDER: {
|
||||
String folderName = condition.value;
|
||||
long folderId = getFolderId(account, folderName);
|
||||
query.append("folder_id = ?");
|
||||
if (condition.attribute == Attribute.EQUALS) {
|
||||
query.append("folder_id = ?");
|
||||
} else {
|
||||
query.append("folder_id != ?");
|
||||
}
|
||||
selectionArgs.add(Long.toString(folderId));
|
||||
break;
|
||||
}
|
||||
@ -144,6 +149,10 @@ public class SqlQueryBuilder {
|
||||
columnName = "flagged";
|
||||
break;
|
||||
}
|
||||
case DISPLAY_CLASS: {
|
||||
columnName = "display_class";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (columnName == null) {
|
||||
@ -220,7 +229,9 @@ public class SqlQueryBuilder {
|
||||
case FOLDER:
|
||||
case ID:
|
||||
case INTEGRATE:
|
||||
case THREAD_ROOT: {
|
||||
case THREAD_ROOT:
|
||||
case READ:
|
||||
case FLAGGED: {
|
||||
return true;
|
||||
}
|
||||
default: {
|
||||
|
Loading…
Reference in New Issue
Block a user