Skip to content

Commit

Permalink
add dartdoc comments
Browse files Browse the repository at this point in the history
  • Loading branch information
leonx98 committed Jul 1, 2022
1 parent d6d556a commit 5f736c3
Show file tree
Hide file tree
Showing 8 changed files with 160 additions and 25 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
## 1.2.3

* export events + listeners via singleton
* add dartdoc comments

## 1.2.2

* fix RenderBoxError during didUpdateWidget()
Expand Down
3 changes: 3 additions & 0 deletions lib/src/channel.dart
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,11 @@ typedef RawDropListener = void Function(DropEvent);
typedef DragEventListener = void Function(DragEvent event);
typedef UniqueKeyString = String;

/// Main communication between the Dart- and native-layer
class FlutterNativeDragNDrop {
static const MethodChannel _channel = MethodChannel('flutter_native_drag_n_drop');

/// Singleton instance
static final instance = FlutterNativeDragNDrop._();

FlutterNativeDragNDrop._();
Expand Down
32 changes: 26 additions & 6 deletions lib/src/events.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,49 +3,69 @@ import 'package:flutter/painting.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter_native_drag_n_drop/src/native_drag_item.dart';

/// Base class for drop events, mainly used by [NativeDropTarget]
///
/// [items] is list of drag items
/// [location] is the global location of the cursor
abstract class DropEvent {
List<NativeDragItem> items;
Offset location;
DropEvent(this.location, this.items);
}

/// Event object when drop has entered the drop target area
class DropEnterEvent extends DropEvent {
DropEnterEvent({required Offset location, required List<NativeDragItem> items}) : super(location, items);
DropEnterEvent(
{required Offset location, required List<NativeDragItem> items})
: super(location, items);
}

/// Event object when drag has exited the drop target area
class DropExitEvent extends DropEvent {
DropExitEvent({required Offset location, required List<NativeDragItem> items}) : super(location, items);
DropExitEvent({required Offset location, required List<NativeDragItem> items})
: super(location, items);
}

/// Event object when drag has moved on a drop target
class DropUpdateEvent extends DropEvent {
DropUpdateEvent({required Offset location, required List<NativeDragItem> items}) : super(location, items);
DropUpdateEvent(
{required Offset location, required List<NativeDragItem> items})
: super(location, items);
}

/// Event object when drop has finished
class DropDoneEvent extends DropEvent {
DropDoneEvent({required Offset location, required List<NativeDragItem> items}) : super(location, items);
DropDoneEvent({required Offset location, required List<NativeDragItem> items})
: super(location, items);
}

/// Base class for drag events, mainly used by [NativeDraggable]
///
/// [location] is the global location of the cursor
abstract class DragEvent {
// global position of the dragged cursor
Offset location;
DragEvent(this.location);
}

/// Event object when drag has started
class DragBeginEvent extends DragEvent {
DragBeginEvent({required Offset location}) : super(location);
}

/// Event object when drag has moved
class DragMovedEvent extends DragEvent {
DragMovedEvent({required Offset location}) : super(location);
}

/// Event object when drag has ended
class DragEndedEvent extends DragEvent {
DragEndedEvent({required Offset location}) : super(location);
}

/// Event object which is fired when native layer needs the fileStream to write the file
class FileStreamEvent {
final NativeDragFileItem item;
final String fileName;
final String url;
FileStreamEvent(this.item, this.fileName, this.url);
}
}
9 changes: 9 additions & 0 deletions lib/src/native_drag_item.dart
Original file line number Diff line number Diff line change
@@ -1,10 +1,19 @@
/// [NativeDragItems] is used for when you just drag and drop within the application (e.g folder, image)
///
/// [name] should be a unique name which identifies this drag item
/// [data] are any data passed to the [NativeDropTarget]
class NativeDragItem<T extends Object> {
final String name;
final T? data;

NativeDragItem({required this.name, this.data});
}

/// [NativeDragFileItem] is used for files, especially when you want to support the drag and drop outside of the application (e.g file to Finder or Mail client)
///
/// [fileName] will be the future fileName
/// [fileSize] is the size of the file
/// [data] are any data passed to the [NativeDropTarget]
class NativeDragFileItem<T extends Object> extends NativeDragItem {
final String fileName;
final int fileSize;
Expand Down
26 changes: 26 additions & 0 deletions lib/src/native_draggable.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,37 @@ import 'dart:typed_data';
import 'channel.dart';

typedef OnDragUpdateCallback = void Function(DragEvent event);

/// Callback which is called when the native layer needs the file bytes
///
/// [item] is the corresponding [NativeDragFileItem] object
/// [fileName] is the fileName
/// [url] is the location where the user dropped the drag file item
/// [progressController] must be used to inform about the current progress
/// must return a Stream to write to
typedef FileStreamCallback = Stream<Uint8List> Function(NativeDragFileItem item,
String fileName, String url, ProgressController progressController);

/// A widget that can be dragged from to a NativeDragTarget.
class NativeDraggable extends StatefulWidget {
final Widget child;

/// Drag items when dragging only within application
final List<NativeDragItem>? items;

/// Drag file items when dragging out of application
final List<NativeDragFileItem>? fileItems;

/// Callback which is called when you drop a drag file item out of application boundary
final FileStreamCallback fileStreamCallback;

/// Callback when drag has started
final OnDragUpdateCallback? onDragStarted;

/// Callback when drag has moved
final OnDragUpdateCallback? onDragUpdate;

/// Callback when drag has ended
final OnDragUpdateCallback? onDragEnd;

const NativeDraggable(
Expand All @@ -38,7 +58,11 @@ class NativeDraggable extends StatefulWidget {

class DraggableState extends State<NativeDraggable> {
final GlobalKey _widgetKey = GlobalKey();

/// Identifies this receiver across Flutter- and the native-layer
final UniqueKey uniqueKey = UniqueKey();

/// List of [ProgressController] objects which controls the progress indicator of every drag file item
final List<ProgressController> progressControllers = [];

/// WIP
Expand Down Expand Up @@ -115,13 +139,15 @@ class DraggableState extends State<NativeDraggable> {
}
}

/// Don't call it by yourself. It is used by this library internally
Stream<Uint8List> onFileStreamEvent(FileStreamEvent event) {
final progressController =
progressControllers.firstWhere((p) => event.fileName == p.fileName);
return widget.fileStreamCallback(
event.item, event.fileName, event.url, progressController);
}

/// Don't call it by yourself. It is used by this library internally
void onDragEvent(DragEvent event) {
if (event is DragBeginEvent) {
widget.onDragStarted?.call(event);
Expand Down
99 changes: 82 additions & 17 deletions lib/src/native_drop_target.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,26 +3,45 @@ import 'package:flutter_native_drag_n_drop/src/channel.dart';
import 'package:flutter_native_drag_n_drop/src/native_drag_item.dart';
import 'events.dart';

/// An object that contains metadata when the drag is done
@immutable
class DropDoneDetails {
const DropDoneDetails({required this.items, required this.localPosition, required this.globalPosition});
const DropDoneDetails(
{required this.items,
required this.localPosition,
required this.globalPosition});

/// List with the corresponding drag items
final List<NativeDragItem> items;

/// Local position (relative to the application window) of the dropped items
final Offset localPosition;

/// Global position (relative to the screen window) of the dropped items
final Offset globalPosition;
}

/// An object that contains metadata when the drag is done
class DropEventDetails {
DropEventDetails({required this.items, required this.localPosition, required this.globalPosition});
DropEventDetails(
{required this.items,
required this.localPosition,
required this.globalPosition});

/// List with the corresponding drag item
final List<NativeDragItem> items;

/// Local position (relative to the application window) of the dropped items
final Offset localPosition;

/// Global position (relative to the screen window) of the dropped items
final Offset globalPosition;
}

typedef OnDragDoneCallback = void Function(DropDoneDetails details);
typedef OnDragCallback<Detail> = void Function(Detail details);
typedef DragTargetWillAccept<T extends Object> = bool Function(List<NativeDragItem> items);
typedef DragTargetWillAccept<T extends Object> = bool Function(
List<NativeDragItem> items);

/// A widget that accepts draggable files.
class NativeDropTarget extends StatefulWidget {
Expand All @@ -38,12 +57,23 @@ class NativeDropTarget extends StatefulWidget {
}) : super(key: key);

final DragTargetBuilder<NativeDragItem> builder;

/// Callback when drag has entered the drop area
final OnDragCallback<DropEventDetails>? onDragEntered;

/// Callback when drag has exited the drop area
final OnDragCallback<DropEventDetails>? onDragExited;

/// Callback when drag has moved within the drop area
final OnDragCallback<DropEventDetails>? onDragUpdated;
final DragTargetWillAccept? onWillAccept;

/// Callback when drag has dropped
final OnDragDoneCallback? onDragDone;

/// Callback to decide if items will be accept from this drop target
final DragTargetWillAccept? onWillAccept;

/// Flag to enable/disable the response of drags
final bool enable;

@override
Expand Down Expand Up @@ -78,7 +108,8 @@ class _DropTargetState extends State<NativeDropTarget> {
} else if (!widget.enable && oldWidget.enable) {
FlutterNativeDragNDrop.instance.removeRawDropEventListener(_onDropEvent);
if (_status != _DragTargetStatus.idle) {
_updateStatus(_DragTargetStatus.idle, localLocation: Offset.zero, globalLocation: Offset.zero, items: []);
_updateStatus(_DragTargetStatus.idle,
localLocation: Offset.zero, globalLocation: Offset.zero, items: []);
}
}
}
Expand All @@ -95,31 +126,65 @@ class _DropTargetState extends State<NativeDropTarget> {
if (!inBounds) {
assert(_status == _DragTargetStatus.idle);
} else {
_updateStatus(_DragTargetStatus.enter, globalLocation: globalPosition, localLocation: position, items: event.items);
_updateStatus(_DragTargetStatus.enter,
globalLocation: globalPosition,
localLocation: position,
items: event.items);
}
} else if (event is DropUpdateEvent) {
if (_status == _DragTargetStatus.idle && inBounds) {
_updateStatus(_DragTargetStatus.enter, globalLocation: globalPosition, localLocation: position, items: event.items);
} else if ((_status == _DragTargetStatus.enter || _status == _DragTargetStatus.update) && inBounds) {
_updateStatus(_DragTargetStatus.update, globalLocation: globalPosition, localLocation: position, debugRequiredStatus: false, items: event.items);
_updateStatus(_DragTargetStatus.enter,
globalLocation: globalPosition,
localLocation: position,
items: event.items);
} else if ((_status == _DragTargetStatus.enter ||
_status == _DragTargetStatus.update) &&
inBounds) {
_updateStatus(_DragTargetStatus.update,
globalLocation: globalPosition,
localLocation: position,
debugRequiredStatus: false,
items: event.items);
} else if (_status != _DragTargetStatus.idle && !inBounds) {
_updateStatus( _DragTargetStatus.idle, globalLocation: globalPosition, localLocation: position, items: event.items);
_updateStatus(_DragTargetStatus.idle,
globalLocation: globalPosition,
localLocation: position,
items: event.items);
}
} else if (event is DropExitEvent && _status != _DragTargetStatus.idle) {
_updateStatus(_DragTargetStatus.idle, globalLocation: globalPosition, localLocation: position, items: event.items);
} else if (event is DropDoneEvent && _status != _DragTargetStatus.idle && inBounds) {
_updateStatus( _DragTargetStatus.idle, debugRequiredStatus: false, globalLocation: globalPosition, localLocation: position, items: event.items);
_updateStatus(_DragTargetStatus.idle,
globalLocation: globalPosition,
localLocation: position,
items: event.items);
} else if (event is DropDoneEvent &&
_status != _DragTargetStatus.idle &&
inBounds) {
_updateStatus(_DragTargetStatus.idle,
debugRequiredStatus: false,
globalLocation: globalPosition,
localLocation: position,
items: event.items);
if (widget.onWillAccept != null && !widget.onWillAccept!(event.items)) {
return;
}
widget.onDragDone?.call(DropDoneDetails(items: event.items, localPosition: position, globalPosition: globalPosition));
widget.onDragDone?.call(DropDoneDetails(
items: event.items,
localPosition: position,
globalPosition: globalPosition));
}
}

void _updateStatus(_DragTargetStatus status, {bool debugRequiredStatus = true, required Offset localLocation, required Offset globalLocation, required List<NativeDragItem> items}) {
void _updateStatus(_DragTargetStatus status,
{bool debugRequiredStatus = true,
required Offset localLocation,
required Offset globalLocation,
required List<NativeDragItem> items}) {
assert(!debugRequiredStatus || _status != status);
_status = status;
final details = DropEventDetails(items: items, localPosition: localLocation, globalPosition: globalLocation);
final details = DropEventDetails(
items: items,
localPosition: localLocation,
globalPosition: globalLocation);
switch (_status) {
case _DragTargetStatus.enter:
widget.onDragEntered?.call(details);
Expand Down Expand Up @@ -163,4 +228,4 @@ class _DropTargetState extends State<NativeDropTarget> {
Widget build(BuildContext context) {
return widget.builder(context, _acceptedData, _rejectedData);
}
}
}
7 changes: 7 additions & 0 deletions lib/src/progress_controller.dart
Original file line number Diff line number Diff line change
@@ -1,11 +1,18 @@
import 'package:flutter_native_drag_n_drop/src/channel.dart';

/// An object where you have to pass the current progress of the fileStream in bytes. The system use the progress to update the progress indicator in the filesystem manager(e.g. Finder on macOS)
///
/// [id] identifies this progress controller to their drag file item
/// [fileName] is the corresponding fileName
class ProgressController {
final String id;
final String fileName;

ProgressController({required this.id, required this.fileName});

/// Used [count] to updates the current progress indicator
///
/// [count] is the current progress in bytes
updateProgress(int count) {
FlutterNativeDragNDrop.instance.updateProgress(id, fileName, count);
}
Expand Down
4 changes: 2 additions & 2 deletions pubspec.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name: flutter_native_drag_n_drop
description: A flutter plugin to support the native drag and drop.
version: 1.2.2
description: A flutter plugin to support the native drag and drop, especially to drag files (only files) out of the application boundary.
version: 1.2.3
homepage: https://github.com/skalio/native-drag-and-drop

environment:
Expand Down

0 comments on commit 5f736c3

Please sign in to comment.