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_audio_snippet">(audio)</string>
|
||||||
<string name="DraftDatabase_Draft_video_snippet">(video)</string>
|
<string name="DraftDatabase_Draft_video_snippet">(video)</string>
|
||||||
<string name="DraftDatabase_Draft_location_snippet">(location)</string>
|
<string name="DraftDatabase_Draft_location_snippet">(location)</string>
|
||||||
|
<string name="DraftDatabase_Draft_quote_snippet">(reply)</string>
|
||||||
|
|
||||||
<!-- AttchmentManager -->
|
<!-- AttchmentManager -->
|
||||||
<string name="AttachmentManager_cant_open_media_selection">Can\'t find an app to select media.</string>
|
<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.OutgoingGroupMediaMessage;
|
||||||
import org.thoughtcrime.securesms.mms.OutgoingMediaMessage;
|
import org.thoughtcrime.securesms.mms.OutgoingMediaMessage;
|
||||||
import org.thoughtcrime.securesms.mms.OutgoingSecureMediaMessage;
|
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.Slide;
|
||||||
import org.thoughtcrime.securesms.mms.SlideDeck;
|
import org.thoughtcrime.securesms.mms.SlideDeck;
|
||||||
import org.thoughtcrime.securesms.notifications.MarkReadReceiver;
|
import org.thoughtcrime.securesms.notifications.MarkReadReceiver;
|
||||||
@ -1035,6 +1037,9 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
|||||||
case Draft.VIDEO:
|
case Draft.VIDEO:
|
||||||
setMedia(Uri.parse(draft.getValue()), MediaType.VIDEO);
|
setMedia(Uri.parse(draft.getValue()), MediaType.VIDEO);
|
||||||
break;
|
break;
|
||||||
|
case Draft.QUOTE:
|
||||||
|
new QuoteRestorationTask(draft.getValue()).execute();
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
Log.w(TAG, 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()));
|
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;
|
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 VIDEO = "video";
|
||||||
public static final String AUDIO = "audio";
|
public static final String AUDIO = "audio";
|
||||||
public static final String LOCATION = "location";
|
public static final String LOCATION = "location";
|
||||||
|
public static final String QUOTE = "quote";
|
||||||
|
|
||||||
private final String type;
|
private final String type;
|
||||||
private final String value;
|
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 VIDEO: return context.getString(R.string.DraftDatabase_Draft_video_snippet);
|
||||||
case AUDIO: return context.getString(R.string.DraftDatabase_Draft_audio_snippet);
|
case AUDIO: return context.getString(R.string.DraftDatabase_Draft_audio_snippet);
|
||||||
case LOCATION: return context.getString(R.string.DraftDatabase_Draft_location_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;
|
default: return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,6 +19,7 @@ package org.thoughtcrime.securesms.database;
|
|||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.database.Cursor;
|
import android.database.Cursor;
|
||||||
import android.support.annotation.NonNull;
|
import android.support.annotation.NonNull;
|
||||||
|
import android.support.annotation.Nullable;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
import net.sqlcipher.database.SQLiteDatabase;
|
import net.sqlcipher.database.SQLiteDatabase;
|
||||||
@ -71,8 +72,24 @@ public class MmsSmsDatabase extends Database {
|
|||||||
super(context, databaseHelper);
|
super(context, databaseHelper);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Cursor getMessagesFor(long timestamp) {
|
public @Nullable MessageRecord getMessageFor(long timestamp, Address author) {
|
||||||
return queryTables(PROJECTION, MmsSmsColumns.NORMALIZED_DATE_SENT + " = " + timestamp, null, null);
|
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) {
|
public Cursor getConversation(long threadId, long limit) {
|
||||||
|
@ -865,32 +865,22 @@ public class PushDecryptJob extends ContextJob {
|
|||||||
return Optional.absent();
|
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())) {
|
if (message != 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)))
|
|
||||||
{
|
|
||||||
Log.w(TAG, "Found matching message record...");
|
Log.w(TAG, "Found matching message record...");
|
||||||
|
|
||||||
List<Attachment> attachments = new LinkedList<>();
|
List<Attachment> attachments = new LinkedList<>();
|
||||||
|
|
||||||
if (messageRecord.isMms()) {
|
if (message.isMms()) {
|
||||||
attachments = ((MmsMessageRecord)messageRecord).getSlideDeck().asAttachments();
|
attachments = ((MmsMessageRecord) message).getSlideDeck().asAttachments();
|
||||||
}
|
}
|
||||||
|
|
||||||
return Optional.of(new QuoteModel(quote.get().getId(), author, messageRecord.getBody(), attachments));
|
return Optional.of(new QuoteModel(quote.get().getId(), author, message.getBody(), attachments));
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Log.w(TAG, "Didn't find matching message record...");
|
Log.w(TAG, "Didn't find matching message record...");
|
||||||
|
|
||||||
return Optional.of(new QuoteModel(quote.get().getId(),
|
return Optional.of(new QuoteModel(quote.get().getId(),
|
||||||
author,
|
author,
|
||||||
quote.get().getText(),
|
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