import 'package:Envelope/components/view_image.dart'; import 'package:Envelope/models/image_message.dart'; import 'package:Envelope/models/my_profile.dart'; import 'package:Envelope/utils/time.dart'; import 'package:flutter/material.dart'; import '/models/messages.dart'; @immutable class ConversationMessage extends StatefulWidget { const ConversationMessage({ Key? key, required this.message, required this.profile, required this.index, }) : super(key: key); final Message message; final MyProfile profile; final int index; @override _ConversationMessageState createState() => _ConversationMessageState(); } class _ConversationMessageState extends State { List> menuItems = []; Offset? _tapPosition; bool showDownloadButton = false; bool showDeleteButton = false; @override void initState() { super.initState(); showDownloadButton = widget.message.runtimeType == ImageMessage; showDeleteButton = widget.message.senderId == widget.profile.id; if (showDownloadButton) { menuItems.add(PopupMenuItem( value: 'download', child: Row( children: const [ Icon(Icons.download), SizedBox( width: 10, ), Text('Download') ], ), )); } if (showDeleteButton) { menuItems.add(PopupMenuItem( value: 'delete', child: Row( children: const [ Icon(Icons.delete), SizedBox( width: 10, ), Text('Delete') ], ), )); } setState(() {}); } @override Widget build(BuildContext context) { return Container( padding: const EdgeInsets.only(left: 14,right: 14,top: 0,bottom: 0), child: Align( alignment: ( widget.message.senderId == widget.profile.id ? Alignment.topRight : Alignment.topLeft ), child: Column( crossAxisAlignment: widget.message.senderId == widget.profile.id ? CrossAxisAlignment.end : CrossAxisAlignment.start, children: [ messageContent(context), const SizedBox(height: 1.5), Row( mainAxisAlignment: widget.message.senderId == widget.profile.id ? MainAxisAlignment.end : MainAxisAlignment.start, children: [ const SizedBox(width: 10), usernameOrFailedToSend(), ], ), const SizedBox(height: 1.5), Row( mainAxisAlignment: widget.message.senderId == widget.profile.id ? MainAxisAlignment.end : MainAxisAlignment.start, children: [ const SizedBox(width: 10), Text( convertToAgo(widget.message.createdAt), textAlign: widget.message.senderId == widget.profile.id ? TextAlign.left : TextAlign.right, style: TextStyle( fontSize: 12, color: Colors.grey[500], ), ), ], ), widget.index != 0 ? const SizedBox(height: 20) : const SizedBox.shrink(), ], ) ), ); } void _showCustomMenu() { final Size overlay = MediaQuery.of(context).size; int addVerticalOffset = 75 * menuItems.length; // TODO: Implement download & delete methods showMenu( context: context, items: menuItems, position: RelativeRect.fromRect( Offset(_tapPosition!.dx, (_tapPosition!.dy - addVerticalOffset)) & const Size(40, 40), Offset.zero & overlay ) ) .then((String? delta) async { if (delta == null) { return; } print(delta); }); } void _storePosition(TapDownDetails details) { _tapPosition = details.globalPosition; } Widget messageContent(BuildContext context) { if (widget.message.runtimeType == ImageMessage) { return GestureDetector( onTap: () { Navigator.push(context, MaterialPageRoute(builder: (context) { return ViewImage( message: (widget.message as ImageMessage) ); })); }, onLongPress: _showCustomMenu, onTapDown: _storePosition, child: ConstrainedBox( constraints: const BoxConstraints(maxHeight: 350, maxWidth: 250), child: ClipRRect( borderRadius: BorderRadius.circular(20), child: Image.file( (widget.message as ImageMessage).file, fit: BoxFit.fill, ), ), ), ); } return GestureDetector( onLongPress: _showCustomMenu, onTapDown: _storePosition, child: Container( decoration: BoxDecoration( borderRadius: BorderRadius.circular(20), color: ( widget.message.senderId == widget.profile.id ? Theme.of(context).colorScheme.primary : Theme.of(context).colorScheme.tertiary ), ), padding: const EdgeInsets.all(12), child: Text( widget.message.getContent(), style: TextStyle( fontSize: 15, color: widget.message.senderId == widget.profile.id ? Theme.of(context).colorScheme.onPrimary : Theme.of(context).colorScheme.onTertiary, ), ), ), ); } Widget usernameOrFailedToSend() { if (widget.message.senderId != widget.profile.id) { return Text( widget.message.senderUsername, style: TextStyle( fontSize: 12, color: Colors.grey[300], ), ); } if (widget.message.failedToSend) { return Row( mainAxisAlignment: MainAxisAlignment.end, children: const [ Icon( Icons.warning_rounded, color: Colors.red, size: 20, ), Text( 'Failed to send', style: TextStyle(color: Colors.red, fontSize: 12), textAlign: TextAlign.right, ), ], ); } return const SizedBox.shrink(); } }