pickFiles method
Picks files from the device storage based on the provided options.
Platform implementations should override this method to handle file picking on their respective platforms.
Implementation
@override
Future<List<PickedFile>?> pickFiles(FilePickerOptions options) async {
final completer = Completer<List<PickedFile>?>();
try {
final input = html.FileUploadInputElement();
input.style.display = 'none';
// Set accept attribute based on file type
input.accept = _getAcceptString(options.type, options.allowedExtensions);
// Set multiple selection
input.multiple = options.allowMultiple;
// Add to DOM
html.document.body?.append(input);
// Set up event listeners
input.onChange.listen((event) async {
final files = input.files;
if (files != null && files.isNotEmpty) {
final pickedFiles = <PickedFile>[];
for (final file in files) {
try {
final pickedFile = await _processWebFile(file, options);
if (pickedFile != null) {
pickedFiles.add(pickedFile);
}
} catch (e) {
debugPrint('Error processing file ${file.name}: $e');
}
}
// Remove input from DOM
input.remove();
completer.complete(pickedFiles.isEmpty ? null : pickedFiles);
} else {
input.remove();
completer.complete(null);
}
});
input.onError.listen((event) {
input.remove();
completer.complete(null);
});
// Handle cancel (when user closes dialog without selecting)
final cancelTimer = Timer(const Duration(minutes: 5), () {
if (!completer.isCompleted) {
input.remove();
completer.complete(null);
}
});
// Detect window focus to handle cancel
html.window.onFocus.listen((event) {
Timer(const Duration(milliseconds: 500), () {
if (!completer.isCompleted && (input.files?.isEmpty ?? true)) {
cancelTimer.cancel();
input.remove();
completer.complete(null);
}
});
});
// Trigger file picker
input.click();
} catch (e) {
completer.complete(null);
}
return completer.future;
}