import 'package:comunic/helpers/database/conversation_messages_database_helper.dart'; import 'package:comunic/helpers/database/conversations_database_helper.dart'; import 'package:comunic/helpers/users_helper.dart'; import 'package:comunic/lists/conversation_messages_list.dart'; import 'package:comunic/lists/conversations_list.dart'; import 'package:comunic/lists/users_list.dart'; import 'package:comunic/models/api_request.dart'; import 'package:comunic/models/api_response.dart'; import 'package:comunic/models/conversation.dart'; import 'package:comunic/models/conversation_message.dart'; import 'package:comunic/models/new_conversation_message.dart'; import 'package:comunic/utils/account_utils.dart'; import 'package:meta/meta.dart'; /// Conversation helper /// /// @author Pierre HUBERT enum SendMessageResult { SUCCESS, MESSAGE_REJECTED, FAILED } class ConversationsHelper { final ConversationsDatabaseHelper _conversationsDatabaseHelper = ConversationsDatabaseHelper(); final ConversationMessagesDatabaseHelper _conversationMessagesDatabaseHelper = ConversationMessagesDatabaseHelper(); /// Download the list of conversations from the server Future downloadList() async { final response = await APIRequest(uri: "conversations/getList", needLogin: true).exec(); if (response.code != 200) return null; try { ConversationsList list = ConversationsList(); response.getArray().forEach((f) => list.add(_apiToConversation(f))); // Update the database await _conversationsDatabaseHelper.clearTable(); await _conversationsDatabaseHelper.insertAll(list); return list; } on Exception catch (e) { print(e.toString()); return null; } } /// Get the local list of conversations Future getCachedList() async { final list = await _conversationsDatabaseHelper.getAll(); list.sort(); return list; } /// Get information about a single conversation specified by its [id] Future _downloadSingle(int id) async { try { final response = await APIRequest( uri: "conversations/getInfoOne", needLogin: true, args: {"conversationID": id.toString()}).exec(); if (response.code != 200) return null; final conversation = _apiToConversation(response.getObject()); _conversationsDatabaseHelper.insertOrUpdate(conversation); return conversation; } on Exception catch (e) { print(e.toString()); print("Could not get information about a single conversation !"); return null; } } /// Get information about a single conversation. If [force] is set to false, /// cached version of the conversation will be used, else it will always get /// the information from the server Future getSingle(int id, {bool force = false}) async { if (force || !await _conversationsDatabaseHelper.has(id)) return await _downloadSingle(id); else return _conversationsDatabaseHelper.get(id); } /// Get the name of a [conversation]. This requires information /// about the users of this conversation static String getConversationName( Conversation conversation, UsersList users) { if (conversation.hasName) return conversation.name; String name = ""; int count = 0; for (int i = 0; i < 3 && i < conversation.members.length; i++) if (conversation.members[i] != userID()) { name += (count > 0 ? ", " : "") + users.getUser(conversation.members[i]).fullName; count++; } if (conversation.members.length > 3) name += ", ..."; return name; } /// Asynchronously get the name fo the conversation /// /// Unlike the synchronous method, this method does not need information /// about the members of the conversation /// /// Returns null in case of failure static Future getConversationNameAsync( Conversation conversation) async { if (conversation.hasName) return conversation.name; //Get information about the members of the conversation final members = await UsersHelper().getUsersInfo(conversation.members); if (members == null) return null; return ConversationsHelper.getConversationName(conversation, members); } /// Turn an API entry into a [Conversation] object Conversation _apiToConversation(Map map) { return Conversation( id: map["ID"], ownerID: map["ID_owner"], lastActive: map["last_active"], name: map["name"] == false ? null : map["name"], following: map["following"] == 1, sawLastMessage: map["saw_last_message"] == 1, members: map["members"].map((f) => int.parse(f)).toList(), ); } /// Refresh the list of messages of a conversation /// /// Set [lastMessageID] to 0 to specify that we do not have any message of the /// conversation yet or another value else Future _downloadNewMessagesSingle( int conversationID, {int lastMessageID = 0}) async { // Execute the request on the server final response = await APIRequest( uri: "conversations/refresh_single", needLogin: true, args: { "conversationID": conversationID.toString(), "last_message_id": lastMessageID.toString() }).exec(); if (response.code != 200) return null; // Parse the response of the server ConversationMessagesList list = ConversationMessagesList(); response.getArray().forEach((f) { list.add(ConversationMessage( id: f["ID"], conversationID: conversationID, userID: f["ID_user"], timeInsert: f["time_insert"], message: f["message"], imageURL: f["image_path"])); }); // Save messages in the cache _conversationMessagesDatabaseHelper.insertOrUpdateAll(list); return list; } /// Get new messages for a given conversation /// /// If [lastMessageID] is set to 0 then we retrieve the last messages of /// the conversation. /// Otherwise [lastMessageID] contains the ID of the last known message Future getNewMessages( {@required int conversationID, int lastMessageID = 0, bool online = true}) async { if (online) return await _downloadNewMessagesSingle(conversationID, lastMessageID: lastMessageID); else return await _conversationMessagesDatabaseHelper .getAllMessagesConversations(conversationID, lastMessageID: lastMessageID); } /// Send a new message to the server Future sendMessage(NewConversationMessage message) async { final request = APIRequest( uri: "conversations/sendMessage", needLogin: true, args: { "conversationID": message.conversationID.toString(), "message": message.hasMessage ? message.message : "" }, ); //Check for image if (message.hasImage) request.addFile("image", message.image); //Send the message APIResponse response; if (!message.hasImage) response = await request.exec(); else response = await request.execWithFiles(); if (response.code == 401) return SendMessageResult.MESSAGE_REJECTED; else if (response.code != 200) return SendMessageResult.FAILED; return SendMessageResult.SUCCESS; } }