From dfae580ffa0dc6e34536403e0a4082d2cca67ebd Mon Sep 17 00:00:00 2001 From: Mikunj Date: Thu, 15 Nov 2018 11:13:55 +1100 Subject: [PATCH 1/5] Added notification when receiving a friend request and when a friend request was accepted. --- js/models/conversations.js | 30 ++++++++++++++++++++++-------- js/models/messages.js | 1 + 2 files changed, 23 insertions(+), 8 deletions(-) diff --git a/js/models/conversations.js b/js/models/conversations.js index 34384145a..ee8382a99 100644 --- a/js/models/conversations.js +++ b/js/models/conversations.js @@ -487,6 +487,20 @@ } await this.updatePendingFriendRequests(); + + this.getNotificationIcon().then(iconUrl => { + window.log.info('Add notification for friend request updated', { + conversationId: this.idForLogging(), + }); + Whisper.Notifications.add({ + conversationId: this.id, + iconUrl, + isExpiringMessage: false, + message: `Accepted your friend request`, + messageSentAt: Date.now(), + title: this.getTitle(), + }); + }); }, async onFriendRequestTimedOut() { this.updateTextInputState(); @@ -755,14 +769,14 @@ const id = await window.Signal.Data.saveMessage(message, { Message: Whisper.Message, }); + + const whisperMessage = new Whisper.Message({ + ...message, + id, + }); - this.trigger( - 'newmessage', - new Whisper.Message({ - ...message, - id, - }) - ); + this.trigger('newmessage', whisperMessage); + this.notify(whisperMessage); }, async addVerifiedChange(verifiedChangeId, verified, providedOptions) { const options = providedOptions || {}; @@ -2027,7 +2041,7 @@ }, notify(message) { - if (!message.isIncoming()) { + if (!(message.isIncoming() || message.isFriendRequest())) { return Promise.resolve(); } const conversationId = this.id; diff --git a/js/models/messages.js b/js/models/messages.js index a12e78cb0..bce16382f 100644 --- a/js/models/messages.js +++ b/js/models/messages.js @@ -192,6 +192,7 @@ getNotificationText() { const description = this.getDescription(); if (description) { + if (this.isFriendRequest()) return `Friend Request: ${description}`; return description; } if (this.get('attachments').length > 0) { From 061b8ab2cb02a144b728406c7ed00743ebba1c61 Mon Sep 17 00:00:00 2001 From: Mikunj Date: Thu, 15 Nov 2018 11:46:38 +1100 Subject: [PATCH 2/5] Added function to help friend request notifications --- _locales/en/messages.json | 30 ++++++++++++++++++++ js/models/conversations.js | 56 ++++++++++++++++++++++++++++---------- 2 files changed, 71 insertions(+), 15 deletions(-) diff --git a/_locales/en/messages.json b/_locales/en/messages.json index c3bf9d532..fe19c3d27 100644 --- a/_locales/en/messages.json +++ b/_locales/en/messages.json @@ -1589,5 +1589,35 @@ "friendRequestDeclined": { "message": "Friend request declined", "description": "Shown in the conversation history when the user declines a friend request" + }, + "friendRequestNotificationTitle": { + "message": "Friend request", + "description": "Shown in a notification title when receiving a friend request" + }, + "friendRequestNotificationMessage": { + "message": "$name$ sent you a friend request", + "description": + "Shown in a notification body when receiving a friend request", + "placeholders": { + "name": { + "content": "$1", + "example": "Bob" + } + } + }, + "friendRequestAcceptedNotificationTitle": { + "message": "Friend request accepted", + "description": "Shown in a notification title when friend request was accepted by the other user" + }, + "friendRequestAcceptedNotificationMessage": { + "message": "$name$ accepted your friend request", + "description": + "Shown in a notification body when friend request was accepted by the other user", + "placeholders": { + "name": { + "content": "$1", + "example": "Bob" + } + } } } diff --git a/js/models/conversations.js b/js/models/conversations.js index ee8382a99..6d36b8eec 100644 --- a/js/models/conversations.js +++ b/js/models/conversations.js @@ -487,20 +487,8 @@ } await this.updatePendingFriendRequests(); - - this.getNotificationIcon().then(iconUrl => { - window.log.info('Add notification for friend request updated', { - conversationId: this.idForLogging(), - }); - Whisper.Notifications.add({ - conversationId: this.id, - iconUrl, - isExpiringMessage: false, - message: `Accepted your friend request`, - messageSentAt: Date.now(), - title: this.getTitle(), - }); - }); + + this.notifyFriendRequest(this.id, 'accepted') }, async onFriendRequestTimedOut() { this.updateTextInputState(); @@ -2041,7 +2029,8 @@ }, notify(message) { - if (!(message.isIncoming() || message.isFriendRequest())) { + if (!message.isIncoming()) { + if (message.isFriendRequest()) return this.notifyFriendRequest(message.get('source'), 'requested'); return Promise.resolve(); } const conversationId = this.id; @@ -2073,6 +2062,43 @@ }) ); }, + // Notification for friend request received + async notifyFriendRequest(source, type) { + // Data validation + if (!source) return Promise.reject('Invalid source'); + if (!['accepted', 'requested'].includes(type)) return Promise.reject('Type must be accepted or requested.'); + + // Call the notification on the right conversation + let conversation = this; + if (conversation.id !== source) { + try { + conversation = await ConversationController.getOrCreateAndWait( + source, + 'private' + ); + } catch (e) { + return Promise.reject('Failed to fetch conversation'); + } + } + + const isTypeAccepted = type === 'accepted'; + const title = isTypeAccepted ? 'friendRequestAcceptedNotificationTitle' : 'friendRequestNotificationTitle'; + const message = isTypeAccepted ? 'friendRequestAcceptedNotificationMessage' : 'friendRequestNotificationMessage'; + + conversation.getNotificationIcon().then(iconUrl => { + window.log.info('Add notification for friend request updated', { + conversationId: conversation.idForLogging(), + }); + Whisper.Notifications.add({ + conversationId: conversation.id, + iconUrl, + isExpiringMessage: false, + message: i18n(message, conversation.getTitle()), + messageSentAt: Date.now(), + title: i18n(title), + }); + }); + }, }); Whisper.ConversationCollection = Backbone.Collection.extend({ From 745d0e82d4c0789659698ab4a5348d3f2fa74c5f Mon Sep 17 00:00:00 2001 From: Mikunj Date: Thu, 15 Nov 2018 12:01:25 +1100 Subject: [PATCH 3/5] Added unread count badge . --- js/models/conversations.js | 6 +++++- libtextsecure/message_receiver.js | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/js/models/conversations.js b/js/models/conversations.js index 6d36b8eec..bcd00d8af 100644 --- a/js/models/conversations.js +++ b/js/models/conversations.js @@ -460,10 +460,13 @@ } } }, - async onFriendRequestAccepted() { + async onFriendRequestAccepted(updateUnread = false) { + // Make sure we don't keep incrementing the unread count + const unreadCount = this.isKeyExchangeCompleted() || !updateUnread ? {} : { unreadCount: this.get('unreadCount') + 1 }; this.set({ friendRequestStatus: null, keyExchangeCompleted: true, + ...unreadCount }); await window.Signal.Data.updateConversation(this.id, this.attributes, { @@ -715,6 +718,7 @@ this.set({ active_at: Date.now(), timestamp: Date.now(), + unreadCount: this.get('unreadCount') + 1, }); await window.Signal.Data.updateConversation(this.id, this.attributes, { diff --git a/libtextsecure/message_receiver.js b/libtextsecure/message_receiver.js index 3690ecc43..080b22888 100644 --- a/libtextsecure/message_receiver.js +++ b/libtextsecure/message_receiver.js @@ -1028,7 +1028,7 @@ MessageReceiver.prototype.extend({ ); // Update the conversation - await conversation.onFriendRequestAccepted(); + await conversation.onFriendRequestAccepted(true); } } } From 4f4ebf3ddd6536546885b08a3531abe4c1e22105 Mon Sep 17 00:00:00 2001 From: Mikunj Date: Thu, 15 Nov 2018 14:22:38 +1100 Subject: [PATCH 4/5] Added an info log on graceful conversation fallback, --- js/models/conversations.js | 1 + 1 file changed, 1 insertion(+) diff --git a/js/models/conversations.js b/js/models/conversations.js index bcd00d8af..19e701c98 100644 --- a/js/models/conversations.js +++ b/js/models/conversations.js @@ -2080,6 +2080,7 @@ source, 'private' ); + window.log.info(`Notify called on a different conversation. expected: ${this.id}. actual: ${conversation.id}`); } catch (e) { return Promise.reject('Failed to fetch conversation'); } From 17e5c861a141f5510377e0396f3f8570a4520a1e Mon Sep 17 00:00:00 2001 From: Mikunj Date: Fri, 16 Nov 2018 13:35:50 +1100 Subject: [PATCH 5/5] Fixed review issues. Fixed lint error. --- js/models/conversations.js | 26 ++++++++++++++------------ js/models/messages.js | 3 ++- libtextsecure/message_receiver.js | 4 ++-- 3 files changed, 18 insertions(+), 15 deletions(-) diff --git a/js/models/conversations.js b/js/models/conversations.js index 19e701c98..ab1429e5c 100644 --- a/js/models/conversations.js +++ b/js/models/conversations.js @@ -460,13 +460,13 @@ } } }, - async onFriendRequestAccepted(updateUnread = false) { + async onFriendRequestAccepted({ updateUnread }) { // Make sure we don't keep incrementing the unread count const unreadCount = this.isKeyExchangeCompleted() || !updateUnread ? {} : { unreadCount: this.get('unreadCount') + 1 }; this.set({ friendRequestStatus: null, keyExchangeCompleted: true, - ...unreadCount + ...unreadCount, }); await window.Signal.Data.updateConversation(this.id, this.attributes, { @@ -478,16 +478,17 @@ // Update any pending outgoing messages const pending = await this.getPendingFriendRequests('outgoing'); - for (const request of pending) { - // Only update successfully sent requests - if (request.hasErrors()) continue; + await Promise.all( + pending.map(async request => { + if (request.hasErrors()) return; - request.set({ friendStatus: 'accepted' }); - await window.Signal.Data.saveMessage(request.attributes, { - Message: Whisper.Message, - }); - this.trigger('updateMessage', request); - } + request.set({ friendStatus: 'accepted' }); + await window.Signal.Data.saveMessage(request.attributes, { + Message: Whisper.Message, + }); + this.trigger('updateMessage', request); + }) + ); await this.updatePendingFriendRequests(); @@ -2034,7 +2035,8 @@ notify(message) { if (!message.isIncoming()) { - if (message.isFriendRequest()) return this.notifyFriendRequest(message.get('source'), 'requested'); + if (message.isFriendRequest()) + return this.notifyFriendRequest(message.get('source'), 'requested'); return Promise.resolve(); } const conversationId = this.id; diff --git a/js/models/messages.js b/js/models/messages.js index bce16382f..95b6afe73 100644 --- a/js/models/messages.js +++ b/js/models/messages.js @@ -192,7 +192,8 @@ getNotificationText() { const description = this.getDescription(); if (description) { - if (this.isFriendRequest()) return `Friend Request: ${description}`; + if (this.isFriendRequest()) + return `Friend Request: ${description}`; return description; } if (this.get('attachments').length > 0) { diff --git a/libtextsecure/message_receiver.js b/libtextsecure/message_receiver.js index 080b22888..ac67f1b10 100644 --- a/libtextsecure/message_receiver.js +++ b/libtextsecure/message_receiver.js @@ -1024,11 +1024,11 @@ MessageReceiver.prototype.extend({ if (savePreKey) { await this.handlePreKeyBundleMessage( envelope.source, - this.decodePreKeyBundleMessage(content.preKeyBundleMessage), + this.decodePreKeyBundleMessage(content.preKeyBundleMessage) ); // Update the conversation - await conversation.onFriendRequestAccepted(true); + await conversation.onFriendRequestAccepted({ updateUnread: true }); } } }