feat(images): surface actionable upload errors for private photo pipeline

- Change uploadCarImage to throw explicit errors instead of returning null
- Handle upload exceptions in garage detail flow with clearer user feedback
- Guide users to retry with a smaller/clearer image when upload constraints fail
This commit is contained in:
Lukas Müllner 2026-03-04 11:31:37 +01:00
parent aab5c7d039
commit d287d175b5
2 changed files with 30 additions and 31 deletions

View file

@ -678,14 +678,18 @@ class GarageScreenState extends State<GarageScreen> {
showGlobalSnackBar('Uploading photo…');
final oldPath = car['user_image_url'] as String?;
final newPath = await StorageService.uploadCarImage(
String newPath;
try {
newPath = await StorageService.uploadCarImage(
file: File(xFile.path),
entryId: car['id'] as int,
oldPath: oldPath,
);
if (newPath == null) {
showGlobalSnackBar('Failed to upload photo.', isError: true);
} catch (e) {
showGlobalSnackBar(
'Failed to upload photo. Please try a smaller/clearer image. ($e)',
isError: true,
);
return;
}

View file

@ -18,12 +18,11 @@ class StorageService {
/// Upload a car image for a specific hotwheels entry.
/// Returns the storage path on success (e.g. `uid/123.jpg`).
static Future<String?> uploadCarImage({
static Future<String> uploadCarImage({
required File file,
required int entryId,
String? oldPath,
}) async {
try {
if (oldPath != null && oldPath.isNotEmpty) {
await deleteCarImage(oldPath);
}
@ -42,10 +41,6 @@ class StorageService {
);
return path;
} catch (e) {
debugPrint('StorageService.uploadCarImage error: $e');
return null;
}
}
/// Generates a temporary signed URL for a private image path.