From 88a5b7a87f4ea93291f79fe8e29bcac320aa9c4a Mon Sep 17 00:00:00 2001 From: Niels Andriesse Date: Wed, 11 Sep 2019 15:52:32 +1000 Subject: [PATCH] Implement quotes in group chats --- .../conversation/ConversationFragment.java | 4 +-- .../securesms/jobs/PushDecryptJob.java | 25 +++++++++------ .../securesms/loki/LokiGroupChatPoller.kt | 31 +++++++++++++------ 3 files changed, 39 insertions(+), 21 deletions(-) diff --git a/src/org/thoughtcrime/securesms/conversation/ConversationFragment.java b/src/org/thoughtcrime/securesms/conversation/ConversationFragment.java index 585dc5b01..1496074fb 100644 --- a/src/org/thoughtcrime/securesms/conversation/ConversationFragment.java +++ b/src/org/thoughtcrime/securesms/conversation/ConversationFragment.java @@ -406,11 +406,11 @@ public class ConversationFragment extends Fragment menu.findItem(R.id.menu_context_copy).setVisible(!actionMessage && hasText); boolean isGroupChat = recipient.isGroupRecipient(); + boolean isLokiPublicChat = recipient.getName() != null && recipient.getName().equals("Loki Public Chat"); if (isGroupChat) { - menu.findItem(R.id.menu_context_reply).setVisible(false); + menu.findItem(R.id.menu_context_reply).setVisible(isLokiPublicChat); LokiAPIDatabase lokiAPIDatabase = DatabaseFactory.getLokiAPIDatabase(getContext()); - boolean isLokiPublicChat = recipient.getName().equals("Loki Public Chat"); int selectedMessageCount = messageRecords.size(); boolean isSentByUser = ((MessageRecord)messageRecords.toArray()[0]).isOutgoing(); boolean userCanModerate = lokiAPIDatabase.isModerator(LokiGroupChatAPI.getPublicChatServerID(), LokiGroupChatAPI.getPublicChatServer()); diff --git a/src/org/thoughtcrime/securesms/jobs/PushDecryptJob.java b/src/org/thoughtcrime/securesms/jobs/PushDecryptJob.java index e23f87b8a..f741cc286 100644 --- a/src/org/thoughtcrime/securesms/jobs/PushDecryptJob.java +++ b/src/org/thoughtcrime/securesms/jobs/PushDecryptJob.java @@ -305,7 +305,7 @@ public class PushDecryptJob extends BaseJob implements InjectableType { if (message.isEndSession()) handleEndSessionMessage(content, smsMessageId); else if (message.isGroupUpdate()) handleGroupMessage(content, message, smsMessageId); else if (message.isExpirationUpdate()) handleExpirationUpdate(content, message, smsMessageId); - else if (isMediaMessage) handleMediaMessage(content, message, smsMessageId); + else if (isMediaMessage) handleMediaMessage(content, message, smsMessageId, Optional.absent()); else if (message.getBody().isPresent()) handleTextMessage(content, message, smsMessageId, Optional.absent()); if (message.getGroupInfo().isPresent() && groupDatabase.isUnknownGroup(GroupUtil.getEncodedId(message.getGroupInfo().get().getGroupId(), false))) { @@ -733,9 +733,10 @@ public class PushDecryptJob extends BaseJob implements InjectableType { MessageNotifier.updateNotification(context); } - private void handleMediaMessage(@NonNull SignalServiceContent content, - @NonNull SignalServiceDataMessage message, - @NonNull Optional smsMessageId) + public void handleMediaMessage(@NonNull SignalServiceContent content, + @NonNull SignalServiceDataMessage message, + @NonNull Optional smsMessageId, + @Nullable Optional messageServerIDOrNull) throws StorageFailedException { notifyTypingStoppedFromIncomingMessage(getMessageDestination(content, message), content.getSender(), content.getSenderDevice()); @@ -764,7 +765,7 @@ public class PushDecryptJob extends BaseJob implements InjectableType { } if (c == linkPreviewCount) { try { - handleMediaMessage(content, mediaMessage, smsMessageId); + handleMediaMessage(content, mediaMessage, smsMessageId, messageServerIDOrNull); } catch (Exception e) { // TODO: Handle } @@ -772,14 +773,14 @@ public class PushDecryptJob extends BaseJob implements InjectableType { })); } } else { - handleMediaMessage(content, mediaMessage, smsMessageId); + handleMediaMessage(content, mediaMessage, smsMessageId, messageServerIDOrNull); } } else { - handleMediaMessage(content, mediaMessage, smsMessageId); + handleMediaMessage(content, mediaMessage, smsMessageId, messageServerIDOrNull); } } - private void handleMediaMessage(@NonNull SignalServiceContent content, @NonNull IncomingMediaMessage mediaMessage, @NonNull Optional smsMessageID) throws StorageFailedException { + private void handleMediaMessage(@NonNull SignalServiceContent content, @NonNull IncomingMediaMessage mediaMessage, @NonNull Optional smsMessageID, @Nullable Optional messageServerIDOrNull) throws StorageFailedException { MmsDatabase database = DatabaseFactory.getMmsDatabase(context); database.beginTransaction(); @@ -811,6 +812,12 @@ public class PushDecryptJob extends BaseJob implements InjectableType { database.endTransaction(); } + if (insertResult.isPresent() && messageServerIDOrNull.isPresent()) { + long messageID = insertResult.get().getMessageId(); + long messageServerID = messageServerIDOrNull.get(); + DatabaseFactory.getLokiMessageDatabase(context).setServerID(messageID, messageServerID); + } + if (insertResult.isPresent()) { MessageNotifier.updateNotification(context, insertResult.get().getThreadId()); } @@ -963,7 +970,7 @@ public class PushDecryptJob extends BaseJob implements InjectableType { if (lp.isPresent()) { mediaMessage.getLinkPreviews().add(lp.get()); } if (c == urlCount) { try { - handleMediaMessage(content, mediaMessage, smsMessageId); + handleMediaMessage(content, mediaMessage, smsMessageId, messageServerIDOrNull); } catch (Exception e) { // TODO: Handle } diff --git a/src/org/thoughtcrime/securesms/loki/LokiGroupChatPoller.kt b/src/org/thoughtcrime/securesms/loki/LokiGroupChatPoller.kt index 4b6afca3f..b1bb313f9 100644 --- a/src/org/thoughtcrime/securesms/loki/LokiGroupChatPoller.kt +++ b/src/org/thoughtcrime/securesms/loki/LokiGroupChatPoller.kt @@ -3,19 +3,15 @@ package org.thoughtcrime.securesms.loki import android.content.Context import android.os.Handler import android.util.Log -import org.thoughtcrime.securesms.attachments.Attachment -import org.thoughtcrime.securesms.contactshare.Contact import org.thoughtcrime.securesms.crypto.IdentityKeyUtil import org.thoughtcrime.securesms.database.Address import org.thoughtcrime.securesms.database.DatabaseFactory import org.thoughtcrime.securesms.database.ThreadDatabase -import org.thoughtcrime.securesms.database.documents.IdentityKeyMismatch -import org.thoughtcrime.securesms.database.documents.NetworkFailure import org.thoughtcrime.securesms.jobs.PushDecryptJob -import org.thoughtcrime.securesms.linkpreview.LinkPreview import org.thoughtcrime.securesms.linkpreview.LinkPreviewRepository import org.thoughtcrime.securesms.linkpreview.LinkPreviewUtil import org.thoughtcrime.securesms.mms.OutgoingMediaMessage +import org.thoughtcrime.securesms.mms.QuoteModel import org.thoughtcrime.securesms.recipients.Recipient import org.thoughtcrime.securesms.util.GroupUtil import org.thoughtcrime.securesms.util.TextSecurePreferences @@ -28,7 +24,6 @@ import org.whispersystems.signalservice.api.push.SignalServiceAddress import org.whispersystems.signalservice.loki.api.LokiGroupChat import org.whispersystems.signalservice.loki.api.LokiGroupChatAPI import org.whispersystems.signalservice.loki.api.LokiGroupMessage -import java.util.* class LokiGroupChatPoller(private val context: Context, private val group: LokiGroupChat) { private val handler = Handler() @@ -102,11 +97,21 @@ class LokiGroupChatPoller(private val context: Context, private val group: LokiG fun processIncomingMessage(message: LokiGroupMessage) { val id = group.id.toByteArray() val x1 = SignalServiceGroup(SignalServiceGroup.Type.UPDATE, id, null, null, null) - val x2 = SignalServiceDataMessage(message.timestamp, x1, null, message.body) + val quote: SignalServiceDataMessage.Quote? + if (message.quote != null) { + quote = SignalServiceDataMessage.Quote(message.quote!!.quotedMessageTimestamp, SignalServiceAddress(message.quote!!.quoteeHexEncodedPublicKey), message.quote!!.quotedMessageBody, listOf()) + } else { + quote = null + } + val x2 = SignalServiceDataMessage(message.timestamp, x1, listOf(), message.body, false, 0, false, null, false, quote, null, null, null) val x3 = SignalServiceContent(x2, message.hexEncodedPublicKey, SignalServiceAddress.DEFAULT_DEVICE_ID, message.timestamp, false) val senderDisplayName = "${message.displayName} (...${message.hexEncodedPublicKey.takeLast(8)})" DatabaseFactory.getLokiUserDatabase(context).setServerDisplayName(group.id, message.hexEncodedPublicKey, senderDisplayName) - PushDecryptJob(context).handleTextMessage(x3, x2, Optional.absent(), Optional.of(message.serverID)) + if (quote != null) { + PushDecryptJob(context).handleMediaMessage(x3, x2, Optional.absent(), Optional.of(message.serverID)) + } else { + PushDecryptJob(context).handleTextMessage(x3, x2, Optional.absent(), Optional.of(message.serverID)) + } } fun processOutgoingMessage(message: LokiGroupMessage) { val messageServerID = message.serverID ?: return @@ -116,8 +121,14 @@ class LokiGroupChatPoller(private val context: Context, private val group: LokiG val id = group.id.toByteArray() val mmsDatabase = DatabaseFactory.getMmsDatabase(context) val recipient = Recipient.from(context, Address.fromSerialized(GroupUtil.getEncodedId(id, false)), false) - val signalMessage = OutgoingMediaMessage(recipient, message.body, ArrayList(), message.timestamp, 0, 0, ThreadDatabase.DistributionTypes.DEFAULT, - null, ArrayList(), ArrayList(), ArrayList(), ArrayList()) + val quote: QuoteModel? + if (message.quote != null) { + quote = QuoteModel(message.quote!!.quotedMessageTimestamp, Address.fromSerialized(message.quote!!.quoteeHexEncodedPublicKey), message.quote!!.quotedMessageBody, false, listOf()) + } else { + quote = null + } + val signalMessage = OutgoingMediaMessage(recipient, message.body, listOf(), message.timestamp, 0, 0, + ThreadDatabase.DistributionTypes.DEFAULT, quote, listOf(), listOf(), listOf(), listOf()) val threadID = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(recipient) fun finalize() { val messageID = mmsDatabase.insertMessageOutbox(signalMessage, threadID, false, null)