Skip to content

Conversation

@xsahil03x
Copy link
Member

@xsahil03x xsahil03x commented Nov 13, 2025

Submit a pull request

Fixes: #2421

Description of the pull request

This PR introduces a new MessagePreviewFormatter class to allow developers to customize how message previews are formatted in the channel list.

Previously, the formatting logic was hardcoded within the StreamMessagePreviewText and StreamDraftMessagePreviewText widgets. This change extracts that logic into a new, configurable StreamMessagePreviewFormatter class.

Key changes:

  • MessagePreviewFormatter: A new abstract class is introduced to define the contract for formatting message and draft message previews.
  • StreamMessagePreviewFormatter: The default implementation that replicates the previous hardcoded behavior. It can be extended to override specific formatting methods (e.g., for polls, attachments, or group messages).
  • StreamChatConfiguration: The configuration now accepts an optional messagePreviewFormatter instance, allowing for app-wide customization.
  • The StreamMessagePreviewText and StreamDraftMessagePreviewText widgets have been refactored to use the new formatter, significantly simplifying their implementation.

Summary by CodeRabbit

  • New Features

    • Message previews in channel lists and draft messages can now be customized globally through configuration.
    • Added customization interface to override formatting logic and styling for message previews throughout the application.
  • Refactor

    • Centralized message preview formatting for improved consistency across the app.
  • Tests

    • Extended test coverage for custom message preview formatting scenarios.

This commit introduces a new `MessagePreviewFormatter` class to allow developers to customize how message previews are formatted in the channel list.

Previously, the formatting logic was hardcoded within the `StreamMessagePreviewText` and `StreamDraftMessagePreviewText` widgets. This change extracts that logic into a new, configurable `StreamMessagePreviewFormatter` class.

Key changes:
- **`MessagePreviewFormatter`:** A new abstract class is introduced to define the contract for formatting message and draft message previews.
- **`StreamMessagePreviewFormatter`:** The default implementation that replicates the previous hardcoded behavior. It can be extended to override specific formatting methods (e.g., for polls, attachments, or group messages).
- **`StreamChatConfiguration`:** The configuration now accepts an optional `messagePreviewFormatter` instance, allowing for app-wide customization.
- The `StreamMessagePreviewText` and `StreamDraftMessagePreviewText` widgets have been refactored to use the new formatter, significantly simplifying their implementation.
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 13, 2025

Warning

Rate limit exceeded

@xsahil03x has exceeded the limit for the number of commits or files that can be reviewed per hour. Please wait 19 minutes and 47 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 ae88b80 and 7999efa.

📒 Files selected for processing (3)
  • packages/stream_chat_flutter/lib/src/scroll_view/channel_scroll_view/stream_channel_list_tile.dart (0 hunks)
  • packages/stream_chat_flutter/lib/src/scroll_view/draft_scroll_view/stream_draft_list_tile.dart (0 hunks)
  • packages/stream_chat_flutter/lib/src/scroll_view/thread_scroll_view/stream_thread_list_tile.dart (0 hunks)

Walkthrough

This PR introduces a centralized message preview formatting system for the Stream Chat Flutter package. It adds a new MessagePreviewFormatter interface and StreamMessagePreviewFormatter implementation with customization hooks, integrates it into StreamChatConfigurationData, and refactors message preview rendering widgets to delegate formatting logic to this new formatter.

Changes

Cohort / File(s) Summary
New Formatter Interface & Implementation
src/utils/message_preview_formatter.dart
Introduces MessagePreviewFormatter interface with two formatting methods: formatMessage and formatDraftMessage. Implements StreamMessagePreviewFormatter with logic for handling deleted, system, poll, and regular messages; supports mention bolding; includes protected customization hooks for message types, sender context, and attachments; adds String.splitByRegExp extension for splitting text around mentions.
Configuration Integration
src/stream_chat_configuration.dart
Adds messagePreviewFormatter field to StreamChatConfigurationData; updates factory constructor with optional messagePreviewFormatter parameter (defaults to MessagePreviewFormatter()); updates copyWith method to accept and propagate the formatter.
Widget Refactoring
src/channel/stream_message_preview_text.dart, src/channel/stream_draft_message_preview_text.dart
Replaces inline preview text construction with calls to config.messagePreviewFormatter.formatMessage and formatDraftMessage; removes helper methods (_getPreviewText, _pollPreviewText, etc.) and centralizes formatting logic.
Public API Exports
lib/stream_chat_flutter.dart
Exports src/channel/stream_draft_message_preview_text.dart and src/utils/message_preview_formatter.dart for public API access.
Test Updates
test/src/channel/stream_draft_message_preview_text_test.dart, test/src/channel/stream_message_preview_text_test.dart
Adds mock-based testing infrastructure; extends test helpers with optional configData parameter; introduces test group for custom formatter override behavior; includes private test formatter class with custom prefix override.
Documentation
CHANGELOG.md
Records new public interfaces, implementations, and configuration hook.

Sequence Diagram(s)

sequenceDiagram
    participant Widget as Message Preview Widget
    participant Config as StreamChatConfiguration
    participant Formatter as StreamMessagePreviewFormatter
    participant Theme as Theme/Translations

    Widget->>Config: access config.messagePreviewFormatter
    Config-->>Widget: returns MessagePreviewFormatter
    Widget->>Formatter: formatMessage(context, message, ...)
    Formatter->>Formatter: determine message type<br/>(deleted/system/poll/regular)
    Formatter->>Formatter: extract message content<br/>(attachments, text, etc.)
    Formatter->>Formatter: apply sender context<br/>(current user/DM/group)
    Formatter->>Theme: resolve theme colors & translations
    Formatter->>Formatter: build TextSpan with styling<br/>(bold mentions, colors)
    Formatter-->>Widget: return formatted TextSpan
    Widget->>Widget: render Text.rich(textSpan)
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

  • message_preview_formatter.dart: High complexity with numerous protected customization hooks, attachment type handling, poll preview logic, and mention bolding via regex splitting. Requires careful verification of message type branches and styling consistency.
  • Widget refactoring files: Verify that all prior logic (special handling for deletions, system messages, polls, mentions) has been correctly moved into the formatter and invoked correctly.
  • Configuration integration: Review the default instance creation and copyWith propagation to ensure messagePreviewFormatter is always non-null.
  • Test coverage: Validate that custom formatter override scenario is adequately tested; check mock setup in stream_draft_message_preview_text_test.dart.

Possibly related PRs

  • feat(ui)!: refactor poll message into attachment #2296: Refactors poll messages into PollAttachment and removes hasPoll property; related because this PR introduces formatPollMessage as a customization hook within the new formatter, affecting how polls are rendered in previews.

Suggested reviewers

  • renefloor
  • Brazol

Poem

🐰 A formatter hops into the stream,
With hooks and customization supreme,
Messages now dance with grace,
In every channel's preview space, ✨📝
Clean and composable—a dream!

Pre-merge checks and finishing touches

✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change: introducing MessagePreviewFormatter as a new customization interface for message preview formatting.
Linked Issues check ✅ Passed The PR successfully implements formatMessageAttachments to display custom attachment types with icons and titles, meeting the core requirement from issue #2421 to support preview messages with custom attachments.
Out of Scope Changes check ✅ Passed All changes are directly scoped to implementing the MessagePreviewFormatter abstraction and refactoring preview widgets, with no unrelated modifications detected.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

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.

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)
packages/stream_chat_flutter/lib/src/utils/message_preview_formatter.dart (1)

481-517: Ensure draft prefix styling is applied even when textStyle is null

In formatDraftMessage, the bold/accentPrimary styling is derived from textStyle?.copyWith(...). If callers omit textStyle, the prefix ends up with no explicit style and won't reliably get the documented accent-colored/bold treatment, falling back to whatever the ambient DefaultTextStyle is.

You may want to normalize through a base style so the prefix styling is consistent:

   @override
   TextSpan formatDraftMessage(
     BuildContext context,
     DraftMessage draftMessage, {
     TextStyle? textStyle,
   }) {
-    final theme = StreamChatTheme.of(context);
-    final colorTheme = theme.colorTheme;
-
-    return TextSpan(
-      text: getDraftPrefix(context),
-      style: textStyle?.copyWith(
-        fontWeight: FontWeight.bold,
-        color: colorTheme.accentPrimary,
-      ),
-      children: [
-        const TextSpan(text: ' '), // Space between prefix and message
-        TextSpan(text: draftMessage.text, style: textStyle),
-      ],
-    );
+    final theme = StreamChatTheme.of(context);
+    final colorTheme = theme.colorTheme;
+    final baseStyle = textStyle ?? DefaultTextStyle.of(context).style;
+
+    return TextSpan(
+      text: getDraftPrefix(context),
+      style: baseStyle.copyWith(
+        fontWeight: FontWeight.bold,
+        color: colorTheme.accentPrimary,
+      ),
+      children: [
+        const TextSpan(text: ' '), // Space between prefix and message
+        TextSpan(text: draftMessage.text, style: baseStyle),
+      ],
+    );
   }

This keeps behavior the same when a textStyle is provided, while making the documented styling reliable when it is omitted.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Linear 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 3899379 and ae88b80.

📒 Files selected for processing (8)
  • packages/stream_chat_flutter/CHANGELOG.md (1 hunks)
  • packages/stream_chat_flutter/lib/src/channel/stream_draft_message_preview_text.dart (1 hunks)
  • packages/stream_chat_flutter/lib/src/channel/stream_message_preview_text.dart (1 hunks)
  • packages/stream_chat_flutter/lib/src/stream_chat_configuration.dart (6 hunks)
  • packages/stream_chat_flutter/lib/src/utils/message_preview_formatter.dart (1 hunks)
  • packages/stream_chat_flutter/lib/stream_chat_flutter.dart (2 hunks)
  • packages/stream_chat_flutter/test/src/channel/stream_draft_message_preview_text_test.dart (2 hunks)
  • packages/stream_chat_flutter/test/src/channel/stream_message_preview_text_test.dart (3 hunks)
🧰 Additional context used
🧠 Learnings (3)
📓 Common learnings
Learnt from: xsahil03x
Repo: GetStream/stream-chat-flutter PR: 2394
File: packages/stream_chat_flutter/lib/src/message_action/message_actions_builder.dart:82-92
Timestamp: 2025-09-25T08:19:01.469Z
Learning: In the Stream Chat Flutter library, when deleting a message that hasn't been sent to the server yet (message.remoteCreatedAt == null) or is bounced with error, the _deleteMessage method in channel.dart automatically handles deletion locally via _deleteLocalMessage without making API calls, preventing 404 errors and deletingFailed states.
Learnt from: xsahil03x
Repo: GetStream/stream-chat-flutter PR: 2394
File: packages/stream_chat_flutter/lib/src/message_action/message_actions_builder.dart:82-92
Timestamp: 2025-09-25T08:19:01.469Z
Learning: In the Stream Chat Flutter library, when deleting a message that hasn't been sent to the server yet (message.remoteCreatedAt == null) or is bounced with error, the _deleteMessage method in channel.dart automatically handles deletion locally via _deleteLocalMessage without making API calls, preventing 404 errors and deletingFailed states.
📚 Learning: 2025-09-25T08:19:01.469Z
Learnt from: xsahil03x
Repo: GetStream/stream-chat-flutter PR: 2394
File: packages/stream_chat_flutter/lib/src/message_action/message_actions_builder.dart:82-92
Timestamp: 2025-09-25T08:19:01.469Z
Learning: In the Stream Chat Flutter library, when deleting a message that hasn't been sent to the server yet (message.remoteCreatedAt == null) or is bounced with error, the _deleteMessage method in channel.dart automatically handles deletion locally via _deleteLocalMessage without making API calls, preventing 404 errors and deletingFailed states.

Applied to files:

  • packages/stream_chat_flutter/CHANGELOG.md
  • packages/stream_chat_flutter/lib/stream_chat_flutter.dart
  • packages/stream_chat_flutter/lib/src/channel/stream_message_preview_text.dart
  • packages/stream_chat_flutter/lib/src/utils/message_preview_formatter.dart
  • packages/stream_chat_flutter/lib/src/channel/stream_draft_message_preview_text.dart
  • packages/stream_chat_flutter/test/src/channel/stream_draft_message_preview_text_test.dart
📚 Learning: 2025-09-25T08:19:01.469Z
Learnt from: xsahil03x
Repo: GetStream/stream-chat-flutter PR: 2394
File: packages/stream_chat_flutter/lib/src/message_action/message_actions_builder.dart:82-92
Timestamp: 2025-09-25T08:19:01.469Z
Learning: In the Stream Chat Flutter library, when deleting a message with MessageSendingStatus.failed or MessageSendingStatus.failed_update status, the _deleteMessage method in channel.dart automatically handles deletion locally via _deleteLocalMessage without making API calls, preventing 404 errors and deletingFailed states.

Applied to files:

  • packages/stream_chat_flutter/CHANGELOG.md
  • packages/stream_chat_flutter/lib/stream_chat_flutter.dart
  • packages/stream_chat_flutter/lib/src/channel/stream_message_preview_text.dart
  • packages/stream_chat_flutter/lib/src/utils/message_preview_formatter.dart
  • packages/stream_chat_flutter/lib/src/channel/stream_draft_message_preview_text.dart
  • packages/stream_chat_flutter/test/src/channel/stream_draft_message_preview_text_test.dart
⏰ 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). (11)
  • GitHub Check: build (ios)
  • GitHub Check: test
  • GitHub Check: build (android)
  • GitHub Check: analyze
  • GitHub Check: format
  • GitHub Check: stream_chat_localizations
  • GitHub Check: stream_chat_flutter_core
  • GitHub Check: stream_chat_flutter
  • GitHub Check: stream_chat_persistence
  • GitHub Check: stream_chat
  • GitHub Check: analyze_legacy_versions
🔇 Additional comments (9)
packages/stream_chat_flutter/lib/src/channel/stream_draft_message_preview_text.dart (1)

21-28: Draft preview widget now cleanly delegates to configuration formatter

Using StreamChatConfiguration.of(context).messagePreviewFormatter.formatDraftMessage(...) keeps draft previews in sync with global configuration and simplifies this widget. No issues spotted.

packages/stream_chat_flutter/CHANGELOG.md (1)

5-8: Changelog accurately documents new message preview formatter hooks

The entry correctly names MessagePreviewFormatter, StreamMessagePreviewFormatter, and StreamChatConfigurationData.messagePreviewFormatter, and describes their purpose in line with the implementation.

packages/stream_chat_flutter/lib/src/stream_chat_configuration.dart (1)

118-140: messagePreviewFormatter configuration wiring looks consistent

The messagePreviewFormatter field is correctly threaded through the factory (?? MessagePreviewFormatter()), the private constructor (required), and copyWith (preserves existing value when omitted). The doc comment clearly states the default to MessagePreviewFormatter, matching usage.

Also applies to: 151-163, 186-189

packages/stream_chat_flutter/test/src/channel/stream_message_preview_text_test.dart (2)

29-30: Injecting StreamChatConfigurationData into tests is a good extension point

The optional configData parameter and wiring to StreamChat(streamChatConfigData: configData, ...) make it easy to exercise custom preview formatting in tests without touching production code, while keeping existing call sites unaffected.

Also applies to: 38-44


545-671: Custom MessagePreviewFormatter tests cover key override scenarios

The Custom MessagePreviewFormatter group and _CustomMessagePreviewFormatter implementation thoroughly validate overrides for current-user/group messages, polls, attachments (including a custom product type), and direct messages. This gives strong confidence that downstream apps can customize previews and support custom attachments as intended by the new formatter API.

Also applies to: 675-729

packages/stream_chat_flutter/lib/stream_chat_flutter.dart (1)

42-42: Exporting draft preview and formatter APIs makes customization accessible

Adding exports for src/channel/stream_draft_message_preview_text.dart and src/utils/message_preview_formatter.dart correctly exposes the new draft preview widget and formatter interface/implementation to package consumers.

Also applies to: 134-135

packages/stream_chat_flutter/lib/src/channel/stream_message_preview_text.dart (1)

34-43: Message preview widget now cleanly delegates to MessagePreviewFormatter

Using StreamChatConfiguration.of(context).messagePreviewFormatter.formatMessage(...) after translation and replaceMentions centralizes preview logic (polls, attachments, group prefixes, etc.) in the formatter and keeps this widget simple. No behavioral issues stand out.

packages/stream_chat_flutter/test/src/channel/stream_draft_message_preview_text_test.dart (1)

3-7: Draft preview tests correctly validate default and custom formatter behavior

The updated helper wiring StreamChat(streamChatConfigData: ...) plus _CustomMessagePreviewFormatter.getDraftPrefix give good coverage of both the default 'Draft:' prefix and a customized '✏️' prefix, confirming that draft previews respect StreamChatConfigurationData.messagePreviewFormatter.

Also applies to: 14-22, 26-30, 55-75, 78-85

packages/stream_chat_flutter/lib/src/utils/message_preview_formatter.dart (1)

1-420: Centralized preview formatter design looks solid and extensible

The MessagePreviewFormatter interface and StreamMessagePreviewFormatter implementation nicely encapsulate preview behavior: _buildPreviewText routes by message type and sender/channel context, formatMessageAttachments maps core attachment types to the expected icons/text (including audio/file/image/video/giphy/voiceRecording), formatPollMessage handles voter/creator/name fallbacks, and mention bolding via splitByRegExp keeps styling localized to @user segments. The protected hooks (regular/system/deleted/poll messages, current/direct/group prefixes, attachment and draft handling) give downstream apps clear extension points for custom attachment types and alternative prefixes without duplicating base logic.

Also applies to: 442-541

@xsahil03x xsahil03x force-pushed the feat/message-preview-formatter branch from 29bc946 to 7999efa Compare November 13, 2025 23:08
@codecov
Copy link

codecov bot commented Nov 13, 2025

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 64.24%. Comparing base (3899379) to head (7999efa).
⚠️ Report is 1 commits behind head on master.

Additional details and impacted files
@@            Coverage Diff             @@
##           master    #2441      +/-   ##
==========================================
+ Coverage   64.19%   64.24%   +0.04%     
==========================================
  Files         415      416       +1     
  Lines       25986    26022      +36     
==========================================
+ Hits        16682    16718      +36     
  Misses       9304     9304              

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Copy link
Contributor

@Brazol Brazol left a comment

Choose a reason for hiding this comment

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

LGTM

@xsahil03x xsahil03x merged commit a9cd6ae into master Nov 14, 2025
17 checks passed
@xsahil03x xsahil03x deleted the feat/message-preview-formatter branch November 14, 2025 09:44
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.

Support preview message containing additional custom attachments

3 participants