useStorageFile function
Returns a StorageFileResult
that can be used to first select a file and
then upload that file to Firebase Storage.
This delegates work to FilePicker and can be managed by calling methods
on StorageFileResult.fileHandler
.
StorageFileResult.fileHandler.selectFile()
Once a file has been selected, to commit the file to Firebase Storage, you
simply need to commit
that file which will upload the file to Firebase.
When true, generateUniqueFileName
will append a 5 character to the file
name to ensure it is unique in the database. This may not be desirable
however if you'd like the previous file to be deleted or overwritten.
Example:
'my coolPicture.jpg' -> '6a9h4_my_coolPicture.jpg'
Implementation
StorageFileHandler<PlatformFile, String> useStorageFile({
required Reference reference,
required FileType fileType,
required String Function(String fileName) fileNameBuilder,
List<String>? allowedExtensions,
SettableMetadata? settableMetadata,
}) {
const nothingSnapshot =
AsyncSnapshotWithProgress<String, TaskSnapshot>.nothing();
final snapshotListenable = useValueNotifier(nothingSnapshot);
final streamSubscription = useRef<StreamSubscription?>(null);
final isMounted = useIsMounted();
final fileHandler = useFile(
fileType: fileType,
allowedExtensions: allowedExtensions,
);
final remoteFilePath = useState<String?>(null);
void clearError() {
snapshotListenable.value = nothingSnapshot;
}
Future<CommitHandler<String>> commit(PlatformFile platformFile) async {
final completer = Completer<CommitHandler<String>>();
if (streamSubscription.value != null) {
completer.completeError('Stream upload already in progress');
}
clearError();
try {
final filePathName = platformFile.name;
final fileName = fileNameBuilder(filePathName);
final childReference = reference.child(fileName);
final UploadTask uploadTask;
// TODO: Check if file exists with current name.
// Web must work off bytes, no filePath
if (kIsWeb) {
uploadTask = childReference.putData(
platformFile.bytes!,
settableMetadata,
);
} else {
final filePath = platformFile.path;
uploadTask = childReference.putFile(
File(filePath!),
settableMetadata,
);
}
streamSubscription.value = uploadTask.snapshotEvents.listen(
(TaskSnapshot snapshot) {
if (isMounted()) {
snapshotListenable.value =
AsyncSnapshotWithProgress<String, TaskSnapshot>.waiting(
snapshot,
);
}
},
onError: (Object _error, StackTrace _stackTrace) {
completer.completeError(_error, _stackTrace);
if (isMounted()) {
snapshotListenable.value =
AsyncSnapshotWithProgress<String, TaskSnapshot>.withError(
ConnectionState.active,
_error,
_stackTrace,
);
}
},
cancelOnError: true,
);
await uploadTask;
final _remoteFilePath = childReference.fullPath;
if (isMounted()) {
snapshotListenable.value =
AsyncSnapshotWithProgress<String, TaskSnapshot>.withData(
ConnectionState.done,
_remoteFilePath,
);
remoteFilePath.value = _remoteFilePath;
}
completer.complete(
CommitHandler(
value: childReference.fullPath,
revert: () async {
await childReference.delete();
},
),
);
} catch (_error, _stackTrace) {
completer.completeError(_error, _stackTrace);
if (isMounted()) {
snapshotListenable.value =
AsyncSnapshotWithProgress<String, TaskSnapshot>.withError(
ConnectionState.done,
_error,
_stackTrace,
);
}
} finally {
streamSubscription.value?.cancel();
streamSubscription.value = null;
}
return completer.future;
}
FutureOr<CommitHandler<String>?> maybeCommit([
PlatformFile? platformFile,
]) {
if (platformFile != null) {
return commit(platformFile);
}
return fileHandler.snapshot.maybeWhen(data: commit, orElse: () => null);
}
return StorageFileHandler(
commit: commit,
maybeCommit: maybeCommit,
fileHandler: fileHandler,
snapshotListenable: snapshotListenable,
remoteFilePath: remoteFilePath.value,
);
}