1
0
mirror of https://gitlab.com/comunic/comunicmobile synced 2024-11-29 16:26:27 +00:00
comunicmobile/lib/helpers/conversations_helper.dart

315 lines
10 KiB
Dart

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();
/// Create a new conversation
///
/// Return the ID of the newly created conversation or -1 in case of failure
Future<int> createConversation(Conversation settings) async {
final response =
await APIRequest(uri: "conversations/create", needLogin: true, args: {
"name": settings.hasName ? settings.name : "false",
"follow": settings.following ? "true" : "false",
"users": settings.members.join(",")
}).exec();
if (response.code != 200) return -1;
return response.getObject()["conversationID"];
}
/// Update an existing conversation
///
/// Returns a boolean depending of the success of the operation
Future<bool> updateConversation(Conversation settings) async {
final request =
APIRequest(uri: "conversations/updateSettings", needLogin: true, args: {
"conversationID": settings.id.toString(),
"following": settings.following ? "true" : "false"
});
// Update all conversation settings, if possible
if (settings.isOwner) {
request.addString("name", settings.hasName ? settings.name : "false");
request.addString("members", settings.members.join(","));
}
final response = await request.exec();
if(response.code != 200)
return false;
//Delete old conversation entry from the database
await _conversationsDatabaseHelper.delete(settings.id);
// Success
return true;
}
/// Delete a conversation specified by its [id]
Future<bool> deleteConversation(int id) async {
final response = await APIRequest(
uri: "conversations/delete",
needLogin: true,
args: {
"conversationID": id.toString(),
},
).exec();
return response.code == 200;
}
/// Download the list of conversations from the server
Future<ConversationsList> 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<ConversationsList> getCachedList() async {
final list = await _conversationsDatabaseHelper.getAll();
list.sort();
return list;
}
/// Get information about a single conversation specified by its [id]
Future<Conversation> _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<Conversation> 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<String> 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<String, dynamic> 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<int>((f) => int.parse(f)).toList(),
);
}
/// Parse a list of messages given by the server
Future<ConversationMessagesList> _parseConversationMessageFromServer(
int conversationID, APIResponse response) async {
if (response.code != 200) return null;
// Parse the response of the server
ConversationMessagesList list = ConversationMessagesList();
response.getArray().forEach((f) {
list.add(
_apiToConversationMessage(
conversationID: conversationID,
map: f,
),
);
});
// Save messages in the cache
_conversationMessagesDatabaseHelper.insertOrUpdateAll(list);
return list;
}
/// 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<ConversationMessagesList> _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();
return await _parseConversationMessageFromServer(conversationID, response);
}
/// Get older messages for a given conversation from an online source
Future<ConversationMessagesList> getOlderMessages({
@required int conversationID,
@required int oldestMessagesID,
int limit = 15,
}) async {
// Perform the request online
final response = await APIRequest(
uri: "conversations/get_older_messages",
needLogin: true,
args: {
"conversationID": conversationID.toString(),
"oldest_message_id": oldestMessagesID.toString(),
"limit": limit.toString()
}).exec();
return await _parseConversationMessageFromServer(conversationID, response);
}
/// 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<ConversationMessagesList> 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<SendMessageResult> 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;
}
/// Turn an API response into a ConversationMessage object
ConversationMessage _apiToConversationMessage({
@required int conversationID,
@required Map<String, dynamic> map,
}) {
return ConversationMessage(
id: map["ID"],
conversationID: conversationID,
userID: map["ID_user"],
timeInsert: map["time_insert"],
message: map["message"],
imageURL: map["image_path"],
);
}
}