import 'dart:convert'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:shared_preferences/shared_preferences.dart'; import '../models/tracker.dart'; /// Persists the list of trackers to [SharedPreferences] as JSON. /// /// A repository is justified here because storage is asynchronous, has /// specialized queries (save/load all), and is consumed both by the service /// layer and by tests with fake implementations. class TrackerStorage { TrackerStorage(this._prefs); static const String _storageKey = 'bible_tracker.trackers.v1'; final SharedPreferences _prefs; /// Synchronous because the underlying [SharedPreferences] getter already /// works against an in-memory cache. Keeping this sync lets the service /// start up with real data on the first frame, with no async-load race. List loadAll() { final String? raw = _prefs.getString(_storageKey); if (raw == null || raw.isEmpty) { return []; } final List decoded = jsonDecode(raw) as List; return decoded .cast>() .map(Tracker.fromJson) .toList(growable: false); } Future saveAll(List trackers) async { final List> json = trackers .map((Tracker tracker) => tracker.toJson()) .toList(growable: false); await _prefs.setString(_storageKey, jsonEncode(json)); } } /// Must be overridden at startup with an initialized [SharedPreferences]. final Provider sharedPreferencesProvider = Provider( (Ref ref) => throw UnimplementedError( 'sharedPreferencesProvider must be overridden before use', ), ); final Provider trackerStorageProvider = Provider( (Ref ref) => TrackerStorage(ref.read(sharedPreferencesProvider)), );