import 'package:app_settings/app_settings.dart'; import 'package:file_picker/file_picker.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:image_picker/image_picker.dart'; import '../api/errors/error_mapper.dart'; import '../api/errors/permission_exception.dart'; import 'confirm_dialog.dart'; import 'info_dialog.dart'; /// Thin wrapper around the platform pickers. Every method resolves to `null` /// when the user cancels **or** when picking failed; failures are reported to /// the user right here (permission denial with a shortcut to the system /// settings, everything else as a plain error dialog) so call sites can treat /// the result like a cancel. class FilePick { static final _picker = ImagePicker(); static Future?> multipleGalleryPick(BuildContext context) => _guarded(context, () async { final pickedImages = await _picker.pickMultiImage(); return pickedImages.isNotEmpty ? pickedImages : null; }); static Future singleGalleryPick(BuildContext context) => _guarded(context, () => _picker.pickImage(source: ImageSource.gallery)); static Future cameraPick(BuildContext context) => _guarded(context, () => _picker.pickImage(source: ImageSource.camera)); static Future?> documentPick() async { final result = await FilePicker.pickFiles(allowMultiple: true); return result?.files.map((e) => e.path).nonNulls.toList(); } static Future _guarded( BuildContext context, Future Function() pick, ) async { try { return await pick(); } on PlatformException catch (e) { final denied = PermissionException.fromPlatform(e); if (!context.mounted) return null; if (denied != null) { _showPermissionDialog(context, denied); } else { _showErrorDialog(context, e); } return null; } catch (e) { if (context.mounted) _showErrorDialog(context, e); return null; } } static void _showPermissionDialog( BuildContext context, PermissionException denied, ) => ConfirmDialog( icon: Icons.block_outlined, title: 'Zugriff verweigert', content: denied.userMessage, confirmButton: 'Einstellungen öffnen', onConfirm: AppSettings.openAppSettings, ).asDialog(context); static void _showErrorDialog(BuildContext context, Object error) { final message = errorToUserMessage(error); final details = errorToTechnicalDetails(error); final body = details != null && details != message ? '$message\n\n$details' : message; InfoDialog.show(context, body, copyable: true, title: 'Fehler'); } }