import 'dart:io'; import 'dart:typed_data'; import '../models/fuel_entry.dart'; import 'cloud/cloud_storage_provider.dart'; import 'fuel_report.dart'; /// Result of [loadReceiptImageBytes]: the photo bytes that were resolved, /// plus which entries couldn't be — e.g. because the receipt was uploaded /// through a *different* cloud provider than the one currently connected /// (its stored reference is meaningless to the active provider's API), or /// the entry is offline/the remote file's since been deleted. Surfacing /// [failedEntries] instead of only ever silently dropping them is what /// makes that distinguishable from "there was never a receipt at all". class ReceiptImageLoadResult { final Map bytesByEntryId; final List failedEntries; ReceiptImageLoadResult({required this.bytesByEntryId, required this.failedEntries}); } /// Reads (or downloads) the receipt photo for every entry in [report]. /// /// Prefers the local copy when one's still on-device; falls back to /// downloading via [activeProvider] for entries that have already been /// uploaded and cleared locally. An entry that fails to download (offline, /// revoked cloud access, since-deleted remote file, a reference belonging /// to a different provider than the one currently connected, ...) is left /// out of [ReceiptImageLoadResult.bytesByEntryId] and reported in /// [ReceiptImageLoadResult.failedEntries] instead — one missing receipt /// photo shouldn't block the rest of the document, but it also shouldn't /// vanish without a trace. Future loadReceiptImageBytes({ required FuelReport report, required CloudStorageProvider? activeProvider, }) async { final bytesByEntryId = {}; final failedEntries = []; CloudStorageSession? session; try { for (final row in report.rows) { for (final entry in row.entries) { final localPath = entry.receiptImagePath; if (localPath != null) { final file = File(localPath); if (await file.exists()) { bytesByEntryId[entry.id] = Uint8List.fromList(await file.readAsBytes()); continue; } } final driveFileId = entry.receiptDriveFileId; if (driveFileId == null || activeProvider == null || !activeProvider.isSignedIn) { failedEntries.add(entry); continue; } try { session ??= activeProvider.beginSession(); final bytes = await session.downloadFileBytes(driveFileId); bytesByEntryId[entry.id] = Uint8List.fromList(bytes); } catch (_) { failedEntries.add(entry); } } } } finally { session?.close(); } return ReceiptImageLoadResult(bytesByEntryId: bytesByEntryId, failedEntries: failedEntries); }