diff --git a/res/menu/accounts_context.xml b/res/menu/accounts_context.xml index e55d13a94..798d32d20 100644 --- a/res/menu/accounts_context.xml +++ b/res/menu/accounts_context.xml @@ -21,6 +21,10 @@ android:title="@string/remove_account_action" /> + + diff --git a/res/values/strings.xml b/res/values/strings.xml index fd36f1509..830ccf0a6 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -1073,4 +1073,7 @@ Welcome to K-9 Mail setup. K-9 is an open source mail client for Android origin Save attachment No file browser found. Where would you like to save this attachment? + Move up + Move down + diff --git a/src/com/fsck/k9/Account.java b/src/com/fsck/k9/Account.java index 9c9d23584..fb9b93869 100644 --- a/src/com/fsck/k9/Account.java +++ b/src/com/fsck/k9/Account.java @@ -21,7 +21,9 @@ import com.fsck.k9.view.ColorChip; import java.util.ArrayList; import java.util.Arrays; import java.util.Calendar; +import java.util.Collections; import java.util.Date; +import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Random; @@ -376,20 +378,30 @@ public class Account implements BaseAccount { mCryptoApp = prefs.getString(mUuid + ".cryptoApp", Apg.NAME); mCryptoAutoSignature = prefs.getBoolean(mUuid + ".cryptoAutoSignature", false); } - - - protected synchronized void delete(Preferences preferences) { - String[] uuids = preferences.getPreferences().getString("accountUuids", "").split(","); + + private String combineUuids(String[] uuids) { StringBuffer sb = new StringBuffer(); for (int i = 0, length = uuids.length; i < length; i++) { - if (!uuids[i].equals(mUuid)) { - if (sb.length() > 0) { - sb.append(','); - } - sb.append(uuids[i]); + if (sb.length() > 0) { + sb.append(','); } + sb.append(uuids[i]); } String accountUuids = sb.toString(); + return accountUuids; + } + + protected synchronized void delete(Preferences preferences) { + String[] uuids = preferences.getPreferences().getString("accountUuids", "").split(","); + String[] newUuids = new String[uuids.length - 1]; + int i = 0; + for (String uuid : uuids) { + if (uuid.equals(mUuid) == false) { + newUuids[i++] = uuid; + } + } + + String accountUuids = combineUuids(newUuids); SharedPreferences.Editor editor = preferences.getPreferences().edit(); editor.putString("accountUuids", accountUuids); @@ -455,6 +467,64 @@ public class Account implements BaseAccount { editor.commit(); } + public static int findNewAccountNumber(List accountNumbers) { + int newAccountNumber = -1; + Collections.sort(accountNumbers); + for (int accountNumber : accountNumbers) { + if (accountNumber > newAccountNumber + 1) { + break; + } + newAccountNumber = accountNumber; + } + newAccountNumber++; + return newAccountNumber; + } + + public static List getExistingAccountNumbers(Preferences preferences) { + Account[] accounts = preferences.getAccounts(); + List accountNumbers = new LinkedList(); + for (int i = 0; i < accounts.length; i++) { + accountNumbers.add(accounts[i].getAccountNumber()); + } + return accountNumbers; + } + public static int generateAccountNumber(Preferences preferences) { + List accountNumbers = getExistingAccountNumbers(preferences); + return findNewAccountNumber(accountNumbers); + } + + public void move(Preferences preferences, boolean moveUp) { + String[] uuids = preferences.getPreferences().getString("accountUuids", "").split(","); + SharedPreferences.Editor editor = preferences.getPreferences().edit(); + String[] newUuids = new String[uuids.length]; + if (moveUp) { + for (int i = 0; i < uuids.length; i++) { + if (i > 0 && uuids[i].equals(mUuid)) { + newUuids[i] = newUuids[i-1]; + newUuids[i-1] = mUuid; + } + else { + newUuids[i] = uuids[i]; + } + } + } + else { + for (int i = uuids.length - 1; i >= 0; i--) { + if (i < uuids.length - 1 && uuids[i].equals(mUuid)) { + newUuids[i] = newUuids[i+1]; + newUuids[i+1] = mUuid; + } + else { + newUuids[i] = uuids[i]; + } + } + } + String accountUuids = combineUuids(newUuids); + editor.putString("accountUuids", accountUuids); + editor.commit(); + preferences.refreshAccounts(); + } + public synchronized void save(Preferences preferences) { SharedPreferences.Editor editor = preferences.getPreferences().edit(); diff --git a/src/com/fsck/k9/Preferences.java b/src/com/fsck/k9/Preferences.java index dece28412..6ee07f538 100644 --- a/src/com/fsck/k9/Preferences.java +++ b/src/com/fsck/k9/Preferences.java @@ -3,7 +3,11 @@ package com.fsck.k9; import java.util.ArrayList; import java.util.Collection; +import java.util.HashMap; +import java.util.LinkedList; import java.util.List; +import java.util.Map; + import android.content.Context; import android.content.SharedPreferences; import android.util.Config; @@ -29,7 +33,8 @@ public class Preferences { private Storage mStorage; - private List accounts; + private Map accounts = null; + private List accountsInOrder = null; private Account newAccount; private Context mContext; @@ -45,16 +50,35 @@ public class Preferences { } private synchronized void loadAccounts() { + accounts = new HashMap(); + refreshAccounts(); + } + + public synchronized void refreshAccounts() { + Map newAccountMap = new HashMap(); + accountsInOrder = new LinkedList(); String accountUuids = getPreferences().getString("accountUuids", null); if ((accountUuids != null) && (accountUuids.length() != 0)) { String[] uuids = accountUuids.split(","); - accounts = new ArrayList(uuids.length); for (String uuid : uuids) { - accounts.add(new Account(this, uuid)); + Account account = accounts.get(uuid); + if (account != null) { + newAccountMap.put(uuid, account); + accountsInOrder.add(account); + } else { + Account newAccount = new Account(this, uuid); + newAccountMap.put(uuid, newAccount); + accountsInOrder.add(newAccount); + } } - } else { - accounts = new ArrayList(); } + if ((newAccount != null) && newAccount.getAccountNumber() != -1) { + newAccountMap.put(newAccount.getUuid(), newAccount); + accountsInOrder.add(newAccount); + newAccount = null; + } + + accounts = newAccountMap; } /** @@ -67,12 +91,7 @@ public class Preferences { loadAccounts(); } - if ((newAccount != null) && newAccount.getAccountNumber() != -1) { - accounts.add(newAccount); - newAccount = null; - } - - return accounts.toArray(EMPTY_ACCOUNT_ARRAY); + return accountsInOrder.toArray(EMPTY_ACCOUNT_ARRAY); } /** @@ -81,16 +100,9 @@ public class Preferences { * @return all accounts with {@link Account#isAvailable(Context)} */ public synchronized Collection getAvailableAccounts() { - if (accounts == null) { - loadAccounts(); - } - - if ((newAccount != null) && newAccount.getAccountNumber() != -1) { - accounts.add(newAccount); - newAccount = null; - } + Account[] allAccounts = getAccounts(); Collection retval = new ArrayList(accounts.size()); - for (Account account : accounts) { + for (Account account : allAccounts) { if (account.isAvailable(mContext)) { retval.add(account); } @@ -103,28 +115,22 @@ public class Preferences { if (accounts == null) { loadAccounts(); } + Account account = accounts.get(uuid); - for (Account account : accounts) { - if (account.getUuid().equals(uuid)) { - return account; - } - } - - if ((newAccount != null) && newAccount.getUuid().equals(uuid)) { - return newAccount; - } - - return null; + return account; } public synchronized Account newAccount() { newAccount = new Account(K9.app); + accounts.put(newAccount.getUuid(), newAccount); + accountsInOrder.add(newAccount); return newAccount; } public synchronized void deleteAccount(Account account) { - accounts.remove(account); + accounts.remove(account.getUuid()); + accountsInOrder.remove(account); account.delete(this); if (newAccount == account) { diff --git a/src/com/fsck/k9/activity/Accounts.java b/src/com/fsck/k9/activity/Accounts.java index 7053707fe..4b804b009 100644 --- a/src/com/fsck/k9/activity/Accounts.java +++ b/src/com/fsck/k9/activity/Accounts.java @@ -584,6 +584,12 @@ public class Accounts extends K9ListActivity implements OnItemClickListener, OnC case R.id.recreate: onRecreate(realAccount); break; + case R.id.move_up: + onMove(realAccount, true); + break; + case R.id.move_down: + onMove(realAccount, false); + break; } return true; } @@ -602,7 +608,22 @@ public class Accounts extends K9ListActivity implements OnItemClickListener, OnC private void onRecreate(Account account) { showDialog(DIALOG_RECREATE_ACCOUNT); } - + private void onMove(final Account account, final boolean up) { + AsyncUIProcessor.getInstance(getApplication()).execute( + new Runnable() + { + @Override + public void run() { + account.move(Preferences.getPreferences(Accounts.this), up); + runOnUiThread(new Runnable() { + @Override + public void run() { + refresh(); + } + }); + } + }); + } public void onItemClick(AdapterView parent, View view, int position, long id) { BaseAccount account = (BaseAccount)parent.getItemAtPosition(position); diff --git a/src/com/fsck/k9/activity/AsyncUIProcessor.java b/src/com/fsck/k9/activity/AsyncUIProcessor.java new file mode 100644 index 000000000..55947b2c4 --- /dev/null +++ b/src/com/fsck/k9/activity/AsyncUIProcessor.java @@ -0,0 +1,33 @@ +package com.fsck.k9.activity; + +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +import android.app.Application; + +/** + * The class should be used to run long-running processes invoked from the UI that + * do not affect the Stores. There are probably pieces of MessagingController + * that can be moved here. There is no wakelock used here. Any network activity, or + * true background activity, that is invoked from here should wakelock itself. UI-centric + * activity does not need to be wakelocked, as it will simply continue when the phone wakes + * without disruption. + * + */ +public class AsyncUIProcessor { + + private final ExecutorService threadPool = Executors.newCachedThreadPool(); + private static AsyncUIProcessor inst = null; + private AsyncUIProcessor() { + } + + public synchronized static AsyncUIProcessor getInstance(Application application) { + if (inst == null) { + inst = new AsyncUIProcessor(); + } + return inst; + } + public void execute(Runnable runnable) { + threadPool.execute(runnable); + } +}