@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,398 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: cometchat-flutter-v6-placement
|
|
3
|
+
description: >
|
|
4
|
+
Use when deciding WHERE to put CometChat in a Flutter app. Covers placement patterns:
|
|
5
|
+
tab-based home (IndexedStack), Navigator.push messages screen, modal/bottom sheet chat,
|
|
6
|
+
thread overlay, embedded panel, and floating widget. Includes Scaffold configuration,
|
|
7
|
+
resizeToAvoidBottomInset, SafeArea, and keyboard-aware spacing patterns.
|
|
8
|
+
Triggers on "add chat to my app", "where to put chat", "messages screen layout",
|
|
9
|
+
"tab bar with chat", "chat in modal", "chat in drawer", "embedded chat",
|
|
10
|
+
"Scaffold layout", or "keyboard handling".
|
|
11
|
+
license: "MIT"
|
|
12
|
+
compatibility: "cometchat_chat_uikit ^6.0.0-beta2; flutter >=2.5.0"
|
|
13
|
+
allowed-tools: "executeBash, readFile, readCode, fileSearch, listDirectory, grepSearch"
|
|
14
|
+
metadata:
|
|
15
|
+
author: "CometChat"
|
|
16
|
+
version: "3.0.0"
|
|
17
|
+
tags: "cometchat flutter placement route modal drawer tabs scaffold keyboard layout"
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
# CometChat Flutter UIKit — Placement
|
|
21
|
+
|
|
22
|
+
WHERE to put CometChat in your Flutter app. Five patterns, each with complete code.
|
|
23
|
+
|
|
24
|
+
**Before using this skill:**
|
|
25
|
+
- Read `cometchat-flutter-v6-core` for init, login, and rules
|
|
26
|
+
- Read `cometchat-flutter-v6-components` for component names and props (when available)
|
|
27
|
+
|
|
28
|
+
---
|
|
29
|
+
|
|
30
|
+
## Placement Recommendation
|
|
31
|
+
|
|
32
|
+
| User intent | Recommended pattern | Components |
|
|
33
|
+
|-------------|-------------------|------------|
|
|
34
|
+
| Messaging app | Tab-based home (full screen) | IndexedStack + CometChatConversations + Messages screen |
|
|
35
|
+
| Marketplace / platform | Navigator.push from product page | Single-thread messages screen |
|
|
36
|
+
| SaaS / dashboard | Modal or bottom sheet | CometChatConversations in BottomSheet |
|
|
37
|
+
| Social / community | Tab-based home with calls | IndexedStack + Conversations + CallLogs + Users + Groups |
|
|
38
|
+
| Support / helpdesk | Floating action button → modal | FAB + showModalBottomSheet |
|
|
39
|
+
| Just exploring | Replace home page | CometChatConversations as Scaffold body |
|
|
40
|
+
|
|
41
|
+
---
|
|
42
|
+
|
|
43
|
+
## Pattern 1: Tab-Based Home (Most Common)
|
|
44
|
+
|
|
45
|
+
BottomNavigationBar with IndexedStack to preserve tab state. This is what master_app uses.
|
|
46
|
+
|
|
47
|
+
```dart
|
|
48
|
+
class HomeScreen extends StatefulWidget {
|
|
49
|
+
const HomeScreen({super.key});
|
|
50
|
+
@override
|
|
51
|
+
State<HomeScreen> createState() => _HomeScreenState();
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
class _HomeScreenState extends State<HomeScreen> {
|
|
55
|
+
int _currentIndex = 0;
|
|
56
|
+
|
|
57
|
+
@override
|
|
58
|
+
Widget build(BuildContext context) {
|
|
59
|
+
return Scaffold(
|
|
60
|
+
body: IndexedStack(
|
|
61
|
+
index: _currentIndex,
|
|
62
|
+
children: [
|
|
63
|
+
// Tab 0: Conversations
|
|
64
|
+
CometChatConversations(
|
|
65
|
+
hideAppbar: true,
|
|
66
|
+
onItemTap: (conversation) => _openChat(context, conversation),
|
|
67
|
+
),
|
|
68
|
+
// Tab 1: Call Logs
|
|
69
|
+
CometChatCallLogs(hideAppbar: true),
|
|
70
|
+
// Tab 2: Users
|
|
71
|
+
CometChatUsers(
|
|
72
|
+
hideAppbar: true,
|
|
73
|
+
onItemTap: (_, user) => _pushMessages(context, user: user),
|
|
74
|
+
),
|
|
75
|
+
// Tab 3: Groups
|
|
76
|
+
CometChatGroups(
|
|
77
|
+
hideAppbar: true,
|
|
78
|
+
onItemTap: (_, group) => _pushMessages(context, group: group),
|
|
79
|
+
),
|
|
80
|
+
],
|
|
81
|
+
),
|
|
82
|
+
bottomNavigationBar: BottomNavigationBar(
|
|
83
|
+
currentIndex: _currentIndex,
|
|
84
|
+
onTap: (i) => setState(() => _currentIndex = i),
|
|
85
|
+
type: BottomNavigationBarType.fixed,
|
|
86
|
+
items: const [
|
|
87
|
+
BottomNavigationBarItem(icon: Icon(Icons.chat_outlined), label: 'Chats'),
|
|
88
|
+
BottomNavigationBarItem(icon: Icon(Icons.call_outlined), label: 'Calls'),
|
|
89
|
+
BottomNavigationBarItem(icon: Icon(Icons.person_outline), label: 'Users'),
|
|
90
|
+
BottomNavigationBarItem(icon: Icon(Icons.people_outline), label: 'Groups'),
|
|
91
|
+
],
|
|
92
|
+
),
|
|
93
|
+
);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
void _openChat(BuildContext context, Conversation conversation) {
|
|
97
|
+
final user = conversation.conversationWith is User
|
|
98
|
+
? conversation.conversationWith as User : null;
|
|
99
|
+
final group = conversation.conversationWith is Group
|
|
100
|
+
? conversation.conversationWith as Group : null;
|
|
101
|
+
_pushMessages(context, user: user, group: group);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
void _pushMessages(BuildContext context, {User? user, Group? group}) {
|
|
105
|
+
Navigator.push(context, MaterialPageRoute(
|
|
106
|
+
builder: (_) => MessagesScreen(user: user, group: group),
|
|
107
|
+
));
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
**Key details:**
|
|
113
|
+
- `IndexedStack` keeps all tabs alive — no re-fetch when switching tabs
|
|
114
|
+
- `hideAppbar: true` on all components — the parent Scaffold provides the AppBar
|
|
115
|
+
- `onItemTap` extracts `User`/`Group` from `conversation.conversationWith`
|
|
116
|
+
- Protected groups need a join/password screen before navigating to messages
|
|
117
|
+
|
|
118
|
+
---
|
|
119
|
+
|
|
120
|
+
## Pattern 2: Messages Screen (Navigator.push)
|
|
121
|
+
|
|
122
|
+
The standard messages screen pushed from any conversation/user/group tap.
|
|
123
|
+
|
|
124
|
+
```dart
|
|
125
|
+
class MessagesScreen extends StatefulWidget {
|
|
126
|
+
final User? user;
|
|
127
|
+
final Group? group;
|
|
128
|
+
const MessagesScreen({super.key, this.user, this.group})
|
|
129
|
+
: assert(user != null || group != null);
|
|
130
|
+
@override
|
|
131
|
+
State<MessagesScreen> createState() => _MessagesScreenState();
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
class _MessagesScreenState extends State<MessagesScreen> {
|
|
135
|
+
late User? _user;
|
|
136
|
+
late Group? _group;
|
|
137
|
+
|
|
138
|
+
@override
|
|
139
|
+
void initState() {
|
|
140
|
+
super.initState();
|
|
141
|
+
_user = widget.user; // Mutable copy — updated by SDK listeners
|
|
142
|
+
_group = widget.group;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
@override
|
|
146
|
+
Widget build(BuildContext context) {
|
|
147
|
+
return Scaffold(
|
|
148
|
+
resizeToAvoidBottomInset: false, // REQUIRED — composer handles keyboard
|
|
149
|
+
appBar: CometChatMessageHeader(
|
|
150
|
+
user: _user,
|
|
151
|
+
group: _group,
|
|
152
|
+
onBack: () => Navigator.pop(context),
|
|
153
|
+
),
|
|
154
|
+
body: SafeArea(
|
|
155
|
+
bottom: false, // Composer handles bottom safe area
|
|
156
|
+
child: Column(
|
|
157
|
+
children: [
|
|
158
|
+
Expanded(child: CometChatMessageList(user: _user, group: _group)),
|
|
159
|
+
CometChatMessageComposer(user: _user, group: _group),
|
|
160
|
+
],
|
|
161
|
+
),
|
|
162
|
+
),
|
|
163
|
+
);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
### Critical Scaffold Rules
|
|
169
|
+
|
|
170
|
+
1. `resizeToAvoidBottomInset: false` — MANDATORY on any Scaffold with `CometChatMessageComposer`. The composer uses `SliverSpacing` internally to handle keyboard. Setting `true` causes double-compensation.
|
|
171
|
+
2. `SafeArea(bottom: false)` — The composer handles bottom safe area internally.
|
|
172
|
+
3. Mutable `_user`/`_group` — Keep mutable copies in State, not `widget.user`/`widget.group`. Update from SDK listeners for block/kick/scope changes.
|
|
173
|
+
|
|
174
|
+
---
|
|
175
|
+
|
|
176
|
+
## Pattern 3: Thread Screen
|
|
177
|
+
|
|
178
|
+
Thread replies pushed from `onThreadRepliesClick`. Same Scaffold rules apply.
|
|
179
|
+
|
|
180
|
+
```dart
|
|
181
|
+
class ThreadScreen extends StatelessWidget {
|
|
182
|
+
final User? user;
|
|
183
|
+
final Group? group;
|
|
184
|
+
final BaseMessage message;
|
|
185
|
+
final CometChatMessageTemplate? template;
|
|
186
|
+
|
|
187
|
+
const ThreadScreen({
|
|
188
|
+
super.key, this.user, this.group,
|
|
189
|
+
required this.message, this.template,
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
@override
|
|
193
|
+
Widget build(BuildContext context) {
|
|
194
|
+
return Scaffold(
|
|
195
|
+
resizeToAvoidBottomInset: false, // REQUIRED — same rule as messages
|
|
196
|
+
appBar: CometChatMessageHeader(
|
|
197
|
+
user: user, group: group,
|
|
198
|
+
onBack: () => Navigator.pop(context),
|
|
199
|
+
),
|
|
200
|
+
body: SafeArea(
|
|
201
|
+
bottom: false,
|
|
202
|
+
child: Column(
|
|
203
|
+
children: [
|
|
204
|
+
CometChatThreadedHeader(
|
|
205
|
+
parentMessage: message,
|
|
206
|
+
loggedInUser: CometChatUIKit.loggedInUser!,
|
|
207
|
+
template: template,
|
|
208
|
+
),
|
|
209
|
+
Expanded(
|
|
210
|
+
child: CometChatMessageList(
|
|
211
|
+
user: user, group: group,
|
|
212
|
+
parentMessageId: message.id,
|
|
213
|
+
hideReplyInThreadOption: true,
|
|
214
|
+
),
|
|
215
|
+
),
|
|
216
|
+
CometChatMessageComposer(
|
|
217
|
+
user: user, group: group,
|
|
218
|
+
parentMessageId: message.id,
|
|
219
|
+
),
|
|
220
|
+
],
|
|
221
|
+
),
|
|
222
|
+
),
|
|
223
|
+
);
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
Wire it from the messages screen:
|
|
229
|
+
```dart
|
|
230
|
+
CometChatMessageList(
|
|
231
|
+
onThreadRepliesClick: (message, ctx, {template}) {
|
|
232
|
+
Navigator.push(context, MaterialPageRoute(
|
|
233
|
+
builder: (_) => ThreadScreen(
|
|
234
|
+
user: _user, group: _group,
|
|
235
|
+
message: message, template: template,
|
|
236
|
+
),
|
|
237
|
+
));
|
|
238
|
+
},
|
|
239
|
+
)
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
---
|
|
243
|
+
|
|
244
|
+
## Pattern 4: Modal / Bottom Sheet Chat
|
|
245
|
+
|
|
246
|
+
Quick chat access from any screen without full navigation.
|
|
247
|
+
|
|
248
|
+
```dart
|
|
249
|
+
void _openChatModal(BuildContext context, User user) {
|
|
250
|
+
showModalBottomSheet(
|
|
251
|
+
context: context,
|
|
252
|
+
isScrollControlled: true,
|
|
253
|
+
useSafeArea: true,
|
|
254
|
+
builder: (_) => SizedBox(
|
|
255
|
+
height: MediaQuery.sizeOf(context).height * 0.85,
|
|
256
|
+
child: Scaffold(
|
|
257
|
+
resizeToAvoidBottomInset: false, // Still required!
|
|
258
|
+
appBar: CometChatMessageHeader(
|
|
259
|
+
user: user,
|
|
260
|
+
onBack: () => Navigator.pop(context),
|
|
261
|
+
),
|
|
262
|
+
body: Column(
|
|
263
|
+
children: [
|
|
264
|
+
Expanded(child: CometChatMessageList(user: user)),
|
|
265
|
+
CometChatMessageComposer(user: user),
|
|
266
|
+
],
|
|
267
|
+
),
|
|
268
|
+
),
|
|
269
|
+
),
|
|
270
|
+
);
|
|
271
|
+
}
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
**Key details:**
|
|
275
|
+
- `isScrollControlled: true` — allows the sheet to be taller than half screen
|
|
276
|
+
- `useSafeArea: true` — respects notch/status bar
|
|
277
|
+
- Inner `Scaffold` still needs `resizeToAvoidBottomInset: false`
|
|
278
|
+
- Use `MediaQuery.sizeOf(context)` not `MediaQuery.of(context).size`
|
|
279
|
+
|
|
280
|
+
---
|
|
281
|
+
|
|
282
|
+
## Pattern 5: Embedded Panel
|
|
283
|
+
|
|
284
|
+
Chat embedded alongside other content (e.g., split view on tablets).
|
|
285
|
+
|
|
286
|
+
```dart
|
|
287
|
+
class SplitView extends StatelessWidget {
|
|
288
|
+
final User user;
|
|
289
|
+
const SplitView({super.key, required this.user});
|
|
290
|
+
|
|
291
|
+
@override
|
|
292
|
+
Widget build(BuildContext context) {
|
|
293
|
+
return Scaffold(
|
|
294
|
+
resizeToAvoidBottomInset: false,
|
|
295
|
+
body: Row(
|
|
296
|
+
children: [
|
|
297
|
+
// Left: your app content
|
|
298
|
+
Expanded(flex: 3, child: YourProductPage()),
|
|
299
|
+
// Right: embedded chat
|
|
300
|
+
Expanded(
|
|
301
|
+
flex: 2,
|
|
302
|
+
child: Column(
|
|
303
|
+
children: [
|
|
304
|
+
CometChatMessageHeader(user: user),
|
|
305
|
+
Expanded(child: CometChatMessageList(user: user)),
|
|
306
|
+
CometChatMessageComposer(user: user),
|
|
307
|
+
],
|
|
308
|
+
),
|
|
309
|
+
),
|
|
310
|
+
],
|
|
311
|
+
),
|
|
312
|
+
);
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
```
|
|
316
|
+
|
|
317
|
+
---
|
|
318
|
+
|
|
319
|
+
## Pattern 6: Floating Action Button → Chat
|
|
320
|
+
|
|
321
|
+
```dart
|
|
322
|
+
Scaffold(
|
|
323
|
+
body: YourMainContent(),
|
|
324
|
+
floatingActionButton: FloatingActionButton(
|
|
325
|
+
onPressed: () => _openChatModal(context, supportUser),
|
|
326
|
+
child: const Icon(Icons.chat),
|
|
327
|
+
),
|
|
328
|
+
)
|
|
329
|
+
```
|
|
330
|
+
|
|
331
|
+
---
|
|
332
|
+
|
|
333
|
+
## Incoming Calls — Global Placement
|
|
334
|
+
|
|
335
|
+
Incoming call handling MUST be at the app root level, not per-screen. Use `VoipCallHandler` or mount the call overlay in `MaterialApp.builder`:
|
|
336
|
+
|
|
337
|
+
```dart
|
|
338
|
+
// In main.dart — before runApp
|
|
339
|
+
VoipCallHandler.instance.init();
|
|
340
|
+
|
|
341
|
+
// Or in MaterialApp builder for overlay approach
|
|
342
|
+
MaterialApp(
|
|
343
|
+
builder: (context, child) {
|
|
344
|
+
return Stack(children: [
|
|
345
|
+
child!,
|
|
346
|
+
// Global incoming call overlay
|
|
347
|
+
]);
|
|
348
|
+
},
|
|
349
|
+
)
|
|
350
|
+
```
|
|
351
|
+
|
|
352
|
+
---
|
|
353
|
+
|
|
354
|
+
## Anti-Patterns
|
|
355
|
+
|
|
356
|
+
```dart
|
|
357
|
+
// ❌ WRONG — resizeToAvoidBottomInset not set (defaults to true)
|
|
358
|
+
Scaffold(
|
|
359
|
+
body: Column(children: [
|
|
360
|
+
Expanded(child: CometChatMessageList(user: user)),
|
|
361
|
+
CometChatMessageComposer(user: user),
|
|
362
|
+
]),
|
|
363
|
+
)
|
|
364
|
+
|
|
365
|
+
// ❌ WRONG — passing widget.user directly (stale after block/kick)
|
|
366
|
+
CometChatMessageList(user: widget.user)
|
|
367
|
+
|
|
368
|
+
// ❌ WRONG — incoming call handler only on messages screen
|
|
369
|
+
// Calls ring on ALL screens, not just the one with call buttons
|
|
370
|
+
|
|
371
|
+
// ❌ WRONG — navigating to messages without extracting user/group
|
|
372
|
+
onItemTap: (conv) => Navigator.push(context, MaterialPageRoute(
|
|
373
|
+
builder: (_) => MessagesScreen(conversation: conv), // Wrong!
|
|
374
|
+
))
|
|
375
|
+
|
|
376
|
+
// ✅ CORRECT — extract user/group from conversation
|
|
377
|
+
onItemTap: (conv) {
|
|
378
|
+
final user = conv.conversationWith is User ? conv.conversationWith as User : null;
|
|
379
|
+
final group = conv.conversationWith is Group ? conv.conversationWith as Group : null;
|
|
380
|
+
Navigator.push(context, MaterialPageRoute(
|
|
381
|
+
builder: (_) => MessagesScreen(user: user, group: group),
|
|
382
|
+
));
|
|
383
|
+
}
|
|
384
|
+
```
|
|
385
|
+
|
|
386
|
+
---
|
|
387
|
+
|
|
388
|
+
## Checklist
|
|
389
|
+
|
|
390
|
+
- [ ] `resizeToAvoidBottomInset: false` on every Scaffold with `CometChatMessageComposer`
|
|
391
|
+
- [ ] `SafeArea(bottom: false)` when using composer (it handles safe area internally)
|
|
392
|
+
- [ ] Mutable `_user`/`_group` state copies, not `widget.user`/`widget.group`
|
|
393
|
+
- [ ] `onItemTap` extracts `User`/`Group` from `conversation.conversationWith`
|
|
394
|
+
- [ ] Protected groups handled (check `group.hasJoined` and `group.type`)
|
|
395
|
+
- [ ] Incoming call handler mounted at app root level
|
|
396
|
+
- [ ] Thread screen also has `resizeToAvoidBottomInset: false`
|
|
397
|
+
- [ ] `hideAppbar: true` when parent provides its own AppBar
|
|
398
|
+
- [ ] `IndexedStack` used for tab-based home (preserves tab state)
|