import 'package:flutter_riverpod/flutter_riverpod.dart'; import '../library/library_providers.dart'; import '../models/home_index.dart'; /// Pre-warms the drift cache for likely-tap targets. Conservative on /// purpose: only warms artistProvider rows (single row, single round /// trip per id) and only ever fires once per id per session. Album /// detail is NOT prewarmed — the albumProvider auto-fetches its track /// list when missing, and pre-warming N albums fans out N parallel /// "fetch tracks" round trips that compete with the user's actual /// playback request for bandwidth. /// /// Driven off the per-item home path (homeIndexProvider). Only the /// artist-typed sections (rediscover / last-played artists) carry /// artist ids directly; album/track tiles hydrate their own artist on /// render via the per-item path, so warming those here is unnecessary. class MetadataPrefetcher { MetadataPrefetcher(this._ref) { _ref.listen>(homeIndexProvider, (_, next) { next.whenData(_warmIndex); }); } final Ref _ref; /// Per-session dedupe so re-rendering a screen (every UI rebuild /// fires the data: callback) doesn't trigger N more fetches for /// ids we've already warmed. final Set _warmedArtists = {}; /// Cap warmed per emission. Covers what fits on screen without /// scrolling. static const _topN = 8; /// Pre-warm artists. Albums are intentionally not pre-warmed — /// see class comment. void warmArtists(Iterable ids) { var n = 0; for (final id in ids) { if (id.isEmpty) continue; if (!_warmedArtists.add(id)) continue; // already warmed if (n++ >= _topN) break; _swallow(_ref.read(artistProvider(id).future)); } } void _warmIndex(HomeIndex h) { warmArtists({ ...h.rediscoverArtists.take(_topN), ...h.lastPlayedArtists.take(_topN), }); } /// Discards the return value and any error from a fire-and-forget /// provider read. We don't care about the value here — we only want /// the side effect of writing drift. void _swallow(Future f) { f.then((_) {}).onError((_, __) {}); } } /// Read once at app start to activate the prefetcher (e.g. wire it /// from a top-level Consumer or main.dart container override). final metadataPrefetcherProvider = Provider((ref) { return MetadataPrefetcher(ref); });