|
| 1 | +# Reaction List Migration Guide |
| 2 | + |
| 3 | +This guide covers the new reaction list controller, view, and detail sheet introduced in the Stream Chat Flutter SDK design refresh. |
| 4 | + |
| 5 | +--- |
| 6 | + |
| 7 | +## Table of Contents |
| 8 | + |
| 9 | +- [StreamReactionListController](#streamreactionlistcontroller) |
| 10 | +- [StreamReactionListView](#streamreactionlistview) |
| 11 | +- [ReactionDetailSheet](#reactiondetailsheet) |
| 12 | +- [Migration Checklist](#migration-checklist) |
| 13 | + |
| 14 | +--- |
| 15 | + |
| 16 | +## StreamReactionListController |
| 17 | + |
| 18 | +`StreamReactionListController` is a new controller in `stream_chat_flutter_core` for fetching and paginating reactions for a message. It extends `PagedValueNotifier<String?, Reaction>`, following the same pattern as `StreamChannelListController` and other list controllers. |
| 19 | + |
| 20 | +### Constructor |
| 21 | + |
| 22 | +```dart |
| 23 | +StreamReactionListController({ |
| 24 | + required StreamChatClient client, |
| 25 | + required String messageId, |
| 26 | + Filter? filter, |
| 27 | + SortOrder<Reaction>? sort, |
| 28 | + int limit = 25, // defaultReactionPagedLimit |
| 29 | +}) |
| 30 | +``` |
| 31 | + |
| 32 | +| Parameter | Type | Default | Description | |
| 33 | +|-----------|------|---------|-------------| |
| 34 | +| `client` | `StreamChatClient` | **required** | The Stream chat client | |
| 35 | +| `messageId` | `String` | **required** | ID of the message to load reactions for | |
| 36 | +| `filter` | `Filter?` | `null` | Query filter; supports fields `type`, `user_id`, `created_at` | |
| 37 | +| `sort` | `SortOrder<Reaction>?` | `null` | Sort order; only `created_at` is backend-supported (`ReactionSortKey.createdAt`) | |
| 38 | +| `limit` | `int` | `25` | Page size | |
| 39 | + |
| 40 | +### Methods |
| 41 | + |
| 42 | +| Method | Description | |
| 43 | +|--------|-------------| |
| 44 | +| `doInitialLoad()` | Loads the first page of reactions | |
| 45 | +| `loadMore(String? nextPageKey)` | Loads the next page using cursor-based pagination | |
| 46 | +| `refresh({bool resetValue = true})` | Reloads from the beginning; resets active filter/sort to constructor values when `resetValue` is `true` | |
| 47 | + |
| 48 | +### Runtime Filter / Sort Changes |
| 49 | + |
| 50 | +You can update `filter` and `sort` at runtime (e.g., when the user taps a reaction-type tab) and then call `doInitialLoad()` to reload: |
| 51 | + |
| 52 | +```dart |
| 53 | +controller.filter = Filter.equal('type', 'like'); |
| 54 | +controller.doInitialLoad(); |
| 55 | +``` |
| 56 | + |
| 57 | +### Basic Usage |
| 58 | + |
| 59 | +```dart |
| 60 | +final controller = StreamReactionListController( |
| 61 | + client: StreamChat.of(context).client, |
| 62 | + messageId: message.id, |
| 63 | + sort: const [SortOption.desc(ReactionSortKey.createdAt)], |
| 64 | +); |
| 65 | +
|
| 66 | +await controller.doInitialLoad(); |
| 67 | +``` |
| 68 | + |
| 69 | +--- |
| 70 | + |
| 71 | +## StreamReactionListView |
| 72 | + |
| 73 | +`StreamReactionListView` is a new widget in `stream_chat_flutter` that renders a paginated list of reactions using a `StreamReactionListController`. |
| 74 | + |
| 75 | +### Constructor |
| 76 | + |
| 77 | +```dart |
| 78 | +StreamReactionListView({ |
| 79 | + required StreamReactionListController controller, |
| 80 | + required StreamReactionListViewIndexedWidgetBuilder itemBuilder, |
| 81 | + PagedValueScrollViewIndexedWidgetBuilder<Reaction>? separatorBuilder, |
| 82 | + WidgetBuilder? emptyBuilder, |
| 83 | + WidgetBuilder? loadingBuilder, |
| 84 | + Widget Function(BuildContext, StreamChatError)? errorBuilder, |
| 85 | + int loadMoreTriggerIndex = 3, |
| 86 | + // Standard ListView params: scrollDirection, reverse, scrollController, |
| 87 | + // primary, physics, shrinkWrap, padding, cacheExtent, etc. |
| 88 | +}) |
| 89 | +``` |
| 90 | + |
| 91 | +| Parameter | Type | Required | Description | |
| 92 | +|-----------|------|----------|-------------| |
| 93 | +| `controller` | `StreamReactionListController` | yes | Provides and paginates the reaction data | |
| 94 | +| `itemBuilder` | `StreamReactionListViewIndexedWidgetBuilder` | yes | Builds each reaction item | |
| 95 | +| `separatorBuilder` | `PagedValueScrollViewIndexedWidgetBuilder<Reaction>?` | no | Builds separators between items (defaults to `SizedBox.shrink`) | |
| 96 | +| `emptyBuilder` | `WidgetBuilder?` | no | Widget shown when there are no reactions | |
| 97 | +| `loadingBuilder` | `WidgetBuilder?` | no | Widget shown during initial load | |
| 98 | +| `errorBuilder` | `Widget Function(BuildContext, StreamChatError)?` | no | Widget shown on error | |
| 99 | +| `loadMoreTriggerIndex` | `int` | no | How many items from the end to trigger the next page load (default: 3) | |
| 100 | + |
| 101 | +### Usage |
| 102 | + |
| 103 | +```dart |
| 104 | +StreamReactionListView( |
| 105 | + controller: controller, |
| 106 | + itemBuilder: (context, reactions, index) { |
| 107 | + final reaction = reactions[index]; |
| 108 | + return ListTile( |
| 109 | + leading: Text(reaction.type), |
| 110 | + title: Text(reaction.user?.name ?? ''), |
| 111 | + ); |
| 112 | + }, |
| 113 | +) |
| 114 | +``` |
| 115 | + |
| 116 | +--- |
| 117 | + |
| 118 | +## ReactionDetailSheet |
| 119 | + |
| 120 | +`ReactionDetailSheet` replaces the old `MessageReactionsModal`. It shows a bottom sheet with the total reaction count, emoji filter chips per reaction type, and a scrollable list of reactors using `StreamReactionListController` internally. |
| 121 | + |
| 122 | +### Showing the Sheet |
| 123 | + |
| 124 | +Use the static `show` method — the constructor is private: |
| 125 | + |
| 126 | +```dart |
| 127 | +final action = await ReactionDetailSheet.show( |
| 128 | + context: context, |
| 129 | + message: message, |
| 130 | + initialReactionType: 'like', // optional: pre-select a reaction type |
| 131 | +); |
| 132 | +``` |
| 133 | + |
| 134 | +`show` returns a `MessageAction?`: |
| 135 | +- `SelectReaction` — if the user picks or removes a reaction |
| 136 | +- `null` — if the sheet is dismissed without selection |
| 137 | + |
| 138 | +### Parameters of `show` |
| 139 | + |
| 140 | +| Parameter | Type | Required | Description | |
| 141 | +|-----------|------|----------|-------------| |
| 142 | +| `context` | `BuildContext` | yes | Build context | |
| 143 | +| `message` | `Message` | yes | The message whose reactions to display | |
| 144 | +| `initialReactionType` | `String?` | no | Pre-selects this reaction type chip when the sheet opens | |
| 145 | + |
| 146 | +### Migration from `MessageReactionsModal` |
| 147 | + |
| 148 | +**Before:** |
| 149 | +```dart |
| 150 | +showDialog( |
| 151 | + context: context, |
| 152 | + builder: (_) => MessageReactionsModal(message: message), |
| 153 | +); |
| 154 | +``` |
| 155 | + |
| 156 | +**After:** |
| 157 | +```dart |
| 158 | +await ReactionDetailSheet.show( |
| 159 | + context: context, |
| 160 | + message: message, |
| 161 | +); |
| 162 | +``` |
| 163 | + |
| 164 | +> **Note:** `ReactionDetailSheet` is displayed as a `DraggableScrollableSheet` (snapping between 50% and full height) and supports cursor-based pagination for large reaction lists. |
| 165 | +
|
| 166 | +--- |
| 167 | + |
| 168 | +## Migration Checklist |
| 169 | + |
| 170 | +- [ ] Replace `MessageReactionsModal` with `ReactionDetailSheet.show()` |
| 171 | +- [ ] Use `StreamReactionListController` to load/paginate reactions programmatically |
| 172 | +- [ ] Use `StreamReactionListView` with a `StreamReactionListController` for custom reaction list UIs |
| 173 | +- [ ] For runtime reaction-type filtering, set `controller.filter` and call `controller.doInitialLoad()` |
0 commit comments