Files
Client/lib/widget/file_pick.dart
T

78 lines
2.6 KiB
Dart

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<List<XFile>?> multipleGalleryPick(BuildContext context) =>
_guarded(context, () async {
final pickedImages = await _picker.pickMultiImage();
return pickedImages.isNotEmpty ? pickedImages : null;
});
static Future<XFile?> singleGalleryPick(BuildContext context) =>
_guarded(context, () => _picker.pickImage(source: ImageSource.gallery));
static Future<XFile?> cameraPick(BuildContext context) =>
_guarded(context, () => _picker.pickImage(source: ImageSource.camera));
static Future<List<String>?> documentPick() async {
final result = await FilePicker.pickFiles(allowMultiple: true);
return result?.files.map((e) => e.path).nonNulls.toList();
}
static Future<T?> _guarded<T>(
BuildContext context,
Future<T?> 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');
}
}