diff --git a/packages/desktop_drop/example/lib/main.dart b/packages/desktop_drop/example/lib/main.dart index 0a65ec37..c4aa1cda 100644 --- a/packages/desktop_drop/example/lib/main.dart +++ b/packages/desktop_drop/example/lib/main.dart @@ -51,28 +51,28 @@ class _ExampleDragTargetState extends State { @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) { @@ -87,10 +87,7 @@ class _ExampleDragTargetState extends State { 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, diff --git a/packages/desktop_drop/example/macos/Podfile.lock b/packages/desktop_drop/example/macos/Podfile.lock index 582d3d89..cb95be65 100644 --- a/packages/desktop_drop/example/macos/Podfile.lock +++ b/packages/desktop_drop/example/macos/Podfile.lock @@ -15,7 +15,7 @@ EXTERNAL SOURCES: SPEC CHECKSUMS: desktop_drop: 69eeff437544aa619c8db7f4481b3a65f7696898 - FlutterMacOS: 8f6f14fa908a6fb3fba0cd85dbd81ec4b251fb24 + FlutterMacOS: ae6af50a8ea7d6103d888583d46bd8328a7e9811 PODFILE CHECKSUM: 353c8bcc5d5b0994e508d035b5431cfe18c1dea7 diff --git a/packages/desktop_drop/example/pubspec.lock b/packages/desktop_drop/example/pubspec.lock index c09f4e10..bccbd2ce 100644 --- a/packages/desktop_drop/example/pubspec.lock +++ b/packages/desktop_drop/example/pubspec.lock @@ -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: @@ -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: @@ -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: @@ -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: @@ -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: @@ -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" diff --git a/packages/desktop_drop/lib/desktop_drop_web.dart b/packages/desktop_drop/lib/desktop_drop_web.dart index a60d5d1b..7d100b5e 100644 --- a/packages/desktop_drop/lib/desktop_drop_web.dart +++ b/packages/desktop_drop/lib/desktop_drop_web.dart @@ -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'; @@ -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 = []; - - 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 = []; + + 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 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}\'', diff --git a/packages/desktop_drop/lib/src/channel.dart b/packages/desktop_drop/lib/src/channel.dart index 492a9319..5f6995d4 100644 --- a/packages/desktop_drop/lib/src/channel.dart +++ b/packages/desktop_drop/lib/src/channel.dart @@ -1,14 +1,21 @@ import 'dart:convert'; +import 'package:collection/collection.dart'; import 'package:cross_file/cross_file.dart'; +import 'package:flutter/foundation.dart'; +import 'package:flutter/rendering.dart'; import 'package:flutter/services.dart'; import 'package:flutter/widgets.dart'; import 'drop_item.dart'; import 'events.dart'; -import 'utils/platform.dart' if (dart.library.html) 'utils/platform_web.dart'; -typedef RawDropListener = void Function(DropEvent); +abstract class RawDropListener { + /// Returns true if event was handled, false otherwise + bool handleDropEvent(DropEvent event); + + Offset globalToLocalOffset(Offset global); +} class DesktopDrop { static const MethodChannel _channel = MethodChannel('desktop_drop'); @@ -17,24 +24,25 @@ class DesktopDrop { static final instance = DesktopDrop._(); - final _listeners = {}; - - var _inited = false; + var _initialized = false; + RawDropListener? _currentTargetListener; Offset? _offset; void init() { - if (_inited) { + if (_initialized) { return; } - _inited = true; - _channel.setMethodCallHandler((call) async { - try { - return await _handleMethodChannel(call); - } catch (e, s) { - debugPrint('_handleMethodChannel: $e $s'); - } - }); + _initialized = true; + _channel.setMethodCallHandler( + (call) async { + try { + return await _handleMethodChannel(call); + } catch (e, s) { + debugPrint('_handleMethodChannel: $e $s'); + } + }, + ); } Future _handleMethodChannel(MethodCall call) async { @@ -42,26 +50,25 @@ class DesktopDrop { case "entered": final position = (call.arguments as List).cast(); _offset = Offset(position[0], position[1]); - _notifyEvent(DropEnterEvent(location: _offset!)); + _notifyPositionEvent(DropEnterEvent(location: _offset!)); break; case "updated": - if (_offset == null && Platform.isLinux) { - final position = (call.arguments as List).cast(); - _offset = Offset(position[0], position[1]); - _notifyEvent(DropEnterEvent(location: _offset!)); - return; - } final position = (call.arguments as List).cast(); + final previousOffset = _offset; _offset = Offset(position[0], position[1]); - _notifyEvent(DropUpdateEvent(location: _offset!)); + if (previousOffset == null) { + _notifyPositionEvent(DropEnterEvent(location: _offset!)); + } else { + _notifyPositionEvent(DropUpdateEvent(location: _offset!)); + } break; case "exited": - _notifyEvent(DropExitEvent(location: _offset ?? Offset.zero)); + _notifyPositionEvent(DropExitEvent(location: _offset ?? Offset.zero)); _offset = null; break; case "performOperation": final paths = (call.arguments as List).cast(); - _notifyEvent( + _notifyDoneEvent( DropDoneEvent( location: _offset ?? Offset.zero, files: paths.map((e) => XFile(e)).toList(), @@ -81,10 +88,12 @@ class DesktopDrop { } return ''; }).where((e) => e.isNotEmpty); - _notifyEvent(DropDoneEvent( - location: Offset(offset[0], offset[1]), - files: paths.map((e) => XFile(e)).toList(), - )); + _notifyDoneEvent( + DropDoneEvent( + location: Offset(offset[0], offset[1]), + files: paths.map((e) => XFile(e)).toList(), + ), + ); break; case "performOperation_web": final results = (call.arguments as List) @@ -98,7 +107,7 @@ class DesktopDrop { mimeType: e.type, )) .toList(); - _notifyEvent( + _notifyDoneEvent( DropDoneEvent(location: _offset ?? Offset.zero, files: results), ); _offset = null; @@ -108,19 +117,66 @@ class DesktopDrop { } } - void _notifyEvent(DropEvent event) { - for (final listener in _listeners) { - listener(event); + void _notifyPositionEvent(DropEvent event) { + final RawDropListener? target; + + if (event is DropExitEvent) { + target = null; + } else { + final result = BoxHitTestResult(); + WidgetsBinding.instance.renderView.hitTest(result, position: event.location); + + target = result.path.firstWhereOrNull((entry) => entry.target is RawDropListener)?.target as RawDropListener?; } - } - void addRawDropEventListener(RawDropListener listener) { - assert(!_listeners.contains(listener)); - _listeners.add(listener); + if (_currentTargetListener != target) { + final previous = _currentTargetListener; + if (previous != null) { + previous.handleDropEvent( + DropExitEvent( + location: previous.globalToLocalOffset(event.location), + ), + ); + } + if (kIsWeb) { + _channel.invokeMethod('updateDroppableStatus', target != null); + } + } + if (target != null) { + final position = target.globalToLocalOffset(event.location); + if (_currentTargetListener == null) { + target.handleDropEvent(DropEnterEvent(location: position)); + } else { + target.handleDropEvent(DropUpdateEvent(location: position)); + } + } + _currentTargetListener = target; } - void removeRawDropEventListener(RawDropListener listener) { - assert(_listeners.contains(listener)); - _listeners.remove(listener); + void _notifyDoneEvent(DropDoneEvent event) { + final result = BoxHitTestResult(); + WidgetsBinding.instance.renderView.hitTest(result, position: event.location); + + final target = result.path.firstWhereOrNull((entry) => entry.target is RawDropListener)?.target as RawDropListener?; + final previous = _currentTargetListener; + if (previous != null) { + previous.handleDropEvent( + DropExitEvent( + location: previous.globalToLocalOffset(event.location), + ), + ); + _currentTargetListener = null; + } + if (target != null) { + target.handleDropEvent( + DropDoneEvent( + location: target.globalToLocalOffset(event.location), + files: event.files, + ), + ); + } + if (kIsWeb) { + _channel.invokeMethod('updateDroppableStatus', false); + } } } diff --git a/packages/desktop_drop/lib/src/drop_target.dart b/packages/desktop_drop/lib/src/drop_target.dart index 7f03f4e8..900592c6 100644 --- a/packages/desktop_drop/lib/src/drop_target.dart +++ b/packages/desktop_drop/lib/src/drop_target.dart @@ -1,220 +1,160 @@ import 'package:cross_file/cross_file.dart'; +import 'package:flutter/rendering.dart'; import 'package:flutter/widgets.dart'; import 'channel.dart'; import 'events.dart'; -import 'utils/platform.dart' if (dart.library.html) 'utils/platform_web.dart'; - -@immutable -class DropDoneDetails { - const DropDoneDetails({ - required this.files, - required this.localPosition, - required this.globalPosition, - }); - - final List files; - final Offset localPosition; - final Offset globalPosition; -} - -class DropEventDetails { - DropEventDetails({ - required this.localPosition, - required this.globalPosition, - }); - - final Offset localPosition; - final Offset globalPosition; -} +typedef OnDragDoneCallback = void Function(List files, Offset localPosition); -typedef OnDragDoneCallback = void Function(DropDoneDetails details); +typedef OnDragCallback = void Function(Offset localPosition); -typedef OnDragCallback = void Function(Detail details); +typedef OnDragActiveStatusChange = void Function(bool isActive); /// A widget that accepts draggable files. -class DropTarget extends StatefulWidget { +class DropTarget extends SingleChildRenderObjectWidget { const DropTarget({ Key? key, - required this.child, + super.child, this.onDragEntered, this.onDragExited, this.onDragDone, this.onDragUpdated, - this.enable = true, + this.onDragActiveStatusChange, + this.isEnabled = true, }) : super(key: key); - final Widget child; - /// Callback when drag entered target area. - final OnDragCallback? onDragEntered; + final OnDragCallback? onDragEntered; /// Callback when drag exited target area. - final OnDragCallback? onDragExited; + final OnDragCallback? onDragExited; /// Callback when drag hover on target area. - final OnDragCallback? onDragUpdated; + final OnDragCallback? onDragUpdated; /// Callback when drag dropped on target area. final OnDragDoneCallback? onDragDone; - /// Whether to enable drop target. - /// - /// ATTENTION: You should disable drop target when you push a new page/widget in - /// front of this drop target, since the drop target will still receive drag events - /// even it is invisible. - /// https://github.com/MixinNetwork/flutter-plugins/issues/2 - final bool enable; + final OnDragActiveStatusChange? onDragActiveStatusChange; - @override - State createState() => _DropTargetState(); -} - -enum _DragTargetStatus { - enter, - update, - idle, -} + final bool isEnabled; -class _DropTargetState extends State { - _DragTargetStatus _status = _DragTargetStatus.idle; + @override + _DropTargetRenderObject createRenderObject(BuildContext context) => _DropTargetRenderObject( + isEnabled: isEnabled, + onDragEntered: onDragEntered, + onDragExited: onDragExited, + onDragUpdated: onDragUpdated, + onDragDone: onDragDone, + onDragActiveStatusChange: onDragActiveStatusChange, + ); @override - void initState() { - super.initState(); - DesktopDrop.instance.init(); - if (widget.enable) { - DesktopDrop.instance.addRawDropEventListener(_onDropEvent); - } + void updateRenderObject(BuildContext context, covariant _DropTargetRenderObject renderObject) { + renderObject + ..isEnabled = isEnabled + ..onDragEntered = onDragEntered + ..onDragExited = onDragExited + ..onDragUpdated = onDragUpdated + ..onDragDone = onDragDone + ..onDragActiveStatusChange = onDragActiveStatusChange; } +} - @override - void didUpdateWidget(DropTarget oldWidget) { - super.didUpdateWidget(oldWidget); - if (widget.enable && !oldWidget.enable) { - DesktopDrop.instance.addRawDropEventListener(_onDropEvent); - } else if (!widget.enable && oldWidget.enable) { - DesktopDrop.instance.removeRawDropEventListener(_onDropEvent); - if (_status != _DragTargetStatus.idle) { - _updateStatus( - _DragTargetStatus.idle, - localLocation: Offset.zero, - globalLocation: Offset.zero, - ); - } - } +class _DropTargetRenderObject extends RenderProxyBoxWithHitTestBehavior implements RawDropListener { + _DropTargetRenderObject({ + required bool isEnabled, + required this.onDragEntered, + required this.onDragExited, + required this.onDragUpdated, + required this.onDragDone, + required this.onDragActiveStatusChange, + }) : super(behavior: HitTestBehavior.opaque) { + DesktopDrop.instance.init(); + this.isEnabled = isEnabled; } - void _onDropEvent(DropEvent event) { - final renderBox = context.findRenderObject() as RenderBox?; - if (renderBox == null) { + bool _isActive = false; + set isActive(bool newValue) { + if (newValue == _isActive) { return; } - final globalPosition = _scaleHoverPoint(context, event.location); - final position = renderBox.globalToLocal(globalPosition); - bool inBounds = renderBox.paintBounds.contains(position); - if (event is DropEnterEvent) { - if (!inBounds) { - assert(_status == _DragTargetStatus.idle); + final position = _latestLocalPosition!; + if (newValue) { + if (_isActive) { + onDragUpdated?.call(position); } else { - _updateStatus( - _DragTargetStatus.enter, - globalLocation: globalPosition, - localLocation: position, - ); - } - } else if (event is DropUpdateEvent) { - if (_status == _DragTargetStatus.idle && inBounds) { - _updateStatus( - _DragTargetStatus.enter, - globalLocation: globalPosition, - localLocation: position, - ); - } else if ((_status == _DragTargetStatus.enter || - _status == _DragTargetStatus.update) && - inBounds) { - _updateStatus( - _DragTargetStatus.update, - globalLocation: globalPosition, - localLocation: position, - debugRequiredStatus: false, - ); - } else if (_status != _DragTargetStatus.idle && !inBounds) { - _updateStatus( - _DragTargetStatus.idle, - globalLocation: globalPosition, - localLocation: position, - ); + onDragEntered?.call(position); } - } else if (event is DropExitEvent && _status != _DragTargetStatus.idle) { - _updateStatus( - _DragTargetStatus.idle, - globalLocation: globalPosition, - localLocation: position, - ); - } else if (event is DropDoneEvent && - (_status != _DragTargetStatus.idle || Platform.isLinux) && - inBounds) { - _updateStatus( - _DragTargetStatus.idle, - debugRequiredStatus: false, - globalLocation: globalPosition, - localLocation: position, - ); - widget.onDragDone?.call(DropDoneDetails( - files: event.files, - localPosition: position, - globalPosition: globalPosition, - )); + } else { + _latestLocalPosition = null; + onDragExited?.call(position); } + _isActive = newValue; + onDragActiveStatusChange?.call(newValue); } - void _updateStatus( - _DragTargetStatus status, { - bool debugRequiredStatus = true, - required Offset localLocation, - required Offset globalLocation, - }) { - assert(!debugRequiredStatus || _status != status); - _status = status; - final details = DropEventDetails( - localPosition: localLocation, - globalPosition: globalLocation, - ); - switch (_status) { - case _DragTargetStatus.enter: - widget.onDragEntered?.call(details); - break; - case _DragTargetStatus.update: - widget.onDragUpdated?.call(details); - break; - case _DragTargetStatus.idle: - widget.onDragExited?.call(details); - break; + bool _isEnabled = false; + set isEnabled(bool value) { + if (value != _isEnabled) { + _isEnabled = value; + if (!value) { + isActive = false; + } } } + /// Callback when drag entered target area. + OnDragCallback? onDragEntered; + + /// Callback when drag exited target area. + OnDragCallback? onDragExited; + + /// Callback when drag hover on target area. + OnDragCallback? onDragUpdated; + + /// Callback when drag dropped on target area. + OnDragDoneCallback? onDragDone; + + OnDragActiveStatusChange? onDragActiveStatusChange; + + Offset? _latestLocalPosition; + @override void dispose() { - if (widget.enable) { - DesktopDrop.instance.removeRawDropEventListener(_onDropEvent); - } + isEnabled = false; super.dispose(); } @override - Widget build(BuildContext context) { - return widget.child; + bool hitTest(BoxHitTestResult result, {required Offset position}) { + if (!_isEnabled) { + return child?.hitTest(result, position: position) ?? false; + } + return super.hitTest(result, position: position); } -} -Offset _scaleHoverPoint(BuildContext context, Offset point) { - if (Platform.isWindows || Platform.isAndroid) { - return point.scale( - 1 / MediaQuery.of(context).devicePixelRatio, - 1 / MediaQuery.of(context).devicePixelRatio, - ); + @override + bool handleDropEvent(DropEvent event) { + _latestLocalPosition = event.location; + + if (!_isEnabled) { + isActive = false; + return false; + } + + if (event is DropEnterEvent || event is DropUpdateEvent) { + isActive = true; + } else if (event is DropExitEvent) { + isActive = false; + } else if (event is DropDoneEvent) { + onDragDone?.call(event.files, _latestLocalPosition!); + isActive = false; + } + return true; } - return point; + + @override + Offset globalToLocalOffset(Offset global) => globalToLocal(global); } diff --git a/packages/desktop_drop/lib/src/events.dart b/packages/desktop_drop/lib/src/events.dart index f23e8056..5c0ad461 100644 --- a/packages/desktop_drop/lib/src/events.dart +++ b/packages/desktop_drop/lib/src/events.dart @@ -4,36 +4,32 @@ import 'package:flutter/painting.dart'; abstract class DropEvent { Offset location; - DropEvent(this.location); + DropEvent({required this.location}); @override - String toString() { - return '$runtimeType($location)'; - } + String toString() => '$runtimeType($location)'; } class DropEnterEvent extends DropEvent { - DropEnterEvent({required Offset location}) : super(location); + DropEnterEvent({required super.location}); } class DropExitEvent extends DropEvent { - DropExitEvent({required Offset location}) : super(location); + DropExitEvent({required super.location}); } class DropUpdateEvent extends DropEvent { - DropUpdateEvent({required Offset location}) : super(location); + DropUpdateEvent({required super.location}); } class DropDoneEvent extends DropEvent { final List files; DropDoneEvent({ - required Offset location, + required super.location, required this.files, - }) : super(location); + }); @override - String toString() { - return '$runtimeType($location, $files)'; - } + String toString() => '$runtimeType($location, $files)'; } diff --git a/packages/desktop_drop/lib/src/utils/platform.dart b/packages/desktop_drop/lib/src/utils/platform.dart deleted file mode 100644 index 93be0bc9..00000000 --- a/packages/desktop_drop/lib/src/utils/platform.dart +++ /dev/null @@ -1,11 +0,0 @@ -import 'dart:io' as io; - -class Platform { - static bool get isLinux => io.Platform.isLinux; - - static bool get isWindows => io.Platform.isWindows; - - static bool get isWeb => false; - - static bool get isAndroid => io.Platform.isAndroid; -} diff --git a/packages/desktop_drop/lib/src/utils/platform_web.dart b/packages/desktop_drop/lib/src/utils/platform_web.dart deleted file mode 100644 index ae2c8188..00000000 --- a/packages/desktop_drop/lib/src/utils/platform_web.dart +++ /dev/null @@ -1,9 +0,0 @@ -class Platform { - static bool get isLinux => false; - - static bool get isWindows => false; - - static bool get isWeb => true; - - static bool get isAndroid => false; -} diff --git a/packages/desktop_drop/pubspec.yaml b/packages/desktop_drop/pubspec.yaml index da850a04..6761cab4 100644 --- a/packages/desktop_drop/pubspec.yaml +++ b/packages/desktop_drop/pubspec.yaml @@ -4,7 +4,7 @@ version: 0.4.4 homepage: https://github.com/MixinNetwork/flutter-plugins/tree/main/packages/desktop_drop environment: - sdk: ">=2.12.0 <3.0.0" + sdk: ">=2.17.0 <3.0.0" flutter: ">=1.20.0" dependencies: @@ -13,6 +13,7 @@ dependencies: flutter_web_plugins: sdk: flutter cross_file: ^0.3.3+4 + collection: any dev_dependencies: flutter_test: