Use database ID to keep track of the current draft

By using the database ID we avoid having to deal with the problem of
changing UIDs. First the message has a local UID, then, when the upload
to the server is completed, it gets a remote UID.
This commit is contained in:
cketti 2012-01-22 05:14:58 +01:00
parent 96f827d291
commit bddacf6b64
3 changed files with 80 additions and 35 deletions

View File

@ -84,6 +84,8 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc
private static final int DIALOG_REFUSE_TO_SAVE_DRAFT_MARKED_ENCRYPTED = 2;
private static final int DIALOG_CONTINUE_WITHOUT_PUBLIC_KEY = 3;
private static final long INVALID_DRAFT_ID = MessagingController.INVALID_MESSAGE_ID;
private static final String ACTION_COMPOSE = "com.fsck.k9.intent.action.COMPOSE";
private static final String ACTION_REPLY = "com.fsck.k9.intent.action.REPLY";
private static final String ACTION_REPLY_ALL = "com.fsck.k9.intent.action.REPLY_ALL";
@ -104,8 +106,7 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc
"com.fsck.k9.activity.MessageCompose.QuotedTextShown";
private static final String STATE_KEY_SOURCE_MESSAGE_PROCED =
"com.fsck.k9.activity.MessageCompose.stateKeySourceMessageProced";
private static final String STATE_KEY_DRAFT_UID =
"com.fsck.k9.activity.MessageCompose.draftUid";
private static final String STATE_KEY_DRAFT_ID = "com.fsck.k9.activity.MessageCompose.draftId";
private static final String STATE_KEY_HTML_QUOTE = "com.fsck.k9.activity.MessageCompose.HTMLQuote";
private static final String STATE_IDENTITY_CHANGED =
"com.fsck.k9.activity.MessageCompose.identityChanged";
@ -228,10 +229,11 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc
private boolean mIgnoreOnStop = false;
/**
* The draft uid of this message. This is used when saving drafts so that the same draft is
* overwritten instead of being created anew. This property is null until the first save.
* The database ID of this message's draft. This is used when saving drafts so the message in
* the database is updated instead of being created anew. This property is INVALID_DRAFT_ID
* until the first save.
*/
private String mDraftUid;
private long mDraftId = INVALID_DRAFT_ID;
private Handler mHandler = new Handler() {
@Override
@ -893,7 +895,7 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc
outState.putBoolean(STATE_KEY_BCC_SHOWN, mBccWrapper.getVisibility() == View.VISIBLE);
outState.putSerializable(STATE_KEY_QUOTED_TEXT_MODE, mQuotedTextMode);
outState.putBoolean(STATE_KEY_SOURCE_MESSAGE_PROCED, mSourceMessageProcessed);
outState.putString(STATE_KEY_DRAFT_UID, mDraftUid);
outState.putLong(STATE_KEY_DRAFT_ID, mDraftId);
outState.putSerializable(STATE_IDENTITY, mIdentity);
outState.putBoolean(STATE_IDENTITY_CHANGED, mIdentityChanged);
outState.putSerializable(STATE_PGP_DATA, mPgpData);
@ -930,7 +932,7 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc
mQuotedHTML.loadDataWithBaseURL("http://", mQuotedHtmlContent.getQuotedContent(), "text/html", "utf-8", null);
}
}
mDraftUid = savedInstanceState.getString(STATE_KEY_DRAFT_UID);
mDraftId = savedInstanceState.getLong(STATE_KEY_DRAFT_ID);
mIdentity = (Identity)savedInstanceState.getSerializable(STATE_IDENTITY);
mIdentityChanged = savedInstanceState.getBoolean(STATE_IDENTITY_CHANGED);
mPgpData = (PgpData) savedInstanceState.getSerializable(STATE_PGP_DATA);
@ -1609,9 +1611,9 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc
}
private void onDiscard() {
if (mDraftUid != null) {
MessagingController.getInstance(getApplication()).deleteDraft(mAccount, mDraftUid);
mDraftUid = null;
if (mDraftId != INVALID_DRAFT_ID) {
MessagingController.getInstance(getApplication()).deleteDraft(mAccount, mDraftId);
mDraftId = INVALID_DRAFT_ID;
}
mHandler.sendEmptyMessage(MSG_DISCARDED_DRAFT);
mDraftNeedsSaving = false;
@ -1817,12 +1819,12 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc
}
// test whether there is something to save
if (mDraftNeedsSaving || (mDraftUid != null)) {
final String previousDraftUid = mDraftUid;
if (mDraftNeedsSaving || (mDraftId != INVALID_DRAFT_ID)) {
final long previousDraftId = mDraftId;
final Account previousAccount = mAccount;
// make current message appear as new
mDraftUid = null;
mDraftId = INVALID_DRAFT_ID;
// actual account switch
mAccount = account;
@ -1832,13 +1834,13 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc
}
saveMessage();
if (previousDraftUid != null) {
if (previousDraftId != INVALID_DRAFT_ID) {
if (K9.DEBUG) {
Log.v(K9.LOG_TAG, "Account switch, deleting draft from previous account: "
+ previousDraftUid);
+ previousDraftId);
}
MessagingController.getInstance(getApplication()).deleteDraft(previousAccount,
previousDraftUid);
previousDraftId);
}
} else {
mAccount = account;
@ -2264,7 +2266,7 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc
} else if (ACTION_EDIT_DRAFT.equals(action)) {
String showQuotedTextMode = "NONE";
mDraftUid = message.getUid();
mDraftId = MessagingController.getInstance(getApplication()).getId(message);
mSubjectView.setText(message.getSubject());
addAddresses(mToView, message.getRecipients(RecipientType.TO));
if (message.getRecipients(RecipientType.CC).length > 0) {
@ -2854,14 +2856,6 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc
@Override
public void messageUidChanged(Account account, String folder, String oldUid, String newUid) {
//TODO: is this really necessary here? mDraftUid is update after the call to MessagingController.saveDraft()
// Track UID changes of the draft message
if (account.equals(mAccount) &&
folder.equals(mAccount.getDraftsFolderName()) &&
oldUid.equals(mDraftUid)) {
mDraftUid = newUid;
}
// Track UID changes of the source message
if (mMessageReference != null) {
final Account sourceAccount = Preferences.getPreferences(MessageCompose.this).getAccount(mMessageReference.accountUuid);
@ -2957,9 +2951,9 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc
}
MessagingController.getInstance(getApplication()).sendMessage(mAccount, message, null);
if (mDraftUid != null) {
MessagingController.getInstance(getApplication()).deleteDraft(mAccount, mDraftUid);
mDraftUid = null;
if (mDraftId != INVALID_DRAFT_ID) {
MessagingController.getInstance(getApplication()).deleteDraft(mAccount, mDraftId);
mDraftId = INVALID_DRAFT_ID;
}
return null;
@ -2983,9 +2977,7 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc
/*
* Save a draft
*/
if (mDraftUid != null) {
message.setUid(mDraftUid);
} else if (ACTION_EDIT_DRAFT.equals(getIntent().getAction())) {
if (ACTION_EDIT_DRAFT.equals(getIntent().getAction())) {
/*
* We're saving a previously saved draft, so update the new message's uid
* to the old message's uid.
@ -2996,8 +2988,8 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc
}
final MessagingController messagingController = MessagingController.getInstance(getApplication());
Message draftMessage = messagingController.saveDraft(mAccount, message);
mDraftUid = draftMessage.getUid();
Message draftMessage = messagingController.saveDraft(mAccount, message, mDraftId);
mDraftId = messagingController.getId(draftMessage);
mHandler.sendEmptyMessage(MSG_SAVED_DRAFT);
return null;

View File

@ -79,6 +79,7 @@ import com.fsck.k9.mail.store.LocalStore.PendingCommand;
* removed from the queue once the activity is no longer active.
*/
public class MessagingController implements Runnable {
public static final long INVALID_MESSAGE_ID = -1;
/**
* Immutable empty {@link String} array
@ -3303,12 +3304,13 @@ public class MessagingController implements Runnable {
});
}
public void deleteDraft(final Account account, String uid) {
public void deleteDraft(final Account account, long id) {
LocalFolder localFolder = null;
try {
LocalStore localStore = account.getLocalStore();
localFolder = localStore.getFolder(account.getDraftsFolderName());
localFolder.open(OpenMode.READ_WRITE);
String uid = localFolder.getMessageUidById(id);
Message message = localFolder.getMessage(uid);
if (message != null) {
deleteMessages(new Message[] { message }, null);
@ -4059,12 +4061,18 @@ public class MessagingController implements Runnable {
* @param message Message to save.
* @return Message representing the entry in the local store.
*/
public Message saveDraft(final Account account, final Message message) {
public Message saveDraft(final Account account, final Message message, long existingDraftId) {
Message localMessage = null;
try {
LocalStore localStore = account.getLocalStore();
LocalFolder localFolder = localStore.getFolder(account.getDraftsFolderName());
localFolder.open(OpenMode.READ_WRITE);
if (existingDraftId != INVALID_MESSAGE_ID) {
String uid = localFolder.getMessageUidById(existingDraftId);
message.setUid(uid);
}
// Save the message to the store.
localFolder.appendMessages(new Message[] {
message
@ -4089,6 +4097,18 @@ public class MessagingController implements Runnable {
return localMessage;
}
public long getId(Message message) {
long id;
if (message instanceof LocalMessage) {
id = ((LocalMessage) message).getId();
} else {
Log.w(K9.LOG_TAG, "MessagingController.getId() called without a LocalMessage");
id = INVALID_MESSAGE_ID;
}
return id;
}
public boolean modeMismatch(Account.FolderMode aMode, Folder.FolderClass fMode) {
if (aMode == Account.FolderMode.NONE
|| (aMode == Account.FolderMode.FIRST_CLASS &&

View File

@ -1798,6 +1798,39 @@ public class LocalStore extends Store implements Serializable {
});
}
public String getMessageUidById(final long id) throws MessagingException {
try {
return database.execute(false, new DbCallback<String>() {
@Override
public String doDbWork(final SQLiteDatabase db) throws WrappedException, UnavailableStorageException {
try {
open(OpenMode.READ_WRITE);
Cursor cursor = null;
try {
cursor = db.rawQuery(
"SELECT uid FROM messages " +
"WHERE id = ? AND folder_id = ?",
new String[] {
Long.toString(id), Long.toString(mFolderId)
});
if (!cursor.moveToNext()) {
return null;
}
return cursor.getString(0);
} finally {
Utility.closeQuietly(cursor);
}
} catch (MessagingException e) {
throw new WrappedException(e);
}
}
});
} catch (WrappedException e) {
throw(MessagingException) e.getCause();
}
}
@Override
public Message getMessage(final String uid) throws MessagingException {
try {