chore: update documentation

This commit is contained in:
appflowy 2022-09-05 16:29:16 +08:00
parent a3d2cef40a
commit c7fdfb4090
16 changed files with 545 additions and 515 deletions

View File

@ -22,7 +22,7 @@ part 'board_bloc.freezed.dart';
class BoardBloc extends Bloc<BoardEvent, BoardState> {
final BoardDataController _gridDataController;
late final AFBoardDataController boardController;
late final AppFlowyBoardDataController boardController;
final MoveRowFFIService _rowService;
LinkedHashMap<String, GroupController> groupControllers = LinkedHashMap();
@ -34,8 +34,8 @@ class BoardBloc extends Bloc<BoardEvent, BoardState> {
: _rowService = MoveRowFFIService(gridId: view.id),
_gridDataController = BoardDataController(view: view),
super(BoardState.initial(view.id)) {
boardController = AFBoardDataController(
onMoveColumn: (
boardController = AppFlowyBoardDataController(
onMoveGroup: (
fromColumnId,
fromIndex,
toColumnId,
@ -43,7 +43,7 @@ class BoardBloc extends Bloc<BoardEvent, BoardState> {
) {
_moveGroup(fromColumnId, toColumnId);
},
onMoveColumnItem: (
onMoveGroupItem: (
columnId,
fromIndex,
toIndex,
@ -52,15 +52,15 @@ class BoardBloc extends Bloc<BoardEvent, BoardState> {
final toRow = groupControllers[columnId]?.rowAtIndex(toIndex);
_moveRow(fromRow, columnId, toRow);
},
onMoveColumnItemToColumn: (
fromColumnId,
onMoveGroupItemToGroup: (
fromGroupId,
fromIndex,
toColumnId,
toGroupId,
toIndex,
) {
final fromRow = groupControllers[fromColumnId]?.rowAtIndex(fromIndex);
final toRow = groupControllers[toColumnId]?.rowAtIndex(toIndex);
_moveRow(fromRow, toColumnId, toRow);
final fromRow = groupControllers[fromGroupId]?.rowAtIndex(fromIndex);
final toRow = groupControllers[toGroupId]?.rowAtIndex(toIndex);
_moveRow(fromRow, toGroupId, toRow);
},
);
@ -165,10 +165,10 @@ class BoardBloc extends Bloc<BoardEvent, BoardState> {
boardController.clear();
//
List<AFBoardColumnData> columns = groups
List<AppFlowyBoardGroupData> columns = groups
.where((group) => fieldController.getField(group.fieldId) != null)
.map((group) {
return AFBoardColumnData(
return AppFlowyBoardGroupData(
id: group.groupId,
name: group.desc,
items: _buildRows(group),
@ -178,7 +178,7 @@ class BoardBloc extends Bloc<BoardEvent, BoardState> {
),
);
}).toList();
boardController.addColumns(columns);
boardController.addGroups(columns);
for (final group in groups) {
final delegate = GroupControllerDelegateImpl(
@ -227,8 +227,8 @@ class BoardBloc extends Bloc<BoardEvent, BoardState> {
if (isClosed) return;
for (final group in updatedGroups) {
final columnController =
boardController.getColumnController(group.groupId);
columnController?.updateColumnName(group.desc);
boardController.getGroupController(group.groupId);
columnController?.updateGroupName(group.desc);
}
},
onError: (err) {
@ -243,13 +243,13 @@ class BoardBloc extends Bloc<BoardEvent, BoardState> {
);
}
List<AFColumnItem> _buildRows(GroupPB group) {
List<AppFlowyGroupItem> _buildRows(GroupPB group) {
final items = group.rows.map((row) {
final fieldContext = fieldController.getField(group.fieldId);
return BoardColumnItem(row: row, fieldContext: fieldContext!);
}).toList();
return <AFColumnItem>[...items];
return <AppFlowyGroupItem>[...items];
}
Future<void> _loadGrid(Emitter<BoardState> emit) async {
@ -335,7 +335,7 @@ class GridFieldEquatable extends Equatable {
UnmodifiableListView<FieldPB> get value => UnmodifiableListView(_fields);
}
class BoardColumnItem extends AFColumnItem {
class BoardColumnItem extends AppFlowyGroupItem {
final RowPB row;
final GridFieldContext fieldContext;
@ -350,7 +350,7 @@ class BoardColumnItem extends AFColumnItem {
class GroupControllerDelegateImpl extends GroupControllerDelegate {
final GridFieldController fieldController;
final AFBoardDataController controller;
final AppFlowyBoardDataController controller;
final void Function(String, RowPB, int?) onNewColumnItem;
GroupControllerDelegateImpl({
@ -369,16 +369,16 @@ class GroupControllerDelegateImpl extends GroupControllerDelegate {
if (index != null) {
final item = BoardColumnItem(row: row, fieldContext: fieldContext);
controller.insertColumnItem(group.groupId, index, item);
controller.insertGroupItem(group.groupId, index, item);
} else {
final item = BoardColumnItem(row: row, fieldContext: fieldContext);
controller.addColumnItem(group.groupId, item);
controller.addGroupItem(group.groupId, item);
}
}
@override
void removeRow(GroupPB group, String rowId) {
controller.removeColumnItem(group.groupId, rowId);
controller.removeGroupItem(group.groupId, rowId);
}
@override
@ -388,7 +388,7 @@ class GroupControllerDelegateImpl extends GroupControllerDelegate {
Log.warn("FieldContext should not be null");
return;
}
controller.updateColumnItem(
controller.updateGroupItem(
group.groupId,
BoardColumnItem(row: row, fieldContext: fieldContext),
);
@ -404,9 +404,9 @@ class GroupControllerDelegateImpl extends GroupControllerDelegate {
final item = BoardColumnItem(row: row, fieldContext: fieldContext);
if (index != null) {
controller.insertColumnItem(group.groupId, index, item);
controller.insertGroupItem(group.groupId, index, item);
} else {
controller.addColumnItem(group.groupId, item);
controller.addGroupItem(group.groupId, item);
}
onNewColumnItem(group.groupId, row, index);
}

View File

@ -65,8 +65,8 @@ class _BoardContentState extends State<BoardContent> {
late ScrollController scrollController;
late AFBoardScrollManager scrollManager;
final config = AFBoardConfig(
columnBackgroundColor: HexColor.fromHex('#F7F8FC'),
final config = AppFlowyBoardConfig(
groupBackgroundColor: HexColor.fromHex('#F7F8FC'),
);
@override
@ -101,7 +101,7 @@ class _BoardContentState extends State<BoardContent> {
Expanded _buildBoard(BuildContext context) {
return Expanded(
child: AFBoard(
child: AppFlowyBoard(
scrollManager: scrollManager,
scrollController: scrollController,
dataController: context.read<BoardBloc>().boardController,
@ -112,9 +112,9 @@ class _BoardContentState extends State<BoardContent> {
column,
columnItem,
),
columnConstraints: const BoxConstraints.tightFor(width: 300),
config: AFBoardConfig(
columnBackgroundColor: HexColor.fromHex('#F7F8FC'),
groupConstraints: const BoxConstraints.tightFor(width: 300),
config: AppFlowyBoardConfig(
groupBackgroundColor: HexColor.fromHex('#F7F8FC'),
),
),
);
@ -149,14 +149,14 @@ class _BoardContentState extends State<BoardContent> {
Widget _buildHeader(
BuildContext context,
AFBoardColumnData columnData,
AppFlowyBoardGroupData columnData,
) {
final boardCustomData = columnData.customData as BoardCustomData;
return AppFlowyColumnHeader(
return AppFlowyGroupHeader(
title: Flexible(
fit: FlexFit.tight,
child: FlowyText.medium(
columnData.headerData.columnName,
columnData.headerData.groupName,
fontSize: 14,
overflow: TextOverflow.clip,
color: context.read<AppTheme>().textColor,
@ -181,14 +181,14 @@ class _BoardContentState extends State<BoardContent> {
);
}
Widget _buildFooter(BuildContext context, AFBoardColumnData columnData) {
Widget _buildFooter(BuildContext context, AppFlowyBoardGroupData columnData) {
final boardCustomData = columnData.customData as BoardCustomData;
final group = boardCustomData.group;
if (group.isDefault) {
return const SizedBox();
} else {
return AppFlowyColumnFooter(
return AppFlowyGroupFooter(
icon: SizedBox(
height: 20,
width: 20,
@ -215,8 +215,8 @@ class _BoardContentState extends State<BoardContent> {
Widget _buildCard(
BuildContext context,
AFBoardColumnData column,
AFColumnItem columnItem,
AppFlowyBoardGroupData column,
AppFlowyGroupItem columnItem,
) {
final boardColumnItem = columnItem as BoardColumnItem;
final rowPB = boardColumnItem.row;
@ -242,7 +242,7 @@ class _BoardContentState extends State<BoardContent> {
},
);
return AppFlowyColumnItemCard(
return AppFlowyGroupItemCard(
key: ValueKey(columnItem.id),
margin: config.cardPadding,
decoration: _makeBoxDecoration(context),

View File

@ -9,6 +9,7 @@
<a href="https://twitter.com/appflowy"><b>Twitter</b></a>
</p>
<p align="center">
<img src="https://github.com/AppFlowy-IO/AppFlowy/blob/main/frontend/app_flowy/packages/appflowy_board/example/gifs/appflowy_board_video_1.gif?raw=true" width="680" title="AppFlowyBoard">
</p>
@ -30,6 +31,7 @@ Add the AppFlowy Board [Flutter package](https://docs.flutter.dev/development/pa
With Flutter:
```dart
flutter pub add appflowy_board
flutter pub get
```
This will add a line like this to your package's pubspec.yaml (and run an implicit flutter pub get):
@ -38,6 +40,8 @@ dependencies:
appflowy_board: ^0.0.6
```
## Create board
Import the package in your Dart file:
```dart
import 'package:appflowy_board/appflowy_board.dart';
@ -47,14 +51,18 @@ import 'package:appflowy_board/appflowy_board.dart';
To quickly grasp how it can be used, look at the /example/lib folder.
First, run main.dart to play with the demo.
Second, let's delve into multi_board_list_example.dart to understand a few key components:
* A Board widget is created via instantiating an AFBoard() object.
* In the AFBoard() object, you can find:
* AFBoardDataController, which is defined in board_data.dart, is feeded with prepopulated mock data. It also contains callback functions to materialize future user data.
* Three builders: AppFlowyColumnHeader, AppFlowyColumnFooter, AppFlowyColumnItemCard. See below image for what they are used for.
<p>
<!-- <p>
<img src="https://github.com/AppFlowy-IO/AppFlowy/blob/main/frontend/app_flowy/packages/appflowy_board/example/gifs/appflowy_board_builders.jpg?raw=true" width="100%" title="AppFlowyBoard">
</p>
</p> -->
## Glossary
Please refer to the API documentation.
@ -68,4 +76,4 @@ Please look at [CONTRIBUTING.md](https://appflowy.gitbook.io/docs/essential-docu
Distributed under the AGPLv3 License. See [LICENSE](https://github.com/AppFlowy-IO/AppFlowy-Docs/blob/main/LICENSE) for more information.
d

View File

@ -9,21 +9,22 @@ class MultiBoardListExample extends StatefulWidget {
}
class _MultiBoardListExampleState extends State<MultiBoardListExample> {
final AFBoardDataController boardDataController = AFBoardDataController(
onMoveColumn: (fromColumnId, fromIndex, toColumnId, toIndex) {
final AppFlowyBoardDataController boardDataController =
AppFlowyBoardDataController(
onMoveGroup: (fromColumnId, fromIndex, toColumnId, toIndex) {
// debugPrint('Move column from $fromIndex to $toIndex');
},
onMoveColumnItem: (columnId, fromIndex, toIndex) {
onMoveGroupItem: (columnId, fromIndex, toIndex) {
// debugPrint('Move $columnId:$fromIndex to $columnId:$toIndex');
},
onMoveColumnItemToColumn: (fromColumnId, fromIndex, toColumnId, toIndex) {
onMoveGroupItemToGroup: (fromColumnId, fromIndex, toColumnId, toIndex) {
// debugPrint('Move $fromColumnId:$fromIndex to $toColumnId:$toIndex');
},
);
@override
void initState() {
List<AFColumnItem> a = [
List<AppFlowyGroupItem> a = [
TextItem("Card 1"),
TextItem("Card 2"),
RichTextItem(title: "Card 3", subtitle: 'Aug 1, 2020 4:05 PM'),
@ -35,82 +36,83 @@ class _MultiBoardListExampleState extends State<MultiBoardListExample> {
TextItem("Card 9"),
];
final column1 = AFBoardColumnData(id: "To Do", name: "To Do", items: a);
final column2 = AFBoardColumnData(
final column1 =
AppFlowyBoardGroupData(id: "To Do", name: "To Do", items: a);
final column2 = AppFlowyBoardGroupData(
id: "In Progress",
name: "In Progress",
items: <AFColumnItem>[
items: <AppFlowyGroupItem>[
RichTextItem(title: "Card 10", subtitle: 'Aug 1, 2020 4:05 PM'),
TextItem("Card 11"),
],
);
final column3 =
AFBoardColumnData(id: "Done", name: "Done", items: <AFColumnItem>[]);
final column3 = AppFlowyBoardGroupData(
id: "Done", name: "Done", items: <AppFlowyGroupItem>[]);
boardDataController.addColumn(column1);
boardDataController.addColumn(column2);
boardDataController.addColumn(column3);
boardDataController.addGroup(column1);
boardDataController.addGroup(column2);
boardDataController.addGroup(column3);
super.initState();
}
@override
Widget build(BuildContext context) {
final config = AFBoardConfig(
columnBackgroundColor: HexColor.fromHex('#F7F8FC'),
final config = AppFlowyBoardConfig(
groupBackgroundColor: HexColor.fromHex('#F7F8FC'),
);
return Container(
color: Colors.white,
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 30, horizontal: 20),
child: AFBoard(
child: AppFlowyBoard(
dataController: boardDataController,
footerBuilder: (context, columnData) {
return AppFlowyColumnFooter(
return AppFlowyGroupFooter(
icon: const Icon(Icons.add, size: 20),
title: const Text('New'),
height: 50,
margin: config.columnItemPadding,
margin: config.groupItemPadding,
);
},
headerBuilder: (context, columnData) {
return AppFlowyColumnHeader(
return AppFlowyGroupHeader(
icon: const Icon(Icons.lightbulb_circle),
title: SizedBox(
width: 60,
child: TextField(
controller: TextEditingController()
..text = columnData.headerData.columnName,
..text = columnData.headerData.groupName,
onSubmitted: (val) {
boardDataController
.getColumnController(columnData.headerData.columnId)!
.updateColumnName(val);
.getGroupController(columnData.headerData.groupId)!
.updateGroupName(val);
},
),
),
addIcon: const Icon(Icons.add, size: 20),
moreIcon: const Icon(Icons.more_horiz, size: 20),
height: 50,
margin: config.columnItemPadding,
margin: config.groupItemPadding,
);
},
cardBuilder: (context, column, columnItem) {
return AppFlowyColumnItemCard(
return AppFlowyGroupItemCard(
key: ValueKey(columnItem.id),
child: _buildCard(columnItem),
);
},
columnConstraints: const BoxConstraints.tightFor(width: 240),
config: AFBoardConfig(
columnBackgroundColor: HexColor.fromHex('#F7F8FC'),
groupConstraints: const BoxConstraints.tightFor(width: 240),
config: AppFlowyBoardConfig(
groupBackgroundColor: HexColor.fromHex('#F7F8FC'),
),
),
),
);
}
Widget _buildCard(AFColumnItem item) {
Widget _buildCard(AppFlowyGroupItem item) {
if (item is TextItem) {
return Align(
alignment: Alignment.centerLeft,
@ -172,7 +174,7 @@ class _RichTextCardState extends State<RichTextCard> {
}
}
class TextItem extends AFColumnItem {
class TextItem extends AppFlowyGroupItem {
final String s;
TextItem(this.s);
@ -181,7 +183,7 @@ class TextItem extends AFColumnItem {
String get id => s;
}
class RichTextItem extends AFColumnItem {
class RichTextItem extends AppFlowyGroupItem {
final String title;
final String subtitle;

View File

@ -9,11 +9,11 @@ class SingleBoardListExample extends StatefulWidget {
}
class _SingleBoardListExampleState extends State<SingleBoardListExample> {
final AFBoardDataController boardData = AFBoardDataController();
final AppFlowyBoardDataController boardData = AppFlowyBoardDataController();
@override
void initState() {
final column = AFBoardColumnData(
final column = AppFlowyBoardGroupData(
id: "1",
name: "1",
items: [
@ -24,13 +24,13 @@ class _SingleBoardListExampleState extends State<SingleBoardListExample> {
],
);
boardData.addColumn(column);
boardData.addGroup(column);
super.initState();
}
@override
Widget build(BuildContext context) {
return AFBoard(
return AppFlowyBoard(
dataController: boardData,
cardBuilder: (context, column, columnItem) {
return _RowWidget(
@ -55,7 +55,7 @@ class _RowWidget extends StatelessWidget {
}
}
class TextItem extends AFColumnItem {
class TextItem extends AppFlowyGroupItem {
final String s;
TextItem(this.s);

View File

@ -11,70 +11,78 @@ import 'reorder_phantom/phantom_controller.dart';
import '../rendering/board_overlay.dart';
class AFBoardScrollManager {
BoardColumnsState? _columnState;
BoardGroupsState? _groupState;
// AFBoardScrollManager();
void scrollToBottom(String columnId, VoidCallback? completed) {
_columnState
?.getReorderFlexState(columnId: columnId)
void scrollToBottom(String groupId, VoidCallback? completed) {
_groupState
?.getReorderFlexState(groupId: groupId)
?.scrollToBottom(completed);
}
}
class AFBoardConfig {
class AppFlowyBoardConfig {
final double cornerRadius;
final EdgeInsets columnPadding;
final EdgeInsets columnItemPadding;
final EdgeInsets groupPadding;
final EdgeInsets groupItemPadding;
final EdgeInsets footerPadding;
final EdgeInsets headerPadding;
final EdgeInsets cardPadding;
final Color columnBackgroundColor;
final Color groupBackgroundColor;
const AFBoardConfig({
const AppFlowyBoardConfig({
this.cornerRadius = 6.0,
this.columnPadding = const EdgeInsets.symmetric(horizontal: 8),
this.columnItemPadding = const EdgeInsets.symmetric(horizontal: 12),
this.groupPadding = const EdgeInsets.symmetric(horizontal: 8),
this.groupItemPadding = const EdgeInsets.symmetric(horizontal: 12),
this.footerPadding = const EdgeInsets.symmetric(horizontal: 12),
this.headerPadding = const EdgeInsets.symmetric(horizontal: 16),
this.cardPadding = const EdgeInsets.symmetric(horizontal: 3, vertical: 4),
this.columnBackgroundColor = Colors.transparent,
this.groupBackgroundColor = Colors.transparent,
});
}
class AFBoard extends StatelessWidget {
class AppFlowyBoard extends StatelessWidget {
/// The direction to use as the main axis.
final Axis direction = Axis.vertical;
///
/// The widget that will be rendered as the background of the board.
final Widget? background;
/// The [cardBuilder] function which will be invoked on each card build.
/// The [cardBuilder] takes the [BuildContext],[AppFlowyBoardGroupData] and
/// the corresponding [AppFlowyGroupItem].
///
final AFBoardColumnCardBuilder cardBuilder;
/// must return a widget.
final AppFlowyBoardCardBuilder cardBuilder;
/// The [headerBuilder] function which will be invoked on each group build.
/// The [headerBuilder] takes the [BuildContext] and [AppFlowyBoardGroupData].
///
/// must return a widget.
final AppFlowyBoardHeaderBuilder? headerBuilder;
/// The [footerBuilder] function which will be invoked on each group build.
/// The [footerBuilder] takes the [BuildContext] and [AppFlowyBoardGroupData].
///
/// must return a widget.
final AppFlowyBoardFooterBuilder? footerBuilder;
///
final AFBoardColumnHeaderBuilder? headerBuilder;
final AppFlowyBoardDataController dataController;
///
final AFBoardColumnFooterBuilder? footerBuilder;
///
final AFBoardDataController dataController;
final BoxConstraints columnConstraints;
final BoxConstraints groupConstraints;
///
late final BoardPhantomController phantomController;
final ScrollController? scrollController;
final AFBoardConfig config;
final AppFlowyBoardConfig config;
final AFBoardScrollManager? scrollManager;
final BoardColumnsState _columnState = BoardColumnsState();
final BoardGroupsState _groupState = BoardGroupsState();
AFBoard({
AppFlowyBoard({
required this.dataController,
required this.cardBuilder,
this.background,
@ -82,13 +90,13 @@ class AFBoard extends StatelessWidget {
this.headerBuilder,
this.scrollController,
this.scrollManager,
this.columnConstraints = const BoxConstraints(maxWidth: 200),
this.config = const AFBoardConfig(),
this.groupConstraints = const BoxConstraints(maxWidth: 200),
this.config = const AppFlowyBoardConfig(),
Key? key,
}) : super(key: key) {
phantomController = BoardPhantomController(
delegate: dataController,
columnsState: _columnState,
groupsState: _groupState,
);
}
@ -96,10 +104,10 @@ class AFBoard extends StatelessWidget {
Widget build(BuildContext context) {
return ChangeNotifierProvider.value(
value: dataController,
child: Consumer<AFBoardDataController>(
child: Consumer<AppFlowyBoardDataController>(
builder: (context, notifier, child) {
if (scrollManager != null) {
scrollManager!._columnState = _columnState;
scrollManager!._groupState = _groupState;
}
return AFBoardContent(
@ -107,15 +115,15 @@ class AFBoard extends StatelessWidget {
dataController: dataController,
scrollController: scrollController,
scrollManager: scrollManager,
columnsState: _columnState,
columnsState: _groupState,
background: background,
delegate: phantomController,
columnConstraints: columnConstraints,
columnConstraints: groupConstraints,
cardBuilder: cardBuilder,
footBuilder: footerBuilder,
footerBuilder: footerBuilder,
headerBuilder: headerBuilder,
phantomController: phantomController,
onReorder: dataController.moveColumn,
onReorder: dataController.moveGroup,
);
},
),
@ -128,22 +136,22 @@ class AFBoardContent extends StatefulWidget {
final OnDragStarted? onDragStarted;
final OnReorder onReorder;
final OnDragEnded? onDragEnded;
final AFBoardDataController dataController;
final AppFlowyBoardDataController dataController;
final Widget? background;
final AFBoardConfig config;
final AppFlowyBoardConfig config;
final ReorderFlexConfig reorderFlexConfig;
final BoxConstraints columnConstraints;
final AFBoardScrollManager? scrollManager;
final BoardColumnsState columnsState;
final BoardGroupsState columnsState;
///
final AFBoardColumnCardBuilder cardBuilder;
final AppFlowyBoardCardBuilder cardBuilder;
///
final AFBoardColumnHeaderBuilder? headerBuilder;
final AppFlowyBoardHeaderBuilder? headerBuilder;
///
final AFBoardColumnFooterBuilder? footBuilder;
final AppFlowyBoardFooterBuilder? footerBuilder;
final OverlapDragTargetDelegate delegate;
@ -162,7 +170,7 @@ class AFBoardContent extends StatefulWidget {
this.background,
required this.columnConstraints,
required this.cardBuilder,
this.footBuilder,
this.footerBuilder,
this.headerBuilder,
required this.phantomController,
Key? key,
@ -178,13 +186,15 @@ class _AFBoardContentState extends State<AFBoardContent> {
GlobalKey(debugLabel: '$AFBoardContent overlay key');
late BoardOverlayEntry _overlayEntry;
final Map<String, GlobalObjectKey> _reorderFlexKeys = {};
@override
void initState() {
_overlayEntry = BoardOverlayEntry(
builder: (BuildContext context) {
final interceptor = OverlappingDragTargetInterceptor(
reorderFlexId: widget.dataController.identifier,
acceptedReorderFlexId: widget.dataController.columnIds,
acceptedReorderFlexId: widget.dataController.groupIds,
delegate: widget.delegate,
columnsState: widget.columnsState,
);
@ -233,40 +243,45 @@ class _AFBoardContentState extends State<AFBoardContent> {
List<Widget> _buildColumns() {
final List<Widget> children =
widget.dataController.columnDatas.asMap().entries.map(
widget.dataController.groupDatas.asMap().entries.map(
(item) {
final columnData = item.value;
final columnIndex = item.key;
final dataSource = _BoardColumnDataSourceImpl(
columnId: columnData.id,
final dataSource = _BoardGroupDataSourceImpl(
groupId: columnData.id,
dataController: widget.dataController,
);
if (_reorderFlexKeys[columnData.id] == null) {
_reorderFlexKeys[columnData.id] = GlobalObjectKey(columnData.id);
}
GlobalObjectKey reorderFlexKey = _reorderFlexKeys[columnData.id]!;
return ChangeNotifierProvider.value(
key: ValueKey(columnData.id),
value: widget.dataController.getColumnController(columnData.id),
child: Consumer<AFBoardColumnDataController>(
value: widget.dataController.getGroupController(columnData.id),
child: Consumer<AFBoardGroupDataController>(
builder: (context, value, child) {
final boardColumn = AFBoardColumnWidget(
final boardColumn = AppFlowyBoardGroupWidget(
reorderFlexKey: reorderFlexKey,
// key: PageStorageKey<String>(columnData.id),
margin: _marginFromIndex(columnIndex),
itemMargin: widget.config.columnItemPadding,
itemMargin: widget.config.groupItemPadding,
headerBuilder: _buildHeader,
footBuilder: widget.footBuilder,
footerBuilder: widget.footerBuilder,
cardBuilder: widget.cardBuilder,
dataSource: dataSource,
scrollController: ScrollController(),
phantomController: widget.phantomController,
onReorder: widget.dataController.moveColumnItem,
onReorder: widget.dataController.moveGroupItem,
cornerRadius: widget.config.cornerRadius,
backgroundColor: widget.config.columnBackgroundColor,
backgroundColor: widget.config.groupBackgroundColor,
dragStateStorage: widget.columnsState,
dragTargetIndexKeyStorage: widget.columnsState,
);
widget.columnsState.addColumn(columnData.id, boardColumn);
widget.columnsState.addGroup(columnData.id, boardColumn);
return ConstrainedBox(
constraints: widget.columnConstraints,
child: boardColumn,
@ -282,79 +297,79 @@ class _AFBoardContentState extends State<AFBoardContent> {
Widget? _buildHeader(
BuildContext context,
AFBoardColumnData columnData,
AppFlowyBoardGroupData groupData,
) {
if (widget.headerBuilder == null) {
return null;
}
return Selector<AFBoardColumnDataController, AFBoardColumnHeaderData>(
selector: (context, controller) => controller.columnData.headerData,
return Selector<AFBoardGroupDataController, AppFlowyBoardGroupHeaderData>(
selector: (context, controller) => controller.groupData.headerData,
builder: (context, headerData, _) {
return widget.headerBuilder!(context, columnData)!;
return widget.headerBuilder!(context, groupData)!;
},
);
}
EdgeInsets _marginFromIndex(int index) {
if (widget.dataController.columnDatas.isEmpty) {
return widget.config.columnPadding;
if (widget.dataController.groupDatas.isEmpty) {
return widget.config.groupPadding;
}
if (index == 0) {
return EdgeInsets.only(right: widget.config.columnPadding.right);
return EdgeInsets.only(right: widget.config.groupPadding.right);
}
if (index == widget.dataController.columnDatas.length - 1) {
return EdgeInsets.only(left: widget.config.columnPadding.left);
if (index == widget.dataController.groupDatas.length - 1) {
return EdgeInsets.only(left: widget.config.groupPadding.left);
}
return widget.config.columnPadding;
return widget.config.groupPadding;
}
}
class _BoardColumnDataSourceImpl extends AFBoardColumnDataDataSource {
String columnId;
final AFBoardDataController dataController;
class _BoardGroupDataSourceImpl extends AppFlowyBoardGroupDataDataSource {
String groupId;
final AppFlowyBoardDataController dataController;
_BoardColumnDataSourceImpl({
required this.columnId,
_BoardGroupDataSourceImpl({
required this.groupId,
required this.dataController,
});
@override
AFBoardColumnData get columnData =>
dataController.getColumnController(columnId)!.columnData;
AppFlowyBoardGroupData get groupData =>
dataController.getGroupController(groupId)!.groupData;
@override
List<String> get acceptedColumnIds => dataController.columnIds;
List<String> get acceptedGroupIds => dataController.groupIds;
}
class BoardColumnContext {
GlobalKey? columnKey;
class BoardGroupContext {
GlobalKey? groupKey;
DraggingState? draggingState;
}
class BoardColumnsState extends DraggingStateStorage
class BoardGroupsState extends DraggingStateStorage
with ReorderDragTargetIndexKeyStorage {
/// Quick access to the [AFBoardColumnWidget]
final Map<String, GlobalKey> columnKeys = {};
final Map<String, DraggingState> columnDragStates = {};
final Map<String, Map<String, GlobalObjectKey>> columnDragDragTargets = {};
/// Quick access to the [AppFlowyBoardGroupWidget]
final Map<String, GlobalKey> groupKeys = {};
final Map<String, DraggingState> groupDragStates = {};
final Map<String, Map<String, GlobalObjectKey>> groupDragDragTargets = {};
void addColumn(String columnId, AFBoardColumnWidget columnWidget) {
columnKeys[columnId] = columnWidget.globalKey;
void addGroup(String groupId, AppFlowyBoardGroupWidget groupWidget) {
groupKeys[groupId] = groupWidget.reorderFlexKey;
}
ReorderFlexState? getReorderFlexState({required String columnId}) {
final flexGlobalKey = columnKeys[columnId];
ReorderFlexState? getReorderFlexState({required String groupId}) {
final flexGlobalKey = groupKeys[groupId];
if (flexGlobalKey == null) return null;
if (flexGlobalKey.currentState is! ReorderFlexState) return null;
final state = flexGlobalKey.currentState as ReorderFlexState;
return state;
}
ReorderFlex? getReorderFlex({required String columnId}) {
final flexGlobalKey = columnKeys[columnId];
ReorderFlex? getReorderFlex({required String groupId}) {
final flexGlobalKey = groupKeys[groupId];
if (flexGlobalKey == null) return null;
if (flexGlobalKey.currentWidget is! ReorderFlex) return null;
final widget = flexGlobalKey.currentWidget as ReorderFlex;
@ -363,18 +378,18 @@ class BoardColumnsState extends DraggingStateStorage
@override
DraggingState? read(String reorderFlexId) {
return columnDragStates[reorderFlexId];
return groupDragStates[reorderFlexId];
}
@override
void write(String reorderFlexId, DraggingState state) {
Log.trace('$reorderFlexId Write dragging state: $state');
columnDragStates[reorderFlexId] = state;
groupDragStates[reorderFlexId] = state;
}
@override
void remove(String reorderFlexId) {
columnDragStates.remove(reorderFlexId);
groupDragStates.remove(reorderFlexId);
}
@override
@ -383,20 +398,20 @@ class BoardColumnsState extends DraggingStateStorage
String key,
GlobalObjectKey<State<StatefulWidget>> value,
) {
Map<String, GlobalObjectKey>? column = columnDragDragTargets[reorderFlexId];
if (column == null) {
column = {};
columnDragDragTargets[reorderFlexId] = column;
Map<String, GlobalObjectKey>? group = groupDragDragTargets[reorderFlexId];
if (group == null) {
group = {};
groupDragDragTargets[reorderFlexId] = group;
}
column[key] = value;
group[key] = value;
}
@override
GlobalObjectKey<State<StatefulWidget>>? readKey(
String reorderFlexId, String key) {
Map<String, GlobalObjectKey>? column = columnDragDragTargets[reorderFlexId];
if (column != null) {
return column[key];
Map<String, GlobalObjectKey>? group = groupDragDragTargets[reorderFlexId];
if (group != null) {
return group[key];
} else {
return null;
}

View File

@ -9,49 +9,49 @@ import '../reorder_flex/reorder_flex.dart';
import '../reorder_flex/drag_target_interceptor.dart';
import 'board_column_data.dart';
typedef OnColumnDragStarted = void Function(int index);
typedef OnGroupDragStarted = void Function(int index);
typedef OnColumnDragEnded = void Function(String listId);
typedef OnGroupDragEnded = void Function(String listId);
typedef OnColumnReorder = void Function(
typedef OnGroupReorder = void Function(
String listId,
int fromIndex,
int toIndex,
);
typedef OnColumnDeleted = void Function(String listId, int deletedIndex);
typedef OnGroupDeleted = void Function(String listId, int deletedIndex);
typedef OnColumnInserted = void Function(String listId, int insertedIndex);
typedef OnGroupInserted = void Function(String listId, int insertedIndex);
typedef AFBoardColumnCardBuilder = Widget Function(
typedef AppFlowyBoardCardBuilder = Widget Function(
BuildContext context,
AFBoardColumnData columnData,
AFColumnItem item,
AppFlowyBoardGroupData groupData,
AppFlowyGroupItem item,
);
typedef AFBoardColumnHeaderBuilder = Widget? Function(
typedef AppFlowyBoardHeaderBuilder = Widget? Function(
BuildContext context,
AFBoardColumnData columnData,
AppFlowyBoardGroupData groupData,
);
typedef AFBoardColumnFooterBuilder = Widget Function(
typedef AppFlowyBoardFooterBuilder = Widget Function(
BuildContext context,
AFBoardColumnData columnData,
AppFlowyBoardGroupData groupData,
);
abstract class AFBoardColumnDataDataSource extends ReoderFlexDataSource {
AFBoardColumnData get columnData;
abstract class AppFlowyBoardGroupDataDataSource extends ReoderFlexDataSource {
AppFlowyBoardGroupData get groupData;
List<String> get acceptedColumnIds;
List<String> get acceptedGroupIds;
@override
String get identifier => columnData.id;
String get identifier => groupData.id;
@override
UnmodifiableListView<AFColumnItem> get items => columnData.items;
UnmodifiableListView<AppFlowyGroupItem> get items => groupData.items;
void debugPrint() {
String msg = '[$AFBoardColumnDataDataSource] $columnData data: ';
String msg = '[$AppFlowyBoardGroupDataDataSource] $groupData data: ';
for (var element in items) {
msg = '$msg$element,';
}
@ -60,25 +60,25 @@ abstract class AFBoardColumnDataDataSource extends ReoderFlexDataSource {
}
}
/// [AFBoardColumnWidget] represents the column of the Board.
/// [AppFlowyBoardGroupWidget] represents the column of the Board.
///
class AFBoardColumnWidget extends StatefulWidget {
final AFBoardColumnDataDataSource dataSource;
class AppFlowyBoardGroupWidget extends StatefulWidget {
final AppFlowyBoardGroupDataDataSource dataSource;
final ScrollController? scrollController;
final ReorderFlexConfig config;
final OnColumnDragStarted? onDragStarted;
final OnColumnReorder onReorder;
final OnColumnDragEnded? onDragEnded;
final OnGroupDragStarted? onDragStarted;
final OnGroupReorder onReorder;
final OnGroupDragEnded? onDragEnded;
final BoardPhantomController phantomController;
String get columnId => dataSource.columnData.id;
String get groupId => dataSource.groupData.id;
final AFBoardColumnCardBuilder cardBuilder;
final AppFlowyBoardCardBuilder cardBuilder;
final AFBoardColumnHeaderBuilder? headerBuilder;
final AppFlowyBoardHeaderBuilder? headerBuilder;
final AFBoardColumnFooterBuilder? footBuilder;
final AppFlowyBoardFooterBuilder? footerBuilder;
final EdgeInsets margin;
@ -92,12 +92,13 @@ class AFBoardColumnWidget extends StatefulWidget {
final ReorderDragTargetIndexKeyStorage? dragTargetIndexKeyStorage;
final GlobalObjectKey globalKey;
final GlobalObjectKey reorderFlexKey;
AFBoardColumnWidget({
const AppFlowyBoardGroupWidget({
Key? key,
required this.reorderFlexKey,
this.headerBuilder,
this.footBuilder,
this.footerBuilder,
required this.cardBuilder,
required this.onReorder,
required this.dataSource,
@ -111,59 +112,59 @@ class AFBoardColumnWidget extends StatefulWidget {
this.itemMargin = EdgeInsets.zero,
this.cornerRadius = 0.0,
this.backgroundColor = Colors.transparent,
}) : globalKey = GlobalObjectKey(dataSource.columnData.id),
config = const ReorderFlexConfig(setStateWhenEndDrag: false),
}) : config = const ReorderFlexConfig(setStateWhenEndDrag: false),
super(key: key);
@override
State<AFBoardColumnWidget> createState() => _AFBoardColumnWidgetState();
State<AppFlowyBoardGroupWidget> createState() =>
_AppFlowyBoardGroupWidgetState();
}
class _AFBoardColumnWidgetState extends State<AFBoardColumnWidget> {
class _AppFlowyBoardGroupWidgetState extends State<AppFlowyBoardGroupWidget> {
final GlobalKey _columnOverlayKey =
GlobalKey(debugLabel: '$AFBoardColumnWidget overlay key');
GlobalKey(debugLabel: '$AppFlowyBoardGroupWidget overlay key');
late BoardOverlayEntry _overlayEntry;
@override
void initState() {
_overlayEntry = BoardOverlayEntry(
builder: (BuildContext context) {
final children = widget.dataSource.columnData.items
final children = widget.dataSource.groupData.items
.map((item) => _buildWidget(context, item))
.toList();
final header =
widget.headerBuilder?.call(context, widget.dataSource.columnData);
widget.headerBuilder?.call(context, widget.dataSource.groupData);
final footer =
widget.footBuilder?.call(context, widget.dataSource.columnData);
widget.footerBuilder?.call(context, widget.dataSource.groupData);
final interceptor = CrossReorderFlexDragTargetInterceptor(
reorderFlexId: widget.columnId,
reorderFlexId: widget.groupId,
delegate: widget.phantomController,
acceptedReorderFlexIds: widget.dataSource.acceptedColumnIds,
acceptedReorderFlexIds: widget.dataSource.acceptedGroupIds,
draggableTargetBuilder: PhantomDraggableBuilder(),
);
Widget reorderFlex = ReorderFlex(
key: widget.globalKey,
key: widget.reorderFlexKey,
dragStateStorage: widget.dragStateStorage,
dragTargetIndexKeyStorage: widget.dragTargetIndexKeyStorage,
scrollController: widget.scrollController,
config: widget.config,
onDragStarted: (index) {
widget.phantomController.columnStartDragging(widget.columnId);
widget.phantomController.groupStartDragging(widget.groupId);
widget.onDragStarted?.call(index);
},
onReorder: ((fromIndex, toIndex) {
if (widget.phantomController.isFromColumn(widget.columnId)) {
widget.onReorder(widget.columnId, fromIndex, toIndex);
if (widget.phantomController.isFromGroup(widget.groupId)) {
widget.onReorder(widget.groupId, fromIndex, toIndex);
widget.phantomController.transformIndex(fromIndex, toIndex);
}
}),
onDragEnded: () {
widget.phantomController.columnEndDragging(widget.columnId);
widget.onDragEnded?.call(widget.columnId);
widget.phantomController.groupEndDragging(widget.groupId);
widget.onDragEnded?.call(widget.groupId);
widget.dataSource.debugPrint();
},
dataSource: widget.dataSource,
@ -171,6 +172,10 @@ class _AFBoardColumnWidgetState extends State<AFBoardColumnWidget> {
children: children,
);
reorderFlex = Expanded(
child: Padding(padding: widget.itemMargin, child: reorderFlex),
);
return Container(
margin: widget.margin,
clipBehavior: Clip.hardEdge,
@ -181,9 +186,7 @@ class _AFBoardColumnWidgetState extends State<AFBoardColumnWidget> {
child: Column(
children: [
if (header != null) header,
Expanded(
child: Padding(padding: widget.itemMargin, child: reorderFlex),
),
reorderFlex,
if (footer != null) footer,
],
),
@ -202,15 +205,15 @@ class _AFBoardColumnWidgetState extends State<AFBoardColumnWidget> {
);
}
Widget _buildWidget(BuildContext context, AFColumnItem item) {
if (item is PhantomColumnItem) {
Widget _buildWidget(BuildContext context, AppFlowyGroupItem item) {
if (item is PhantomGroupItem) {
return PassthroughPhantomWidget(
key: UniqueKey(),
opacity: widget.config.draggingWidgetOpacity,
passthroughPhantomContext: item.phantomContext,
);
} else {
return widget.cardBuilder(context, widget.dataSource.columnData, item);
return widget.cardBuilder(context, widget.dataSource.groupData, item);
}
}
}

View File

@ -5,14 +5,14 @@ import 'package:flutter/material.dart';
import '../../utils/log.dart';
import '../reorder_flex/reorder_flex.dart';
abstract class AFColumnItem extends ReoderFlexItem {
abstract class AppFlowyGroupItem extends ReoderFlexItem {
bool get isPhantom => false;
@override
String toString() => id;
}
/// [AFBoardColumnDataController] is used to handle the [AFBoardColumnData].
/// [AFBoardGroupDataController] is used to handle the [AppFlowyBoardGroupData].
/// * Remove an item by calling [removeAt] method.
/// * Move item to another position by calling [move] method.
/// * Insert item to index by calling [insert] method
@ -20,23 +20,23 @@ abstract class AFColumnItem extends ReoderFlexItem {
///
/// All there operations will notify listeners by default.
///
class AFBoardColumnDataController extends ChangeNotifier with EquatableMixin {
final AFBoardColumnData columnData;
class AFBoardGroupDataController extends ChangeNotifier with EquatableMixin {
final AppFlowyBoardGroupData groupData;
AFBoardColumnDataController({
required this.columnData,
AFBoardGroupDataController({
required this.groupData,
});
@override
List<Object?> get props => columnData.props;
List<Object?> get props => groupData.props;
/// Returns the readonly List<ColumnItem>
UnmodifiableListView<AFColumnItem> get items =>
UnmodifiableListView(columnData.items);
/// Returns the readonly List<AppFlowyGroupItem>
UnmodifiableListView<AppFlowyGroupItem> get items =>
UnmodifiableListView(groupData.items);
void updateColumnName(String newName) {
if (columnData.headerData.columnName != newName) {
columnData.headerData.columnName = newName;
void updateGroupName(String newName) {
if (groupData.headerData.groupName != newName) {
groupData.headerData.groupName = newName;
notifyListeners();
}
}
@ -46,19 +46,18 @@ class AFBoardColumnDataController extends ChangeNotifier with EquatableMixin {
/// * [notify] the default value of [notify] is true, it will notify the
/// listener. Set to [false] if you do not want to notify the listeners.
///
AFColumnItem removeAt(int index, {bool notify = true}) {
AppFlowyGroupItem removeAt(int index, {bool notify = true}) {
assert(index >= 0);
Log.debug(
'[$AFBoardColumnDataController] $columnData remove item at $index');
final item = columnData._items.removeAt(index);
Log.debug('[$AFBoardGroupDataController] $groupData remove item at $index');
final item = groupData._items.removeAt(index);
if (notify) {
notifyListeners();
}
return item;
}
void removeWhere(bool Function(AFColumnItem) condition) {
void removeWhere(bool Function(AppFlowyGroupItem) condition) {
final index = items.indexWhere(condition);
if (index != -1) {
removeAt(index);
@ -75,9 +74,9 @@ class AFBoardColumnDataController extends ChangeNotifier with EquatableMixin {
return false;
}
Log.debug(
'[$AFBoardColumnDataController] $columnData move item from $fromIndex to $toIndex');
final item = columnData._items.removeAt(fromIndex);
columnData._items.insert(toIndex, item);
'[$AFBoardGroupDataController] $groupData move item from $fromIndex to $toIndex');
final item = groupData._items.removeAt(fromIndex);
groupData._items.insert(toIndex, item);
notifyListeners();
return true;
}
@ -86,18 +85,18 @@ class AFBoardColumnDataController extends ChangeNotifier with EquatableMixin {
/// is true.
///
/// The default value of [notify] is true.
bool insert(int index, AFColumnItem item, {bool notify = true}) {
bool insert(int index, AppFlowyGroupItem item, {bool notify = true}) {
assert(index >= 0);
Log.debug(
'[$AFBoardColumnDataController] $columnData insert $item at $index');
'[$AFBoardGroupDataController] $groupData insert $item at $index');
if (_containsItem(item)) {
return false;
} else {
if (columnData._items.length > index) {
columnData._items.insert(index, item);
if (groupData._items.length > index) {
groupData._items.insert(index, item);
} else {
columnData._items.add(item);
groupData._items.add(item);
}
if (notify) notifyListeners();
@ -105,74 +104,75 @@ class AFBoardColumnDataController extends ChangeNotifier with EquatableMixin {
}
}
bool add(AFColumnItem item, {bool notify = true}) {
bool add(AppFlowyGroupItem item, {bool notify = true}) {
if (_containsItem(item)) {
return false;
} else {
columnData._items.add(item);
groupData._items.add(item);
if (notify) notifyListeners();
return true;
}
}
/// Replace the item at index with the [newItem].
void replace(int index, AFColumnItem newItem) {
if (columnData._items.isEmpty) {
columnData._items.add(newItem);
Log.debug('[$AFBoardColumnDataController] $columnData add $newItem');
void replace(int index, AppFlowyGroupItem newItem) {
if (groupData._items.isEmpty) {
groupData._items.add(newItem);
Log.debug('[$AFBoardGroupDataController] $groupData add $newItem');
} else {
if (index >= columnData._items.length) {
if (index >= groupData._items.length) {
return;
}
final removedItem = columnData._items.removeAt(index);
columnData._items.insert(index, newItem);
final removedItem = groupData._items.removeAt(index);
groupData._items.insert(index, newItem);
Log.debug(
'[$AFBoardColumnDataController] $columnData replace $removedItem with $newItem at $index');
'[$AFBoardGroupDataController] $groupData replace $removedItem with $newItem at $index');
}
notifyListeners();
}
void replaceOrInsertItem(AFColumnItem newItem) {
final index = columnData._items.indexWhere((item) => item.id == newItem.id);
void replaceOrInsertItem(AppFlowyGroupItem newItem) {
final index = groupData._items.indexWhere((item) => item.id == newItem.id);
if (index != -1) {
columnData._items.removeAt(index);
columnData._items.insert(index, newItem);
groupData._items.removeAt(index);
groupData._items.insert(index, newItem);
notifyListeners();
} else {
columnData._items.add(newItem);
groupData._items.add(newItem);
notifyListeners();
}
}
bool _containsItem(AFColumnItem item) {
return columnData._items.indexWhere((element) => element.id == item.id) !=
bool _containsItem(AppFlowyGroupItem item) {
return groupData._items.indexWhere((element) => element.id == item.id) !=
-1;
}
}
/// [AFBoardColumnData] represents the data of each Column of the Board.
class AFBoardColumnData<CustomData> extends ReoderFlexItem with EquatableMixin {
/// [AppFlowyBoardGroupData] represents the data of each group of the Board.
class AppFlowyBoardGroupData<CustomData> extends ReoderFlexItem
with EquatableMixin {
@override
final String id;
AFBoardColumnHeaderData headerData;
final List<AFColumnItem> _items;
AppFlowyBoardGroupHeaderData headerData;
final List<AppFlowyGroupItem> _items;
final CustomData? customData;
AFBoardColumnData({
AppFlowyBoardGroupData({
this.customData,
required this.id,
required String name,
List<AFColumnItem> items = const [],
List<AppFlowyGroupItem> items = const [],
}) : _items = items,
headerData = AFBoardColumnHeaderData(
columnId: id,
columnName: name,
headerData = AppFlowyBoardGroupHeaderData(
groupId: id,
groupName: name,
);
/// Returns the readonly List<ColumnItem>
UnmodifiableListView<AFColumnItem> get items =>
/// Returns the readonly List<AppFlowyGroupItem>
UnmodifiableListView<AppFlowyGroupItem> get items =>
UnmodifiableListView([..._items]);
@override
@ -180,13 +180,14 @@ class AFBoardColumnData<CustomData> extends ReoderFlexItem with EquatableMixin {
@override
String toString() {
return 'Column:[$id]';
return 'Group:[$id]';
}
}
class AFBoardColumnHeaderData {
String columnId;
String columnName;
class AppFlowyBoardGroupHeaderData {
String groupId;
String groupName;
AFBoardColumnHeaderData({required this.columnId, required this.columnName});
AppFlowyBoardGroupHeaderData(
{required this.groupId, required this.groupName});
}

View File

@ -8,213 +8,213 @@ import 'reorder_flex/reorder_flex.dart';
import 'package:flutter/material.dart';
import 'reorder_phantom/phantom_controller.dart';
typedef OnMoveColumn = void Function(
String fromColumnId,
typedef OnMoveGroup = void Function(
String fromGroupId,
int fromIndex,
String toColumnId,
String toGroupId,
int toIndex,
);
typedef OnMoveColumnItem = void Function(
String columnId,
typedef OnMoveGroupItem = void Function(
String groupId,
int fromIndex,
int toIndex,
);
typedef OnMoveColumnItemToColumn = void Function(
String fromColumnId,
typedef OnMoveGroupItemToGroup = void Function(
String fromGroupId,
int fromIndex,
String toColumnId,
String toGroupId,
int toIndex,
);
class AFBoardDataController extends ChangeNotifier
class AppFlowyBoardDataController extends ChangeNotifier
with EquatableMixin, BoardPhantomControllerDelegate, ReoderFlexDataSource {
final List<AFBoardColumnData> _columnDatas = [];
final OnMoveColumn? onMoveColumn;
final OnMoveColumnItem? onMoveColumnItem;
final OnMoveColumnItemToColumn? onMoveColumnItemToColumn;
final List<AppFlowyBoardGroupData> _groupDatas = [];
final OnMoveGroup? onMoveGroup;
final OnMoveGroupItem? onMoveGroupItem;
final OnMoveGroupItemToGroup? onMoveGroupItemToGroup;
List<AFBoardColumnData> get columnDatas => _columnDatas;
UnmodifiableListView<AppFlowyBoardGroupData> get groupDatas =>
UnmodifiableListView(_groupDatas);
List<String> get columnIds =>
_columnDatas.map((columnData) => columnData.id).toList();
List<String> get groupIds =>
_groupDatas.map((groupData) => groupData.id).toList();
final LinkedHashMap<String, AFBoardColumnDataController> _columnControllers =
final LinkedHashMap<String, AFBoardGroupDataController> _groupControllers =
LinkedHashMap();
AFBoardDataController({
this.onMoveColumn,
this.onMoveColumnItem,
this.onMoveColumnItemToColumn,
AppFlowyBoardDataController({
this.onMoveGroup,
this.onMoveGroupItem,
this.onMoveGroupItemToGroup,
});
void addColumn(AFBoardColumnData columnData, {bool notify = true}) {
if (_columnControllers[columnData.id] != null) return;
void addGroup(AppFlowyBoardGroupData groupData, {bool notify = true}) {
if (_groupControllers[groupData.id] != null) return;
final controller = AFBoardColumnDataController(columnData: columnData);
_columnDatas.add(columnData);
_columnControllers[columnData.id] = controller;
final controller = AFBoardGroupDataController(groupData: groupData);
_groupDatas.add(groupData);
_groupControllers[groupData.id] = controller;
if (notify) notifyListeners();
}
void addColumns(List<AFBoardColumnData> columns, {bool notify = true}) {
for (final column in columns) {
addColumn(column, notify: false);
void addGroups(List<AppFlowyBoardGroupData> groups, {bool notify = true}) {
for (final column in groups) {
addGroup(column, notify: false);
}
if (columns.isNotEmpty && notify) notifyListeners();
if (groups.isNotEmpty && notify) notifyListeners();
}
void removeColumn(String columnId, {bool notify = true}) {
final index = _columnDatas.indexWhere((column) => column.id == columnId);
void removeGroup(String groupId, {bool notify = true}) {
final index = _groupDatas.indexWhere((group) => group.id == groupId);
if (index == -1) {
Log.warn(
'Try to remove Column:[$columnId] failed. Column:[$columnId] not exist');
'Try to remove Group:[$groupId] failed. Group:[$groupId] not exist');
}
if (index != -1) {
_columnDatas.removeAt(index);
_columnControllers.remove(columnId);
_groupDatas.removeAt(index);
_groupControllers.remove(groupId);
if (notify) notifyListeners();
}
}
void removeColumns(List<String> columnIds, {bool notify = true}) {
for (final columnId in columnIds) {
removeColumn(columnId, notify: false);
void removeGroups(List<String> groupIds, {bool notify = true}) {
for (final groupId in groupIds) {
removeGroup(groupId, notify: false);
}
if (columnIds.isNotEmpty && notify) notifyListeners();
if (groupIds.isNotEmpty && notify) notifyListeners();
}
void clear() {
_columnDatas.clear();
_columnControllers.clear();
_groupDatas.clear();
_groupControllers.clear();
notifyListeners();
}
AFBoardColumnDataController? getColumnController(String columnId) {
final columnController = _columnControllers[columnId];
if (columnController == null) {
Log.warn('Column:[$columnId] \'s controller is not exist');
AFBoardGroupDataController? getGroupController(String groupId) {
final groupController = _groupControllers[groupId];
if (groupController == null) {
Log.warn('Group:[$groupId] \'s controller is not exist');
}
return columnController;
return groupController;
}
void moveColumn(int fromIndex, int toIndex, {bool notify = true}) {
final toColumnData = _columnDatas[toIndex];
final fromColumnData = _columnDatas.removeAt(fromIndex);
void moveGroup(int fromIndex, int toIndex, {bool notify = true}) {
final toGroupData = _groupDatas[toIndex];
final fromGroupData = _groupDatas.removeAt(fromIndex);
_columnDatas.insert(toIndex, fromColumnData);
onMoveColumn?.call(fromColumnData.id, fromIndex, toColumnData.id, toIndex);
_groupDatas.insert(toIndex, fromGroupData);
onMoveGroup?.call(fromGroupData.id, fromIndex, toGroupData.id, toIndex);
if (notify) notifyListeners();
}
void moveColumnItem(String columnId, int fromIndex, int toIndex) {
if (getColumnController(columnId)?.move(fromIndex, toIndex) ?? false) {
onMoveColumnItem?.call(columnId, fromIndex, toIndex);
void moveGroupItem(String groupId, int fromIndex, int toIndex) {
if (getGroupController(groupId)?.move(fromIndex, toIndex) ?? false) {
onMoveGroupItem?.call(groupId, fromIndex, toIndex);
}
}
void addColumnItem(String columnId, AFColumnItem item) {
getColumnController(columnId)?.add(item);
void addGroupItem(String groupId, AppFlowyGroupItem item) {
getGroupController(groupId)?.add(item);
}
void insertColumnItem(String columnId, int index, AFColumnItem item) {
getColumnController(columnId)?.insert(index, item);
void insertGroupItem(String groupId, int index, AppFlowyGroupItem item) {
getGroupController(groupId)?.insert(index, item);
}
void removeColumnItem(String columnId, String itemId) {
getColumnController(columnId)?.removeWhere((item) => item.id == itemId);
void removeGroupItem(String groupId, String itemId) {
getGroupController(groupId)?.removeWhere((item) => item.id == itemId);
}
void updateColumnItem(String columnId, AFColumnItem item) {
getColumnController(columnId)?.replaceOrInsertItem(item);
void updateGroupItem(String groupId, AppFlowyGroupItem item) {
getGroupController(groupId)?.replaceOrInsertItem(item);
}
@override
@protected
void swapColumnItem(
String fromColumnId,
int fromColumnIndex,
String toColumnId,
int toColumnIndex,
void swapGroupItem(
String fromGroupId,
int fromGroupIndex,
String toGroupId,
int toGroupIndex,
) {
final fromColumnController = getColumnController(fromColumnId)!;
final toColumnController = getColumnController(toColumnId)!;
final item = fromColumnController.removeAt(fromColumnIndex);
if (toColumnController.items.length > toColumnIndex) {
assert(toColumnController.items[toColumnIndex] is PhantomColumnItem);
final fromGroupController = getGroupController(fromGroupId)!;
final toGroupController = getGroupController(toGroupId)!;
final item = fromGroupController.removeAt(fromGroupIndex);
if (toGroupController.items.length > toGroupIndex) {
assert(toGroupController.items[toGroupIndex] is PhantomGroupItem);
}
toColumnController.replace(toColumnIndex, item);
onMoveColumnItemToColumn?.call(
fromColumnId,
fromColumnIndex,
toColumnId,
toColumnIndex,
toGroupController.replace(toGroupIndex, item);
onMoveGroupItemToGroup?.call(
fromGroupId,
fromGroupIndex,
toGroupId,
toGroupIndex,
);
}
@override
List<Object?> get props {
return [_columnDatas];
return [_groupDatas];
}
@override
AFBoardColumnDataController? controller(String columnId) {
return _columnControllers[columnId];
AFBoardGroupDataController? controller(String groupId) {
return _groupControllers[groupId];
}
@override
String get identifier => '$AFBoardDataController';
String get identifier => '$AppFlowyBoardDataController';
@override
UnmodifiableListView<ReoderFlexItem> get items =>
UnmodifiableListView(_columnDatas);
UnmodifiableListView(_groupDatas);
@override
@protected
bool removePhantom(String columnId) {
final columnController = getColumnController(columnId);
if (columnController == null) {
Log.warn('Can not find the column controller with columnId: $columnId');
bool removePhantom(String groupId) {
final groupController = getGroupController(groupId);
if (groupController == null) {
Log.warn('Can not find the group controller with groupId: $groupId');
return false;
}
final index = columnController.items.indexWhere((item) => item.isPhantom);
final index = groupController.items.indexWhere((item) => item.isPhantom);
final isExist = index != -1;
if (isExist) {
columnController.removeAt(index);
groupController.removeAt(index);
Log.debug(
'[$AFBoardDataController] Column:[$columnId] remove phantom, current count: ${columnController.items.length}');
'[$AppFlowyBoardDataController] Group:[$groupId] remove phantom, current count: ${groupController.items.length}');
}
return isExist;
}
@override
@protected
void updatePhantom(String columnId, int newIndex) {
final columnDataController = getColumnController(columnId)!;
final index =
columnDataController.items.indexWhere((item) => item.isPhantom);
void updatePhantom(String groupId, int newIndex) {
final groupController = getGroupController(groupId)!;
final index = groupController.items.indexWhere((item) => item.isPhantom);
if (index != -1) {
if (index != newIndex) {
Log.trace(
'[$BoardPhantomController] update $columnId:$index to $columnId:$newIndex');
final item = columnDataController.removeAt(index, notify: false);
columnDataController.insert(newIndex, item, notify: false);
'[$BoardPhantomController] update $groupId:$index to $groupId:$newIndex');
final item = groupController.removeAt(index, notify: false);
groupController.insert(newIndex, item, notify: false);
}
}
}
@override
@protected
void insertPhantom(String columnId, int index, PhantomColumnItem item) {
getColumnController(columnId)!.insert(index, item);
void insertPhantom(String groupId, int index, PhantomGroupItem item) {
getGroupController(groupId)!.insert(index, item);
}
}

View File

@ -55,7 +55,7 @@ class OverlappingDragTargetInterceptor extends DragTargetInterceptor {
final String reorderFlexId;
final List<String> acceptedReorderFlexId;
final OverlapDragTargetDelegate delegate;
final BoardColumnsState columnsState;
final BoardGroupsState columnsState;
Timer? _delayOperation;
OverlappingDragTargetInterceptor({
@ -81,7 +81,7 @@ class OverlappingDragTargetInterceptor extends DragTargetInterceptor {
delegate.cancel();
} else {
// Ignore the event if the dragTarget overlaps with the other column's dragTargets.
final columnKeys = columnsState.columnDragDragTargets[dragTargetId];
final columnKeys = columnsState.groupDragDragTargets[dragTargetId];
if (columnKeys != null) {
final keys = columnKeys.values.toList();
if (dragTargetData.isOverlapWithWidgets(keys)) {
@ -102,7 +102,7 @@ class OverlappingDragTargetInterceptor extends DragTargetInterceptor {
delegate.moveTo(dragTargetId, dragTargetData, index);
columnsState
.getReorderFlexState(columnId: dragTargetId)
.getReorderFlexState(groupId: dragTargetId)
?.resetDragTargetIndex(index);
}
});
@ -165,13 +165,13 @@ class CrossReorderFlexDragTargetInterceptor extends DragTargetInterceptor {
@override
void onAccept(FlexDragTargetData dragTargetData) {
Log.trace(
'[$CrossReorderFlexDragTargetInterceptor] Column:[$reorderFlexId] on onAccept');
'[$CrossReorderFlexDragTargetInterceptor] Group:[$reorderFlexId] on onAccept');
}
@override
void onLeave(FlexDragTargetData dragTargetData) {
Log.trace(
'[$CrossReorderFlexDragTargetInterceptor] Column:[$reorderFlexId] on leave');
'[$CrossReorderFlexDragTargetInterceptor] Group:[$reorderFlexId] on leave');
}
@override

View File

@ -49,8 +49,8 @@ class ReorderFlexConfig {
/// Determines if setSatte method needs to be called when the drag is complete.
/// Default value is [true].
///
/// If the [ReorderFlex] will be rebuild after the [ReorderFlex]'s children
/// were changed, then the [setStateWhenEndDrag] should set to [false].
/// If the [ReorderFlex] needs to be rebuild after the [ReorderFlex] end dragging,
/// the [setStateWhenEndDrag] should set to [true].
final bool setStateWhenEndDrag;
final bool useMoveAnimation;
@ -252,7 +252,7 @@ class ReorderFlexState extends State<ReorderFlex>
}
Log.trace(
'Rebuild: Column:[${dragState.reorderFlexId}] ${dragState.toString()}, childIndex: $childIndex shiftedIndex: $shiftedIndex');
'Rebuild: Group:[${dragState.reorderFlexId}] ${dragState.toString()}, childIndex: $childIndex shiftedIndex: $shiftedIndex');
final currentIndex = dragState.currentIndex;
final dragPhantomIndex = dragState.phantomIndex;
@ -368,7 +368,7 @@ class ReorderFlexState extends State<ReorderFlex>
),
onDragStarted: (draggingWidget, draggingIndex, size) {
Log.debug(
"[DragTarget] Column:[${widget.dataSource.identifier}] start dragging item at $draggingIndex");
"[DragTarget] Group:[${widget.dataSource.identifier}] start dragging item at $draggingIndex");
_startDragging(draggingWidget, draggingIndex, size);
widget.onDragStarted?.call(draggingIndex);
widget.dragStateStorage?.remove(widget.reorderFlexId);
@ -379,7 +379,7 @@ class ReorderFlexState extends State<ReorderFlex>
onDragEnded: (dragTargetData) {
if (!mounted) return;
Log.debug(
"[DragTarget]: Column:[${widget.dataSource.identifier}] end dragging");
"[DragTarget]: Group:[${widget.dataSource.identifier}] end dragging");
_notifier.updateDragTargetIndex(-1);
onDragEnded() {

View File

@ -8,30 +8,30 @@ import '../reorder_flex/drag_target_interceptor.dart';
import 'phantom_state.dart';
abstract class BoardPhantomControllerDelegate {
AFBoardColumnDataController? controller(String columnId);
AFBoardGroupDataController? controller(String groupId);
bool removePhantom(String columnId);
bool removePhantom(String groupId);
/// Insert the phantom into column
/// Insert the phantom into the group
///
/// * [toColumnId] id of the column
/// * [groupId] id of the group
/// * [phantomIndex] the phantom occupies index
void insertPhantom(
String columnId,
String groupId,
int index,
PhantomColumnItem item,
PhantomGroupItem item,
);
/// Update the column's phantom index if it exists.
/// [toColumnId] the id of the column
/// Update the group's phantom index if it exists.
/// [toGroupId] the id of the group
/// [dragTargetIndex] the index of the dragTarget
void updatePhantom(String columnId, int newIndex);
void updatePhantom(String groupId, int newIndex);
void swapColumnItem(
String fromColumnId,
int fromColumnIndex,
String toColumnId,
int toColumnIndex,
void swapGroupItem(
String fromGroupId,
int fromGroupIndex,
String toGroupId,
int toGroupIndex,
);
}
@ -39,16 +39,16 @@ class BoardPhantomController extends OverlapDragTargetDelegate
with CrossReorderFlexDragTargetDelegate {
PhantomRecord? phantomRecord;
final BoardPhantomControllerDelegate delegate;
final BoardColumnsState columnsState;
final phantomState = ColumnPhantomState();
final BoardGroupsState groupsState;
final phantomState = GroupPhantomState();
BoardPhantomController({
required this.delegate,
required this.columnsState,
required this.groupsState,
});
bool isFromColumn(String columnId) {
bool isFromGroup(String groupId) {
if (phantomRecord != null) {
return phantomRecord!.fromColumnId == columnId;
return phantomRecord!.fromGroupId == groupId;
} else {
return true;
}
@ -58,32 +58,32 @@ class BoardPhantomController extends OverlapDragTargetDelegate
if (phantomRecord == null) {
return;
}
assert(phantomRecord!.fromColumnIndex == fromIndex);
phantomRecord?.updateFromColumnIndex(toIndex);
assert(phantomRecord!.fromGroupIndex == fromIndex);
phantomRecord?.updateFromGroupIndex(toIndex);
}
void columnStartDragging(String columnId) {
phantomState.setColumnIsDragging(columnId, true);
void groupStartDragging(String groupId) {
phantomState.setGroupIsDragging(groupId, true);
}
/// Remove the phantom in the column when the column is end dragging.
void columnEndDragging(String columnId) {
phantomState.setColumnIsDragging(columnId, false);
/// Remove the phantom in the group when the group is end dragging.
void groupEndDragging(String groupId) {
phantomState.setGroupIsDragging(groupId, false);
if (phantomRecord == null) return;
final fromColumnId = phantomRecord!.fromColumnId;
final toColumnId = phantomRecord!.toColumnId;
if (fromColumnId == columnId) {
phantomState.notifyDidRemovePhantom(toColumnId);
final fromGroupId = phantomRecord!.fromGroupId;
final toGroupId = phantomRecord!.toGroupId;
if (fromGroupId == groupId) {
phantomState.notifyDidRemovePhantom(toGroupId);
}
if (phantomRecord!.toColumnId == columnId) {
delegate.swapColumnItem(
fromColumnId,
phantomRecord!.fromColumnIndex,
toColumnId,
phantomRecord!.toColumnIndex,
if (phantomRecord!.toGroupId == groupId) {
delegate.swapGroupItem(
fromGroupId,
phantomRecord!.fromGroupIndex,
toGroupId,
phantomRecord!.toGroupIndex,
);
// Log.debug(
@ -92,16 +92,16 @@ class BoardPhantomController extends OverlapDragTargetDelegate
}
}
/// Remove the phantom in the column if it contains phantom
void _removePhantom(String columnId) {
if (delegate.removePhantom(columnId)) {
phantomState.notifyDidRemovePhantom(columnId);
phantomState.removeColumnListener(columnId);
/// Remove the phantom in the group if it contains phantom
void _removePhantom(String groupId) {
if (delegate.removePhantom(groupId)) {
phantomState.notifyDidRemovePhantom(groupId);
phantomState.removeGroupListener(groupId);
}
}
void _insertPhantom(
String toColumnId,
String toGroupId,
FlexDragTargetData dragTargetData,
int phantomIndex,
) {
@ -109,38 +109,38 @@ class BoardPhantomController extends OverlapDragTargetDelegate
index: phantomIndex,
dragTargetData: dragTargetData,
);
phantomState.addColumnListener(toColumnId, phantomContext);
phantomState.addGroupListener(toGroupId, phantomContext);
delegate.insertPhantom(
toColumnId,
toGroupId,
phantomIndex,
PhantomColumnItem(phantomContext),
PhantomGroupItem(phantomContext),
);
phantomState.notifyDidInsertPhantom(toColumnId, phantomIndex);
phantomState.notifyDidInsertPhantom(toGroupId, phantomIndex);
}
/// Reset or initial the [PhantomRecord]
///
///
/// * [columnId] the id of the column
/// * [groupId] the id of the group
/// * [dragTargetData]
/// * [dragTargetIndex]
///
void _resetPhantomRecord(
String columnId,
String groupId,
FlexDragTargetData dragTargetData,
int dragTargetIndex,
) {
// Log.debug(
// '[$BoardPhantomController] move Column:[${dragTargetData.reorderFlexId}]:${dragTargetData.draggingIndex} '
// 'to Column:[$columnId]:$dragTargetIndex');
// '[$BoardPhantomController] move Group:[${dragTargetData.reorderFlexId}]:${dragTargetData.draggingIndex} '
// 'to Group:[$groupId]:$dragTargetIndex');
phantomRecord = PhantomRecord(
toColumnId: columnId,
toColumnIndex: dragTargetIndex,
fromColumnId: dragTargetData.reorderFlexId,
fromColumnIndex: dragTargetData.draggingIndex,
toGroupId: groupId,
toGroupIndex: dragTargetIndex,
fromGroupId: dragTargetData.reorderFlexId,
fromGroupIndex: dragTargetData.draggingIndex,
);
Log.debug('[$BoardPhantomController] will move: $phantomRecord');
}
@ -158,10 +158,10 @@ class BoardPhantomController extends OverlapDragTargetDelegate
return true;
}
final isNewDragTarget = phantomRecord!.toColumnId != reorderFlexId;
final isNewDragTarget = phantomRecord!.toGroupId != reorderFlexId;
if (isNewDragTarget) {
/// Remove the phantom when the dragTarget is moved from one column to another column.
_removePhantom(phantomRecord!.toColumnId);
/// Remove the phantom when the dragTarget is moved from one group to another group.
_removePhantom(phantomRecord!.toGroupId);
_resetPhantomRecord(reorderFlexId, dragTargetData, dragTargetIndex);
_insertPhantom(reorderFlexId, dragTargetData, dragTargetIndex);
}
@ -177,9 +177,9 @@ class BoardPhantomController extends OverlapDragTargetDelegate
phantomRecord?.updateInsertedIndex(dragTargetIndex);
assert(phantomRecord != null);
if (phantomRecord!.toColumnId == reorderFlexId) {
if (phantomRecord!.toGroupId == reorderFlexId) {
/// Update the existing phantom index
delegate.updatePhantom(phantomRecord!.toColumnId, dragTargetIndex);
delegate.updatePhantom(phantomRecord!.toGroupId, dragTargetIndex);
}
}
@ -189,8 +189,8 @@ class BoardPhantomController extends OverlapDragTargetDelegate
return;
}
/// Remove the phantom when the dragTarge is go back to the original column.
_removePhantom(phantomRecord!.toColumnId);
/// Remove the phantom when the dragTarge is go back to the original group.
_removePhantom(phantomRecord!.toGroupId);
phantomRecord = null;
}
@ -215,63 +215,63 @@ class BoardPhantomController extends OverlapDragTargetDelegate
final controller = delegate.controller(dragTargetId);
if (controller != null) {
return controller.columnData.items.length;
return controller.groupData.items.length;
} else {
return 0;
}
}
}
/// Use [PhantomRecord] to record where to remove the column item and where to
/// insert the column item.
/// Use [PhantomRecord] to record where to remove the group item and where to
/// insert the group item.
///
/// [fromColumnId] the column that phantom comes from
/// [fromColumnIndex] the index of the phantom from the original column
/// [toColumnId] the column that the phantom moves into
/// [toColumnIndex] the index of the phantom moves into the column
/// [fromGroupId] the group that phantom comes from
/// [fromGroupIndex] the index of the phantom from the original group
/// [toGroupId] the group that the phantom moves into
/// [toGroupIndex] the index of the phantom moves into the group
///
class PhantomRecord {
final String fromColumnId;
int fromColumnIndex;
final String fromGroupId;
int fromGroupIndex;
final String toColumnId;
int toColumnIndex;
final String toGroupId;
int toGroupIndex;
PhantomRecord({
required this.toColumnId,
required this.toColumnIndex,
required this.fromColumnId,
required this.fromColumnIndex,
required this.toGroupId,
required this.toGroupIndex,
required this.fromGroupId,
required this.fromGroupIndex,
});
void updateFromColumnIndex(int index) {
if (fromColumnIndex == index) {
void updateFromGroupIndex(int index) {
if (fromGroupIndex == index) {
return;
}
fromColumnIndex = index;
fromGroupIndex = index;
}
void updateInsertedIndex(int index) {
if (toColumnIndex == index) {
if (toGroupIndex == index) {
return;
}
Log.debug(
'[$PhantomRecord] Column:[$toColumnId] update position $toColumnIndex -> $index');
toColumnIndex = index;
'[$PhantomRecord] Group:[$toGroupId] update position $toGroupIndex -> $index');
toGroupIndex = index;
}
@override
String toString() {
return 'Column:[$fromColumnId]:$fromColumnIndex to Column:[$toColumnId]:$toColumnIndex';
return 'Group:[$fromGroupId]:$fromGroupIndex to Group:[$toGroupId]:$toGroupIndex';
}
}
class PhantomColumnItem extends AFColumnItem {
class PhantomGroupItem extends AppFlowyGroupItem {
final PassthroughPhantomContext phantomContext;
PhantomColumnItem(PassthroughPhantomContext insertedPhantom)
PhantomGroupItem(PassthroughPhantomContext insertedPhantom)
: phantomContext = insertedPhantom;
@override
@ -305,7 +305,8 @@ class PassthroughPhantomContext extends FakeDragTargetEventTrigger
Widget? get draggingWidget => dragTargetData.draggingWidget;
AFColumnItem get itemData => dragTargetData.reorderFlexItem as AFColumnItem;
AppFlowyGroupItem get itemData =>
dragTargetData.reorderFlexItem as AppFlowyGroupItem;
@override
void Function(int?)? onInserted;

View File

@ -1,48 +1,48 @@
import 'phantom_controller.dart';
import 'package:flutter/material.dart';
class ColumnPhantomState {
final _states = <String, ColumnState>{};
class GroupPhantomState {
final _states = <String, GroupState>{};
void setColumnIsDragging(String columnId, bool isDragging) {
_stateWithId(columnId).isDragging = isDragging;
void setGroupIsDragging(String groupId, bool isDragging) {
_stateWithId(groupId).isDragging = isDragging;
}
bool isDragging(String columnId) {
return _stateWithId(columnId).isDragging;
bool isDragging(String groupId) {
return _stateWithId(groupId).isDragging;
}
void addColumnListener(String columnId, PassthroughPhantomListener listener) {
_stateWithId(columnId).notifier.addListener(
void addGroupListener(String groupId, PassthroughPhantomListener listener) {
_stateWithId(groupId).notifier.addListener(
onInserted: (index) => listener.onInserted?.call(index),
onDeleted: () => listener.onDragEnded?.call(),
);
}
void removeColumnListener(String columnId) {
_stateWithId(columnId).notifier.dispose();
_states.remove(columnId);
void removeGroupListener(String groupId) {
_stateWithId(groupId).notifier.dispose();
_states.remove(groupId);
}
void notifyDidInsertPhantom(String columnId, int index) {
_stateWithId(columnId).notifier.insert(index);
void notifyDidInsertPhantom(String groupId, int index) {
_stateWithId(groupId).notifier.insert(index);
}
void notifyDidRemovePhantom(String columnId) {
_stateWithId(columnId).notifier.remove();
void notifyDidRemovePhantom(String groupId) {
_stateWithId(groupId).notifier.remove();
}
ColumnState _stateWithId(String columnId) {
var state = _states[columnId];
GroupState _stateWithId(String groupId) {
var state = _states[groupId];
if (state == null) {
state = ColumnState();
_states[columnId] = state;
state = GroupState();
_states[groupId] = state;
}
return state;
}
}
class ColumnState {
class GroupState {
bool isDragging = false;
final notifier = PassthroughPhantomNotifier();
}

View File

@ -1,12 +1,12 @@
import 'package:flutter/material.dart';
class AppFlowyColumnItemCard extends StatefulWidget {
class AppFlowyGroupItemCard extends StatefulWidget {
final Widget? child;
final EdgeInsets margin;
final BoxConstraints boxConstraints;
final BoxDecoration decoration;
const AppFlowyColumnItemCard({
const AppFlowyGroupItemCard({
this.child,
this.margin = const EdgeInsets.all(4),
this.decoration = const BoxDecoration(
@ -18,10 +18,10 @@ class AppFlowyColumnItemCard extends StatefulWidget {
}) : super(key: key);
@override
State<AppFlowyColumnItemCard> createState() => _AppFlowyColumnItemCardState();
State<AppFlowyGroupItemCard> createState() => _AppFlowyGroupItemCardState();
}
class _AppFlowyColumnItemCardState extends State<AppFlowyColumnItemCard> {
class _AppFlowyGroupItemCardState extends State<AppFlowyGroupItemCard> {
@override
Widget build(BuildContext context) {
return Padding(

View File

@ -2,14 +2,14 @@ import 'package:flutter/material.dart';
typedef OnFooterAddButtonClick = void Function();
class AppFlowyColumnFooter extends StatefulWidget {
class AppFlowyGroupFooter extends StatefulWidget {
final double height;
final Widget? icon;
final Widget? title;
final EdgeInsets margin;
final OnFooterAddButtonClick? onAddButtonClick;
const AppFlowyColumnFooter({
const AppFlowyGroupFooter({
this.icon,
this.title,
this.margin = const EdgeInsets.symmetric(horizontal: 12),
@ -19,10 +19,10 @@ class AppFlowyColumnFooter extends StatefulWidget {
}) : super(key: key);
@override
State<AppFlowyColumnFooter> createState() => _AppFlowyColumnFooterState();
State<AppFlowyGroupFooter> createState() => _AppFlowyGroupFooterState();
}
class _AppFlowyColumnFooterState extends State<AppFlowyColumnFooter> {
class _AppFlowyGroupFooterState extends State<AppFlowyGroupFooter> {
@override
Widget build(BuildContext context) {
return GestureDetector(

View File

@ -3,7 +3,7 @@ import 'package:flutter/material.dart';
typedef OnHeaderAddButtonClick = void Function();
typedef OnHeaderMoreButtonClick = void Function();
class AppFlowyColumnHeader extends StatefulWidget {
class AppFlowyGroupHeader extends StatefulWidget {
final double height;
final Widget? icon;
final Widget? title;
@ -13,7 +13,7 @@ class AppFlowyColumnHeader extends StatefulWidget {
final OnHeaderAddButtonClick? onAddButtonClick;
final OnHeaderMoreButtonClick? onMoreButtonClick;
const AppFlowyColumnHeader({
const AppFlowyGroupHeader({
required this.height,
this.icon,
this.title,
@ -26,10 +26,10 @@ class AppFlowyColumnHeader extends StatefulWidget {
}) : super(key: key);
@override
State<AppFlowyColumnHeader> createState() => _AppFlowyColumnHeaderState();
State<AppFlowyGroupHeader> createState() => _AppFlowyGroupHeaderState();
}
class _AppFlowyColumnHeaderState extends State<AppFlowyColumnHeader> {
class _AppFlowyGroupHeaderState extends State<AppFlowyGroupHeader> {
@override
Widget build(BuildContext context) {
List<Widget> children = [];