Implement quotes in group chats

This commit is contained in:
Niels Andriesse 2019-09-11 15:52:32 +10:00
parent 7d1b4c363f
commit 88a5b7a87f
3 changed files with 39 additions and 21 deletions

View File

@ -406,11 +406,11 @@ public class ConversationFragment extends Fragment
menu.findItem(R.id.menu_context_copy).setVisible(!actionMessage && hasText); menu.findItem(R.id.menu_context_copy).setVisible(!actionMessage && hasText);
boolean isGroupChat = recipient.isGroupRecipient(); boolean isGroupChat = recipient.isGroupRecipient();
boolean isLokiPublicChat = recipient.getName() != null && recipient.getName().equals("Loki Public Chat");
if (isGroupChat) { 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()); LokiAPIDatabase lokiAPIDatabase = DatabaseFactory.getLokiAPIDatabase(getContext());
boolean isLokiPublicChat = recipient.getName().equals("Loki Public Chat");
int selectedMessageCount = messageRecords.size(); int selectedMessageCount = messageRecords.size();
boolean isSentByUser = ((MessageRecord)messageRecords.toArray()[0]).isOutgoing(); boolean isSentByUser = ((MessageRecord)messageRecords.toArray()[0]).isOutgoing();
boolean userCanModerate = lokiAPIDatabase.isModerator(LokiGroupChatAPI.getPublicChatServerID(), LokiGroupChatAPI.getPublicChatServer()); boolean userCanModerate = lokiAPIDatabase.isModerator(LokiGroupChatAPI.getPublicChatServerID(), LokiGroupChatAPI.getPublicChatServer());

View File

@ -305,7 +305,7 @@ public class PushDecryptJob extends BaseJob implements InjectableType {
if (message.isEndSession()) handleEndSessionMessage(content, smsMessageId); if (message.isEndSession()) handleEndSessionMessage(content, smsMessageId);
else if (message.isGroupUpdate()) handleGroupMessage(content, message, smsMessageId); else if (message.isGroupUpdate()) handleGroupMessage(content, message, smsMessageId);
else if (message.isExpirationUpdate()) handleExpirationUpdate(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()); else if (message.getBody().isPresent()) handleTextMessage(content, message, smsMessageId, Optional.absent());
if (message.getGroupInfo().isPresent() && groupDatabase.isUnknownGroup(GroupUtil.getEncodedId(message.getGroupInfo().get().getGroupId(), false))) { 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); MessageNotifier.updateNotification(context);
} }
private void handleMediaMessage(@NonNull SignalServiceContent content, public void handleMediaMessage(@NonNull SignalServiceContent content,
@NonNull SignalServiceDataMessage message, @NonNull SignalServiceDataMessage message,
@NonNull Optional<Long> smsMessageId) @NonNull Optional<Long> smsMessageId,
@Nullable Optional<Long> messageServerIDOrNull)
throws StorageFailedException throws StorageFailedException
{ {
notifyTypingStoppedFromIncomingMessage(getMessageDestination(content, message), content.getSender(), content.getSenderDevice()); notifyTypingStoppedFromIncomingMessage(getMessageDestination(content, message), content.getSender(), content.getSenderDevice());
@ -764,7 +765,7 @@ public class PushDecryptJob extends BaseJob implements InjectableType {
} }
if (c == linkPreviewCount) { if (c == linkPreviewCount) {
try { try {
handleMediaMessage(content, mediaMessage, smsMessageId); handleMediaMessage(content, mediaMessage, smsMessageId, messageServerIDOrNull);
} catch (Exception e) { } catch (Exception e) {
// TODO: Handle // TODO: Handle
} }
@ -772,14 +773,14 @@ public class PushDecryptJob extends BaseJob implements InjectableType {
})); }));
} }
} else { } else {
handleMediaMessage(content, mediaMessage, smsMessageId); handleMediaMessage(content, mediaMessage, smsMessageId, messageServerIDOrNull);
} }
} else { } else {
handleMediaMessage(content, mediaMessage, smsMessageId); handleMediaMessage(content, mediaMessage, smsMessageId, messageServerIDOrNull);
} }
} }
private void handleMediaMessage(@NonNull SignalServiceContent content, @NonNull IncomingMediaMessage mediaMessage, @NonNull Optional<Long> smsMessageID) throws StorageFailedException { private void handleMediaMessage(@NonNull SignalServiceContent content, @NonNull IncomingMediaMessage mediaMessage, @NonNull Optional<Long> smsMessageID, @Nullable Optional<Long> messageServerIDOrNull) throws StorageFailedException {
MmsDatabase database = DatabaseFactory.getMmsDatabase(context); MmsDatabase database = DatabaseFactory.getMmsDatabase(context);
database.beginTransaction(); database.beginTransaction();
@ -811,6 +812,12 @@ public class PushDecryptJob extends BaseJob implements InjectableType {
database.endTransaction(); 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()) { if (insertResult.isPresent()) {
MessageNotifier.updateNotification(context, insertResult.get().getThreadId()); 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 (lp.isPresent()) { mediaMessage.getLinkPreviews().add(lp.get()); }
if (c == urlCount) { if (c == urlCount) {
try { try {
handleMediaMessage(content, mediaMessage, smsMessageId); handleMediaMessage(content, mediaMessage, smsMessageId, messageServerIDOrNull);
} catch (Exception e) { } catch (Exception e) {
// TODO: Handle // TODO: Handle
} }

View File

@ -3,19 +3,15 @@ package org.thoughtcrime.securesms.loki
import android.content.Context import android.content.Context
import android.os.Handler import android.os.Handler
import android.util.Log 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.crypto.IdentityKeyUtil
import org.thoughtcrime.securesms.database.Address import org.thoughtcrime.securesms.database.Address
import org.thoughtcrime.securesms.database.DatabaseFactory import org.thoughtcrime.securesms.database.DatabaseFactory
import org.thoughtcrime.securesms.database.ThreadDatabase 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.jobs.PushDecryptJob
import org.thoughtcrime.securesms.linkpreview.LinkPreview
import org.thoughtcrime.securesms.linkpreview.LinkPreviewRepository import org.thoughtcrime.securesms.linkpreview.LinkPreviewRepository
import org.thoughtcrime.securesms.linkpreview.LinkPreviewUtil import org.thoughtcrime.securesms.linkpreview.LinkPreviewUtil
import org.thoughtcrime.securesms.mms.OutgoingMediaMessage import org.thoughtcrime.securesms.mms.OutgoingMediaMessage
import org.thoughtcrime.securesms.mms.QuoteModel
import org.thoughtcrime.securesms.recipients.Recipient import org.thoughtcrime.securesms.recipients.Recipient
import org.thoughtcrime.securesms.util.GroupUtil import org.thoughtcrime.securesms.util.GroupUtil
import org.thoughtcrime.securesms.util.TextSecurePreferences 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.LokiGroupChat
import org.whispersystems.signalservice.loki.api.LokiGroupChatAPI import org.whispersystems.signalservice.loki.api.LokiGroupChatAPI
import org.whispersystems.signalservice.loki.api.LokiGroupMessage import org.whispersystems.signalservice.loki.api.LokiGroupMessage
import java.util.*
class LokiGroupChatPoller(private val context: Context, private val group: LokiGroupChat) { class LokiGroupChatPoller(private val context: Context, private val group: LokiGroupChat) {
private val handler = Handler() private val handler = Handler()
@ -102,11 +97,21 @@ class LokiGroupChatPoller(private val context: Context, private val group: LokiG
fun processIncomingMessage(message: LokiGroupMessage) { fun processIncomingMessage(message: LokiGroupMessage) {
val id = group.id.toByteArray() val id = group.id.toByteArray()
val x1 = SignalServiceGroup(SignalServiceGroup.Type.UPDATE, id, null, null, null) 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 x3 = SignalServiceContent(x2, message.hexEncodedPublicKey, SignalServiceAddress.DEFAULT_DEVICE_ID, message.timestamp, false)
val senderDisplayName = "${message.displayName} (...${message.hexEncodedPublicKey.takeLast(8)})" val senderDisplayName = "${message.displayName} (...${message.hexEncodedPublicKey.takeLast(8)})"
DatabaseFactory.getLokiUserDatabase(context).setServerDisplayName(group.id, message.hexEncodedPublicKey, senderDisplayName) 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) { fun processOutgoingMessage(message: LokiGroupMessage) {
val messageServerID = message.serverID ?: return 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 id = group.id.toByteArray()
val mmsDatabase = DatabaseFactory.getMmsDatabase(context) val mmsDatabase = DatabaseFactory.getMmsDatabase(context)
val recipient = Recipient.from(context, Address.fromSerialized(GroupUtil.getEncodedId(id, false)), false) val recipient = Recipient.from(context, Address.fromSerialized(GroupUtil.getEncodedId(id, false)), false)
val signalMessage = OutgoingMediaMessage(recipient, message.body, ArrayList<Attachment>(), message.timestamp, 0, 0, ThreadDatabase.DistributionTypes.DEFAULT, val quote: QuoteModel?
null, ArrayList<Contact>(), ArrayList<LinkPreview>(), ArrayList<NetworkFailure>(), ArrayList<IdentityKeyMismatch>()) 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) val threadID = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(recipient)
fun finalize() { fun finalize() {
val messageID = mmsDatabase.insertMessageOutbox(signalMessage, threadID, false, null) val messageID = mmsDatabase.insertMessageOutbox(signalMessage, threadID, false, null)