watchBuildings method

Stream<List<CampusMapBuilding>> watchBuildings()

Watches building outlines with their own available floors from Drift.

Cached data emits immediately. A missing or 14-day-old catalog refreshes once per subscription; failures retain stale data or emit an empty catalog for the screen's retry state. Bundled first-floor outlines replace upstream outlines, including existing caches. Buildings without usable first-floor outlines are not CampusMapBuilding.shownOnMap.

Implementation

Stream<List<CampusMapBuilding>> watchBuildings() async* {
  var attempted = false;
  final query = _db.select(_db.campusMapBuildings).join([
    leftOuterJoin(
      _db.campusMapFloors,
      _db.campusMapFloors.building.equalsExp(_db.campusMapBuildings.code),
    ),
  ]);
  await for (final rows in query.watch()) {
    final stamp = (await _sync())?.catalogFetchedAt;
    if (stamp == null && !attempted) {
      attempted = true;
      try {
        await refreshBuildings();
        continue;
      } catch (_) {
        // An empty snapshot exposes the cold-load retry UI.
      }
    }
    final floors = <String, List<CampusMapFloor>>{};
    final buildings = <String, MapBuildingRecord>{};
    for (final row in rows) {
      final building = row.readTable(_db.campusMapBuildings);
      buildings[building.code] = building;
      if (row.readTableOrNull(_db.campusMapFloors) case final floor?) {
        floors
            .putIfAbsent(building.code, () => [])
            .add(
              CampusMapFloor(layerName: floor.layerName, code: floor.code),
            );
      }
    }
    yield [
      for (final building in buildings.values)
        CampusMapBuilding(
          code: building.code,
          name: _firstFloorOutlines?[building.code]?.name ?? building.name,
          polygons: decodeCampusMapGeometry(
            _firstFloorOutlines?[building.code]?.geometry ??
                building.geometry,
          ),
          floors: (floors[building.code] ?? [])
            ..sort((a, b) => a.order.compareTo(b.order)),
          shownOnMap:
              (_firstFloorOutlines == null ||
                  _firstFloorOutlines.containsKey(building.code)) &&
              (floors[building.code]?.any((floor) => floor.code == '1F') ??
                  false),
        ),
    ]..sort((a, b) => a.name.compareTo(b.name));
    if (!attempted &&
        (stamp == null || _now().difference(stamp) >= _cacheTtl)) {
      attempted = true;
      try {
        await refreshBuildings();
      } catch (_) {
        // Keep the catalog already emitted above.
      }
    }
  }
}