A whole bunch of changes
This commit is contained in:
parent
901ec678a3
commit
956231048e
122 changed files with 5442 additions and 914 deletions
70
lib/services/fuel_report_images.dart
Normal file
70
lib/services/fuel_report_images.dart
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
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<String, Uint8List> bytesByEntryId;
|
||||
final List<FuelEntry> 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<ReceiptImageLoadResult> loadReceiptImageBytes({
|
||||
required FuelReport report,
|
||||
required CloudStorageProvider? activeProvider,
|
||||
}) async {
|
||||
final bytesByEntryId = <String, Uint8List>{};
|
||||
final failedEntries = <FuelEntry>[];
|
||||
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);
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue