@cometchat/skills 3.0.0 → 4.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +44 -17
- package/bin/install.js +389 -43
- package/package.json +19 -9
- package/skills/cometchat/SKILL.md +1066 -265
- package/skills/cometchat-android-v5/SKILL.md +120 -0
- package/skills/cometchat-android-v5-components/SKILL.md +430 -0
- package/skills/cometchat-android-v5-core/SKILL.md +468 -0
- package/skills/cometchat-android-v5-customization/SKILL.md +305 -0
- package/skills/cometchat-android-v5-extensions/SKILL.md +124 -0
- package/skills/cometchat-android-v5-features/SKILL.md +130 -0
- package/skills/cometchat-android-v5-placement/SKILL.md +276 -0
- package/skills/cometchat-android-v5-production/SKILL.md +94 -0
- package/skills/cometchat-android-v5-push/SKILL.md +620 -0
- package/skills/cometchat-android-v5-testing/SKILL.md +187 -0
- package/skills/cometchat-android-v5-theming/SKILL.md +166 -0
- package/skills/cometchat-android-v5-troubleshooting/SKILL.md +73 -0
- package/skills/cometchat-android-v6/SKILL.md +107 -0
- package/skills/cometchat-android-v6-builder-settings/SKILL.md +145 -0
- package/skills/cometchat-android-v6-compose-components/SKILL.md +202 -0
- package/skills/cometchat-android-v6-compose-customization/SKILL.md +280 -0
- package/skills/cometchat-android-v6-compose-placement/SKILL.md +213 -0
- package/skills/cometchat-android-v6-compose-theming/SKILL.md +224 -0
- package/skills/cometchat-android-v6-core/SKILL.md +354 -0
- package/skills/cometchat-android-v6-events/SKILL.md +212 -0
- package/skills/cometchat-android-v6-extensions/SKILL.md +191 -0
- package/skills/cometchat-android-v6-features/SKILL.md +130 -0
- package/skills/cometchat-android-v6-kotlin-components/SKILL.md +197 -0
- package/skills/cometchat-android-v6-kotlin-customization/SKILL.md +268 -0
- package/skills/cometchat-android-v6-kotlin-placement/SKILL.md +248 -0
- package/skills/cometchat-android-v6-kotlin-theming/SKILL.md +202 -0
- package/skills/cometchat-android-v6-production/SKILL.md +187 -0
- package/skills/cometchat-android-v6-push/SKILL.md +274 -0
- package/skills/cometchat-android-v6-testing/SKILL.md +279 -0
- package/skills/cometchat-android-v6-troubleshooting/SKILL.md +249 -0
- package/skills/cometchat-angular-components/SKILL.md +706 -0
- package/skills/cometchat-angular-core/SKILL.md +444 -0
- package/skills/cometchat-angular-customization/SKILL.md +424 -0
- package/skills/cometchat-angular-features/SKILL.md +447 -0
- package/skills/cometchat-angular-patterns/SKILL.md +447 -0
- package/skills/cometchat-angular-placement/SKILL.md +685 -0
- package/skills/cometchat-angular-production/SKILL.md +415 -0
- package/skills/cometchat-angular-theming/SKILL.md +365 -0
- package/skills/cometchat-angular-troubleshooting/SKILL.md +329 -0
- package/skills/cometchat-astro-patterns/SKILL.md +3 -3
- package/skills/cometchat-components/SKILL.md +11 -0
- package/skills/cometchat-core/SKILL.md +11 -6
- package/skills/cometchat-customization/references/component-catalog.md +1 -1
- package/skills/cometchat-features/SKILL.md +176 -108
- package/skills/cometchat-flutter-v5/SKILL.md +167 -0
- package/skills/cometchat-flutter-v5-calls/SKILL.md +192 -0
- package/skills/cometchat-flutter-v5-conversations/SKILL.md +117 -0
- package/skills/cometchat-flutter-v5-core/SKILL.md +221 -0
- package/skills/cometchat-flutter-v5-customization/SKILL.md +227 -0
- package/skills/cometchat-flutter-v5-events/SKILL.md +155 -0
- package/skills/cometchat-flutter-v5-messages/SKILL.md +258 -0
- package/skills/cometchat-flutter-v5-production/SKILL.md +207 -0
- package/skills/cometchat-flutter-v5-push/SKILL.md +284 -0
- package/skills/cometchat-flutter-v5-theming/SKILL.md +160 -0
- package/skills/cometchat-flutter-v5-troubleshooting/SKILL.md +129 -0
- package/skills/cometchat-flutter-v5-users-groups/SKILL.md +151 -0
- package/skills/cometchat-flutter-v6/SKILL.md +445 -0
- package/skills/cometchat-flutter-v6-calls/SKILL.md +333 -0
- package/skills/cometchat-flutter-v6-components/SKILL.md +365 -0
- package/skills/cometchat-flutter-v6-conversations/SKILL.md +210 -0
- package/skills/cometchat-flutter-v6-core/SKILL.md +305 -0
- package/skills/cometchat-flutter-v6-customization/SKILL.md +666 -0
- package/skills/cometchat-flutter-v6-events/SKILL.md +216 -0
- package/skills/cometchat-flutter-v6-features/SKILL.md +406 -0
- package/skills/cometchat-flutter-v6-messages/SKILL.md +333 -0
- package/skills/cometchat-flutter-v6-migration/SKILL.md +381 -0
- package/skills/cometchat-flutter-v6-placement/SKILL.md +398 -0
- package/skills/cometchat-flutter-v6-production/SKILL.md +632 -0
- package/skills/cometchat-flutter-v6-theming/SKILL.md +260 -0
- package/skills/cometchat-flutter-v6-troubleshooting/SKILL.md +726 -0
- package/skills/cometchat-flutter-v6-users-groups/SKILL.md +216 -0
- package/skills/cometchat-ios/SKILL.md +323 -0
- package/skills/cometchat-ios-components/SKILL.md +651 -0
- package/skills/cometchat-ios-core/SKILL.md +822 -0
- package/skills/cometchat-ios-customization/SKILL.md +825 -0
- package/skills/cometchat-ios-features/SKILL.md +725 -0
- package/skills/cometchat-ios-placement/SKILL.md +750 -0
- package/skills/cometchat-ios-production/SKILL.md +730 -0
- package/skills/cometchat-ios-push/SKILL.md +582 -0
- package/skills/cometchat-ios-theming/SKILL.md +631 -0
- package/skills/cometchat-ios-troubleshooting/SKILL.md +983 -0
- package/skills/cometchat-native-bare-patterns/SKILL.md +470 -0
- package/skills/cometchat-native-components/SKILL.md +594 -0
- package/skills/cometchat-native-core/SKILL.md +407 -0
- package/skills/cometchat-native-customization/SKILL.md +594 -0
- package/skills/cometchat-native-expo-patterns/SKILL.md +485 -0
- package/skills/cometchat-native-features/SKILL.md +608 -0
- package/skills/cometchat-native-placement/SKILL.md +500 -0
- package/skills/cometchat-native-production/SKILL.md +694 -0
- package/skills/cometchat-native-push/SKILL.md +593 -0
- package/skills/cometchat-native-testing/SKILL.md +583 -0
- package/skills/cometchat-native-theming/SKILL.md +656 -0
- package/skills/cometchat-native-troubleshooting/SKILL.md +433 -0
- package/skills/cometchat-nextjs-patterns/SKILL.md +5 -5
- package/skills/cometchat-production/SKILL.md +60 -0
- package/skills/cometchat-react-router-patterns/SKILL.md +23 -21
|
@@ -0,0 +1,666 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: cometchat-flutter-v6-customization
|
|
3
|
+
description: >
|
|
4
|
+
Customize CometChat Flutter UIKit v6 beyond defaults — four tiers: props/view slots,
|
|
5
|
+
request builders, text formatters + message templates, and BubbleFactory/DataSource.
|
|
6
|
+
Use when the user wants custom bubbles, custom headers, custom list items, custom
|
|
7
|
+
message actions, or custom message types.
|
|
8
|
+
license: "MIT"
|
|
9
|
+
compatibility: "cometchat_chat_uikit ^6.0.0-beta2"
|
|
10
|
+
allowed-tools: "executeBash, readFile, readCode, fileSearch, listDirectory, grepSearch"
|
|
11
|
+
metadata:
|
|
12
|
+
author: "CometChat"
|
|
13
|
+
version: "3.0.0"
|
|
14
|
+
tags: "cometchat flutter customization bubbles templates formatters datasource"
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
# CometChat Flutter UIKit v6 — Customization Guide
|
|
18
|
+
|
|
19
|
+
Four tiers of customization, from lightest to deepest.
|
|
20
|
+
|
|
21
|
+
## 1. Four-Tier Customization Model
|
|
22
|
+
|
|
23
|
+
| Tier | Mechanism | Scope | When to Use |
|
|
24
|
+
|------|-----------|-------|-------------|
|
|
25
|
+
| 1 | Props & View Slots | Per-component UI overrides | Custom list items, subtitles, trailing widgets, headers |
|
|
26
|
+
| 2 | Request Builders | Data filtering & pagination | Filter conversations, users, groups, messages, group members |
|
|
27
|
+
| 3 | Text Formatters & Message Templates | Message rendering & actions | Custom text styling, custom long-press options, custom bubble slots |
|
|
28
|
+
| 4 | BubbleFactory & DataSource | New message types | Location bubbles, poll bubbles, any custom `category_type` |
|
|
29
|
+
|
|
30
|
+
Start at Tier 1. Move deeper only when the lighter tier can't solve the problem.
|
|
31
|
+
|
|
32
|
+
## 2. Tier 1: Props & View Slots
|
|
33
|
+
|
|
34
|
+
Every list-based component exposes view slot callbacks that let you replace individual parts of each list item without rebuilding the entire widget.
|
|
35
|
+
|
|
36
|
+
### CometChatConversations
|
|
37
|
+
|
|
38
|
+
```dart
|
|
39
|
+
CometChatConversations(
|
|
40
|
+
// Replace the entire list item
|
|
41
|
+
listItemView: (Conversation conversation) => MyCustomConversationTile(conversation),
|
|
42
|
+
|
|
43
|
+
// Replace individual slots
|
|
44
|
+
subtitleView: (BuildContext context, Conversation conversation) =>
|
|
45
|
+
Text(conversation.lastMessage?.text ?? ''),
|
|
46
|
+
trailingView: (Conversation conversation) =>
|
|
47
|
+
Icon(Icons.chevron_right),
|
|
48
|
+
leadingView: (BuildContext context, Conversation conversation) =>
|
|
49
|
+
CircleAvatar(child: Text(conversation.conversationWith?.name?[0] ?? '')),
|
|
50
|
+
titleView: (BuildContext context, Conversation conversation) =>
|
|
51
|
+
Text(conversation.conversationWith?.name ?? '', style: TextStyle(fontWeight: FontWeight.bold)),
|
|
52
|
+
|
|
53
|
+
// State views
|
|
54
|
+
emptyStateView: (context) => Center(child: Text('No conversations yet')),
|
|
55
|
+
errorStateView: (context) => Center(child: Text('Something went wrong')),
|
|
56
|
+
loadingStateView: (context) => Center(child: CircularProgressIndicator()),
|
|
57
|
+
)
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
### CometChatUsers
|
|
61
|
+
|
|
62
|
+
```dart
|
|
63
|
+
CometChatUsers(
|
|
64
|
+
listItemView: (User user) => MyCustomUserTile(user),
|
|
65
|
+
subtitleView: (BuildContext context, User user) => Text(user.status ?? ''),
|
|
66
|
+
trailingView: (BuildContext context, User user) => Icon(Icons.message),
|
|
67
|
+
leadingView: (BuildContext context, User user) => CometChatAvatar(name: user.name),
|
|
68
|
+
titleView: (BuildContext context, User user) => Text(user.name),
|
|
69
|
+
)
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
### CometChatGroups
|
|
73
|
+
|
|
74
|
+
```dart
|
|
75
|
+
CometChatGroups(
|
|
76
|
+
listItemView: (Group group) => MyCustomGroupTile(group),
|
|
77
|
+
subtitleView: (BuildContext context, Group group) =>
|
|
78
|
+
Text('${group.membersCount} members'),
|
|
79
|
+
trailingView: (BuildContext context, Group group) => Icon(Icons.arrow_forward),
|
|
80
|
+
leadingView: (BuildContext context, Group group) => CometChatAvatar(name: group.name),
|
|
81
|
+
titleView: (BuildContext context, Group group) => Text(group.name),
|
|
82
|
+
)
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
### CometChatMessageHeader
|
|
86
|
+
|
|
87
|
+
```dart
|
|
88
|
+
CometChatMessageHeader(
|
|
89
|
+
user: user,
|
|
90
|
+
group: group,
|
|
91
|
+
subtitleView: (Group? group, User? user, BuildContext context) =>
|
|
92
|
+
Text('Custom subtitle'),
|
|
93
|
+
trailingView: (User? user, Group? group, BuildContext context) => [
|
|
94
|
+
IconButton(icon: Icon(Icons.search), onPressed: () {}),
|
|
95
|
+
IconButton(icon: Icon(Icons.info_outline), onPressed: () {}),
|
|
96
|
+
],
|
|
97
|
+
listItemView: (Group? group, User? user, BuildContext context) =>
|
|
98
|
+
MyCustomHeaderWidget(user: user, group: group),
|
|
99
|
+
titleView: null, // use default
|
|
100
|
+
leadingStateView: null, // use default
|
|
101
|
+
)
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
### CometChatMessageList
|
|
105
|
+
|
|
106
|
+
```dart
|
|
107
|
+
CometChatMessageList(
|
|
108
|
+
user: user,
|
|
109
|
+
group: group,
|
|
110
|
+
headerView: (context, state) => MyCustomListHeader(),
|
|
111
|
+
footerView: (context, state) => MyCustomListFooter(),
|
|
112
|
+
emptyStateView: (context) => Center(child: Text('Start a conversation')),
|
|
113
|
+
emptyChatGreetingView: (context) => WelcomeWidget(),
|
|
114
|
+
loadingStateView: (context) => ShimmerList(),
|
|
115
|
+
errorStateView: (context) => RetryWidget(),
|
|
116
|
+
)
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
### CometChatMessageComposer
|
|
120
|
+
|
|
121
|
+
```dart
|
|
122
|
+
CometChatMessageComposer(
|
|
123
|
+
user: user,
|
|
124
|
+
group: group,
|
|
125
|
+
headerView: (context, state) => ReplyPreviewBanner(),
|
|
126
|
+
footerView: (context, state) => SuggestedActionsBar(),
|
|
127
|
+
auxiliaryButtonView: (context, user, group, composerState) =>
|
|
128
|
+
IconButton(icon: Icon(Icons.gif), onPressed: () {}),
|
|
129
|
+
secondaryButtonView: (context, user, group, composerState) =>
|
|
130
|
+
IconButton(icon: Icon(Icons.attach_file), onPressed: () {}),
|
|
131
|
+
sendButtonView: Icon(Icons.send, color: Colors.blue),
|
|
132
|
+
)
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
## 3. Tier 2: Request Builders
|
|
136
|
+
|
|
137
|
+
Override the SDK request builder to control what data is fetched.
|
|
138
|
+
|
|
139
|
+
### ConversationsRequestBuilder
|
|
140
|
+
|
|
141
|
+
```dart
|
|
142
|
+
CometChatConversations(
|
|
143
|
+
conversationsRequestBuilder: ConversationsRequestBuilder()
|
|
144
|
+
..limit = 30
|
|
145
|
+
..conversationType = ConversationType.user // only 1-on-1 chats
|
|
146
|
+
..withTags = true
|
|
147
|
+
..tags = ['vip'],
|
|
148
|
+
)
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
### MessagesRequestBuilder
|
|
152
|
+
|
|
153
|
+
```dart
|
|
154
|
+
CometChatMessageList(
|
|
155
|
+
user: user,
|
|
156
|
+
messagesRequestBuilder: MessagesRequestBuilder()
|
|
157
|
+
..uid = user.uid
|
|
158
|
+
..limit = 50
|
|
159
|
+
..hideDeletedMessages = true
|
|
160
|
+
..searchKeyword = 'invoice'
|
|
161
|
+
..categories = [MessageCategoryConstants.message]
|
|
162
|
+
..types = [MessageTypeConstants.text, MessageTypeConstants.image],
|
|
163
|
+
)
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
### UsersRequestBuilder
|
|
167
|
+
|
|
168
|
+
```dart
|
|
169
|
+
CometChatUsers(
|
|
170
|
+
usersRequestBuilder: UsersRequestBuilder()
|
|
171
|
+
..limit = 30
|
|
172
|
+
..friendsOnly = true
|
|
173
|
+
..searchKeyword = 'john'
|
|
174
|
+
..roles = ['admin', 'moderator'],
|
|
175
|
+
)
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
### GroupsRequestBuilder
|
|
179
|
+
|
|
180
|
+
```dart
|
|
181
|
+
CometChatGroups(
|
|
182
|
+
groupsRequestBuilder: GroupsRequestBuilder()
|
|
183
|
+
..limit = 30
|
|
184
|
+
..joinedOnly = true
|
|
185
|
+
..searchKeyword = 'team'
|
|
186
|
+
..withTags = true
|
|
187
|
+
..tags = ['project-alpha'],
|
|
188
|
+
)
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
### GroupMembersRequestBuilder
|
|
192
|
+
|
|
193
|
+
```dart
|
|
194
|
+
CometChatGroupMembers(
|
|
195
|
+
group: group,
|
|
196
|
+
groupMembersRequestBuilder: GroupMembersRequestBuilder(group.guid)
|
|
197
|
+
..limit = 30
|
|
198
|
+
..scopes = [GroupMemberScope.admin, GroupMemberScope.moderator],
|
|
199
|
+
)
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
## 4. Tier 3: Text Formatters & Message Templates
|
|
203
|
+
|
|
204
|
+
### Text Formatters
|
|
205
|
+
|
|
206
|
+
`CometChatTextFormatter` is the abstract base class. Subclass it to create custom text styling in both the message list and the composer.
|
|
207
|
+
|
|
208
|
+
Built-in formatters:
|
|
209
|
+
|
|
210
|
+
| Formatter | Purpose |
|
|
211
|
+
|-----------|---------|
|
|
212
|
+
| `CometChatMentionsFormatter` | @mention users with suggestion list |
|
|
213
|
+
| `MarkdownTextFormatter` | Bold, italic, strikethrough, code, links, lists |
|
|
214
|
+
| `CometChatUrlFormatter` | Clickable URLs |
|
|
215
|
+
| `CometChatPhoneNumberFormatter` | Clickable phone numbers |
|
|
216
|
+
| `CometChatEmailFormatter` | Clickable email addresses |
|
|
217
|
+
|
|
218
|
+
Key properties on `CometChatTextFormatter`:
|
|
219
|
+
|
|
220
|
+
```dart
|
|
221
|
+
abstract class CometChatTextFormatter implements Formatter {
|
|
222
|
+
String? trackingCharacter; // e.g. '@' for mentions
|
|
223
|
+
RegExp? pattern; // regex to match in text
|
|
224
|
+
Function(String?)? onSearch; // called when tracking character typed
|
|
225
|
+
bool? showLoadingIndicator;
|
|
226
|
+
BaseMessage? message;
|
|
227
|
+
User? user;
|
|
228
|
+
Group? group;
|
|
229
|
+
StreamSink<List<SuggestionListItem>>? suggestionListEventSink;
|
|
230
|
+
|
|
231
|
+
void init();
|
|
232
|
+
void handlePreMessageSend(BuildContext context, BaseMessage baseMessage);
|
|
233
|
+
void onScrollToBottom(TextEditingController textEditingController);
|
|
234
|
+
void onChange(TextEditingController textEditingController, String previousText);
|
|
235
|
+
|
|
236
|
+
List<AttributedText> buildInputFieldText({...});
|
|
237
|
+
List<AttributedText> getAttributedText(String text, BuildContext context, BubbleAlignment? alignment, {...});
|
|
238
|
+
TextStyle getMessageBubbleTextStyle(BuildContext context, BubbleAlignment? alignment, {bool forConversation = false});
|
|
239
|
+
TextStyle getMessageInputTextStyle(BuildContext context);
|
|
240
|
+
}
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
Pass the same formatters to both list and composer:
|
|
244
|
+
|
|
245
|
+
```dart
|
|
246
|
+
final formatters = [
|
|
247
|
+
CometChatMentionsFormatter(user: user, group: group),
|
|
248
|
+
MarkdownTextFormatter(),
|
|
249
|
+
CometChatUrlFormatter(),
|
|
250
|
+
CometChatPhoneNumberFormatter(),
|
|
251
|
+
CometChatEmailFormatter(),
|
|
252
|
+
];
|
|
253
|
+
|
|
254
|
+
CometChatMessageList(user: user, textFormatters: formatters)
|
|
255
|
+
CometChatMessageComposer(user: user, textFormatters: formatters)
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
### Message Templates
|
|
259
|
+
|
|
260
|
+
`CometChatMessageTemplate` controls how a message type renders in the bubble and what long-press options appear.
|
|
261
|
+
|
|
262
|
+
```dart
|
|
263
|
+
class CometChatMessageTemplate {
|
|
264
|
+
CometChatMessageTemplate({
|
|
265
|
+
required this.type, // e.g. 'text', 'image', or 'location'
|
|
266
|
+
required this.category, // e.g. 'message' or 'custom'
|
|
267
|
+
this.bubbleView, // replaces the ENTIRE bubble
|
|
268
|
+
this.headerView, // top of bubble (sender name area)
|
|
269
|
+
this.contentView, // main content area
|
|
270
|
+
this.footerView, // below statusInfoView
|
|
271
|
+
this.bottomView, // below contentView
|
|
272
|
+
this.statusInfoView, // receipts/time area
|
|
273
|
+
this.threadView, // thread reply indicator
|
|
274
|
+
this.replyView, // quoted reply preview
|
|
275
|
+
this.options, // long-press menu options
|
|
276
|
+
});
|
|
277
|
+
}
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
Override templates on `CometChatMessageList`:
|
|
281
|
+
|
|
282
|
+
```dart
|
|
283
|
+
CometChatMessageList(
|
|
284
|
+
user: user,
|
|
285
|
+
// Replace all templates
|
|
286
|
+
templates: [
|
|
287
|
+
CometChatMessageTemplate(
|
|
288
|
+
type: MessageTypeConstants.text,
|
|
289
|
+
category: MessageCategoryConstants.message,
|
|
290
|
+
contentView: (message, context, alignment, {additionalConfigurations}) =>
|
|
291
|
+
MyCustomTextContent(message: message),
|
|
292
|
+
options: (loggedInUser, message, context, group, additionalConfigurations) => [
|
|
293
|
+
CometChatMessageOption(
|
|
294
|
+
id: 'bookmark',
|
|
295
|
+
title: 'Bookmark',
|
|
296
|
+
icon: Icon(Icons.bookmark_border, size: 24),
|
|
297
|
+
onItemClick: (message, state) {
|
|
298
|
+
// handle bookmark
|
|
299
|
+
},
|
|
300
|
+
),
|
|
301
|
+
],
|
|
302
|
+
),
|
|
303
|
+
],
|
|
304
|
+
// Or add templates alongside defaults
|
|
305
|
+
addTemplate: [
|
|
306
|
+
CometChatMessageTemplate(
|
|
307
|
+
type: 'location',
|
|
308
|
+
category: 'custom',
|
|
309
|
+
contentView: (message, context, alignment, {additionalConfigurations}) =>
|
|
310
|
+
LocationBubbleContent(message: message as CustomMessage),
|
|
311
|
+
),
|
|
312
|
+
],
|
|
313
|
+
)
|
|
314
|
+
```
|
|
315
|
+
|
|
316
|
+
`CometChatMessageOption` model:
|
|
317
|
+
|
|
318
|
+
```dart
|
|
319
|
+
CometChatMessageOption(
|
|
320
|
+
id: 'pin', // unique identifier
|
|
321
|
+
title: 'Pin Message', // display text
|
|
322
|
+
icon: Icon(Icons.push_pin), // leading icon
|
|
323
|
+
onItemClick: (BaseMessage message, CometChatMessageListControllerProtocol state) {
|
|
324
|
+
// your action
|
|
325
|
+
},
|
|
326
|
+
messageOptionSheetStyle: CometChatMessageOptionSheetStyle(...),
|
|
327
|
+
)
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
## 5. Tier 4: BubbleFactory & DataSource
|
|
331
|
+
|
|
332
|
+
### BubbleFactory
|
|
333
|
+
|
|
334
|
+
The deepest customization for rendering message content. Each factory handles one `category_type` key.
|
|
335
|
+
|
|
336
|
+
```dart
|
|
337
|
+
/// Abstract factory — one per message type.
|
|
338
|
+
abstract class BubbleFactory<T extends BaseMessage> {
|
|
339
|
+
Widget build(
|
|
340
|
+
BuildContext context,
|
|
341
|
+
T message,
|
|
342
|
+
BubbleAlignment alignment, {
|
|
343
|
+
CometChatColorPalette? colorPalette,
|
|
344
|
+
CometChatTypography? typography,
|
|
345
|
+
CometChatSpacing? spacing,
|
|
346
|
+
});
|
|
347
|
+
|
|
348
|
+
/// Returns "category_type" key, or "deleted" for deleted messages.
|
|
349
|
+
static String getFactoryKey(BaseMessage message);
|
|
350
|
+
|
|
351
|
+
/// Creates a key from category + type strings.
|
|
352
|
+
static String createKey(String category, String type) => '${category}_$type';
|
|
353
|
+
}
|
|
354
|
+
```
|
|
355
|
+
|
|
356
|
+
### DefaultBubbleFactories
|
|
357
|
+
|
|
358
|
+
The built-in registry:
|
|
359
|
+
|
|
360
|
+
```dart
|
|
361
|
+
class DefaultBubbleFactories {
|
|
362
|
+
static Map<String, BubbleFactory> getDefaults({
|
|
363
|
+
List<CometChatTextFormatter>? textFormatters,
|
|
364
|
+
CometChatTextBubbleStyle? incomingTextStyle,
|
|
365
|
+
CometChatTextBubbleStyle? outgoingTextStyle,
|
|
366
|
+
CometChatImageBubbleStyle? imageStyle,
|
|
367
|
+
CometChatVideoBubbleStyle? videoStyle,
|
|
368
|
+
CometChatAudioBubbleStyle? audioStyle,
|
|
369
|
+
CometChatFileBubbleStyle? fileStyle,
|
|
370
|
+
});
|
|
371
|
+
}
|
|
372
|
+
```
|
|
373
|
+
|
|
374
|
+
Default keys registered:
|
|
375
|
+
- `message_text` → `TextBubbleFactory`
|
|
376
|
+
- `message_image` → `ImageBubbleFactory`
|
|
377
|
+
- `message_video` → `VideoBubbleFactory`
|
|
378
|
+
- `message_audio` → `AudioBubbleFactory`
|
|
379
|
+
- `message_file` → `FileBubbleFactory`
|
|
380
|
+
- `deleted` → `DeletedBubbleFactory`
|
|
381
|
+
|
|
382
|
+
### Creating a Custom BubbleFactory
|
|
383
|
+
|
|
384
|
+
Example: a location message bubble.
|
|
385
|
+
|
|
386
|
+
```dart
|
|
387
|
+
class LocationBubbleFactory extends BubbleFactory<CustomMessage> {
|
|
388
|
+
@override
|
|
389
|
+
Widget build(
|
|
390
|
+
BuildContext context,
|
|
391
|
+
CustomMessage message,
|
|
392
|
+
BubbleAlignment alignment, {
|
|
393
|
+
CometChatColorPalette? colorPalette,
|
|
394
|
+
CometChatTypography? typography,
|
|
395
|
+
CometChatSpacing? spacing,
|
|
396
|
+
}) {
|
|
397
|
+
final data = message.customData;
|
|
398
|
+
final lat = data?['latitude'] as double? ?? 0;
|
|
399
|
+
final lng = data?['longitude'] as double? ?? 0;
|
|
400
|
+
|
|
401
|
+
return GestureDetector(
|
|
402
|
+
onTap: () => _openMap(lat, lng),
|
|
403
|
+
child: Column(
|
|
404
|
+
mainAxisSize: MainAxisSize.min,
|
|
405
|
+
children: [
|
|
406
|
+
Image.network(
|
|
407
|
+
'https://maps.googleapis.com/maps/api/staticmap?center=$lat,$lng&zoom=15&size=300x200&key=YOUR_KEY',
|
|
408
|
+
width: 240,
|
|
409
|
+
height: 160,
|
|
410
|
+
fit: BoxFit.cover,
|
|
411
|
+
),
|
|
412
|
+
Padding(
|
|
413
|
+
padding: EdgeInsets.all(spacing?.padding2 ?? 8),
|
|
414
|
+
child: Text(
|
|
415
|
+
'📍 $lat, $lng',
|
|
416
|
+
style: typography?.body?.regular,
|
|
417
|
+
),
|
|
418
|
+
),
|
|
419
|
+
],
|
|
420
|
+
),
|
|
421
|
+
);
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
```
|
|
425
|
+
|
|
426
|
+
### Registering Custom Factories
|
|
427
|
+
|
|
428
|
+
Merge your custom factories with the defaults using `CometChatMessageTemplate.addTemplate` on the message list, or by providing a custom `templates` list that includes a `contentView` for your custom type.
|
|
429
|
+
|
|
430
|
+
The `CometChatMessageBubble` widget supports two modes:
|
|
431
|
+
- Smart mode: pass `message` and the factory registry resolves the content widget via `BubbleFactory.getFactoryKey(message)` → O(1) map lookup.
|
|
432
|
+
- Manual mode: pass `contentView` directly — bypasses the factory.
|
|
433
|
+
|
|
434
|
+
```dart
|
|
435
|
+
// Using addTemplate to register a custom type alongside defaults
|
|
436
|
+
CometChatMessageList(
|
|
437
|
+
user: user,
|
|
438
|
+
addTemplate: [
|
|
439
|
+
CometChatMessageTemplate(
|
|
440
|
+
type: 'location',
|
|
441
|
+
category: 'custom',
|
|
442
|
+
contentView: (message, context, alignment, {additionalConfigurations}) {
|
|
443
|
+
final factory = LocationBubbleFactory();
|
|
444
|
+
return factory.build(context, message as CustomMessage, alignment);
|
|
445
|
+
},
|
|
446
|
+
),
|
|
447
|
+
],
|
|
448
|
+
)
|
|
449
|
+
```
|
|
450
|
+
|
|
451
|
+
### DataSource Pattern
|
|
452
|
+
|
|
453
|
+
Each component follows Clean Architecture with its own data source layer. The data sources abstract SDK calls behind interfaces:
|
|
454
|
+
|
|
455
|
+
```dart
|
|
456
|
+
// Example: ConversationsRemoteDataSource
|
|
457
|
+
abstract class ConversationsRemoteDataSource {
|
|
458
|
+
Future<List<Conversation>> getConversations({ConversationsRequest? request});
|
|
459
|
+
Future<void> deleteConversation(String conversationWith);
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
class ConversationsRemoteDataSourceImpl implements ConversationsRemoteDataSource {
|
|
463
|
+
// Delegates to CometChat SDK
|
|
464
|
+
}
|
|
465
|
+
```
|
|
466
|
+
|
|
467
|
+
To customize data fetching, provide a custom BLoC instance:
|
|
468
|
+
|
|
469
|
+
```dart
|
|
470
|
+
CometChatConversations(
|
|
471
|
+
conversationsBloc: MyCustomConversationsBloc(),
|
|
472
|
+
)
|
|
473
|
+
|
|
474
|
+
CometChatUsers(
|
|
475
|
+
usersBloc: MyCustomUsersBloc(),
|
|
476
|
+
)
|
|
477
|
+
|
|
478
|
+
CometChatGroups(
|
|
479
|
+
groupsBloc: MyCustomGroupsBloc(),
|
|
480
|
+
)
|
|
481
|
+
|
|
482
|
+
CometChatMessageList(
|
|
483
|
+
messageListBloc: MyCustomMessageListBloc(),
|
|
484
|
+
)
|
|
485
|
+
```
|
|
486
|
+
|
|
487
|
+
## 6. Style Overrides
|
|
488
|
+
|
|
489
|
+
Every component has a `CometChat{Component}Style` class that extends `ThemeExtension`. Styles use a `merge()` pattern — your overrides layer on top of theme defaults.
|
|
490
|
+
|
|
491
|
+
### Pattern
|
|
492
|
+
|
|
493
|
+
```dart
|
|
494
|
+
@immutable
|
|
495
|
+
class CometChatTextBubbleStyle extends ThemeExtension<CometChatTextBubbleStyle> {
|
|
496
|
+
const CometChatTextBubbleStyle({
|
|
497
|
+
this.textStyle,
|
|
498
|
+
this.textColor,
|
|
499
|
+
this.backgroundColor,
|
|
500
|
+
this.border,
|
|
501
|
+
this.borderRadius,
|
|
502
|
+
this.messageBubbleAvatarStyle,
|
|
503
|
+
this.messageBubbleDateStyle,
|
|
504
|
+
this.messageBubbleBackgroundImage,
|
|
505
|
+
this.senderNameTextStyle,
|
|
506
|
+
this.messageReceiptStyle,
|
|
507
|
+
// ...
|
|
508
|
+
});
|
|
509
|
+
|
|
510
|
+
// Factory to get theme-registered instance
|
|
511
|
+
static CometChatTextBubbleStyle of(BuildContext context) => const CometChatTextBubbleStyle();
|
|
512
|
+
|
|
513
|
+
// Merge your overrides on top of theme defaults
|
|
514
|
+
CometChatTextBubbleStyle merge(CometChatTextBubbleStyle? style);
|
|
515
|
+
|
|
516
|
+
// copyWith for selective overrides
|
|
517
|
+
CometChatTextBubbleStyle copyWith({...});
|
|
518
|
+
}
|
|
519
|
+
```
|
|
520
|
+
|
|
521
|
+
### Usage
|
|
522
|
+
|
|
523
|
+
```dart
|
|
524
|
+
CometChatConversations(
|
|
525
|
+
conversationsStyle: CometChatConversationsStyle(
|
|
526
|
+
backgroundColor: Colors.grey[100],
|
|
527
|
+
titleTextStyle: TextStyle(fontSize: 18, fontWeight: FontWeight.w600),
|
|
528
|
+
),
|
|
529
|
+
)
|
|
530
|
+
|
|
531
|
+
CometChatMessageHeader(
|
|
532
|
+
user: user,
|
|
533
|
+
messageHeaderStyle: CometChatMessageHeaderStyle(
|
|
534
|
+
backgroundColor: colorPalette.background1,
|
|
535
|
+
),
|
|
536
|
+
)
|
|
537
|
+
|
|
538
|
+
CometChatMessageList(
|
|
539
|
+
user: user,
|
|
540
|
+
style: CometChatMessageListStyle(
|
|
541
|
+
backgroundColor: Colors.white,
|
|
542
|
+
),
|
|
543
|
+
)
|
|
544
|
+
|
|
545
|
+
CometChatMessageComposer(
|
|
546
|
+
user: user,
|
|
547
|
+
messageComposerStyle: CometChatMessageComposerStyle(
|
|
548
|
+
backgroundColor: Colors.white,
|
|
549
|
+
borderRadius: BorderRadius.circular(24),
|
|
550
|
+
),
|
|
551
|
+
)
|
|
552
|
+
```
|
|
553
|
+
|
|
554
|
+
### Theme Caching
|
|
555
|
+
|
|
556
|
+
For performance, parent widgets cache theme lookups in `didChangeDependencies()` and pass them to children via optional `colorPalette`, `spacing`, `typography` params. This avoids expensive `CometChatThemeHelper` lookups during keyboard animation rebuilds.
|
|
557
|
+
|
|
558
|
+
```dart
|
|
559
|
+
// Parent caches once
|
|
560
|
+
late CometChatColorPalette _colorPalette;
|
|
561
|
+
bool _themeInitialized = false;
|
|
562
|
+
|
|
563
|
+
@override
|
|
564
|
+
void didChangeDependencies() {
|
|
565
|
+
super.didChangeDependencies();
|
|
566
|
+
if (!_themeInitialized) {
|
|
567
|
+
_colorPalette = CometChatThemeHelper.getColorPalette(context);
|
|
568
|
+
_themeInitialized = true;
|
|
569
|
+
}
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
// Pass to children
|
|
573
|
+
CometChatMessageBubble(
|
|
574
|
+
colorPalette: _colorPalette, // pre-cached, zero lookups in child
|
|
575
|
+
spacing: _spacing,
|
|
576
|
+
)
|
|
577
|
+
```
|
|
578
|
+
|
|
579
|
+
## 7. Anti-Patterns
|
|
580
|
+
|
|
581
|
+
```dart
|
|
582
|
+
// ❌ WRONG — different formatters for list and composer
|
|
583
|
+
CometChatMessageList(textFormatters: [MarkdownTextFormatter()])
|
|
584
|
+
CometChatMessageComposer(textFormatters: []) // inconsistent rendering
|
|
585
|
+
|
|
586
|
+
// ✅ CORRECT — same formatter list
|
|
587
|
+
final formatters = [CometChatMentionsFormatter(user: user), MarkdownTextFormatter()];
|
|
588
|
+
CometChatMessageList(textFormatters: formatters)
|
|
589
|
+
CometChatMessageComposer(textFormatters: formatters)
|
|
590
|
+
```
|
|
591
|
+
|
|
592
|
+
```dart
|
|
593
|
+
// ❌ WRONG — calling CometChatThemeHelper in build() of a frequently-rebuilt widget
|
|
594
|
+
@override
|
|
595
|
+
Widget build(BuildContext context) {
|
|
596
|
+
final colorPalette = CometChatThemeHelper.getColorPalette(context); // expensive every rebuild
|
|
597
|
+
return Container(color: colorPalette.primary);
|
|
598
|
+
}
|
|
599
|
+
|
|
600
|
+
// ✅ CORRECT — cache in didChangeDependencies, use _themeInitialized flag
|
|
601
|
+
```
|
|
602
|
+
|
|
603
|
+
```dart
|
|
604
|
+
// ❌ WRONG — overriding templates without providing options (loses default long-press menu)
|
|
605
|
+
CometChatMessageList(
|
|
606
|
+
templates: [
|
|
607
|
+
CometChatMessageTemplate(
|
|
608
|
+
type: MessageTypeConstants.text,
|
|
609
|
+
category: MessageCategoryConstants.message,
|
|
610
|
+
contentView: (msg, ctx, align, {additionalConfigurations}) => Text(msg.text),
|
|
611
|
+
// options: null — no long-press menu at all!
|
|
612
|
+
),
|
|
613
|
+
],
|
|
614
|
+
)
|
|
615
|
+
|
|
616
|
+
// ✅ CORRECT — use addTemplate to add new types, or include options when overriding templates
|
|
617
|
+
```
|
|
618
|
+
|
|
619
|
+
```dart
|
|
620
|
+
// ❌ WRONG — creating a BubbleFactory that ignores the colorPalette/spacing params
|
|
621
|
+
class BadFactory extends BubbleFactory<CustomMessage> {
|
|
622
|
+
@override
|
|
623
|
+
Widget build(BuildContext context, CustomMessage message, BubbleAlignment alignment, {
|
|
624
|
+
CometChatColorPalette? colorPalette,
|
|
625
|
+
CometChatTypography? typography,
|
|
626
|
+
CometChatSpacing? spacing,
|
|
627
|
+
}) {
|
|
628
|
+
return Container(color: Colors.blue); // hardcoded color, ignores theme
|
|
629
|
+
}
|
|
630
|
+
}
|
|
631
|
+
|
|
632
|
+
// ✅ CORRECT — use the passed theme values
|
|
633
|
+
return Container(color: colorPalette?.primary ?? Colors.blue);
|
|
634
|
+
```
|
|
635
|
+
|
|
636
|
+
```dart
|
|
637
|
+
// ❌ WRONG — forgetting resizeToAvoidBottomInset: false on Scaffold with composer
|
|
638
|
+
Scaffold(
|
|
639
|
+
body: Column(children: [
|
|
640
|
+
Expanded(child: CometChatMessageList(user: user)),
|
|
641
|
+
CometChatMessageComposer(user: user),
|
|
642
|
+
]),
|
|
643
|
+
)
|
|
644
|
+
|
|
645
|
+
// ✅ CORRECT
|
|
646
|
+
Scaffold(
|
|
647
|
+
resizeToAvoidBottomInset: false,
|
|
648
|
+
body: Column(children: [
|
|
649
|
+
Expanded(child: CometChatMessageList(user: user)),
|
|
650
|
+
CometChatMessageComposer(user: user),
|
|
651
|
+
]),
|
|
652
|
+
)
|
|
653
|
+
```
|
|
654
|
+
|
|
655
|
+
## 8. Checklist
|
|
656
|
+
|
|
657
|
+
- [ ] Start at Tier 1 (props/view slots) before going deeper
|
|
658
|
+
- [ ] Same `textFormatters` list passed to both `CometChatMessageList` and `CometChatMessageComposer`
|
|
659
|
+
- [ ] Use `addTemplate` to add new message types alongside defaults (don't replace `templates` unless intentional)
|
|
660
|
+
- [ ] Custom `BubbleFactory.build()` uses the passed `colorPalette`/`typography`/`spacing` params, not hardcoded values
|
|
661
|
+
- [ ] Style overrides use `merge()` pattern, not constructor replacement
|
|
662
|
+
- [ ] Theme lookups cached in `didChangeDependencies()` with `_themeInitialized` flag
|
|
663
|
+
- [ ] `Scaffold` containing `CometChatMessageComposer` has `resizeToAvoidBottomInset: false`
|
|
664
|
+
- [ ] Custom `CometChatMessageOption.onItemClick` handles both `BaseMessage` and the controller protocol
|
|
665
|
+
- [ ] Request builders set `limit` to a reasonable value (default 30–50)
|
|
666
|
+
- [ ] Mutable `_user`/`_group` state copies passed to UIKit components, not `widget.user`/`widget.group`
|