Skip to content

Commit c21d91e

Browse files
authored
fix: push notification titles and avatars for discussions and threads (RocketChat#6900)
1 parent 1fe0bf7 commit c21d91e

File tree

4 files changed

+40
-64
lines changed

4 files changed

+40
-64
lines changed

android/app/src/main/java/chat/rocket/reactnative/notification/CustomPushNotification.java

Lines changed: 12 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ public void onReceived() {
9595

9696
private void handleNotification() {
9797
Ejson receivedEjson = safeFromJson(mBundle.getString("ejson", "{}"), Ejson.class);
98-
98+
9999
if (receivedEjson != null && receivedEjson.notificationType != null && receivedEjson.notificationType.equals("message-id-only")) {
100100
Log.d(TAG, "Detected message-id-only notification, will fetch full content from server");
101101
loadNotificationAndProcess(receivedEjson);
@@ -202,8 +202,12 @@ private void showNotification(Bundle bundle, Ejson ejson, String notId) {
202202
boolean hasSender = ejson != null && ejson.sender != null;
203203
String title = bundle.getString("title");
204204

205+
String displaySenderName = (ejson != null && ejson.senderName != null && !ejson.senderName.isEmpty())
206+
? ejson.senderName
207+
: (hasSender ? ejson.sender.username : title);
208+
205209
bundle.putLong("time", new Date().getTime());
206-
bundle.putString("username", hasSender ? ejson.sender.username : title);
210+
bundle.putString("username", displaySenderName);
207211
bundle.putString("senderId", hasSender ? ejson.sender._id : "1");
208212

209213
String avatarUri = ejson != null ? ejson.getAvatarUri() : null;
@@ -291,19 +295,6 @@ private Notification.Builder buildNotification(int notificationId) {
291295

292296
// Determine the correct title based on notification type
293297
String notificationTitle = title;
294-
if (ejson != null && ejson.type != null) {
295-
if ("p".equals(ejson.type) || "c".equals(ejson.type)) {
296-
// For groups/channels, use room name if available, otherwise fall back to title
297-
notificationTitle = (ejson.name != null && !ejson.name.isEmpty()) ? ejson.name : title;
298-
} else if ("d".equals(ejson.type)) {
299-
// For direct messages, use title (sender name from server)
300-
notificationTitle = title;
301-
} else if ("l".equals(ejson.type)) {
302-
// For omnichannel, use sender name if available, otherwise fall back to title
303-
notificationTitle = (ejson.sender != null && ejson.sender.name != null && !ejson.sender.name.isEmpty())
304-
? ejson.sender.name : title;
305-
}
306-
}
307298

308299
if (ENABLE_VERBOSE_LOGS) {
309300
Log.d(TAG, "[buildNotification] notId=" + notId);
@@ -465,19 +456,6 @@ private void notificationStyle(Notification.Builder notification, int notId, Bun
465456
// Determine the correct conversation title based on notification type
466457
Ejson bundleEjson = safeFromJson(bundle.getString("ejson", "{}"), Ejson.class);
467458
String conversationTitle = title;
468-
if (bundleEjson != null && bundleEjson.type != null) {
469-
if ("p".equals(bundleEjson.type) || "c".equals(bundleEjson.type)) {
470-
// For groups/channels, use room name if available, otherwise fall back to title
471-
conversationTitle = (bundleEjson.name != null && !bundleEjson.name.isEmpty()) ? bundleEjson.name : title;
472-
} else if ("d".equals(bundleEjson.type)) {
473-
// For direct messages, use title (sender name from server)
474-
conversationTitle = title;
475-
} else if ("l".equals(bundleEjson.type)) {
476-
// For omnichannel, use sender name if available, otherwise fall back to title
477-
conversationTitle = (bundleEjson.sender != null && bundleEjson.sender.name != null && !bundleEjson.sender.name.isEmpty())
478-
? bundleEjson.sender.name : title;
479-
}
480-
}
481459
messageStyle.setConversationTitle(conversationTitle);
482460

483461
if (bundles != null) {
@@ -489,15 +467,17 @@ private void notificationStyle(Notification.Builder notification, int notId, Bun
489467
Ejson ejson = safeFromJson(data.getString("ejson", "{}"), Ejson.class);
490468
String m = extractMessage(message, ejson);
491469

470+
String displaySenderName = (ejson != null && ejson.senderName != null && !ejson.senderName.isEmpty())
471+
? ejson.senderName
472+
: (ejson != null && ejson.sender != null ? ejson.sender.username : title);
473+
492474
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.P) {
493-
String senderName = ejson != null ? ejson.senderName : "Unknown";
494-
messageStyle.addMessage(m, timestamp, senderName);
475+
messageStyle.addMessage(m, timestamp, displaySenderName);
495476
} else {
496477
Bitmap avatar = getAvatar(avatarUri);
497-
String senderName = ejson != null ? ejson.senderName : "Unknown";
498478
Person.Builder senderBuilder = new Person.Builder()
499479
.setKey(senderId)
500-
.setName(senderName);
480+
.setName(displaySenderName);
501481

502482
if (avatar != null) {
503483
senderBuilder.setIcon(Icon.createWithBitmap(avatar));

android/app/src/main/java/chat/rocket/reactnative/notification/Ejson.java

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -67,20 +67,18 @@ private String buildAvatarUri(String avatarPath, String errorContext) {
6767
String userToken = token();
6868
String uid = userId();
6969

70-
if (userToken.isEmpty() || uid.isEmpty()) {
71-
Log.w(TAG, "Cannot generate " + errorContext + " avatar URI: missing auth credentials");
72-
return null;
70+
String finalUri = server + avatarPath + "?format=png&size=100";
71+
if (!userToken.isEmpty() && !uid.isEmpty()) {
72+
finalUri += "&rc_token=" + userToken + "&rc_uid=" + uid;
7373
}
7474

75-
return server + avatarPath + "?format=png&size=100&rc_token=" + userToken + "&rc_uid=" + uid;
75+
return finalUri;
7676
}
7777

7878
public String getAvatarUri() {
7979
String avatarPath;
8080

81-
// For DMs, show sender's avatar; for groups/channels, show room avatar
8281
if ("d".equals(type)) {
83-
// Direct message: use sender's avatar
8482
if (sender == null || sender.username == null || sender.username.isEmpty()) {
8583
Log.w(TAG, "Cannot generate avatar URI: sender or username is null");
8684
return null;
@@ -92,7 +90,6 @@ public String getAvatarUri() {
9290
return null;
9391
}
9492
} else {
95-
// Group/Channel/Livechat: use room avatar
9693
if (rid == null || rid.isEmpty()) {
9794
Log.w(TAG, "Cannot generate avatar URI: rid is null for non-DM");
9895
return null;

android/app/src/main/java/chat/rocket/reactnative/notification/VideoConfNotification.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -91,11 +91,11 @@ class VideoConfNotification(private val context: Context) {
9191

9292
if (ejson.caller != null) {
9393
callerId = ejson.caller._id ?: ""
94-
callerName = ejson.caller.name ?: "Unknown"
94+
callerName = ejson.senderName ?: ejson.caller.name ?: "Unknown"
9595
} else if (ejson.sender != null) {
9696
// Fallback to sender if caller is not present
9797
callerId = ejson.sender._id ?: ""
98-
callerName = ejson.sender.name ?: ejson.senderName ?: "Unknown"
98+
callerName = ejson.senderName ?: ejson.sender.name ?: "Unknown"
9999
} else {
100100
callerId = ""
101101
callerName = "Unknown"

ios/NotificationService/NotificationService.swift

Lines changed: 22 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -14,22 +14,21 @@ class NotificationService: UNNotificationServiceExtension {
1414
self.contentHandler = contentHandler
1515
bestAttemptContent = (request.content.mutableCopy() as? UNMutableNotificationContent)
1616

17-
guard let bestAttemptContent = bestAttemptContent,
18-
let ejsonString = bestAttemptContent.userInfo["ejson"] as? String,
19-
let ejson = ejsonString.data(using: .utf8),
20-
let payload = try? JSONDecoder().decode(Payload.self, from: ejson) else {
21-
contentHandler(request.content)
22-
return
23-
}
24-
25-
rocketchat = RocketChat(server: payload.host.removeTrailingSlash())
26-
27-
if payload.notificationType == .videoconf {
28-
processVideoConf(payload: payload)
29-
} else if payload.notificationType == .messageIdOnly {
30-
fetchMessageContent(payload: payload)
17+
if let bestAttemptContent = bestAttemptContent,
18+
let ejsonString = bestAttemptContent.userInfo["ejson"] as? String,
19+
let ejson = ejsonString.data(using: .utf8),
20+
let payload = try? JSONDecoder().decode(Payload.self, from: ejson) {
21+
rocketchat = RocketChat(server: payload.host.removeTrailingSlash())
22+
23+
if payload.notificationType == .videoconf {
24+
processVideoConf(payload: payload)
25+
} else if payload.notificationType == .messageIdOnly {
26+
fetchMessageContent(payload: payload)
27+
} else {
28+
processPayload(payload: payload)
29+
}
3130
} else {
32-
processPayload(payload: payload)
31+
contentHandler(request.content)
3332
}
3433
}
3534

@@ -49,7 +48,7 @@ class NotificationService: UNNotificationServiceExtension {
4948
}
5049

5150
// 1. Setup Basic Content
52-
let callerName = payload.caller?.name ?? "Unknown"
51+
let callerName = payload.senderName ?? payload.caller?.name ?? "Unknown"
5352
bestAttemptContent.title = NSLocalizedString("Video Call", comment: "")
5453
bestAttemptContent.body = String(format: NSLocalizedString("Incoming call from %@", comment: ""), callerName)
5554
bestAttemptContent.categoryIdentifier = "VIDEOCONF"
@@ -77,14 +76,15 @@ class NotificationService: UNNotificationServiceExtension {
7776
guard let bestAttemptContent = bestAttemptContent else { return }
7877

7978
// 1. Setup Basic Content (Title/Body)
80-
let senderName = payload.sender?.name ?? payload.senderName ?? "Unknown"
79+
let senderName = payload.senderName ?? payload.sender?.name ?? "Unknown"
8180
let senderUsername = payload.sender?.username ?? payload.senderName ?? ""
8281

83-
bestAttemptContent.title = senderName
82+
if bestAttemptContent.title.isEmpty {
83+
bestAttemptContent.title = senderName
84+
}
8485

8586
if let roomType = payload.type {
8687
if roomType == .group || roomType == .channel {
87-
bestAttemptContent.title = payload.name ?? senderName
8888
// Strip sender prefix if present
8989
if let body = bestAttemptContent.body as? String {
9090
let prefix = "\(senderUsername): "
@@ -98,8 +98,6 @@ class NotificationService: UNNotificationServiceExtension {
9898
}
9999
}
100100
}
101-
} else if roomType == .livechat {
102-
bestAttemptContent.title = payload.sender?.name ?? senderName
103101
}
104102
}
105103

@@ -122,7 +120,7 @@ class NotificationService: UNNotificationServiceExtension {
122120
avatarData: avatarData,
123121
conversationId: payload.rid ?? "",
124122
isGroup: isGroup,
125-
groupName: payload.name
123+
groupName: bestAttemptContent.title
126124
)
127125

128126
self.contentHandler?(self.finalContent ?? bestAttemptContent)
@@ -214,7 +212,8 @@ class NotificationService: UNNotificationServiceExtension {
214212
if let messageId = payload.messageId {
215213
self.rocketchat?.getPushWithId(messageId) { notification in
216214
if let notification = notification {
217-
// Set body first, processPayload will strip sender prefix for groups/channels
215+
// Set title and body first, processPayload will strip sender prefix for groups/channels
216+
self.bestAttemptContent?.title = notification.title
218217
self.bestAttemptContent?.body = notification.text
219218

220219
// Update ejson with full payload from server for correct navigation

0 commit comments

Comments
 (0)