Skip to main content
Quick Reference for AI Agents & Developers
// Fetch a user and show messages directly
Future<User> fetchCometChatUser(String uid) async {
  final completer = Completer<User>();
  CometChat.getUser(
    uid,
    onSuccess: (user) => completer.complete(user),
    onError: (error) => completer.completeError(error),
  );
  return completer.future;
}

// Show messages screen directly
FutureBuilder<User>(
  future: fetchCometChatUser("cometchat-uid-2"),
  builder: (context, snapshot) {
    if (snapshot.hasData) {
      return MessagesScreen(user: snapshot.data!);
    }
    return CircularProgressIndicator();
  },
)

// Messages screen
Scaffold(
  appBar: CometChatMessageHeader(user: user, group: group),
  body: Column(
    children: [
      Expanded(child: CometChatMessageList(user: user, group: group)),
      CometChatMessageComposer(user: user, group: group),
    ],
  ),
)
Key Components:
The One-to-One Chat feature provides a streamlined direct messaging interface, making it ideal for support chats, dating apps, and private messaging platforms. This setup eliminates distractions by focusing solely on a dedicated chat window.

How It Works

This implementation bypasses the conversation list and opens directly into a chat:
  1. Fetch User/Group – Retrieve the target user or group using their UID/GUID
  2. Direct Navigation – Launch directly into the message screen
  3. Focused Experience – No conversation list, just the active chat
  4. Ideal for Context – Perfect for support tickets, notifications, or deep links

Use Cases

  • Customer Support – Direct users to agent chat from help center
  • Dating Apps – Open chat after a match
  • Notifications – Deep link from push notification to specific chat
  • Onboarding – Guide new users through a welcome chat
  • Contextual Messaging – Start chat from user profile or product page

Implementation

Step 1: Render the Message View

The CometChatMessageList widget displays all messages for a specific user or group. Follow the steps below to render this component:
main.dart
@override
Widget build(BuildContext context) {
  return Scaffold(
    body: SafeArea(
      child: FutureBuilder<User>(
        future: fetchCometChatUser("cometchat-uid-2"),
        builder: (context, snapshot) {
          if (snapshot.connectionState == ConnectionState.waiting) {
            return const Center(child: CircularProgressIndicator());
          } else if (snapshot.hasError) {
            return Center(child: Text("Error: ${snapshot.error}"));
          } else if (snapshot.hasData) {
            return MessagesScreen(user: snapshot.data!);
          } else {
            return const Center(child: Text("User not found"));
          }
        },
      ),
    ),
  );
}
Key Concepts:
ConceptDescription
fetchCometChatUser()Async function to retrieve user by UID
FutureBuilderWidget that builds based on async operation state
MessagesScreenCustom widget containing message components

Full Example: main.dart

main.dart
import 'package:flutter/material.dart';
import 'package:cometchat_chat_uikit/cometchat_chat_uikit.dart';
import 'package:cometchat_calls_uikit/cometchat_calls_uikit.dart';  // Optional: Include if you're using Audio/Video Calling
import 'messages_screen.dart';
import 'cometchat_config.dart';

import 'dart:async';

void main() => runApp(const MyApp());

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'CometChat UI Kit',
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
        useMaterial3: true,
      ),
      home: const Home(),
    );
  }
}

class Home extends StatelessWidget {
  const Home({super.key});

  Future<void> _initializeAndLogin() async {
    final settings = UIKitSettingsBuilder()
      ..subscriptionType = CometChatSubscriptionType.allUsers
      ..autoEstablishSocketConnection = true
      ..appId = CometChatConfig.appId
      ..region = CometChatConfig.region
      ..authKey = CometChatConfig.authKey
      ..extensions = CometChatUIKitChatExtensions.getDefaultExtensions()  // Replace with empty array to disable extensions
      ..callingExtension = CometChatCallingExtension();  // Optional: Include if you're using Audio/Video Calling

    await CometChatUIKit.init(uiKitSettings: settings.build());
    await CometChatUIKit.login(
      'cometchat-uid-1',
      onSuccess: (_) => debugPrint('✅ Login Successful'),
      onError: (err) => throw Exception('Login Failed: $err'),
    );
  }

  @override
  Widget build(BuildContext context) {
    return FutureBuilder<void>(
      future: _initializeAndLogin(),
      builder: (ctx, snap) {
        if (snap.connectionState != ConnectionState.done) {
          return const Scaffold(
            body: SafeArea(
              child: Center(child: CircularProgressIndicator()),
            ),
          );
        }
        if (snap.hasError) {
          return Scaffold(
            body: SafeArea(
              child: Center(
                child: Text(
                  'Error starting app:\n${snap.error}',
                  textAlign: TextAlign.center,
                ),
              ),
            ),
          );
        }
        return const MessagesPage();
      },
    );
  }
}

class MessagesPage extends StatelessWidget {
  const MessagesPage({super.key});

  Future<User> fetchCometChatUser(String uid) async {
    final completer = Completer<User>();
    CometChat.getUser(
      uid,
      onSuccess: (user) => completer.complete(user),
      onError: (error) => completer.completeError(error),
    );
    return completer.future;
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: SafeArea(
        child: FutureBuilder<User>(
          future: fetchCometChatUser("cometchat-uid-2"),
          builder: (context, snapshot) {
            if (snapshot.connectionState == ConnectionState.waiting) {
              return const Center(child: CircularProgressIndicator());
            } else if (snapshot.hasError) {
              return Center(child: Text("Error: ${snapshot.error}"));
            } else if (snapshot.hasData) {
              return MessagesScreen(user: snapshot.data!);
            } else {
              return const Center(child: Text("User not found"));
            }
          },
        ),
      ),
    );
  }
}

Step 2: Render the Messages Component

To create a complete messaging view, include the following components in messages_screen.dart:
messages_screen.dart
import 'package:flutter/material.dart';
import 'package:cometchat_chat_uikit/cometchat_chat_uikit.dart';

class MessagesScreen extends StatefulWidget {
  final User? user;
  final Group? group;

  const MessagesScreen({Key? key, this.user, this.group}) : super(key: key);

  @override
  State<MessagesScreen> createState() => _MessagesScreenState();
}

class _MessagesScreenState extends State<MessagesScreen> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: CometChatMessageHeader(
        user: widget.user,
        group: widget.group,
      ),
      body: SafeArea(
        child: Column(
          children: [
            Expanded(
              child: CometChatMessageList(
                user: widget.user,
                group: widget.group,
              ),
            ),
            CometChatMessageComposer(
              user: widget.user,
              group: widget.group,
            ),
          ],
        ),
      ),
    );
  }
}
Component Breakdown:
ComponentPurposeKey Features
CometChatMessageHeaderShows conversation title, avatar, and actionsUser/group info, back button, call buttons
CometChatMessageListDisplays messages in chronological orderReal-time updates, reactions, replies
CometChatMessageComposerInput field for composing messagesText, media, attachments, emojis

Step 3: Run the App

Use the following command to run the app on a connected device or emulator:
flutter run
This will launch the app, and you should see the one-to-one chat interface with the message header, list, and composer ready for use.

Variations

For Group Chat

To open a group chat instead of a one-to-one chat, fetch a group instead of a user:
Future<Group> fetchCometChatGroup(String guid) async {
  final completer = Completer<Group>();
  CometChat.getGroup(
    guid,
    onSuccess: (group) => completer.complete(group),
    onError: (error) => completer.completeError(error),
  );
  return completer.future;
}

// In your widget
FutureBuilder<Group>(
  future: fetchCometChatGroup("your-group-guid"),
  builder: (context, snapshot) {
    if (snapshot.hasData) {
      return MessagesScreen(group: snapshot.data!);
    }
    return CircularProgressIndicator();
  },
)

From Route Parameters

Pass user/group ID through navigation:
// Navigate with parameters
Navigator.push(
  context,
  MaterialPageRoute(
    builder: (_) => ChatScreen(userId: "cometchat-uid-2"),
  ),
);

// ChatScreen widget
class ChatScreen extends StatelessWidget {
  final String userId;
  
  const ChatScreen({Key? key, required this.userId}) : super(key: key);

  Future<User> fetchUser() async {
    final completer = Completer<User>();
    CometChat.getUser(
      userId,
      onSuccess: (user) => completer.complete(user),
      onError: (error) => completer.completeError(error),
    );
    return completer.future;
  }

  @override
  Widget build(BuildContext context) {
    return FutureBuilder<User>(
      future: fetchUser(),
      builder: (context, snapshot) {
        if (snapshot.hasData) {
          return MessagesScreen(user: snapshot.data!);
        }
        return Scaffold(
          body: Center(child: CircularProgressIndicator()),
        );
      },
    );
  }
}
Handle deep links to open specific chats:
// In your main app
MaterialApp(
  onGenerateRoute: (settings) {
    if (settings.name == '/chat') {
      final args = settings.arguments as Map<String, dynamic>;
      return MaterialPageRoute(
        builder: (_) => ChatScreen(
          userId: args['userId'],
          groupId: args['groupId'],
        ),
      );
    }
    return null;
  },
)

// Navigate from deep link
Navigator.pushNamed(
  context,
  '/chat',
  arguments: {'userId': 'cometchat-uid-2'},
);

Customization Options

Hide Header or Composer

MessagesScreen(
  user: user,
  hideMessageHeader: true,  // Hide the header
  hideMessageComposer: false,  // Show the composer
)

Custom Message Actions

CometChatMessageList(
  user: user,
  onMessageTap: (message) {
    // Handle message tap
  },
  onMessageLongPress: (message) {
    // Show options menu
  },
)

Styling

CometChatMessageList(
  user: user,
  messageListStyle: MessageListStyle(
    background: Colors.grey[100],
    loadingIconTint: Colors.blue,
  ),
)
For complete customization options, see:

Common Use Cases

// From support ticket screen
ElevatedButton(
  onPressed: () {
    Navigator.push(
      context,
      MaterialPageRoute(
        builder: (_) => ChatScreen(
          userId: ticket.assignedAgentId,
        ),
      ),
    );
  },
  child: Text('Chat with Support'),
)
// From user profile screen
IconButton(
  icon: Icon(Icons.message),
  onPressed: () {
    Navigator.push(
      context,
      MaterialPageRoute(
        builder: (_) => ChatScreen(userId: profile.userId),
      ),
    );
  },
)
// Handle notification tap
void handleNotificationTap(Map<String, dynamic> data) {
  final userId = data['senderId'];
  Navigator.pushNamed(
    context,
    '/chat',
    arguments: {'userId': userId},
  );
}
CometChatMessageComposer(
  user: user,
  text: "Hello! I need help with...",  // Pre-filled text
)

Best Practices

Always handle errors when fetching users or groups:
FutureBuilder<User>(
  future: fetchCometChatUser(userId),
  builder: (context, snapshot) {
    if (snapshot.hasError) {
      return Scaffold(
        body: Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: [
              Icon(Icons.error, size: 48, color: Colors.red),
              SizedBox(height: 16),
              Text('Failed to load chat'),
              ElevatedButton(
                onPressed: () => setState(() {}),  // Retry
                child: Text('Retry'),
              ),
            ],
          ),
        ),
      );
    }
    // ... rest of builder
  },
)
Provide clear loading indicators:
if (snapshot.connectionState == ConnectionState.waiting) {
  return Scaffold(
    body: Center(
      child: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: [
          CircularProgressIndicator(),
          SizedBox(height: 16),
          Text('Loading chat...'),
        ],
      ),
    ),
  );
}
Cache fetched users to avoid repeated API calls:
class UserCache {
  static final Map<String, User> _cache = {};
  
  static Future<User> getUser(String uid) async {
    if (_cache.containsKey(uid)) {
      return _cache[uid]!;
    }
    
    final completer = Completer<User>();
    CometChat.getUser(
      uid,
      onSuccess: (user) {
        _cache[uid] = user;
        completer.complete(user);
      },
      onError: (error) => completer.completeError(error),
    );
    return completer.future;
  }
}

Next Steps

Message Components

Explore message list, header, and composer features

Conversation List

Add a conversation list for multi-chat support

Theming Guide

Customize colors, fonts, and styles to match your brand

Events & Listeners

Handle real-time events and user interactions