Show drafts in conversation list snippets

// FREEBIE
This commit is contained in:
Jake McGinty 2014-12-11 17:13:01 -08:00
parent 1d0c9536fc
commit b05967f2c9
7 changed files with 80 additions and 23 deletions

View File

@ -42,6 +42,11 @@
<string name="ApplicationPreferencesActivity_incoming_sms">Incoming SMS</string>
<string name="ApplicationPreferencesActivity_outgoing_sms">outgoing SMS</string>
<!-- DraftDatabase -->
<string name="DraftDatabase_Draft_image_snippet">(image)</string>
<string name="DraftDatabase_Draft_audio_snippet">(audio)</string>
<string name="DraftDatabase_Draft_video_snippet">(image)</string>
<!-- AttchmentManager -->
<string name="AttachmentManager_cant_open_media_selection">Can\'t find an app to select media.</string>
@ -311,6 +316,7 @@
<!-- ThreadRecord -->
<string name="ThreadRecord_left_the_group">Left the group...</string>
<string name="TheadRecord_secure_session_ended">Secure session ended.</string>
<string name="ThreadRecord_draft">Draft:</string>
<!-- VerifyIdentityActivity -->
<string name="VerifyIdentityActivity_you_do_not_have_an_identity_key">You do not have an identity key.</string>

View File

@ -71,7 +71,9 @@ import org.thoughtcrime.securesms.crypto.storage.TextSecureSessionStore;
import org.thoughtcrime.securesms.database.DatabaseFactory;
import org.thoughtcrime.securesms.database.DraftDatabase;
import org.thoughtcrime.securesms.database.DraftDatabase.Draft;
import org.thoughtcrime.securesms.database.DraftDatabase.Drafts;
import org.thoughtcrime.securesms.database.GroupDatabase;
import org.thoughtcrime.securesms.database.MmsSmsColumns.Types;
import org.thoughtcrime.securesms.database.ThreadDatabase;
import org.thoughtcrime.securesms.mms.AttachmentManager;
import org.thoughtcrime.securesms.mms.AttachmentTypeSelectorAdapter;
@ -111,7 +113,6 @@ import org.whispersystems.libaxolotl.state.SessionStore;
import org.whispersystems.textsecure.api.push.PushAddress;
import java.io.IOException;
import java.util.LinkedList;
import java.util.List;
import static org.thoughtcrime.securesms.database.GroupDatabase.GroupRecord;
@ -914,8 +915,8 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
builder.show();
}
private List<Draft> getDraftsForCurrentState() {
List<Draft> drafts = new LinkedList<>();
private Drafts getDraftsForCurrentState() {
Drafts drafts = new Drafts();
if (!Util.isEmpty(composeText)) {
drafts.add(new Draft(Draft.TEXT, composeText.getText().toString()));
@ -934,27 +935,22 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
if (this.threadId <= 0 || this.recipients == null || this.recipients.isEmpty())
return;
final List<Draft> drafts = getDraftsForCurrentState();
if (drafts.size() <= 0)
return;
final Drafts drafts = getDraftsForCurrentState();
final long thisThreadId = this.threadId;
final MasterSecret thisMasterSecret = this.masterSecret.parcelClone();
new AsyncTask<Void, Void, Void>() {
@Override
protected void onPostExecute(Void aVoid) {
super.onPostExecute(aVoid);
Toast.makeText(ConversationActivity.this,
R.string.ConversationActivity_saved_draft,
Toast.LENGTH_SHORT).show();
}
@Override
protected Void doInBackground(Void... params) {
MasterCipher masterCipher = new MasterCipher(thisMasterSecret);
DatabaseFactory.getDraftDatabase(ConversationActivity.this).insertDrafts(masterCipher, thisThreadId, drafts);
ThreadDatabase threadDatabase = DatabaseFactory.getThreadDatabase(ConversationActivity.this);
if (drafts.size() > 0) {
threadDatabase.updateSnippet(thisThreadId, drafts.getSnippet(ConversationActivity.this), Types.BASE_DRAFT_TYPE);
} else {
threadDatabase.update(thisThreadId);
}
MemoryCleaner.clean(thisMasterSecret);
return null;
}

View File

@ -35,6 +35,7 @@ import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.TextView;
import org.thoughtcrime.securesms.database.DatabaseFactory;
import org.thoughtcrime.securesms.database.model.ThreadRecord;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.Recipients;
@ -42,6 +43,7 @@ import org.thoughtcrime.securesms.util.DateUtils;
import org.thoughtcrime.securesms.util.Emoji;
import java.util.Set;
import java.util.concurrent.ThreadFactory;
/**
* A view that displays the element in a list of multiple conversation threads.
@ -102,10 +104,10 @@ public class ConversationListItem extends RelativeLayout
this.recipients.addListener(this);
this.fromView.setText(formatFrom(recipients, count, read));
this.subjectView.setText(Emoji.getInstance(context).emojify(thread.getDisplayBody(),
Emoji.EMOJI_SMALL,
new Emoji.InvalidatingPageLoadedListener(subjectView)),
TextView.BufferType.SPANNABLE);
this.subjectView.setText(Emoji.getInstance(context).emojify(thread.getDisplayBody(),
Emoji.EMOJI_SMALL,
new Emoji.InvalidatingPageLoadedListener(subjectView)),
TextView.BufferType.SPANNABLE);
if (thread.getDate() > 0)
this.dateView.setText(DateUtils.getBetterRelativeTimeSpanString(getContext(), thread.getDate()));

View File

@ -7,6 +7,7 @@ import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.util.Log;
import org.thoughtcrime.securesms.R;
import org.whispersystems.libaxolotl.InvalidMessageException;
import org.thoughtcrime.securesms.crypto.MasterCipher;
@ -98,5 +99,37 @@ public class DraftDatabase extends Database {
public String getValue() {
return value;
}
public String getSnippet(Context context) {
switch (type) {
case TEXT: return value;
case IMAGE: return context.getString(R.string.DraftDatabase_Draft_image_snippet);
case VIDEO: return context.getString(R.string.DraftDatabase_Draft_video_snippet);
case AUDIO: return context.getString(R.string.DraftDatabase_Draft_audio_snippet);
default: return null;
}
}
}
public static class Drafts extends LinkedList<Draft> {
private Draft getDraftOfType(String type) {
for (Draft draft : this) {
if (Draft.TEXT.equals(draft.getType())) {
return draft;
}
}
return null;
}
public String getSnippet(Context context) {
Draft textDraft = getDraftOfType(Draft.TEXT);
if (textDraft != null) {
return textDraft.getSnippet(context);
} else if (size() > 0) {
return get(0).getSnippet(context);
} else {
return "";
}
}
}
}

View File

@ -25,6 +25,7 @@ public interface MmsSmsColumns {
protected static final long BASE_SENT_FAILED_TYPE = 24;
protected static final long BASE_PENDING_SECURE_SMS_FALLBACK = 25;
protected static final long BASE_PENDING_INSECURE_SMS_FALLBACK = 26;
public static final long BASE_DRAFT_TYPE = 27;
protected static final long[] OUTGOING_MESSAGE_TYPES = {BASE_OUTBOX_TYPE, BASE_SENT_TYPE,
BASE_SENDING_TYPE, BASE_SENT_FAILED_TYPE,
@ -63,6 +64,10 @@ public interface MmsSmsColumns {
protected static final long ENCRYPTION_REMOTE_DUPLICATE_BIT = 0x04000000;
protected static final long ENCRYPTION_REMOTE_LEGACY_BIT = 0x02000000;
public static boolean isDraftMessageType(long type) {
return (type & BASE_TYPE_MASK) == BASE_DRAFT_TYPE;
}
public static boolean isFailedMessageType(long type) {
return (type & BASE_TYPE_MASK) == BASE_SENT_FAILED_TYPE;
}

View File

@ -115,7 +115,7 @@ public class ThreadDatabase extends Database {
private void updateThread(long threadId, long count, String body, long date, long type)
{
ContentValues contentValues = new ContentValues(3);
ContentValues contentValues = new ContentValues(4);
contentValues.put(DATE, date - date % 1000);
contentValues.put(MESSAGE_COUNT, count);
contentValues.put(SNIPPET, body);
@ -126,6 +126,15 @@ public class ThreadDatabase extends Database {
notifyConversationListListeners();
}
public void updateSnippet(long threadId, String snippet, long type) {
ContentValues contentValues = new ContentValues(3);
contentValues.put(SNIPPET, snippet);
contentValues.put(SNIPPET_TYPE, type);
SQLiteDatabase db = databaseHelper.getWritableDatabase();
db.update(TABLE_NAME, contentValues, ID + " = ?", new String[] {threadId + ""});
notifyConversationListListeners();
}
private void deleteThread(long threadId) {
SQLiteDatabase db = databaseHelper.getWritableDatabase();
db.delete(TABLE_NAME, ID_WHERE, new String[] {threadId+""});

View File

@ -72,6 +72,9 @@ public class ThreadRecord extends DisplayRecord {
return emphasisAdded(context.getString(R.string.TheadRecord_secure_session_ended));
} else if (MmsSmsColumns.Types.isLegacyType(type)) {
return emphasisAdded(context.getString(R.string.MessageRecord_message_encrypted_with_a_legacy_protocol_version_that_is_no_longer_supported));
} else if (MmsSmsColumns.Types.isDraftMessageType(type)) {
String draftText = context.getString(R.string.ThreadRecord_draft);
return emphasisAdded(draftText + " " + getBody().getBody(), 0, draftText.length());
} else {
if (TextUtils.isEmpty(getBody().getBody())) {
return new SpannableString(context.getString(R.string.MessageNotifier_no_subject));
@ -82,10 +85,13 @@ public class ThreadRecord extends DisplayRecord {
}
private SpannableString emphasisAdded(String sequence) {
return emphasisAdded(sequence, 0, sequence.length());
}
private SpannableString emphasisAdded(String sequence, int start, int end) {
SpannableString spannable = new SpannableString(sequence);
spannable.setSpan(new StyleSpan(android.graphics.Typeface.ITALIC), 0,
sequence.length(),
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
spannable.setSpan(new StyleSpan(android.graphics.Typeface.ITALIC),
start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
return spannable;
}