Skip to content

Conversation

@diegolmello
Copy link
Member

@diegolmello diegolmello commented Jan 8, 2026

Proposed changes

This PR fixes several inconsistencies in push notification display for discussions and threads on both Android and iOS.

It ensures that the human-readable room name provided in the notification payload is correctly displayed as the title, instead of falling back to technical room IDs or sender names. It also aligns the avatar resolution logic with the main application, improving reliability for public rooms and discussions by allowing URI generation even when local credentials are not immediately available.

Issue(s)

https://rocketchat.atlassian.net/browse/CORE-1649

How to test or reproduce

  1. Receive a push notification from a Discussion:
    • Verify the title shows the human-readable discussion name.
    • Verify the avatar correctly loads the room icon.
  2. Receive a push notification from a Thread:
    • Verify the title reflects the room context provided by the server.
    • Verify the avatar resolution is correct (using room avatar for non-DMs).
    • Note: We're not displaying the thread name atm, because we need to change backend.
  3. Test on both Android and iOS physical devices.
  4. Test on workspaces with Use_Real_Name On and Off.

Screenshots

N/A (Verified with logs and visual inspection on physical devices)

Types of changes

  • Bugfix (non-breaking change which fixes an issue)
  • Improvement (non-breaking change which improves a current function)
  • New feature (non-breaking change which adds functionality)
  • Documentation update (if none of the other choices apply)

Checklist

  • I have read the CONTRIBUTING doc
  • I have signed the CLA
  • Lint and unit tests pass locally with my changes
  • I have added tests that prove my fix is effective or that my feature works (if applicable)
  • I have added necessary documentation (if applicable)
  • Any dependent changes have been merged and published in downstream modules

Further comments

The fix involves:

  • Android: Prioritizing the bundle's title field in CustomPushNotification.java and updating Ejson.java to generate avatar URIs without requiring strict local credential presence.
  • iOS: Updating NotificationService.swift to use the original title as the groupName in communication intents and ensuring the title is updated when fetching content for "message-id-only" notifications.

Summary by CodeRabbit

  • Bug Fixes & Improvements
    • Safer notification handling for partial payloads (early fetch for id-only notifications) and more defensive title/body updates.
    • Consistent sender/caller naming across notifications and device versions so display names show reliably.
    • Simplified conversation/title logic to avoid incorrect special-casing and preserve base titles.
    • Avatar URLs now consistently constructed so images load more reliably even when auth info is missing.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 8, 2026

Caution

Review failed

The pull request is closed.

Walkthrough

Standardizes sender-name selection and avatar-URI construction; simplifies Android notification title/conversation-title logic; adds early fetch flow for message-id-only pushes; and restructures iOS NotificationService payload handling and defensive title/body assignment.

Changes

Cohort / File(s) Summary
Android Notification Flow
android/app/src/main/java/chat/rocket/reactnative/notification/CustomPushNotification.java
Introduces displaySenderName (prefer ejson.senderNameejson.sender.username → title); early-return for "message-id-only" pushes to fetch full content; removes multi-branch title/conversation-title selection and applies base-title consistently.
Android Avatar URI Construction
android/app/src/main/java/chat/rocket/reactnative/notification/Ejson.java
buildAvatarUri now always returns base avatar URI (server + avatarPath + "?format=png&size=100"); appends rc_token/rc_uid only if both present. Minor comment cleanup in getAvatarUri.
Android Video Conf Name Selection
android/app/src/main/java/chat/rocket/reactnative/notification/VideoConfNotification.kt
Caller/sender name resolution now prioritizes ejson.senderName before falling back to ejson.caller.name or ejson.sender.name.
iOS Notification Processing
ios/NotificationService/NotificationService.swift
Replaces guard-let cascade with nested optional-binding; adds default processPayload path for unknown types; sets title/body defensively (avoid overwriting); ensures fetched message updates title/body and ejson before processing; uses computed title for group/channel intents.

Sequence Diagram(s)

sequenceDiagram
    participant Push as Push Receiver
    participant Parser as EJSON Parser
    participant Fetch as Message Fetcher
    participant Builder as Notification Builder
    participant OS as Notification Manager

    Push->>Parser: receive push -> parse ejson
    Parser->>Parser: compute displaySenderName, check type
    alt payload is message-id-only
        Parser->>Fetch: fetch full message content
        Fetch-->>Parser: return full payload (update ejson, title, body)
    end
    Parser->>Builder: build notification (title/body/avatar using displaySenderName & base title)
    Builder->>OS: display notification
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Suggested reviewers

  • OtavioStasiak

Poem

🐇 I hopped through payloads, nimble and bright,

names now chosen, avatars policed just right.
When IDs whisper, I fetch what they mean,
titles keep their shape, notifications stay clean.
Hop, deliver, a rabbit's small delight.

🚥 Pre-merge checks | ✅ 4 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 54.55% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main objective: fixing push notification display for discussions and threads by ensuring correct titles and avatars.
Linked Issues check ✅ Passed Code changes align with CORE-1649 objectives: Android and iOS notification files prioritize human-readable titles from payload and enable avatar URI generation without strict local credentials.
Out of Scope Changes check ✅ Passed All changes are directly related to the linked issue scope: sender name fallback logic, title prioritization, and avatar URI generation for notifications.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch fix.push-thread-discussion

📜 Recent review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Jira integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 2dbe2fb and 11a6691.

📒 Files selected for processing (4)
  • android/app/src/main/java/chat/rocket/reactnative/notification/CustomPushNotification.java
  • android/app/src/main/java/chat/rocket/reactnative/notification/Ejson.java
  • android/app/src/main/java/chat/rocket/reactnative/notification/VideoConfNotification.kt
  • ios/NotificationService/NotificationService.swift

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@diegolmello diegolmello had a problem deploying to official_android_build January 8, 2026 17:38 — with GitHub Actions Error
@diegolmello diegolmello temporarily deployed to experimental_android_build January 8, 2026 17:38 — with GitHub Actions Inactive
@diegolmello diegolmello temporarily deployed to experimental_ios_build January 8, 2026 17:38 — with GitHub Actions Inactive
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (1)
android/app/src/main/java/chat/rocket/reactnative/notification/Ejson.java (1)

77-82: Consider URL-encoding credentials for consistency, though not strictly required.

The code correctly generates avatar URIs with optional credentials. While userToken and uid are appended without encoding, Rocket.Chat tokens use only URL-safe characters (A–Z, a–z, 0–9, -, _) and user IDs are alphanumeric, so the URL remains well-formed. However, the method already uses URLEncoder elsewhere for avatarPath components (lines 94, 105, 127), creating an inconsistency. For consistency and defense-in-depth, consider encoding these query parameters:

if (!userToken.isEmpty() && !uid.isEmpty()) {
    try {
        finalUri += "&rc_token=" + URLEncoder.encode(userToken, "UTF-8") + "&rc_uid=" + URLEncoder.encode(uid, "UTF-8");
    } catch (UnsupportedEncodingException e) {
        Log.e(TAG, "Failed to encode credentials", e);
    }
}
📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Jira integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between b990e60 and cd10118.

📒 Files selected for processing (3)
  • android/app/src/main/java/chat/rocket/reactnative/notification/CustomPushNotification.java
  • android/app/src/main/java/chat/rocket/reactnative/notification/Ejson.java
  • ios/NotificationService/NotificationService.swift
🧰 Additional context used
🧬 Code graph analysis (1)
ios/NotificationService/NotificationService.swift (1)
ios/Shared/Extensions/String+Extensions.swift (1)
  • removeTrailingSlash (25-31)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: ESLint and Test / run-eslint-and-test
🔇 Additional comments (6)
ios/NotificationService/NotificationService.swift (4)

17-32: Clean refactoring of the entry point.

The if-let binding chain is cleaner than a guard-let cascade here since it allows a natural fallback in the else branch. Correctly returns the original request.content when payload parsing fails.


82-84: Correctly preserves server-provided titles.

This conditional assignment ensures human-readable room names from the payload aren't overwritten by the sender name, addressing the core issue for discussions and threads.


117-124: Consistent use of computed title for group name.

Using bestAttemptContent.title for groupName ensures the communication intent displays the same human-readable name as the notification title, maintaining consistency across iOS notification surfaces.


213-225: Title from server-provided notification is preserved correctly.

The code sets bestAttemptContent.title from the notification returned by getPushWithId before calling processPayload. Since processPayload only assigns senderName when title.isEmpty, the server-provided title (which includes the proper discussion/thread name) is preserved and won't be overwritten.

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

162-166: LGTM! Early return prevents double processing.

The early return after loadNotificationAndProcess is correct—the notification will be processed asynchronously in the callback after fetching full content from the server, avoiding duplicate calls to processNotification().


373-374: Title field handling is safe and confirmed by server fetch logic.

The simplified logic at lines 374 and 535 that directly uses the bundle title is valid. LoadNotification.java confirms that the server response includes a title field (line 200: bundle.putString("title", json.data.notification.title)), and message-id-only notifications properly fetch this from the server before processing. The code consistently relies on the server providing the title field, which aligns with removing the previous type-based fallback logic.

No evidence of notification types that exclude the title field. The change is correct and removes unnecessary type-checking while maintaining UX by depending on server-provided titles.

@diegolmello diegolmello had a problem deploying to upload_experimental_android January 8, 2026 18:08 — with GitHub Actions Error
@github-actions
Copy link

github-actions bot commented Jan 8, 2026

Android Build Available

Rocket.Chat Experimental 4.69.0.108004

Internal App Sharing: https://play.google.com/apps/test/RQVpXLytHNc/ahAO29uNTprCWSTau0A58sU5qhKHvuOKCmuflidkzIziZDqL4go7TFahzkHHgcz7Tvff4NoyMM0Cr26GZ_VkJCWbex

@github-actions
Copy link

github-actions bot commented Jan 8, 2026

iOS Build Available

Rocket.Chat Experimental 4.69.0.108005

@diegolmello diegolmello temporarily deployed to experimental_ios_build January 8, 2026 18:26 — with GitHub Actions Inactive
@diegolmello diegolmello had a problem deploying to official_android_build January 8, 2026 18:26 — with GitHub Actions Error
@diegolmello diegolmello temporarily deployed to experimental_android_build January 8, 2026 18:26 — with GitHub Actions Inactive
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Fix all issues with AI agents
In
@android/app/src/main/java/chat/rocket/reactnative/notification/CustomPushNotification.java:
- Around line 551-561: The fallback for the sender display name is inconsistent
with showNotification: update the logic that computes displaySenderName (used in
CustomPushNotification within the message-style branch) to use
ejson.sender.username as the fallback instead of ejson.sender.name, and ensure
the final fallback remains the intended value (e.g., "Unknown" or the same title
used by showNotification if desired); locate the variable displaySenderName and
the branches where ejson.sender is accessed and replace the reference to
sender.name with sender.username to keep display behavior consistent with
showNotification.
- Around line 292-297: The sender name fallback is inconsistent: in
CustomPushNotification you build displaySenderName using ejson.sender.username
but elsewhere (notificationStyle and VideoConfNotification) use
ejson.sender.name; update the construction of displaySenderName (and the
username bundle entry) to use ejson.sender.name with the same null/empty checks
(i.e., replace references to ejson.sender.username with ejson.sender.name) so
notificationStyle, VideoConfNotification, and this bundle all display the same
sender value.
📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Jira integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between cd10118 and 07dde62.

📒 Files selected for processing (3)
  • android/app/src/main/java/chat/rocket/reactnative/notification/CustomPushNotification.java
  • android/app/src/main/java/chat/rocket/reactnative/notification/VideoConfNotification.kt
  • ios/NotificationService/NotificationService.swift
🧰 Additional context used
🧬 Code graph analysis (1)
ios/NotificationService/NotificationService.swift (1)
ios/Shared/Extensions/String+Extensions.swift (1)
  • removeTrailingSlash (25-31)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: ESLint and Test / run-eslint-and-test
  • GitHub Check: format
🔇 Additional comments (7)
android/app/src/main/java/chat/rocket/reactnative/notification/VideoConfNotification.kt (1)

94-94: LGTM! Sender name fallback prioritization is correct.

The changes correctly prioritize ejson.senderName as the primary source for caller name display, with caller.name/sender.name as fallbacks. This aligns with the PR's objective to standardize sender name handling across notification types.

Also applies to: 98-98

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

378-378: LGTM! Title simplification aligns with PR objectives.

Removing the dynamic title selection logic and consistently using the bundle title field directly addresses the PR's goal of prioritizing the human-readable room name provided in the notification payload. This ensures discussions and threads display their proper names rather than falling back to technical IDs or sender names.

Also applies to: 539-539

ios/NotificationService/NotificationService.swift (5)

17-32: LGTM! Well-structured routing logic.

The restructuring from nested if-let to guard-let with dedicated handler routing improves code clarity and maintainability. The addition of the general processPayload handler (line 28) and the graceful fallback to original content on parsing failure (line 31) enhance robustness.


51-51: LGTM! Caller name priority aligns with PR objectives.

Prioritizing payload.senderName ensures consistency with the Android changes and aligns with the PR objective to standardize sender name handling across platforms.


79-84: LGTM! Defensive title preservation.

The isEmpty check ensures that existing titles (e.g., human-readable room/discussion names from the payload) are not overwritten with sender names. This directly addresses the PR objective to preserve correct notification titles for discussions and threads.


123-123: LGTM! Correct group name propagation.

Using bestAttemptContent.title as the groupName ensures that the preserved human-readable room name is correctly propagated to the iOS communication intent, aligning with the PR objective to display correct titles for discussions and threads.


305-310: Verify alignment with PR objectives for avatar resolution.

The PR objectives mention "allowing avatar URI generation even when local credentials are not immediately available, improving reliability for public rooms and discussions." However, fetchAvatarData still requires credentials and returns nil if unavailable (lines 307-310).

While the Android changes (Ejson.java) may handle URI generation differently, please confirm whether the iOS implementation should also support avatar fetching for public rooms/discussions without local credentials, or if the current iOS behavior is intentional due to platform differences in avatar data fetching (direct binary fetch vs. URI construction).

@github-actions
Copy link

github-actions bot commented Jan 8, 2026

iOS Build Available

Rocket.Chat Experimental 4.69.0.108008

@diegolmello diegolmello temporarily deployed to experimental_ios_build January 8, 2026 19:08 — with GitHub Actions Inactive
@diegolmello diegolmello had a problem deploying to experimental_android_build January 8, 2026 19:08 — with GitHub Actions Error
@diegolmello diegolmello temporarily deployed to official_android_build January 8, 2026 19:08 — with GitHub Actions Inactive
@diegolmello diegolmello had a problem deploying to upload_official_android January 8, 2026 19:37 — with GitHub Actions Error
@github-actions
Copy link

github-actions bot commented Jan 8, 2026

@github-actions
Copy link

github-actions bot commented Jan 8, 2026

iOS Build Available

Rocket.Chat Experimental 4.69.0.108010

Copy link
Contributor

@OtavioStasiak OtavioStasiak left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good to me!
Tested on both platforms.

@diegolmello diegolmello force-pushed the fix.push-thread-discussion branch from 2dbe2fb to 11a6691 Compare January 9, 2026 11:32
@diegolmello diegolmello merged commit c21d91e into develop Jan 9, 2026
4 of 6 checks passed
@diegolmello diegolmello deleted the fix.push-thread-discussion branch January 9, 2026 11:33
@diegolmello diegolmello requested a deployment to experimental_ios_build January 9, 2026 11:35 — with GitHub Actions Waiting
@diegolmello diegolmello requested a deployment to experimental_android_build January 9, 2026 11:35 — with GitHub Actions Waiting
@diegolmello diegolmello requested a deployment to official_android_build January 9, 2026 11:35 — with GitHub Actions Waiting
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants