Skip to content

[image_picker][web] cancel cause picker to never return #92176

@aoatmon

Description

@aoatmon

Steps to Reproduce

  • clone this repository or use the code sample below
  • run flutter run -d chrome
  • tap the fab
  • when the picker window show up choose cancel

Expected results:

  • should return null

Actual results:

  • never returns
code sample
import 'package:flutter/material.dart';
import 'package:image_picker/image_picker.dart';

void main() {
  runApp(const PickerFilesProvider(child: MaterialApp(home: MyHomePage())));
}

Future<Iterable<XFile>> pickFiles() async {
  try {
    final maybeFiles = await ImagePicker().pickMultiImage();
    return [if (maybeFiles != null) ...maybeFiles];
  } on Exception catch (e, s) {
    debugPrint('$e, $s');
    return [];
  } on Error catch (e) {
    debugPrint('$e, ${e.stackTrace}');
    return [];
  }
}

extension XfilesNamesX on Iterable<XFile> {
  Iterable<String> get names sync* {
    for (final file in this) {
      yield file.name;
    }
  }
}

class PickerFilesProvider extends StatefulWidget {
  final Widget child;
  const PickerFilesProvider({
    required this.child,
  }) : super(key: const ValueKey('PickerFilesProvider'));

  @override
  State<PickerFilesProvider> createState() => _PickerFilesProviderState();
}

class _PickerFilesProviderState extends State<PickerFilesProvider> {
  late final ValueNotifier<Iterable<String>> _notifier;

  @override
  void initState() {
    super.initState();
    _notifier = ValueNotifier(<String>[]);
  }

  @override
  void dispose() {
    _notifier.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return _PickedFiles(
      child: widget.child,
      notifier: _notifier,
    );
  }
}

class _PickedFiles extends InheritedWidget {
  final ValueNotifier<Iterable<String>> notifier;
  const _PickedFiles({
    required this.notifier,
    required Widget child,
  }) : super(key: const ValueKey('PickedFiles'), child: child);

  static _PickedFiles of(BuildContext context) {
    final _PickedFiles? result =
        context.dependOnInheritedWidgetOfExactType<_PickedFiles>();
    assert(result != null, 'No PickedFiles found in context');
    return result!;
  }

  @override
  // ignore: avoid_renaming_method_parameters
  bool updateShouldNotify(_) => false;
}

extension PickedFilesX on BuildContext {
  ValueNotifier<Iterable<String>> get pickerfiles =>
      _PickedFiles.of(this).notifier;
}

class PickerButton extends StatefulWidget {
  const PickerButton({
    final key = const ValueKey('PickerButton'),
  }) : super(key: key);

  @override
  State<PickerButton> createState() => _PickerWidgetState();
}

class _PickerWidgetState extends State<PickerButton> {
  late final ValueNotifier<bool> _busy;

  @override
  void initState() {
    super.initState();
    _busy = ValueNotifier(false);
  }

  @override
  void dispose() {
    _busy.dispose();
    super.dispose();
  }

  void _pickFiles() async {
    _busy.value = true;
    context.pickerfiles.value = (await pickFiles()).names;
    _busy.value = false;
  }

  @override
  Widget build(BuildContext context) {
    return FloatingActionButton(
      child: ValueListenableBuilder<bool>(
          valueListenable: _busy,
          builder: (context, busy, _) => busy
              ? const CircularProgressIndicator(color: Colors.black)
              : const Icon(Icons.upload)),
      onPressed: _pickFiles,
    );
  }
}

class MyHomePage extends StatelessWidget {
  const MyHomePage({
    final key = const ValueKey('MyHomePage'),
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return const Scaffold(
      body: PickedFilesListView(),
      floatingActionButton: PickerButton(),
    );
  }
}

class PickedFilesListView extends StatelessWidget {
  const PickedFilesListView({
    final key = const ValueKey('PickedFilesListView'),
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return ValueListenableBuilder<Iterable<String>>(
      valueListenable: context.pickerfiles,
      builder: (context, names, _) => ListView(children: [
        for (final name in names) Center(child: Text(name)),
      ]),
    );
  }
}
pubspec
environment:
  sdk: '>=2.14.3 <3.0.0'
  flutter: ^2.5.2

dependencies:
  flutter:
    sdk: flutter
  image_picker: ^0.8.4

dev_dependencies:
  flutter_lints: ^1.0.4

flutter:
  uses-material-design: true
doctor
[✓] Flutter (Channel stable, 2.5.3, on macOS 11.6 20G165 darwin-x64, locale en-EE)
    • Flutter version 2.5.3 at /Users/francesco/fvm/versions/stable
    • Upstream repository https://github.com/flutter/flutter.git
    • Framework revision 18116933e7 (5 days ago), 2021-10-15 10:46:35 -0700
    • Engine revision d3ea636dc5
    • Dart version 2.14.4

[✓] Android toolchain - develop for Android devices (Android SDK version 30.0.3)
    • Android SDK at /Users/francesco/Library/Android/sdk
    • Platform android-30, build-tools 30.0.3
    • Java binary at: /Applications/Android Studio.app/Contents/jre/Contents/Home/bin/java
    • Java version OpenJDK Runtime Environment (build 11.0.10+0-b96-7281165)
    • All Android licenses accepted.

[✓] Xcode - develop for iOS and macOS
    • Xcode at /Applications/Xcode.app/Contents/Developer
    • Xcode 13.0, Build version 13A233
    • CocoaPods version 1.11.0

[✓] Chrome - develop for the web
    • Chrome at /Applications/Google Chrome.app/Contents/MacOS/Google Chrome

[✓] Android Studio (version 2020.3)
    • Android Studio at /Applications/Android Studio.app/Contents
    • Flutter plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/9212-flutter
    • Dart plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/6351-dart
    • Java version OpenJDK Runtime Environment (build 11.0.10+0-b96-7281165)

[✓] VS Code (version 1.61.2)
    • VS Code at /Applications/Visual Studio Code.app/Contents
    • Flutter extension version 3.27.0

[✓] Connected device (3 available)
    • Pixel 3a (mobile) • 965AY0WP5C • android-arm64  • Android 11 (API 30)
    • macOS (desktop)   • macos      • darwin-x64     • macOS 11.6 20G165 darwin-x64
    • Chrome (web)      • chrome     • web-javascript • Google Chrome 94.0.4606.81

• No issues found!

Metadata

Metadata

Assignees

No one assigned

    Labels

    P2Important issues not at the top of the work listfound in release: 3.10Found to occur in 3.10found in release: 3.11Found to occur in 3.11has reproducible stepsThe issue has been confirmed reproducible and is ready to work onp: image_pickerThe Image Picker plugin.packageflutter/packages repository. See also p: labels.platform-webWeb applications specificallyr: fixedIssue is closed as already fixed in a newer versionteam-webOwned by Web platform teamtriaged-webTriaged by Web platform team

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions