mirror of
https://github.com/oxen-io/session-android.git
synced 2024-11-27 20:15:21 +00:00
Save replies in drafts.
Previously, quotes were not saved to drafts, meaning they would be lost when leaving the conversation or app. Now, a QuoteId (which represents the necessary data to restore the QuoteModel) is serialized and stored in the DraftDatabase. Fixes #7716 Closes #7729
This commit is contained in:
parent
7100030c22
commit
43622e603d
@ -53,6 +53,7 @@
|
||||
<string name="DraftDatabase_Draft_audio_snippet">(audio)</string>
|
||||
<string name="DraftDatabase_Draft_video_snippet">(video)</string>
|
||||
<string name="DraftDatabase_Draft_location_snippet">(location)</string>
|
||||
<string name="DraftDatabase_Draft_quote_snippet">(reply)</string>
|
||||
|
||||
<!-- AttchmentManager -->
|
||||
<string name="AttachmentManager_cant_open_media_selection">Can\'t find an app to select media.</string>
|
||||
|
@ -128,6 +128,8 @@ import org.thoughtcrime.securesms.mms.OutgoingExpirationUpdateMessage;
|
||||
import org.thoughtcrime.securesms.mms.OutgoingGroupMediaMessage;
|
||||
import org.thoughtcrime.securesms.mms.OutgoingMediaMessage;
|
||||
import org.thoughtcrime.securesms.mms.OutgoingSecureMediaMessage;
|
||||
import org.thoughtcrime.securesms.mms.QuoteId;
|
||||
import org.thoughtcrime.securesms.mms.QuoteModel;
|
||||
import org.thoughtcrime.securesms.mms.Slide;
|
||||
import org.thoughtcrime.securesms.mms.SlideDeck;
|
||||
import org.thoughtcrime.securesms.notifications.MarkReadReceiver;
|
||||
@ -1035,6 +1037,9 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
||||
case Draft.VIDEO:
|
||||
setMedia(Uri.parse(draft.getValue()), MediaType.VIDEO);
|
||||
break;
|
||||
case Draft.QUOTE:
|
||||
new QuoteRestorationTask(draft.getValue()).execute();
|
||||
break;
|
||||
}
|
||||
} catch (IOException e) {
|
||||
Log.w(TAG, e);
|
||||
@ -1431,6 +1436,12 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
||||
else if (slide.hasImage() && slide.getUri() != null) drafts.add(new Draft(Draft.IMAGE, slide.getUri().toString()));
|
||||
}
|
||||
|
||||
Optional<QuoteModel> quote = inputPanel.getQuote();
|
||||
|
||||
if (quote.isPresent()) {
|
||||
drafts.add(new Draft(Draft.QUOTE, new QuoteId(quote.get().getId(), quote.get().getAuthor()).serialize()));
|
||||
}
|
||||
|
||||
return drafts;
|
||||
}
|
||||
|
||||
@ -2134,4 +2145,33 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class QuoteRestorationTask extends AsyncTask<Void, Void, MessageRecord> {
|
||||
|
||||
private final String serialized;
|
||||
|
||||
QuoteRestorationTask(@NonNull String serialized) {
|
||||
this.serialized = serialized;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected MessageRecord doInBackground(Void... voids) {
|
||||
QuoteId quoteId = QuoteId.deserialize(serialized);
|
||||
|
||||
if (quoteId != null) {
|
||||
return DatabaseFactory.getMmsSmsDatabase(getApplicationContext()).getMessageFor(quoteId.getId(), quoteId.getAuthor());
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(MessageRecord messageRecord) {
|
||||
if (messageRecord != null) {
|
||||
handleReplyMessage(messageRecord);
|
||||
} else {
|
||||
Log.e(TAG, "Failed to restore a quote from a draft. No matching message record.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -101,6 +101,7 @@ public class DraftDatabase extends Database {
|
||||
public static final String VIDEO = "video";
|
||||
public static final String AUDIO = "audio";
|
||||
public static final String LOCATION = "location";
|
||||
public static final String QUOTE = "quote";
|
||||
|
||||
private final String type;
|
||||
private final String value;
|
||||
@ -125,6 +126,7 @@ public class DraftDatabase extends Database {
|
||||
case VIDEO: return context.getString(R.string.DraftDatabase_Draft_video_snippet);
|
||||
case AUDIO: return context.getString(R.string.DraftDatabase_Draft_audio_snippet);
|
||||
case LOCATION: return context.getString(R.string.DraftDatabase_Draft_location_snippet);
|
||||
case QUOTE: return context.getString(R.string.DraftDatabase_Draft_quote_snippet);
|
||||
default: return null;
|
||||
}
|
||||
}
|
||||
|
@ -19,6 +19,7 @@ package org.thoughtcrime.securesms.database;
|
||||
import android.content.Context;
|
||||
import android.database.Cursor;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.util.Log;
|
||||
|
||||
import net.sqlcipher.database.SQLiteDatabase;
|
||||
@ -71,8 +72,24 @@ public class MmsSmsDatabase extends Database {
|
||||
super(context, databaseHelper);
|
||||
}
|
||||
|
||||
public Cursor getMessagesFor(long timestamp) {
|
||||
return queryTables(PROJECTION, MmsSmsColumns.NORMALIZED_DATE_SENT + " = " + timestamp, null, null);
|
||||
public @Nullable MessageRecord getMessageFor(long timestamp, Address author) {
|
||||
MmsSmsDatabase db = DatabaseFactory.getMmsSmsDatabase(context);
|
||||
|
||||
try (Cursor cursor = queryTables(PROJECTION, MmsSmsColumns.NORMALIZED_DATE_SENT + " = " + timestamp, null, null)) {
|
||||
MmsSmsDatabase.Reader reader = db.readerFor(cursor);
|
||||
|
||||
MessageRecord messageRecord;
|
||||
|
||||
while ((messageRecord = reader.getNext()) != null) {
|
||||
if ((Util.isOwnNumber(context, author) && messageRecord.isOutgoing()) ||
|
||||
(!Util.isOwnNumber(context, author) && messageRecord.getIndividualRecipient().getAddress().equals(author)))
|
||||
{
|
||||
return messageRecord;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public Cursor getConversation(long threadId, long limit) {
|
||||
|
@ -865,32 +865,22 @@ public class PushDecryptJob extends ContextJob {
|
||||
return Optional.absent();
|
||||
}
|
||||
|
||||
MmsSmsDatabase db = DatabaseFactory.getMmsSmsDatabase(context);
|
||||
Address author = Address.fromExternal(context, quote.get().getAuthor().getNumber());
|
||||
Address author = Address.fromExternal(context, quote.get().getAuthor().getNumber());
|
||||
MessageRecord message = DatabaseFactory.getMmsSmsDatabase(context).getMessageFor(quote.get().getId(), author);
|
||||
|
||||
try (Cursor cursor = db.getMessagesFor(quote.get().getId())) {
|
||||
MmsSmsDatabase.Reader reader = db.readerFor(cursor);
|
||||
if (message != null) {
|
||||
Log.w(TAG, "Found matching message record...");
|
||||
|
||||
MessageRecord messageRecord;
|
||||
List<Attachment> attachments = new LinkedList<>();
|
||||
|
||||
while ((messageRecord = reader.getNext()) != null) {
|
||||
if ((Util.isOwnNumber(context, author) && messageRecord.isOutgoing()) ||
|
||||
(!Util.isOwnNumber(context, author) && messageRecord.getIndividualRecipient().getAddress().equals(author)))
|
||||
{
|
||||
Log.w(TAG, "Found matching message record...");
|
||||
List<Attachment> attachments = new LinkedList<>();
|
||||
|
||||
if (messageRecord.isMms()) {
|
||||
attachments = ((MmsMessageRecord)messageRecord).getSlideDeck().asAttachments();
|
||||
}
|
||||
|
||||
return Optional.of(new QuoteModel(quote.get().getId(), author, messageRecord.getBody(), attachments));
|
||||
}
|
||||
if (message.isMms()) {
|
||||
attachments = ((MmsMessageRecord) message).getSlideDeck().asAttachments();
|
||||
}
|
||||
|
||||
return Optional.of(new QuoteModel(quote.get().getId(), author, message.getBody(), attachments));
|
||||
}
|
||||
|
||||
Log.w(TAG, "Didn't find matching message record...");
|
||||
|
||||
return Optional.of(new QuoteModel(quote.get().getId(),
|
||||
author,
|
||||
quote.get().getText(),
|
||||
|
59
src/org/thoughtcrime/securesms/mms/QuoteId.java
Normal file
59
src/org/thoughtcrime/securesms/mms/QuoteId.java
Normal file
@ -0,0 +1,59 @@
|
||||
package org.thoughtcrime.securesms.mms;
|
||||
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.util.Log;
|
||||
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
import org.thoughtcrime.securesms.database.Address;
|
||||
import org.thoughtcrime.securesms.database.model.MessageRecord;
|
||||
|
||||
/**
|
||||
* Represents the information required to find the {@link MessageRecord} pointed to by a quote.
|
||||
*/
|
||||
public class QuoteId {
|
||||
|
||||
private static final String TAG = QuoteId.class.getSimpleName();
|
||||
|
||||
private static final String ID = "id";
|
||||
private static final String AUTHOR = "author";
|
||||
|
||||
private final long id;
|
||||
private final Address author;
|
||||
|
||||
public QuoteId(long id, @NonNull Address author) {
|
||||
this.id = id;
|
||||
this.author = author;
|
||||
}
|
||||
|
||||
public long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public @NonNull Address getAuthor() {
|
||||
return author;
|
||||
}
|
||||
|
||||
public @NonNull String serialize() {
|
||||
try {
|
||||
JSONObject object = new JSONObject();
|
||||
object.put(ID, id);
|
||||
object.put(AUTHOR, author.serialize());
|
||||
return object.toString();
|
||||
} catch (JSONException e) {
|
||||
Log.e(TAG, "Failed to serialize to json", e);
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
public static @Nullable QuoteId deserialize(@NonNull String serialized) {
|
||||
try {
|
||||
JSONObject json = new JSONObject(serialized);
|
||||
return new QuoteId(json.getLong(ID), Address.fromSerialized(json.getString(AUTHOR)));
|
||||
} catch (JSONException e) {
|
||||
Log.e(TAG, "Failed to deserialize from json", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user