51 lines
1.2 KiB
Dart
51 lines
1.2 KiB
Dart
/// Schedule heavy tab work off the first paint, yielding so nav stays responsive.
|
|
library;
|
|
|
|
import 'dart:async';
|
|
|
|
/// Runs [compute] after a frame, cancellable via [cancel] / generation bumps.
|
|
class DeferredTabWork<T> {
|
|
int _gen = 0;
|
|
Object? _loadingKey;
|
|
T? value;
|
|
Object? valueKey;
|
|
|
|
bool readyFor(Object key) => value != null && valueKey == key;
|
|
|
|
bool get isLoading => _loadingKey != null;
|
|
|
|
void cancel() {
|
|
_gen++;
|
|
_loadingKey = null;
|
|
}
|
|
|
|
/// Starts work for [key] unless already ready or in flight for that key.
|
|
void ensure({
|
|
required Object key,
|
|
required Future<T> Function(Future<void> Function() yieldUi) compute,
|
|
required void Function() onUpdate,
|
|
required bool Function() mounted,
|
|
}) {
|
|
if (readyFor(key) || _loadingKey == key) return;
|
|
_loadingKey = key;
|
|
final gen = ++_gen;
|
|
|
|
unawaited(() async {
|
|
await Future<void>.delayed(Duration.zero);
|
|
if (!mounted() || gen != _gen) return;
|
|
|
|
Future<void> yieldUi() async {
|
|
await Future<void>.delayed(Duration.zero);
|
|
}
|
|
|
|
final result = await compute(yieldUi);
|
|
if (!mounted() || gen != _gen) return;
|
|
|
|
value = result;
|
|
valueKey = key;
|
|
if (_loadingKey == key) _loadingKey = null;
|
|
onUpdate();
|
|
}());
|
|
}
|
|
}
|