Added sqlite
This commit is contained in:
parent
73a7c93e64
commit
f01186df79
14 changed files with 784 additions and 382 deletions
|
|
@ -8,24 +8,29 @@ import 'package:uuid/uuid.dart';
|
|||
|
||||
import '../models/fuel_entry.dart';
|
||||
import '../models/vehicle.dart';
|
||||
import 'database_service.dart';
|
||||
import 'drive_auth_service.dart';
|
||||
import 'drive_sync_service.dart';
|
||||
import 'storage_service.dart';
|
||||
|
||||
const _prefsKeyDriveFolderId = 'drive_app_folder_id';
|
||||
const _prefsKeyDriveFolderPath = 'drive_app_folder_path';
|
||||
|
||||
/// Single source of truth for the app's in-memory data (vehicles + fuel
|
||||
/// entries), backed by [StorageService] for local persistence and
|
||||
/// entries), backed by [DatabaseService] (local SQLite) for persistence and
|
||||
/// [DriveSyncService] for pushing/pulling the shared Drive copy. Screens
|
||||
/// read from this via Provider and call its mutating methods, which write
|
||||
/// through to local disk immediately and kick off a best-effort background
|
||||
/// sync to Drive.
|
||||
/// through to the local database immediately and kick off a best-effort
|
||||
/// background sync to Drive.
|
||||
///
|
||||
/// The `vehicles`/`fuelEntries` lists are an in-memory read cache of the
|
||||
/// database, refreshed after every mutation and after every sync (since
|
||||
/// sync's merge happens as SQL directly against the database, not by
|
||||
/// handing back updated Dart objects).
|
||||
class AppState extends ChangeNotifier {
|
||||
final StorageService storage = StorageService();
|
||||
final DatabaseService database = DatabaseService();
|
||||
final DriveAuthService driveAuth = DriveAuthService();
|
||||
late final DriveSyncService driveSync =
|
||||
DriveSyncService(authService: driveAuth, storageService: storage);
|
||||
DriveSyncService(authService: driveAuth, databaseService: database);
|
||||
final _uuid = const Uuid();
|
||||
|
||||
List<Vehicle> vehicles = [];
|
||||
|
|
@ -42,10 +47,8 @@ class AppState extends ChangeNotifier {
|
|||
StreamSubscription<List<ConnectivityResult>>? _connectivitySubscription;
|
||||
|
||||
Future<void> init() async {
|
||||
await storage.init();
|
||||
final data = await storage.loadData();
|
||||
vehicles = data.vehicles;
|
||||
fuelEntries = data.entries;
|
||||
await database.init();
|
||||
await _refreshFromDatabase();
|
||||
isLoading = false;
|
||||
notifyListeners();
|
||||
|
||||
|
|
@ -64,6 +67,11 @@ class AppState extends ChangeNotifier {
|
|||
super.dispose();
|
||||
}
|
||||
|
||||
Future<void> _refreshFromDatabase() async {
|
||||
vehicles = await database.getVehicles();
|
||||
fuelEntries = await database.getFuelEntries();
|
||||
}
|
||||
|
||||
Future<void> _restoreDriveConnection() async {
|
||||
final signedIn = await driveAuth.attemptSilentSignIn();
|
||||
if (!signedIn) return;
|
||||
|
|
@ -125,15 +133,10 @@ class AppState extends ChangeNotifier {
|
|||
isSyncing = true;
|
||||
notifyListeners();
|
||||
|
||||
final result = await driveSync.syncNow(
|
||||
localVehicles: vehicles,
|
||||
localFuelEntries: fuelEntries,
|
||||
);
|
||||
final result = await driveSync.syncNow();
|
||||
|
||||
if (result.ranSync) {
|
||||
vehicles = result.vehicles!;
|
||||
fuelEntries = result.fuelEntries!;
|
||||
await storage.saveData(vehicles: vehicles, entries: fuelEntries);
|
||||
await _refreshFromDatabase();
|
||||
lastSyncedAt = DateTime.now();
|
||||
lastSyncError = null;
|
||||
} else if (result.error != null) {
|
||||
|
|
@ -150,31 +153,30 @@ class AppState extends ChangeNotifier {
|
|||
required String color,
|
||||
required String licensePlate,
|
||||
}) async {
|
||||
vehicles.add(Vehicle(
|
||||
final vehicle = Vehicle(
|
||||
id: _uuid.v4(),
|
||||
make: make,
|
||||
model: model,
|
||||
color: color,
|
||||
licensePlate: licensePlate,
|
||||
updatedAt: DateTime.now().toUtc(),
|
||||
));
|
||||
);
|
||||
await database.saveVehicle(vehicle);
|
||||
await _persist();
|
||||
}
|
||||
|
||||
Future<void> updateVehicle(Vehicle updated) async {
|
||||
final index = vehicles.indexWhere((v) => v.id == updated.id);
|
||||
if (index != -1) {
|
||||
vehicles[index] = updated.copyWith(updatedAt: DateTime.now().toUtc());
|
||||
await _persist();
|
||||
}
|
||||
await database.saveVehicle(updated.copyWith(updatedAt: DateTime.now().toUtc()));
|
||||
await _persist();
|
||||
}
|
||||
|
||||
Future<void> deleteVehicle(String vehicleId) async {
|
||||
for (final entry in fuelEntries.where((e) => e.vehicleId == vehicleId)) {
|
||||
await storage.deleteReceiptImage(entry.receiptImagePath);
|
||||
final now = DateTime.now().toUtc();
|
||||
final orphanedLocalPaths = await database.softDeleteFuelEntriesForVehicle(vehicleId, now);
|
||||
for (final path in orphanedLocalPaths) {
|
||||
await database.deleteReceiptImageFile(path);
|
||||
}
|
||||
fuelEntries.removeWhere((e) => e.vehicleId == vehicleId);
|
||||
vehicles.removeWhere((v) => v.id == vehicleId);
|
||||
await database.softDeleteVehicle(vehicleId, now);
|
||||
await _persist();
|
||||
}
|
||||
|
||||
|
|
@ -189,7 +191,7 @@ class AppState extends ChangeNotifier {
|
|||
final id = _uuid.v4();
|
||||
String? storedImagePath;
|
||||
if (receiptImage != null) {
|
||||
storedImagePath = await storage.storeReceiptImage(receiptImage, id);
|
||||
storedImagePath = await database.storeReceiptImage(receiptImage, id);
|
||||
}
|
||||
|
||||
final entry = FuelEntry(
|
||||
|
|
@ -202,15 +204,15 @@ class AppState extends ChangeNotifier {
|
|||
receiptImagePath: storedImagePath,
|
||||
updatedAt: DateTime.now().toUtc(),
|
||||
);
|
||||
fuelEntries.add(entry);
|
||||
await database.saveFuelEntry(entry);
|
||||
await _persist();
|
||||
return entry;
|
||||
}
|
||||
|
||||
Future<void> deleteFuelEntry(String entryId) async {
|
||||
final entry = fuelEntries.firstWhere((e) => e.id == entryId);
|
||||
await storage.deleteReceiptImage(entry.receiptImagePath);
|
||||
fuelEntries.removeWhere((e) => e.id == entryId);
|
||||
await database.deleteReceiptImageFile(entry.receiptImagePath);
|
||||
await database.softDeleteFuelEntry(entryId, DateTime.now().toUtc());
|
||||
await _persist();
|
||||
}
|
||||
|
||||
|
|
@ -236,7 +238,7 @@ class AppState extends ChangeNotifier {
|
|||
}
|
||||
|
||||
Future<void> _persist() async {
|
||||
await storage.saveData(vehicles: vehicles, entries: fuelEntries);
|
||||
await _refreshFromDatabase();
|
||||
notifyListeners();
|
||||
unawaited(syncNow());
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue