import "package:collection/collection.dart"; import "package:flutter_chat_core/flutter_chat_core.dart"; import "package:flutter_chat_core/flutter_chat_core.dart" as chat; import "package:flutter_riverpod/flutter_riverpod.dart"; import "package:matrix/matrix.dart"; import "package:nexus/controllers/events_controller.dart"; import "package:nexus/helpers/extension_helper.dart"; class RoomChatController extends AsyncNotifier { final Room room; RoomChatController(this.room); @override Future build() async { final response = await ref.watch(EventsController.provider(room).future); ref.onDispose( room.client.onTimelineEvent.stream.listen((event) async { if (event.roomId != room.id) return; final message = await event.toMessage(); if (message != null) { if (event.relationshipType == RelationshipTypes.edit) { final controller = await future; final oldMessage = controller.messages.firstWhereOrNull( (element) => element.id == event.relationshipEventId, ); if (oldMessage == null) return; await updateMessage(oldMessage, message); } else { await insertMessage(message); } } }).cancel, ); return InMemoryChatController( messages: { for (var msg in (await Future.wait( response.chunk.map( (event) => Event.fromMatrixEvent(event, room).toMessage(), ), )).nonNulls.toList().reversed.toList()) msg.id: msg, }.values.toList(), ); } Future insertMessage(Message message) async { final controller = await future; final oldMessage = message.metadata?["txnId"] == null ? null : controller.messages.firstWhereOrNull( (element) => element.metadata?["txnId"] == message.metadata?["txnId"], ); return oldMessage == null ? controller.insertMessage(message) : controller.updateMessage(oldMessage, message); } Future loadOlder() async { final controller = await future; final response = await ref .watch(EventsController.provider(room).notifier) .prev(); await controller.insertAllMessages( (await Future.wait( response.chunk.map( (event) => Event.fromMatrixEvent(event, room).toMessage(), ), )).nonNulls.toList().reversed.toList(), index: 0, ); } Future markRead() async { final controller = await future; final id = controller.messages.last.id; await room.setReadMarker(id, mRead: id); } Future updateMessage(Message message, Message newMessage) async => (await future).updateMessage(message, newMessage); Future send(String message, {Message? replyTo}) async => await room.sendTextEvent( message, inReplyTo: replyTo == null ? null : await room.getEventById(replyTo.id), ); Future resolveUser(String id) async { final user = await room.client.getUserProfile(id); return chat.User( id: id, name: user.displayname, imageSource: (await user.avatarUrl?.getThumbnailUri( // TODO: Fix use of account avatar not room avatar room.client, width: 24, height: 24, ))?.toString(), ); } static final provider = AsyncNotifierProvider.family .autoDispose( RoomChatController.new, ); }