agentsclimarketplace

Cometchat flutter v5 core

Skill cometchat/cometchat-skills/skills/cometchat-flutter-v5-core

Use when writing any code that uses CometChat Flutter UIKit v5 (cometchat_chat_uikit v5.2.14, cometchat_calls_uikit v5.0.15, cometchat_uikit_shared v5.2.3). Contains hard rules that prevent silent failures.From its SKILL.md

Install
npx -y skills add cometchat/cometchat-skills --skill cometchat-flutter-v5-core

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

One thing to look at

  • no licenseNo license file was found in the repository. Code published without one is not open source by default, so using it at work is a question for whoever answers licensing questions where you are.

What its file declares

Copied from the file, not written here

The file declares its own license as MIT. That is the author’s claim about this one file, and it is not the same thing as the license GitHub reports for the repository, which is listed with the other numbers below.

SKILL.md

11.7 KB, ~2.8k tokens by cl100k_base, as published. Nobody here has run it

CometChat Flutter UIKit v5 — Core Rules

Ground truth: cometchat_chat_uikit: ^5.2 (GetX-based; pair with cometchat_calls_uikit: ^5.0 / raw cometchat_calls_sdk ^5.0.2 for calls) — the pub-cache package source + docs/ui-kit/flutter/v5. Official docs: https://www.cometchat.com/docs/ui-kit/flutter/v5/overview · Docs MCP: claude mcp add --transport http cometchat-docs https://www.cometchat.com/docs/mcp (or fetch the URL directly without MCP). V5 is legacy/maintenance-only (V6 is current); verify Dart symbols against the resolved package source.

Non-negotiable constraints for all CometChat UIKit v5 code. Violating these causes silent failures or crashes.

Key v5 Architecture Facts

  • State management: GetX (GetBuilder, GetxController, Get.put, Get.find, Get.delete)
  • Separate packages: cometchat_chat_uikit + cometchat_calls_uikit + cometchat_uikit_shared
  • SDK: cometchat_sdk ^4.1.2 + cometchat_calls_sdk ^4.2.2 (chat-kit baseline). For voice/video calling, do NOT use cometchat_calls_uikit (4.x-bound) — integrate the raw cometchat_calls_sdk ^5.0.2 per cometchat-flutter-v5-calls (the V5-canonical calls path).
  • Imports — two barrels. For chat-only projects: package:cometchat_chat_uikit/cometchat_chat_uikit.dart. For projects that also need voice/video calling: ADD package:cometchat_calls_uikit/cometchat_calls_uikit.dart as a SECOND import — the calls barrel re-exports shared + SDK only and does NOT re-export cometchat_chat_uikit. Chat widgets like CometChatConversations, CometChatMessageList, CometChatMessageComposer are reachable only through the chat barrel.
  • CometChatUIKit.login(uid) takes a String directly (not an object)
  • No ServiceLocator pattern — controllers are created via Get.put() internally
  • Style classes use ThemeExtension with merge() pattern

Rule: INIT_FIRST

CometChatUIKit.init() must complete before any login, component usage, or SDK call.

// ✅ CORRECT
final settings = (UIKitSettingsBuilder()
      ..appId = 'APP_ID'
      ..region = 'us'
      ..authKey = 'AUTH_KEY'
      ..subscriptionType = CometChatSubscriptionType.allUsers)
    .build();

CometChatUIKit.init(
  uiKitSettings: settings,
  onSuccess: (_) => debugPrint('Init done'),
  onError: (e) => debugPrint('Init failed: ${e.message}'),
);

// ❌ WRONG — login before init completes
CometChatUIKit.init(uiKitSettings: settings);
CometChatUIKit.login('uid'); // Race condition

Rule: AUTH_CHECK_AFTER_INIT

After CometChatUIKit.init() completes, the static field CometChatUIKit.loggedInUser is populated if a cached session exists (init internally calls getLoggedInUser()). You can check it synchronously in onSuccess, or use CometChatUIKit.getLoggedInUser() for an explicit async check.

// ✅ CORRECT — synchronous check after init
CometChatUIKit.init(
  uiKitSettings: settings,
  onSuccess: (_) {
    final hasUser = CometChatUIKit.loggedInUser != null;
    // Route to home or login
  },
);

// ✅ ALSO CORRECT — explicit async check (used by master app)
CometChatUIKit.init(
  uiKitSettings: settings,
  onSuccess: (_) async {
    final user = await CometChatUIKit.getLoggedInUser();
    if (user != null) {
      await CometChatUIKit.login(user.uid, onSuccess: ...);
    }
  },
);

Note: CometChatUIKit.login() handles re-login gracefully — if the user is already logged in with the same UID, it returns the cached user without hitting the server.

Rule: LISTENER_LIFECYCLE

SDK listeners MUST be registered with a unique ID in initState() (or GetxController onInit()) and removed in dispose() (or onClose()).

// ✅ CORRECT
class _MyScreenState extends State<MyScreen> with MessageListener {
  late final String _listenerId;

  @override
  void initState() {
    super.initState();
    _listenerId = 'my_screen_${DateTime.now().millisecondsSinceEpoch}';
    CometChat.addMessageListener(_listenerId, this);
  }

  @override
  void dispose() {
    CometChat.removeMessageListener(_listenerId);
    super.dispose();
  }
}

// ❌ WRONG — hardcoded ID causes collisions; missing dispose removal
CometChat.addMessageListener('messages', this); // Collision!

Rule: THEME_CACHE

Cache theme values in didChangeDependencies() — unconditionally, no flag needed. Never call CometChatThemeHelper.getColorPalette(context) in build().

getColorPalette() creates a new CometChatColorPalette object every call, resolving each token individually via Theme.of(context). During keyboard animation, MediaQuery changes trigger rebuilds, making this expensive in build().

// ✅ CORRECT — matches actual package pattern (no flag)
@override
void didChangeDependencies() {
  super.didChangeDependencies();
  colorPalette = CometChatThemeHelper.getColorPalette(context);
  spacing = CometChatThemeHelper.getSpacing(context);
  typography = CometChatThemeHelper.getTypography(context);
}

// ❌ WRONG — lookup in build causes jank
@override
Widget build(BuildContext context) {
  final colors = CometChatThemeHelper.getColorPalette(context); // Expensive!
  return Container(color: colors.primary);
}

Do NOT use a _themeInitialized flag — it prevents theme updates when the system switches between light/dark mode.

Rule: SUBSCRIPTION_TYPE_REQUIRED

Omitting subscriptionType in UIKitSettingsBuilder silently disables all presence events (online/offline, typing indicators). No error is thrown.

// ✅ CORRECT
UIKitSettingsBuilder()
  ..subscriptionType = CometChatSubscriptionType.allUsers

Rule: REGION_LOWERCASE

Region must be a lowercase string: 'us', 'eu', or 'in'.

Rule: MUID_PRESERVATION

When handling ccMessageSent events, compare by muid first, then id — the SDK may return an empty muid in the success callback.

Pattern: Callback → Async Bridge (Completer)

import 'dart:async';

Future<bool> initAsync(UIKitSettings settings) {
  final completer = Completer<bool>();
  CometChatUIKit.init(
    uiKitSettings: settings,
    onSuccess: (_) => completer.complete(true),
    onError: (e) => completer.complete(false),
  );
  return completer.future;
}

v5 Component Architecture Pattern (GetX)

{component}/
├── cometchat_{component}.dart              # StatefulWidget
├── cometchat_{component}_controller.dart   # extends GetxController
├── cometchat_{component}_style.dart        # ThemeExtension with merge()
└── {component}_builder_protocol.dart       # Request builder protocol

Internal lifecycle:

@override
void initState() {
  super.initState();
  tag = widget.controllerTag ?? 'default_tag_${DateTime.now().millisecondsSinceEpoch}';
  controller = Get.put<Controller>(Controller(...), tag: tag);
}

@override
void dispose() {
  if (widget.controllerTag == null) {
    Get.delete<Controller>(tag: tag);
  }
  super.dispose();
}

Android Build Requirements

  • android.useAndroidX=true and android.enableJetifier=true in gradle.properties
  • minSdk 26 in android/app/build.gradle
  • ProGuard: -keep class com.cometchat.** { *; } and -keep interface com.cometchat.** { *; }

Top 10 Error Debugging

SymptomCauseFix
"Authentication null"CometChatUIKit.init() not calledCall init before login/components
"APP ID null"appId not set in UIKitSettingsBuilderSet ..appId = 'YOUR_APP_ID'
No typing indicators / presencesubscriptionType not setSet ..subscriptionType = CometChatSubscriptionType.allUsers
Theme jank during keyboardTheme looked up in build()Cache in didChangeDependencies()
Listener leak / duplicate eventsListener not removed in dispose()Always remove with same ID
GetX controller not foundUsing Get.find() before Get.put()Let UIKit components manage their own controllers
Region errorUppercase region stringUse lowercase: 'us', 'eu', 'in'
Release build crashMissing ProGuard keep rulesAdd -keep class com.cometchat.** { *; }

Checklist — Every CometChat v5 Screen

  • CometChatUIKit.init() called before any usage
  • subscriptionType set in UIKitSettingsBuilder
  • region is lowercase
  • Theme cached in didChangeDependencies(), not build()
  • SDK listeners registered with unique ID, removed in dispose()
  • Colors from CometChatThemeHelper, never hardcoded
  • Imports: package:cometchat_chat_uikit/cometchat_chat_uikit.dart always; ADD package:cometchat_calls_uikit/cometchat_calls_uikit.dart if you use voice/video

Visual Builder integration

Flutter V5 is the primary home for Visual Builder integration. The canonical repo at the chat_builder/ directory inside the Flutter Visual Builder ZIP (download from https://preview.cometchat.com/downloads/cometchat-builder-flutter.zip) ships V5-shaped code — cometchat_chat_uikit: ^5.2.12 + cometchat_calls_uikit: ^5.0.13. The integration copies the entire chat_builder/ directory as a path: dependency, then BuilderSettingsHelper.loadFromAsset() reads chat_builder/assets/sample_app/cometchat-builder-settings.json and configures the bundled chat UI accordingly.

The full recipe lives in cometchat-flutter-v6-core §"Visual Builder integration" because that's where the V6-prep restructure originally landed the validated content. Both skills reference the same canonical; the V6 page carries a "V5-shaped code" warning at the top. V5 customers should follow that recipe AS-IS — the canonical IS V5-targeted.

Validated 2026-05-21 against Flutter 3.38.3: flutter build apk --debug produces app-debug.apk after applying:

  • Envelope-wrapped JSON at chat_builder/assets/sample_app/cometchat-builder-settings.json. The CLI (source of truth) writes { builderId, name, settings: {...} }; the vendor canonical's own checked-in file carries only { builderId, settings } (no name). BuilderSettingsHelper.loadFromAsset() reads only builderId + settings and ignores any extra top-level keys, so the CLI's extra name is harmless.
  • Two missing-field defaults injected pre-write (mentionAll + inAppSounds — same as Android)
  • android.enableJetifier=true in android/gradle.properties (the chat SDK pulls com.android.support transitively)
  • await BuilderSettingsHelper.loadFromAsset() in lib/main.dart before runApp()
  • chat_builder: { path: ./chat_builder } in host pubspec.yaml

Differences from the V6 page's recipe text:

  • V5 host code uses StatefulWidget with direct listener management (V6 uses BLoC pattern); both work with the embedded chat_builder package since it owns its own state.
  • V5 calls (the standalone cometchat-flutter-v5-calls flow, outside the builder) don't need the [[project_v6_flutter_calls_partial]] navigatorKey workaround — that's a V6-specific incoming-call-routing requirement. However, the Visual Builder canonical itself (V5-shaped) wires navigatorKey: CallNavigationContext.navigatorKey UNCONDITIONALLY in every MaterialApp ChatBuilder.createApp() builds, regardless of whether calls are enabled — so if you mount ChatBuilder.createApp() (recommended) or replicate its MaterialApp in a host wrapper, keep that navigator key in place. Do NOT gate it behind "calls enabled". See the v6-core recipe's wrapper guidance.

What ships with it

Read from the repository

Just SKILL.md. No reference files, no scripts.

Keep looking

Skills are one crate of 325,949. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.