import 'package:comunic/helpers/serialization/base_serialization_helper.dart'; import 'package:comunic/lists/users_list.dart'; import 'package:comunic/models/displayed_content.dart'; import 'package:comunic/utils/account_utils.dart' as account; import 'package:comunic/utils/intl_utils.dart'; import 'package:flutter/material.dart'; import 'package:meta/meta.dart'; /// Single conversation message /// /// @author Pierre HUBERT enum ConversationMessageFileType { IMAGE, VIDEO, AUDIO, PDF, ZIP, OTHER, } const _ConversationFileMimeTypeMapping = { "image/jpeg": ConversationMessageFileType.IMAGE, "image/png": ConversationMessageFileType.IMAGE, "image/gif": ConversationMessageFileType.IMAGE, "video/mp4": ConversationMessageFileType.VIDEO, "audio/m4a": ConversationMessageFileType.AUDIO, "audio/mpeg": ConversationMessageFileType.AUDIO, "application/pdf": ConversationMessageFileType.PDF, "application/zip": ConversationMessageFileType.ZIP, }; class ConversationMessageFile { final String url; final int size; final String name; final String thumbnail; final String type; const ConversationMessageFile({ @required this.url, @required this.size, @required this.name, @required this.thumbnail, @required this.type, }) : assert(url != null), assert(size != null), assert(name != null), assert(type != null); /// Get the type of file ConversationMessageFileType get fileType { if (type != null && _ConversationFileMimeTypeMapping.containsKey(type)) return _ConversationFileMimeTypeMapping[type]; else return ConversationMessageFileType.OTHER; } /// Get the icon associated with file type IconData get icon { switch (fileType) { case ConversationMessageFileType.IMAGE: return Icons.image; case ConversationMessageFileType.VIDEO: return Icons.video_library; case ConversationMessageFileType.AUDIO: return Icons.audiotrack; case ConversationMessageFileType.PDF: return Icons.picture_as_pdf; case ConversationMessageFileType.ZIP: return Icons.archive; default: return Icons.insert_drive_file; } } bool get hasThumbnail => thumbnail != null; Map toJson() => { "url": url, "size": size, "name": name, "thumbnail": thumbnail, "type": type }; ConversationMessageFile.fromJson(Map json) : url = json["url"], size = json["size"], name = json["name"], thumbnail = json["thumbnail"], type = json["type"]; } enum ConversationServerMessageType { USER_CREATED_CONVERSATION, USER_ADDED_ANOTHER_USER, USER_LEFT_CONV, USER_REMOVED_ANOTHER_USER } class ConversationServerMessage { final ConversationServerMessageType type; final int userID; final int userWhoAdded; final int userAdded; final int userWhoRemoved; final int userRemoved; const ConversationServerMessage({ @required this.type, @required this.userID, @required this.userWhoAdded, @required this.userAdded, @required this.userWhoRemoved, @required this.userRemoved, }) : assert(type != null), assert(userID != null || (type != ConversationServerMessageType.USER_CREATED_CONVERSATION && type != ConversationServerMessageType.USER_LEFT_CONV)), assert((userWhoAdded != null && userAdded != null) || type != ConversationServerMessageType.USER_ADDED_ANOTHER_USER), assert((userWhoRemoved != null && userRemoved != null) || type != ConversationServerMessageType.USER_REMOVED_ANOTHER_USER); Set get usersID { switch (type) { case ConversationServerMessageType.USER_CREATED_CONVERSATION: case ConversationServerMessageType.USER_LEFT_CONV: return Set()..add(userID); case ConversationServerMessageType.USER_ADDED_ANOTHER_USER: return Set()..add(userWhoAdded)..add(userAdded); case ConversationServerMessageType.USER_REMOVED_ANOTHER_USER: return Set()..add(userWhoRemoved)..add(userRemoved); } throw Exception("Unsupported server message type!"); } String getText(UsersList list) { switch (type) { case ConversationServerMessageType.USER_CREATED_CONVERSATION: return tr("%1% created the conversation", args: {"1": list.getUser(userID).fullName}); case ConversationServerMessageType.USER_ADDED_ANOTHER_USER: return tr("%1% added %2% to the conversation", args: { "1": list.getUser(userWhoAdded).fullName, "2": list.getUser(userAdded).fullName, }); case ConversationServerMessageType.USER_LEFT_CONV: return tr("%1% left the conversation", args: { "1": list.getUser(userID).fullName, }); case ConversationServerMessageType.USER_REMOVED_ANOTHER_USER: return tr("%1% removed %2% from the conversation", args: { "1": list.getUser(userWhoRemoved).fullName, "2": list.getUser(userRemoved).fullName, }); } throw Exception("Unsupported message type!"); } Map toJson() => { "type": type.toString(), "userID": userID, "userWhoAdded": userWhoAdded, "userAdded": userAdded, "userWhoRemoved": userWhoRemoved, "userRemoved": userRemoved, }; ConversationServerMessage.fromJson(Map json) : type = ConversationServerMessageType.values .firstWhere((el) => el.toString() == json["type"]), userID = json["userID"], userWhoAdded = json["userWhoAdded"], userAdded = json["userAdded"], userWhoRemoved = json["userWhoRemoved"], userRemoved = json["userRemoved"]; } class ConversationMessage extends SerializableElement { final int id; final int convID; final int userID; final int timeSent; final DisplayedString message; final ConversationMessageFile file; final ConversationServerMessage serverMessage; ConversationMessage({ @required this.id, @required this.convID, @required this.userID, @required this.timeSent, @required this.message, @required this.file, @required this.serverMessage, }) : assert(id != null), assert(convID != null), assert(userID != null || serverMessage != null), assert(timeSent != null), assert(message != null || file != null || serverMessage != null); DateTime get date => DateTime.fromMillisecondsSinceEpoch(timeSent * 1000); bool get hasMessage => !message.isNull && message.length > 0; bool get hasFile => file != null; bool get isOwner => account.userID() == userID; bool get isServerMessage => serverMessage != null; /// Get the list of the ID of the users implied in this message Set get usersID { if (userID != null) return Set()..add(userID); return serverMessage.usersID; } @override int compareTo(ConversationMessage other) { return id.compareTo(other.id); } Map toJson() { return { "id": id, "convID": convID, "userID": userID, "timeSent": timeSent, "message": message.content, "file": file?.toJson(), "serverMessage": serverMessage?.toJson(), }; } ConversationMessage.fromJson(Map map) : id = map["id"], convID = map["convID"], userID = map["userID"], timeSent = map["timeSent"], message = DisplayedString(map["message"]), file = map["file"] == null ? null : ConversationMessageFile.fromJson(map["file"]), serverMessage = map["serverMessage"] == null ? null : ConversationServerMessage.fromJson(map["serverMessage"]); }