feat: add interceptor into selection service to custom the drag target node (#1044)

This commit is contained in:
Lucas 2025-02-26 14:20:19 +08:00 • committed by GitHub
commit 400083fde6
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 70 additions and 16 deletions

View file

@ -437,12 +437,21 @@ class _DesktopSelectionServiceWidgetState
void renderDropTargetForOffset( void renderDropTargetForOffset(
Offset offset, { Offset offset, {
DragAreaBuilder? builder, DragAreaBuilder? builder,
DragTargetNodeInterceptor? interceptor,
}) { }) {
removeDropTarget(); removeDropTarget();
final node = getNodeInOffset(offset); Node? node = getNodeInOffset(offset);
final selectable = node?.selectable; if (node == null) {
if (node == null || selectable == null) { return;
}
if (interceptor != null) {
node = interceptor(context, node);
}
final selectable = node.selectable;
if (selectable == null) {
return; return;
} }
@ -461,7 +470,7 @@ class _DesktopSelectionServiceWidgetState
_dropTargetEntry = OverlayEntry( _dropTargetEntry = OverlayEntry(
builder: (context) { builder: (context) {
if (builder != null) { if (builder != null && node != null) {
return builder( return builder(
context, context,
DragAreaBuilderData( DragAreaBuilderData(
@ -507,9 +516,21 @@ class _DesktopSelectionServiceWidgetState
} }
@override @override
DropTargetRenderData? getDropTargetRenderData(Offset offset) { DropTargetRenderData? getDropTargetRenderData(
final node = getNodeInOffset(offset); Offset offset, {
final selectable = node?.selectable; DragTargetNodeInterceptor? interceptor,
}) {
Node? node = getNodeInOffset(offset);
if (node == null) {
return null;
}
if (interceptor != null) {
node = interceptor(context, node);
}
final selectable = node.selectable;
if (selectable == null) { if (selectable == null) {
return null; return null;
} }
@ -527,10 +548,10 @@ class _DesktopSelectionServiceWidgetState
final isCloserToStart = topDistance < bottomDistance; final isCloserToStart = topDistance < bottomDistance;
final dropPath = isCloserToStart ? node?.path : node?.path.next; final dropPath = isCloserToStart ? node.path : node.path.next;
return DropTargetRenderData( return DropTargetRenderData(
dropPath: dropPath ?? node?.path, dropPath: dropPath,
cursorNode: node, cursorNode: node,
); );
} }

View file

@ -881,10 +881,18 @@ class _MobileSelectionServiceWidgetState
} }
@override @override
void renderDropTargetForOffset(Offset offset, {DragAreaBuilder? builder}) { void renderDropTargetForOffset(
Offset offset, {
DragAreaBuilder? builder,
DragTargetNodeInterceptor? interceptor,
}) {
// Do nothing on mobile // Do nothing on mobile
} }
@override @override
DropTargetRenderData? getDropTargetRenderData(Offset offset) => null; DropTargetRenderData? getDropTargetRenderData(
Offset offset, {
DragTargetNodeInterceptor? interceptor,
}) =>
null;
} }

View file

@ -19,6 +19,11 @@ typedef DragAreaBuilder = Widget Function(
DragAreaBuilderData data, DragAreaBuilderData data,
); );
typedef DragTargetNodeInterceptor = Node Function(
BuildContext context,
Node node,
);
/// [AppFlowySelectionService] is responsible for processing /// [AppFlowySelectionService] is responsible for processing
/// the [Selection] changes and updates. /// the [Selection] changes and updates.
/// ///
@ -105,9 +110,12 @@ abstract class AppFlowySelectionService {
/// ///
/// If [builder] is provided, the line will be drawn by [builder]. /// If [builder] is provided, the line will be drawn by [builder].
/// Otherwise, the line will be drawn by default [DropTargetStyle]. /// Otherwise, the line will be drawn by default [DropTargetStyle].
///
/// If [interceptor] is provided, the node will be intercepted by [interceptor].
void renderDropTargetForOffset( void renderDropTargetForOffset(
Offset offset, { Offset offset, {
DragAreaBuilder? builder, DragAreaBuilder? builder,
DragTargetNodeInterceptor? interceptor,
}); });
/// Removes the horizontal line drawn by [renderDropTargetForOffset]. /// Removes the horizontal line drawn by [renderDropTargetForOffset].
@ -116,7 +124,10 @@ abstract class AppFlowySelectionService {
/// Returns the [DropTargetRenderData] for the [offset]. /// Returns the [DropTargetRenderData] for the [offset].
/// ///
DropTargetRenderData? getDropTargetRenderData(Offset offset); DropTargetRenderData? getDropTargetRenderData(
Offset offset, {
DragTargetNodeInterceptor? interceptor,
});
} }
class SelectionGestureInterceptor { class SelectionGestureInterceptor {

View file

@ -124,10 +124,24 @@ class _SelectionServiceWidgetState extends State<SelectionServiceWidget>
void removeDropTarget() => forward.removeDropTarget(); void removeDropTarget() => forward.removeDropTarget();
@override @override
void renderDropTargetForOffset(Offset offset, {DragAreaBuilder? builder}) => void renderDropTargetForOffset(
forward.renderDropTargetForOffset(offset, builder: builder); Offset offset, {
DragAreaBuilder? builder,
DragTargetNodeInterceptor? interceptor,
}) =>
forward.renderDropTargetForOffset(
offset,
builder: builder,
interceptor: interceptor,
);
@override @override
DropTargetRenderData? getDropTargetRenderData(Offset offset) => DropTargetRenderData? getDropTargetRenderData(
forward.getDropTargetRenderData(offset); Offset offset, {
DragTargetNodeInterceptor? interceptor,
}) =>
forward.getDropTargetRenderData(
offset,
interceptor: interceptor,
);
} }