remove avatar indicators in group chats

This commit is contained in:
otsmr 2026-03-01 13:58:33 +01:00
parent 2cf9e575e9
commit ca62069652
2 changed files with 2 additions and 88 deletions

View file

@ -342,38 +342,6 @@ class MessagesDao extends DatabaseAccessor<TwonlyDB> with _$MessagesDaoMixin {
.getSingleOrNull(); .getSingleOrNull();
} }
Stream<Future<List<(Message, Contact)>>> watchLastOpenedMessagePerContact(
String groupId,
) {
const sql = '''
SELECT m.*, c.*
FROM (
SELECT ma.contact_id, ma.message_id,
ROW_NUMBER() OVER (PARTITION BY ma.contact_id
ORDER BY ma.action_at DESC, ma.message_id DESC) AS rn
FROM message_actions ma
WHERE ma.type = 'openedAt'
) last_open
JOIN messages m ON m.message_id = last_open.message_id
JOIN contacts c ON c.user_id = last_open.contact_id
WHERE last_open.rn = 1 AND m.group_id = ?;
''';
return customSelect(
sql,
variables: [Variable.withString(groupId)],
readsFrom: {messages, messageActions, contacts},
).watch().map((rows) async {
final res = <(Message, Contact)>[];
for (final row in rows) {
final message = await messages.mapFromRow(row);
final contact = await contacts.mapFromRow(row);
res.add((message, contact));
}
return res;
});
}
Future<void> deleteMessagesById(String messageId) { Future<void> deleteMessagesById(String messageId) {
return (delete(messages)..where((t) => t.messageId.equals(messageId))).go(); return (delete(messages)..where((t) => t.messageId.equals(messageId))).go();
} }

View file

@ -33,7 +33,6 @@ class ChatItem {
const ChatItem._({ const ChatItem._({
this.message, this.message,
this.date, this.date,
this.lastOpenedPosition,
this.groupAction, this.groupAction,
}); });
factory ChatItem.date(DateTime date) { factory ChatItem.date(DateTime date) {
@ -42,20 +41,15 @@ class ChatItem {
factory ChatItem.message(Message message) { factory ChatItem.message(Message message) {
return ChatItem._(message: message); return ChatItem._(message: message);
} }
factory ChatItem.lastOpenedPosition(List<Contact> contacts) {
return ChatItem._(lastOpenedPosition: contacts);
}
factory ChatItem.groupAction(GroupHistory groupAction) { factory ChatItem.groupAction(GroupHistory groupAction) {
return ChatItem._(groupAction: groupAction); return ChatItem._(groupAction: groupAction);
} }
final GroupHistory? groupAction; final GroupHistory? groupAction;
final Message? message; final Message? message;
final DateTime? date; final DateTime? date;
final List<Contact>? lastOpenedPosition;
bool get isMessage => message != null; bool get isMessage => message != null;
bool get isDate => date != null; bool get isDate => date != null;
bool get isGroupAction => groupAction != null; bool get isGroupAction => groupAction != null;
bool get isLastOpenedPosition => lastOpenedPosition != null;
} }
/// Displays detailed information about a SampleItem. /// Displays detailed information about a SampleItem.
@ -75,14 +69,11 @@ class _ChatMessagesViewState extends State<ChatMessagesView> {
late StreamSubscription<List<Message>> messageSub; late StreamSubscription<List<Message>> messageSub;
StreamSubscription<List<GroupHistory>>? groupActionsSub; StreamSubscription<List<GroupHistory>>? groupActionsSub;
StreamSubscription<List<Contact>>? contactSub; StreamSubscription<List<Contact>>? contactSub;
StreamSubscription<Future<List<(Message, Contact)>>>?
lastOpenedMessageByContactSub;
Map<int, Contact> userIdToContact = {}; Map<int, Contact> userIdToContact = {};
List<ChatItem> messages = []; List<ChatItem> messages = [];
List<Message> allMessages = []; List<Message> allMessages = [];
List<(Message, Contact)> lastOpenedMessageByContact = [];
List<GroupHistory> groupActions = []; List<GroupHistory> groupActions = [];
List<MemoryItem> galleryItems = []; List<MemoryItem> galleryItems = [];
Message? quotesMessage; Message? quotesMessage;
@ -105,7 +96,6 @@ class _ChatMessagesViewState extends State<ChatMessagesView> {
messageSub.cancel(); messageSub.cancel();
contactSub?.cancel(); contactSub?.cancel();
groupActionsSub?.cancel(); groupActionsSub?.cancel();
lastOpenedMessageByContactSub?.cancel();
super.dispose(); super.dispose();
} }
@ -121,19 +111,10 @@ class _ChatMessagesViewState extends State<ChatMessagesView> {
}); });
if (!widget.group.isDirectChat) { if (!widget.group.isDirectChat) {
final lastOpenedStream =
twonlyDB.messagesDao.watchLastOpenedMessagePerContact(group.groupId);
lastOpenedMessageByContactSub =
lastOpenedStream.listen((lastActionsFuture) async {
final update = await lastActionsFuture;
lastOpenedMessageByContact = update;
await setMessages(allMessages, update, groupActions);
});
final actionsStream = twonlyDB.groupsDao.watchGroupActions(group.groupId); final actionsStream = twonlyDB.groupsDao.watchGroupActions(group.groupId);
groupActionsSub = actionsStream.listen((update) async { groupActionsSub = actionsStream.listen((update) async {
groupActions = update; groupActions = update;
await setMessages(allMessages, lastOpenedMessageByContact, update); await setMessages(allMessages, update);
}); });
final contactsStream = twonlyDB.contactsDao.watchAllContacts(); final contactsStream = twonlyDB.contactsDao.watchAllContacts();
@ -154,14 +135,13 @@ class _ChatMessagesViewState extends State<ChatMessagesView> {
// return; // return;
} }
await protectMessageUpdating.protect(() async { await protectMessageUpdating.protect(() async {
await setMessages(update, lastOpenedMessageByContact, groupActions); await setMessages(update, groupActions);
}); });
}); });
} }
Future<void> setMessages( Future<void> setMessages(
List<Message> newMessages, List<Message> newMessages,
List<(Message, Contact)> lastOpenedMessageByContact,
List<GroupHistory> groupActions, List<GroupHistory> groupActions,
) async { ) async {
await flutterLocalNotificationsPlugin.cancelAll(); await flutterLocalNotificationsPlugin.cancelAll();
@ -172,19 +152,7 @@ class _ChatMessagesViewState extends State<ChatMessagesView> {
DateTime? lastDate; DateTime? lastDate;
final openedMessages = <int, List<String>>{}; final openedMessages = <int, List<String>>{};
final lastOpenedMessageToContact = <String, List<Contact>>{};
final myLastMessageIndex =
newMessages.lastIndexWhere((t) => t.senderId == null);
for (final opened in lastOpenedMessageByContact) {
if (!lastOpenedMessageToContact.containsKey(opened.$1.messageId)) {
lastOpenedMessageToContact[opened.$1.messageId] = [opened.$2];
} else {
lastOpenedMessageToContact[opened.$1.messageId]!.add(opened.$2);
}
}
var index = 0;
var groupHistoryIndex = 0; var groupHistoryIndex = 0;
for (final msg in newMessages) { for (final msg in newMessages) {
@ -199,7 +167,6 @@ class _ChatMessagesViewState extends State<ChatMessagesView> {
} }
} }
} }
index += 1;
if (msg.type != MessageType.media.name && if (msg.type != MessageType.media.name &&
msg.senderId != null && msg.senderId != null &&
msg.openedAt == null) { msg.openedAt == null) {
@ -221,16 +188,6 @@ class _ChatMessagesViewState extends State<ChatMessagesView> {
lastDate = msg.createdAt; lastDate = msg.createdAt;
} }
chatItems.add(ChatItem.message(msg)); chatItems.add(ChatItem.message(msg));
if (index <= myLastMessageIndex || index == newMessages.length) {
if (lastOpenedMessageToContact.containsKey(msg.messageId)) {
chatItems.add(
ChatItem.lastOpenedPosition(
lastOpenedMessageToContact[msg.messageId]!,
),
);
}
}
} }
if (groupHistoryIndex < groupActions.length) { if (groupHistoryIndex < groupActions.length) {
for (var i = groupHistoryIndex; i < groupActions.length; i++) { for (var i = groupHistoryIndex; i < groupActions.length; i++) {
@ -341,17 +298,6 @@ class _ChatMessagesViewState extends State<ChatMessagesView> {
return ChatDateChip( return ChatDateChip(
item: messages[i], item: messages[i],
); );
} else if (messages[i].isLastOpenedPosition) {
return Wrap(
spacing: 8,
alignment: WrapAlignment.center,
children: messages[i].lastOpenedPosition!.map((w) {
return AvatarIcon(
contactId: w.userId,
fontSize: 12,
);
}).toList(),
);
} else if (messages[i].isGroupAction) { } else if (messages[i].isGroupAction) {
return ChatGroupAction( return ChatGroupAction(
key: Key(messages[i].groupAction!.groupHistoryId), key: Key(messages[i].groupAction!.groupHistoryId),