Skip to content

[desktop_drop]: support multiple DropTarget and improve web handling #235

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 8 additions & 11 deletions packages/desktop_drop/example/lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -51,28 +51,28 @@ class _ExampleDragTargetState extends State<ExampleDragTarget> {
@override
Widget build(BuildContext context) {
return DropTarget(
onDragDone: (detail) async {
onDragDone: (files, location) async {
setState(() {
_list.addAll(detail.files);
_list.addAll(files);
});

debugPrint('onDragDone:');
for (final file in detail.files) {
for (final file in files) {
debugPrint(' ${file.path} ${file.name}'
' ${await file.lastModified()}'
' ${await file.length()}'
' ${file.mimeType}');
}
},
onDragUpdated: (details) {
onDragUpdated: (localPosition) {
setState(() {
offset = details.localPosition;
offset = localPosition;
});
},
onDragEntered: (detail) {
onDragEntered: (localPosition) {
setState(() {
_dragging = true;
offset = detail.localPosition;
offset = localPosition;
});
},
onDragExited: (detail) {
Expand All @@ -87,10 +87,7 @@ class _ExampleDragTargetState extends State<ExampleDragTarget> {
color: _dragging ? Colors.blue.withOpacity(0.4) : Colors.black26,
child: Stack(
children: [
if (_list.isEmpty)
const Center(child: Text("Drop here"))
else
Text(_list.map((e) => e.path).join("\n")),
if (_list.isEmpty) const Center(child: Text("Drop here")) else Text(_list.map((e) => e.path).join("\n")),
if (offset != null)
Align(
alignment: Alignment.topRight,
Expand Down
2 changes: 1 addition & 1 deletion packages/desktop_drop/example/macos/Podfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ EXTERNAL SOURCES:

SPEC CHECKSUMS:
desktop_drop: 69eeff437544aa619c8db7f4481b3a65f7696898
FlutterMacOS: 8f6f14fa908a6fb3fba0cd85dbd81ec4b251fb24
FlutterMacOS: ae6af50a8ea7d6103d888583d46bd8328a7e9811

PODFILE CHECKSUM: 353c8bcc5d5b0994e508d035b5431cfe18c1dea7

Expand Down
30 changes: 15 additions & 15 deletions packages/desktop_drop/example/pubspec.lock
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,10 @@ packages:
dependency: transitive
description:
name: collection
sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a
sha256: f092b211a4319e98e5ff58223576de6c2803db36221657b46c82574721240687
url: "https://pub.dev"
source: hosted
version: "1.18.0"
version: "1.17.2"
cross_file:
dependency: "direct main"
description:
Expand All @@ -53,10 +53,10 @@ packages:
dependency: "direct main"
description:
name: cupertino_icons
sha256: "486b7bc707424572cdf7bd7e812a0c146de3fd47ecadf070254cc60383f21dd8"
sha256: e35129dc44c9118cee2a5603506d823bab99c68393879edb440e0090d07586be
url: "https://pub.dev"
source: hosted
version: "1.0.3"
version: "1.0.5"
desktop_drop:
dependency: "direct main"
description:
Expand Down Expand Up @@ -131,10 +131,10 @@ packages:
dependency: transitive
description:
name: meta
sha256: a6e590c838b18133bb482a2745ad77c5bb7715fb0451209e1a7567d416678b8e
sha256: "3c74dbf8763d36539f114c799d8a2d87343b5067e9d796ca22b5eb8437090ee3"
url: "https://pub.dev"
source: hosted
version: "1.10.0"
version: "1.9.1"
path:
dependency: transitive
description:
Expand All @@ -160,18 +160,18 @@ packages:
dependency: transitive
description:
name: stack_trace
sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b"
sha256: c3c7d8edb15bee7f0f74debd4b9c5f3c2ea86766fe4178eb2a18eb30a0bdaed5
url: "https://pub.dev"
source: hosted
version: "1.11.1"
version: "1.11.0"
stream_channel:
dependency: transitive
description:
name: stream_channel
sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7
sha256: "83615bee9045c1d322bbbd1ba209b7a749c2cbcdcb3fdd1df8eb488b3279c1c8"
url: "https://pub.dev"
source: hosted
version: "2.1.2"
version: "2.1.1"
string_scanner:
dependency: transitive
description:
Expand All @@ -192,10 +192,10 @@ packages:
dependency: transitive
description:
name: test_api
sha256: "5c2f730018264d276c20e4f1503fd1308dfbbae39ec8ee63c5236311ac06954b"
sha256: "75760ffd7786fffdfb9597c35c5b27eaeec82be8edfb6d71d32651128ed7aab8"
url: "https://pub.dev"
source: hosted
version: "0.6.1"
version: "0.6.0"
vector_math:
dependency: transitive
description:
Expand All @@ -208,10 +208,10 @@ packages:
dependency: transitive
description:
name: web
sha256: "14f1f70c51119012600c5f1f60ca68efda5a9b6077748163c6af2893ec5df8fc"
sha256: dc8ccd225a2005c1be616fe02951e2e342092edf968cf0844220383757ef8f10
url: "https://pub.dev"
source: hosted
version: "0.2.1-beta"
version: "0.1.4-beta"
sdks:
dart: ">=3.2.0-157.0.dev <4.0.0"
dart: ">=3.1.0-185.0.dev <4.0.0"
flutter: ">=1.20.0"
147 changes: 92 additions & 55 deletions packages/desktop_drop/lib/desktop_drop_web.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import 'dart:async';
import 'dart:html' as html show window, Url;
import 'dart:html' as html show window, Url, DataTransfer;

import 'package:flutter/cupertino.dart';
import 'package:flutter/services.dart';
Expand All @@ -25,66 +25,103 @@ class DesktopDropWeb {
pluginInstance._registerEvents();
}

html.DataTransfer? __dataTransfer;

html.DataTransfer? get _dataTransfer => __dataTransfer;

set _dataTransfer(html.DataTransfer? newValue) {
if (__dataTransfer != newValue) {
if (__dataTransfer != null) {
newValue?.dropEffect = __dataTransfer!.dropEffect;
}
__dataTransfer = newValue;
}
}

void _registerEvents() {
html.window.onDrop.listen((event) {
event.preventDefault();

final results = <WebDropItem>[];

try {
final items = event.dataTransfer.files;
if (items != null) {
for (final item in items) {
results.add(
WebDropItem(
uri: html.Url.createObjectUrl(item),
name: item.name,
size: item.size,
type: item.type,
relativePath: item.relativePath,
lastModified: item.lastModified != null
? DateTime.fromMillisecondsSinceEpoch(item.lastModified!)
: item.lastModifiedDate,
),
);
html.window.onDragEnter.listen(
(event) {
event.preventDefault();
_dataTransfer = event.dataTransfer;
channel.invokeMethod('entered', [
event.client.x.toDouble(),
event.client.y.toDouble(),
]);
},
);

html.window.onDragOver.listen(
(event) {
event.preventDefault();
_dataTransfer = event.dataTransfer;
channel.invokeMethod('updated', [
event.client.x.toDouble(),
event.client.y.toDouble(),
]);
},
);

html.window.onDrop.listen(
(event) {
event.preventDefault();
_dataTransfer = null;
final results = <WebDropItem>[];

try {
final items = event.dataTransfer.files;
if (items != null) {
for (final item in items) {
results.add(
WebDropItem(
uri: html.Url.createObjectUrl(item),
name: item.name,
size: item.size,
type: item.type,
relativePath: item.relativePath,
lastModified: item.lastModified != null
? DateTime.fromMillisecondsSinceEpoch(item.lastModified!)
: item.lastModifiedDate,
),
);
}
}
} catch (e, s) {
debugPrint('desktop_drop_web: $e $s');
} finally {
channel.invokeMethod(
"performOperation_web",
results.map((e) => e.toJson()).toList(),
);
}
} catch (e, s) {
debugPrint('desktop_drop_web: $e $s');
} finally {
channel.invokeMethod(
"performOperation_web",
results.map((e) => e.toJson()).toList(),
);
}
});

html.window.onDragEnter.listen((event) {
event.preventDefault();
channel.invokeMethod('entered', [
event.client.x.toDouble(),
event.client.y.toDouble(),
]);
});

html.window.onDragOver.listen((event) {
event.preventDefault();
channel.invokeMethod('updated', [
event.client.x.toDouble(),
event.client.y.toDouble(),
]);
});

html.window.onDragLeave.listen((event) {
event.preventDefault();
channel.invokeMethod('exited', [
event.client.x.toDouble(),
event.client.y.toDouble(),
]);
});
},
);

html.window.onDragLeave.listen(
(event) {
event.preventDefault();
_dataTransfer = null;
channel.invokeMethod('exited', [
event.client.x.toDouble(),
event.client.y.toDouble(),
]);
},
);
}

Future<dynamic> handleMethodCall(MethodCall call) async {
switch (call.method) {
case 'updateDroppableStatus':
final enable = call.arguments as bool;
final current = _dataTransfer?.dropEffect;
final newValue = enable ? 'copy' : 'move';
if (current != newValue) {
_dataTransfer?.dropEffect = newValue;
}
return;
default:
break;
}

throw PlatformException(
code: 'Unimplemented',
details: 'desktop_drop for web doesn\'t implement \'${call.method}\'',
Expand Down
Loading