import 'package:flutter_riverpod/flutter_riverpod.dart'; import '../api/endpoints/search.dart'; import '../library/library_providers.dart' show dioProvider; import '../models/search_response.dart'; final searchApiProvider = FutureProvider((ref) async { return SearchApi(await ref.watch(dioProvider.future)); }); /// Current search query text. The screen's TextField writes here on /// every keystroke; the resultsProvider below debounces. class SearchQueryNotifier extends Notifier { @override String build() => ''; void set(String q) => state = q; } final searchQueryProvider = NotifierProvider(SearchQueryNotifier.new); /// Debounced search results. Returns null for empty queries so the /// screen can show a neutral empty state instead of "0 results." /// /// Debounce: 250ms. After the wait, re-reads the live query — if the /// user has typed more in that window, this attempt is silently /// abandoned (returns null) and a newer attempt fires on the next /// rebuild. No request hits the server while the user is mid-typing. final searchResultsProvider = FutureProvider((ref) async { final q = ref.watch(searchQueryProvider).trim(); if (q.isEmpty) return null; await Future.delayed(const Duration(milliseconds: 250)); // Re-read the (possibly newer) query; if the user typed more, bail. if (ref.read(searchQueryProvider).trim() != q) return null; final api = await ref.watch(searchApiProvider.future); return api.search(q); });