part of '../neon_spreed.dart'; abstract class SpreedRoomBlocEvents { void loadMoreMessages(); void sendMessage(final String message); Future leaveRoom(); } abstract class SpreedRoomBlocStates { BehaviorSubject> get room; BehaviorSubject>> get messages; BehaviorSubject get allLoaded; BehaviorSubject get sendingMessage; BehaviorSubject get lastCommonReadMessageId; } class SpreedRoomBloc extends InteractiveBloc implements SpreedRoomBlocEvents, SpreedRoomBlocStates { SpreedRoomBloc( this.options, this.account, final spreed.Room r, ) { roomToken = r.token; room.add(Result.success(r)); unawaited(refresh()); } final SpreedAppSpecificOptions options; final Account account; late final String roomToken; final _limit = 100; int? _lastKnownMessageId; @override void dispose() { unawaited(room.close()); unawaited(messages.close()); unawaited(allLoaded.close()); unawaited(sendingMessage.close()); unawaited(lastCommonReadMessageId.close()); super.dispose(); } @override BehaviorSubject allLoaded = BehaviorSubject.seeded(false); @override BehaviorSubject lastCommonReadMessageId = BehaviorSubject.seeded(null); @override BehaviorSubject>> messages = BehaviorSubject(); @override BehaviorSubject> room = BehaviorSubject(); @override BehaviorSubject sendingMessage = BehaviorSubject.seeded(null); @override Future refresh() async { await RequestManager.instance.wrapNextcloud( account.id, 'spreed-room-$roomToken', room, account.client.spreed.room.joinRoomRaw(token: roomToken), (final response) => response.body.ocs.data, ); await _loadMessages(force: true); } @override // ignore: avoid_void_async void sendMessage(final String message) async { try { sendingMessage.add(message); await account.client.spreed.chat.sendMessage( token: roomToken, message: message, ); await _loadMessages(force: true); } catch (e, s) { debugPrint(e.toString()); debugPrint(s.toString()); addError(e); } finally { sendingMessage.add(null); } } @override Future loadMoreMessages() async { await _loadMessages(force: false); } @override Future leaveRoom() async { try { await account.client.spreed.room.leaveRoom(token: roomToken); } catch (e, s) { debugPrint(e.toString()); debugPrint(s.toString()); addError(e); } } Future _loadMessages({required final bool force}) async { if (!force && (allLoaded.valueOrNull ?? false)) { return; } final previousData = messages.valueOrNull?.data; try { messages.add( Result( previousData, null, isLoading: true, isCached: true, ), ); final data = await account.client.spreed.chat.receiveMessages( token: roomToken, lookIntoFuture: 0, includeLastKnown: 1, limit: _limit, lastKnownMessageId: (force ? null : _lastKnownMessageId) ?? 0, lastCommonReadId: lastCommonReadMessageId.valueOrNull ?? 0, ); _lastKnownMessageId = data.headers.xChatLastGiven != null ? int.parse(data.headers.xChatLastGiven!) : null; lastCommonReadMessageId.add( data.headers.xChatLastCommonRead != null ? int.parse(data.headers.xChatLastCommonRead!) : null, ); if (data.body.ocs.data.length < _limit) { allLoaded.add(true); } messages.add( Result.success( { if (previousData != null) ..._messagesToUniqueMap(previousData), ..._messagesToUniqueMap(data.body.ocs.data.toList()), }.values.sorted((final a, final b) => b.id.compareTo(a.id)).toList(), ), ); } catch (e, s) { debugPrint(e.toString()); debugPrint(s.toString()); messages.add( Result( previousData, e, isLoading: false, isCached: true, ), ); } } Map _messagesToUniqueMap(final List messages) => { for (final message in messages) ...{ message.id: message, }, }; }