import 'dart:convert'; import 'package:flutter/material.dart'; import 'package:flutter_spinkit/flutter_spinkit.dart'; import 'package:image_picker/image_picker.dart'; import 'package:messaging_app/components/messaging_provider.dart'; import 'package:messaging_app/models/chats.dart'; import 'package:messaging_app/models/messages.dart'; import 'package:messaging_app/service/media_service.dart'; import 'package:messaging_app/service/snackbar_service.dart'; import 'package:provider/provider.dart'; import 'package:timeago/timeago.dart' as timeago; class ConversationsPage extends StatefulWidget { ConversationsPage({ super.key, required this.chatId, // required this.receiverId, required this.chatImage, required this.chatName, }); String chatId; // String receiverId; String chatName; String chatImage; @override State createState() { return _ConversationsPageState(); } } class _ConversationsPageState extends State { // late double _deviceHeight; late double _deviceWidth; final ScrollController _scrollController; final GlobalKey _formKey; late MessagingProviders _auth; List> _messagesArray; List _messages; List _members; int _memberPosition; String _messageText; _ConversationsPageState() : _messageText = '', _formKey = GlobalKey(), _scrollController = ScrollController(), _messagesArray = [], _messages = [], _members = [], _memberPosition = 0; @override Widget build(BuildContext context) { // _deviceHeight = MediaQuery.of(context).size.height; _deviceWidth = MediaQuery.of(context).size.width; return Scaffold( appBar: AppBar( backgroundColor: Theme.of(context).scaffoldBackgroundColor, title: Text(widget.chatName), titleTextStyle: TextStyle(fontSize: 16), ), body: ChangeNotifierProvider.value( value: MessagingProviders.instance, child: _conversationPageUI(), ), ); } Widget _conversationPageUI() { return Builder( builder: (_context) { _auth = Provider.of(_context); SnackBarService.instance.buildContext = _context; return Stack( clipBehavior: Clip.none, children: [ _messageListView(), _messageInputField(_context), ], ); }, ); } Widget _messageListView() { return Container( height: _deviceHeight * 0.80, width: _deviceWidth, child: StreamBuilder( stream: MessagingProviders.instance.getMessage(widget.chatId), builder: (_context, _snapshot) { if (_snapshot.hasData) { _members = _snapshot.data!.members; _memberPosition = _members.indexOf(_auth.user!.$id); _messages = _snapshot.data!.messages![_memberPosition]; _messagesArray = _snapshot.data!.messages!; } if (_snapshot.hasData) { if (_messages.isEmpty) { return Align( child: Text("No Chat"), ); } else { return ListView.builder( controller: _scrollController, padding: EdgeInsets.symmetric( horizontal: 10, vertical: 10, ), itemCount: _messages.length, itemBuilder: (BuildContext _context, int _index) { _messages[_index]; return _messageView(_messages, _index); }, ); } } else if (_snapshot.hasError) { return Align( child: Text("No Chat"), ); } else { return SpinKitWanderingCubes( color: Colors.blue, size: 50.0, ); } }, ), ); } Widget _messageView(List _messages, int _index) { bool _isOwnMessage = false; if (_messages[_index].senderId == _auth.user!.$id) { _isOwnMessage = true; } return Padding( padding: const EdgeInsets.only(bottom: 10), child: Row( crossAxisAlignment: CrossAxisAlignment.end, mainAxisAlignment: _isOwnMessage ? MainAxisAlignment.end : MainAxisAlignment.start, mainAxisSize: MainAxisSize.max, children: [ deleteButton(_isOwnMessage, _messages, _index), _isOwnMessage ? Container() : _imageViewBubble(), SizedBox( width: _deviceWidth * 0.01, ), _messages[_index].type == "text" ? _textMessageBubble(_isOwnMessage, _messages[_index]) : _imageMessageBubble(_isOwnMessage, _messages[_index]), deleteButton(!_isOwnMessage, _messages, _index), ], ), ); } Widget _textMessageBubble(bool _isOwnMessage, Messages _message) { List _colorScheme = _isOwnMessage ? [Colors.blue, Color.fromRGBO(42, 117, 188, 1)] : [Color.fromRGBO(49, 69, 69, 1), Color.fromRGBO(43, 43, 43, 1)]; return Container( // height: _deviceHeight * 0.10, width: _deviceWidth * 0.60, padding: EdgeInsets.symmetric(horizontal: 5, vertical: 5), decoration: BoxDecoration( borderRadius: BorderRadius.circular(15), gradient: LinearGradient( colors: _colorScheme, stops: [0.25, 0.85], begin: Alignment.bottomLeft, end: Alignment.bottomRight), ), child: Column( mainAxisAlignment: MainAxisAlignment.spaceAround, mainAxisSize: MainAxisSize.max, crossAxisAlignment: CrossAxisAlignment.start, children: [ Text(_message.message), SizedBox( height: 10, ), Text( timeago.format(DateTime.parse(_message.timeStamp)), style: TextStyle(color: Colors.white70, fontSize: 10), ), ], ), ); } Widget _imageMessageBubble(bool _isOwnMessage, Messages _message) { List _colorScheme = _isOwnMessage ? [Colors.blue, Color.fromRGBO(42, 117, 188, 1)] : [Color.fromRGBO(49, 69, 69, 1), Color.fromRGBO(43, 43, 43, 1)]; return Container( // height: _deviceHeight * 0.10, // width: _deviceWidth * 0.75, padding: EdgeInsets.symmetric(horizontal: 10, vertical: 10), decoration: BoxDecoration( borderRadius: BorderRadius.circular(15), gradient: LinearGradient( colors: _colorScheme, stops: [0.25, 0.85], begin: Alignment.bottomLeft, end: Alignment.bottomRight), ), child: Column( mainAxisAlignment: MainAxisAlignment.spaceAround, mainAxisSize: MainAxisSize.max, crossAxisAlignment: CrossAxisAlignment.start, children: [ Container( height: _deviceHeight * 0.30, width: _deviceWidth * 0.40, decoration: BoxDecoration( borderRadius: BorderRadius.circular(10), image: DecorationImage( image: NetworkImage(_message.message), fit: BoxFit.cover, ), ), ), SizedBox( height: 10, ), Text( timeago.format(DateTime.parse(_message.timeStamp)), style: TextStyle(color: Colors.white70, fontSize: 10), ), ], ), ); } Widget _imageViewBubble() { return Container( height: _deviceHeight * 0.05, width: _deviceHeight * 0.05, decoration: BoxDecoration( borderRadius: BorderRadius.circular(500), image: DecorationImage( fit: BoxFit.cover, image: NetworkImage( widget.chatImage, ), ), ), ); } Widget _messageInputField(BuildContext _context) { return Align( alignment: Alignment.bottomCenter, child: Form( key: _formKey, child: Row( crossAxisAlignment: CrossAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.start, mainAxisSize: MainAxisSize.max, children: [ _messageInput(), _sendImage(), _sendText(_context), ], ), ), ); } Widget _messageInput() { return Container( padding: EdgeInsets.only(left: 10, right: 10), decoration: BoxDecoration( color: Color.fromRGBO(43, 43, 43, 1), borderRadius: BorderRadius.circular(30)), margin: EdgeInsets.symmetric( horizontal: _deviceWidth * 0.04, vertical: _deviceHeight * 0.02, ), width: _deviceWidth * 0.70, child: TextFormField( maxLines: null, validator: (_input) { if (_input!.isEmpty) { SnackBarService.instance .showSnackBarError("please enter a message"); } return null; }, onChanged: (_input) { _formKey.currentState?.save(); }, onSaved: (_input) { setState(() { _messageText = _input!; }); }, cursorColor: Colors.white, decoration: InputDecoration( border: InputBorder.none, hintText: "type a message", ), autocorrect: false, ), ); } Widget _sendText(BuildContext _context) { return Container( height: _deviceHeight * 0.045, width: _deviceHeight * 0.045, child: IconButton( onPressed: () async { if (_formKey.currentState!.validate()) { if (_messageText.isNotEmpty) { // await sendMessage('text', _messageText); _formKey.currentState?.reset(); FocusScope.of(_context).unfocus(); } } }, icon: Icon( Icons.send, color: Colors.white, ), ), ); } Widget _sendImage() { return SizedBox( height: _deviceHeight * 0.045, width: _deviceHeight * 0.045, child: FloatingActionButton( onPressed: () async { XFile? _imageFile = await MediaService.instance.getImageFromLibrary(); if (_imageFile != null) { var _url = await MessagingProviders.instance .uploadUserImage(_imageFile, '_uid'); await sendMessage('image', _url); } }, backgroundColor: Colors.blue, child: Icon( Icons.camera_enhance, ), ), ); } Widget deleteButton( bool _isOwnMessage, List _messages, int _index) { return !_isOwnMessage ? SizedBox() : Row( children: [ IconButton( icon: const Icon( Icons.delete, size: 15, ), onPressed: () async { List outMessages = []; _messages.removeAt(_index); _messagesArray[_memberPosition] = _messages; for (var i = 0; i < _messagesArray.length; i++) { outMessages.add( json.encode( {_members[i]: _messagesArray[i]}, ), ); } await _auth.sendMessage( widget.chatId, {"messages": outMessages}, ); }, ), ], ); } Future sendMessage(var type, var _message) async { List outMessages = []; for (var i = 0; i < _members.length; i++) { _messagesArray[i].add( Messages( message: _message, senderId: _auth.user!.$id, type: type, timeStamp: DateTime.now().toUtc().toString(), ), ); outMessages.add( json.encode( {_members[i]: _messagesArray[i]}, ), ); } await _auth.sendMessage( widget.chatId, {"messages": outMessages}, ); } }