chat_plugin 1.0.0 copy "chat_plugin: ^1.0.0" to clipboard
chat_plugin: ^1.0.0 copied to clipboard

A flexible, feature-rich chat plugin for Flutter applications that provides real-time messaging capabilities using Socket.IO.

example/lib/main.dart

import 'dart:convert';

import 'package:flutter/material.dart';
import 'dart:async';

import 'package:chat_plugin/chat_plugin.dart';
import 'package:http/http.dart' as http;

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  
  // Initialize the chat plugin with a custom configuration
  await ChatPlugin.initialize(
    config: ChatConfig(
      apiUrl: 'https://your-chat-server.com',
      enableTypingIndicators: true,
      enableReadReceipts: true,
      enableOnlineStatus: true,
      autoMarkAsRead: true,
      connectionTimeout: 15,
      maxReconnectionAttempts: 3,
      chatRoomRefreshInterval: 30,
      // You can provide initial user credentials if available
      userId: null, // Will be set after login
      token: null,  // Will be set after login
      // Additional headers for API requests
      additionalHeaders: {
        'App-Version': '1.0.0',
        'Platform': 'flutter',
      },
      // Custom socket parameters
      socketParams: {
        'transports': ['websocket'],
        'autoConnect': false,
      }
    ),
  );
  
  // Set up custom API handlers
  setupCustomApiHandlers();
  
  // Set up custom socket events
  setupCustomSocketEvents();
  
  runApp(MyApp());
}

void setupCustomApiHandlers() {
  // Create custom API handlers for chat operations
  final apiHandlers = ChatApiHandlers(
    // Custom implementation for loading messages
    loadMessagesHandler: ({int page = 1, int limit = 20, String searchText = ""}) async {
      final chatService = ChatPlugin.chatService;
      final userId = ChatConfig.instance.userId;
      final token = ChatConfig.instance.token;
      final receiverId = chatService.receiverId;
      
      if (userId == null || token == null || receiverId.isEmpty) {
        throw Exception('Not authenticated or no receiver selected');
      }
      
      // Custom implementation for fetching messages
      final response = await http.get(
        Uri.parse('https://your-custom-api.com/messages?sender=$userId&receiver=$receiverId&page=$page&limit=$limit'),
        headers: {
          'Authorization': 'Bearer $token',
          'Content-Type': 'application/json',
        },
      );
      
      if (response.statusCode == 200) {
        final List<dynamic> data = jsonDecode(response.body);
        return data.map((msg) => ChatMessage.fromMap(msg, userId)).toList();
      } else {
        throw Exception('Failed to load messages: ${response.statusCode}');
      }
    },
    
    // Custom implementation for loading chat rooms
    loadChatRoomsHandler: () async {
      final userId = ChatConfig.instance.userId;
      final token = ChatConfig.instance.token;
      
      if (userId == null || token == null) {
        throw Exception('Not authenticated');
      }
      
      // Custom implementation for fetching chat rooms
      final response = await http.get(
        Uri.parse('https://your-custom-api.com/chat-rooms?userId=$userId'),
        headers: {
          'Authorization': 'Bearer $token',
          'Content-Type': 'application/json',
        },
      );
      
      if (response.statusCode == 200) {
        final List<dynamic> data = jsonDecode(response.body);
        return data.map((room) => ChatRoom.fromMap(room)).toList();
      } else {
        throw Exception('Failed to load chat rooms: ${response.statusCode}');
      }
    },
    
    // Custom implementation for sending messages
    sendMessageHandler: (String text) async {
      final chatService = ChatPlugin.chatService;
      final userId = ChatConfig.instance.userId;
      final token = ChatConfig.instance.token;
      final receiverId = chatService.receiverId;
      
      if (userId == null || token == null || receiverId.isEmpty) {
        throw Exception('Not authenticated or no receiver selected');
      }
      
      String messageId = DateTime.now().millisecondsSinceEpoch.toString();
      
      // Custom implementation for sending a message
      final response = await http.post(
        Uri.parse('https://your-custom-api.com/messages'),
        headers: {
          'Authorization': 'Bearer $token',
          'Content-Type': 'application/json',
        },
        body: jsonEncode({
          'messageId': messageId,
          'sender': userId,
          'receiver': receiverId,
          'message': text,
          'timestamp': DateTime.now().toIso8601String(),
        }),
      );
      
      if (response.statusCode == 201) {
        // Create and return the sent message
        return ChatMessage(
          messageId: messageId,
          senderId: userId,
          receiverId: receiverId,
          message: text,
          createdAt: DateTime.now(),
          status: 'sent',
          isMine: true,
        );
      } else {
        throw Exception('Failed to send message: ${response.statusCode}');
      }
    },
    
    // Custom implementation for deleting messages
    deleteMessageHandler: (String messageId) async {
      final userId = ChatConfig.instance.userId;
      final token = ChatConfig.instance.token;
      
      if (userId == null || token == null) {
        throw Exception('Not authenticated');
      }
      
      // Custom implementation for deleting a message
      final response = await http.delete(
        Uri.parse('https://your-custom-api.com/messages/$messageId'),
        headers: {
          'Authorization': 'Bearer $token',
          'Content-Type': 'application/json',
        },
      );
      
      return response.statusCode == 200;
    },
  );
  
  // Set the custom API handlers
  ChatPlugin.chatService.setApiHandlers(apiHandlers);
}

void setupCustomSocketEvents() {
  // Set custom socket event configuration
  ChatPlugin.chatService.setSocketEventConfig(
    SocketEventConfig(
      sendMessageEvent: 'custom_send_message',
      receiveMessageEvent: 'custom_receive_message',
      joinRoomEvent: 'custom_join_room',
      typingStartEvent: 'custom_typing_start',
      typingEndEvent: 'custom_typing_end',
      messageDeliveredEvent: 'custom_message_delivered',
      messagesReadEvent: 'custom_messages_read',
      markMessagesReadEvent: 'custom_mark_messages_read',
      userStatusChangeEvent: 'custom_user_status_change',
      registerUserEvent: 'custom_register_user',
      deleteMessageEvent: 'custom_delete_message',
    ),
  );
  
  // Register for custom socket events once socket is connected
  Future.delayed(const Duration(seconds: 1), () {
    final chatService = ChatPlugin.chatService;
    
    if (chatService.isSocketConnected) {
      chatService.registerCustomSocketEvents({
        'custom_user_joined': (data) {
          print('User joined: $data');
          chatService.triggerCustomEvent('userJoined', data);
        },
        'custom_user_left': (data) {
          print('User left: $data');
          chatService.triggerCustomEvent('userLeft', data);
        },
        'custom_message_reaction': (data) {
          print('Message reaction: $data');
          chatService.triggerCustomEvent('messageReaction', data);
        },
      });
    }
  });
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Custom Chat Plugin Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
        visualDensity: VisualDensity.adaptivePlatformDensity,
      ),
      home: HomePage(),
    );
  }
}


class HomePage extends StatefulWidget {
  @override
  _HomePageState createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  final TextEditingController _usernameController = TextEditingController();
  final TextEditingController _passwordController = TextEditingController();
  bool _isLoggedIn = false;
  bool _isLoading = false;
  final ChatService _chatService = ChatPlugin.chatService;

  @override
  void initState() {
    super.initState();
    _checkLoginStatus();
    
    // Listen for custom events
    _chatService.addEventListener(
      ChatEventType.custom,
      'homepage_custom_listener',
      (data) {
        if (data['eventName'] == 'userJoined') {
          ScaffoldMessenger.of(context).showSnackBar(
            SnackBar(content: Text('User joined: ${data['data']['username']}'))
          );
        }
      },
    );
    
    // Listen for connection status changes
    _chatService.addEventListener(
      ChatEventType.connectionStatusChanged,
      'homepage_connection_listener',
      (isConnected) {
        print('Connection status changed: $isConnected');
        if (!isConnected && _isLoggedIn) {
          ScaffoldMessenger.of(context).showSnackBar(
            SnackBar(content: Text('Connection lost. Reconnecting...'))
          );
        }
      },
    );
  }

  Future<void> _checkLoginStatus() async {
    setState(() {
      _isLoading = true;
    });

    try {
      // Check if userId and token exist in ChatConfig
      _isLoggedIn = ChatConfig.instance.userId != null && ChatConfig.instance.token != null;
      
      if (_isLoggedIn) {
        // Initialize global connection for notifications
        await _chatService.initialize();
      }
    } catch (e) {
      print("Error checking login status: $e");
      _isLoggedIn = false;
    }

    setState(() {
      _isLoading = false;
    });
  }

  Future<void> _login() async {
    if (_usernameController.text.isEmpty || _passwordController.text.isEmpty) {
      ScaffoldMessenger.of(context).showSnackBar(
        SnackBar(content: Text('Please enter username and password')),
      );
      return;
    }

    setState(() {
      _isLoading = true;
    });

    try {
      // Custom login implementation
      final response = await http.post(
        Uri.parse('https://your-custom-api.com/login'),
        headers: {'Content-Type': 'application/json'},
        body: jsonEncode({
          'username': _usernameController.text,
          'password': _passwordController.text,
        }),
      );

      if (response.statusCode == 200) {
        final data = jsonDecode(response.body);
        final userId = data['userId'];
        final token = data['token'];
        
        if (userId != null && token != null) {
          // Update the chat config with the new credentials
          ChatConfig.instance = ChatConfig.instance.updateCredentials(
            userId: userId,
            token: token,
          );
          
          // Update UI
          setState(() {
            _isLoggedIn = true;
            _isLoading = false;
          });
          
          // Initialize global connection for notifications
          await _chatService.initialize();
          
          return;
        }
      }
      
      // If we reach here, login failed
      ScaffoldMessenger.of(context).showSnackBar(
        SnackBar(content: Text('Login failed. Please check your credentials.')),
      );
    } catch (e) {
      print("Login error: $e");
      ScaffoldMessenger.of(context).showSnackBar(
        SnackBar(content: Text('An error occurred during login')),
      );
    }

    setState(() {
      _isLoading = false;
    });
  }

  Future<void> _logout() async {
    setState(() {
      _isLoading = true;
    });

    try {
      // Disconnect chat service
      _chatService.fullDisconnect();
      
      // Clear credentials
      ChatConfig.instance = ChatConfig.instance.clearCredentials();
      
      setState(() {
        _isLoggedIn = false;
      });
    } catch (e) {
      print("Logout error: $e");
      ScaffoldMessenger.of(context).showSnackBar(
        SnackBar(content: Text('An error occurred during logout')),
      );
    }

    setState(() {
      _isLoading = false;
    });
  }
  
  // Method to emit a custom socket event
  void _emitCustomEvent() {
    if (_chatService.isSocketConnected) {
      _chatService.emitCustomEvent('custom_test_event', {
        'userId': ChatConfig.instance.userId,
        'timestamp': DateTime.now().toIso8601String(),
        'data': 'Hello from Flutter app!'
      });
      
      ScaffoldMessenger.of(context).showSnackBar(
        SnackBar(content: Text('Custom event emitted')),
      );
    } else {
      ScaffoldMessenger.of(context).showSnackBar(
        SnackBar(content: Text('Socket not connected')),
      );
    }
  }

  @override
  Widget build(BuildContext context) {
    if (_isLoading) {
      return Scaffold(
        body: Center(
          child: CircularProgressIndicator(),
        ),
      );
    }

    if (_isLoggedIn) {
      return Scaffold(
        appBar: AppBar(
          title: Text('Custom Chat Demo'),
          actions: [
            IconButton(
              icon: Icon(Icons.send),
              onPressed: _emitCustomEvent,
              tooltip: 'Emit custom event',
            ),
            IconButton(
              icon: Icon(Icons.logout),
              onPressed: _logout,
              tooltip: 'Logout',
            ),
          ],
        ),
        body: Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: [
              const Text(
                'You are logged in!',
                style: TextStyle(fontSize: 18),
              ),
              SizedBox(height: 20),
              Text(
                'Connection status: ${_chatService.isSocketConnected ? 'Connected' : 'Disconnected'}',
                style: TextStyle(fontSize: 14, color: _chatService.isSocketConnected ? Colors.green : Colors.red),
              ),
              SizedBox(height: 20),
              ElevatedButton(
                onPressed: () {
                  // Navigator.push(
                  //   context,
                  //   MaterialPageRoute(
                  //     builder: (context) => MyChatListScreen(),
                  //   ),
                  // );
                },
                child: Text('View Conversations'),
              ),
            ],
          ),
        ),
      );
    } else {
      return Scaffold(
        appBar: AppBar(
          title: Text('Custom Chat Demo Login'),
        ),
        body: Padding(
          padding: const EdgeInsets.all(16.0),
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: [
              TextField(
                controller: _usernameController,
                decoration: const InputDecoration(
                  labelText: 'Username',
                  border: OutlineInputBorder(),
                ),
              ),
              SizedBox(height: 10),
              TextField(
                controller: _passwordController,
                obscureText: true,
                decoration: const InputDecoration(
                  labelText: 'Password',
                  border: OutlineInputBorder(),
                ),
              ),
              SizedBox(height: 20),
              ElevatedButton(
                onPressed: _login,
                child: Text('Login'),
              ),
            ],
          ),
        ),
      );
    }
  }
  
  @override
  void dispose() {
    // Remove event listeners
    _chatService.removeEventListener(ChatEventType.custom, 'homepage_custom_listener');
    _chatService.removeEventListener(ChatEventType.connectionStatusChanged, 'homepage_connection_listener');
    super.dispose();
  }
}
1
likes
140
points
28
downloads

Publisher

verified publishersnippetcoder.com

Weekly Downloads

A flexible, feature-rich chat plugin for Flutter applications that provides real-time messaging capabilities using Socket.IO.

Homepage

Documentation

API reference

License

MIT (license)

Dependencies

flutter, http, intl, plugin_platform_interface, provider, socket_io_client

More

Packages that depend on chat_plugin

Packages that implement chat_plugin