Added Google Drive storage location
This commit is contained in:
parent
e630f2a3ec
commit
73a7c93e64
22 changed files with 1690 additions and 205 deletions
|
|
@ -3,17 +3,17 @@ import 'dart:io';
|
|||
|
||||
import 'package:path/path.dart' as p;
|
||||
import 'package:path_provider/path_provider.dart';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
|
||||
import '../models/fuel_entry.dart';
|
||||
import '../models/vehicle.dart';
|
||||
|
||||
/// Owns the on-disk layout for the app: a `data.json` file holding vehicles
|
||||
/// and fuel entries, plus a `receipts/` subfolder holding receipt photos.
|
||||
/// The parent directory containing both is user-configurable (see
|
||||
/// [setSaveDirectory]) and persisted across launches via SharedPreferences.
|
||||
/// Owns the local, offline staging area: a `data.json` file holding
|
||||
/// vehicles and fuel entries, plus a `receipts/` subfolder holding receipt
|
||||
/// photos not yet uploaded to Drive. This is always
|
||||
/// `ApplicationDocumentsDirectory/FuelTaxTracker` — not user-configurable —
|
||||
/// since Drive (via [DriveSyncService]) is now the real shared destination
|
||||
/// and this is just a local cache/holding area used while offline.
|
||||
class StorageService {
|
||||
static const _prefsKey = 'save_directory_path';
|
||||
static const _dataFileName = 'fuel_tax_data.json';
|
||||
static const _receiptsFolderName = 'receipts';
|
||||
|
||||
|
|
@ -24,36 +24,31 @@ class StorageService {
|
|||
Directory get receiptsDirectory =>
|
||||
Directory(p.join(_saveDirectory.path, _receiptsFolderName));
|
||||
|
||||
File get _dataFile => File(p.join(_saveDirectory.path, _dataFileName));
|
||||
File get dataFile => File(p.join(_saveDirectory.path, _dataFileName));
|
||||
|
||||
/// Must be called once before any other method. Loads the previously
|
||||
/// chosen save directory, falling back to the app's own documents
|
||||
/// directory the first time the app runs.
|
||||
/// Must be called once before any other method.
|
||||
Future<void> init() async {
|
||||
final prefs = await SharedPreferences.getInstance();
|
||||
final storedPath = prefs.getString(_prefsKey);
|
||||
|
||||
if (storedPath != null && await Directory(storedPath).exists()) {
|
||||
_saveDirectory = Directory(storedPath);
|
||||
} else {
|
||||
final docsDir = await getApplicationDocumentsDirectory();
|
||||
_saveDirectory = Directory(p.join(docsDir.path, 'FuelTaxTracker'));
|
||||
}
|
||||
final docsDir = await getApplicationDocumentsDirectory();
|
||||
_saveDirectory = Directory(p.join(docsDir.path, 'FuelTaxTracker'));
|
||||
|
||||
await _saveDirectory.create(recursive: true);
|
||||
await receiptsDirectory.create(recursive: true);
|
||||
}
|
||||
|
||||
Future<({List<Vehicle> vehicles, List<FuelEntry> entries})> loadData() async {
|
||||
if (!await _dataFile.exists()) {
|
||||
if (!await dataFile.exists()) {
|
||||
return (vehicles: <Vehicle>[], entries: <FuelEntry>[]);
|
||||
}
|
||||
|
||||
final raw = await _dataFile.readAsString();
|
||||
final raw = await dataFile.readAsString();
|
||||
if (raw.trim().isEmpty) {
|
||||
return (vehicles: <Vehicle>[], entries: <FuelEntry>[]);
|
||||
}
|
||||
|
||||
return decodeData(raw);
|
||||
}
|
||||
|
||||
({List<Vehicle> vehicles, List<FuelEntry> entries}) decodeData(String raw) {
|
||||
final json = jsonDecode(raw) as Map<String, dynamic>;
|
||||
final vehicles = (json['vehicles'] as List<dynamic>? ?? [])
|
||||
.map((v) => Vehicle.fromJson(v as Map<String, dynamic>))
|
||||
|
|
@ -65,19 +60,26 @@ class StorageService {
|
|||
return (vehicles: vehicles, entries: entries);
|
||||
}
|
||||
|
||||
Future<void> saveData({
|
||||
String encodeData({
|
||||
required List<Vehicle> vehicles,
|
||||
required List<FuelEntry> entries,
|
||||
}) async {
|
||||
}) {
|
||||
final json = {
|
||||
'vehicles': vehicles.map((v) => v.toJson()).toList(),
|
||||
'fuelEntries': entries.map((e) => e.toJson()).toList(),
|
||||
};
|
||||
await _dataFile.writeAsString(const JsonEncoder.withIndent(' ').convert(json));
|
||||
return const JsonEncoder.withIndent(' ').convert(json);
|
||||
}
|
||||
|
||||
/// Copies a captured receipt image into the receipts folder and returns
|
||||
/// the path it was stored at.
|
||||
Future<void> saveData({
|
||||
required List<Vehicle> vehicles,
|
||||
required List<FuelEntry> entries,
|
||||
}) async {
|
||||
await dataFile.writeAsString(encodeData(vehicles: vehicles, entries: entries));
|
||||
}
|
||||
|
||||
/// Copies a captured receipt image into the local receipts folder and
|
||||
/// returns the path it was stored at, pending upload to Drive.
|
||||
Future<String> storeReceiptImage(File sourceImage, String fuelEntryId) async {
|
||||
final ext = p.extension(sourceImage.path);
|
||||
final destPath = p.join(receiptsDirectory.path, '$fuelEntryId$ext');
|
||||
|
|
@ -92,37 +94,4 @@ class StorageService {
|
|||
await file.delete();
|
||||
}
|
||||
}
|
||||
|
||||
/// Changes where the data file and receipt images live, moving any
|
||||
/// existing data/images from the old location into the new one.
|
||||
Future<void> setSaveDirectory(String newPath) async {
|
||||
final newDir = Directory(newPath);
|
||||
await newDir.create(recursive: true);
|
||||
final newReceiptsDir = Directory(p.join(newPath, _receiptsFolderName));
|
||||
await newReceiptsDir.create(recursive: true);
|
||||
|
||||
final oldDataFile = _dataFile;
|
||||
final oldReceiptsDir = receiptsDirectory;
|
||||
|
||||
if (await oldDataFile.exists() &&
|
||||
p.equals(oldDataFile.path, p.join(newPath, _dataFileName)) == false) {
|
||||
await oldDataFile.copy(p.join(newPath, _dataFileName));
|
||||
}
|
||||
|
||||
if (await oldReceiptsDir.exists()) {
|
||||
await for (final entity in oldReceiptsDir.list()) {
|
||||
if (entity is File) {
|
||||
final destPath = p.join(newReceiptsDir.path, p.basename(entity.path));
|
||||
if (!p.equals(entity.path, destPath)) {
|
||||
await entity.copy(destPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_saveDirectory = newDir;
|
||||
|
||||
final prefs = await SharedPreferences.getInstance();
|
||||
await prefs.setString(_prefsKey, newPath);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue