MO-Fuel-Tax-Back/lib/services/app_state.dart
2026-08-08 08:22:14 -05:00

129 lines
3.5 KiB
Dart

import 'dart:io';
import 'package:flutter/foundation.dart';
import 'package:uuid/uuid.dart';
import '../models/fuel_entry.dart';
import '../models/vehicle.dart';
import 'storage_service.dart';
/// Single source of truth for the app's in-memory data (vehicles + fuel
/// entries), backed by [StorageService] for persistence. Screens read from
/// this via Provider and call its mutating methods, which take care of
/// writing through to disk and notifying listeners.
class AppState extends ChangeNotifier {
final StorageService storage = StorageService();
final _uuid = const Uuid();
List<Vehicle> vehicles = [];
List<FuelEntry> fuelEntries = [];
bool isLoading = true;
Future<void> init() async {
await storage.init();
final data = await storage.loadData();
vehicles = data.vehicles;
fuelEntries = data.entries;
isLoading = false;
notifyListeners();
}
Future<void> addVehicle({
required String make,
required String model,
required String color,
required String licensePlate,
}) async {
vehicles.add(Vehicle(
id: _uuid.v4(),
make: make,
model: model,
color: color,
licensePlate: licensePlate,
));
await _persist();
}
Future<void> updateVehicle(Vehicle updated) async {
final index = vehicles.indexWhere((v) => v.id == updated.id);
if (index != -1) {
vehicles[index] = updated;
await _persist();
}
}
Future<void> deleteVehicle(String vehicleId) async {
for (final entry in fuelEntries.where((e) => e.vehicleId == vehicleId)) {
await storage.deleteReceiptImage(entry.receiptImagePath);
}
fuelEntries.removeWhere((e) => e.vehicleId == vehicleId);
vehicles.removeWhere((v) => v.id == vehicleId);
await _persist();
}
Future<FuelEntry> addFuelEntry({
required String vehicleId,
required DateTime date,
required double gallons,
required double pricePerGallon,
required double totalCost,
File? receiptImage,
}) async {
final id = _uuid.v4();
String? storedImagePath;
if (receiptImage != null) {
storedImagePath = await storage.storeReceiptImage(receiptImage, id);
}
final entry = FuelEntry(
id: id,
vehicleId: vehicleId,
date: date,
gallons: gallons,
pricePerGallon: pricePerGallon,
totalCost: totalCost,
receiptImagePath: storedImagePath,
);
fuelEntries.add(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 _persist();
}
List<FuelEntry> entriesForVehicle(String vehicleId) {
final list = fuelEntries.where((e) => e.vehicleId == vehicleId).toList();
list.sort((a, b) => b.date.compareTo(a.date));
return list;
}
double totalGallonsForVehicle(String vehicleId) => fuelEntries
.where((e) => e.vehicleId == vehicleId)
.fold(0.0, (sum, e) => sum + e.gallons);
double get totalGallonsAllVehicles =>
fuelEntries.fold(0.0, (sum, e) => sum + e.gallons);
Vehicle? vehicleById(String id) {
try {
return vehicles.firstWhere((v) => v.id == id);
} catch (_) {
return null;
}
}
Future<void> changeSaveDirectory(String newPath) async {
await storage.setSaveDirectory(newPath);
notifyListeners();
}
Future<void> _persist() async {
await storage.saveData(vehicles: vehicles, entries: fuelEntries);
notifyListeners();
}
}