mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2024-08-30 18:12:39 +00:00
chore: update ui
This commit is contained in:
parent
971a5e245a
commit
db5b3e3bd3
@ -1,3 +1,8 @@
|
|||||||
|
# 0.0.3
|
||||||
|
* Support customize UI
|
||||||
|
* Update example
|
||||||
|
* Add AppFlowy style widget
|
||||||
|
|
||||||
## 0.0.2
|
## 0.0.2
|
||||||
|
|
||||||
* Update documentation
|
* Update documentation
|
||||||
|
@ -6,30 +6,25 @@ The **appflowy_board** is a package that is used in [AppFlowy](https://github.co
|
|||||||
**appflowy_board** will be a standard git repository when it becomes stable.
|
**appflowy_board** will be a standard git repository when it becomes stable.
|
||||||
## Getting Started
|
## Getting Started
|
||||||
|
|
||||||
|
<p>
|
||||||
|
<img src="" width="180" title="AppFlowyBoard">
|
||||||
|
</p>
|
||||||
|
|
||||||
```dart
|
```dart
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
final column1 = BoardColumnData(id: "1", items: [
|
final column1 = BoardColumnData(id: "To Do", items: [
|
||||||
TextItem("a"),
|
TextItem("Card 1"),
|
||||||
TextItem("b"),
|
TextItem("Card 2"),
|
||||||
TextItem("c"),
|
TextItem("Card 3"),
|
||||||
TextItem("d"),
|
TextItem("Card 4"),
|
||||||
]);
|
]);
|
||||||
final column2 = BoardColumnData(id: "2", items: [
|
final column2 = BoardColumnData(id: "In Progress", items: [
|
||||||
TextItem("1"),
|
TextItem("Card 5"),
|
||||||
TextItem("2"),
|
TextItem("Card 6"),
|
||||||
TextItem("3"),
|
|
||||||
TextItem("4"),
|
|
||||||
TextItem("5"),
|
|
||||||
]);
|
]);
|
||||||
|
|
||||||
final column3 = BoardColumnData(id: "3", items: [
|
final column3 = BoardColumnData(id: "Done", items: []);
|
||||||
TextItem("A"),
|
|
||||||
TextItem("B"),
|
|
||||||
TextItem("C"),
|
|
||||||
TextItem("D"),
|
|
||||||
]);
|
|
||||||
|
|
||||||
boardDataController.addColumn(column1);
|
boardDataController.addColumn(column1);
|
||||||
boardDataController.addColumn(column2);
|
boardDataController.addColumn(column2);
|
||||||
@ -40,25 +35,52 @@ The **appflowy_board** is a package that is used in [AppFlowy](https://github.co
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Board(
|
final config = BoardConfig(
|
||||||
dataController: boardDataController,
|
columnBackgroundColor: HexColor.fromHex('#F7F8FC'),
|
||||||
background: Container(color: Colors.red),
|
);
|
||||||
footBuilder: (context, columnData) {
|
return Container(
|
||||||
return Container(
|
color: Colors.white,
|
||||||
color: Colors.purple,
|
child: Padding(
|
||||||
height: 30,
|
padding: const EdgeInsets.symmetric(vertical: 30, horizontal: 20),
|
||||||
);
|
child: Board(
|
||||||
},
|
dataController: boardDataController,
|
||||||
headerBuilder: (context, columnData) {
|
footBuilder: (context, columnData) {
|
||||||
return Container(
|
return AppFlowyColumnFooter(
|
||||||
color: Colors.yellow,
|
icon: const Icon(Icons.add, size: 20),
|
||||||
height: 30,
|
title: const Text('New'),
|
||||||
);
|
height: 50,
|
||||||
},
|
margin: config.columnItemPadding,
|
||||||
cardBuilder: (context, item) {
|
);
|
||||||
return _RowWidget(item: item as TextItem, key: ObjectKey(item));
|
},
|
||||||
},
|
headerBuilder: (context, columnData) {
|
||||||
columnConstraints: const BoxConstraints.tightFor(width: 240),
|
return AppFlowyColumnHeader(
|
||||||
|
icon: const Icon(Icons.lightbulb_circle),
|
||||||
|
title: Text(columnData.id),
|
||||||
|
addIcon: const Icon(Icons.add, size: 20),
|
||||||
|
moreIcon: const Icon(Icons.more_horiz, size: 20),
|
||||||
|
height: 50,
|
||||||
|
margin: config.columnItemPadding,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
cardBuilder: (context, item) {
|
||||||
|
final textItem = item as TextItem;
|
||||||
|
return AppFlowyColumnItemCard(
|
||||||
|
key: ObjectKey(item),
|
||||||
|
child: Align(
|
||||||
|
alignment: Alignment.centerLeft,
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 20),
|
||||||
|
child: Text(textItem.s),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
columnConstraints: const BoxConstraints.tightFor(width: 240),
|
||||||
|
config: BoardConfig(
|
||||||
|
columnBackgroundColor: HexColor.fromHex('#F7F8FC'),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
```
|
```
|
Binary file not shown.
After Width: | Height: | Size: 69 KiB |
@ -32,7 +32,7 @@ class _MyAppState extends State<MyApp> {
|
|||||||
return MaterialApp(
|
return MaterialApp(
|
||||||
home: Scaffold(
|
home: Scaffold(
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
title: const Text('FlowyBoard example'),
|
title: const Text('AppFlowy Board'),
|
||||||
),
|
),
|
||||||
body: _examples[_currentIndex],
|
body: _examples[_currentIndex],
|
||||||
bottomNavigationBar: BottomNavigationBar(
|
bottomNavigationBar: BottomNavigationBar(
|
||||||
@ -43,10 +43,10 @@ class _MyAppState extends State<MyApp> {
|
|||||||
items: [
|
items: [
|
||||||
BottomNavigationBarItem(
|
BottomNavigationBarItem(
|
||||||
icon: Icon(Icons.grid_on, color: _bottomNavigationColor),
|
icon: Icon(Icons.grid_on, color: _bottomNavigationColor),
|
||||||
label: "MultiBoardList"),
|
label: "MultiColumn"),
|
||||||
BottomNavigationBarItem(
|
BottomNavigationBarItem(
|
||||||
icon: Icon(Icons.grid_on, color: _bottomNavigationColor),
|
icon: Icon(Icons.grid_on, color: _bottomNavigationColor),
|
||||||
label: "SingleBoardList"),
|
label: "SingleColumn"),
|
||||||
],
|
],
|
||||||
onTap: (int index) {
|
onTap: (int index) {
|
||||||
setState(() {
|
setState(() {
|
||||||
|
@ -23,26 +23,18 @@ class _MultiBoardListExampleState extends State<MultiBoardListExample> {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
final column1 = BoardColumnData(id: "1", items: [
|
final column1 = BoardColumnData(id: "To Do", items: [
|
||||||
TextItem("a"),
|
TextItem("Card 1"),
|
||||||
TextItem("b"),
|
TextItem("Card 2"),
|
||||||
TextItem("c"),
|
TextItem("Card 3"),
|
||||||
TextItem("d"),
|
TextItem("Card 4"),
|
||||||
]);
|
]);
|
||||||
final column2 = BoardColumnData(id: "2", items: [
|
final column2 = BoardColumnData(id: "In Progress", items: [
|
||||||
TextItem("1"),
|
TextItem("Card 5"),
|
||||||
TextItem("2"),
|
TextItem("Card 6"),
|
||||||
TextItem("3"),
|
|
||||||
TextItem("4"),
|
|
||||||
TextItem("5"),
|
|
||||||
]);
|
]);
|
||||||
|
|
||||||
final column3 = BoardColumnData(id: "3", items: [
|
final column3 = BoardColumnData(id: "Done", items: []);
|
||||||
TextItem("A"),
|
|
||||||
TextItem("B"),
|
|
||||||
TextItem("C"),
|
|
||||||
TextItem("D"),
|
|
||||||
]);
|
|
||||||
|
|
||||||
boardDataController.addColumn(column1);
|
boardDataController.addColumn(column1);
|
||||||
boardDataController.addColumn(column2);
|
boardDataController.addColumn(column2);
|
||||||
@ -53,40 +45,52 @@ class _MultiBoardListExampleState extends State<MultiBoardListExample> {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Board(
|
final config = BoardConfig(
|
||||||
dataController: boardDataController,
|
columnBackgroundColor: HexColor.fromHex('#F7F8FC'),
|
||||||
background: Container(color: Colors.red),
|
|
||||||
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),
|
|
||||||
);
|
);
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class _RowWidget extends StatelessWidget {
|
|
||||||
final TextItem item;
|
|
||||||
const _RowWidget({Key? key, required this.item}) : super(key: key);
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return Container(
|
return Container(
|
||||||
key: ObjectKey(item),
|
color: Colors.white,
|
||||||
height: 60,
|
child: Padding(
|
||||||
color: Colors.green,
|
padding: const EdgeInsets.symmetric(vertical: 30, horizontal: 20),
|
||||||
child: Center(child: Text(item.s)),
|
child: Board(
|
||||||
|
dataController: boardDataController,
|
||||||
|
footBuilder: (context, columnData) {
|
||||||
|
return AppFlowyColumnFooter(
|
||||||
|
icon: const Icon(Icons.add, size: 20),
|
||||||
|
title: const Text('New'),
|
||||||
|
height: 50,
|
||||||
|
margin: config.columnItemPadding,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
headerBuilder: (context, columnData) {
|
||||||
|
return AppFlowyColumnHeader(
|
||||||
|
icon: const Icon(Icons.lightbulb_circle),
|
||||||
|
title: Text(columnData.id),
|
||||||
|
addIcon: const Icon(Icons.add, size: 20),
|
||||||
|
moreIcon: const Icon(Icons.more_horiz, size: 20),
|
||||||
|
height: 50,
|
||||||
|
margin: config.columnItemPadding,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
cardBuilder: (context, item) {
|
||||||
|
final textItem = item as TextItem;
|
||||||
|
return AppFlowyColumnItemCard(
|
||||||
|
key: ObjectKey(item),
|
||||||
|
child: Align(
|
||||||
|
alignment: Alignment.centerLeft,
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 20),
|
||||||
|
child: Text(textItem.s),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
columnConstraints: const BoxConstraints.tightFor(width: 240),
|
||||||
|
config: BoardConfig(
|
||||||
|
columnBackgroundColor: HexColor.fromHex('#F7F8FC'),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -99,3 +103,12 @@ class TextItem extends ColumnItem {
|
|||||||
@override
|
@override
|
||||||
String get id => s;
|
String get id => s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extension HexColor on Color {
|
||||||
|
static Color fromHex(String hexString) {
|
||||||
|
final buffer = StringBuffer();
|
||||||
|
if (hexString.length == 6 || hexString.length == 7) buffer.write('ff');
|
||||||
|
buffer.write(hexString.replaceFirst('#', ''));
|
||||||
|
return Color(int.parse(buffer.toString(), radix: 16));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -2,4 +2,5 @@ library appflowy_board;
|
|||||||
|
|
||||||
export 'src/widgets/board_column/board_column_data.dart';
|
export 'src/widgets/board_column/board_column_data.dart';
|
||||||
export 'src/widgets/board_data.dart';
|
export 'src/widgets/board_data.dart';
|
||||||
|
export 'src/widgets/styled_widgets/appflowy_styled_widgets.dart';
|
||||||
export 'src/widgets/board.dart';
|
export 'src/widgets/board.dart';
|
||||||
|
@ -6,7 +6,7 @@ const DART_LOG = "Dart_LOG";
|
|||||||
class Log {
|
class Log {
|
||||||
// static const enableLog = bool.hasEnvironment(DART_LOG);
|
// static const enableLog = bool.hasEnvironment(DART_LOG);
|
||||||
// static final shared = Log();
|
// static final shared = Log();
|
||||||
static const enableLog = false;
|
static const enableLog = true;
|
||||||
|
|
||||||
static void info(String? message) {
|
static void info(String? message) {
|
||||||
if (enableLog) {
|
if (enableLog) {
|
||||||
|
@ -3,23 +3,29 @@ import 'package:provider/provider.dart';
|
|||||||
import 'board_column/board_column.dart';
|
import 'board_column/board_column.dart';
|
||||||
import 'board_column/board_column_data.dart';
|
import 'board_column/board_column_data.dart';
|
||||||
import 'board_data.dart';
|
import 'board_data.dart';
|
||||||
import 'flex/drag_target_inteceptor.dart';
|
import 'reorder_flex/drag_target_inteceptor.dart';
|
||||||
import 'flex/reorder_flex.dart';
|
import 'reorder_flex/reorder_flex.dart';
|
||||||
import 'phantom/phantom_controller.dart';
|
import 'reorder_phantom/phantom_controller.dart';
|
||||||
import '../rendering/board_overlay.dart';
|
import '../rendering/board_overlay.dart';
|
||||||
|
|
||||||
|
class BoardConfig {
|
||||||
|
final double cornerRadius;
|
||||||
|
final EdgeInsets columnPadding;
|
||||||
|
final EdgeInsets columnItemPadding;
|
||||||
|
final Color columnBackgroundColor;
|
||||||
|
|
||||||
|
const BoardConfig({
|
||||||
|
this.cornerRadius = 6.0,
|
||||||
|
this.columnPadding = const EdgeInsets.symmetric(horizontal: 8),
|
||||||
|
this.columnItemPadding = const EdgeInsets.symmetric(horizontal: 10),
|
||||||
|
this.columnBackgroundColor = Colors.transparent,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
class Board extends StatelessWidget {
|
class Board extends StatelessWidget {
|
||||||
/// The direction to use as the main axis.
|
/// The direction to use as the main axis.
|
||||||
final Axis direction = Axis.vertical;
|
final Axis direction = Axis.vertical;
|
||||||
|
|
||||||
/// How much space to place between children in a run in the main axis.
|
|
||||||
/// Defaults to 10.0.
|
|
||||||
final double spacing;
|
|
||||||
|
|
||||||
/// How much space to place between the runs themselves in the cross axis.
|
|
||||||
/// Defaults to 0.0.
|
|
||||||
final double runSpacing;
|
|
||||||
|
|
||||||
///
|
///
|
||||||
final Widget? background;
|
final Widget? background;
|
||||||
|
|
||||||
@ -40,15 +46,16 @@ class Board extends StatelessWidget {
|
|||||||
///
|
///
|
||||||
final BoardPhantomController phantomController;
|
final BoardPhantomController phantomController;
|
||||||
|
|
||||||
|
final BoardConfig config;
|
||||||
|
|
||||||
Board({
|
Board({
|
||||||
required this.dataController,
|
required this.dataController,
|
||||||
required this.cardBuilder,
|
required this.cardBuilder,
|
||||||
this.spacing = 10.0,
|
|
||||||
this.runSpacing = 0.0,
|
|
||||||
this.background,
|
this.background,
|
||||||
this.footBuilder,
|
this.footBuilder,
|
||||||
this.headerBuilder,
|
this.headerBuilder,
|
||||||
this.columnConstraints = const BoxConstraints(maxWidth: 200),
|
this.columnConstraints = const BoxConstraints(maxWidth: 200),
|
||||||
|
this.config = const BoardConfig(),
|
||||||
Key? key,
|
Key? key,
|
||||||
}) : phantomController = BoardPhantomController(delegate: dataController),
|
}) : phantomController = BoardPhantomController(delegate: dataController),
|
||||||
super(key: key);
|
super(key: key);
|
||||||
@ -60,9 +67,9 @@ class Board extends StatelessWidget {
|
|||||||
child: Consumer<BoardDataController>(
|
child: Consumer<BoardDataController>(
|
||||||
builder: (context, notifier, child) {
|
builder: (context, notifier, child) {
|
||||||
return BoardContent(
|
return BoardContent(
|
||||||
|
config: config,
|
||||||
dataController: dataController,
|
dataController: dataController,
|
||||||
background: background,
|
background: background,
|
||||||
spacing: spacing,
|
|
||||||
delegate: phantomController,
|
delegate: phantomController,
|
||||||
columnConstraints: columnConstraints,
|
columnConstraints: columnConstraints,
|
||||||
cardBuilder: cardBuilder,
|
cardBuilder: cardBuilder,
|
||||||
@ -84,8 +91,8 @@ class BoardContent extends StatefulWidget {
|
|||||||
final OnDragEnded? onDragEnded;
|
final OnDragEnded? onDragEnded;
|
||||||
final BoardDataController dataController;
|
final BoardDataController dataController;
|
||||||
final Widget? background;
|
final Widget? background;
|
||||||
final double spacing;
|
final BoardConfig config;
|
||||||
final ReorderFlexConfig config;
|
final ReorderFlexConfig reorderFlexConfig;
|
||||||
final BoxConstraints columnConstraints;
|
final BoxConstraints columnConstraints;
|
||||||
|
|
||||||
///
|
///
|
||||||
@ -101,7 +108,8 @@ class BoardContent extends StatefulWidget {
|
|||||||
|
|
||||||
final BoardPhantomController phantomController;
|
final BoardPhantomController phantomController;
|
||||||
|
|
||||||
BoardContent({
|
const BoardContent({
|
||||||
|
required this.config,
|
||||||
required this.onReorder,
|
required this.onReorder,
|
||||||
required this.delegate,
|
required this.delegate,
|
||||||
required this.dataController,
|
required this.dataController,
|
||||||
@ -109,14 +117,13 @@ class BoardContent extends StatefulWidget {
|
|||||||
this.onDragEnded,
|
this.onDragEnded,
|
||||||
this.scrollController,
|
this.scrollController,
|
||||||
this.background,
|
this.background,
|
||||||
this.spacing = 10.0,
|
|
||||||
required this.columnConstraints,
|
required this.columnConstraints,
|
||||||
required this.cardBuilder,
|
required this.cardBuilder,
|
||||||
this.footBuilder,
|
this.footBuilder,
|
||||||
this.headerBuilder,
|
this.headerBuilder,
|
||||||
required this.phantomController,
|
required this.phantomController,
|
||||||
Key? key,
|
Key? key,
|
||||||
}) : config = ReorderFlexConfig(spacing: spacing),
|
}) : reorderFlexConfig = const ReorderFlexConfig(),
|
||||||
super(key: key);
|
super(key: key);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -140,7 +147,7 @@ class _BoardContentState extends State<BoardContent> {
|
|||||||
|
|
||||||
final reorderFlex = ReorderFlex(
|
final reorderFlex = ReorderFlex(
|
||||||
key: widget.key,
|
key: widget.key,
|
||||||
config: widget.config,
|
config: widget.reorderFlexConfig,
|
||||||
scrollController: widget.scrollController,
|
scrollController: widget.scrollController,
|
||||||
onDragStarted: widget.onDragStarted,
|
onDragStarted: widget.onDragStarted,
|
||||||
onReorder: widget.onReorder,
|
onReorder: widget.onReorder,
|
||||||
@ -154,7 +161,15 @@ class _BoardContentState extends State<BoardContent> {
|
|||||||
return Stack(
|
return Stack(
|
||||||
alignment: AlignmentDirectional.topStart,
|
alignment: AlignmentDirectional.topStart,
|
||||||
children: [
|
children: [
|
||||||
if (widget.background != null) widget.background!,
|
if (widget.background != null)
|
||||||
|
Container(
|
||||||
|
clipBehavior: Clip.hardEdge,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
borderRadius:
|
||||||
|
BorderRadius.circular(widget.config.cornerRadius),
|
||||||
|
),
|
||||||
|
child: widget.background,
|
||||||
|
),
|
||||||
reorderFlex,
|
reorderFlex,
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
@ -173,8 +188,12 @@ class _BoardContentState extends State<BoardContent> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
List<Widget> _buildColumns() {
|
List<Widget> _buildColumns() {
|
||||||
final List<Widget> children = widget.dataController.columnDatas.map(
|
final List<Widget> children =
|
||||||
(columnData) {
|
widget.dataController.columnDatas.asMap().entries.map(
|
||||||
|
(item) {
|
||||||
|
final columnData = item.value;
|
||||||
|
final columnIndex = item.key;
|
||||||
|
|
||||||
final dataSource = _BoardColumnDataSourceImpl(
|
final dataSource = _BoardColumnDataSourceImpl(
|
||||||
columnId: columnData.id,
|
columnId: columnData.id,
|
||||||
dataController: widget.dataController,
|
dataController: widget.dataController,
|
||||||
@ -188,6 +207,8 @@ class _BoardContentState extends State<BoardContent> {
|
|||||||
return ConstrainedBox(
|
return ConstrainedBox(
|
||||||
constraints: widget.columnConstraints,
|
constraints: widget.columnConstraints,
|
||||||
child: BoardColumnWidget(
|
child: BoardColumnWidget(
|
||||||
|
margin: _marginFromIndex(columnIndex),
|
||||||
|
itemMargin: widget.config.columnItemPadding,
|
||||||
headerBuilder: widget.headerBuilder,
|
headerBuilder: widget.headerBuilder,
|
||||||
footBuilder: widget.footBuilder,
|
footBuilder: widget.footBuilder,
|
||||||
cardBuilder: widget.cardBuilder,
|
cardBuilder: widget.cardBuilder,
|
||||||
@ -195,7 +216,8 @@ class _BoardContentState extends State<BoardContent> {
|
|||||||
scrollController: ScrollController(),
|
scrollController: ScrollController(),
|
||||||
phantomController: widget.phantomController,
|
phantomController: widget.phantomController,
|
||||||
onReorder: widget.dataController.moveColumnItem,
|
onReorder: widget.dataController.moveColumnItem,
|
||||||
spacing: 10,
|
cornerRadius: widget.config.cornerRadius,
|
||||||
|
backgroundColor: widget.config.columnBackgroundColor,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
@ -206,6 +228,22 @@ class _BoardContentState extends State<BoardContent> {
|
|||||||
|
|
||||||
return children;
|
return children;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
EdgeInsets _marginFromIndex(int index) {
|
||||||
|
if (widget.dataController.columnDatas.isEmpty) {
|
||||||
|
return widget.config.columnPadding;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (index == 0) {
|
||||||
|
return EdgeInsets.only(right: widget.config.columnPadding.right);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (index == widget.dataController.columnDatas.length - 1) {
|
||||||
|
return EdgeInsets.only(left: widget.config.columnPadding.left);
|
||||||
|
}
|
||||||
|
|
||||||
|
return widget.config.columnPadding;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class _BoardColumnDataSourceImpl extends BoardColumnDataDataSource {
|
class _BoardColumnDataSourceImpl extends BoardColumnDataDataSource {
|
||||||
|
@ -3,9 +3,9 @@ import 'dart:collection';
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import '../../rendering/board_overlay.dart';
|
import '../../rendering/board_overlay.dart';
|
||||||
import '../../utils/log.dart';
|
import '../../utils/log.dart';
|
||||||
import '../phantom/phantom_controller.dart';
|
import '../reorder_phantom/phantom_controller.dart';
|
||||||
import '../flex/reorder_flex.dart';
|
import '../reorder_flex/reorder_flex.dart';
|
||||||
import '../flex/drag_target_inteceptor.dart';
|
import '../reorder_flex/drag_target_inteceptor.dart';
|
||||||
import 'board_column_data.dart';
|
import 'board_column_data.dart';
|
||||||
|
|
||||||
typedef OnColumnDragStarted = void Function(int index);
|
typedef OnColumnDragStarted = void Function(int index);
|
||||||
@ -79,7 +79,15 @@ class BoardColumnWidget extends StatefulWidget {
|
|||||||
|
|
||||||
final BoardColumnFooterBuilder? footBuilder;
|
final BoardColumnFooterBuilder? footBuilder;
|
||||||
|
|
||||||
BoardColumnWidget({
|
final EdgeInsets margin;
|
||||||
|
|
||||||
|
final EdgeInsets itemMargin;
|
||||||
|
|
||||||
|
final double cornerRadius;
|
||||||
|
|
||||||
|
final Color backgroundColor;
|
||||||
|
|
||||||
|
const BoardColumnWidget({
|
||||||
Key? key,
|
Key? key,
|
||||||
this.headerBuilder,
|
this.headerBuilder,
|
||||||
this.footBuilder,
|
this.footBuilder,
|
||||||
@ -90,8 +98,11 @@ class BoardColumnWidget extends StatefulWidget {
|
|||||||
this.onDragStarted,
|
this.onDragStarted,
|
||||||
this.scrollController,
|
this.scrollController,
|
||||||
this.onDragEnded,
|
this.onDragEnded,
|
||||||
double? spacing,
|
this.margin = EdgeInsets.zero,
|
||||||
}) : config = ReorderFlexConfig(spacing: spacing),
|
this.itemMargin = EdgeInsets.zero,
|
||||||
|
this.cornerRadius = 0.0,
|
||||||
|
this.backgroundColor = Colors.transparent,
|
||||||
|
}) : config = const ReorderFlexConfig(),
|
||||||
super(key: key);
|
super(key: key);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -149,12 +160,25 @@ class _BoardColumnWidgetState extends State<BoardColumnWidget> {
|
|||||||
children: children,
|
children: children,
|
||||||
);
|
);
|
||||||
|
|
||||||
return Column(
|
return Container(
|
||||||
children: [
|
margin: widget.margin,
|
||||||
if (header != null) header,
|
clipBehavior: Clip.hardEdge,
|
||||||
Expanded(child: reorderFlex),
|
decoration: BoxDecoration(
|
||||||
if (footer != null) footer,
|
color: widget.backgroundColor,
|
||||||
],
|
borderRadius: BorderRadius.circular(widget.cornerRadius),
|
||||||
|
),
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
if (header != null) header,
|
||||||
|
Expanded(
|
||||||
|
child: Padding(
|
||||||
|
padding: widget.itemMargin,
|
||||||
|
child: reorderFlex,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
if (footer != null) footer,
|
||||||
|
],
|
||||||
|
),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
opaque: false,
|
opaque: false,
|
||||||
|
@ -3,7 +3,7 @@ import 'dart:collection';
|
|||||||
import 'package:equatable/equatable.dart';
|
import 'package:equatable/equatable.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import '../../utils/log.dart';
|
import '../../utils/log.dart';
|
||||||
import '../flex/reorder_flex.dart';
|
import '../reorder_flex/reorder_flex.dart';
|
||||||
|
|
||||||
abstract class ColumnItem extends ReoderFlexItem {
|
abstract class ColumnItem extends ReoderFlexItem {
|
||||||
bool get isPhantom => false;
|
bool get isPhantom => false;
|
||||||
@ -92,10 +92,16 @@ class BoardColumnDataController extends ChangeNotifier with EquatableMixin {
|
|||||||
|
|
||||||
/// Replace the item at index with the [newItem].
|
/// Replace the item at index with the [newItem].
|
||||||
void replace(int index, ColumnItem newItem) {
|
void replace(int index, ColumnItem newItem) {
|
||||||
final removedItem = columnData._items.removeAt(index);
|
if (columnData._items.isEmpty) {
|
||||||
columnData._items.insert(index, newItem);
|
columnData._items.add(newItem);
|
||||||
Log.debug(
|
Log.debug('[$BoardColumnDataController] $columnData add $newItem');
|
||||||
'[$BoardColumnDataController] $columnData replace $removedItem with $newItem at $index');
|
} else {
|
||||||
|
final removedItem = columnData._items.removeAt(index);
|
||||||
|
columnData._items.insert(index, newItem);
|
||||||
|
Log.debug(
|
||||||
|
'[$BoardColumnDataController] $columnData replace $removedItem with $newItem at $index');
|
||||||
|
}
|
||||||
|
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -119,6 +125,6 @@ class BoardColumnData extends ReoderFlexItem with EquatableMixin {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
String toString() {
|
String toString() {
|
||||||
return 'Column$id';
|
return 'Column:[$id]';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,9 +4,9 @@ import 'package:equatable/equatable.dart';
|
|||||||
|
|
||||||
import '../utils/log.dart';
|
import '../utils/log.dart';
|
||||||
import 'board_column/board_column_data.dart';
|
import 'board_column/board_column_data.dart';
|
||||||
import 'flex/reorder_flex.dart';
|
import 'reorder_flex/reorder_flex.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'phantom/phantom_controller.dart';
|
import 'reorder_phantom/phantom_controller.dart';
|
||||||
|
|
||||||
typedef OnMoveColumn = void Function(int fromIndex, int toIndex);
|
typedef OnMoveColumn = void Function(int fromIndex, int toIndex);
|
||||||
|
|
||||||
@ -79,8 +79,11 @@ class BoardDataController extends ChangeNotifier
|
|||||||
int toColumnIndex,
|
int toColumnIndex,
|
||||||
) {
|
) {
|
||||||
final item = columnController(fromColumnId).removeAt(fromColumnIndex);
|
final item = columnController(fromColumnId).removeAt(fromColumnIndex);
|
||||||
assert(
|
|
||||||
columnController(toColumnId).items[toColumnIndex] is PhantomColumnItem);
|
if (columnController(toColumnId).items.length > toColumnIndex) {
|
||||||
|
assert(columnController(toColumnId).items[toColumnIndex]
|
||||||
|
is PhantomColumnItem);
|
||||||
|
}
|
||||||
|
|
||||||
columnController(toColumnId).replace(toColumnIndex, item);
|
columnController(toColumnId).replace(toColumnIndex, item);
|
||||||
|
|
||||||
@ -120,7 +123,7 @@ class BoardDataController extends ChangeNotifier
|
|||||||
columnController.removeAt(index);
|
columnController.removeAt(index);
|
||||||
|
|
||||||
Log.debug(
|
Log.debug(
|
||||||
'[$BoardDataController] Column$columnId remove phantom, current count: ${columnController.items.length}');
|
'[$BoardDataController] Column:[$columnId] remove phantom, current count: ${columnController.items.length}');
|
||||||
}
|
}
|
||||||
return isExist;
|
return isExist;
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,6 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter/scheduler.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
import '../transitions.dart';
|
import '../transitions.dart';
|
||||||
|
|
||||||
abstract class DragTargetData {
|
abstract class DragTargetData {
|
||||||
@ -65,6 +67,8 @@ class ReorderDragTarget<T extends DragTargetData> extends StatefulWidget {
|
|||||||
final AnimationController insertAnimationController;
|
final AnimationController insertAnimationController;
|
||||||
final AnimationController deleteAnimationController;
|
final AnimationController deleteAnimationController;
|
||||||
|
|
||||||
|
final bool useMoveAnimation;
|
||||||
|
|
||||||
ReorderDragTarget({
|
ReorderDragTarget({
|
||||||
Key? key,
|
Key? key,
|
||||||
required this.child,
|
required this.child,
|
||||||
@ -74,6 +78,7 @@ class ReorderDragTarget<T extends DragTargetData> extends StatefulWidget {
|
|||||||
required this.onWillAccept,
|
required this.onWillAccept,
|
||||||
required this.insertAnimationController,
|
required this.insertAnimationController,
|
||||||
required this.deleteAnimationController,
|
required this.deleteAnimationController,
|
||||||
|
required this.useMoveAnimation,
|
||||||
this.onAccept,
|
this.onAccept,
|
||||||
this.onLeave,
|
this.onLeave,
|
||||||
this.draggableTargetBuilder,
|
this.draggableTargetBuilder,
|
||||||
@ -140,7 +145,10 @@ class _ReorderDragTargetState<T extends DragTargetData>
|
|||||||
data: widget.dragTargetData,
|
data: widget.dragTargetData,
|
||||||
ignoringFeedbackSemantics: false,
|
ignoringFeedbackSemantics: false,
|
||||||
feedback: feedbackBuilder,
|
feedback: feedbackBuilder,
|
||||||
childWhenDragging: IgnorePointerWidget(child: widget.child),
|
childWhenDragging: IgnorePointerWidget(
|
||||||
|
useIntrinsicSize: !widget.useMoveAnimation,
|
||||||
|
child: widget.child,
|
||||||
|
),
|
||||||
onDragStarted: () {
|
onDragStarted: () {
|
||||||
_draggingFeedbackSize = widget._indexGlobalKey.currentContext?.size;
|
_draggingFeedbackSize = widget._indexGlobalKey.currentContext?.size;
|
||||||
widget.onDragStarted(
|
widget.onDragStarted(
|
||||||
@ -174,11 +182,13 @@ class _ReorderDragTargetState<T extends DragTargetData>
|
|||||||
transform: Matrix4.rotationZ(0),
|
transform: Matrix4.rotationZ(0),
|
||||||
alignment: FractionalOffset.topLeft,
|
alignment: FractionalOffset.topLeft,
|
||||||
child: Material(
|
child: Material(
|
||||||
elevation: 3.0,
|
|
||||||
color: Colors.transparent,
|
color: Colors.transparent,
|
||||||
borderRadius: BorderRadius.zero,
|
borderRadius: BorderRadius.zero,
|
||||||
clipBehavior: Clip.hardEdge,
|
clipBehavior: Clip.hardEdge,
|
||||||
child: ConstrainedBox(constraints: constraints, child: child),
|
child: ConstrainedBox(
|
||||||
|
constraints: constraints,
|
||||||
|
child: Opacity(opacity: 0.6, child: child),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -254,10 +264,12 @@ class IgnorePointerWidget extends StatelessWidget {
|
|||||||
final sizedChild = useIntrinsicSize
|
final sizedChild = useIntrinsicSize
|
||||||
? child
|
? child
|
||||||
: SizedBox(width: 0.0, height: 0.0, child: child);
|
: SizedBox(width: 0.0, height: 0.0, child: child);
|
||||||
|
|
||||||
|
final opacity = useIntrinsicSize ? 0.3 : 0.0;
|
||||||
return IgnorePointer(
|
return IgnorePointer(
|
||||||
ignoring: true,
|
ignoring: true,
|
||||||
child: Opacity(
|
child: Opacity(
|
||||||
opacity: 0,
|
opacity: opacity,
|
||||||
child: sizedChild,
|
child: sizedChild,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@ -282,6 +294,82 @@ class PhantomWidget extends StatelessWidget {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
abstract class DragTargetMovePlaceholderDelegate {
|
||||||
|
void registerPlaceholder(
|
||||||
|
int dragTargetIndex,
|
||||||
|
void Function(int currentDragTargetIndex) callback,
|
||||||
|
);
|
||||||
|
|
||||||
|
void unregisterPlaceholder(int dragTargetIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
class DragTargeMovePlaceholder extends StatefulWidget {
|
||||||
|
final double height;
|
||||||
|
final Color color;
|
||||||
|
final Color highlightColor;
|
||||||
|
final int dragTargetIndex;
|
||||||
|
final DragTargetMovePlaceholderDelegate delegate;
|
||||||
|
|
||||||
|
const DragTargeMovePlaceholder({
|
||||||
|
required this.delegate,
|
||||||
|
required this.dragTargetIndex,
|
||||||
|
this.height = 4,
|
||||||
|
this.color = Colors.transparent,
|
||||||
|
this.highlightColor = Colors.lightBlue,
|
||||||
|
Key? key,
|
||||||
|
}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<DragTargeMovePlaceholder> createState() =>
|
||||||
|
_DragTargeMovePlaceholderState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _DragTargeMovePlaceholderState extends State<DragTargeMovePlaceholder> {
|
||||||
|
ValueNotifier<bool> isHighlight = ValueNotifier(false);
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
widget.delegate.registerPlaceholder(
|
||||||
|
widget.dragTargetIndex,
|
||||||
|
(currentDragTargetIndex) {
|
||||||
|
if (!mounted) return;
|
||||||
|
|
||||||
|
SchedulerBinding.instance.addPostFrameCallback((Duration duration) {
|
||||||
|
if (currentDragTargetIndex == -1) {
|
||||||
|
isHighlight.value = false;
|
||||||
|
} else {
|
||||||
|
isHighlight.value =
|
||||||
|
widget.dragTargetIndex == currentDragTargetIndex;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
);
|
||||||
|
super.initState();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
isHighlight.dispose();
|
||||||
|
widget.delegate.unregisterPlaceholder(widget.dragTargetIndex);
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return ChangeNotifierProvider.value(
|
||||||
|
value: isHighlight,
|
||||||
|
child: Consumer<ValueNotifier<bool>>(
|
||||||
|
builder: (context, notifier, child) {
|
||||||
|
return Container(
|
||||||
|
height: widget.height,
|
||||||
|
color: notifier.value ? widget.highlightColor : widget.color,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
abstract class FakeDragTargetEventTrigger {
|
abstract class FakeDragTargetEventTrigger {
|
||||||
void fakeOnDragEnded(VoidCallback callback);
|
void fakeOnDragEnded(VoidCallback callback);
|
||||||
}
|
}
|
||||||
|
@ -30,12 +30,14 @@ abstract class DragTargetInterceptor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
abstract class OverlapDragTargetDelegate {
|
abstract class OverlapDragTargetDelegate {
|
||||||
void didReturnOriginalDragTarget();
|
void cancel();
|
||||||
void didCrossOtherDragTarget(
|
void moveTo(
|
||||||
String reorderFlexId,
|
String reorderFlexId,
|
||||||
FlexDragTargetData dragTargetData,
|
FlexDragTargetData dragTargetData,
|
||||||
int dragTargetIndex,
|
int dragTargetIndex,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
bool canMoveTo(String dragTargetId);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// [OverlappingDragTargetInteceptor] is used to receive the overlapping
|
/// [OverlappingDragTargetInteceptor] is used to receive the overlapping
|
||||||
@ -68,13 +70,11 @@ class OverlappingDragTargetInteceptor extends DragTargetInterceptor {
|
|||||||
required String dragTargetId,
|
required String dragTargetId,
|
||||||
required int dragTargetIndex}) {
|
required int dragTargetIndex}) {
|
||||||
if (dragTargetId == dragTargetData.reorderFlexId) {
|
if (dragTargetId == dragTargetData.reorderFlexId) {
|
||||||
delegate.didReturnOriginalDragTarget();
|
delegate.cancel();
|
||||||
} else {
|
} else {
|
||||||
delegate.didCrossOtherDragTarget(
|
if (delegate.canMoveTo(dragTargetId)) {
|
||||||
dragTargetId,
|
delegate.moveTo(dragTargetId, dragTargetData, 0);
|
||||||
dragTargetData,
|
}
|
||||||
dragTargetIndex,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@ -128,13 +128,13 @@ class CrossReorderFlexDragTargetInterceptor extends DragTargetInterceptor {
|
|||||||
@override
|
@override
|
||||||
void onAccept(FlexDragTargetData dragTargetData) {
|
void onAccept(FlexDragTargetData dragTargetData) {
|
||||||
Log.trace(
|
Log.trace(
|
||||||
'[$CrossReorderFlexDragTargetInterceptor] Column$reorderFlexId on onAccept');
|
'[$CrossReorderFlexDragTargetInterceptor] Column:[$reorderFlexId] on onAccept');
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void onLeave(FlexDragTargetData dragTargetData) {
|
void onLeave(FlexDragTargetData dragTargetData) {
|
||||||
Log.trace(
|
Log.trace(
|
||||||
'[$CrossReorderFlexDragTargetInterceptor] Column$reorderFlexId on leave');
|
'[$CrossReorderFlexDragTargetInterceptor] Column:[$reorderFlexId] on leave');
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -41,16 +41,19 @@ class ReorderFlexConfig {
|
|||||||
// How long an animation to scroll to an off-screen element
|
// How long an animation to scroll to an off-screen element
|
||||||
final Duration scrollAnimationDuration = const Duration(milliseconds: 250);
|
final Duration scrollAnimationDuration = const Duration(milliseconds: 250);
|
||||||
|
|
||||||
final double? spacing;
|
final bool useMoveAnimation;
|
||||||
|
|
||||||
const ReorderFlexConfig({this.spacing});
|
final bool useMovePlaceholder;
|
||||||
|
|
||||||
|
const ReorderFlexConfig({
|
||||||
|
this.useMoveAnimation = true,
|
||||||
|
}) : useMovePlaceholder = !useMoveAnimation;
|
||||||
}
|
}
|
||||||
|
|
||||||
class ReorderFlex extends StatefulWidget {
|
class ReorderFlex extends StatefulWidget {
|
||||||
final ReorderFlexConfig config;
|
final ReorderFlexConfig config;
|
||||||
|
|
||||||
final List<Widget> children;
|
final List<Widget> children;
|
||||||
final EdgeInsets? padding;
|
|
||||||
|
|
||||||
/// [direction] How to place the children, default is Axis.vertical
|
/// [direction] How to place the children, default is Axis.vertical
|
||||||
final Axis direction;
|
final Axis direction;
|
||||||
@ -81,7 +84,6 @@ class ReorderFlex extends StatefulWidget {
|
|||||||
this.onDragStarted,
|
this.onDragStarted,
|
||||||
this.onDragEnded,
|
this.onDragEnded,
|
||||||
this.interceptor,
|
this.interceptor,
|
||||||
this.padding,
|
|
||||||
this.direction = Axis.vertical,
|
this.direction = Axis.vertical,
|
||||||
}) : super(key: key);
|
}) : super(key: key);
|
||||||
|
|
||||||
@ -108,8 +110,11 @@ class ReorderFlexState extends State<ReorderFlex>
|
|||||||
/// [_animation] controls the dragging animations
|
/// [_animation] controls the dragging animations
|
||||||
late DragTargetAnimation _animation;
|
late DragTargetAnimation _animation;
|
||||||
|
|
||||||
|
late ReorderFlexNotifier _notifier;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
|
_notifier = ReorderFlexNotifier();
|
||||||
dragState = DraggingState(widget.reorderFlexId);
|
dragState = DraggingState(widget.reorderFlexId);
|
||||||
|
|
||||||
_animation = DragTargetAnimation(
|
_animation = DragTargetAnimation(
|
||||||
@ -154,13 +159,14 @@ class ReorderFlexState extends State<ReorderFlex>
|
|||||||
|
|
||||||
for (int i = 0; i < widget.children.length; i += 1) {
|
for (int i = 0; i < widget.children.length; i += 1) {
|
||||||
Widget child = widget.children[i];
|
Widget child = widget.children[i];
|
||||||
|
children.add(_wrap(child, i));
|
||||||
|
|
||||||
if (widget.config.spacing != null) {
|
// if (widget.config.useMovePlaceholder) {
|
||||||
children.add(SizedBox(width: widget.config.spacing!));
|
// children.add(DragTargeMovePlaceholder(
|
||||||
}
|
// dragTargetIndex: i,
|
||||||
|
// delegate: _notifier,
|
||||||
final wrapChild = _wrap(child, i);
|
// ));
|
||||||
children.add(wrapChild);
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
final child = _wrapContainer(children);
|
final child = _wrapContainer(children);
|
||||||
@ -199,7 +205,8 @@ class ReorderFlexState extends State<ReorderFlex>
|
|||||||
/// [childIndex]: the index of the child in a list
|
/// [childIndex]: the index of the child in a list
|
||||||
Widget _wrap(Widget child, int childIndex) {
|
Widget _wrap(Widget child, int childIndex) {
|
||||||
return Builder(builder: (context) {
|
return Builder(builder: (context) {
|
||||||
final dragTarget = _buildDragTarget(context, child, childIndex);
|
final ReorderDragTarget dragTarget =
|
||||||
|
_buildDragTarget(context, child, childIndex);
|
||||||
int shiftedIndex = childIndex;
|
int shiftedIndex = childIndex;
|
||||||
|
|
||||||
if (dragState.isOverlapWithPhantom()) {
|
if (dragState.isOverlapWithPhantom()) {
|
||||||
@ -207,7 +214,7 @@ class ReorderFlexState extends State<ReorderFlex>
|
|||||||
}
|
}
|
||||||
|
|
||||||
Log.trace(
|
Log.trace(
|
||||||
'Rebuild: Column${dragState.id} ${dragState.toString()}, childIndex: $childIndex shiftedIndex: $shiftedIndex');
|
'Rebuild: Column:[${dragState.id}] ${dragState.toString()}, childIndex: $childIndex shiftedIndex: $shiftedIndex');
|
||||||
final currentIndex = dragState.currentIndex;
|
final currentIndex = dragState.currentIndex;
|
||||||
final dragPhantomIndex = dragState.phantomIndex;
|
final dragPhantomIndex = dragState.phantomIndex;
|
||||||
|
|
||||||
@ -234,15 +241,18 @@ class ReorderFlexState extends State<ReorderFlex>
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Determine the size of the drop area to show under the dragging widget.
|
/// Determine the size of the drop area to show under the dragging widget.
|
||||||
final feedbackSize = dragState.feedbackSize;
|
Size? feedbackSize = Size.zero;
|
||||||
|
if (widget.config.useMoveAnimation) {
|
||||||
|
feedbackSize = dragState.feedbackSize;
|
||||||
|
}
|
||||||
|
|
||||||
Widget appearSpace = _makeAppearSpace(dragSpace, feedbackSize);
|
Widget appearSpace = _makeAppearSpace(dragSpace, feedbackSize);
|
||||||
Widget disappearSpace = _makeDisappearSpace(dragSpace, feedbackSize);
|
Widget disappearSpace = _makeDisappearSpace(dragSpace, feedbackSize);
|
||||||
|
|
||||||
/// When start dragging, the dragTarget, [ReorderDragTarget], will
|
/// When start dragging, the dragTarget, [ReorderDragTarget], will
|
||||||
/// return a [IgnorePointerWidget] which size is zero.
|
/// return a [IgnorePointerWidget] which size is zero.
|
||||||
if (dragState.isPhantomAboveDragTarget()) {
|
if (dragState.isPhantomAboveDragTarget()) {
|
||||||
//the phantom is moving down, i.e. the tile below the phantom is moving up
|
_notifier.updateDragTargetIndex(currentIndex);
|
||||||
Log.trace('index:$childIndex item moving up / phantom moving down');
|
|
||||||
if (shiftedIndex == currentIndex && childIndex == dragPhantomIndex) {
|
if (shiftedIndex == currentIndex && childIndex == dragPhantomIndex) {
|
||||||
return _buildDraggingContainer(children: [
|
return _buildDraggingContainer(children: [
|
||||||
disappearSpace,
|
disappearSpace,
|
||||||
@ -264,8 +274,7 @@ class ReorderFlexState extends State<ReorderFlex>
|
|||||||
|
|
||||||
///
|
///
|
||||||
if (dragState.isPhantomBelowDragTarget()) {
|
if (dragState.isPhantomBelowDragTarget()) {
|
||||||
//the phantom is moving up, i.e. the tile above the phantom is moving down
|
_notifier.updateDragTargetIndex(currentIndex);
|
||||||
Log.trace('index:$childIndex item moving down / phantom moving up');
|
|
||||||
if (shiftedIndex == currentIndex && childIndex == dragPhantomIndex) {
|
if (shiftedIndex == currentIndex && childIndex == dragPhantomIndex) {
|
||||||
return _buildDraggingContainer(children: [
|
return _buildDraggingContainer(children: [
|
||||||
appearSpace,
|
appearSpace,
|
||||||
@ -303,10 +312,7 @@ class ReorderFlexState extends State<ReorderFlex>
|
|||||||
}
|
}
|
||||||
|
|
||||||
ReorderDragTarget _buildDragTarget(
|
ReorderDragTarget _buildDragTarget(
|
||||||
BuildContext builderContext,
|
BuildContext builderContext, Widget child, int dragTargetIndex) {
|
||||||
Widget child,
|
|
||||||
int dragTargetIndex,
|
|
||||||
) {
|
|
||||||
final ReoderFlexItem reorderFlexItem =
|
final ReoderFlexItem reorderFlexItem =
|
||||||
widget.dataSource.items[dragTargetIndex];
|
widget.dataSource.items[dragTargetIndex];
|
||||||
return ReorderDragTarget<FlexDragTargetData>(
|
return ReorderDragTarget<FlexDragTargetData>(
|
||||||
@ -319,14 +325,14 @@ class ReorderFlexState extends State<ReorderFlex>
|
|||||||
),
|
),
|
||||||
onDragStarted: (draggingWidget, draggingIndex, size) {
|
onDragStarted: (draggingWidget, draggingIndex, size) {
|
||||||
Log.debug(
|
Log.debug(
|
||||||
"[DragTarget] Column${widget.dataSource.identifier} start dragging item at $draggingIndex");
|
"[DragTarget] Column:[${widget.dataSource.identifier}] start dragging item at $draggingIndex");
|
||||||
_startDragging(draggingWidget, draggingIndex, size);
|
_startDragging(draggingWidget, draggingIndex, size);
|
||||||
widget.onDragStarted?.call(draggingIndex);
|
widget.onDragStarted?.call(draggingIndex);
|
||||||
},
|
},
|
||||||
onDragEnded: (dragTargetData) {
|
onDragEnded: (dragTargetData) {
|
||||||
Log.debug(
|
Log.debug(
|
||||||
"[DragTarget]: Column${widget.dataSource.identifier} end dragging");
|
"[DragTarget]: Column:[${widget.dataSource.identifier}] end dragging");
|
||||||
|
_notifier.updateDragTargetIndex(-1);
|
||||||
setState(() {
|
setState(() {
|
||||||
if (dragTargetData.reorderFlexId == widget.reorderFlexId) {
|
if (dragTargetData.reorderFlexId == widget.reorderFlexId) {
|
||||||
_onReordered(
|
_onReordered(
|
||||||
@ -340,14 +346,11 @@ class ReorderFlexState extends State<ReorderFlex>
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
onWillAccept: (FlexDragTargetData dragTargetData) {
|
onWillAccept: (FlexDragTargetData dragTargetData) {
|
||||||
Log.debug('Insert animation: ${_animation.deleteController.status}');
|
|
||||||
|
|
||||||
if (_animation.deleteController.isAnimating) {
|
if (_animation.deleteController.isAnimating) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(widget.dataSource.items.length > dragTargetIndex);
|
assert(widget.dataSource.items.length > dragTargetIndex);
|
||||||
|
|
||||||
if (_interceptDragTarget(
|
if (_interceptDragTarget(
|
||||||
dragTargetData,
|
dragTargetData,
|
||||||
(interceptor) => interceptor.onWillAccept(
|
(interceptor) => interceptor.onWillAccept(
|
||||||
@ -370,6 +373,7 @@ class ReorderFlexState extends State<ReorderFlex>
|
|||||||
);
|
);
|
||||||
},
|
},
|
||||||
onLeave: (dragTargetData) {
|
onLeave: (dragTargetData) {
|
||||||
|
_notifier.updateDragTargetIndex(-1);
|
||||||
_interceptDragTarget(
|
_interceptDragTarget(
|
||||||
dragTargetData,
|
dragTargetData,
|
||||||
(interceptor) => interceptor.onLeave(dragTargetData),
|
(interceptor) => interceptor.onLeave(dragTargetData),
|
||||||
@ -378,6 +382,7 @@ class ReorderFlexState extends State<ReorderFlex>
|
|||||||
insertAnimationController: _animation.insertController,
|
insertAnimationController: _animation.insertController,
|
||||||
deleteAnimationController: _animation.deleteController,
|
deleteAnimationController: _animation.deleteController,
|
||||||
draggableTargetBuilder: widget.interceptor?.draggableTargetBuilder,
|
draggableTargetBuilder: widget.interceptor?.draggableTargetBuilder,
|
||||||
|
useMoveAnimation: widget.config.useMoveAnimation,
|
||||||
child: child,
|
child: child,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -430,7 +435,7 @@ class ReorderFlexState extends State<ReorderFlex>
|
|||||||
/// The [willAccept] will be true if the dargTarget is the widget that gets
|
/// The [willAccept] will be true if the dargTarget is the widget that gets
|
||||||
/// dragged and it is dragged on top of the other dragTargets.
|
/// dragged and it is dragged on top of the other dragTargets.
|
||||||
///
|
///
|
||||||
Log.trace(
|
Log.debug(
|
||||||
'[$ReorderDragTarget] ${widget.dataSource.identifier} on will accept, dragIndex:$dragIndex, dragTargetIndex:$dragTargetIndex, count: ${widget.dataSource.items.length}');
|
'[$ReorderDragTarget] ${widget.dataSource.identifier} on will accept, dragIndex:$dragIndex, dragTargetIndex:$dragTargetIndex, count: ${widget.dataSource.items.length}');
|
||||||
|
|
||||||
bool willAccept =
|
bool willAccept =
|
||||||
@ -442,7 +447,6 @@ class ReorderFlexState extends State<ReorderFlex>
|
|||||||
} else {
|
} else {
|
||||||
dragState.updateNextIndex(dragTargetIndex);
|
dragState.updateNextIndex(dragTargetIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
_requestAnimationToNextIndex(isAcceptingNewTarget: true);
|
_requestAnimationToNextIndex(isAcceptingNewTarget: true);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -467,7 +471,6 @@ class ReorderFlexState extends State<ReorderFlex>
|
|||||||
} else {
|
} else {
|
||||||
return SingleChildScrollView(
|
return SingleChildScrollView(
|
||||||
scrollDirection: widget.direction,
|
scrollDirection: widget.direction,
|
||||||
padding: widget.padding,
|
|
||||||
controller: _scrollController,
|
controller: _scrollController,
|
||||||
child: child,
|
child: child,
|
||||||
);
|
);
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import 'package:flutter/widgets.dart';
|
import 'package:flutter/widgets.dart';
|
||||||
|
|
||||||
import '../transitions.dart';
|
import '../transitions.dart';
|
||||||
|
import 'drag_target.dart';
|
||||||
|
|
||||||
mixin ReorderFlexMinxi {
|
mixin ReorderFlexMinxi {
|
||||||
@protected
|
@protected
|
||||||
@ -86,3 +87,56 @@ extension CurveAnimationController on AnimationController {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class ReorderFlexNotifier extends DragTargetMovePlaceholderDelegate {
|
||||||
|
Map<int, DragTargetEventNotifier> dragTargeEventNotifier = {};
|
||||||
|
|
||||||
|
void updateDragTargetIndex(int index) {
|
||||||
|
for (var notifier in dragTargeEventNotifier.values) {
|
||||||
|
notifier.setDragTargetIndex(index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DragTargetEventNotifier _notifierFromIndex(int dragTargetIndex) {
|
||||||
|
DragTargetEventNotifier? notifier = dragTargeEventNotifier[dragTargetIndex];
|
||||||
|
if (notifier == null) {
|
||||||
|
final newNotifier = DragTargetEventNotifier();
|
||||||
|
dragTargeEventNotifier[dragTargetIndex] = newNotifier;
|
||||||
|
notifier = newNotifier;
|
||||||
|
}
|
||||||
|
|
||||||
|
return notifier;
|
||||||
|
}
|
||||||
|
|
||||||
|
void dispose() {
|
||||||
|
for (var notifier in dragTargeEventNotifier.values) {
|
||||||
|
notifier.dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void registerPlaceholder(
|
||||||
|
int dragTargetIndex,
|
||||||
|
void Function(int dragTargetIndex) callback,
|
||||||
|
) {
|
||||||
|
_notifierFromIndex(dragTargetIndex).addListener(() {
|
||||||
|
callback.call(_notifierFromIndex(dragTargetIndex).currentDragTargetIndex);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void unregisterPlaceholder(int dragTargetIndex) {
|
||||||
|
dragTargeEventNotifier.remove(dragTargetIndex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class DragTargetEventNotifier extends ChangeNotifier {
|
||||||
|
int currentDragTargetIndex = -1;
|
||||||
|
|
||||||
|
void setDragTargetIndex(int index) {
|
||||||
|
if (currentDragTargetIndex != index) {
|
||||||
|
currentDragTargetIndex = index;
|
||||||
|
notifyListeners();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1,9 +1,11 @@
|
|||||||
|
import 'dart:async';
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import '../../utils/log.dart';
|
import '../../utils/log.dart';
|
||||||
import '../board_column/board_column_data.dart';
|
import '../board_column/board_column_data.dart';
|
||||||
import '../flex/drag_state.dart';
|
import '../reorder_flex/drag_state.dart';
|
||||||
import '../flex/drag_target.dart';
|
import '../reorder_flex/drag_target.dart';
|
||||||
import '../flex/drag_target_inteceptor.dart';
|
import '../reorder_flex/drag_target_inteceptor.dart';
|
||||||
import 'phantom_state.dart';
|
import 'phantom_state.dart';
|
||||||
|
|
||||||
abstract class BoardPhantomControllerDelegate {
|
abstract class BoardPhantomControllerDelegate {
|
||||||
@ -127,8 +129,8 @@ class BoardPhantomController extends OverlapDragTargetDelegate
|
|||||||
FlexDragTargetData dragTargetData,
|
FlexDragTargetData dragTargetData,
|
||||||
int dragTargetIndex,
|
int dragTargetIndex,
|
||||||
) {
|
) {
|
||||||
// Log.debug('[$BoardPhantomController] move Column${dragTargetData.reorderFlexId}:${dragTargetData.draggingIndex} '
|
// Log.debug('[$BoardPhantomController] move Column:[${dragTargetData.reorderFlexId}]:${dragTargetData.draggingIndex} '
|
||||||
// 'to Column$columnId:$index');
|
// 'to Column:[$columnId]:$index');
|
||||||
|
|
||||||
phantomRecord = PhantomRecord(
|
phantomRecord = PhantomRecord(
|
||||||
toColumnId: columnId,
|
toColumnId: columnId,
|
||||||
@ -177,7 +179,7 @@ class BoardPhantomController extends OverlapDragTargetDelegate
|
|||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void didReturnOriginalDragTarget() {
|
void cancel() {
|
||||||
if (phantomRecord == null) {
|
if (phantomRecord == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -188,7 +190,7 @@ class BoardPhantomController extends OverlapDragTargetDelegate
|
|||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void didCrossOtherDragTarget(
|
void moveTo(
|
||||||
String reorderFlexId,
|
String reorderFlexId,
|
||||||
FlexDragTargetData dragTargetData,
|
FlexDragTargetData dragTargetData,
|
||||||
int dragTargetIndex,
|
int dragTargetIndex,
|
||||||
@ -199,6 +201,12 @@ class BoardPhantomController extends OverlapDragTargetDelegate
|
|||||||
dragTargetIndex,
|
dragTargetIndex,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool canMoveTo(String dragTargetId) {
|
||||||
|
// TODO: implement shouldReceive
|
||||||
|
return delegate.controller(dragTargetId)?.columnData.items.length == 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Use [PhantomRecord] to record where to remove the column item and where to
|
/// Use [PhantomRecord] to record where to remove the column item and where to
|
||||||
@ -228,7 +236,7 @@ class PhantomRecord {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Log.debug(
|
Log.debug(
|
||||||
'[$PhantomRecord] Update Column$fromColumnId remove position to $index');
|
'[$PhantomRecord] Update Column:[$fromColumnId] remove position to $index');
|
||||||
fromColumnIndex = index;
|
fromColumnIndex = index;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -238,13 +246,13 @@ class PhantomRecord {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Log.debug(
|
Log.debug(
|
||||||
'[$PhantomRecord] Column$toColumnId update position $toColumnIndex -> $index');
|
'[$PhantomRecord] Column:[$toColumnId] update position $toColumnIndex -> $index');
|
||||||
toColumnIndex = index;
|
toColumnIndex = index;
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String toString() {
|
String toString() {
|
||||||
return 'Column$fromColumnId:$fromColumnIndex to Column$toColumnId:$toColumnIndex';
|
return 'Column:[$fromColumnId]:$fromColumnIndex to Column:[$toColumnId]:$toColumnIndex';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -0,0 +1,3 @@
|
|||||||
|
export 'card.dart';
|
||||||
|
export 'footer.dart';
|
||||||
|
export 'header.dart';
|
@ -0,0 +1,37 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
class AppFlowyColumnItemCard extends StatefulWidget {
|
||||||
|
final Widget? child;
|
||||||
|
final Color backgroundColor;
|
||||||
|
final double cornerRadius;
|
||||||
|
final BoxConstraints boxConstraints;
|
||||||
|
|
||||||
|
const AppFlowyColumnItemCard({
|
||||||
|
this.child,
|
||||||
|
this.backgroundColor = Colors.white,
|
||||||
|
this.cornerRadius = 0.0,
|
||||||
|
this.boxConstraints = const BoxConstraints.tightFor(height: 60),
|
||||||
|
Key? key,
|
||||||
|
}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<AppFlowyColumnItemCard> createState() => _AppFlowyColumnItemCardState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _AppFlowyColumnItemCardState extends State<AppFlowyColumnItemCard> {
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Padding(
|
||||||
|
padding: const EdgeInsets.all(4.0),
|
||||||
|
child: Container(
|
||||||
|
constraints: widget.boxConstraints,
|
||||||
|
clipBehavior: Clip.hardEdge,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: widget.backgroundColor,
|
||||||
|
borderRadius: BorderRadius.circular(widget.cornerRadius),
|
||||||
|
),
|
||||||
|
child: widget.child,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,46 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
typedef OnFooterAddButtonClick = void Function();
|
||||||
|
|
||||||
|
class AppFlowyColumnFooter extends StatefulWidget {
|
||||||
|
final double height;
|
||||||
|
final Widget? icon;
|
||||||
|
final Widget? title;
|
||||||
|
final EdgeInsets margin;
|
||||||
|
final OnFooterAddButtonClick? onAddButtonClick;
|
||||||
|
|
||||||
|
const AppFlowyColumnFooter({
|
||||||
|
this.icon,
|
||||||
|
this.title,
|
||||||
|
this.margin = EdgeInsets.zero,
|
||||||
|
required this.height,
|
||||||
|
this.onAddButtonClick,
|
||||||
|
Key? key,
|
||||||
|
}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<AppFlowyColumnFooter> createState() => _AppFlowyColumnFooterState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _AppFlowyColumnFooterState extends State<AppFlowyColumnFooter> {
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return GestureDetector(
|
||||||
|
onTap: widget.onAddButtonClick,
|
||||||
|
child: SizedBox(
|
||||||
|
height: widget.height,
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 10),
|
||||||
|
child: Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.start,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
if (widget.icon != null) widget.icon!,
|
||||||
|
if (widget.title != null) widget.title!,
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,74 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
typedef OnHeaderAddButtonClick = void Function();
|
||||||
|
typedef OnHeaderMoreButtonClick = void Function();
|
||||||
|
|
||||||
|
class AppFlowyColumnHeader extends StatefulWidget {
|
||||||
|
final double height;
|
||||||
|
final Widget? icon;
|
||||||
|
final Widget? title;
|
||||||
|
final Widget? addIcon;
|
||||||
|
final Widget? moreIcon;
|
||||||
|
final EdgeInsets margin;
|
||||||
|
final OnHeaderAddButtonClick? onAddButtonClick;
|
||||||
|
final OnHeaderMoreButtonClick? onMoreButtonClick;
|
||||||
|
|
||||||
|
const AppFlowyColumnHeader({
|
||||||
|
required this.height,
|
||||||
|
this.icon,
|
||||||
|
this.title,
|
||||||
|
this.addIcon,
|
||||||
|
this.moreIcon,
|
||||||
|
this.margin = EdgeInsets.zero,
|
||||||
|
this.onAddButtonClick,
|
||||||
|
this.onMoreButtonClick,
|
||||||
|
Key? key,
|
||||||
|
}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<AppFlowyColumnHeader> createState() => _AppFlowyColumnHeaderState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _AppFlowyColumnHeaderState extends State<AppFlowyColumnHeader> {
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
List<Widget> children = [];
|
||||||
|
|
||||||
|
if (widget.icon != null) {
|
||||||
|
children.add(widget.icon!);
|
||||||
|
children.add(_hSpace());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (widget.title != null) {
|
||||||
|
children.add(widget.title!);
|
||||||
|
children.add(_hSpace());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (widget.moreIcon != null) {
|
||||||
|
children.add(const Spacer());
|
||||||
|
children.add(
|
||||||
|
IconButton(onPressed: widget.onMoreButtonClick, icon: widget.moreIcon!),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (widget.addIcon != null) {
|
||||||
|
children.add(
|
||||||
|
IconButton(onPressed: widget.onAddButtonClick, icon: widget.addIcon!),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return SizedBox(
|
||||||
|
height: widget.height,
|
||||||
|
child: Padding(
|
||||||
|
padding: widget.margin,
|
||||||
|
child: Row(
|
||||||
|
children: children,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _hSpace() {
|
||||||
|
return const SizedBox(width: 6);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user