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> { @override IMap build() => .new(); void addState( String roomId, IList 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 rooms, [ ISet 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.new, ); }