loadHiddenEvents method

Future<List<HiddenEvent>> loadHiddenEvents({
  1. List<String>? ids,
  2. List<String>? pubKeys,
  3. List<int>? kinds,
  4. List<String>? coordinates,
  5. Map<String, List<String>>? tags,
  6. int? since,
  7. int? until,
  8. String? search,
  9. int? limit,
  10. Set<HiddenEventReason> reasons = kAllHiddenEventReasons,
  11. int? now,
})

Implements CacheManager.loadHiddenEvents on top of a raw loader.

Implementation

Future<List<HiddenEvent>> loadHiddenEvents({
  List<String>? ids,
  List<String>? pubKeys,
  List<int>? kinds,
  List<String>? coordinates,
  Map<String, List<String>>? tags,
  int? since,
  int? until,
  String? search,
  int? limit,
  Set<HiddenEventReason> reasons = kAllHiddenEventReasons,
  int? now,
}) async {
  if (reasons.isEmpty) return <HiddenEvent>[];

  Set<String>? wantedConflictKeys;
  var queryPubKeys = pubKeys;
  var queryKinds = kinds;

  if (coordinates != null) {
    wantedConflictKeys = {};
    final coordinateAuthors = <String>{};
    final coordinateKinds = <int>{};
    for (final coordinate in coordinates) {
      final key = EventCacheStateRecord.normalizeConflictKey(coordinate);
      if (key == null) continue;
      wantedConflictKeys.add(key);
      final parts = coordinate.split(':');
      coordinateKinds.add(int.parse(parts[0]));
      coordinateAuthors.add(parts[1]);
    }
    if (wantedConflictKeys.isEmpty) return <HiddenEvent>[];

    // Filters combine with AND, so an explicit pubKeys/kinds is already at
    // least as narrow as the coordinates it is combined with.
    queryPubKeys ??= coordinateAuthors.toList();
    queryKinds ??= coordinateKinds.toList();
  }

  final candidates = await _loadRawEvents(
    ids: ids,
    pubKeys: queryPubKeys,
    kinds: queryKinds,
    tags: tags,
    since: since,
    until: until,
    search: search,
  );
  if (candidates.isEmpty) return <HiddenEvent>[];

  final currentTime = now ?? Nip01Event.secondsSinceEpoch();
  final state = await _resolveState(candidates);

  final hidden = <HiddenEvent>[];
  for (final event in candidates) {
    if (wantedConflictKeys != null &&
        !wantedConflictKeys.contains(
          EventCacheStateRecord.conflictKeyFor(event),
        )) {
      continue;
    }

    final record = state[event.id];
    if (record == null) continue;

    final eventReasons = hiddenReasons(record, currentTime);
    if (eventReasons.isEmpty) continue;
    if (!eventReasons.any(reasons.contains)) continue;

    hidden.add(
      HiddenEvent(event: event, state: record, reasons: eventReasons),
    );
  }

  hidden.sort((a, b) {
    final byTime = b.event.createdAt.compareTo(a.event.createdAt);
    return byTime != 0 ? byTime : a.event.id.compareTo(b.event.id);
  });

  if (limit != null && limit > 0 && hidden.length > limit) {
    return hidden.take(limit).toList();
  }
  return hidden;
}