-
Notifications
You must be signed in to change notification settings - Fork 357
feat(llc, core, ui): message reminders #2269
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
base: master
Are you sure you want to change the base?
Conversation
Important Review skippedDraft detected. Please check the settings in the CodeRabbit UI or the You can disable this status message by setting the WalkthroughThis update introduces comprehensive support for message reminders across the chat SDK and sample app. It adds new data models, API methods, event types, and UI components for creating, updating, deleting, and listing reminders on messages, including real-time event handling and reminder management interfaces in both the core library and the Flutter sample application. Changes
Sequence Diagram(s)sequenceDiagram
participant User
participant UI
participant ReminderController
participant StreamChatClient
participant RemindersApi
participant Backend
User->>UI: Selects "Remind me" on a message
UI->>ReminderController: Request to create reminder
ReminderController->>StreamChatClient: createReminder(messageId, remindAt)
StreamChatClient->>RemindersApi: createReminder(messageId, remindAt)
RemindersApi->>Backend: POST /messages/{messageId}/reminders
Backend-->>RemindersApi: Reminder created response
RemindersApi-->>StreamChatClient: Reminder response
StreamChatClient-->>ReminderController: Reminder response
ReminderController-->>UI: Update reminders list
UI-->>User: Show reminder indicator
Backend-->>StreamChatClient: Emits reminder.created event
StreamChatClient-->>ReminderController: Event stream
ReminderController-->>UI: Update reminders list
Assessment against linked issues
Poem
🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. 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)
Other keywords and placeholders
CodeRabbit Configuration File (
|
@coderabbitai review |
✅ Actions performedReview triggered.
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 8
🧹 Nitpick comments (8)
packages/stream_chat/lib/src/core/api/responses.dart (1)
769-773
: Fix the comment to accurately describe the reminder field.The comment incorrectly refers to "Draft returned by the api call" but should reference reminder since this is the base class for reminder responses.
/// Base Model response for draft based api calls. class MessageReminderResponse extends _BaseResponse { - /// Draft returned by the api call + /// Reminder returned by the api call late MessageReminder reminder; }packages/stream_chat_flutter_core/lib/src/stream_message_reminder_list_event_handler.dart (1)
22-24
: Fix documentation inconsistency in onMessageReminderCreated.The documentation comment incorrectly refers to
messageReminderUpdated
event type but should refer to the creation event./// Function which gets called for the event - /// [EventType.messageReminderUpdated]. + /// [EventType.messageReminderCreated]. /// - /// This event is fired when a message reminder is updated. + /// This event is fired when a message reminder is created. /// - /// By default, this updates the reminder in the list. + /// By default, this adds the reminder to the list.Also applies to: 28-36
packages/stream_chat/lib/src/client/channel.dart (1)
1311-1319
: updateReminder(): documentation/argument mismatchThe doc-string mentions
reminderId
but the parameter ismessageId
.
If the endpoint expects a message id (which matches the usage), please update the comment; otherwise the implementation is wrong.packages/stream_chat_flutter_core/lib/src/stream_message_reminder_list_controller.dart (5)
96-107
:value
override re-sorts on every assignment – avoid redundant workEvery time
value
is set, the list is cloned and resorted, even when the incomingPagedValue
is already ordered or contains only the delta fromloadMore()
.
For large lists this can be expensive.
- Short-circuit when the incoming list is already sorted:
- items: success.items.sorted(reminderSort.compare), + items: success.items.isSorted(reminderSort.compare) + ? success.items + : success.items.sorted(reminderSort.compare),
isSorted
can be a tiny extension that performs an O(n) check.
- Consider sorting only once right before exposing items to the UI rather than on every assignment.
[performance]
176-199
: Filter the event stream to save bandwidth & CPU
client.on().listen
delivers all WS events, most of which are irrelevant here.
You can substantially reduce GC pressure and wake-ups by pre-filtering:- _reminderEventSubscription = client.on().listen((event) { + _reminderEventSubscription = client + .on( + EventType.reminderCreated, + EventType.reminderUpdated, + EventType.reminderDeleted, + EventType.notificationReminderDue, + EventType.connectionRecovered, + ) + .listen((event) {This also makes intent explicit.
[performance]
221-235
:merge
extension is non-standard – ensure null-safety & O(n²) avoidanceNice use of
merge
, but:
If
messageId
oruserId
can benull
,(reminder.messageId, reminder.userId)
forms a tuple containingnull
, causingMapKey
collisions. Guard with??
fallbacks or assert non-null.
merge
must be O(n) internally; otherwise repeated updates could degrade to O(n²). Verify the extension’s implementation or switch to aMap<(String,String),MessageReminder>
internally.
240-255
:deleteReminder
could use the key-based approach used inupdateReminder
You already compute a composite key in
updateReminder
; replicating that logic here would simplify the code and avoid an O(n) scan:- final removeIndex = currentReminders.indexWhere( - (it) { - var predicate = it.userId == reminder.userId; - predicate &= it.messageId == reminder.messageId; - return predicate; - }, - ); + final removeIndex = currentReminders.indexWhere( + (it) => it.userId == reminder.userId && + it.messageId == reminder.messageId, + );(Or keep a
Set
/Map
keyed by the tuple for O(1) removals.)
275-279
: Race-free disposal
_unsubscribeFromReminderListEvents()
cancels the subscription but does not set a disposed flag.
If a pendingloadMore()
future completes after disposal, it can re-establish state.
Set a_isDisposed
boolean and early-return inloadMore
/doInitialLoad
when disposed.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (24)
packages/stream_chat/lib/src/client/channel.dart
(3 hunks)packages/stream_chat/lib/src/client/client.dart
(2 hunks)packages/stream_chat/lib/src/core/api/reminders_api.dart
(1 hunks)packages/stream_chat/lib/src/core/api/responses.dart
(2 hunks)packages/stream_chat/lib/src/core/api/responses.g.dart
(1 hunks)packages/stream_chat/lib/src/core/api/stream_chat_api.dart
(2 hunks)packages/stream_chat/lib/src/core/models/channel_config.dart
(2 hunks)packages/stream_chat/lib/src/core/models/channel_config.g.dart
(2 hunks)packages/stream_chat/lib/src/core/models/event.dart
(8 hunks)packages/stream_chat/lib/src/core/models/event.g.dart
(3 hunks)packages/stream_chat/lib/src/core/models/message.dart
(8 hunks)packages/stream_chat/lib/src/core/models/message.g.dart
(2 hunks)packages/stream_chat/lib/src/core/models/message_reminder.dart
(1 hunks)packages/stream_chat/lib/src/core/models/message_reminder.g.dart
(1 hunks)packages/stream_chat/lib/src/event_type.dart
(1 hunks)packages/stream_chat/lib/stream_chat.dart
(1 hunks)packages/stream_chat_flutter_core/lib/src/stream_message_reminder_list_controller.dart
(1 hunks)packages/stream_chat_flutter_core/lib/src/stream_message_reminder_list_event_handler.dart
(1 hunks)packages/stream_chat_flutter_core/lib/stream_chat_flutter_core.dart
(1 hunks)sample_app/lib/pages/channel_list_page.dart
(3 hunks)sample_app/lib/pages/channel_page.dart
(5 hunks)sample_app/lib/pages/reminders_page.dart
(1 hunks)sample_app/lib/widgets/reminder_dialog.dart
(1 hunks)sample_app/pubspec.yaml
(1 hunks)
🔇 Additional comments (46)
sample_app/pubspec.yaml (1)
34-34
:✅ Verification successful
Verify the jiffy package version for currency and security.
The
jiffy ^6.2.1
dependency addition is appropriate for the message reminders feature, as it provides excellent DateTime manipulation and formatting capabilities. However, ensure this version is current and free from security vulnerabilities.
🌐 Web query:
What is the latest stable version of the jiffy Dart package and are there any known security vulnerabilities in version 6.2.1?
💡 Result:
Latest Stable Version of the Jiffy Dart Package
The latest stable version of the Jiffy package for Dart and Flutter is 6.4.3 as of May 2025[1][3]. This version is compatible with Dart 3, supports all major platforms, and includes several improvements over previous versions.
Known Security Vulnerabilities in Jiffy 6.2.1
No security advisories or known vulnerabilities have been published for Jiffy version 6.2.1. Searches of CVE databases and Dart's official security advisory listings return no results for vulnerabilities associated specifically with the
jiffy
package, including version 6.2.1[6][7][9]. The Dart security advisories are integrated with GitHub's advisory database, and any major or recent issues would be surfaced via tools likedart pub get
; as of now, there are no alerts or advisories listed for this version.Summary Table
Package Latest Stable Version Security Issues in 6.2.1 Jiffy (Dart/Flutter) 6.4.3 None reported as of May 2025 If you are starting a new project or maintaining an existing one, upgrading to the latest version (6.4.3) is recommended to benefit from continued bug fixes, improvements, and any future security patches[1][3][2].
Citations:
- 1: https://pub.dev/packages/jiffy
- 2: https://pub.dev/packages/jiffy/versions
- 3: https://fluttergems.dev/packages/jiffy/
- 4: https://codewithandrea.com/newsletter/may-2025/
- 5: https://github.com/jama5262/jiffy/blob/master/doc/README.md
- 6: https://dart.dev/tools/pub/security-advisories
- 7: https://cve.mitre.org/cgi-bin/cvekey.cgi
- 8: https://blog.stackademic.com/the-essential-flutter-dart-package-guide-for-2025-10-most-downloaded-libraries-every-developer-fd7ccfe5dc02
- 9: https://www.cvedetails.com/vendor/12360/Dart.html
- 10: https://www.scribd.com/document/687489337/Locks-Safes-and-Security-an-International-Police-Reference-eBook-Version-by-Marc-Weber-Tobias-Z-lib-org
Audit of jiffy version – no security risks; consider upgrade
- Verified that Jiffy 6.2.1 has no known security advisories or vulnerabilities.
- The latest stable release is 6.4.3 (May 2025), which includes additional bug fixes and improvements.
- You may continue with 6.2.1 safely, but consider updating to
^6.4.3
to benefit from the latest enhancements.packages/stream_chat/lib/stream_chat.dart (1)
47-47
: LGTM! Export follows consistent patterns.The export for
message_reminder.dart
is correctly placed in alphabetical order and follows the established pattern for model exports in this library file.packages/stream_chat/lib/src/core/api/stream_chat_api.dart (2)
12-12
: LGTM! Import follows consistent patterns.The import for
RemindersApi
is correctly placed in alphabetical order with other API imports.
91-93
: LGTM! API integration follows established patterns.The
RemindersApi
integration perfectly follows the established pattern used by other APIs in this class:
- Proper documentation comment
- Lazy initialization using the null-aware assignment operator
- Private nullable field for caching
- Consistent naming convention
packages/stream_chat_flutter_core/lib/stream_chat_flutter_core.dart (1)
25-26
: LGTM! Exports follow consistent architectural patterns.The two new exports for
stream_message_reminder_list_controller.dart
andstream_message_reminder_list_event_handler.dart
are:
- Correctly placed in alphabetical order
- Following the established naming convention
- Consistent with the controller + event handler pattern used by other list management features (channels, drafts, threads)
packages/stream_chat/lib/src/core/models/channel_config.dart (1)
28-28
: LGTM! Clean implementation following established patterns.The
userMessageReminders
field addition follows the existing code patterns perfectly:
- Appropriate default value of
false
for new feature- Consistent constructor parameter ordering
- Clear documentation explaining the field's purpose
- Follows naming conventions and field declaration patterns
Also applies to: 91-92
packages/stream_chat/lib/src/core/models/channel_config.g.dart (1)
36-36
: Auto-generated serialization code looks correct.The JSON serialization/deserialization logic properly handles the new
userMessageReminders
field:
- Correct snake_case JSON key mapping (
user_message_reminders
)- Appropriate null safety with
?? false
default- Follows consistent patterns with other boolean configuration fields
Also applies to: 59-59
sample_app/lib/pages/channel_list_page.dart (3)
13-13
: Clean import addition.The import statement follows the existing pattern and is properly organized with other page imports.
96-104
: Excellent tab implementation following established patterns.The new "Reminders" tab is well-implemented:
- Semantic bookmark icon choice is appropriate for reminders functionality
- Consistent color theming using
_isSelected(4)
logic- Follows the exact same structure as existing navigation items
- Proper index handling for the 5th tab position
149-149
: Proper IndexedStack integration.The
RemindersPage
is correctly added to the IndexedStack at the appropriate index position matching the bottom navigation tab order.packages/stream_chat/lib/src/core/models/message.g.dart (1)
95-97
: Auto-generated serialization correctly handles the new reminder field.The serialization logic properly implements the optional
reminder
field:
- Appropriate null checking during deserialization
- Correct type mapping to
MessageReminder.fromJson
- Follows the same pattern as other optional complex fields (poll, draft)
- Proper null-safe serialization with
?.toJson()
Also applies to: 116-116
packages/stream_chat/lib/src/event_type.dart (1)
162-172
: LGTM! Reminder event types follow established conventions.The new reminder-related event types are properly implemented with consistent naming conventions and appropriate documentation. They follow the existing pattern of camelCase constants with dot-separated lowercase string values.
packages/stream_chat/lib/src/core/models/message_reminder.g.dart (1)
39-41
:❌ Incorrect review comment
Verify null safety consistency for DateTime fields.
The
toJson
method callstoIso8601String()
oncreatedAt
andupdatedAt
without null checks, but thefromJson
method treats these fields as nullable. This suggests potential inconsistency in theMessageReminder
model definition.
🏁 Script executed:
#!/bin/bash # Check the MessageReminder model definition to verify DateTime field nullability cat packages/stream_chat/lib/src/core/models/message_reminder.dart | grep -A 10 -B 5 "createdAt\|updatedAt"Length of output: 3336
Ignore null-safety concerns for
createdAt
/updatedAt
The
MessageReminder
constructor acceptsDateTime? createdAt
andupdatedAt
but immediately defaults them toDateTime.now()
, making the final fields non-nullable. Therefore, callingtoIso8601String()
intoJson
is safe and consistent with the model.No changes are required.
Likely an incorrect or invalid review comment.
packages/stream_chat/lib/src/core/models/event.g.dart (1)
11-11
: LGTM! Event JSON serialization properly handles new fields.The additions for
userId
andreminder
fields are correctly implemented with:
- Proper null safety handling in both serialization and deserialization
- Appropriate JSON key mapping (
user_id
for userId)- Consistent use of conditional serialization patterns
Also applies to: 68-70, 77-77, 114-114
packages/stream_chat/lib/src/core/models/event.dart (4)
13-13
: LGTM! Constructor properly includes new parameters.The
userId
andreminder
parameters are correctly added to the constructor following the existing parameter order and nullable patterns.Also applies to: 43-43
59-60
: LGTM! Field declarations are well-documented and consistent.The new fields follow the established documentation pattern and proper type declarations. The
userId
field provides clear context about event ownership, and thereminder
field enables events to carry reminder data.Also applies to: 154-155
164-164
: LGTM! Serialization fields properly registered.The
user_id
andreminder
keys are correctly added totopLevelFields
, ensuring proper serialization handling by theSerializer
utility.Also applies to: 195-195
206-206
: LGTM! copyWith method comprehensively updated.The
copyWith
method properly includes the new fields in both the parameter list and the constructor call, maintaining consistency with the existing implementation pattern.Also applies to: 236-236, 241-241, 271-271
packages/stream_chat/lib/src/core/api/responses.g.dart (1)
447-469
: LGTM! Generated code follows established patterns.The new JSON deserialization functions for reminder responses are correctly generated and follow the same patterns as existing response deserializers. The handling of nullable fields, default values, and nested object deserialization is consistent with the rest of the codebase.
packages/stream_chat/lib/src/core/models/message.dart (7)
7-7
: LGTM! Proper import added for MessageReminder.The import statement correctly adds the MessageReminder model which is needed for the new reminder field.
71-71
: LGTM! Reminder field properly added to constructor.The reminder parameter is correctly added to the Message constructor with the appropriate nullable type.
312-315
: LGTM! Reminder field properly declared with good documentation.The reminder field is correctly declared as optional with clear documentation explaining its purpose.
364-364
: LGTM! Reminder field added to topLevelFields.The reminder field is correctly included in the topLevelFields array, which is essential for proper serialization handling.
426-426
: LGTM! Reminder field properly integrated into copyWith method.The reminder parameter is correctly added to the copyWith method signature and implementation using the null-const sentinel pattern, consistent with the existing draft field handling.
Also applies to: 507-508
553-553
: LGTM! Reminder field included in merge method.The reminder field is properly included in the merge method to ensure it's copied when combining messages.
618-618
: LGTM! Reminder field added to props for equality comparison.The reminder field is correctly included in the props getter, ensuring it's considered in equality comparisons and hash code generation.
packages/stream_chat/lib/src/core/api/responses.dart (2)
14-14
: LGTM! Proper import added for MessageReminder.The import statement correctly adds the MessageReminder model which is needed for the new response classes.
775-804
: LGTM! Reminder response classes follow established patterns.The new response classes (
CreateReminderResponse
,UpdateReminderResponse
, andQueryRemindersResponse
) are well-structured and follow the same patterns as existing response classes in the codebase. They properly:
- Use
@JsonSerializable(createToJson: false)
annotation- Extend appropriate base classes
- Include static
fromJson
factory methods- Handle lists with default values for
QueryRemindersResponse
- Include pagination support with the
next
fieldpackages/stream_chat_flutter_core/lib/src/stream_message_reminder_list_event_handler.dart (5)
8-8
: LGTM! Well-designed mixin class for event handling.The
mixin class
approach allows flexible composition and provides good default implementations for reminder event handling.
15-20
: LGTM! Proper no-op implementation for connection recovery.The connection recovery handler is appropriately implemented as a no-op with clear documentation explaining its purpose and potential use cases.
44-52
: LGTM! Proper implementation for reminder updates.The update handler correctly extracts the reminder from the event and calls the controller's update method.
60-68
: LGTM! Proper implementation for reminder deletion.The deletion handler correctly extracts the reminder from the event and calls the controller's delete method.
76-81
: LGTM! Logical delegation for reminder due events.The reminder due handler appropriately delegates to the update handler, as a due reminder should be updated in the list to reflect its new status.
packages/stream_chat/lib/src/core/api/reminders_api.dart (1)
10-91
: LGTM! Well-structured API class.The
RemindersApi
class follows consistent patterns with other API classes in the codebase. The use of POST for querying is appropriate given the complexity of filters and pagination parameters that may be included.packages/stream_chat/lib/src/client/client.dart (2)
29-29
: LGTM! Correct import addition.The import for the new MessageReminder model is properly added.
1958-2003
: LGTM! Clean integration of reminder functionality.The reminder methods are well-implemented with:
- Consistent delegation to the API layer
- Clear documentation
- Appropriate parameter handling
- Follows established patterns in the codebase
sample_app/lib/widgets/reminder_dialog.dart (3)
4-15
: LGTM! Excellent use of sealed classes for type safety.The
ReminderOption
hierarchy withScheduledReminder
andBookmarkReminder
provides clear type safety and makes the intent explicit. This is a well-designed pattern for distinguishing between scheduled reminders and bookmarks.
17-53
: LGTM! Well-implemented create reminder dialog.The dialog provides a clean user experience with:
- Predefined durations that cover common use cases
- Human-readable relative time display using Jiffy
- Consistent Cupertino theming
- Proper navigation handling
55-102
: LGTM! Edit dialog with appropriate functionality.The edit dialog appropriately extends the create dialog with the ability to clear due dates for non-bookmark reminders. The conditional logic for showing the "Clear due date" option is correct.
packages/stream_chat/lib/src/core/models/message_reminder.dart (5)
10-14
: LGTM! Excellent use of sentinel pattern.The
_NullConst
pattern is a sophisticated approach to distinguish between explicitly setting a nullable field to null versus leaving it unchanged in thecopyWith
method. This is a best practice for optional nullable parameters.
28-42
: LGTM! Well-designed constructor with sensible defaults.The constructor properly handles:
- Required core identifiers
- Optional related objects that may be populated later
- Automatic timestamp initialization
- Clear parameter organization
48-78
: LGTM! Appropriate JSON serialization configuration.The use of
@JsonKey(includeToJson: false)
for related objects (channel, message, user) is correct since these are typically populated from separate API calls and shouldn't be serialized back to the server.
84-106
: LGTM! Correct implementation of copyWith with sentinel pattern.The
copyWith
method correctly uses the sentinel value to distinguish between:
- Not changing the
remindAt
field (whenremindAt == _nullConst
)- Explicitly setting it to null (when
remindAt
isnull
)- Setting it to a specific DateTime value
This allows for precise control over nullable field updates.
151-164
: LGTM! Type-safe sort keys with extension types.The
MessageReminderSortKey
extension type provides compile-time safety for sort field names while maintaining string compatibility with the API. This is a modern Dart pattern that prevents typos in sort field names.sample_app/lib/pages/channel_page.dart (1)
220-224
:client.createReminder(messageId)
call no longer matches the new signatureAfter making
remindAt
optional (see previous comment) the call is fine; if you keep itrequired
, this line won’t compile. Keep the two in sync.packages/stream_chat_flutter_core/lib/src/stream_message_reminder_list_controller.dart (1)
202-208
:refresh(resetValue: true)
unexpectedly reverts active filters/sortsBecause
resetValue: true
assigns_activeFilter = filter
andfilter
is the constructor value (see first comment), callingrefresh()
after dynamically changing filters reverts the controller to its initial query, surprising callers.Consider either:
- Removing the automatic reset when
resetValue
istrue
, or- Passing explicit parameters to
refresh()
.At minimum, document this gotcha in the dart-doc.
return QueryRemindersResponse.fromJson(response.data); | ||
} | ||
|
||
/// Creates a new reminder for the specified [messageId. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fix documentation typo.
There's a syntax error in the documentation comment.
Apply this diff to fix the typo:
- /// Creates a new reminder for the specified [messageId.
+ /// Creates a new reminder for the specified [messageId].
🤖 Prompt for AI Agents
In packages/stream_chat/lib/src/core/api/reminders_api.dart at line 41, the
documentation comment has a syntax error with an unclosed bracket in
"[messageId.". Fix the typo by properly closing the bracket and ensuring the
comment is syntactically correct.
/// Create a reminder for the given [messageId]. | ||
/// | ||
/// Optionally, provide a [remindAt] date to set when the reminder should | ||
/// be triggered. If not provided, the reminder will be created as a | ||
/// bookmark type instead. | ||
Future<CreateReminderResponse> createReminder( | ||
String messageId, { | ||
required DateTime remindAt, | ||
}) { | ||
_checkInitialized(); | ||
return _client.createReminder( | ||
messageId, | ||
remindAt: remindAt, | ||
); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
createReminder(): Required remindAt
parameter contradicts the API contract
The doc-string says remindAt
is optional (bookmark vs timed reminder) but the method signature makes it required
.
Down-stream code (ChannelPage
, RemindersPage
, etc.) already calls client.createReminder(messageId)
without a 2nd argument, so this will not compile.
-Future<CreateReminderResponse> createReminder(
- String messageId, {
- required DateTime remindAt,
-}) {
+Future<CreateReminderResponse> createReminder(
+ String messageId, {
+ DateTime? remindAt,
+}) {
Also consider validating that an explicit remindAt
is not in the past.
🤖 Prompt for AI Agents
In packages/stream_chat/lib/src/client/channel.dart around lines 1295 to 1309,
the createReminder method incorrectly marks the remindAt parameter as required,
contradicting the doc-string that states it is optional. Update the method
signature to make remindAt optional by removing the required keyword and
allowing null values. Additionally, add validation inside the method to check if
remindAt is provided and ensure it is not set to a past date, throwing an error
or handling it appropriately if it is. This will align the method with the API
contract and prevent compilation errors in downstream code.
void _listenReminderCreated() { | ||
_subscriptions.add( | ||
_channel.on(EventType.reminderCreated).listen((event) { | ||
final reminder = event.reminder; | ||
if (reminder == null) return; | ||
|
||
updateReminder(reminder); | ||
}), | ||
); | ||
} | ||
|
||
void _listenReminderUpdated() { | ||
_subscriptions.add( | ||
_channel.on(EventType.reminderUpdated).listen((event) { | ||
final reminder = event.reminder; | ||
if (reminder == null) return; | ||
|
||
updateReminder(reminder); | ||
}), | ||
); | ||
} | ||
|
||
void _listenReminderDeleted() { | ||
_subscriptions.add( | ||
_channel.on(EventType.reminderDeleted).listen((event) { | ||
final reminder = event.reminder; | ||
if (reminder == null) return; | ||
|
||
deleteReminder(reminder); | ||
}), | ||
); | ||
} | ||
|
||
/// Updates the [reminder] of the message if it exists. | ||
void updateReminder(MessageReminder reminder) { | ||
final messageId = reminder.messageId; | ||
for (final message in messages) { | ||
if (message.id == messageId) { | ||
return updateMessage( | ||
message.copyWith(reminder: reminder), | ||
); | ||
} | ||
} | ||
} | ||
|
||
/// Deletes the [reminder] of the message if it exists. | ||
void deleteReminder(MessageReminder reminder) { | ||
// TODO: Delete the reminder from the persistence client. | ||
|
||
final messageId = reminder.messageId; | ||
for (final message in messages) { | ||
if (message.id == messageId) { | ||
return updateMessage( | ||
message.copyWith(reminder: null), | ||
); | ||
} | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Thread-messages are ignored when updating/deleting a reminder
updateReminder()
/ deleteReminder()
iterate only over messages
, so reminders attached to a thread reply that is not shown in channel will never be updated locally.
-for (final message in messages) {
+for (final message in [...messages, ...threads.values.expand((m) => m)]) {
Without this, the UI can display stale data.
📝 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.
void _listenReminderCreated() { | |
_subscriptions.add( | |
_channel.on(EventType.reminderCreated).listen((event) { | |
final reminder = event.reminder; | |
if (reminder == null) return; | |
updateReminder(reminder); | |
}), | |
); | |
} | |
void _listenReminderUpdated() { | |
_subscriptions.add( | |
_channel.on(EventType.reminderUpdated).listen((event) { | |
final reminder = event.reminder; | |
if (reminder == null) return; | |
updateReminder(reminder); | |
}), | |
); | |
} | |
void _listenReminderDeleted() { | |
_subscriptions.add( | |
_channel.on(EventType.reminderDeleted).listen((event) { | |
final reminder = event.reminder; | |
if (reminder == null) return; | |
deleteReminder(reminder); | |
}), | |
); | |
} | |
/// Updates the [reminder] of the message if it exists. | |
void updateReminder(MessageReminder reminder) { | |
final messageId = reminder.messageId; | |
for (final message in messages) { | |
if (message.id == messageId) { | |
return updateMessage( | |
message.copyWith(reminder: reminder), | |
); | |
} | |
} | |
} | |
/// Deletes the [reminder] of the message if it exists. | |
void deleteReminder(MessageReminder reminder) { | |
// TODO: Delete the reminder from the persistence client. | |
final messageId = reminder.messageId; | |
for (final message in messages) { | |
if (message.id == messageId) { | |
return updateMessage( | |
message.copyWith(reminder: null), | |
); | |
} | |
} | |
} | |
/// Updates the [reminder] of the message if it exists. | |
void updateReminder(MessageReminder reminder) { | |
final messageId = reminder.messageId; | |
- for (final message in messages) { | |
+ for (final message in [...messages, ...threads.values.expand((m) => m)]) { | |
if (message.id == messageId) { | |
return updateMessage( | |
message.copyWith(reminder: reminder), | |
); | |
} | |
} | |
} | |
/// Deletes the [reminder] of the message if it exists. | |
void deleteReminder(MessageReminder reminder) { | |
// TODO: Delete the reminder from the persistence client. | |
final messageId = reminder.messageId; | |
- for (final message in messages) { | |
+ for (final message in [...messages, ...threads.values.expand((m) => m)]) { | |
if (message.id == messageId) { | |
return updateMessage( | |
message.copyWith(reminder: null), | |
); | |
} | |
} | |
} |
🤖 Prompt for AI Agents
In packages/stream_chat/lib/src/client/channel.dart around lines 2629 to 2686,
the updateReminder and deleteReminder methods only iterate over the top-level
messages list, ignoring thread replies that may have reminders. To fix this,
modify these methods to also iterate over thread messages (replies) within each
message, ensuring reminders attached to thread replies are updated or deleted
accordingly. This will prevent stale reminder data in the UI by covering all
messages including those in threads.
import 'dart:async'; | ||
|
||
import 'package:flutter/material.dart'; | ||
import 'package:flutter_slidable/flutter_slidable.dart'; | ||
import 'package:go_router/go_router.dart'; | ||
import 'package:sample_app/routes/routes.dart'; | ||
import 'package:sample_app/widgets/reminder_dialog.dart'; | ||
import 'package:stream_chat_flutter/stream_chat_flutter.dart'; | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Missing import for Jiffy
leads to unresolved identifier
TimedReminderIndicator
uses Jiffy
, but the file doesn’t import it.
import 'package:flutter/material.dart';
+import 'package:jiffy/jiffy.dart';
If you want to avoid the heavy dependency you could switch to timeago
.
📝 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.
import 'dart:async'; | |
import 'package:flutter/material.dart'; | |
import 'package:flutter_slidable/flutter_slidable.dart'; | |
import 'package:go_router/go_router.dart'; | |
import 'package:sample_app/routes/routes.dart'; | |
import 'package:sample_app/widgets/reminder_dialog.dart'; | |
import 'package:stream_chat_flutter/stream_chat_flutter.dart'; | |
import 'dart:async'; | |
import 'package:flutter/material.dart'; | |
+import 'package:jiffy/jiffy.dart'; | |
import 'package:flutter_slidable/flutter_slidable.dart'; | |
import 'package:go_router/go_router.dart'; | |
import 'package:sample_app/routes/routes.dart'; | |
import 'package:sample_app/widgets/reminder_dialog.dart'; | |
import 'package:stream_chat_flutter/stream_chat_flutter.dart'; |
🤖 Prompt for AI Agents
In sample_app/lib/pages/reminders_page.dart at the top import section (lines 1
to 9), the code uses the `Jiffy` class in `TimedReminderIndicator` but does not
import the `jiffy` package, causing an unresolved identifier error. Fix this by
adding the appropriate import statement for `Jiffy` (e.g., `import
'package:jiffy/jiffy.dart';`). Alternatively, if you want to avoid adding the
heavy `jiffy` dependency, refactor the code to use the `timeago` package instead
and import it accordingly.
Submit a pull request
Linear: FLU-143
Screenshots / Videos
Screen.Recording.2025-06-03.at.13.21.29.mov
Summary by CodeRabbit
New Features
Enhancements
Chores
jiffy
package dependency for improved date/time handling.