From b62164dde5958bd494f5555a5515b55be14d8ba7 Mon Sep 17 00:00:00 2001 From: davmar Date: Thu, 17 Sep 2026 00:50:15 +0200 Subject: [PATCH] spinner feedback to ui 2 --- lib/utils/deferred_tab_work.dart | 50 ++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 lib/utils/deferred_tab_work.dart diff --git a/lib/utils/deferred_tab_work.dart b/lib/utils/deferred_tab_work.dart new file mode 100644 index 0000000..d3e6236 --- /dev/null +++ b/lib/utils/deferred_tab_work.dart @@ -0,0 +1,50 @@ +/// 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(); + }()); + } +}