Fixes Issue 1410

Fixes Issue 1431

Present flagged message count inside a star, matching the visual
presentation on individual messages.

Provide display of unread and flagged message counts for canned
searches.

Perhaps the message counts for searches and account size display
should be defeatable for improved speed.
This commit is contained in:
Daniel Applebaum 2010-04-17 03:32:17 +00:00
parent 7cf0ec7327
commit 5bd24fe425
10 changed files with 309 additions and 148 deletions

View File

@ -5,8 +5,7 @@
android:layout_height="?android:attr/listPreferredItemHeight"
android:orientation="horizontal"
android:gravity="center_vertical"
android:paddingRight="4dip">
android:paddingRight="6dip">
<View
android:id="@+id/chip"
android:background="@drawable/appointment_indicator_leftside_1"
@ -37,17 +36,47 @@
android:layout_height="fill_parent"
android:layout_width="0dip"
android:layout_weight="1" />
<TextView
android:id="@+id/new_message_count"
android:ellipsize="end"
android:singleLine="true"
android:textAppearance="?android:attr/textAppearanceLarge"
android:textColor="?android:attr/textColorPrimary"
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/text_box"
android:paddingLeft="10dip"
android:paddingRight="10dip"
android:minWidth="64dip"
android:gravity="right" />
android:layout_height="fill_parent"
android:orientation="vertical"
android:paddingLeft="6dip"
android:paddingTop="6dip"
android:paddingBottom="0dip"
android:paddingRight="6dip"
android:gravity="right"
>
<TextView
android:id="@+id/new_message_count"
android:ellipsize="end"
android:singleLine="true"
android:textAppearance="?android:attr/textAppearanceMedium"
android:textColor="?android:attr/textColorPrimary"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/text_box"
android:paddingLeft="10dip"
android:paddingRight="10dip"
android:gravity="right"
android:layout_gravity="top"
android:layout_alignParentTop="true"
/>
<TextView
android:id="@+id/flagged_message_count"
android:ellipsize="end"
android:singleLine="true"
android:textAppearance="?android:attr/textAppearanceSmall"
android:textColor="#000000"
android:background="@drawable/btn_star_big_buttonless_on"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingRight="10dip"
android:paddingTop="6dip"
android:paddingLeft="10dip"
android:paddingBottom="4dip"
android:gravity="right"
android:layout_gravity="bottom"
android:layout_alignParentBottom="true"
/>
</RelativeLayout>
</LinearLayout>

View File

@ -6,8 +6,6 @@
android:orientation="horizontal"
android:gravity="center_vertical"
android:background="@android:color/transparent"
android:paddingRight="4dip">
<View
android:id="@+id/chip"
@ -41,17 +39,46 @@
android:ellipsize="end"
android:layout_height="wrap_content" />
</LinearLayout>
<TextView
android:id="@+id/folder_unread_message_count"
android:ellipsize="end"
android:singleLine="true"
android:textAppearance="?android:attr/textAppearanceLarge"
android:textColor="?android:attr/textColorPrimary"
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/text_box"
android:paddingLeft="10dip"
android:paddingRight="10dip"
android:minWidth="64dip"
android:gravity="right" />
android:layout_height="fill_parent"
android:orientation="vertical"
android:paddingLeft="6dip"
android:paddingTop="6dip"
android:paddingBottom="0dip"
android:paddingRight="6dip"
android:gravity="right"
>
<TextView
android:id="@+id/folder_unread_message_count"
android:ellipsize="end"
android:singleLine="true"
android:textAppearance="?android:attr/textAppearanceMedium"
android:textColor="?android:attr/textColorPrimary"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/text_box"
android:paddingLeft="10dip"
android:paddingRight="10dip"
android:gravity="right"
android:layout_gravity="top"
android:layout_alignParentTop="true"/>
<TextView
android:id="@+id/folder_flagged_message_count"
android:ellipsize="end"
android:singleLine="true"
android:textAppearance="?android:attr/textAppearanceSmall"
android:textColor="#000000"
android:background="@drawable/btn_star_big_buttonless_on"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingRight="10dip"
android:paddingTop="6dip"
android:paddingLeft="10dip"
android:paddingBottom="4dip"
android:gravity="right"
android:layout_gravity="bottom"
android:layout_alignParentBottom="true"
/>
</RelativeLayout>
</LinearLayout>

View File

@ -24,7 +24,7 @@ import java.util.concurrent.ConcurrentHashMap;
* Account stores all of the settings for a single account defined by the user. It is able to save
* and delete itself given a Preferences to work with. Each account is defined by a UUID.
*/
public class Account
public class Account implements BaseAccount
{
public static final String EXPUNGE_IMMEDIATELY = "EXPUNGE_IMMEDIATELY";
public static final String EXPUNGE_MANUALLY = "EXPUNGE_MANUALLY";

View File

@ -0,0 +1,10 @@
package com.fsck.k9;
public interface BaseAccount
{
public String getEmail();
public void setEmail(String email);
public String getDescription();
public void setDescription(String description);
public String getUuid();
}

View File

@ -696,22 +696,27 @@ public class MessagingController implements Runnable
}
}
public void searchLocalMessages(SearchAccount searchAccount, final Message[] messages, final MessagingListener listener)
{
searchLocalMessages(searchAccount, searchAccount.getQuery(), messages, searchAccount.isIntegrate(),
searchAccount.getRequiredFlags(), searchAccount.getForbiddenFlags(), listener);
}
/**
* Find all messages in any local account which match the query 'query'
*
* @param account
* @param account TODO
* @param query
* @param listener
* @param account
*
* @throws MessagingException
*/
public void searchLocalMessages(final String query, final Message[] messages, final boolean integrate, final Flag[] requiredFlags, final Flag[] forbiddenFlags,
final MessagingListener listener)
public void searchLocalMessages(final BaseAccount baseAccount, final String query, final Message[] messages, final boolean integrate, final Flag[] requiredFlags,
final Flag[] forbiddenFlags, final MessagingListener listener)
{
if (listener == null)
{
return;
}
final AccountStats stats = new AccountStats();
threadPool.execute(new Runnable()
{
public void run()
@ -733,8 +738,10 @@ public class MessagingController implements Runnable
break;
}
listener.listLocalMessagesStarted(account, null);
if (listener != null)
{
listener.listLocalMessagesStarted(account, null);
}
if (integrate || displayableOnly)
{
@ -784,10 +791,21 @@ public class MessagingController implements Runnable
}
messages.add(message);
listener.listLocalMessagesAddMessages(account, null, messages);
stats.unreadMessageCount += (message.isSet(Flag.SEEN) == false) ? 1 : 0;
stats.flaggedMessageCount += (message.isSet(Flag.FLAGGED)) ? 1 : 0;
if (listener != null)
{
listener.listLocalMessagesAddMessages(account, null, messages);
}
}
public void messagesFinished(int number) {}
public void messagesFinished(int number)
{
if (baseAccount != null)
{
listener.accountStatusChanged(baseAccount, stats);
}
}
};
try
@ -798,12 +816,18 @@ public class MessagingController implements Runnable
}
catch (Exception e)
{
listener.listLocalMessagesFailed(account, null, e.getMessage());
if (listener != null)
{
listener.listLocalMessagesFailed(account, null, e.getMessage());
}
addErrorMessage(account, null, e);
}
finally
{
listener.listLocalMessagesFinished(account, null);
if (listener != null)
{
listener.listLocalMessagesFinished(account, null);
}
}
}
}
@ -3376,7 +3400,7 @@ public class MessagingController implements Runnable
}
}
public void getAccountUnreadCount(final Context context, final Account account,
public void getAccountStats(final Context context, final Account account,
final MessagingListener l)
{
Runnable unreadRunnable = new Runnable()
@ -3397,10 +3421,9 @@ public class MessagingController implements Runnable
}
};
put("getAccountUnreadCount:" + account.getDescription(), l, unreadRunnable);
put("getAccountStats:" + account.getDescription(), l, unreadRunnable);
}
public void getFolderUnreadMessageCount(final Account account, final String folderName,
final MessagingListener l)
{

View File

@ -18,10 +18,10 @@ import java.util.List;
public class MessagingListener
{
public void accountStatusChanged(Account account, AccountStats stats)
public void accountStatusChanged(BaseAccount account, AccountStats stats)
{
}
public void accountSizeChanged(Account account, long oldSize, long newSize)
{
}

View File

@ -0,0 +1,89 @@
/**
*
*/
package com.fsck.k9;
import java.util.UUID;
import android.content.Context;
import com.fsck.k9.mail.Flag;
import com.fsck.k9.mail.Message;
public class SearchAccount implements BaseAccount
{
private Flag[] mRequiredFlags = null;
private Flag[] mForbiddenFlags = null;
private String email = null;
private String description = null;
private String query = "";
private boolean integrate = false;
private String mUuid = UUID.randomUUID().toString();
public SearchAccount(Context context, boolean nintegrate, Flag[] requiredFlags, Flag[] forbiddenFlags)
{
mRequiredFlags = requiredFlags;
mForbiddenFlags = forbiddenFlags;
integrate = nintegrate;
}
@Override
public synchronized String getEmail()
{
return email;
}
@Override
public synchronized void setEmail(String email)
{
this.email = email;
}
public Flag[] getRequiredFlags()
{
return mRequiredFlags;
}
public Flag[] getForbiddenFlags()
{
return mForbiddenFlags;
}
public boolean isIntegrate()
{
return integrate;
}
public String getDescription()
{
return description;
}
public void setDescription(String description)
{
this.description = description;
}
public String getQuery()
{
return query;
}
public void setQuery(String query)
{
this.query = query;
}
public String getUuid()
{
return mUuid;
}
public void setUuid(String nUuid)
{
mUuid = nUuid;
}
public void setIntegrate(boolean integrate)
{
this.integrate = integrate;
}
}

View File

@ -30,10 +30,9 @@ import java.util.concurrent.ConcurrentHashMap;
public class Accounts extends K9ListActivity implements OnItemClickListener, OnClickListener
{
private static final int DIALOG_REMOVE_ACCOUNT = 1;
//private ConcurrentHashMap<String, Integer> unreadMessageCounts = new ConcurrentHashMap<String, Integer>();
private ConcurrentHashMap<String, AccountStats> accountStats = new ConcurrentHashMap<String, AccountStats>();
private ConcurrentHashMap<Account, String> pendingWork = new ConcurrentHashMap<Account, String>();
private ConcurrentHashMap<BaseAccount, String> pendingWork = new ConcurrentHashMap<BaseAccount, String>();
private Account mSelectedContextAccount;
private int mUnreadMessageCount = 0;
@ -155,7 +154,7 @@ public class Accounts extends K9ListActivity implements OnItemClickListener, OnC
}
}
@Override
public void accountStatusChanged(Account account, AccountStats stats)
public void accountStatusChanged(BaseAccount account, AccountStats stats)
{
AccountStats oldStats = accountStats.get(account.getUuid());
int oldUnreadMessageCount = 0;
@ -164,8 +163,10 @@ public class Accounts extends K9ListActivity implements OnItemClickListener, OnC
oldUnreadMessageCount = oldStats.unreadMessageCount;
}
accountStats.put(account.getUuid(), stats);
// unreadMessageCounts.put(account.getUuid(), stats.unreadMessageCount);
mUnreadMessageCount += stats.unreadMessageCount - oldUnreadMessageCount;
if (account instanceof Account)
{
mUnreadMessageCount += stats.unreadMessageCount - oldUnreadMessageCount;
}
mHandler.dataChanged();
pendingWork.remove(account);
@ -195,7 +196,7 @@ public class Accounts extends K9ListActivity implements OnItemClickListener, OnC
int numNewMessages)
{
super.synchronizeMailboxFinished(account, folder, totalMessagesInMailbox, numNewMessages);
MessagingController.getInstance(getApplication()).getAccountUnreadCount(Accounts.this, account, mListener);
MessagingController.getInstance(getApplication()).getAccountStats(Accounts.this, account, mListener);
mHandler.progress(false);
@ -280,7 +281,6 @@ public class Accounts extends K9ListActivity implements OnItemClickListener, OnC
};
//private static String UNREAD_MESSAGE_COUNTS = "unreadMessageCounts";
private static String ACCOUNT_STATS = "accountStats";
private static String SELECTED_CONTEXT_ACCOUNT = "selectedContextAccount";
@ -390,9 +390,9 @@ public class Accounts extends K9ListActivity implements OnItemClickListener, OnC
private void refresh()
{
Account[] accounts = Preferences.getPreferences(this).getAccounts();
BaseAccount[] accounts = Preferences.getPreferences(this).getAccounts();
Account[] newAccounts = new Account[accounts.length + 4];
BaseAccount[] newAccounts = new BaseAccount[accounts.length + 4];
newAccounts[0] = integratedInboxAccount;
newAccounts[1] = integratedInboxStarredAccount;
newAccounts[2] = unreadAccount;
@ -401,19 +401,26 @@ public class Accounts extends K9ListActivity implements OnItemClickListener, OnC
mAdapter = new AccountsAdapter(newAccounts);
getListView().setAdapter(mAdapter);
if (accounts.length > 0)
if (newAccounts.length > 0)
{
mHandler.progress(Window.PROGRESS_START);
}
pendingWork.clear();
mUnreadMessageCount = 0;
accountStats.clear();
for (Account account : accounts)
for (BaseAccount account : newAccounts)
{
pendingWork.put(account, "true");
MessagingController.getInstance(getApplication()).getAccountUnreadCount(Accounts.this, account, mListener);
if (account instanceof Account)
{
Account realAccount = (Account)account;
MessagingController.getInstance(getApplication()).getAccountStats(Accounts.this, realAccount, mListener);
}
else if (account instanceof SearchAccount)
{
SearchAccount searchAccount = (SearchAccount)account;
MessagingController.getInstance(getApplication()).searchLocalMessages(searchAccount, null, mListener);
}
}
}
@ -468,20 +475,24 @@ public class Accounts extends K9ListActivity implements OnItemClickListener, OnC
}
}
private void onOpenAccount(Account account)
private void onOpenAccount(BaseAccount account)
{
if (account instanceof SearchAccount)
{
SearchAccount searchAccount = (SearchAccount)account;
MessageList.actionHandle(this, searchAccount.getDescription(), "", searchAccount.isIntegrate(), searchAccount.getRequiredFlags(), searchAccount.getForbiddenFlags());
}
else if (K9.FOLDER_NONE.equals(account.getAutoExpandFolderName()))
{
FolderList.actionHandleAccount(this, account);
}
else
{
MessageList.actionHandleFolder(this, account, account.getAutoExpandFolderName());
Account realAccount = (Account)account;
if (K9.FOLDER_NONE.equals(realAccount.getAutoExpandFolderName()))
{
FolderList.actionHandleAccount(this, realAccount);
}
else
{
MessageList.actionHandleFolder(this, realAccount, realAccount.getAutoExpandFolderName());
}
}
}
@ -617,7 +628,7 @@ public class Accounts extends K9ListActivity implements OnItemClickListener, OnC
public void onItemClick(AdapterView<?> parent, View view, int position, long id)
{
Account account = (Account)parent.getItemAtPosition(position);
BaseAccount account = (BaseAccount)parent.getItemAtPosition(position);
onOpenAccount(account);
}
@ -719,7 +730,7 @@ public class Accounts extends K9ListActivity implements OnItemClickListener, OnC
getMenuInflater().inflate(R.menu.accounts_context, menu);
AdapterContextMenuInfo info = (AdapterContextMenuInfo) menuInfo;
Account account = (Account) mAdapter.getItem(info.position);
BaseAccount account = mAdapter.getItem(info.position);
if (account instanceof SearchAccount)
{
for (int i = 0; i < menu.size(); i++)
@ -733,9 +744,9 @@ public class Accounts extends K9ListActivity implements OnItemClickListener, OnC
}
}
class AccountsAdapter extends ArrayAdapter<Account>
class AccountsAdapter extends ArrayAdapter<BaseAccount>
{
public AccountsAdapter(Account[] accounts)
public AccountsAdapter(BaseAccount[] accounts)
{
super(Accounts.this, 0, accounts);
}
@ -743,7 +754,7 @@ public class Accounts extends K9ListActivity implements OnItemClickListener, OnC
@Override
public View getView(int position, View convertView, ViewGroup parent)
{
Account account = getItem(position);
BaseAccount account = getItem(position);
View view;
if (convertView != null)
{
@ -760,6 +771,7 @@ public class Accounts extends K9ListActivity implements OnItemClickListener, OnC
holder.description = (TextView) view.findViewById(R.id.description);
holder.email = (TextView) view.findViewById(R.id.email);
holder.newMessageCount = (TextView) view.findViewById(R.id.new_message_count);
holder.flaggedMessageCount = (TextView) view.findViewById(R.id.flagged_message_count);
holder.chip = view.findViewById(R.id.chip);
@ -767,10 +779,9 @@ public class Accounts extends K9ListActivity implements OnItemClickListener, OnC
}
AccountStats stats = accountStats.get(account.getUuid());
if (stats != null)
if (stats != null && account instanceof Account)
{
holder.email.setText(SizeFormatter.formatSize(Accounts.this, stats.size)
+ (stats.flaggedMessageCount > 0 ? " / " + stats.flaggedMessageCount + "*" : ""));
holder.email.setText(SizeFormatter.formatSize(Accounts.this, stats.size));
}
else
{
@ -796,30 +807,37 @@ public class Accounts extends K9ListActivity implements OnItemClickListener, OnC
unreadMessageCount = stats.unreadMessageCount;
holder.newMessageCount.setText(Integer.toString(unreadMessageCount));
holder.newMessageCount.setVisibility(unreadMessageCount > 0 ? View.VISIBLE : View.GONE);
holder.flaggedMessageCount.setText(Integer.toString(stats.flaggedMessageCount));
holder.flaggedMessageCount.setVisibility(stats.flaggedMessageCount > 0 ? View.VISIBLE : View.GONE);
}
else
{
//holder.newMessageCount.setText("-");
holder.newMessageCount.setVisibility(View.GONE);
holder.flaggedMessageCount.setVisibility(View.GONE);
}
if (!(account instanceof SearchAccount))
if (account instanceof Account)
{
holder.chip.setBackgroundResource(K9.COLOR_CHIP_RES_IDS[account.getAccountNumber() % K9.COLOR_CHIP_RES_IDS.length]);
}
Account realAccount = (Account)account;
holder.chip.setBackgroundResource(K9.COLOR_CHIP_RES_IDS[realAccount.getAccountNumber() % K9.COLOR_CHIP_RES_IDS.length]);
if (unreadMessageCount == null)
{
holder.chip.getBackground().setAlpha(0);
}
else if (unreadMessageCount == 0)
{
holder.chip.getBackground().setAlpha(127);
}
else
{
holder.chip.getBackground().setAlpha(255);
}
if (unreadMessageCount == null)
}
else
{
holder.chip.getBackground().setAlpha(0);
}
else if (unreadMessageCount == 0)
{
holder.chip.getBackground().setAlpha(127);
}
else
{
holder.chip.getBackground().setAlpha(255);
}
return view;
}
@ -829,50 +847,8 @@ public class Accounts extends K9ListActivity implements OnItemClickListener, OnC
public TextView description;
public TextView email;
public TextView newMessageCount;
public TextView flaggedMessageCount;
public View chip;
}
}
private class SearchAccount extends Account
{
private Flag[] mRequiredFlags = null;
private Flag[] mForbiddenFlags = null;
private String email = null;
private boolean mIntegrate = false;
private SearchAccount(Context context, boolean integrate, Flag[] requiredFlags, Flag[] forbiddenFlags)
{
super(context);
mRequiredFlags = requiredFlags;
mForbiddenFlags = forbiddenFlags;
mIntegrate = integrate;
}
@Override
public synchronized String getEmail()
{
return email;
}
@Override
public synchronized void setEmail(String email)
{
this.email = email;
}
public Flag[] getRequiredFlags()
{
return mRequiredFlags;
}
public Flag[] getForbiddenFlags()
{
return mForbiddenFlags;
}
public boolean isIntegrate()
{
return mIntegrate;
}
}
}

View File

@ -343,7 +343,7 @@ public class FolderList extends K9ListActivity
MessagingController.getInstance(getApplication()).addListener(mAdapter.mListener);
//mAccount.refresh(Preferences.getPreferences(this));
MessagingController.getInstance(getApplication()).getAccountUnreadCount(this, mAccount, mAdapter.mListener);
MessagingController.getInstance(getApplication()).getAccountStats(this, mAccount, mAdapter.mListener);
onRefresh(!REFRESH_REMOTE);
@ -759,8 +759,12 @@ public class FolderList extends K9ListActivity
private ActivityListener mListener = new ActivityListener()
{
@Override
public void accountStatusChanged(Account account, AccountStats stats)
public void accountStatusChanged(BaseAccount account, AccountStats stats)
{
if (!account.equals(mAccount))
{
return;
}
mUnreadMessageCount = stats.unreadMessageCount;
mHandler.refreshTitle();
}
@ -1181,6 +1185,7 @@ public class FolderList extends K9ListActivity
holder = new FolderViewHolder();
holder.folderName = (TextView) view.findViewById(R.id.folder_name);
holder.newMessageCount = (TextView) view.findViewById(R.id.folder_unread_message_count);
holder.flaggedMessageCount = (TextView) view.findViewById(R.id.folder_flagged_message_count);
holder.folderStatus = (TextView) view.findViewById(R.id.folder_status);
holder.chip = view.findViewById(R.id.chip);
holder.rawFolderName = folder.name;
@ -1217,18 +1222,8 @@ public class FolderList extends K9ListActivity
statusText = getString(R.string.folder_push_active_symbol) + " "+ statusText;
}
if (folder.flaggedMessageCount > 0)
{
if (statusText == null)
{
statusText = "";
}
statusText += " / " + folder.flaggedMessageCount + "*";
}
if (statusText != null)
{
holder.folderStatus.setText(statusText);
holder.folderStatus.setVisibility(View.VISIBLE);
}
@ -1248,6 +1243,17 @@ public class FolderList extends K9ListActivity
{
holder.newMessageCount.setVisibility(View.GONE);
}
if (folder.flaggedMessageCount > 0)
{
holder.flaggedMessageCount.setText(Integer
.toString(folder.flaggedMessageCount));
holder.flaggedMessageCount.setVisibility(View.VISIBLE);
}
else
{
holder.flaggedMessageCount.setVisibility(View.GONE);
}
holder.chip.setBackgroundResource(K9.COLOR_CHIP_RES_IDS[mAccount.getAccountNumber() % K9.COLOR_CHIP_RES_IDS.length]);
@ -1407,6 +1413,7 @@ public class FolderList extends K9ListActivity
public TextView folderStatus;
public TextView newMessageCount;
public TextView flaggedMessageCount;
public String rawFolderName;
public View chip;

View File

@ -462,7 +462,7 @@ public class MessageList
}
else if (mQueryString != null)
{
mController.searchLocalMessages(mQueryString, null, mIntegrate, mQueryFlags, mForbiddenFlags, mAdapter.mListener);
mController.searchLocalMessages(null, mQueryString, null, mIntegrate, mQueryFlags, mForbiddenFlags, mAdapter.mListener);
}
mHandler.refreshTitle();