Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Account Specific Notification Badges #1464

Merged
merged 5 commits into from
Jan 7, 2025

Conversation

alexrisch
Copy link
Collaborator

@alexrisch alexrisch commented Jan 3, 2025

Added handling for account specific badging for iOS
Cleaned up styles for Android messages
Fixed profile caching
Fixe profile caching in iOS
Added back sharedData setting

New Android Push Messages View
image

Summary by CodeRabbit

  • New Features

    • Added functionality to manage notification badges for user accounts
    • Enhanced notification handling for background and foreground scenarios
    • Improved profile and conversation type detection
  • Bug Fixes

    • Refined notification reset logic to work with specific accounts
    • Improved error handling in notification processing
  • Chores

    • Updated logging and tracing for notification-related processes
    • Simplified conversation type checking mechanisms
  • Documentation

    • Added JSDoc comments for utility functions

@alexrisch alexrisch requested a review from a team as a code owner January 3, 2025 08:45
Copy link
Contributor

coderabbitai bot commented Jan 3, 2025

Warning

Rate limit exceeded

@alexrisch has exceeded the limit for the number of commits or files that can be reviewed per hour. Please wait 47 minutes and 30 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

📥 Commits

Reviewing files that changed from the base of the PR and between d4cbb2c and 0946ba4.

📒 Files selected for processing (22)
  • App.tsx (2 hunks)
  • components/ConversationFlashList/ConversationFlashList.tsx (3 hunks)
  • components/PinnedConversations/PinnedV3Conversation.tsx (2 hunks)
  • features/notifications/notifications-constants.ts (1 hunks)
  • features/notifications/utils/accountTopicSubscription.ts (2 hunks)
  • features/notifications/utils/background/groupMessageNotification.ts (1 hunks)
  • features/notifications/utils/background/handleBackgroundNotification.ts (1 hunks)
  • features/notifications/utils/background/protocolNotification.ts (2 hunks)
  • features/notifications/utils/handleForegroundNotification.ts (4 hunks)
  • features/notifications/utils/index.ts (1 hunks)
  • features/notifications/utils/notifications-badge.ts (1 hunks)
  • features/notifications/utils/onInteractWithNotification.ts (1 hunks)
  • features/notifications/utils/resetNotifications.ts (1 hunks)
  • ios/ConverseNotificationExtension/MMKV.swift (3 hunks)
  • ios/ConverseNotificationExtension/NotificationService.swift (1 hunks)
  • ios/ConverseNotificationExtension/NotificationUtils.swift (1 hunks)
  • ios/ConverseNotificationExtension/Profile.swift (3 hunks)
  • ios/ConverseNotificationExtension/Xmtp/Messages.swift (1 hunks)
  • utils/groupUtils/conversationContainerHelpers.ts (0 hunks)
  • utils/logout/index.tsx (2 hunks)
  • utils/profile/getProfile.ts (1 hunks)
  • utils/sharedData.tsx (1 hunks)

Walkthrough

This pull request introduces comprehensive changes to the notification handling system across multiple files. The modifications focus on improving notification badge management, refining notification display logic, and ensuring account-specific notification resets. Key changes include updating notification badge tracking, enhancing background and foreground notification processing, and implementing more granular control over notification interactions for different account contexts.

Changes

File Change Summary
App.tsx Added saveApiURI() function import and execution
features/notifications/notifications-constants.ts Added NOTIFICATION_BADGE_MMKV_KEY_PREFIX constant
features/notifications/utils/accountTopicSubscription.ts Modified notification reset logic to use current account
features/notifications/utils/background/groupMessageNotification.ts Substantial refactoring of notification handling logic, added new functions for message notification processing
features/notifications/utils/background/handleBackgroundNotification.ts Added logging statement for function invocation
features/notifications/utils/background/protocolNotification.ts Enhanced error handling and logging for protocol notifications
features/notifications/utils/handleForegroundNotification.ts Updated notification reset logic with account-specific conditions
features/notifications/utils/index.ts Added Android background notification task handling
features/notifications/utils/notifications-badge.ts Added new functions for managing notification badges
features/notifications/utils/onInteractWithNotification.ts Updated resetNotifications call with account parameter
features/notifications/utils/resetNotifications.ts Modified function to accept account parameter
ios/...MMKV.swift Refactored badge and profile management methods
ios/...NotificationService.swift Updated badge increment logic
ios/...NotificationUtils.swift Modified badge increment function
utils/logout/index.tsx Added notification reset during logout process
utils/sharedData.tsx Added saveXmtpEnv function

Sequence Diagram

sequenceDiagram
    participant App
    participant NotificationHandler
    participant AccountStore
    participant BadgeManager
    participant MMKVStorage

    App->>NotificationHandler: Receive Notification
    NotificationHandler->>AccountStore: Get Current Account
    AccountStore-->>NotificationHandler: Return Current Account
    NotificationHandler->>BadgeManager: Check Badge Count
    BadgeManager->>MMKVStorage: Retrieve Account Badge
    MMKVStorage-->>BadgeManager: Return Badge Count
    BadgeManager->>NotificationHandler: Update Notification
    NotificationHandler->>App: Display Notification
Loading

Possibly related PRs

Suggested Reviewers

  • technoplato
  • lourou

Poem

🐰 Notifications dance and sway,
Badges reset in their own way,
Accounts now tracked with care,
No more alerts everywhere!
A rabbit's code, precise and bright 🔔


Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR. (Beta)
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

circularLargeIcon: true,
}
: {};
const displayedNotificaitons = await notifee.getDisplayedNotifications();
Copy link

Choose a reason for hiding this comment

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

The variable displayedNotificaitons contains a typo and should be renamed to displayedNotifications to maintain consistent spelling throughout the codebase.

Spotted by Graphite Reviewer

Is this helpful? React 👍 or 👎 to let us know.

Copy link
Contributor

github-actions bot commented Jan 3, 2025

Performance Comparison Report

  • Current: a6a32e3 - 2025-01-07 22:39:16Z
  • Baseline: main (16315f9) - 2025-01-07 22:37:59Z

Significant Changes To Duration

There are no entries

Meaningless Changes To Duration

Show entries
Name Type Duration Count
Avatar Image 10 runs render 0.5 ms → 0.7 ms (+0.2 ms, +40.0%) 🔴 1 → 1
Avatar Image 50 runs render 0.7 ms → 0.8 ms (+0.1 ms, +18.2%) 🔴 1 → 1
Empty Avatar 10 runs render 1.1 ms → 1.1 ms 1 → 1
Empty Avatar 50 runs render 1.1 ms → 1.0 ms (-0.1 ms, -10.9%) 1 → 1
Text Component with color prop - 10 runs render 0.6 ms → 0.6 ms 1 → 1
Text Component with default props - 10 runs render 1.0 ms → 0.8 ms (-0.2 ms, -20.0%) 🟢 1 → 1
Text Component with translation key - 10 runs render 0.7 ms → 0.9 ms (+0.2 ms, +28.6%) 🔴 1 → 1
Text Component with weight and size - 10 runs render 0.4 ms → 0.9 ms (+0.5 ms, +125.0%) 🔴 1 → 1
Show details
Name Type Duration Count
Avatar Image 10 runs render Baseline
Mean: 0.5 ms
Stdev: 0.5 ms (105.4%)
Runs: 1 1 1 0 1 0 0 1 0 0
Warmup runs: 1

Current
Mean: 0.7 ms
Stdev: 0.5 ms (69.0%)
Runs: 0 1 0 1 1 1 1 1 1 0
Warmup runs: 1
Baseline
Mean: 1
Stdev: 0 (0.0%)
Runs: 1 1 1 1 1 1 1 1 1 1
Render issues:

Current
Mean: 1
Stdev: 0 (0.0%)
Runs: 1 1 1 1 1 1 1 1 1 1
Render issues:
Avatar Image 50 runs render Baseline
Mean: 0.7 ms
Stdev: 0.5 ms (72.5%)
Runs: 0 0 1 1 0 0 0 1 1 1 0 1 1 1 1 1 1 1 0 1 1 1 0 1 1 1 1 0 1 1 0 1 1 1 1 0 1 0 1 0 1 1 0 1 0 1 1 1 0 0
Warmup runs: 1

Current
Mean: 0.8 ms
Stdev: 0.4 ms (53.6%)
Runs: 0 0 1 1 1 1 1 0 0 1 1 1 1 1 1 1 1 1 1 1 0 1 0 1 1 1 1 1 1 1 0 0 1 1 1 0 1 1 1 1 1 1 1 1 1 0 1 1 1 0
Warmup runs: 1
Baseline
Mean: 1
Stdev: 0 (0.0%)
Runs: 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
Render issues:

Current
Mean: 1
Stdev: 0 (0.0%)
Runs: 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
Render issues:
Empty Avatar 10 runs render Baseline
Mean: 1.1 ms
Stdev: 0.3 ms (28.7%)
Runs: 1 1 1 1 1 2 1 1 1 1
Warmup runs: 2

Current
Mean: 1.1 ms
Stdev: 0.6 ms (51.6%)
Runs: 2 1 2 1 0 1 1 1 1 1
Warmup runs: 2
Baseline
Mean: 1
Stdev: 0 (0.0%)
Runs: 1 1 1 1 1 1 1 1 1 1
Render issues:

Current
Mean: 1
Stdev: 0 (0.0%)
Runs: 1 1 1 1 1 1 1 1 1 1
Render issues:
Empty Avatar 50 runs render Baseline
Mean: 1.1 ms
Stdev: 0.4 ms (33.1%)
Runs: 1 1 1 1 1 1 2 1 2 1 1 1 2 1 1 1 1 1 1 2 1 1 1 1 1 1 1 1 1 1 1 1 1 1 2 1 0 1 1 1 1 1 2 1 1 1 1 1 1 1
Warmup runs: 1

Current
Mean: 1.0 ms
Stdev: 0.4 ms (43.7%)
Runs: 1 1 1 1 1 1 2 1 1 1 1 0 1 0 1 1 1 1 1 1 1 1 0 2 1 1 1 1 1 1 1 1 2 1 1 1 1 1 1 1 1 1 1 1 1 0 1 0 1 2
Warmup runs: 1
Baseline
Mean: 1
Stdev: 0 (0.0%)
Runs: 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
Render issues:

Current
Mean: 1
Stdev: 0 (0.0%)
Runs: 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
Render issues:
Text Component with color prop - 10 runs render Baseline
Mean: 0.6 ms
Stdev: 0.7 ms (116.5%)
Runs: 1 2 1 1 0 0 0 0 1 0
Warmup runs: 1

Current
Mean: 0.6 ms
Stdev: 0.5 ms (86.1%)
Runs: 1 0 1 1 1 1 0 1 0 0
Warmup runs: 0
Baseline
Mean: 1
Stdev: 0 (0.0%)
Runs: 1 1 1 1 1 1 1 1 1 1
Render issues:

Current
Mean: 1
Stdev: 0 (0.0%)
Runs: 1 1 1 1 1 1 1 1 1 1
Render issues:
Text Component with default props - 10 runs render Baseline
Mean: 1.0 ms
Stdev: 0.5 ms (47.1%)
Runs: 1 2 1 1 1 1 1 1 0 1
Warmup runs: 4

Current
Mean: 0.8 ms
Stdev: 0.4 ms (52.7%)
Runs: 1 1 1 1 1 1 0 1 1 0
Warmup runs: 3
Baseline
Mean: 1
Stdev: 0 (0.0%)
Runs: 1 1 1 1 1 1 1 1 1 1
Render issues:

Current
Mean: 1
Stdev: 0 (0.0%)
Runs: 1 1 1 1 1 1 1 1 1 1
Render issues:
Text Component with translation key - 10 runs render Baseline
Mean: 0.7 ms
Stdev: 0.5 ms (69.0%)
Runs: 0 1 0 1 0 1 1 1 1 1
Warmup runs: 1

Current
Mean: 0.9 ms
Stdev: 0.3 ms (35.1%)
Runs: 1 1 0 1 1 1 1 1 1 1
Warmup runs: 2
Baseline
Mean: 1
Stdev: 0 (0.0%)
Runs: 1 1 1 1 1 1 1 1 1 1
Render issues:

Current
Mean: 1
Stdev: 0 (0.0%)
Runs: 1 1 1 1 1 1 1 1 1 1
Render issues:
Text Component with weight and size - 10 runs render Baseline
Mean: 0.4 ms
Stdev: 0.5 ms (129.1%)
Runs: 0 1 0 1 0 1 0 0 1 0
Warmup runs: 1

Current
Mean: 0.9 ms
Stdev: 0.3 ms (35.1%)
Runs: 1 1 1 1 1 1 1 0 1 1
Warmup runs: 1
Baseline
Mean: 1
Stdev: 0 (0.0%)
Runs: 1 1 1 1 1 1 1 1 1 1
Render issues:

Current
Mean: 1
Stdev: 0 (0.0%)
Runs: 1 1 1 1 1 1 1 1 1 1
Render issues:

Render Count Changes

There are no entries

Render Issues

There are no entries

Added Scenarios

There are no entries

Removed Scenarios

There are no entries

Generated by 🚫 dangerJS against 0946ba4

@lourou
Copy link
Member

lourou commented Jan 3, 2025

LGTM! Just noticed two type-checking errors:

➜ Typechecking project...
Error: features/notifications/utils/background/groupMessageNotification.ts(102,54): error TS18048: 'conversation' is possibly 'undefined'.
Error: features/notifications/utils/background/groupMessageNotification.ts(161,54): error TS1[8](https://github.com/ephemeraHQ/converse-app/actions/runs/12595190304/job/35103983033?pr=1464#step:5:9)048: 'conversation' is possibly 'undefined'.

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: 5

🧹 Nitpick comments (9)
features/notifications/utils/background/groupMessageNotification.ts (1)

202-205: Error handling is sufficient.
Catching all errors here and logging them is appropriate for background handling. Consider whether rethrowing or additional fallback logic is needed if potential data corruption can occur.

features/notifications/utils/resetNotifications.ts (1)

1-11: Consider renaming for clarity.
This function now only resets for a specific account if present, yet its name suggests a global reset. Consider resetAccountNotifications or a note clarifying that no action is taken if account is falsy.

features/notifications/utils/background/handleBackgroundNotification.ts (1)

17-17: Informative logging statement.
Consider including additional contextual details (e.g., partial rawBody) to help debug issues quickly.

features/notifications/utils/index.ts (1)

Line range hint 27-49: Consider adding stricter type checks for data.
Here, data is cast to any, which can mask potential type mismatches or undefined properties at runtime. To improve reliability, add a well-defined type or perform additional runtime checks to ensure the fields you access (notification.data.body, etc.) exist and are of the expected type.

features/notifications/utils/handleForegroundNotification.ts (2)

15-19: Unify string conversion methods.
The code uses toLowerCase() and toLocaleLowerCase(). For consistency and predictable results, use the same method throughout. Typically, toLowerCase() suffices unless your locale requires special handling.


61-61: Handle potential null account for resetNotifications.
If account fails the check above, you might pass undefined to resetNotifications(account). Consider a fallback or an early return to skip silent resets.

ios/ConverseNotificationExtension/MMKV.swift (1)

127-129: Consider centralizing storage keys.

getBadgeStorageKey(account:) is good for consistent key naming, but storing all keys in a single place, e.g., an enum or a constants file, can improve maintainability. It also simplifies refactoring if the prefix changes in the future.

ios/ConverseNotificationExtension/Xmtp/Messages.swift (1)

100-103: Consider fallback or error-handling for the sender name.
While retrieving and displaying the sender’s preferred name is a good enhancement, you may want to provide a fallback if getPreferredName returns an empty or default string to ensure the notification title remains meaningful.

features/notifications/utils/accountTopicSubscription.ts (1)

4-4: Validate the account format.
When comparing or using account strings, ensure consistent casing or normalizing since account identifiers might differ in uppercase/lowercase. You could do .toLowerCase() when storing or comparing to avoid subtle bugs.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ebcac5a and 2dca3e8.

📒 Files selected for processing (19)
  • App.tsx (2 hunks)
  • features/notifications/notifications-constants.ts (1 hunks)
  • features/notifications/utils/accountTopicSubscription.ts (2 hunks)
  • features/notifications/utils/background/groupMessageNotification.ts (2 hunks)
  • features/notifications/utils/background/handleBackgroundNotification.ts (1 hunks)
  • features/notifications/utils/background/protocolNotification.ts (1 hunks)
  • features/notifications/utils/handleForegroundNotification.ts (4 hunks)
  • features/notifications/utils/index.ts (1 hunks)
  • features/notifications/utils/notifications-badge.ts (1 hunks)
  • features/notifications/utils/onInteractWithNotification.ts (1 hunks)
  • features/notifications/utils/resetNotifications.ts (1 hunks)
  • ios/ConverseNotificationExtension/MMKV.swift (3 hunks)
  • ios/ConverseNotificationExtension/NotificationService.swift (1 hunks)
  • ios/ConverseNotificationExtension/NotificationUtils.swift (1 hunks)
  • ios/ConverseNotificationExtension/Profile.swift (3 hunks)
  • ios/ConverseNotificationExtension/Xmtp/Messages.swift (1 hunks)
  • utils/logout/index.tsx (2 hunks)
  • utils/profile/getProfile.ts (1 hunks)
  • utils/sharedData.tsx (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • features/notifications/notifications-constants.ts
🔇 Additional comments (27)
utils/sharedData.tsx (1)

6-9: Consider handling undefined config.apiURI.
If config.apiURI is undefined or empty, setting it as "api-uri" in mmkv might cause problems downstream. Consider validating config.apiURI or adding fallback logic.

App.tsx (2)

46-46: Good import practice.
Importing saveApiURI here clearly indicates its usage within this module, ensuring the function remains discoverable and explicit in intent.


62-63: Confirm initialization timing.
saveApiURI() is invoked right after initSentry(), which is likely safe. However, if config or mmkv initialization might fail under certain conditions—such as incomplete environment data—consider error handling or logging to detect potential issues.

features/notifications/utils/background/groupMessageNotification.ts (7)

26-26: Logger import looks good.
No concerns here. Great addition for better error tracking.


36-46: Effective fallback logic for syncing conversations.
This ensures you properly handle an unsynced conversation before throwing an error. Nicely done.


50-62: Spam score check is well-structured.
Early return safeguards from unnecessary notification spam. Logical approach to reduce overhead.


64-74: Efficient profile lookup.
The combined use of getProfile plus local conversation members ensures accurate sender info.


76-80: Notification content retrieval is concise.
Clean approach to skip if content is null or undefined.


82-113: Group notification block looks consistent.
Using a messaging style and re-constructing messages for grouped notifications is great for user clarity.


144-200: Direct/1-1 notification flow.
Your approach to show separate messaging style for individual notifications is well-structured.

features/notifications/utils/notifications-badge.ts (1)

15-21: Potential mismatch between incrementBadgeCount and the explicit badge update.
notifee.incrementBadgeCount() increments the existing system-level count by 1, but then you store badge in MMKV. If badge is not exactly currentCount + 1, the two may diverge. Verify that the intended behavior is simply to increment by one each time.

utils/profile/getProfile.ts (3)

35-36: Returning the first array entry is valid.
This handles multiple stored entries properly. If empty, it yields undefined, which aligns with the declared return signature.


41-42: Directly returning fetched profile is concise.
This approach avoids confusion by not returning a Promise inside a Promise.


49-49: Consistent usage of index 0.
Same approach as above, ensuring a single object is returned. If you intend to handle multiple profiles differently, consider an explicit fallback. Otherwise, this is fine.

features/notifications/utils/onInteractWithNotification.ts (1)

65-65: Validate that account is properly resolved.
Ensure that account (derived from either notificationData["account"] or the store) is actually defined when calling resetNotifications(account). Otherwise, a null or undefined value might cause unexpected behavior.

features/notifications/utils/handleForegroundNotification.ts (2)

52-52: Confirm account presence before showing the alert.
When account is returned from notification.request.content.data, verify that the property actually exists; otherwise, your check (account && account !== currentAccount()) might fail quietly if account is undefined.


73-77: Log relevant environment details.
This additional logging for the foregrounded notification on Platform.OS is helpful. If you need further debugging, consider also logging the app version or additional context, but keep it concise to avoid clutter.

ios/ConverseNotificationExtension/Profile.swift (1)

Line range hint 48-71: Avoid ignoring response errors in refreshProfileFromBackend and refreshInboxProfileFromBackend.
While the logic re-throws in some cases, if the response is empty (response.data is null) or if decoding fails, consider logging or handling these errors more explicitly to help diagnose issues when network or backend problems occur.

ios/ConverseNotificationExtension/NotificationUtils.swift (1)

14-17: Ensure concurrency safety for badge increments.

This code correctly handles per-account and total badge updates, but consider concurrency if multiple notifications for the same account may be processed in parallel by the extension. In such a case, performing a simple read–increment–write sequence might result in lost increments unless protected by a concurrency mechanism.

ios/ConverseNotificationExtension/MMKV.swift (3)

68-69: Check for potential nil or partial data in decoded Profile.

The code decodes a Profile object and then immediately returns decoded.socials. Verify that socials is mandatory in the Profile structure. If socials can be missing or optional in the stored JSON, consider graceful handling or default values.


131-135: Validate possible double/Int mismatch.

mmkv?.double(forKey: key) is converted to an Int. If any unexpected floating-point value (e.g., partial) is stored, it might lead to a truncated integer. Consider storing and retrieving an integer type directly to avoid confusion.


146-153: Guard for large account arrays.

getAllBadgeCounts loops through all returned accounts, possibly leading to performance impact if many accounts exist. Consider caching or limiting the account list size if needed. Also confirm concurrency safety if invoked in parallel.

utils/logout/index.tsx (2)

26-26: Good modular design for resetNotifications.

Importing resetNotifications here streamlines the logout process. It helps ensure that relevant notifications and badge counts for the user are reset consistently upon logout.


110-110: Verify sync between resetting notifications and unsubscribing.

Calling resetNotifications(account) is appropriate here. Nevertheless, confirm that unsubscribing from notifications or clearing secure storage doesn't undo the reset notifications or lead to inconsistent states. If needed, handle any concurrency or ordering issues between these calls.

ios/ConverseNotificationExtension/NotificationService.swift (1)

67-67: Badge increment logic is aligned with per-account flows.

Passing the account into incrementBadge ensures that only the relevant badge is incremented, which is consistent with the new per-account design for badge counts. Confirm that handleNotificationAsync only runs once per notification to prevent multiple increments on the same message.

features/notifications/utils/accountTopicSubscription.ts (1)

31-33: Ensure logic works for multiple concurrent accounts.
Checking if (account === currentAccount()) before resetting notifications is a great approach to avoid unnecessary resets. However, consider any edge cases if currentAccount might change between subscription and execution. If that’s unlikely or well-handled, this logic should suffice.

features/notifications/utils/background/protocolNotification.ts (1)

26-52: Good use of try/catch blocks for improved error handling.
Your newly introduced try/catch effectively logs errors without disrupting the entire process. Consider adding more granular logging for each step (e.g., an info log when getXmtpClient is first invoked) to aid debugging.

Comment on lines 102 to 103
(n) => n.notification.android?.groupId === conversation?.topic
);
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Fix type-check error by ensuring conversation is recognized as non-null.
Because you throw an error if conversation is missing at line 45, it’s guaranteed non-null here. TypeScript may still complain, so add a non-null assertion:

-        displayedNotifications.find(
-          (n) => n.notification.android?.groupId === conversation?.topic
-        );
+        displayedNotifications.find(
+          (n) => n.notification.android?.groupId === conversation!.topic
+        );
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
(n) => n.notification.android?.groupId === conversation?.topic
);
(n) => n.notification.android?.groupId === conversation!.topic
);

Comment on lines 160 to 161
displayedNotifications.find(
(n) => n.notification.android?.groupId === conversation?.topic
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Replicate the same fix for type-check error here.
As with line 102, TypeScript requires a non-null assertion or additional check:

-        displayedNotifications.find(
-          (n) => n.notification.android?.groupId === conversation?.topic
-        );
+        displayedNotifications.find(
+          (n) => n.notification.android?.groupId === conversation!.topic
+        );

Committable suggestion skipped: line range outside the PR's diff.

@@ -17,7 +17,7 @@ func getProfile(account: String, address: String) async -> ProfileSocials? {

// If profile is nil, let's refresh it
try? await refreshProfileFromBackend(account: account, address: formattedAddress)

Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Handle errors surfaced by try? await refreshProfileFromBackend(...).
try? discards errors, which can mask network or parsing problems. For better observability, consider catching or logging these errors explicitly.

Comment on lines +140 to +144
func setBadgeByAccount(_ badge: Int, account: String) {
let mmkv = getMmkv()
mmkv?.set(Int32(badge), forKey: "notifications-badge")
let key = getBadgeStorageKey(account: account)
mmkv?.set(Double(badge), forKey: key)
}
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Inconsistent data type usage for badges.

setBadgeByAccount sets the badge as a Double, while the code interprets the value as an Int in getBadgeByAccount. For clarity, store it as an integer to ensure straightforward usage and avoid type-casting pitfalls.

- func setBadgeByAccount(_ badge: Int, account: String) {
-   mmkv?.set(Double(badge), forKey: key)
+ func setBadgeByAccount(_ badge: Int, account: String) {
+   mmkv?.set(badge, forKey: key)

Committable suggestion skipped: line range outside the PR's diff.

Comment on lines +84 to +85
let decoded = try decoder.decode([ProfileSocials].self, from: profilesString!.data(using: .utf8)!)
return decoded[0]
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Handle empty arrays to avoid index out-of-bounds.

When decoding [ProfileSocials], you return decoded[0] directly. If the array is empty, this will cause a crash. Consider adding a safety check before returning decoded[0].

   let decoded = try decoder.decode([ProfileSocials].self, from: profilesString!.data(using: .utf8)!)
-  return decoded[0]
+  guard !decoded.isEmpty else {
+    return nil
+  }
+  return decoded[0]

Committable suggestion skipped: line range outside the PR's diff.

Copy link
Collaborator

@thierryskoda thierryskoda left a comment

Choose a reason for hiding this comment

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

Small comments

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: 3

🧹 Nitpick comments (3)
features/notifications/utils/background/protocolNotification.ts (1)

24-41: Enhance error handling with more specific error types.

The error handling has been improved with try-catch and detailed logging. However, consider enhancing the error handling further by:

  1. Using more specific error types for better error tracking
  2. Adding structured logging with error codes
 try {
   logger.debug(
     `[ProtocolNotification] Received a notification for account ${notification.account}`
   );
   const accounts = getAccountsList();
   if (
     !accounts.find(
       (a) => a.toLowerCase() === notification.account.toLowerCase()
     )
   ) {
-    logger.error(
+    const error = new Error(
+      `Account ${notification.account} not found`
+    );
+    logger.error(
+      '[ProtocolNotification] Account not found',
+      {
+        error,
+        errorCode: 'ACCOUNT_NOT_FOUND',
+        account: notification.account
+      }
+    );
-      `[ProtocolNotification] Account ${notification.account} not found, skipping`
-    );
     return;
   }
features/notifications/utils/background/groupMessageNotification.ts (2)

27-53: Consider handling edge cases in getSenderProfileInfo.

The helper function looks good but could be improved to handle edge cases better:

  1. The empty string return for missing senderAddress could be more informative
  2. Consider caching profile info to improve performance
 if (!senderAddress)
   return {
-    senderName: "",
+    senderName: "Unknown Sender",
+    senderImage: undefined,
   };

268-271: Enhance error logging with structured data.

The error logging could be improved with structured data and error categorization.

- logger.error(
-   `[GroupMessageNotification] Error handling group message notification: ${e}`
- );
+ logger.error('[GroupMessageNotification] Message notification error', {
+   error: e,
+   errorCode: 'MESSAGE_NOTIFICATION_ERROR',
+   contentTopic: notification.contentTopic,
+   account: xmtpClient.address
+ });
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2dca3e8 and df04d3c.

📒 Files selected for processing (5)
  • components/ConversationFlashList.tsx (2 hunks)
  • components/PinnedConversations/PinnedV3Conversation.tsx (2 hunks)
  • features/notifications/utils/background/groupMessageNotification.ts (1 hunks)
  • features/notifications/utils/background/protocolNotification.ts (2 hunks)
  • utils/groupUtils/conversationContainerHelpers.ts (0 hunks)
💤 Files with no reviewable changes (1)
  • utils/groupUtils/conversationContainerHelpers.ts
🔇 Additional comments (9)
components/PinnedConversations/PinnedV3Conversation.tsx (3)

6-6: Import statement looks good.

Since isConversationGroup is used consistently, this import ensures a more concise way to branch between group vs direct message conversations.


17-18: Clear conditional to handle group conversations.

This branch logically returns the PinnedV3GroupConversation component when the conversation is identified as a group.


20-20: Adequate fallback for non-group conversations.

Returning PinnedV3DMConversation is straightforward and aligns with the conversation type check, ensuring a clean separation of group vs. DM rendering logic.

components/ConversationFlashList.tsx (3)

16-16: Consistent usage of isConversationGroup.

Replacing custom or version-based checks with isConversationGroup improves readability and consistency across components.


62-63: Appropriate branching for conversation type.

This logic correctly renders a V3GroupConversationListItem if the conversation is a group. The inline conditions remain cohesive and clear.


65-65: Fallback handling ensures DM item rendering.

Retaining a separate branch for DM items maintains clarity, aligning with the updated approach of using the isConversationGroup function without extra overhead.

features/notifications/utils/background/protocolNotification.ts (2)

6-6: LGTM! Clean import organization.

The imports are well-organized, with the new handleV3MessageNotification and isV3Topic imports properly added to support the enhanced notification routing.

Also applies to: 11-11


45-49: Verify notification routing logic.

The notification routing logic looks correct, but let's verify that all possible content topics are handled appropriately.

✅ Verification successful

Let me try a different approach to verify the notification routing logic.


Notification routing logic is correctly implemented

Based on the codebase analysis, the notification routing logic is properly handling all content topic types:

  1. V3 topics (isV3Topic) are handled by handleV3MessageNotification
  2. Group welcome topics (isGroupWelcomeContentTopic) are handled by handleGroupWelcomeNotification

The implementation is consistent with the topic type checks found in the codebase:

  • isV3Topic checks for MLS group message topics
  • isGroupWelcomeContentTopic checks for topics starting with "/xmtp/mls/1/w-"

No other content topic types are defined in the codebase that would require handling in this notification router.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for any unhandled content topics in the codebase

# Search for content topic definitions and usages
echo "Searching for content topic definitions and handlers..."
rg --type typescript "contentTopic|isV3Topic|isGroupWelcomeContentTopic" -A 2

# Look for potential switch/if-else chains handling content topics
echo "Checking for content topic handling patterns..."
ast-grep --pattern 'if ($topic) { $$$ } else if ($topic) { $$$ }'

Length of output: 408


Script:

#!/bin/bash
# Search for content topic related code with ripgrep
echo "Searching for content topic definitions and handlers..."
rg "contentTopic|isV3Topic|isGroupWelcomeContentTopic"

# Search for topic type checks and handlers
echo "Searching for topic type checks..."
rg "is.*Topic|handle.*Notification"

Length of output: 15502

features/notifications/utils/background/groupMessageNotification.ts (1)

55-66: LGTM! Well-structured type definitions.

The type definitions are clear and properly leverage TypeScript's type system with good separation between base and specific notification types.

Comment on lines +162 to +177
const displayedNotifications = await notifee.getDisplayedNotifications();
const previousGroupIdNotification =
conversation?.topic &&
displayedNotifications.find(
(n) => n.notification.android?.groupId === conversation?.topic
);
const previousMessages =
previousGroupIdNotification?.notification.android?.style?.type ===
AndroidStyle.MESSAGING
? previousGroupIdNotification.notification.android?.style?.messages
: [];
if (previousGroupIdNotification?.notification.id) {
notifee.cancelDisplayedNotification(
previousGroupIdNotification.notification.id
);
}
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Duplicate code detected in notification handling.

The notification cancellation logic is duplicated between group and DM handlers. Consider extracting it to a shared function.

+ const cancelPreviousNotification = async (topic: string) => {
+   const displayedNotifications = await notifee.getDisplayedNotifications();
+   const previousGroupIdNotification =
+     displayedNotifications.find(
+       (n) => n.notification.android?.groupId === topic
+     );
+   if (previousGroupIdNotification?.notification.id) {
+     await notifee.cancelDisplayedNotification(
+       previousGroupIdNotification.notification.id
+     );
+   }
+   return previousGroupIdNotification;
+ };

Committable suggestion skipped: line range outside the PR's diff.

Comment on lines +91 to +106
const displayedNotifications = await notifee.getDisplayedNotifications();
const previousGroupIdNotification =
conversation.topic &&
displayedNotifications.find(
(n) => n.notification.android?.groupId === conversation.topic
);
const previousMessages =
previousGroupIdNotification?.notification.android?.style?.type ===
AndroidStyle.MESSAGING
? previousGroupIdNotification.notification.android?.style?.messages
: [];
if (previousGroupIdNotification?.notification.id) {
notifee.cancelDisplayedNotification(
previousGroupIdNotification.notification.id
);
}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Fix potential race condition in notification handling.

There's a potential race condition between finding the previous notification and canceling it. Consider using a transaction-like approach.

- const displayedNotifications = await notifee.getDisplayedNotifications();
- const previousGroupIdNotification =
-   conversation.topic &&
-   displayedNotifications.find(
-     (n) => n.notification.android?.groupId === conversation.topic
-   );
- if (previousGroupIdNotification?.notification.id) {
-   notifee.cancelDisplayedNotification(
-     previousGroupIdNotification.notification.id
-   );
- }
+ // Atomic operation to get and cancel notification
+ const previousNotificationId = await (async () => {
+   const displayedNotifications = await notifee.getDisplayedNotifications();
+   const previousGroupIdNotification =
+     conversation.topic &&
+     displayedNotifications.find(
+       (n) => n.notification.android?.groupId === conversation.topic
+     );
+   if (previousGroupIdNotification?.notification.id) {
+     await notifee.cancelDisplayedNotification(
+       previousGroupIdNotification.notification.id
+     );
+   }
+   return previousGroupIdNotification;
+ })();

Committable suggestion skipped: line range outside the PR's diff.

Comment on lines +231 to +236
const spamScore = await computeSpamScoreGroupMessage(
xmtpClient,
conversation as GroupWithCodecsType,
message
);
if (spamScore >= 0) return;
Copy link
Contributor

Choose a reason for hiding this comment

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

💡 Codebase verification

Type guard should be used before type casting

The code already imports isConversationGroup type guard but doesn't use it before the type casting. This could lead to runtime errors if the conversation is not actually a group conversation. You should modify the code to use the type guard before the type casting:

if (!isConversationGroup(conversation)) return;

const spamScore = await computeSpamScoreGroupMessage(
  xmtpClient,
  conversation, // type casting not needed here as TypeScript knows it's GroupWithCodecsType
  message
);
  • features/notifications/utils/background/groupMessageNotification.ts: Add type guard check before computing spam score
🔗 Analysis chain

Verify spam score computation type casting.

The type casting of conversation to GroupWithCodecsType might be unsafe. Consider using the isConversationGroup type guard here as well.


Let me try a different search pattern to gather more information.


Let me check the implementation of isConversationGroup type guard.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for similar type casts in the codebase

# Look for type casts to GroupWithCodecsType
echo "Searching for GroupWithCodecsType casts..."
rg --type typescript "as GroupWithCodecsType"

# Look for usage of isConversationGroup
echo "Checking isConversationGroup usage patterns..."
ast-grep --pattern 'if (isConversationGroup($conv)) { $$$ }'

Length of output: 343


Script:

#!/bin/bash
# Search for GroupWithCodecsType usage and type guards
echo "Searching for GroupWithCodecsType..."
rg "GroupWithCodecsType"

echo -e "\nSearching for isConversationGroup..."
rg "isConversationGroup"

echo -e "\nSearching for type guard implementations..."
ast-grep --pattern 'function isConversationGroup($param): $param is $type { $$$ }'

Length of output: 7201


Script:

#!/bin/bash
# Get the implementation of isConversationGroup
echo "Getting isConversationGroup implementation..."
rg -A 5 "export function isConversationGroup"

# Check the specific file for computeSpamScoreGroupMessage usage
echo -e "\nChecking spam score computation context..."
rg -A 5 "computeSpamScoreGroupMessage" "features/notifications/utils/background/groupMessageNotification.ts"

Length of output: 1281

@alexrisch alexrisch force-pushed the ar/notification-badge-account branch from df04d3c to d4cbb2c Compare January 3, 2025 17:56
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

♻️ Duplicate comments (1)
ios/ConverseNotificationExtension/MMKV.swift (1)

84-85: ⚠️ Potential issue

Handle empty arrays to avoid index out-of-bounds.

The array access at index 0 without bounds checking could cause a crash if the array is empty.

🧹 Nitpick comments (6)
features/notifications/utils/resetNotifications.ts (1)

1-11: LGTM! Account-specific notification reset implementation looks good.

The changes properly implement account-specific notification badge clearing with good use of early return pattern.

Consider adding error handling for invalid account parameter.

While the early return handles undefined/empty accounts, consider adding validation for malformed account strings.

 export const resetNotifications = async (
   account: string,
   timeout: number = 0
 ): Promise<void> => {
   setTimeout(async () => {
-    if (!account) {
+    if (!account || !/^[a-zA-Z0-9_-]+$/.test(account)) {
       return;
     }
     clearNotificationBadgeForAccount(account);
   }, timeout);
 };
ios/ConverseNotificationExtension/NotificationUtils.swift (1)

14-18: LGTM! Account-specific badge increment implementation looks good.

The implementation correctly handles account-specific badge counting and updates the total badge count across all accounts.

Consider adding overflow protection.

The badge increment operation should handle potential integer overflow scenarios.

 func incrementBadge(for content: UNMutableNotificationContent, account: String) {
   let newAccountBadgeCount = getBadgeByAccount(account: account) + 1
+  guard newAccountBadgeCount > 0 else {
+    // Handle overflow by capping at max value
+    setBadgeByAccount(Int.max, account: account)
+    return
+  }
   setBadgeByAccount(newAccountBadgeCount, account: account)
   let newBadgeCount = getAllBadgeCounts()
   content.badge = NSNumber(value: newBadgeCount)
 }
ios/ConverseNotificationExtension/MMKV.swift (1)

146-153: LGTM! Total badge count calculation looks good.

The implementation correctly aggregates badge counts across all accounts.

Consider caching the total badge count.

For better performance, consider caching the total badge count and updating it incrementally instead of recalculating it every time.

+private var totalBadgeCount: Int = 0
+
 func setBadgeByAccount(_ badge: Int, account: String) {
   let mmkv = getMmkv()
+  let oldBadge = getBadgeByAccount(account: account)
   let key = getBadgeStorageKey(account: account)
   mmkv?.set(Double(badge), forKey: key)
+  totalBadgeCount += (badge - oldBadge)
 }

 func getAllBadgeCounts() -> Int {
+  if totalBadgeCount == 0 {
     var count = 0
     let accounts = getAccounts()
     for account in accounts {
       let accountCount = getBadgeByAccount(account: account)
       count += accountCount
     }
+    totalBadgeCount = count
+  }
+  return totalBadgeCount
 }
features/notifications/utils/background/groupMessageNotification.ts (3)

27-53: Consider handling edge cases in getSenderProfileInfo.

The function returns an empty sender name when senderAddress is not found, but senderImage is undefined in this case. Consider returning both properties explicitly for consistency.

   if (!senderAddress)
     return {
       senderName: "",
+      senderImage: undefined,
     };

213-222: Improve error handling for conversation sync.

The code attempts to sync and find the conversation again if not found initially. Consider adding a retry limit to prevent infinite loops in case of persistent issues.

+    let retryCount = 0;
+    const MAX_RETRIES = 3;
     let conversation = await xmtpClient.conversations.findConversationByTopic(
       notification.contentTopic as ConversationTopic
     );
-    if (!conversation) {
+    while (!conversation && retryCount < MAX_RETRIES) {
+      retryCount++;
       await xmtpClient.conversations.sync();
       conversation = await xmtpClient.conversations.findConversationByTopic(
         notification.contentTopic as ConversationTopic
       );
-      if (!conversation) throw new Error("Conversation not found");
     }
+    if (!conversation) throw new Error("Conversation not found after retries");

269-271: Enhance error logging.

The error message could be more descriptive by including the notification content topic.

     logger.error(
-      `[GroupMessageNotification] Error handling group message notification: ${e}`
+      `[GroupMessageNotification] Error handling message notification for topic ${notification.contentTopic}: ${e}`
     );
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between df04d3c and d4cbb2c.

📒 Files selected for processing (22)
  • App.tsx (2 hunks)
  • components/ConversationFlashList/ConversationFlashList.tsx (2 hunks)
  • components/PinnedConversations/PinnedV3Conversation.tsx (2 hunks)
  • features/notifications/notifications-constants.ts (1 hunks)
  • features/notifications/utils/accountTopicSubscription.ts (2 hunks)
  • features/notifications/utils/background/groupMessageNotification.ts (1 hunks)
  • features/notifications/utils/background/handleBackgroundNotification.ts (1 hunks)
  • features/notifications/utils/background/protocolNotification.ts (2 hunks)
  • features/notifications/utils/handleForegroundNotification.ts (4 hunks)
  • features/notifications/utils/index.ts (1 hunks)
  • features/notifications/utils/notifications-badge.ts (1 hunks)
  • features/notifications/utils/onInteractWithNotification.ts (1 hunks)
  • features/notifications/utils/resetNotifications.ts (1 hunks)
  • ios/ConverseNotificationExtension/MMKV.swift (3 hunks)
  • ios/ConverseNotificationExtension/NotificationService.swift (1 hunks)
  • ios/ConverseNotificationExtension/NotificationUtils.swift (1 hunks)
  • ios/ConverseNotificationExtension/Profile.swift (3 hunks)
  • ios/ConverseNotificationExtension/Xmtp/Messages.swift (1 hunks)
  • utils/groupUtils/conversationContainerHelpers.ts (0 hunks)
  • utils/logout/index.tsx (2 hunks)
  • utils/profile/getProfile.ts (1 hunks)
  • utils/sharedData.tsx (1 hunks)
💤 Files with no reviewable changes (1)
  • utils/groupUtils/conversationContainerHelpers.ts
✅ Files skipped from review due to trivial changes (1)
  • features/notifications/notifications-constants.ts
🚧 Files skipped from review as they are similar to previous changes (14)
  • features/notifications/utils/background/handleBackgroundNotification.ts
  • utils/sharedData.tsx
  • ios/ConverseNotificationExtension/Xmtp/Messages.swift
  • ios/ConverseNotificationExtension/Profile.swift
  • features/notifications/utils/onInteractWithNotification.ts
  • features/notifications/utils/accountTopicSubscription.ts
  • features/notifications/utils/handleForegroundNotification.ts
  • features/notifications/utils/index.ts
  • components/PinnedConversations/PinnedV3Conversation.tsx
  • ios/ConverseNotificationExtension/NotificationService.swift
  • features/notifications/utils/notifications-badge.ts
  • utils/profile/getProfile.ts
  • App.tsx
  • utils/logout/index.tsx
🔇 Additional comments (10)
components/ConversationFlashList/ConversationFlashList.tsx (3)

24-24: Great modularization of the type check.

Importing isConversationGroup from a dedicated utility module keeps the code organized and improves readability.


71-72: Clean conditional logic for conversation types.

Using isConversationGroup(item) here simplifies the item type checks, making the code more intuitive than unwrapping conversation objects. This approach increases maintainability.


74-74: Consistent rendering of direct message conversations.

The fallback to <V3DMListItem> is clear and continues the simplified approach to item rendering.

ios/ConverseNotificationExtension/MMKV.swift (2)

68-69: LGTM! Profile decoding change looks good.

The change to decode Profile and return its socials property is a clean implementation.


127-144: LGTM! Badge management implementation looks clean.

Good separation of concerns with dedicated functions for key generation and badge management.

Inconsistent data type usage for badges.

The code stores badges as Double but uses them as Int, which could lead to type-casting issues.

features/notifications/utils/background/protocolNotification.ts (2)

24-41: LGTM! Enhanced error handling and logging.

The addition of try-catch block and detailed logging improves the robustness and debuggability of the notification handling process.


42-49: Verify error handling in getXmtpClient.

The code assumes getXmtpClient will always return a valid client. Consider adding explicit error handling for the case where getXmtpClient fails or returns null.

features/notifications/utils/background/groupMessageNotification.ts (3)

91-106: Previous review comment about race condition is still valid.

There's a potential race condition between finding the previous notification and canceling it.


162-177: Previous review comment about duplicate code is still valid.

The notification cancellation logic is duplicated between group and DM handlers.


231-236: Previous review comment about type guard usage is still valid.

The code should use isConversationGroup before type casting to GroupWithCodecsType.

Added handling for account specific badging for iOS
Cleaned up styles for Android messages
Fixed profile caching
Fixe profile caching in iOS
Added back sharedData setting
Removed old functions to use better typesafe
@alexrisch alexrisch force-pushed the ar/notification-badge-account branch from d4cbb2c to 0946ba4 Compare January 7, 2025 22:35
@alexrisch alexrisch merged commit bbe4a32 into main Jan 7, 2025
8 of 9 checks passed
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