derrick56007 / dropzone Goto Github PK
View Code? Open in Web Editor NEWA simple way to bring drag’n’drop to flutter web
Home Page: https://pub.dev/packages/drop_zone
License: MIT License
A simple way to bring drag’n’drop to flutter web
Home Page: https://pub.dev/packages/drop_zone
License: MIT License
I have a form with multiple video and image fields (in this case two video and one image). All have the DropZone is a Stack.
I get several errors:
1> The image does not display, just the videos. If I remove one of the video widget, the image is rendered.
2> When I push a camera widget and pop back I get errors like this:
══╡ EXCEPTION CAUGHT BY SCHEDULER LIBRARY ╞═════════════════════════════════════════════════════════
The following IndexError was thrown during a scheduler callback:
RangeError (index): Index out of range: index must not be negative: -1
Can you help identify the issue?
Hi Derrick,
I really interested with your package. But I can not use or something went wrong
onDrop: (List<html.File> files) {
always return error message "The getter 'uri' was called on null" and can not upload
Can you give advise?
Thank you
When using a DropZone
widget in a Flutter web app and using hot restart, the drop zone will stop working.
I investigated this and found out that the old listener is called instead of the new one after hot restart, i.e. the listener attached to the JS drop events survives the hot restart and no new listener is attached.
@derrick56007 do you have an idea how to fix this?
In this package are support multiple image to drop and preview show only the last image how to saw first image?
The last method is not available, and has to be added explicitly.
final name = file.name;
final mime = file.type;
final length = file.size;
final url = Url.createObjectUrlFromBlob(file);
I believe that a file.url will be a useful addition.
I want to convert it to Io.File or Uint8List format in order to upload. is there any possible way?
I have an iFrame component and I wish to use DropZone - the onDrag and onDrop are not triggered.
Don't know if this is an enhancement, bug or an issue on how I created the iFrame:
html.IFrameElement _iframeElement;
_iframeElement = html.IFrameElement();
_iframeElement.id = iFrameId;
_iframeElement.allow = 'accelerometer; gyroscope;';
_iframeElement.allowFullscreen = true;
_iframeElement.src = initialVideo;
_iframeElement.style.border = 'none';
_iframeElement.style.cursor = 'auto';
_iframeElement.style.width = '100%';
_iframeElement.style.height = '100%';
// ignore: undefined_prefixed_name
ui.platformViewRegistry.registerViewFactory(iFrameId, (int viewId) => _iframeElement);
videoWidget = HtmlElementView(
key: key,
viewType: iFrameId,
);
Hi @derrick56007 thanks for putting this library together. I tried a few for Flutter web and this one seems to work the best for us on various browsers. We ran into a few issues with bugs around multiple drop targets (need a single instance of the drag target), the mouse leaving the window, etc. So I copied your code and refactored it some.
Happy to issue a PR at some point but a bit swamped at the moment.
There are some pieces that are coupled to our codebase in here but thought it'd be better to share the code here to start a discussion.
A few high level points
e.stopPropagation()
for every widget it won't work for multiple widgets (event gets swallowed)._dragInBounds
updates to better deal with edge casesLet me know what you think
//@dart=2.12
// adapted from https://github.com/Derrick56007/dropzone
import 'dart:html';
import 'package:flutter/widgets.dart';
import 'package:turtle_app/file_manager/file_picker/html.dart';
import '../file_drop_target.dart';
import '../local_file.dart';
import 'package:turtle_app/util/event_handler.dart';
FileDropTarget createFileDropTarget({
Key? key,
required Widget child,
Function()? onEnter,
Function()? onExit,
Function(Iterable<LocalFile>)? onDrop,
}) =>
HtmlFileDropTarget(
key: key,
child: child,
onEnter: onEnter,
onExit: onExit,
onDrop: onDrop,
);
class HtmlFileDropTarget extends StatefulWidget implements FileDropTarget {
const HtmlFileDropTarget({
Key? key,
required this.child,
this.onEnter,
this.onExit,
this.onDrop,
}) : super(key: key);
final Widget child;
final Function()? onEnter;
final Function()? onExit;
final Function(Iterable<LocalFile>)? onDrop;
@override
State<StatefulWidget> createState() => _HtmlFileDropTargetState();
}
class _HtmlFileDropTargetState extends State<HtmlFileDropTarget> {
bool _dragInBounds = false;
final _dispose = <void Function()>[];
@override
void dispose() {
super.dispose();
for (final cb in _dispose) cb();
}
@override
void initState() {
super.initState();
_dispose.add(_controller.onDragEnter.addListener(_onDragEnter));
_dispose.add(_controller.onDragOver.addListener(_onDragOver));
_dispose.add(_controller.onDragLeave.addListener(_onDragLeave));
_dispose.add(_controller.onDragDrop.addListener(_onDragDrop));
}
@override
Widget build(BuildContext c) => widget.child;
void _onDragEnter(MouseEvent e) {
// can treat this like drag-over
_onDragOver(e);
}
void _onDragLeave(MouseEvent e) {
// mouse has left the window or drag region so consider this as onExit
_setDragInBounds(false);
}
void _onDragOver(MouseEvent e) {
final renderObject = context.findRenderObject();
if (renderObject == null) {
_setDragInBounds(false);
return;
}
final bounds = _getGlobalPaintBounds(renderObject);
_setDragInBounds(_isCursorWithinBounds(e, bounds));
}
void _onDragDrop(MouseEvent e) {
_setDragInBounds(false);
final htmlFiles = e.dataTransfer.files ?? [];
final localFiles = htmlFiles.map(castToFile);
widget.onDrop?.call(localFiles);
}
void _setDragInBounds(bool value) {
if (_dragInBounds == value) return;
_dragInBounds = value;
if (_dragInBounds) {
widget.onEnter?.call();
} else {
widget.onExit?.call();
}
}
}
Rect _getGlobalPaintBounds(RenderObject renderObject) {
final translation = renderObject.getTransformTo(null).getTranslation();
return renderObject.paintBounds.shift(Offset(translation.x, translation.y));
}
bool _isCursorWithinBounds(MouseEvent e, Rect bounds) {
return e.layer.x >= bounds.left &&
e.layer.x <= bounds.right &&
e.layer.y >= bounds.top &&
e.layer.y <= bounds.bottom;
}
class _HtmlFileDropTargetController {
_HtmlFileDropTargetController() {
final body = document.body!;
body.onDragEnter.listen(_onDragEnter);
body.onDragOver.listen(_onDragOver);
body.onDragLeave.listen(_onDragLeave);
body.onDrop.listen(_onDrop);
}
final onDragEnter = Event<MouseEvent>();
final onDragOver = Event<MouseEvent>();
final onDragLeave = Event<MouseEvent>();
final onDragDrop = Event<MouseEvent>();
void _onDragEnter(MouseEvent e) {
_stopEvent(e);
onDragEnter.notifyListeners(e);
}
void _onDragOver(MouseEvent e) {
_stopEvent(e);
onDragOver.notifyListeners(e);
}
void _onDragLeave(MouseEvent e) {
_stopEvent(e);
onDragLeave.notifyListeners(e);
}
void _onDrop(MouseEvent e) {
_stopEvent(e);
onDragDrop.notifyListeners(e);
}
}
final _controller = _HtmlFileDropTargetController();
void _stopEvent(MouseEvent e) {
e.stopPropagation();
e.stopImmediatePropagation();
e.preventDefault();
}
typedef EventHandler<T> = void Function(T event);
class Event<T> {
final _listeners = <EventHandler<T>>{};
void Function() addListener(EventHandler<T> listener) {
_listeners.add(listener);
return () => removeListener(listener);
}
void removeListener(EventHandler<T> listener) => _listeners.remove(listener);
void notifyListeners(T event) {
for (final listener in _listeners) listener(event);
}
void dispose() {
_listeners.clear();
}
}
Let me know if you have any questions on the changes in the code. Cheers!
Hi,
I would like to display a list with all files that will be uploaded. If I drop them on the drop zone this can be easily done using the onDrop method. I add the filenames to a list and call setState -> my view with a listview is updated.
It is handy that this library also provides a method to open a file picker. Usually both is needed. But if files were picked with that file picker, the on drop is not called. So my view is not updated.
Ho to solve that? Would it be an option to change this library to also call onDop if the filepickes is used?
It would be nice if this worked for Windows/Linux/Desktop
Am I doing something wrong? I pasted this into my .dart code and I get the following error:
The argument type 'Null Function(List<File>)' can't be assigned to the parameter type 'dynamic Function(List<File>?)?'.
Your sample code:
DropZone
(
onDragEnter: () { print('drag enter'); },
onDragExit: () { print('drag exit'); },
onDrop: (List<html.File> files) { print('files dropped'); print(files); },
child: Container ( width: 300, height: 300, )
)
I added the dependency to my pubspec.yaml and imported it.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.