refreshCalendarEvents method
Fetches fresh calendar data for the student's semester lifetime window and writes it to the DB.
The watchCalendarEvents stream automatically emits the updated value. Network errors propagate to the caller.
Implementation
Future<void> refreshCalendarEvents() async {
if (_refreshInFlight case final existing?) return existing.future;
final completer = Completer<void>();
_refreshInFlight = completer;
try {
final (windowStart, windowEnd) = await _computeWindow();
final dtos = await _authRepository.withAuth(
() => _portalService.getCalendar(windowStart, windowEnd),
);
await _database.transaction(() async {
// Clear the window first, then insert fresh data. Overlap semantics
// (consistent with read queries) so boundary-spanning events are
// cleaned up too.
await (_database.delete(_database.calendarEvents)..where((e) {
return e.start.isSmallerThanValue(windowEnd) &
e.end.isBiggerThanValue(windowStart);
}))
.go();
// Skip events without an ID — we can't sync or dedupe them.
final companions = dtos
.where((dto) => dto.id != null)
.map(
(dto) => CalendarEventsCompanion.insert(
portalId: dto.id!,
start: dto.start,
end: dto.end,
allDay: Value(dto.allDay),
title: Value(dto.title),
place: Value(dto.place),
content: Value(dto.content),
ownerName: Value(dto.ownerName),
creatorName: Value(dto.creatorName),
),
)
.toList();
await _database.batch((batch) {
batch.insertAll(_database.calendarEvents, companions);
});
await _database
.update(_database.users)
.write(UsersCompanion(calendarFetchedAt: Value(DateTime.now())));
});
completer.complete();
} catch (e, st) {
completer.completeError(e, st);
rethrow;
} finally {
_refreshInFlight = null;
}
}