A framework for building convergent cross-platform Nextcloud clients using Flutter.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

175 lines
4.4 KiB

part of '../neon_spreed.dart';
abstract class SpreedRoomBlocEvents {
void loadMoreMessages();
void sendMessage(final String message);
Future<void> leaveRoom();
}
abstract class SpreedRoomBlocStates {
BehaviorSubject<Result<spreed.Room>> get room;
BehaviorSubject<Result<List<spreed.ChatMessageInterface>>> get messages;
BehaviorSubject<bool> get allLoaded;
BehaviorSubject<String?> get sendingMessage;
BehaviorSubject<int?> 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<bool> allLoaded = BehaviorSubject.seeded(false);
@override
BehaviorSubject<int?> lastCommonReadMessageId = BehaviorSubject.seeded(null);
@override
BehaviorSubject<Result<List<spreed.ChatMessageInterface>>> messages = BehaviorSubject();
@override
BehaviorSubject<Result<spreed.Room>> room = BehaviorSubject();
@override
BehaviorSubject<String?> sendingMessage = BehaviorSubject.seeded(null);
@override
Future<void> 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<void> loadMoreMessages() async {
await _loadMessages(force: false);
}
@override
Future<void> leaveRoom() async {
try {
await account.client.spreed.room.leaveRoom(token: roomToken);
} catch (e, s) {
debugPrint(e.toString());
debugPrint(s.toString());
addError(e);
}
}
Future<void> _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<int, spreed.ChatMessageInterface> _messagesToUniqueMap(final List<spreed.ChatMessageInterface> messages) => {
for (final message in messages) ...{
message.id: message,
},
};
}