selectWebFiles function

Future<List<File>> selectWebFiles({
  1. bool allowMultiple = false,
  2. List<String> acceptedFileTypes = const [],
})

Selects files using the browser's native file picker without loading file contents.

Implementation

Future<List<web.File>> selectWebFiles({
  bool allowMultiple = false,
  List<String> acceptedFileTypes = const [],
}) {
  final completer = Completer<List<web.File>>();

  if (kTesting) print('[selectWebFiles] Creating file input element');

  // Create a temporary file input element
  final input = web.document.createElement('input') as web.HTMLInputElement;
  input.type = 'file';

  // Configure input element
  if (allowMultiple) {
    input.multiple = true;
    if (kTesting) print('[selectWebFiles] Multiple selection enabled');
  }

  // Handle accepted file types
  if (acceptedFileTypes.isNotEmpty) {
    // Special case: if the only item is '*', don't set any accept filter (accept all)
    if (acceptedFileTypes.length == 1 && acceptedFileTypes[0] == '*') {
      if (kTesting) print('[selectWebFiles] Accept all file types (*)');
    } else {
      input.accept = acceptedFileTypes.join(',');
      if (kTesting)
        print('[selectWebFiles] Accept types: ${acceptedFileTypes.join(',')}');
    }
  }

  // Hide the input element
  input.style.display = 'none';

  // Add the input to the document body
  web.document.body?.appendChild(input);
  if (kTesting) print('[selectWebFiles] Input added to document body');

  // Handle file selection
  input.addEventListener(
    'change',
    (web.Event event) {
      if (kTesting) print('[selectWebFiles] Change event fired');

      final selectedFiles = <web.File>[];

      if (input.files != null) {
        final files = input.files!;
        if (kTesting) print('[selectWebFiles] ${files.length} files selected');

        // Convert FileList to List<File>
        for (var i = 0; i < files.length; i++) {
          final file = files.item(i);
          if (file != null) {
            if (kTesting) {
              print(
                  '[selectWebFiles] File: ${file.name}, size: ${file.size} bytes');
            }
            selectedFiles.add(file);
          }
        }
      }

      // Clean up
      web.document.body?.removeChild(input);
      if (kTesting) print('[selectWebFiles] Input removed from document');

      // Return the selected files
      completer.complete(selectedFiles);
    }.toJS,
  );

  // Open the file picker dialog
  if (kTesting) print('[selectWebFiles] Opening file picker dialog');
  input.click();

  // Set a safety timeout (2 minutes)
  Timer(Duration(minutes: 2), () {
    if (!completer.isCompleted) {
      if (kTesting)
        print('[selectWebFiles] Timeout reached, assuming no files selected');
      try {
        web.document.body?.removeChild(input);
      } catch (_) {
        // Element might have been removed already
      }
      completer.complete([]);
    }
  });

  return completer.future;
}