38 lines
1.4 KiB
Dart
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);
|
|
}
|
|
}
|