63 lines
1.7 KiB
Dart
63 lines
1.7 KiB
Dart
import 'package:file_picker/file_picker.dart';
|
|
import 'package:flutter/services.dart';
|
|
|
|
import '../utils/app_logger.dart';
|
|
|
|
/// Serializes file_picker invocations to avoid
|
|
/// `PlatformException(already_active, File picker is already active)`.
|
|
class FilePickerService {
|
|
static final FilePickerService _instance = FilePickerService._();
|
|
static FilePickerService get instance => _instance;
|
|
FilePickerService._();
|
|
|
|
bool _active = false;
|
|
|
|
Future<T?> _guard<T>(String opName, Future<T?> Function() body) async {
|
|
if (_active) return null;
|
|
_active = true;
|
|
try {
|
|
return await body();
|
|
} on PlatformException catch (e, st) {
|
|
if (e.code == 'already_active') return null;
|
|
appLogger.e('FilePicker.$opName failed', error: e, stackTrace: st);
|
|
rethrow;
|
|
} finally {
|
|
_active = false;
|
|
}
|
|
}
|
|
|
|
Future<FilePickerResult?> pickFiles({
|
|
FileType type = FileType.any,
|
|
List<String>? allowedExtensions,
|
|
bool withData = false,
|
|
}) {
|
|
return _guard(
|
|
'pickFiles',
|
|
() => FilePicker.platform.pickFiles(type: type, allowedExtensions: allowedExtensions, withData: withData),
|
|
);
|
|
}
|
|
|
|
Future<String?> getDirectoryPath({String? dialogTitle}) {
|
|
return _guard('getDirectoryPath', () => FilePicker.platform.getDirectoryPath(dialogTitle: dialogTitle));
|
|
}
|
|
|
|
Future<String?> saveFile({
|
|
String? dialogTitle,
|
|
String? fileName,
|
|
Uint8List? bytes,
|
|
FileType type = FileType.any,
|
|
List<String>? allowedExtensions,
|
|
}) {
|
|
return _guard(
|
|
'saveFile',
|
|
() => FilePicker.platform.saveFile(
|
|
dialogTitle: dialogTitle,
|
|
fileName: fileName,
|
|
bytes: bytes,
|
|
type: type,
|
|
allowedExtensions: allowedExtensions,
|
|
),
|
|
);
|
|
}
|
|
}
|