Provides common and reuseable hooks for firebase_storage. Functions include selecting and uploading files.

Features

Easily replace the workflow around getting a file from the user and then uploading it to firebase storage. Nice features include the ability to revert uploads, retry failed uploads and individually track the progress of each file transfer.

Note

This package depends on file_picker to select files from local storage. Please create an issue if this creates any problems.

Getting started

firebase_storage is required as well as flutter_hooks. To install:

    firebase_storage_hooks:

Usage

To select an arbitrary file use the useFile hook.

class MyHomePage extends HookWidget {
  const MyHomePage({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    final fileHandler = useFile(fileType: FileType.image);

    return Scaffold(
      appBar: AppBar(),
      floatingActionButton: FloatingActionButton(
        onPressed: () async {
          await fileHandler.select();
        },
      ),
      body: Builder(
        builder: (context) {
          if (fileHandler.snapshot.hasError) {
            return Center(
              child: Text(fileHandler.snapshot.error.toString()),
            );
          } else if (fileHandler.snapshot.hasData) {
            final file = fileHandler.snapshot.data!;

            if (kIsWeb) {
              return Image.memory(file.bytes!);
            } else {
              return Image.file(File(file.path!));
            }
          } else {
            return const Center(
              child: CircularProgressIndicator(),
            );
          }
        },
      ),
    );
  }
}

The hook in itself isn't incredibly useful but it does compose nicely into the next hook which manages a Firebase Storage file.

class FirebaseImagePage extends HookWidget {
  const FirebaseImagePage({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    final storageFileHandler = useStorageFile(
      fileType: FileType.image,
      reference: FirebaseStorage.instance.ref(),
    );

    return Scaffold(
      appBar: AppBar(),
      floatingActionButton: FloatingActionButton(
        onPressed: () async {
          await storageFileHandler.fileHandler.select();
        },
      ),
      body: Builder(
        builder: (context) {
          final fileSnapshot = storageFileHandler.fileHandler.snapshot;

          if (fileSnapshot.hasError) {
            return Center(
              child: Text(fileSnapshot.error.toString()),
            );
          } else if (fileSnapshot.hasData) {
            final file = fileSnapshot.data!;

            final image = (kIsWeb
                ? MemoryImage(file.bytes!)
                : FileImage(File(file.path!))) as ImageProvider;

            return Ink.image(
              image: image,
              child: InkWell(
                onTap: () async {
                  final commitHandler = await storageFileHandler.commit();

                  ScaffoldMessenger.of(context).showSnackBar(
                    SnackBar(
                      content: Text(
                        'Committed image to ${commitHandler.value}',
                      ),
                      action: SnackBarAction(
                        onPressed: commitHandler.revert,
                        label: 'Undo',
                      ),
                    ),
                  );
                },
              ),
            );
          } else {
            return const Center(
              child: CircularProgressIndicator(),
            );
          }
        },
      ),
    );
  }
}

The next step will possibly to create widgets that wrap around hooks for common scenerios.

Note This package is not yet recommended for production.

Additional information

Issues and PRs welcome.