import 'dart:typed_data'; import 'package:flutter/material.dart'; import 'package:image_picker/image_picker.dart'; import '../i18n/strings.g.dart'; import '../services/camera_availability.dart'; /// Asks the user to take a photo or pick one from the gallery, then returns its /// bytes (or null if cancelled/unavailable). Camera failures — e.g. on desktop, /// which has no camera — are swallowed and yield null. Future pickPhoto(BuildContext context) async { final t = context.t; final source = await showModalBottomSheet( context: context, builder: (sheetContext) => SafeArea( child: Column( mainAxisSize: MainAxisSize.min, children: [ // Only offer the camera when the device actually has one; camera-less // devices (Chromebooks, Automotive, some TVs) fall back to gallery. if (deviceHasCamera) ListTile( key: const Key('photo.source.camera'), leading: const Icon(Icons.photo_camera_outlined), title: Text(t.photo.camera), onTap: () => Navigator.of(sheetContext).pop(ImageSource.camera), ), ListTile( key: const Key('photo.source.gallery'), leading: const Icon(Icons.photo_library_outlined), title: Text(t.photo.gallery), onTap: () => Navigator.of(sheetContext).pop(ImageSource.gallery), ), ], ), ), ); if (source == null) return null; try { final file = await ImagePicker().pickImage( source: source, maxWidth: 1280, imageQuality: 80, ); return file?.readAsBytes(); } on Object { return null; } } /// Rapid multi-capture for the "capture now, catalogue later" flow: pick many /// photos from the gallery at once, or shoot a burst with the camera (it /// reopens after each shot until the user cancels). Returns every captured /// image's bytes, or an empty list if cancelled/unavailable. Future> pickPhotos(BuildContext context) async { final t = context.t; final source = await showModalBottomSheet( context: context, builder: (sheetContext) => SafeArea( child: Column( mainAxisSize: MainAxisSize.min, children: [ // Only offer the camera when the device actually has one; camera-less // devices (Chromebooks, Automotive, some TVs) fall back to gallery. if (deviceHasCamera) ListTile( key: const Key('photos.source.camera'), leading: const Icon(Icons.photo_camera_outlined), title: Text(t.photo.camera), onTap: () => Navigator.of(sheetContext).pop(ImageSource.camera), ), ListTile( key: const Key('photos.source.gallery'), leading: const Icon(Icons.photo_library_outlined), title: Text(t.photo.gallery), onTap: () => Navigator.of(sheetContext).pop(ImageSource.gallery), ), ], ), ), ); if (source == null) return const []; final picker = ImagePicker(); try { if (source == ImageSource.gallery) { final files = await picker.pickMultiImage( maxWidth: 1280, imageQuality: 80, ); return [for (final file in files) await file.readAsBytes()]; } // Camera burst: keep reopening the camera until the user cancels. final shots = []; while (true) { final file = await picker.pickImage( source: ImageSource.camera, maxWidth: 1280, imageQuality: 80, ); if (file == null) break; shots.add(await file.readAsBytes()); } return shots; } on Object { return const []; } }