Files
manager/lib/core/polling/polling_async_notifier.dart
2026-07-27 14:42:23 +02:00

38 lines
1.4 KiB
Dart

import 'dart:async';
import 'package:riverpod_annotation/riverpod_annotation.dart';
/// Mixed into a `@riverpod` `AutoDisposeAsyncNotifier` to auto-refresh it on
/// a timer while it has at least one listener — Dashboard's summary and
/// Fleet's aggregated view, specifically. The API has no push/websocket, so
/// this is the honest refresh model: a manual pull plus a background
/// timer, not a live stream.
///
/// Usage: `class FooNotifier extends _$FooNotifier with PollingMixin<Foo>`,
/// implement [interval] and [fetch], and have `build()` return
/// `startPolling()`.
mixin PollingMixin<T> on $AsyncNotifier<T> {
/// How often to refetch while this provider has at least one listener.
Duration get interval;
/// Performs the actual fetch. Thrown exceptions surface as
/// `AsyncValue.error` exactly like any other async provider.
Future<T> fetch();
/// Call from `build()`: starts the periodic timer (cancelled on dispose)
/// and returns the initial fetch.
Future<T> startPolling() {
final timer = Timer.periodic(interval, (_) => refresh());
ref.onDispose(timer.cancel);
return fetch();
}
/// Re-fetches and updates state. Deliberately never emits an
/// intermediate `AsyncLoading` — the previous data/error stays on screen
/// until the new result lands, so a background tick never flashes the
/// UI back to a loading spinner.
Future<void> refresh() async {
state = await AsyncValue.guard(fetch);
}
}