Skip to content

Commit 0cd7624

Browse files
committed
feat: refactor to use RenderObjects instead of widgets
1 parent fe53a9d commit 0cd7624

File tree

9 files changed

+206
-262
lines changed

9 files changed

+206
-262
lines changed

packages/desktop_drop/example/lib/main.dart

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -51,28 +51,28 @@ class _ExampleDragTargetState extends State<ExampleDragTarget> {
5151
@override
5252
Widget build(BuildContext context) {
5353
return DropTarget(
54-
onDragDone: (detail) async {
54+
onDragDone: (files, location) async {
5555
setState(() {
56-
_list.addAll(detail.files);
56+
_list.addAll(files);
5757
});
5858

5959
debugPrint('onDragDone:');
60-
for (final file in detail.files) {
60+
for (final file in files) {
6161
debugPrint(' ${file.path} ${file.name}'
6262
' ${await file.lastModified()}'
6363
' ${await file.length()}'
6464
' ${file.mimeType}');
6565
}
6666
},
67-
onDragUpdated: (details) {
67+
onDragUpdated: (localPosition) {
6868
setState(() {
69-
offset = details.localPosition;
69+
offset = localPosition;
7070
});
7171
},
72-
onDragEntered: (detail) {
72+
onDragEntered: (localPosition) {
7373
setState(() {
7474
_dragging = true;
75-
offset = detail.localPosition;
75+
offset = localPosition;
7676
});
7777
},
7878
onDragExited: (detail) {
@@ -87,10 +87,7 @@ class _ExampleDragTargetState extends State<ExampleDragTarget> {
8787
color: _dragging ? Colors.blue.withOpacity(0.4) : Colors.black26,
8888
child: Stack(
8989
children: [
90-
if (_list.isEmpty)
91-
const Center(child: Text("Drop here"))
92-
else
93-
Text(_list.map((e) => e.path).join("\n")),
90+
if (_list.isEmpty) const Center(child: Text("Drop here")) else Text(_list.map((e) => e.path).join("\n")),
9491
if (offset != null)
9592
Align(
9693
alignment: Alignment.topRight,

packages/desktop_drop/example/macos/Podfile.lock

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ EXTERNAL SOURCES:
1515

1616
SPEC CHECKSUMS:
1717
desktop_drop: 69eeff437544aa619c8db7f4481b3a65f7696898
18-
FlutterMacOS: 8f6f14fa908a6fb3fba0cd85dbd81ec4b251fb24
18+
FlutterMacOS: ae6af50a8ea7d6103d888583d46bd8328a7e9811
1919

2020
PODFILE CHECKSUM: 353c8bcc5d5b0994e508d035b5431cfe18c1dea7
2121

packages/desktop_drop/example/pubspec.lock

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -37,10 +37,10 @@ packages:
3737
dependency: transitive
3838
description:
3939
name: collection
40-
sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a
40+
sha256: f092b211a4319e98e5ff58223576de6c2803db36221657b46c82574721240687
4141
url: "https://pub.dev"
4242
source: hosted
43-
version: "1.18.0"
43+
version: "1.17.2"
4444
cross_file:
4545
dependency: "direct main"
4646
description:
@@ -53,10 +53,10 @@ packages:
5353
dependency: "direct main"
5454
description:
5555
name: cupertino_icons
56-
sha256: "486b7bc707424572cdf7bd7e812a0c146de3fd47ecadf070254cc60383f21dd8"
56+
sha256: e35129dc44c9118cee2a5603506d823bab99c68393879edb440e0090d07586be
5757
url: "https://pub.dev"
5858
source: hosted
59-
version: "1.0.3"
59+
version: "1.0.5"
6060
desktop_drop:
6161
dependency: "direct main"
6262
description:
@@ -131,10 +131,10 @@ packages:
131131
dependency: transitive
132132
description:
133133
name: meta
134-
sha256: a6e590c838b18133bb482a2745ad77c5bb7715fb0451209e1a7567d416678b8e
134+
sha256: "3c74dbf8763d36539f114c799d8a2d87343b5067e9d796ca22b5eb8437090ee3"
135135
url: "https://pub.dev"
136136
source: hosted
137-
version: "1.10.0"
137+
version: "1.9.1"
138138
path:
139139
dependency: transitive
140140
description:
@@ -160,18 +160,18 @@ packages:
160160
dependency: transitive
161161
description:
162162
name: stack_trace
163-
sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b"
163+
sha256: c3c7d8edb15bee7f0f74debd4b9c5f3c2ea86766fe4178eb2a18eb30a0bdaed5
164164
url: "https://pub.dev"
165165
source: hosted
166-
version: "1.11.1"
166+
version: "1.11.0"
167167
stream_channel:
168168
dependency: transitive
169169
description:
170170
name: stream_channel
171-
sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7
171+
sha256: "83615bee9045c1d322bbbd1ba209b7a749c2cbcdcb3fdd1df8eb488b3279c1c8"
172172
url: "https://pub.dev"
173173
source: hosted
174-
version: "2.1.2"
174+
version: "2.1.1"
175175
string_scanner:
176176
dependency: transitive
177177
description:
@@ -192,10 +192,10 @@ packages:
192192
dependency: transitive
193193
description:
194194
name: test_api
195-
sha256: "5c2f730018264d276c20e4f1503fd1308dfbbae39ec8ee63c5236311ac06954b"
195+
sha256: "75760ffd7786fffdfb9597c35c5b27eaeec82be8edfb6d71d32651128ed7aab8"
196196
url: "https://pub.dev"
197197
source: hosted
198-
version: "0.6.1"
198+
version: "0.6.0"
199199
vector_math:
200200
dependency: transitive
201201
description:
@@ -208,10 +208,10 @@ packages:
208208
dependency: transitive
209209
description:
210210
name: web
211-
sha256: "14f1f70c51119012600c5f1f60ca68efda5a9b6077748163c6af2893ec5df8fc"
211+
sha256: dc8ccd225a2005c1be616fe02951e2e342092edf968cf0844220383757ef8f10
212212
url: "https://pub.dev"
213213
source: hosted
214-
version: "0.2.1-beta"
214+
version: "0.1.4-beta"
215215
sdks:
216-
dart: ">=3.2.0-157.0.dev <4.0.0"
216+
dart: ">=3.1.0-185.0.dev <4.0.0"
217217
flutter: ">=1.20.0"

packages/desktop_drop/lib/src/channel.dart

Lines changed: 70 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,19 @@
11
import 'dart:convert';
22

3+
import 'package:collection/collection.dart';
34
import 'package:cross_file/cross_file.dart';
5+
import 'package:flutter/rendering.dart';
46
import 'package:flutter/services.dart';
57
import 'package:flutter/widgets.dart';
68

79
import 'drop_item.dart';
810
import 'events.dart';
9-
import 'utils/platform.dart' if (dart.library.html) 'utils/platform_web.dart';
1011

1112
abstract class RawDropListener {
12-
void onEvent(DropEvent event);
13-
bool isInBounds(DropEvent event);
13+
/// Returns true if event was handled, false otherwise
14+
bool handleDropEvent(DropEvent event);
15+
16+
Offset globalToLocalOffset(Offset global);
1417
}
1518

1619
class DesktopDrop {
@@ -20,10 +23,9 @@ class DesktopDrop {
2023

2124
static final instance = DesktopDrop._();
2225

23-
final _listeners = <RawDropListener>{};
24-
2526
var _initialized = false;
2627

28+
RawDropListener? _currentTargetListener;
2729
Offset? _offset;
2830

2931
void init() {
@@ -47,25 +49,25 @@ class DesktopDrop {
4749
case "entered":
4850
final position = (call.arguments as List).cast<double>();
4951
_offset = Offset(position[0], position[1]);
50-
_notifyEvent(DropEnterEvent(location: _offset!));
52+
_notifyPositionEvent(DropEnterEvent(location: _offset!));
5153
break;
5254
case "updated":
5355
final position = (call.arguments as List).cast<double>();
5456
final previousOffset = _offset;
5557
_offset = Offset(position[0], position[1]);
5658
if (previousOffset == null) {
57-
_notifyEvent(DropEnterEvent(location: _offset!));
59+
_notifyPositionEvent(DropEnterEvent(location: _offset!));
5860
} else {
59-
_notifyEvent(DropUpdateEvent(location: _offset!));
61+
_notifyPositionEvent(DropUpdateEvent(location: _offset!));
6062
}
6163
break;
6264
case "exited":
63-
_notifyEvent(DropExitEvent(location: _offset ?? Offset.zero));
65+
_notifyPositionEvent(DropExitEvent(location: _offset ?? Offset.zero));
6466
_offset = null;
6567
break;
6668
case "performOperation":
6769
final paths = (call.arguments as List).cast<String>();
68-
_notifyEvent(
70+
_notifyDoneEvent(
6971
DropDoneEvent(
7072
location: _offset ?? Offset.zero,
7173
files: paths.map((e) => XFile(e)).toList(),
@@ -85,10 +87,12 @@ class DesktopDrop {
8587
}
8688
return '';
8789
}).where((e) => e.isNotEmpty);
88-
_notifyEvent(DropDoneEvent(
89-
location: Offset(offset[0], offset[1]),
90-
files: paths.map((e) => XFile(e)).toList(),
91-
));
90+
_notifyDoneEvent(
91+
DropDoneEvent(
92+
location: Offset(offset[0], offset[1]),
93+
files: paths.map((e) => XFile(e)).toList(),
94+
),
95+
);
9296
break;
9397
case "performOperation_web":
9498
final results = (call.arguments as List)
@@ -102,7 +106,7 @@ class DesktopDrop {
102106
mimeType: e.type,
103107
))
104108
.toList();
105-
_notifyEvent(
109+
_notifyDoneEvent(
106110
DropDoneEvent(location: _offset ?? Offset.zero, files: results),
107111
);
108112
_offset = null;
@@ -112,29 +116,62 @@ class DesktopDrop {
112116
}
113117
}
114118

115-
void _notifyEvent(DropEvent event) {
116-
final reversedListeners = _listeners.toList(growable: false).reversed;
117-
var foundTargetListener = false;
118-
for (final listener in reversedListeners) {
119-
final isInBounds = listener.isInBounds(event);
120-
if (isInBounds && !foundTargetListener) {
121-
foundTargetListener = true;
122-
listener.onEvent(event);
119+
void _notifyPositionEvent(DropEvent event) {
120+
final RawDropListener? target;
121+
122+
if (event is DropExitEvent) {
123+
target = null;
124+
} else {
125+
final result = BoxHitTestResult();
126+
WidgetsBinding.instance.renderView.hitTest(result, position: event.location);
127+
128+
target = result.path.firstWhereOrNull((entry) => entry.target is RawDropListener)?.target as RawDropListener?;
129+
}
130+
131+
if (_currentTargetListener != target) {
132+
final previous = _currentTargetListener;
133+
if (previous != null) {
134+
previous.handleDropEvent(
135+
DropExitEvent(
136+
location: previous.globalToLocalOffset(event.location),
137+
),
138+
);
139+
}
140+
}
141+
if (target != null) {
142+
final position = target.globalToLocalOffset(event.location);
143+
if (_currentTargetListener == null) {
144+
target.handleDropEvent(DropEnterEvent(location: position));
123145
} else {
124-
listener.onEvent(DropExitEvent(location: event.location));
146+
target.handleDropEvent(DropUpdateEvent(location: position));
125147
}
126148
}
127-
128-
_channel.invokeMethod('updateDroppableStatus', foundTargetListener);
149+
_currentTargetListener = target;
150+
_channel.invokeMethod('updateDroppableStatus', target != null);
129151
}
130152

131-
void addRawDropEventListener(RawDropListener listener) {
132-
assert(!_listeners.contains(listener));
133-
_listeners.add(listener);
134-
}
153+
void _notifyDoneEvent(DropDoneEvent event) {
154+
final result = BoxHitTestResult();
155+
WidgetsBinding.instance.renderView.hitTest(result, position: event.location);
135156

136-
void removeRawDropEventListener(RawDropListener listener) {
137-
assert(_listeners.contains(listener));
138-
_listeners.remove(listener);
157+
final target = result.path.firstWhereOrNull((entry) => entry.target is RawDropListener)?.target as RawDropListener?;
158+
final previous = _currentTargetListener;
159+
if (previous != null) {
160+
previous.handleDropEvent(
161+
DropExitEvent(
162+
location: previous.globalToLocalOffset(event.location),
163+
),
164+
);
165+
_currentTargetListener = null;
166+
}
167+
if (target != null) {
168+
target.handleDropEvent(
169+
DropDoneEvent(
170+
location: target.globalToLocalOffset(event.location),
171+
files: event.files,
172+
),
173+
);
174+
}
175+
_channel.invokeMethod('updateDroppableStatus', false);
139176
}
140177
}

0 commit comments

Comments
 (0)