This commit is contained in:
alansley 2024-08-21 06:20:40 +10:00 committed by fanchao
parent c4f0854335
commit b60517f382
4 changed files with 38 additions and 9 deletions

View File

@ -1355,8 +1355,7 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe
// Method to add an emoji to a queue and remove it a short while later - this is used as a // Method to add an emoji to a queue and remove it a short while later - this is used as a
// rate-limiting mechanism and is called from the `sendEmojiReaction` method, below. // rate-limiting mechanism and is called from the `sendEmojiReaction` method, below.
private fun canPerformEmojiReaction(timestamp: Long): Boolean {
fun canPerformEmojiReaction(timestamp: Long): Boolean {
// If the emoji reaction queue is full.. // If the emoji reaction queue is full..
if (emojiRateLimiterQueue.size >= EMOJI_REACTIONS_ALLOWED_PER_MINUTE) { if (emojiRateLimiterQueue.size >= EMOJI_REACTIONS_ALLOWED_PER_MINUTE) {
// ..grab the timestamp of the oldest emoji reaction. // ..grab the timestamp of the oldest emoji reaction.
@ -1421,15 +1420,24 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe
// Send it // Send it
reactionMessage.reaction = Reaction.from(originalMessage.timestamp, originalAuthor.serialize(), emoji, true) reactionMessage.reaction = Reaction.from(originalMessage.timestamp, originalAuthor.serialize(), emoji, true)
if (recipient.isCommunityRecipient) {
// If this is a community then we need to send it to the server
if (recipient.isCommunityRecipient) {
val messageServerId = lokiMessageDb.getServerID(originalMessage.id, !originalMessage.isMms) ?: val messageServerId = lokiMessageDb.getServerID(originalMessage.id, !originalMessage.isMms) ?:
return Log.w(TAG, "Failed to find message server ID when adding emoji reaction") return Log.w(TAG, "Failed to find message server ID when adding emoji reaction")
viewModel.openGroup?.let { viewModel.openGroup?.let { OpenGroupApi.addReaction(it.room, it.server, messageServerId, emoji) }
OpenGroupApi.addReaction(it.room, it.server, messageServerId, emoji)
}
} else { } else {
// Send a notification regarding the emoji reaction, but ONLY if this is a contact (i.e., a 1-on-1 conversation), we
// do NOT send notifications for emoji reactions to closed groups or communities!
if (recipient.isContactRecipient) {
Log.w("ACL", "Sending notification for emoji reaction")
//ApplicationContext.getInstance(this@ConversationActivityV2).messageNotifier.updateNotification(this@ConversationActivityV2, messageRecord.threadId, true)
ApplicationContext.getInstance(this@ConversationActivityV2).messageNotifier.updateNotification(this@ConversationActivityV2, true, 0)
}
Log.w("ACL", "reactionMessage is: " + reactionMessage.text)
MessageSender.send(reactionMessage, recipient.address) MessageSender.send(reactionMessage, recipient.address)
} }

View File

@ -456,6 +456,7 @@ class DefaultMessageNotifier : MessageNotifier {
Log.i(TAG, "Posted notification. $notification") Log.i(TAG, "Posted notification. $notification")
} }
// Note: The only use of this method is from `updateNotification`, above.
private fun constructNotificationState(context: Context, cursor: Cursor): NotificationState { private fun constructNotificationState(context: Context, cursor: Cursor): NotificationState {
val notificationState = NotificationState() val notificationState = NotificationState()
val reader = get(context).mmsSmsDatabase().readerFor(cursor) val reader = get(context).mmsSmsDatabase().readerFor(cursor)
@ -510,19 +511,19 @@ class DefaultMessageNotifier : MessageNotifier {
val contact = (record as MmsMessageRecord).sharedContacts[0] val contact = (record as MmsMessageRecord).sharedContacts[0]
body = ContactUtil.getStringSummary(context, contact) body = ContactUtil.getStringSummary(context, contact)
// If this is a notification about a multimedia message which contains no text but DOES contain a slide deck with at least one slide.. // If this is a notification about a multimedia message which contains no text but DOES contain a slide deck with at least one slide..
} else if (record.isMms && TextUtils.isEmpty(body) && !(record as MmsMessageRecord).slideDeck.slides.isEmpty()) { } else if (record.isMms && TextUtils.isEmpty(body) && !(record as MmsMessageRecord).slideDeck.slides.isEmpty()) {
slideDeck = (record as MediaMmsMessageRecord).slideDeck slideDeck = (record as MediaMmsMessageRecord).slideDeck
body = SpanUtil.italic(slideDeck.body) body = SpanUtil.italic(slideDeck.body)
// If this is a notification about a multimedia message, but it's not ITSELF a multimedia notification AND it contains a slide deck with at least one slide.. // If this is a notification about a multimedia message, but it's not ITSELF a multimedia notification AND it contains a slide deck with at least one slide..
} else if (record.isMms && !record.isMmsNotification && !(record as MmsMessageRecord).slideDeck.slides.isEmpty()) { } else if (record.isMms && !record.isMmsNotification && !(record as MmsMessageRecord).slideDeck.slides.isEmpty()) {
slideDeck = (record as MediaMmsMessageRecord).slideDeck slideDeck = (record as MediaMmsMessageRecord).slideDeck
val message = slideDeck.body + ": " + record.body val message = slideDeck.body + ": " + record.body
val italicLength = message.length - body.length val italicLength = message.length - body.length
body = SpanUtil.italic(message, italicLength) body = SpanUtil.italic(message, italicLength)
// If this is a notification about an invitation to a community.. // If this is a notification about an invitation to a community..
} else if (record.isOpenGroupInvitation) { } else if (record.isOpenGroupInvitation) {
body = SpanUtil.italic(context.getString(R.string.communityInvitation)) body = SpanUtil.italic(context.getString(R.string.communityInvitation))
} }
@ -533,7 +534,11 @@ class DefaultMessageNotifier : MessageNotifier {
blindedPublicKey = generateBlindedId(threadId, context) blindedPublicKey = generateBlindedId(threadId, context)
cache[threadId] = blindedPublicKey cache[threadId] = blindedPublicKey
} }
// Only proceed with notifications if the thread is not muted
if (threadRecipients == null || !threadRecipients.isMuted) { if (threadRecipients == null || !threadRecipients.isMuted) {
// If this notification is regarding a mention..
if (threadRecipients != null && threadRecipients.notifyType == RecipientDatabase.NOTIFY_TYPE_MENTIONS) { if (threadRecipients != null && threadRecipients.notifyType == RecipientDatabase.NOTIFY_TYPE_MENTIONS) {
// check if mentioned here // check if mentioned here
var isQuoteMentioned = false var isQuoteMentioned = false
@ -547,9 +552,14 @@ class DefaultMessageNotifier : MessageNotifier {
if (body.toString().contains("@$userPublicKey") || body.toString().contains("@$blindedPublicKey") || isQuoteMentioned) { if (body.toString().contains("@$userPublicKey") || body.toString().contains("@$blindedPublicKey") || isQuoteMentioned) {
notificationState.addNotification(NotificationItem(id, mms, recipient, conversationRecipient, threadRecipients, threadId, body, timestamp, slideDeck)) notificationState.addNotification(NotificationItem(id, mms, recipient, conversationRecipient, threadRecipients, threadId, body, timestamp, slideDeck))
} }
// ..if this notification is regarding a thread..
} else if (threadRecipients != null && threadRecipients.notifyType == RecipientDatabase.NOTIFY_TYPE_NONE) { } else if (threadRecipients != null && threadRecipients.notifyType == RecipientDatabase.NOTIFY_TYPE_NONE) {
Log.w("ACL", "Hit the notify type NONE block.")
// do nothing, no notifications // do nothing, no notifications
} else { } else {
// If this notification is not a mention or thread notification then it must be RecipientDatabase.NOTIFY_TYPE_ALL because those are the only three enums.
// Note: This is the block that hits for 1-on-1 message notifications
Log.w("ACL", "Hit the notify type ALL block")
notificationState.addNotification(NotificationItem(id, mms, recipient, conversationRecipient, threadRecipients, threadId, body, timestamp, slideDeck)) notificationState.addNotification(NotificationItem(id, mms, recipient, conversationRecipient, threadRecipients, threadId, body, timestamp, slideDeck))
} }

View File

@ -132,8 +132,10 @@ object MessageReceiver {
if (isBlocked(sender!!)) { if (isBlocked(sender!!)) {
throw Error.SenderBlocked throw Error.SenderBlocked
} }
// Parse the proto // Parse the proto
val proto = SignalServiceProtos.Content.parseFrom(PushTransportDetails.getStrippedPaddingMessageBody(plaintext)) val proto = SignalServiceProtos.Content.parseFrom(PushTransportDetails.getStrippedPaddingMessageBody(plaintext))
// Parse the message // Parse the message
val message: Message = ReadReceipt.fromProto(proto) ?: val message: Message = ReadReceipt.fromProto(proto) ?:
TypingIndicator.fromProto(proto) ?: TypingIndicator.fromProto(proto) ?:
@ -155,10 +157,12 @@ object MessageReceiver {
if (!message.isSelfSendValid) throw Error.SelfSend if (!message.isSelfSendValid) throw Error.SelfSend
message.isSenderSelf = true message.isSenderSelf = true
} }
// Guard against control messages in open groups // Guard against control messages in open groups
if (isOpenGroupMessage && message !is VisibleMessage) { if (isOpenGroupMessage && message !is VisibleMessage) {
throw Error.InvalidMessage throw Error.InvalidMessage
} }
// Finish parsing // Finish parsing
message.sender = sender message.sender = sender
message.recipient = userPublicKey message.recipient = userPublicKey
@ -166,18 +170,21 @@ object MessageReceiver {
message.receivedTimestamp = if (envelope.hasServerTimestamp()) envelope.serverTimestamp else SnodeAPI.nowWithOffset message.receivedTimestamp = if (envelope.hasServerTimestamp()) envelope.serverTimestamp else SnodeAPI.nowWithOffset
message.groupPublicKey = groupPublicKey message.groupPublicKey = groupPublicKey
message.openGroupServerMessageID = openGroupServerID message.openGroupServerMessageID = openGroupServerID
// Validate // Validate
var isValid = message.isValid() var isValid = message.isValid()
if (message is VisibleMessage && !isValid && proto.dataMessage.attachmentsCount != 0) { isValid = true } if (message is VisibleMessage && !isValid && proto.dataMessage.attachmentsCount != 0) { isValid = true }
if (!isValid) { if (!isValid) {
throw Error.InvalidMessage throw Error.InvalidMessage
} }
// If the message failed to process the first time around we retry it later (if the error is retryable). In this case the timestamp // If the message failed to process the first time around we retry it later (if the error is retryable). In this case the timestamp
// will already be in the database but we don't want to treat the message as a duplicate. The isRetry flag is a simple workaround // will already be in the database but we don't want to treat the message as a duplicate. The isRetry flag is a simple workaround
// for this issue. // for this issue.
if (groupPublicKey != null && groupPublicKey !in (currentClosedGroups ?: emptySet())) { if (groupPublicKey != null && groupPublicKey !in (currentClosedGroups ?: emptySet())) {
throw Error.NoGroupThread throw Error.NoGroupThread
} }
if ((message is ClosedGroupControlMessage && message.kind is ClosedGroupControlMessage.Kind.New) || message is SharedConfigurationMessage) { if ((message is ClosedGroupControlMessage && message.kind is ClosedGroupControlMessage.Kind.New) || message is SharedConfigurationMessage) {
// Allow duplicates in this case to avoid the following situation: // Allow duplicates in this case to avoid the following situation:
// • The app performed a background poll or received a push notification // • The app performed a background poll or received a push notification
@ -189,6 +196,7 @@ object MessageReceiver {
if (storage.isDuplicateMessage(envelope.timestamp)) { throw Error.DuplicateMessage } if (storage.isDuplicateMessage(envelope.timestamp)) { throw Error.DuplicateMessage }
storage.addReceivedMessageTimestamp(envelope.timestamp) storage.addReceivedMessageTimestamp(envelope.timestamp)
} }
// Return // Return
return Pair(message, proto) return Pair(message, proto)
} }

View File

@ -286,6 +286,9 @@ fun MessageReceiver.handleVisibleMessage(
runThreadUpdate: Boolean, runThreadUpdate: Boolean,
runProfileUpdate: Boolean runProfileUpdate: Boolean
): Long? { ): Long? {
Is this where emoji reacts come in? If so we need to spawn a notification here!
val storage = MessagingModuleConfiguration.shared.storage val storage = MessagingModuleConfiguration.shared.storage
val context = MessagingModuleConfiguration.shared.context val context = MessagingModuleConfiguration.shared.context
message.takeIf { it.isSenderSelf }?.sentTimestamp?.let { MessagingModuleConfiguration.shared.lastSentTimestampCache.submitTimestamp(threadId, it) } message.takeIf { it.isSenderSelf }?.sentTimestamp?.let { MessagingModuleConfiguration.shared.lastSentTimestampCache.submitTimestamp(threadId, it) }