import 'package:get/get.dart'; import 'package:solian/models/channel.dart'; import 'package:solian/models/event.dart'; import 'package:solian/platform.dart'; import 'package:solian/providers/message/adaptor.dart'; import 'package:solian/providers/message/events.dart'; class ChatEventController { late final MessageHistoryDb database; final RxList currentEvents = RxList.empty(growable: true); final RxInt totalEvents = 0.obs; final RxBool isLoading = false.obs; Channel? channel; String? scope; Future initialize() async { if (!PlatformInfo.isWeb) { database = await createHistoryDb(); } currentEvents.clear(); } Future getEvent(int id) async { if (channel == null || scope == null) return null; if (PlatformInfo.isWeb) { final remoteRecord = await getRemoteEvent(id, channel!, scope!); if (remoteRecord == null) return null; return LocalEvent( remoteRecord.id, remoteRecord, remoteRecord.channelId, remoteRecord.createdAt, ); } else { return await database.getEvent(id, channel!, scope: scope!); } } Future getEvents(Channel channel, String scope) async { this.channel = channel; this.scope = scope; syncLocal(channel); isLoading.value = true; if (PlatformInfo.isWeb) { final result = await getRemoteEvents( channel, scope, remainDepth: 3, offset: 0, ); totalEvents.value = result?.$2 ?? 0; if (result != null) { for (final x in result.$1.reversed) { final entry = LocalEvent(x.id, x, x.channelId, x.createdAt); insertEvent(entry); applyEvent(entry); } } } else { final result = await database.syncRemoteEvents( channel, scope: scope, ); totalEvents.value = result?.$2 ?? 0; await syncLocal(channel); } isLoading.value = false; } Future loadEvents(Channel channel, String scope) async { isLoading.value = true; if (PlatformInfo.isWeb) { final result = await getRemoteEvents( channel, scope, remainDepth: 3, offset: currentEvents.length, ); if (result != null) { totalEvents.value = result.$2; for (final x in result.$1.reversed) { final entry = LocalEvent(x.id, x, x.channelId, x.createdAt); currentEvents.add(entry); applyEvent(entry); } } } else { final result = await database.syncRemoteEvents( channel, depth: 3, scope: scope, offset: currentEvents.length, ); totalEvents.value = result?.$2 ?? 0; await syncLocal(channel); } isLoading.value = false; } Future syncLocal(Channel channel) async { if (PlatformInfo.isWeb) return false; final data = await database.localEvents.findAllByChannel(channel.id); currentEvents.replaceRange(0, currentEvents.length, data); for (final x in data.reversed) { applyEvent(x); } return true; } receiveEvent(Event remote) async { LocalEvent entry; if (PlatformInfo.isWeb) { entry = LocalEvent( remote.id, remote, remote.channelId, remote.createdAt, ); } else { entry = await database.receiveEvent(remote); } insertEvent(entry); applyEvent(entry); } insertEvent(LocalEvent entry) { if (entry.channelId != channel?.id) return; final idx = currentEvents.indexWhere((x) => x.data.uuid == entry.data.uuid); if (idx != -1) { currentEvents[idx] = entry; } else { currentEvents.insert(0, entry); } } applyEvent(LocalEvent entry) { if (entry.channelId != channel?.id) return; switch (entry.data.type) { case 'messages.edit': final body = EventMessageBody.fromJson(entry.data.body); if (body.relatedEvent != null) { final idx = currentEvents.indexWhere((x) => x.data.id == body.relatedEvent); if (idx != -1) { currentEvents[idx].data.body = entry.data.body; currentEvents[idx].data.updatedAt = entry.data.updatedAt; } } case 'messages.delete': final body = EventMessageBody.fromJson(entry.data.body); if (body.relatedEvent != null) { currentEvents.removeWhere((x) => x.id == body.relatedEvent); } } } addPendingEvent(Event info) async { currentEvents.insert( 0, LocalEvent( info.id, info, info.channelId, DateTime.now(), ), ); } }