nexus/lib/controllers/rooms.dart
2026-10-02 17:01:25 -04:00

102 lines
3.3 KiB
Dart

import "package:collection/collection.dart";
import "package:fast_immutable_collections/fast_immutable_collections.dart";
import "package:flutter_riverpod/flutter_riverpod.dart";
import "package:nexus/models/event.dart";
import "package:nexus/models/room.dart";
class RoomsController extends Notifier<IMap<String, Room>> {
@override
IMap<String, Room> build() => .new();
void addState(
String roomId,
IList<Event> state, {
bool isMembers = false,
}) => update(
.new({
roomId: Room(
events: .fromEntries(state.map((event) => .new(event.rowId, event))),
hasFetchedState: true,
hasFetchedMembers: isMembers,
state: .new(
state
.groupListsBy((event) => event.type)
.map(
(type, group) => .new(
type,
.fromEntries(group.map((e) => .new(e.stateKey!, e.rowId))),
),
),
),
),
}),
.new(),
);
void update(
IMap<String, Room> rooms, [
ISet<String> leftRooms = const ISet.empty(),
]) {
final merged = rooms.entries.fold(state, (acc, entry) {
final roomId = entry.key;
final incoming = entry.value;
final existing = acc[roomId];
return acc.add(
roomId,
existing?.copyWith(
hasMore: incoming.hasMore,
clientSticky: incoming.resetClientSticky
? incoming.clientSticky
: (incoming.clientSticky.isEmpty == true
? existing.clientSticky
: existing.clientSticky.addAll(
incoming.clientSticky,
))
.removeWhere(
(rowId) => incoming.timeline.values.contains(rowId),
),
metadata: incoming.metadata ?? existing.metadata,
events: incoming.events.isEmpty
? existing.events
: existing.events.addAll(incoming.events),
state: incoming.state.entries.fold(
existing.state,
(previousValue, event) => previousValue.add(
event.key,
(previousValue[event.key] ?? .new()).addAll(event.value),
),
),
resetClientSticky: false,
reset: false,
hasFetchedMembers:
incoming.hasFetchedMembers || existing.hasFetchedMembers,
hasFetchedState:
incoming.hasFetchedState || existing.hasFetchedState,
timeline: (incoming.reset
? incoming.timeline
: existing.timeline.addAll(incoming.timeline)),
receipts: incoming.receipts.entries.fold(
existing.receipts,
(receiptAcc, event) => receiptAcc.add(
event.key,
(receiptAcc[event.key] ?? .new()).addAll(event.value),
),
),
) ??
incoming,
);
});
final prunedList = leftRooms.fold(
merged,
(acc, roomId) => acc.remove(roomId),
);
state = prunedList;
}
static final provider = NotifierProvider<RoomsController, IMap<String, Room>>(
RoomsController.new,
);
}