import 'dart:convert'; import 'dart:io'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:healthcare_pharmacy/pages/index.dart'; import 'package:healthcare_pharmacy/settings.dart'; import 'package:url_launcher/url_launcher.dart' as UrlLauncher; import 'package:web_socket_channel/io.dart'; import 'package:web_socket_channel/web_socket_channel.dart'; import 'models/ChatMessage.dart'; import 'package:image_picker/image_picker.dart'; import 'package:flutter_callkeep/flutter_callkeep.dart'; class ChatUI extends StatefulWidget { const ChatUI({Key? key}) : super(key: key); @override State createState() => _ChatUIState(); } class _ChatUIState extends State { WebSocketChannel channel=IOWebSocketChannel.connect( "wss://socketsbay.com/wss/v2/1/demo/", ); // WebSocket channel for call signaling late WebSocketChannel callChannel; WebSocketConnectionState _connectionState = WebSocketConnectionState.connecting; late ScrollController _scrollController; final TextEditingController _controller = TextEditingController(); // Store messages final List _messages = []; String myUserId = 'user456'; String otherUserId = 'user123'; final ImagePicker _picker = ImagePicker(); Future pickImageFromGallery() async { try { final image = await _picker.pickImage(source: ImageSource.gallery); if (image == null) return; final imageTemp = File(image.path); setState(() { AppSettings.updatedImage = imageTemp; }); // uploadProfileApi(AppSettings.updatedImage); AppSettings.saveProfile(image.path); } on PlatformException catch (e) { print('Failed to pick image: $e'); } } Future takeImageFromCamera() async { try { final image = await _picker.pickImage(source: ImageSource.camera); if (image == null) return; final imageTemp = File(image.path); setState(() { AppSettings.updatedImage = imageTemp; }); //uploadProfileApi(AppSettings.updatedImage); AppSettings.saveProfile(image.path); } on PlatformException catch (e) { print('Failed to pick image: $e'); } } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( backgroundColor: _connectionState == WebSocketConnectionState.error ? Colors.red : _connectionState == WebSocketConnectionState.closed ? Colors.red : Colors.green, elevation: 0, automaticallyImplyLeading: false, flexibleSpace: SafeArea( child: Container( padding: EdgeInsets.only(right: 16), child: Row( children: [ IconButton( onPressed: (){ Navigator.pop(context); }, icon: Icon(Icons.arrow_back,color: Colors.black,), ), SizedBox(width: 2,), CircleAvatar( backgroundImage: NetworkImage("https://ehealth.eletsonline.com/wp-content/uploads/2020/12/pharma-industry-in-2021.jpg"), maxRadius: 20, ), SizedBox(width: 12,), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.center, children: [ Text("Suresh",style: TextStyle( fontSize: 16 ,fontWeight: FontWeight.w600),), // SizedBox(height: 6,), // Text("Online",style: TextStyle(color: Colors.grey.shade600, fontSize: 13),), ], ), ), IconButton( onPressed: () { UrlLauncher.launch("tel://8328206298"); }, icon: Icon(Icons.call, color: Colors.black), ), IconButton( onPressed: () { Navigator.push( context, MaterialPageRoute( builder: (context) => IndexPage()), ); }, icon: Icon(Icons.videocam, color: Colors.black), ), ], ), ), ), ), body: Stack( children: [ ListView.builder( controller: _scrollController, itemCount: _messages.length, shrinkWrap: true, padding: EdgeInsets.only(top: 10,bottom: 60), itemBuilder: (context, index){ bool isSentByMe = _messages[index].senderId == myUserId; return Container( padding: EdgeInsets.only(left: 14,right: 14,top: 10,bottom: 10), child: Align( alignment: (isSentByMe?Alignment.topRight:Alignment.topLeft), child: Container( decoration: BoxDecoration( borderRadius: BorderRadius.circular(20), color: (isSentByMe?Colors.blue[200]:Colors.grey[200]), ), padding: EdgeInsets.symmetric(horizontal: 16,vertical: 10), child: Text(_messages[index].messageContent, style: TextStyle(fontSize: 15),), ), ), ); }, ), Align( alignment: Alignment.bottomLeft, child: Container( padding: EdgeInsets.only(left: 10, bottom: 10, top: 10), height: 60, width: double.infinity, color: Colors.white, child: Row( children: [ GestureDetector( onTap: () { showModalBottomSheet( context: context, builder: (BuildContext context) { return SizedBox( height: 200, child: Center( child: Row( mainAxisAlignment: MainAxisAlignment.center, children: [ GestureDetector( child: Icon( Icons.camera_alt_outlined, size: 100, color: greyColor, ), onTap: () async { await takeImageFromCamera(); Navigator.pop(context); }, ), SizedBox( width: MediaQuery.of(context).size.width * .20, ), GestureDetector( child: Icon( Icons.photo, size: 100, color: greyColor, ), onTap: () async { await pickImageFromGallery(); Navigator.pop(context); }, ), ], ), ), ); }); }, child: Container( height: 30, width: 30, decoration: BoxDecoration( color: Colors.lightBlue, borderRadius: BorderRadius.circular(30), ), child: Icon( Icons.add, color: Colors.white, size: 20, ), ), ), SizedBox( width: 15, ), Expanded( child: TextField( controller: _controller, decoration: InputDecoration( hintText: "Write message...", hintStyle: TextStyle(color: Colors.black54), border: InputBorder.none), ), ), SizedBox( width: 15, ), FloatingActionButton( onPressed: () { String newMessage = _controller.text; if (newMessage.isNotEmpty) { // Add the new message to the list setState(() { _sendMessage(); }); // Clear the text field _controller.clear(); } }, child: Icon( Icons.send, color: Colors.white, size: 18, ), backgroundColor: Colors.blue, elevation: 0, ), ], ), ), ), ], )); } void _sendMessage() { if (_controller.text.isNotEmpty) { var message = ChatMessage( senderId: myUserId, receiverId: otherUserId, messageType: 'text', messageContent: _controller.text, ); channel.sink.add(chatMessageToJson(message)); _messages.add(message); _controller.clear(); } } @override void initState() { super.initState(); // Initialize the WebSocket channel for call signaling callChannel = IOWebSocketChannel.connect( "wss://socketsbay.com/wss/v2/1/demo/call", // adjust the URL accordingly ); _scrollController = ScrollController(); channel.stream.listen((message) { if (message is String) { var receivedMessage = chatMessageFromJson(message); setState(() { _messages.add(receivedMessage); }); _scrollToBottom(); } }, onError: (error) { setState(() { _connectionState = WebSocketConnectionState.error; }); },onDone: (){ setState(() { _connectionState = WebSocketConnectionState.closed; }); },); } // ... existing code ... void startCall(String callId) { // Send a call initiation message to the other user var callMessage = { 'type': 'call', 'callId': callId, 'senderId': myUserId, 'receiverId': otherUserId, }; callChannel.sink.add(jsonEncode(callMessage)); // Update UI or perform other actions as needed // ... // For simplicity, let's assume the call is accepted after a short delay Future.delayed(Duration(seconds: 2), () { // Handle call accepted onCallAccepted(callId); }); } void onCallAccepted(String callId) { // Update UI or perform other actions as needed // ... // Send a call accepted message to the other user var acceptedMessage = { 'type': 'call_accepted', 'callId': callId, 'senderId': myUserId, 'receiverId': otherUserId, }; callChannel.sink.add(jsonEncode(acceptedMessage)); // Start the actual call // ... } void endCall(String callId) { // Send a call end message to the other user var endMessage = { 'type': 'call_end', 'callId': callId, 'senderId': myUserId, 'receiverId': otherUserId, }; callChannel.sink.add(jsonEncode(endMessage)); // Update UI or perform other actions as needed // ... // For simplicity, let's assume the call is ended immediately onCallEnded(callId); } void onCallEnded(String callId) { // Update UI or perform other actions as needed // ... // Close the call WebSocket channel callChannel.sink.close(); // For simplicity, let's assume the call ended immediately // ... } void _scrollToBottom() { // Scroll to the bottom of the list _scrollController.animateTo( _scrollController.position.maxScrollExtent, duration: Duration(milliseconds: 200), curve: Curves.easeOut, ); } @override void dispose() { channel.sink.close(); super.dispose(); } } enum WebSocketConnectionState { connecting, open, closing, closed, error }