mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2024-08-30 18:12:39 +00:00
chore: update board layout, support footer and header
This commit is contained in:
parent
a4b4b20cfc
commit
dbc5de2968
@ -46,9 +46,22 @@ class _MultiBoardListExampleState extends State<MultiBoardListExample> {
|
||||
return Board(
|
||||
dataController: boardData,
|
||||
background: Container(color: Colors.red),
|
||||
builder: (context, item) {
|
||||
footBuilder: (context, columnData) {
|
||||
return Container(
|
||||
color: Colors.purple,
|
||||
height: 30,
|
||||
);
|
||||
},
|
||||
headerBuilder: (context, columnData) {
|
||||
return Container(
|
||||
color: Colors.yellow,
|
||||
height: 30,
|
||||
);
|
||||
},
|
||||
cardBuilder: (context, item) {
|
||||
return _RowWidget(item: item as TextItem, key: ObjectKey(item));
|
||||
},
|
||||
columnConstraints: const BoxConstraints.tightFor(width: 240),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -28,7 +28,7 @@ class _SingleBoardListExampleState extends State<SingleBoardListExample> {
|
||||
Widget build(BuildContext context) {
|
||||
return Board(
|
||||
dataController: boardData,
|
||||
builder: (context, item) {
|
||||
cardBuilder: (context, item) {
|
||||
return _RowWidget(item: item as TextItem, key: ObjectKey(item));
|
||||
},
|
||||
);
|
||||
|
@ -13,8 +13,7 @@ class BoardOverlayEntry {
|
||||
/// Whether this entry occludes the entire overlay.
|
||||
///
|
||||
/// If an entry claims to be opaque, then, for efficiency, the overlay will
|
||||
/// skip building entries below that entry unless they have [maintainState]
|
||||
/// set.
|
||||
/// skip building entries below that entry.
|
||||
bool get opaque => _opaque;
|
||||
bool _opaque;
|
||||
|
||||
|
@ -20,25 +20,37 @@ class Board extends StatelessWidget {
|
||||
/// Defaults to 0.0.
|
||||
final double runSpacing;
|
||||
|
||||
///
|
||||
final Widget? background;
|
||||
|
||||
final BoardColumnItemWidgetBuilder builder;
|
||||
///
|
||||
final BoardColumnCardBuilder cardBuilder;
|
||||
|
||||
///
|
||||
final BoardColumnHeaderBuilder? headerBuilder;
|
||||
|
||||
///
|
||||
final BoardColumnFooterBuilder? footBuilder;
|
||||
|
||||
///
|
||||
final BoardDataController dataController;
|
||||
|
||||
final BoxConstraints columnConstraints;
|
||||
|
||||
///
|
||||
final BoardPhantomController passthroughPhantomContorller;
|
||||
final BoardPhantomController phantomController;
|
||||
|
||||
Board({
|
||||
required this.dataController,
|
||||
required this.builder,
|
||||
required this.cardBuilder,
|
||||
this.spacing = 10.0,
|
||||
this.runSpacing = 0.0,
|
||||
this.background,
|
||||
this.footBuilder,
|
||||
this.headerBuilder,
|
||||
this.columnConstraints = const BoxConstraints(maxWidth: 200),
|
||||
Key? key,
|
||||
}) : passthroughPhantomContorller =
|
||||
BoardPhantomController(delegate: dataController),
|
||||
}) : phantomController = BoardPhantomController(delegate: dataController),
|
||||
super(key: key);
|
||||
|
||||
@override
|
||||
@ -51,41 +63,25 @@ class Board extends StatelessWidget {
|
||||
List<String> acceptColumns =
|
||||
dataController.columnControllers.keys.toList();
|
||||
|
||||
dataController.columnControllers.forEach((columnId, dataController) {
|
||||
Widget child =
|
||||
buildBoardColumn(columnId, acceptColumns, dataController);
|
||||
if (children.isEmpty) {
|
||||
// children.add(SizedBox(width: spacing));
|
||||
}
|
||||
// if (background != null) {
|
||||
// child = Stack(children: [
|
||||
// background!,
|
||||
// child,
|
||||
// ]);
|
||||
// }
|
||||
// children.add(Expanded(key: ValueKey(columnId), child: child));
|
||||
dataController.columnControllers.forEach((columnId, controller) {
|
||||
Widget child = _buildColumn(columnId, acceptColumns, controller);
|
||||
children.add(child);
|
||||
// children.add(SizedBox(width: spacing));
|
||||
});
|
||||
|
||||
return BoardColumnContainer(
|
||||
onReorder: (fromIndex, toIndex) {},
|
||||
boardDataController: dataController,
|
||||
background: background,
|
||||
spacing: spacing,
|
||||
children: children,
|
||||
);
|
||||
|
||||
// return Row(
|
||||
// crossAxisAlignment: CrossAxisAlignment.start,
|
||||
// mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||
// children: children,
|
||||
// );
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
///
|
||||
Widget buildBoardColumn(
|
||||
Widget _buildColumn(
|
||||
String columnId,
|
||||
List<String> acceptColumns,
|
||||
BoardColumnDataController dataController,
|
||||
@ -95,18 +91,19 @@ class Board extends StatelessWidget {
|
||||
value: dataController,
|
||||
child: Consumer<BoardColumnDataController>(
|
||||
builder: (context, value, child) {
|
||||
return SizedBox(
|
||||
width: 200,
|
||||
return ConstrainedBox(
|
||||
constraints: columnConstraints,
|
||||
child: BoardColumnWidget(
|
||||
header: Container(color: Colors.yellow, height: 30),
|
||||
builder: builder,
|
||||
headerBuilder: headerBuilder,
|
||||
footBuilder: footBuilder,
|
||||
cardBuilder: cardBuilder,
|
||||
acceptColumns: acceptColumns,
|
||||
dataController: dataController,
|
||||
scrollController: ScrollController(),
|
||||
onReorder: (_, int fromIndex, int toIndex) {
|
||||
dataController.move(fromIndex, toIndex);
|
||||
},
|
||||
phantomController: passthroughPhantomContorller,
|
||||
phantomController: phantomController,
|
||||
),
|
||||
);
|
||||
},
|
||||
|
@ -4,34 +4,33 @@ import '../../rendering/board_overlay.dart';
|
||||
import '../../utils/log.dart';
|
||||
import '../phantom/phantom_controller.dart';
|
||||
import '../flex/reorder_flex.dart';
|
||||
import '../flex/drag_state.dart';
|
||||
import '../flex/reorder_flex_ext.dart';
|
||||
import '../flex/drag_target_inteceptor.dart';
|
||||
import 'data_controller.dart';
|
||||
|
||||
typedef OnDragStarted = void Function(int index);
|
||||
typedef OnDragEnded = void Function(String listId);
|
||||
typedef OnReorder = void Function(String listId, int fromIndex, int toIndex);
|
||||
typedef OnDeleted = void Function(String listId, int deletedIndex);
|
||||
typedef OnInserted = void Function(String listId, int insertedIndex);
|
||||
typedef OnPassedInPhantom = void Function(
|
||||
String listId,
|
||||
FlexDragTargetData dragTargetData,
|
||||
int phantomIndex,
|
||||
);
|
||||
typedef OnColumnDragStarted = void Function(int index);
|
||||
typedef OnColumnDragEnded = void Function(String listId);
|
||||
typedef OnColumnReorder = void Function(
|
||||
String listId, int fromIndex, int toIndex);
|
||||
typedef OnColumnDeleted = void Function(String listId, int deletedIndex);
|
||||
typedef OnColumnInserted = void Function(String listId, int insertedIndex);
|
||||
|
||||
typedef BoardColumnItemWidgetBuilder = Widget Function(
|
||||
typedef BoardColumnCardBuilder = Widget Function(
|
||||
BuildContext context, ColumnItem item);
|
||||
|
||||
typedef BoardColumnHeaderBuilder = Widget Function(
|
||||
BuildContext context, BoardColumnData columnData);
|
||||
|
||||
typedef BoardColumnFooterBuilder = Widget Function(
|
||||
BuildContext context, BoardColumnData columnData);
|
||||
|
||||
class BoardColumnWidget extends StatefulWidget {
|
||||
final Widget? header;
|
||||
final Widget? footer;
|
||||
final BoardColumnDataController dataController;
|
||||
final ScrollController? scrollController;
|
||||
final ReorderFlexConfig config;
|
||||
|
||||
final OnDragStarted? onDragStarted;
|
||||
final OnReorder onReorder;
|
||||
final OnDragEnded? onDragEnded;
|
||||
final OnColumnDragStarted? onDragStarted;
|
||||
final OnColumnReorder onReorder;
|
||||
final OnColumnDragEnded? onDragEnded;
|
||||
|
||||
final BoardPhantomController phantomController;
|
||||
|
||||
@ -39,18 +38,25 @@ class BoardColumnWidget extends StatefulWidget {
|
||||
|
||||
final List<String> acceptColumns;
|
||||
|
||||
final BoardColumnItemWidgetBuilder builder;
|
||||
final BoardColumnCardBuilder cardBuilder;
|
||||
|
||||
final BoardColumnHeaderBuilder? headerBuilder;
|
||||
|
||||
final BoardColumnFooterBuilder? footBuilder;
|
||||
|
||||
final double? spacing;
|
||||
|
||||
const BoardColumnWidget({
|
||||
Key? key,
|
||||
this.header,
|
||||
this.footer,
|
||||
required this.builder,
|
||||
this.headerBuilder,
|
||||
this.footBuilder,
|
||||
required this.cardBuilder,
|
||||
required this.onReorder,
|
||||
required this.dataController,
|
||||
required this.phantomController,
|
||||
required this.acceptColumns,
|
||||
this.config = const ReorderFlexConfig(),
|
||||
this.spacing,
|
||||
this.onDragStarted,
|
||||
this.scrollController,
|
||||
this.onDragEnded,
|
||||
@ -69,45 +75,59 @@ class _BoardColumnWidgetState extends State<BoardColumnWidget> {
|
||||
@override
|
||||
void initState() {
|
||||
_overlayEntry = BoardOverlayEntry(
|
||||
builder: (BuildContext context) {
|
||||
final children = widget.dataController.items
|
||||
.map((item) => _buildWidget(context, item))
|
||||
.toList();
|
||||
builder: (BuildContext context) {
|
||||
final children = widget.dataController.items
|
||||
.map((item) => _buildWidget(context, item))
|
||||
.toList();
|
||||
|
||||
final dragTargetExtension = ReorderFlextDragTargetExtension(
|
||||
reorderFlexId: widget.columnId,
|
||||
delegate: widget.phantomController,
|
||||
acceptReorderFlexIds: widget.acceptColumns,
|
||||
draggableTargetBuilder: PhantomReorderDraggableBuilder(),
|
||||
);
|
||||
final header = widget.headerBuilder
|
||||
?.call(context, widget.dataController.columnData);
|
||||
|
||||
return ReorderFlex(
|
||||
key: widget.key,
|
||||
header: widget.header,
|
||||
footer: widget.footer,
|
||||
scrollController: widget.scrollController,
|
||||
config: widget.config,
|
||||
onDragStarted: (index) {
|
||||
widget.phantomController.columnStartDragging(widget.columnId);
|
||||
widget.onDragStarted?.call(index);
|
||||
},
|
||||
onReorder: ((fromIndex, toIndex) {
|
||||
if (widget.phantomController.isFromColumn(widget.columnId)) {
|
||||
widget.onReorder(widget.columnId, fromIndex, toIndex);
|
||||
widget.phantomController.transformIndex(fromIndex, toIndex);
|
||||
}
|
||||
}),
|
||||
onDragEnded: () {
|
||||
widget.phantomController.columnEndDragging(widget.columnId);
|
||||
widget.onDragEnded?.call(widget.columnId);
|
||||
_printItems(widget.dataController);
|
||||
},
|
||||
dataSource: widget.dataController,
|
||||
dragTargetExtension: dragTargetExtension,
|
||||
children: children,
|
||||
);
|
||||
},
|
||||
opaque: false);
|
||||
final footer =
|
||||
widget.footBuilder?.call(context, widget.dataController.columnData);
|
||||
|
||||
final interceptor = CrossReorderFlexDragTargetInterceptor(
|
||||
reorderFlexId: widget.columnId,
|
||||
delegate: widget.phantomController,
|
||||
acceptReorderFlexIds: widget.acceptColumns,
|
||||
draggableTargetBuilder: PhantomDraggableBuilder(),
|
||||
);
|
||||
|
||||
final reorderFlex = ReorderFlex(
|
||||
key: widget.key,
|
||||
scrollController: widget.scrollController,
|
||||
config: widget.config,
|
||||
onDragStarted: (index) {
|
||||
widget.phantomController.columnStartDragging(widget.columnId);
|
||||
widget.onDragStarted?.call(index);
|
||||
},
|
||||
onReorder: ((fromIndex, toIndex) {
|
||||
if (widget.phantomController.isFromColumn(widget.columnId)) {
|
||||
widget.onReorder(widget.columnId, fromIndex, toIndex);
|
||||
widget.phantomController.transformIndex(fromIndex, toIndex);
|
||||
}
|
||||
}),
|
||||
onDragEnded: () {
|
||||
widget.phantomController.columnEndDragging(widget.columnId);
|
||||
widget.onDragEnded?.call(widget.columnId);
|
||||
_printItems(widget.dataController);
|
||||
},
|
||||
dataSource: widget.dataController,
|
||||
interceptor: interceptor,
|
||||
spacing: widget.spacing,
|
||||
children: children,
|
||||
);
|
||||
|
||||
return Column(
|
||||
children: [
|
||||
if (header != null) header,
|
||||
Expanded(child: reorderFlex),
|
||||
if (footer != null) footer,
|
||||
],
|
||||
);
|
||||
},
|
||||
opaque: false,
|
||||
);
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@ -127,7 +147,7 @@ class _BoardColumnWidgetState extends State<BoardColumnWidget> {
|
||||
passthroughPhantomContext: item.phantomContext,
|
||||
);
|
||||
} else {
|
||||
return widget.builder(context, item);
|
||||
return widget.cardBuilder(context, item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,12 +1,10 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import '../../flowy_board.dart';
|
||||
import '../rendering/board_overlay.dart';
|
||||
import 'flex/reorder_flex.dart';
|
||||
import 'board.dart';
|
||||
|
||||
class BoardColumnContainer extends StatefulWidget {
|
||||
final Widget? header;
|
||||
final Widget? footer;
|
||||
final ScrollController? scrollController;
|
||||
final OnDragStarted? onDragStarted;
|
||||
final OnReorder onReorder;
|
||||
@ -15,6 +13,7 @@ class BoardColumnContainer extends StatefulWidget {
|
||||
final List<Widget> children;
|
||||
final EdgeInsets? padding;
|
||||
final Widget? background;
|
||||
final double spacing;
|
||||
final ReorderFlexConfig config;
|
||||
|
||||
const BoardColumnContainer({
|
||||
@ -23,11 +22,10 @@ class BoardColumnContainer extends StatefulWidget {
|
||||
required this.children,
|
||||
this.onDragStarted,
|
||||
this.onDragEnded,
|
||||
this.header,
|
||||
this.footer,
|
||||
this.scrollController,
|
||||
this.padding,
|
||||
this.background,
|
||||
this.spacing = 0.0,
|
||||
this.config = const ReorderFlexConfig(),
|
||||
Key? key,
|
||||
}) : super(key: key);
|
||||
@ -47,8 +45,6 @@ class _BoardColumnContainerState extends State<BoardColumnContainer> {
|
||||
builder: (BuildContext context) {
|
||||
Widget reorderFlex = ReorderFlex(
|
||||
key: widget.key,
|
||||
header: widget.header,
|
||||
footer: widget.footer,
|
||||
scrollController: widget.scrollController,
|
||||
config: widget.config,
|
||||
onDragStarted: (index) {},
|
||||
@ -56,6 +52,7 @@ class _BoardColumnContainerState extends State<BoardColumnContainer> {
|
||||
onDragEnded: () {},
|
||||
dataSource: widget.boardDataController,
|
||||
direction: Axis.horizontal,
|
||||
spacing: widget.spacing,
|
||||
children: widget.children,
|
||||
);
|
||||
|
||||
@ -65,17 +62,7 @@ class _BoardColumnContainerState extends State<BoardColumnContainer> {
|
||||
child: reorderFlex,
|
||||
);
|
||||
}
|
||||
|
||||
return Expanded(
|
||||
child: Stack(
|
||||
alignment: AlignmentDirectional.center,
|
||||
children: [
|
||||
Container(
|
||||
color: Colors.red,
|
||||
),
|
||||
reorderFlex
|
||||
],
|
||||
));
|
||||
return _wrapStack(reorderFlex);
|
||||
},
|
||||
opaque: false);
|
||||
super.initState();
|
||||
@ -88,4 +75,14 @@ class _BoardColumnContainerState extends State<BoardColumnContainer> {
|
||||
initialEntries: [_overlayEntry],
|
||||
);
|
||||
}
|
||||
|
||||
Widget _wrapStack(Widget child) {
|
||||
return Stack(
|
||||
alignment: AlignmentDirectional.topStart,
|
||||
children: [
|
||||
if (widget.background != null) widget.background!,
|
||||
child,
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -4,7 +4,7 @@ abstract class DragTargetData {
|
||||
int get draggingIndex;
|
||||
}
|
||||
|
||||
abstract class ReorderDraggableTargetBuilder {
|
||||
abstract class ReorderFlexDraggableTargetBuilder {
|
||||
Widget? build<T extends DragTargetData>(
|
||||
BuildContext context,
|
||||
Widget child,
|
||||
@ -51,7 +51,7 @@ class ReorderDragTarget<T extends DragTargetData> extends StatefulWidget {
|
||||
/// the target.
|
||||
final void Function(T dragTargetData)? onLeave;
|
||||
|
||||
final ReorderDraggableTargetBuilder? draggableTargetBuilder;
|
||||
final ReorderFlexDraggableTargetBuilder? draggableTargetBuilder;
|
||||
|
||||
ReorderDragTarget({
|
||||
Key? key,
|
||||
@ -158,9 +158,10 @@ class _ReorderDragTargetState<T extends DragTargetData>
|
||||
transform: Matrix4.rotationZ(0),
|
||||
alignment: FractionalOffset.topLeft,
|
||||
child: Material(
|
||||
elevation: 3.0,
|
||||
elevation: 6.0,
|
||||
color: Colors.transparent,
|
||||
borderRadius: BorderRadius.zero,
|
||||
clipBehavior: Clip.hardEdge,
|
||||
child: ConstrainedBox(constraints: constraints, child: child),
|
||||
),
|
||||
);
|
||||
|
@ -0,0 +1,114 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import '../../utils/log.dart';
|
||||
import 'drag_state.dart';
|
||||
import 'drag_target.dart';
|
||||
import 'reorder_flex.dart';
|
||||
|
||||
abstract class ReorderFlexDragTargetInterceptor {
|
||||
bool canHandler(FlexDragTargetData dragTargetData);
|
||||
|
||||
bool onWillAccept(
|
||||
BuildContext context,
|
||||
ReorderFlexState reorderFlexState,
|
||||
FlexDragTargetData dragTargetData,
|
||||
int itemIndex,
|
||||
);
|
||||
|
||||
void onAccept(FlexDragTargetData dragTargetData);
|
||||
|
||||
void onLeave(FlexDragTargetData dragTargetData);
|
||||
|
||||
ReorderFlexDraggableTargetBuilder? get draggableTargetBuilder;
|
||||
}
|
||||
|
||||
abstract class CrossReorderFlexDragTargetDelegate {
|
||||
bool acceptNewDragTargetData(
|
||||
String columnId,
|
||||
FlexDragTargetData dragTargetData,
|
||||
int index,
|
||||
);
|
||||
void updateDragTargetData(
|
||||
String columnId,
|
||||
FlexDragTargetData dragTargetData,
|
||||
int index,
|
||||
);
|
||||
}
|
||||
|
||||
class CrossReorderFlexDragTargetInterceptor
|
||||
extends ReorderFlexDragTargetInterceptor {
|
||||
final String reorderFlexId;
|
||||
final List<String> acceptReorderFlexIds;
|
||||
final CrossReorderFlexDragTargetDelegate delegate;
|
||||
@override
|
||||
final ReorderFlexDraggableTargetBuilder? draggableTargetBuilder;
|
||||
|
||||
CrossReorderFlexDragTargetInterceptor({
|
||||
required this.reorderFlexId,
|
||||
required this.delegate,
|
||||
required this.acceptReorderFlexIds,
|
||||
this.draggableTargetBuilder,
|
||||
});
|
||||
|
||||
@override
|
||||
bool canHandler(FlexDragTargetData dragTargetData) {
|
||||
if (acceptReorderFlexIds.isEmpty) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (acceptReorderFlexIds.contains(dragTargetData.reorderFlexId)) {
|
||||
/// If the columnId equal to the dragTargetData's columnId,
|
||||
/// it means the dragTarget is dragging on the top of its own list.
|
||||
/// Otherwise, it means the dargTarget was moved to another list.
|
||||
return reorderFlexId != dragTargetData.reorderFlexId;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
bool onWillAccept(
|
||||
BuildContext context,
|
||||
ReorderFlexState reorderFlexState,
|
||||
FlexDragTargetData dragTargetData,
|
||||
int itemIndex,
|
||||
) {
|
||||
final isNewDragTarget = delegate.acceptNewDragTargetData(
|
||||
reorderFlexId,
|
||||
dragTargetData,
|
||||
itemIndex,
|
||||
);
|
||||
|
||||
if (isNewDragTarget == false) {
|
||||
delegate.updateDragTargetData(
|
||||
reorderFlexId,
|
||||
dragTargetData,
|
||||
itemIndex,
|
||||
);
|
||||
|
||||
reorderFlexState.onWillAccept(
|
||||
context,
|
||||
dragTargetData.draggingIndex,
|
||||
itemIndex,
|
||||
);
|
||||
} else {
|
||||
Log.debug(
|
||||
'[$CrossReorderFlexDragTargetInterceptor] move Column${dragTargetData.reorderFlexId}:${dragTargetData.draggingIndex} '
|
||||
'to Column$reorderFlexId:$itemIndex');
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@override
|
||||
void onAccept(FlexDragTargetData dragTargetData) {
|
||||
Log.trace(
|
||||
'[$CrossReorderFlexDragTargetInterceptor] Column$reorderFlexId on onAccept');
|
||||
}
|
||||
|
||||
@override
|
||||
void onLeave(FlexDragTargetData dragTargetData) {
|
||||
Log.trace(
|
||||
'[$CrossReorderFlexDragTargetInterceptor] Column$reorderFlexId on leave');
|
||||
}
|
||||
}
|
@ -2,12 +2,11 @@ import 'dart:math';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/rendering.dart';
|
||||
|
||||
import '../../utils/log.dart';
|
||||
import 'reorder_mixin.dart';
|
||||
import 'drag_target.dart';
|
||||
import 'drag_state.dart';
|
||||
import 'reorder_flex_ext.dart';
|
||||
import 'drag_target_inteceptor.dart';
|
||||
|
||||
typedef OnDragStarted = void Function(int index);
|
||||
typedef OnDragEnded = void Function();
|
||||
@ -33,14 +32,13 @@ class ReorderFlexConfig {
|
||||
}
|
||||
|
||||
class ReorderFlex extends StatefulWidget with DraggingReorderFlex {
|
||||
final Widget? header;
|
||||
final Widget? footer;
|
||||
final ReorderFlexConfig config;
|
||||
|
||||
final List<Widget> children;
|
||||
final EdgeInsets? padding;
|
||||
final double? spacing;
|
||||
final Axis direction;
|
||||
final MainAxisAlignment mainAxisAlignment = MainAxisAlignment.spaceEvenly;
|
||||
final MainAxisAlignment mainAxisAlignment = MainAxisAlignment.start;
|
||||
final ScrollController? scrollController;
|
||||
|
||||
final OnDragStarted? onDragStarted;
|
||||
@ -49,12 +47,10 @@ class ReorderFlex extends StatefulWidget with DraggingReorderFlex {
|
||||
|
||||
final ReoderFlextDataSource dataSource;
|
||||
|
||||
final ReorderFlextDragTargetExtension? dragTargetExtension;
|
||||
final ReorderFlexDragTargetInterceptor? interceptor;
|
||||
|
||||
const ReorderFlex({
|
||||
Key? key,
|
||||
this.header,
|
||||
this.footer,
|
||||
this.scrollController,
|
||||
required this.dataSource,
|
||||
required this.children,
|
||||
@ -62,9 +58,9 @@ class ReorderFlex extends StatefulWidget with DraggingReorderFlex {
|
||||
required this.onReorder,
|
||||
this.onDragStarted,
|
||||
this.onDragEnded,
|
||||
this.dragTargetExtension,
|
||||
// ignore: unused_element
|
||||
this.interceptor,
|
||||
this.padding,
|
||||
this.spacing,
|
||||
this.direction = Axis.vertical,
|
||||
}) : super(key: key);
|
||||
|
||||
@ -136,23 +132,19 @@ class ReorderFlexState extends State<ReorderFlex>
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final List<Widget> children = [];
|
||||
if (widget.header != null) {
|
||||
children.add(widget.header!);
|
||||
}
|
||||
|
||||
for (int i = 0; i < widget.children.length; i += 1) {
|
||||
Widget child = widget.children[i];
|
||||
if (widget.spacing != null) {
|
||||
children.add(SizedBox(width: widget.spacing!));
|
||||
}
|
||||
|
||||
final wrapChild = _wrap(child, i);
|
||||
children.add(wrapChild);
|
||||
}
|
||||
|
||||
if (widget.footer != null) {
|
||||
children.add(widget.footer!);
|
||||
}
|
||||
|
||||
return _wrapScrollView(
|
||||
child: _wrapContainer(children),
|
||||
);
|
||||
final child = _wrapContainer(children);
|
||||
return _wrapScrollView(child: child);
|
||||
}
|
||||
|
||||
@override
|
||||
@ -316,54 +308,49 @@ class ReorderFlexState extends State<ReorderFlex>
|
||||
});
|
||||
},
|
||||
onWillAccept: (FlexDragTargetData dragTargetData) {
|
||||
Log.debug(
|
||||
'[$ReorderDragTarget] ${widget.dataSource.identifier} on will accept, count: ${widget.dataSource.items.length}');
|
||||
assert(widget.dataSource.items.length > childIndex);
|
||||
|
||||
if (_requestDragExtensionToHanlder(
|
||||
if (_interceptDragTarget(
|
||||
dragTargetData,
|
||||
(extension) {
|
||||
extension.onWillAccept(
|
||||
this,
|
||||
builderContext,
|
||||
dragTargetData,
|
||||
dragState.isDragging(),
|
||||
dragTargetData.draggingIndex,
|
||||
childIndex,
|
||||
);
|
||||
},
|
||||
(interceptor) => interceptor.onWillAccept(
|
||||
builderContext,
|
||||
this,
|
||||
dragTargetData,
|
||||
childIndex,
|
||||
),
|
||||
)) {
|
||||
return true;
|
||||
} else {
|
||||
Log.debug(
|
||||
'[$ReorderDragTarget] ${widget.dataSource.identifier} on will accept, count: ${widget.dataSource.items.length}');
|
||||
final dragIndex = dragTargetData.draggingIndex;
|
||||
return onWillAccept(builderContext, dragIndex, childIndex);
|
||||
}
|
||||
},
|
||||
onAccept: (dragTargetData) {
|
||||
_requestDragExtensionToHanlder(
|
||||
_interceptDragTarget(
|
||||
dragTargetData,
|
||||
(extension) => extension.onAccept(dragTargetData),
|
||||
(interceptor) => interceptor.onAccept(dragTargetData),
|
||||
);
|
||||
},
|
||||
onLeave: (dragTargetData) {
|
||||
_requestDragExtensionToHanlder(
|
||||
_interceptDragTarget(
|
||||
dragTargetData,
|
||||
(extension) => extension.onLeave(dragTargetData),
|
||||
(interceptor) => interceptor.onLeave(dragTargetData),
|
||||
);
|
||||
},
|
||||
draggableTargetBuilder:
|
||||
widget.dragTargetExtension?.draggableTargetBuilder,
|
||||
draggableTargetBuilder: widget.interceptor?.draggableTargetBuilder,
|
||||
child: child,
|
||||
);
|
||||
}
|
||||
|
||||
bool _requestDragExtensionToHanlder(
|
||||
bool _interceptDragTarget(
|
||||
FlexDragTargetData dragTargetData,
|
||||
void Function(ReorderFlextDragTargetExtension) callback,
|
||||
void Function(ReorderFlexDragTargetInterceptor) callback,
|
||||
) {
|
||||
final extension = widget.dragTargetExtension;
|
||||
if (extension != null && extension.canHandler(dragTargetData)) {
|
||||
callback(extension);
|
||||
final interceptor = widget.interceptor;
|
||||
if (interceptor != null && interceptor.canHandler(dragTargetData)) {
|
||||
callback(interceptor);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
@ -466,14 +453,16 @@ class ReorderFlexState extends State<ReorderFlex>
|
||||
case Axis.horizontal:
|
||||
return Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisAlignment: widget.mainAxisAlignment,
|
||||
children: children,
|
||||
);
|
||||
case Axis.vertical:
|
||||
default:
|
||||
return Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisAlignment: widget.mainAxisAlignment,
|
||||
children: children,
|
||||
);
|
||||
}
|
||||
@ -514,9 +503,7 @@ class ReorderFlexState extends State<ReorderFlex>
|
||||
curve: Curves.easeInOut,
|
||||
)
|
||||
.then((void value) {
|
||||
setState(() {
|
||||
_scrolling = false;
|
||||
});
|
||||
setState(() => _scrolling = false);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -1,78 +0,0 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import '../../utils/log.dart';
|
||||
import 'drag_state.dart';
|
||||
import 'drag_target.dart';
|
||||
import 'reorder_flex.dart';
|
||||
|
||||
abstract class DragTargetExtensionDelegate {
|
||||
bool acceptNewDragTargetData(
|
||||
String columnId,
|
||||
FlexDragTargetData dragTargetData,
|
||||
int index,
|
||||
);
|
||||
void updateDragTargetData(
|
||||
String columnId,
|
||||
FlexDragTargetData dragTargetData,
|
||||
int index,
|
||||
);
|
||||
}
|
||||
|
||||
class ReorderFlextDragTargetExtension {
|
||||
final String reorderFlexId;
|
||||
final List<String> acceptReorderFlexIds;
|
||||
final DragTargetExtensionDelegate delegate;
|
||||
final ReorderDraggableTargetBuilder? draggableTargetBuilder;
|
||||
|
||||
ReorderFlextDragTargetExtension({
|
||||
required this.reorderFlexId,
|
||||
required this.delegate,
|
||||
required this.acceptReorderFlexIds,
|
||||
this.draggableTargetBuilder,
|
||||
});
|
||||
|
||||
bool canHandler(FlexDragTargetData dragTargetData) {
|
||||
/// If the columnId equal to the dragTargetData's columnId,
|
||||
/// it means the dragTarget is dragging on the top of its own list.
|
||||
/// Otherwise, it means the dargTarget was moved to another list.
|
||||
///
|
||||
if (!acceptReorderFlexIds.contains(dragTargetData.reorderFlexId)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return reorderFlexId != dragTargetData.reorderFlexId;
|
||||
}
|
||||
|
||||
bool onWillAccept(
|
||||
ReorderFlexState reorderFlexState,
|
||||
BuildContext context,
|
||||
FlexDragTargetData dragTargetData,
|
||||
bool isDragging,
|
||||
int dragIndex,
|
||||
int itemIndex,
|
||||
) {
|
||||
final isNewDragTarget = delegate.acceptNewDragTargetData(
|
||||
reorderFlexId, dragTargetData, itemIndex);
|
||||
|
||||
if (isNewDragTarget == false) {
|
||||
delegate.updateDragTargetData(reorderFlexId, dragTargetData, itemIndex);
|
||||
reorderFlexState.onWillAccept(context, dragIndex, itemIndex);
|
||||
} else {
|
||||
Log.debug(
|
||||
'[$ReorderFlextDragTargetExtension] move Column${dragTargetData.reorderFlexId}:${dragTargetData.draggingIndex} '
|
||||
'to Column$reorderFlexId:$itemIndex');
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void onAccept(FlexDragTargetData dragTargetData) {
|
||||
Log.trace(
|
||||
'[$ReorderFlextDragTargetExtension] Column$reorderFlexId on onAccept');
|
||||
}
|
||||
|
||||
void onLeave(FlexDragTargetData dragTargetData) {
|
||||
Log.trace(
|
||||
'[$ReorderFlextDragTargetExtension] Column$reorderFlexId on leave');
|
||||
}
|
||||
}
|
@ -3,7 +3,7 @@ import '../../../flowy_board.dart';
|
||||
import '../../utils/log.dart';
|
||||
import '../flex/drag_state.dart';
|
||||
import '../flex/drag_target.dart';
|
||||
import '../flex/reorder_flex_ext.dart';
|
||||
import '../flex/drag_target_inteceptor.dart';
|
||||
import 'phantom_state.dart';
|
||||
|
||||
abstract class BoardPhantomControllerDelegate {
|
||||
@ -14,7 +14,7 @@ mixin ColumnDataPhantomMixim {
|
||||
BoardColumnDataController? get;
|
||||
}
|
||||
|
||||
class BoardPhantomController extends DragTargetExtensionDelegate {
|
||||
class BoardPhantomController extends CrossReorderFlexDragTargetDelegate {
|
||||
final BoardPhantomControllerDelegate delegate;
|
||||
|
||||
PhantomRecord? phantomRecord;
|
||||
@ -313,7 +313,7 @@ class PassthroughPhantomWidget extends PhantomWidget {
|
||||
);
|
||||
}
|
||||
|
||||
class PhantomReorderDraggableBuilder extends ReorderDraggableTargetBuilder {
|
||||
class PhantomDraggableBuilder extends ReorderFlexDraggableTargetBuilder {
|
||||
@override
|
||||
Widget? build<T extends DragTargetData>(
|
||||
BuildContext context,
|
||||
|
Loading…
Reference in New Issue
Block a user