flutter pub add web_socket_channel
flutter pub add intl
Then you typically create a service folder and create a dart file like chat_screen.dart with below code
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:web_socket_channel/io.dart';
import 'dart:async';
import 'package:intl/intl.dart';
class ChatScreen extends StatefulWidget {
const ChatScreen({super.key});
@override
ChatScreenState createState() => ChatScreenState();
}
class ChatScreenState extends State<ChatScreen> {
final TextEditingController _controller = TextEditingController();
late IOWebSocketChannel _channel;
final List<Map<String, dynamic>> _messages = []; // Updated to store Map
bool _isTryingToReconnect = false;
int userId = 1;
int locationId = 2;
@override
void initState() {
super.initState();
_initializeWebSocket();
}
void _initializeWebSocket() {
String url = 'wss://puc.mywebsolutions.co.in:8092?userId=$userId&locationId=$locationId';
_channel =
IOWebSocketChannel.connect(url);
_channel.stream.listen(
(message) {
setState(() {
_messages.add(json.decode(message)); // Decode and add to messages
});
},
onDone: _attemptReconnect,
onError: (error) {
_attemptReconnect();
});
}
void _attemptReconnect() {
if (!_isTryingToReconnect) {
_isTryingToReconnect = true;
Timer.periodic(const Duration(seconds: 3), (timer) {
// Check if the WebSocket is closed
if (_channel.closeCode != null) {
print("Attempting to reconnect...");
_initializeWebSocket();
} else {
print("WebSocket is open, stopping reconnection attempts.");
timer.cancel();
_isTryingToReconnect = false;
}
});
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Chat with Staff'),
),
body: Column(
children: <Widget>[
Expanded(
child: ListView.builder(
itemCount: _messages.length,
itemBuilder: (context, index) {
final messageData = _messages[index];
// Using the _formatMessage method to format the message
return _buildMessageBubble(messageData);
},
),
),
Padding(
padding: const EdgeInsets.all(8.0),
child: Row(
children: [
Expanded(
child: TextField(
controller: _controller,
decoration: const InputDecoration(
filled: true, labelText: 'Send a message'),
onSubmitted: (value) {
// This gets called when the user presses the Enter key
if (value.trim().isNotEmpty) {
_sendMessage(value.trim());
_controller.clear(); // Clear the text field after sending
}
},
textInputAction: TextInputAction.send, // Changes the Enter key to a Send icon
),
),
IconButton(
icon: const Icon(Icons.send),
onPressed: () {
if (_controller.text.trim().isNotEmpty) {
_sendMessage(_controller.text.trim());
_controller.clear(); // Clear the text field after sending
}
},
),
],
),
),
],
),
);
}
void _sendMessage(String message) {
if (message.isNotEmpty) {
_channel.sink.add(json.encode({
'text': message,
'username':'flutter_user1',
'locationId':locationId,
'userId':1,
'senderType':'flutterClient'
// Add any additional data you need to send
}));
setState(() {
// Simulate a message send by adding it to the message list
_messages.add({
'event': 'NewMessage',
'data': {
'text': message,
'username': 'flutter_user1',
'user': {
'name': 'You' // Replace with actual username if available
}
}
});
});
_controller.clear(); // Clear the message input field
}
}
Widget _buildMessageBubble(Map<String, dynamic> messageData) {
final isSentByMe = messageData['data']['username'] == 'flutter_user1';
final messageText = messageData['data']['text'] ?? 'No text';
final messageTime = messageData['data']['time']; // Ensure this exists
final senderName = isSentByMe ? 'Me' : (messageData['data']['username'] ?? 'Unknown');
return Row(
mainAxisAlignment: isSentByMe ? MainAxisAlignment.end : MainAxisAlignment.start,
children: [
Container(
padding: const EdgeInsets.symmetric(vertical: 10, horizontal: 16),
margin: const EdgeInsets.symmetric(vertical: 4, horizontal: 8),
decoration: BoxDecoration(
color: isSentByMe ? Colors.lightBlue : Colors.grey[300],
borderRadius: BorderRadius.circular(16),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'$senderName: $messageText',
style: TextStyle(color: isSentByMe ? Colors.white : Colors.black),
),
if (messageTime != null)
Padding(
padding: const EdgeInsets.only(top: 5),
child: Text(
DateFormat('yyyy-MM-dd HH:mm:ss').format(DateTime.parse(messageTime)),
style: TextStyle(
color: Colors.grey[600],
fontSize: 10,
),
),
),
],
),
),
],
);
}
@override
void dispose() {
_channel.sink.close();
super.dispose();
}
}
and include this class in main.dart
import 'package:flutter/material.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:livechat/chatnew.dart';
import 'package:livechat/services/notification_service.dart';
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
import 'firebase_options.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized(); // Required for async main
await Firebase.initializeApp(options: DefaultFirebaseOptions.currentPlatform); // Initialize Firebase
NotificationService().init();
runApp(const MyApp());
initNotifications();
}
void initNotifications() {
FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin = FlutterLocalNotificationsPlugin();
const AndroidInitializationSettings initializationSettingsAndroid = AndroidInitializationSettings('@mipmap/ic_launcher');
final InitializationSettings initializationSettings = InitializationSettings(
android: initializationSettingsAndroid,
);
flutterLocalNotificationsPlugin.initialize(initializationSettings);
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return const MaterialApp(
title: 'Chat App',
home: ChatScreen(),
);
}
}
Leave a Reply