1
0
mirror of https://gitlab.com/comunic/comunicmobile synced 2024-11-25 22:39:22 +00:00

Get conversation message

This commit is contained in:
Pierre HUBERT 2019-04-25 08:56:16 +02:00
parent 1ec197202c
commit e2202a4794
8 changed files with 245 additions and 14 deletions

View File

@ -1,9 +1,11 @@
import 'package:comunic/helpers/database/conversations_database_helper.dart'; import 'package:comunic/helpers/database/conversations_database_helper.dart';
import 'package:comunic/helpers/users_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/conversations_list.dart';
import 'package:comunic/lists/users_list.dart'; import 'package:comunic/lists/users_list.dart';
import 'package:comunic/models/api_request.dart'; import 'package:comunic/models/api_request.dart';
import 'package:comunic/models/conversation.dart'; import 'package:comunic/models/conversation.dart';
import 'package:comunic/models/conversation_message.dart';
import 'package:comunic/utils/account_utils.dart'; import 'package:comunic/utils/account_utils.dart';
/// Conversation helper /// Conversation helper
@ -67,7 +69,7 @@ class ConversationsHelper {
/// cached version of the conversation will be used, else it will always get /// cached version of the conversation will be used, else it will always get
/// the information from the server /// the information from the server
Future<Conversation> getSingle(int id, {bool force = false}) async { Future<Conversation> getSingle(int id, {bool force = false}) async {
if(force || ! await _conversationsDatabaseHelper.has(id)) if (force || !await _conversationsDatabaseHelper.has(id))
return await _downloadSingle(id); return await _downloadSingle(id);
else else
return _conversationsDatabaseHelper.get(id); return _conversationsDatabaseHelper.get(id);
@ -112,7 +114,7 @@ class ConversationsHelper {
} }
/// Turn an API entry into a [Conversation] object /// Turn an API entry into a [Conversation] object
Conversation _apiToConversation(Map<String, dynamic> map){ Conversation _apiToConversation(Map<String, dynamic> map) {
return Conversation( return Conversation(
id: map["ID"], id: map["ID"],
ownerID: map["ID_owner"], ownerID: map["ID_owner"],
@ -123,4 +125,35 @@ class ConversationsHelper {
members: map["members"].map<int>((f) => int.parse(f)).toList(), members: map["members"].map<int>((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<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();
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"],
userID: f["ID_user"],
timeInsert: f["time_insert"],
message: f["message"],
imageURL: f["image_path"]));
});
return list;
}
} }

View File

@ -0,0 +1,35 @@
import 'dart:collection';
import 'package:comunic/models/conversation_message.dart';
/// Conversations messages list
///
/// @author Pierre HUBERT
class ConversationMessagesList extends ListBase<ConversationMessage> {
final List<ConversationMessage> _list = List();
set length(int v) => _list.length = v;
int get length => _list.length;
@override
ConversationMessage operator [](int index) {
return _list[index];
}
@override
void operator []=(int index, ConversationMessage value) {
_list[index] = value;
}
/// Get the list of the users ID who own a message in this list
List<int> getUsersID() {
final List<int> users = List();
for (ConversationMessage message in this)
if (!users.contains(message.userID)) users.add(message.userID);
return users;
}
}

View File

@ -7,10 +7,10 @@ import 'package:comunic/models/user.dart';
/// @author Pierre HUBERT /// @author Pierre HUBERT
class UsersList extends ListBase<User> { class UsersList extends ListBase<User> {
List<User> _list = List(); List<User> _list = List();
int get length => _list.length; int get length => _list.length;
set length(l) => _list.length = l; set length(l) => _list.length = l;
@override @override
@ -24,11 +24,13 @@ class UsersList extends ListBase<User> {
} }
/// Find a user with a specific ID /// Find a user with a specific ID
User getUser(int userID){ User getUser(int userID) {
for(int i = 0; i < this.length; i++) for (int i = 0; i < this.length; i++)
if(this[i].id == userID) if (this[i].id == userID) return this[i];
return this[i];
throw "User not found in the list!"; throw "User not found in the list!";
} }
/// Get the list of users ID present in this list
List<int> get usersID => List.generate(length, (i) => this[i].id);
} }

View File

@ -0,0 +1,29 @@
import 'package:meta/meta.dart';
/// Single conversation message
///
/// @author Pierre HUBERT
class ConversationMessage implements Comparable {
final int id;
final int userID;
final int timeInsert;
final String message;
final String imageURL;
const ConversationMessage({
@required this.id,
@required this.userID,
@required this.timeInsert,
@required this.message,
@required this.imageURL,
}) : assert(id != null),
assert(userID != null),
assert(timeInsert != null),
assert(message != null);
@override
int compareTo(other) {
return id.compareTo(other.id);
}
}

View File

@ -1,5 +1,6 @@
import 'package:comunic/helpers/conversations_helper.dart'; import 'package:comunic/helpers/conversations_helper.dart';
import 'package:comunic/models/conversation.dart'; import 'package:comunic/models/conversation.dart';
import 'package:comunic/ui/screens/conversation_screen.dart';
import 'package:comunic/utils/intl_utils.dart'; import 'package:comunic/utils/intl_utils.dart';
import 'package:comunic/utils/ui_utils.dart'; import 'package:comunic/utils/ui_utils.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
@ -38,16 +39,14 @@ class _ConversationRouteState extends State<ConversationRoute> {
Future<void> _loadConversation() async { Future<void> _loadConversation() async {
setError(false); setError(false);
_conversation = _conversation = await _conversationsHelper.getSingle(widget.conversationID);
await _conversationsHelper.getSingle(widget.conversationID);
if (_conversation == null) return setError(true); if (_conversation == null) return setError(true);
final conversationName = final conversationName =
await ConversationsHelper.getConversationNameAsync(_conversation); await ConversationsHelper.getConversationNameAsync(_conversation);
if(conversationName == null) if (conversationName == null) return setError(true);
return setError(true);
setState(() { setState(() {
_conversationName = conversationName; _conversationName = conversationName;
@ -72,8 +71,12 @@ class _ConversationRouteState extends State<ConversationRoute> {
], ],
); );
//if (_conversationName == null || _conversation == null) if (_conversationName == null || _conversation == null)
return buildCenteredProgressBar(); return buildCenteredProgressBar();
return ConversationScreen(
conversationID: widget.conversationID,
);
} }
@override @override

View File

@ -0,0 +1,94 @@
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/ui/tiles/conversation_message_tile.dart';
import 'package:comunic/utils/intl_utils.dart';
import 'package:comunic/utils/list_utils.dart';
import 'package:comunic/utils/ui_utils.dart';
import 'package:flutter/material.dart';
/// Conversation screen
///
/// @author Pierre HUBERT
enum ErrorLevel { NONE, MINOR, MAJOR }
class ConversationScreen extends StatefulWidget {
final int conversationID;
const ConversationScreen({Key key, this.conversationID})
: assert(conversationID != null),
super(key: key);
@override
State<StatefulWidget> createState() => _ConversationScreenState();
}
class _ConversationScreenState extends State<ConversationScreen> {
final ConversationsHelper _conversationsHelper = ConversationsHelper();
final UsersHelper _usersHelper = UsersHelper();
ConversationMessagesList _messages;
UsersList _usersInfo = UsersList();
ErrorLevel _error = ErrorLevel.NONE;
@override
void didChangeDependencies() {
super.didChangeDependencies();
_loadMessages();
}
void _setError(ErrorLevel err) => setState(() => _error = err);
/// Method called when an error occurred while loading messages
void _errorLoading() {
_setError(_messages == null ? ErrorLevel.MAJOR : ErrorLevel.MINOR);
}
/// Load a list of messages
Future<void> _loadMessages() async {
//First, get the messages
final messages = await _conversationsHelper
.downloadNewMessagesSingle(widget.conversationID);
if (messages == null) return _errorLoading();
//Then get information about users
final usersToGet =
findMissingFromList(_usersInfo.usersID, messages.getUsersID());
final users = await _usersHelper.getUsersInfo(usersToGet);
if (users == null) _errorLoading();
// Save the new list of messages
setState(() {
_usersInfo.addAll(users);
if (_messages == null)
_messages = messages;
else
_messages.addAll(messages);
});
}
/// Error handling
Widget _buildError() {
return buildErrorCard(tr("Could not load the list of messages!"));
}
@override
Widget build(BuildContext context) {
if (_error == ErrorLevel.MAJOR) return _buildError();
if (_messages == null) return buildCenteredProgressBar();
return ListView.builder(
itemCount: _messages.length,
itemBuilder: (c, i) {
return ConversationMessageTile(
message: _messages.elementAt(i),
userInfo: _usersInfo.getUser(_messages[i].userID),
);
});
}
}

View File

@ -0,0 +1,22 @@
import 'package:comunic/models/conversation_message.dart';
import 'package:comunic/models/user.dart';
import 'package:flutter/material.dart';
/// Conversation message tile
///
/// @author Pierre HUBERT
class ConversationMessageTile extends StatelessWidget {
final ConversationMessage message;
final User userInfo;
const ConversationMessageTile({Key key, this.message, this.userInfo})
: assert(message != null),
assert(userInfo != null),
super(key: key);
@override
Widget build(BuildContext context) {
return Text(message.message);
}
}

View File

@ -12,3 +12,16 @@ List<int> listToIntList(List<dynamic> srcList){
return list; return list;
} }
/// Find the list of missing elements of a [testList] from a [srcList]
List<T> findMissingFromList<T>(List<T> srcList, List<T>testList) {
List<T> dest = List();
testList.forEach((f){
if(!srcList.contains(f) && !dest.contains(f))
dest.add(f);
});
return dest;
}