/// 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 { 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 Function(Future 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.delayed(Duration.zero); if (!mounted() || gen != _gen) return; Future yieldUi() async { await Future.delayed(Duration.zero); } final result = await compute(yieldUi); if (!mounted() || gen != _gen) return; value = result; valueKey = key; if (_loadingKey == key) _loadingKey = null; onUpdate(); }()); } }