Add local data store adapter layer and Hive scaffold
This commit is contained in:
@@ -2,15 +2,14 @@ import 'dart:convert';
|
||||
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:relationship_saver/features/local/local_models.dart';
|
||||
import 'package:relationship_saver/features/local/storage/local_data_store.dart';
|
||||
import 'package:relationship_saver/features/local/storage/local_data_store_provider.dart';
|
||||
import 'package:relationship_saver/features/sync/sync_queue_repository.dart';
|
||||
import 'package:relationship_saver/integrations/backend/models/backend_models.dart';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
import 'package:uuid/uuid.dart';
|
||||
|
||||
/// Persisted local data source for offline-first product state.
|
||||
class LocalRepository extends AsyncNotifier<LocalDataState> {
|
||||
static const String _storageKey = 'local_data_state_v1';
|
||||
static const String _schemaVersionKey = 'local_data_schema_version';
|
||||
static const int _schemaVersion = 2;
|
||||
static const int _syncSchemaVersion = 1;
|
||||
|
||||
@@ -18,18 +17,18 @@ class LocalRepository extends AsyncNotifier<LocalDataState> {
|
||||
|
||||
@override
|
||||
Future<LocalDataState> build() async {
|
||||
final SharedPreferences prefs = await SharedPreferences.getInstance();
|
||||
await _migrateIfNeeded(prefs);
|
||||
|
||||
final String? raw = prefs.getString(_storageKey);
|
||||
if (raw == null || raw.isEmpty) {
|
||||
final LocalDataStore store = ref.read(localDataStoreProvider);
|
||||
final LocalDataRecord? record = await store.read();
|
||||
if (record == null || record.rawState.isEmpty) {
|
||||
final LocalDataState seeded = LocalDataState.seed();
|
||||
await _persist(seeded);
|
||||
return seeded;
|
||||
}
|
||||
|
||||
final LocalDataRecord migrated = await _migrateIfNeeded(record);
|
||||
try {
|
||||
final Map<String, dynamic> json = jsonDecode(raw) as Map<String, dynamic>;
|
||||
final Map<String, dynamic> json =
|
||||
jsonDecode(migrated.rawState) as Map<String, dynamic>;
|
||||
return LocalDataState.fromJson(json);
|
||||
} on FormatException {
|
||||
final LocalDataState fallback = LocalDataState.seed();
|
||||
@@ -882,25 +881,37 @@ class LocalRepository extends AsyncNotifier<LocalDataState> {
|
||||
}
|
||||
|
||||
Future<void> _persist(LocalDataState state) async {
|
||||
final SharedPreferences prefs = await SharedPreferences.getInstance();
|
||||
await prefs.setString(_storageKey, jsonEncode(state.toJson()));
|
||||
await prefs.setInt(_schemaVersionKey, _schemaVersion);
|
||||
await ref
|
||||
.read(localDataStoreProvider)
|
||||
.write(
|
||||
rawState: jsonEncode(state.toJson()),
|
||||
schemaVersion: _schemaVersion,
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> _migrateIfNeeded(SharedPreferences prefs) async {
|
||||
final int currentVersion = prefs.getInt(_schemaVersionKey) ?? 0;
|
||||
Future<LocalDataRecord> _migrateIfNeeded(LocalDataRecord record) async {
|
||||
final int currentVersion = record.schemaVersion;
|
||||
if (currentVersion == _schemaVersion) {
|
||||
return;
|
||||
return record;
|
||||
}
|
||||
|
||||
final LocalDataStore store = ref.read(localDataStoreProvider);
|
||||
if (currentVersion <= 0) {
|
||||
await prefs.remove(_storageKey);
|
||||
await prefs.setInt(_schemaVersionKey, _schemaVersion);
|
||||
return;
|
||||
final LocalDataState seeded = LocalDataState.seed();
|
||||
await store.clear();
|
||||
await _persist(seeded);
|
||||
return LocalDataRecord(
|
||||
rawState: jsonEncode(seeded.toJson()),
|
||||
schemaVersion: _schemaVersion,
|
||||
);
|
||||
}
|
||||
|
||||
// Migration placeholder for future schema versions.
|
||||
await prefs.setInt(_schemaVersionKey, _schemaVersion);
|
||||
await store.write(rawState: record.rawState, schemaVersion: _schemaVersion);
|
||||
return LocalDataRecord(
|
||||
rawState: record.rawState,
|
||||
schemaVersion: _schemaVersion,
|
||||
);
|
||||
}
|
||||
|
||||
String _titleFromSummary(String summary) {
|
||||
|
||||
Reference in New Issue
Block a user