diff --git a/lib/helpers/conversations_helper.dart b/lib/helpers/conversations_helper.dart index 812efed..ad28c08 100644 --- a/lib/helpers/conversations_helper.dart +++ b/lib/helpers/conversations_helper.dart @@ -320,6 +320,27 @@ class ConversationsHelper { return SendMessageResult.SUCCESS; } + /// Delete permanently a message specified by its [id] + Future deleteMessage(int id) async { + + // Delete the message online + final response = await APIRequest( + uri: "conversations/deleteMessage", + needLogin: true, + args: { + "messageID": id.toString() + } + ).exec(); + + if(response.code != 200) return false; + + + // Delete the message locally + return await _conversationMessagesDatabaseHelper.delete(id); + + } + + /// Turn an API response into a ConversationMessage object ConversationMessage _apiToConversationMessage({ @required int conversationID, diff --git a/lib/models/conversation_message.dart b/lib/models/conversation_message.dart index 00fa2e2..b31cddf 100644 --- a/lib/models/conversation_message.dart +++ b/lib/models/conversation_message.dart @@ -1,5 +1,6 @@ import 'package:comunic/helpers/database/database_contract.dart'; import 'package:comunic/models/cache_model.dart'; +import 'package:comunic/utils/account_utils.dart' as account; import 'package:meta/meta.dart'; /// Single conversation message @@ -33,6 +34,8 @@ class ConversationMessage extends CacheModel implements Comparable { bool get hasImage => imageURL != null && imageURL != "null"; + bool get isOwner => account.userID() == userID; + @override int compareTo(other) { return id.compareTo(other.id); diff --git a/lib/ui/screens/conversation_screen.dart b/lib/ui/screens/conversation_screen.dart index 98ee515..baff86f 100644 --- a/lib/ui/screens/conversation_screen.dart +++ b/lib/ui/screens/conversation_screen.dart @@ -4,6 +4,7 @@ import 'package:comunic/helpers/conversations_helper.dart'; import 'package:comunic/helpers/users_helper.dart'; import 'package:comunic/lists/conversation_messages_list.dart'; import 'package:comunic/lists/users_list.dart'; +import 'package:comunic/models/conversation_message.dart'; import 'package:comunic/models/new_conversation_message.dart'; import 'package:comunic/ui/tiles/conversation_message_tile.dart'; import 'package:comunic/ui/widgets/scroll_watcher.dart'; @@ -288,6 +289,7 @@ class _ConversationScreenState extends State { userInfo: _usersInfo.getUser(_messages[i].userID), isLastMessage: _isLastMessage(i), isFirstMessage: _isFirstMessage(i), + onRequestMessageDelete: _deleteMessage, ); }), ); @@ -386,4 +388,45 @@ class _ConversationScreenState extends State { ], ); } + + /// Request message deletion + Future _deleteMessage(ConversationMessage message) async { + final choice = await showDialog( + context: context, + builder: (c) => AlertDialog( + title: Text(tr("Confirm deletion")), + content: Text( + tr("Do you really want to delete this message ? The operation can not be cancelled !"), + textAlign: TextAlign.justify, + ), + actions: [ + FlatButton( + child: Text( + tr("Cancel").toUpperCase(), + ), + onPressed: () => Navigator.pop(c, false), + ), + FlatButton( + child: Text( + tr("Confirm").toUpperCase(), + style: TextStyle(color: Colors.red), + ), + onPressed: () => Navigator.pop(c, true), + ), + ], + ), + ); + + if(choice == null || !choice) + return; + + // Execute the request + if(!await _conversationsHelper.deleteMessage(message.id)) + showSimpleSnack(context, tr("Could not delete conversation message!")); + + // Remove the message from the list + setState(() { + _messages.remove(message); + }); + } } diff --git a/lib/ui/tiles/conversation_message_tile.dart b/lib/ui/tiles/conversation_message_tile.dart index fe66447..b58478a 100644 --- a/lib/ui/tiles/conversation_message_tile.dart +++ b/lib/ui/tiles/conversation_message_tile.dart @@ -3,8 +3,8 @@ import 'package:comunic/models/conversation_message.dart'; import 'package:comunic/models/user.dart'; import 'package:comunic/ui/widgets/account_image_widget.dart'; import 'package:comunic/ui/widgets/text_rich_content_widget.dart'; -import 'package:comunic/utils/account_utils.dart'; import 'package:comunic/utils/date_utils.dart'; +import 'package:comunic/utils/intl_utils.dart'; import 'package:comunic/utils/ui_utils.dart'; import 'package:flutter/material.dart'; @@ -12,31 +12,48 @@ import 'package:flutter/material.dart'; /// /// @author Pierre HUBERT +enum _MenuChoices { DELETE } + +typedef OnRequestMessageDelete = void Function(ConversationMessage); + class ConversationMessageTile extends StatelessWidget { final ConversationMessage message; final User userInfo; final bool isLastMessage; final bool isFirstMessage; + final OnRequestMessageDelete onRequestMessageDelete; - const ConversationMessageTile( - {Key key, - @required this.message, - @required this.userInfo, - @required this.isLastMessage, - @required this.isFirstMessage}) - : assert(message != null), + const ConversationMessageTile({ + Key key, + @required this.message, + @required this.userInfo, + @required this.isLastMessage, + @required this.isFirstMessage, + @required this.onRequestMessageDelete, + }) : assert(message != null), assert(userInfo != null), assert(isLastMessage != null), assert(isFirstMessage != null), + assert(onRequestMessageDelete != null), super(key: key); /// Build account image - Widget _buildAccountImage() { + Widget _buildAccountImage(BuildContext context) { return Container( margin: EdgeInsets.all(10.0), - child: AccountImageWidget( - user: userInfo, - width: 35.0, + child: PopupMenuButton<_MenuChoices>( + child: AccountImageWidget( + user: userInfo, + width: 35.0, + ), + itemBuilder: (c) => [ + PopupMenuItem( + enabled: message.isOwner, + value: _MenuChoices.DELETE, + child: Text(tr("Delete")), + ), + ], + onSelected: _menuOptionSelected, ), ); } @@ -141,7 +158,7 @@ class ConversationMessageTile extends StatelessWidget { ), // Account image - _buildAccountImage() + _buildAccountImage(context) ], ), @@ -180,7 +197,7 @@ class ConversationMessageTile extends StatelessWidget { Row( children: [ // Account image - _buildAccountImage(), + _buildAccountImage(context), Column( children: [ @@ -232,8 +249,19 @@ class ConversationMessageTile extends StatelessWidget { @override Widget build(BuildContext context) { - return userID() == message.userID + return message.isOwner ? _buildRightMessage(context) : _buildLeftMessage(context); } + + /// Process menu choice + void _menuOptionSelected(_MenuChoices value) { + + switch(value){ + case _MenuChoices.DELETE: + onRequestMessageDelete(message); + break; + } + + } }