From 4b6417740d0507cf0ed9afd53c2cfea249904834 Mon Sep 17 00:00:00 2001 From: Ian Koerich Maciel Date: Wed, 15 Sep 2021 08:35:19 -0300 Subject: [PATCH 1/7] Make stateless widget immutable As stateless widget must be immutable, this commit fix these issues by turning all properties to final. --- example/example.dart | 9 ++------- lib/boardview.dart | 35 ++++++++++++++++++++++++----------- 2 files changed, 26 insertions(+), 18 deletions(-) diff --git a/example/example.dart b/example/example.dart index c5c7fdb..a31211d 100644 --- a/example/example.dart +++ b/example/example.dart @@ -8,10 +8,7 @@ import 'BoardItemObject.dart'; import 'BoardListObject.dart'; class BoardViewExample extends StatelessWidget { - - - - List _listData = [ + final List _listData = [ BoardListObject(title: "List title 1"), BoardListObject(title: "List title 2"), BoardListObject(title: "List title 3") @@ -19,9 +16,7 @@ class BoardViewExample extends StatelessWidget { //Can be used to animate to different sections of the BoardView - BoardViewController boardViewController = new BoardViewController(); - - + final BoardViewController boardViewController = new BoardViewController(); @override Widget build(BuildContext context) { diff --git a/lib/boardview.dart b/lib/boardview.dart index dfbe9b2..49a443c 100644 --- a/lib/boardview.dart +++ b/lib/boardview.dart @@ -12,17 +12,30 @@ import 'package:vs_scrollbar/vs_scrollbar.dart'; class BoardView extends StatefulWidget { final List? lists; final double width; - Widget? middleWidget; - double? bottomPadding; - bool isSelecting; - bool? scrollbar; - ScrollbarStyle? scrollbarStyle; - BoardViewController? boardViewController; - int dragDelay; - - Function(bool)? itemInMiddleWidget; - OnDropBottomWidget? onDropItemInMiddleWidget; - BoardView({Key? key, this.itemInMiddleWidget,this.scrollbar,this.scrollbarStyle,this.boardViewController,this.dragDelay=300,this.onDropItemInMiddleWidget, this.isSelecting = false, this.lists, this.width = 280, this.middleWidget, this.bottomPadding}) : super(key: key); + final Widget? middleWidget; + final double? bottomPadding; + final bool isSelecting; + final bool? scrollbar; + final ScrollbarStyle? scrollbarStyle; + final BoardViewController? boardViewController; + final int dragDelay; + final Function(bool)? itemInMiddleWidget; + final OnDropBottomWidget? onDropItemInMiddleWidget; + + BoardView({ + Key? key, + this.itemInMiddleWidget, + this.scrollbar, + this.scrollbarStyle, + this.boardViewController, + this.dragDelay = 300, + this.onDropItemInMiddleWidget, + this.isSelecting = false, + this.lists, + this.width = 280, + this.middleWidget, + this.bottomPadding, + }) : super(key: key); @override State createState() { From 5857fa67b4d5863500ce1f841d9e650ef279c45c Mon Sep 17 00:00:00 2001 From: Ian Koerich Maciel Date: Wed, 15 Sep 2021 08:53:55 -0300 Subject: [PATCH 2/7] Call super on AutomaticKeepAliveClientMixin build method Build method on AutomaticKeepAliveClientMixin is marked with @mustCallSuper. This commit add a super.build() call before any code be executed on build method from BoardView, BoardList and BoardItem. --- lib/board_item.dart | 1 + lib/board_list.dart | 1 + 2 files changed, 2 insertions(+) diff --git a/lib/board_item.dart b/lib/board_item.dart index c00cd2f..0822211 100644 --- a/lib/board_item.dart +++ b/lib/board_item.dart @@ -89,6 +89,7 @@ class BoardItemState extends State with AutomaticKeepAliveClientMixin @override Widget build(BuildContext context) { + super.build(context); WidgetsBinding.instance! .addPostFrameCallback((_) => afterFirstLayout(context)); if (widget.boardList!.itemStates.length > widget.index!) { diff --git a/lib/board_list.dart b/lib/board_list.dart index f9d95ec..1484f0c 100644 --- a/lib/board_list.dart +++ b/lib/board_list.dart @@ -78,6 +78,7 @@ class BoardListState extends State with AutomaticKeepAliveClientMixin @override Widget build(BuildContext context) { + super.build(context); List listWidgets = []; if (widget.header != null) { Color? headerBackgroundColor = Color.fromARGB(255, 255, 255, 255); From b991074762d3bf3b898ffeef2188fc25d8346876 Mon Sep 17 00:00:00 2001 From: Ian Koerich Maciel Date: Wed, 15 Sep 2021 09:19:24 -0300 Subject: [PATCH 3/7] Fix unused code on headerBackgroundColor Local variable headerBackgroundColor was not being used, causing default value for background color (255, 255, 255) to never be used. This commit add a proper null check on header container. --- lib/board_list.dart | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/lib/board_list.dart b/lib/board_list.dart index 1484f0c..fd5cdeb 100644 --- a/lib/board_list.dart +++ b/lib/board_list.dart @@ -81,10 +81,6 @@ class BoardListState extends State with AutomaticKeepAliveClientMixin super.build(context); List listWidgets = []; if (widget.header != null) { - Color? headerBackgroundColor = Color.fromARGB(255, 255, 255, 255); - if (widget.headerBackgroundColor != null) { - headerBackgroundColor = widget.headerBackgroundColor; - } listWidgets.add(GestureDetector( onTap: (){ if(widget.onTapList != null){ @@ -109,7 +105,8 @@ class BoardListState extends State with AutomaticKeepAliveClientMixin } }, child: Container( - color: widget.headerBackgroundColor, + color: widget.headerBackgroundColor ?? + const Color.fromARGB(255, 255, 255, 255), child: Row( mainAxisSize: MainAxisSize.max, mainAxisAlignment: MainAxisAlignment.center, From 2785b7b9754645694c497f60c88598b633578772 Mon Sep 17 00:00:00 2001 From: Ian Koerich Maciel Date: Wed, 15 Sep 2021 09:59:31 -0300 Subject: [PATCH 4/7] Fix lint and formatting issues Starting on Flutter 2.5, Google established new standards lint rules for Dart and Flutter (https://medium.com/dartlang/announcing-dart-2-14-b48b9bb2fb67). This commit update the analysis_options.yaml and fix all code to meet these guidelines. --- analysis_options.yaml | 29 ++ example/BoardItemObject.dart | 11 - example/BoardListObject.dart | 16 - example/board_item_object.dart | 5 + example/board_list_object.dart | 8 + example/example.dart | 43 +- lib/board_item.dart | 62 +-- lib/board_list.dart | 117 ++--- lib/{boardview.dart => board_view.dart} | 570 ++++++++++++++---------- lib/board_view_controller.dart | 17 + lib/boardview_controller.dart | 18 - pubspec.lock | 22 +- pubspec.yaml | 1 + test/boardview_test.dart | 5 +- 14 files changed, 527 insertions(+), 397 deletions(-) create mode 100644 analysis_options.yaml delete mode 100644 example/BoardItemObject.dart delete mode 100644 example/BoardListObject.dart create mode 100644 example/board_item_object.dart create mode 100644 example/board_list_object.dart rename lib/{boardview.dart => board_view.dart} (51%) create mode 100644 lib/board_view_controller.dart delete mode 100644 lib/boardview_controller.dart diff --git a/analysis_options.yaml b/analysis_options.yaml new file mode 100644 index 0000000..61b6c4d --- /dev/null +++ b/analysis_options.yaml @@ -0,0 +1,29 @@ +# This file configures the analyzer, which statically analyzes Dart code to +# check for errors, warnings, and lints. +# +# The issues identified by the analyzer are surfaced in the UI of Dart-enabled +# IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be +# invoked from the command line by running `flutter analyze`. + +# The following line activates a set of recommended lints for Flutter apps, +# packages, and plugins designed to encourage good coding practices. +include: package:flutter_lints/flutter.yaml + +linter: + # The lint rules applied to this project can be customized in the + # section below to disable rules from the `package:flutter_lints/flutter.yaml` + # included above or to enable additional rules. A list of all available lints + # and their documentation is published at + # https://dart-lang.github.io/linter/lints/index.html. + # + # Instead of disabling a lint rule for the entire project in the + # section below, it can also be suppressed for a single line of code + # or a specific dart file by using the `// ignore: name_of_lint` and + # `// ignore_for_file: name_of_lint` syntax on the line or in the file + # producing the lint. + rules: + # avoid_print: false # Uncomment to disable the `avoid_print` rule + # prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule + +# Additional information about this file can be found at +# https://dart.dev/guides/language/analysis-options diff --git a/example/BoardItemObject.dart b/example/BoardItemObject.dart deleted file mode 100644 index 36141d5..0000000 --- a/example/BoardItemObject.dart +++ /dev/null @@ -1,11 +0,0 @@ -class BoardItemObject{ - - String? title; - - BoardItemObject({this.title}){ - if(this.title == null){ - this.title = ""; - } - } - -} \ No newline at end of file diff --git a/example/BoardListObject.dart b/example/BoardListObject.dart deleted file mode 100644 index 449d80e..0000000 --- a/example/BoardListObject.dart +++ /dev/null @@ -1,16 +0,0 @@ -import 'BoardItemObject.dart'; - -class BoardListObject{ - - String? title; - List? items; - - BoardListObject({this.title,this.items}){ - if(this.title == null){ - this.title = ""; - } - if(this.items == null){ - this.items = []; - } - } -} \ No newline at end of file diff --git a/example/board_item_object.dart b/example/board_item_object.dart new file mode 100644 index 0000000..e335ec8 --- /dev/null +++ b/example/board_item_object.dart @@ -0,0 +1,5 @@ +class BoardItemObject { + String? title; + + BoardItemObject({this.title = ''}); +} diff --git a/example/board_list_object.dart b/example/board_list_object.dart new file mode 100644 index 0000000..34dabdc --- /dev/null +++ b/example/board_list_object.dart @@ -0,0 +1,8 @@ +import 'board_item_object.dart'; + +class BoardListObject { + String? title; + List? items; + + BoardListObject({this.title = '', this.items = const []}); +} diff --git a/example/example.dart b/example/example.dart index a31211d..c616282 100644 --- a/example/example.dart +++ b/example/example.dart @@ -1,11 +1,11 @@ import 'package:boardview/board_item.dart'; import 'package:boardview/board_list.dart'; -import 'package:boardview/boardview_controller.dart'; +import 'package:boardview/board_view_controller.dart'; import 'package:flutter/material.dart'; -import 'package:boardview/boardview.dart'; +import 'package:boardview/board_view.dart'; -import 'BoardItemObject.dart'; -import 'BoardListObject.dart'; +import 'board_item_object.dart'; +import 'board_list_object.dart'; class BoardViewExample extends StatelessWidget { final List _listData = [ @@ -14,9 +14,10 @@ class BoardViewExample extends StatelessWidget { BoardListObject(title: "List title 3") ]; - //Can be used to animate to different sections of the BoardView - final BoardViewController boardViewController = new BoardViewController(); + final BoardViewController boardViewController = BoardViewController(); + + BoardViewExample({Key? key}) : super(key: key); @override Widget build(BuildContext context) { @@ -32,19 +33,17 @@ class BoardViewExample extends StatelessWidget { Widget buildBoardItem(BoardItemObject itemObject) { return BoardItem( - onStartDragItem: (int? listIndex, int? itemIndex, BoardItemState? state) { - - }, + onStartDragItem: + (int? listIndex, int? itemIndex, BoardItemState? state) {}, onDropItem: (int? listIndex, int? itemIndex, int? oldListIndex, int? oldItemIndex, BoardItemState? state) { //Used to update our local item data var item = _listData[oldListIndex!].items![oldItemIndex!]; - _listData[oldListIndex].items!.removeAt(oldItemIndex!); + _listData[oldListIndex].items!.removeAt(oldItemIndex); _listData[listIndex!].items!.insert(itemIndex!, item); }, - onTapItem: (int? listIndex, int? itemIndex, BoardItemState? state) async { - - }, + onTapItem: + (int? listIndex, int? itemIndex, BoardItemState? state) async {}, item: Card( child: Padding( padding: const EdgeInsets.all(8.0), @@ -60,27 +59,23 @@ class BoardViewExample extends StatelessWidget { } return BoardList( - onStartDragList: (int? listIndex) { - - }, - onTapList: (int? listIndex) async { - - }, + onStartDragList: (int? listIndex) {}, + onTapList: (int? listIndex) async {}, onDropList: (int? listIndex, int? oldListIndex) { //Update our local list data var list = _listData[oldListIndex!]; - _listData.removeAt(oldListIndex!); + _listData.removeAt(oldListIndex); _listData.insert(listIndex!, list); }, - headerBackgroundColor: Color.fromARGB(255, 235, 236, 240), - backgroundColor: Color.fromARGB(255, 235, 236, 240), + headerBackgroundColor: const Color.fromARGB(255, 235, 236, 240), + backgroundColor: const Color.fromARGB(255, 235, 236, 240), header: [ Expanded( child: Padding( - padding: EdgeInsets.all(5), + padding: const EdgeInsets.all(5), child: Text( list.title!, - style: TextStyle(fontSize: 20), + style: const TextStyle(fontSize: 20), ))), ], items: items, diff --git a/lib/board_item.dart b/lib/board_item.dart index 0822211..bae0802 100644 --- a/lib/board_item.dart +++ b/lib/board_item.dart @@ -2,12 +2,14 @@ import 'package:boardview/board_list.dart'; import 'package:flutter/material.dart'; import 'package:flutter/widgets.dart'; -typedef void OnDropItem(int? listIndex, int? itemIndex,int? oldListIndex,int? oldItemIndex, BoardItemState state); -typedef void OnTapItem(int? listIndex, int? itemIndex, BoardItemState state); -typedef void OnStartDragItem( +typedef OnDropItem = void Function(int? listIndex, int? itemIndex, + int? oldListIndex, int? oldItemIndex, BoardItemState state); +typedef OnTapItem = void Function( int? listIndex, int? itemIndex, BoardItemState state); -typedef void OnDragItem(int oldListIndex, int oldItemIndex, int newListIndex, - int newItemIndex, BoardItemState state); +typedef OnStartDragItem = void Function( + int? listIndex, int? itemIndex, BoardItemState state); +typedef OnDragItem = void Function(int oldListIndex, int oldItemIndex, + int newListIndex, int newItemIndex, BoardItemState state); class BoardItem extends StatefulWidget { final BoardListState? boardList; @@ -21,14 +23,14 @@ class BoardItem extends StatefulWidget { const BoardItem( {Key? key, - this.boardList, - this.item, - this.index, - this.onDropItem, - this.onTapItem, - this.onStartDragItem, - this.draggable = true, - this.onDragItem}) + this.boardList, + this.item, + this.index, + this.onDropItem, + this.onTapItem, + this.onStartDragItem, + this.draggable = true, + this.onDragItem}) : super(key: key); @override @@ -37,7 +39,8 @@ class BoardItem extends StatefulWidget { } } -class BoardItemState extends State with AutomaticKeepAliveClientMixin{ +class BoardItemState extends State + with AutomaticKeepAliveClientMixin { late double height; double? width; @@ -46,20 +49,25 @@ class BoardItemState extends State with AutomaticKeepAliveClientMixin void onDropItem(int? listIndex, int? itemIndex) { if (widget.onDropItem != null) { - widget.onDropItem!(listIndex, itemIndex,widget.boardList!.widget.boardView!.startListIndex,widget.boardList!.widget.boardView!.startItemIndex, this); + widget.onDropItem!( + listIndex, + itemIndex, + widget.boardList!.widget.boardView!.startListIndex, + widget.boardList!.widget.boardView!.startItemIndex, + this); } widget.boardList!.widget.boardView!.draggedItemIndex = null; widget.boardList!.widget.boardView!.draggedListIndex = null; - if(widget.boardList!.widget.boardView!.listStates[listIndex!].mounted) { - widget.boardList!.widget.boardView!.listStates[listIndex].setState(() { }); + if (widget.boardList!.widget.boardView!.listStates[listIndex!].mounted) { + widget.boardList!.widget.boardView!.listStates[listIndex].setState(() {}); } } void _startDrag(Widget item, BuildContext context) { if (widget.boardList!.widget.boardView != null) { widget.boardList!.widget.boardView!.onDropItem = onDropItem; - if(widget.boardList!.mounted) { - widget.boardList!.setState(() { }); + if (widget.boardList!.mounted) { + widget.boardList!.setState(() {}); } widget.boardList!.widget.boardView!.draggedItemIndex = widget.index; widget.boardList!.widget.boardView!.height = context.size!.height; @@ -74,17 +82,17 @@ class BoardItemState extends State with AutomaticKeepAliveClientMixin widget.boardList!.widget.index, widget.index, this); } widget.boardList!.widget.boardView!.run(); - if(widget.boardList!.widget.boardView!.mounted) { - widget.boardList!.widget.boardView!.setState(() { }); + if (widget.boardList!.widget.boardView!.mounted) { + widget.boardList!.widget.boardView!.setState(() {}); } } } void afterFirstLayout(BuildContext context) { - try { + if (context.size != null) { height = context.size!.height; width = context.size!.width; - }catch(e){} + } } @override @@ -98,10 +106,11 @@ class BoardItemState extends State with AutomaticKeepAliveClientMixin widget.boardList!.itemStates.insert(widget.index!, this); return GestureDetector( onTapDown: (otd) { - if(widget.draggable) { + if (widget.draggable) { RenderBox object = context.findRenderObject() as RenderBox; Offset pos = object.localToGlobal(Offset.zero); - RenderBox box = widget.boardList!.context.findRenderObject() as RenderBox; + RenderBox box = + widget.boardList!.context.findRenderObject() as RenderBox; Offset listPos = box.localToGlobal(Offset.zero); widget.boardList!.widget.boardView!.leftListX = listPos.dx; widget.boardList!.widget.boardView!.topListY = listPos.dy; @@ -124,7 +133,8 @@ class BoardItemState extends State with AutomaticKeepAliveClientMixin } }, onLongPress: () { - if(!widget.boardList!.widget.boardView!.widget.isSelecting && widget.draggable) { + if (!widget.boardList!.widget.boardView!.widget.isSelecting && + widget.draggable) { _startDrag(widget, context); } }, diff --git a/lib/board_list.dart b/lib/board_list.dart index fd5cdeb..27b6201 100644 --- a/lib/board_list.dart +++ b/lib/board_list.dart @@ -1,11 +1,11 @@ import 'package:boardview/board_item.dart'; -import 'package:boardview/boardview.dart'; +import 'package:boardview/board_view.dart'; import 'package:flutter/material.dart'; import 'package:flutter/widgets.dart'; -typedef void OnDropList(int? listIndex,int? oldListIndex); -typedef void OnTapList(int? listIndex); -typedef void OnStartDragList(int? listIndex); +typedef OnDropList = void Function(int? listIndex, int? oldListIndex); +typedef OnTapList = void Function(int? listIndex); +typedef OnStartDragList = void Function(int? listIndex); class BoardList extends StatefulWidget { final List? header; @@ -28,7 +28,10 @@ class BoardList extends StatefulWidget { this.headerBackgroundColor, this.boardView, this.draggable = true, - this.index, this.onDropList, this.onTapList, this.onStartDragList, + this.index, + this.onDropList, + this.onTapList, + this.onStartDragList, }) : super(key: key); final int? index; @@ -39,25 +42,24 @@ class BoardList extends StatefulWidget { } } -class BoardListState extends State with AutomaticKeepAliveClientMixin{ +class BoardListState extends State + with AutomaticKeepAliveClientMixin { List itemStates = []; - ScrollController boardListController = new ScrollController(); + ScrollController boardListController = ScrollController(); void onDropList(int? listIndex) { - if(widget.onDropList != null){ - widget.onDropList!(listIndex,widget.boardView!.startListIndex); + if (widget.onDropList != null) { + widget.onDropList!(listIndex, widget.boardView!.startListIndex); } widget.boardView!.draggedListIndex = null; - if(widget.boardView!.mounted) { - widget.boardView!.setState(() { - - }); + if (widget.boardView!.mounted) { + widget.boardView!.setState(() {}); } } void _startDrag(Widget item, BuildContext context) { if (widget.boardView != null && widget.draggable) { - if(widget.onStartDragList != null){ + if (widget.onStartDragList != null) { widget.onStartDragList!(widget.index); } widget.boardView!.startListIndex = widget.index; @@ -67,7 +69,7 @@ class BoardListState extends State with AutomaticKeepAliveClientMixin widget.boardView!.draggedItem = item; widget.boardView!.onDropList = onDropList; widget.boardView!.run(); - if(widget.boardView!.mounted) { + if (widget.boardView!.mounted) { widget.boardView!.setState(() {}); } } @@ -82,13 +84,13 @@ class BoardListState extends State with AutomaticKeepAliveClientMixin List listWidgets = []; if (widget.header != null) { listWidgets.add(GestureDetector( - onTap: (){ - if(widget.onTapList != null){ + onTap: () { + if (widget.onTapList != null) { widget.onTapList!(widget.index); } }, onTapDown: (otd) { - if(widget.draggable) { + if (widget.draggable) { RenderBox object = context.findRenderObject() as RenderBox; Offset pos = object.localToGlobal(Offset.zero); widget.boardView!.initialX = pos.dx; @@ -100,7 +102,7 @@ class BoardListState extends State with AutomaticKeepAliveClientMixin }, onTapCancel: () {}, onLongPress: () { - if(!widget.boardView!.widget.isSelecting && widget.draggable) { + if (!widget.boardView!.widget.isSelecting && widget.draggable) { _startDrag(widget, context); } }, @@ -112,51 +114,50 @@ class BoardListState extends State with AutomaticKeepAliveClientMixin mainAxisAlignment: MainAxisAlignment.center, children: widget.header!), ))); - } if (widget.items != null) { - listWidgets.add(Container( - child: Flexible( - fit: FlexFit.loose, - child: new ListView.builder( - shrinkWrap: true, - physics: ClampingScrollPhysics(), - controller: boardListController, - itemCount: widget.items!.length, - itemBuilder: (ctx, index) { - if (widget.items![index].boardList == null || - widget.items![index].index != index || - widget.items![index].boardList!.widget.index != widget.index || - widget.items![index].boardList != this) { - widget.items![index] = new BoardItem( - boardList: this, - item: widget.items![index].item, - draggable: widget.items![index].draggable, - index: index, - onDropItem: widget.items![index].onDropItem, - onTapItem: widget.items![index].onTapItem, - onDragItem: widget.items![index].onDragItem, - onStartDragItem: widget.items![index].onStartDragItem, - ); - } - if (widget.boardView!.draggedItemIndex == index && - widget.boardView!.draggedListIndex == widget.index) { - return Opacity( - opacity: 0.0, - child: widget.items![index], - ); - } else { - return widget.items![index]; - } - }, - )))); + listWidgets.add(Flexible( + fit: FlexFit.loose, + child: ListView.builder( + shrinkWrap: true, + physics: const ClampingScrollPhysics(), + controller: boardListController, + itemCount: widget.items!.length, + itemBuilder: (ctx, index) { + if (widget.items![index].boardList == null || + widget.items![index].index != index || + widget.items![index].boardList!.widget.index != + widget.index || + widget.items![index].boardList != this) { + widget.items![index] = BoardItem( + boardList: this, + item: widget.items![index].item, + draggable: widget.items![index].draggable, + index: index, + onDropItem: widget.items![index].onDropItem, + onTapItem: widget.items![index].onTapItem, + onDragItem: widget.items![index].onDragItem, + onStartDragItem: widget.items![index].onStartDragItem, + ); + } + if (widget.boardView!.draggedItemIndex == index && + widget.boardView!.draggedListIndex == widget.index) { + return Opacity( + opacity: 0.0, + child: widget.items![index], + ); + } else { + return widget.items![index]; + } + }, + ))); } if (widget.footer != null) { listWidgets.add(widget.footer!); } - Color? backgroundColor = Color.fromARGB(255, 255, 255, 255); + Color? backgroundColor = const Color.fromARGB(255, 255, 255, 255); if (widget.backgroundColor != null) { backgroundColor = widget.backgroundColor; @@ -167,12 +168,12 @@ class BoardListState extends State with AutomaticKeepAliveClientMixin widget.boardView!.listStates.insert(widget.index!, this); return Container( - margin: EdgeInsets.all(8), + margin: const EdgeInsets.all(8), decoration: BoxDecoration(color: backgroundColor), child: Column( mainAxisSize: MainAxisSize.min, mainAxisAlignment: MainAxisAlignment.start, - children: listWidgets as List, + children: listWidgets, )); } } diff --git a/lib/boardview.dart b/lib/board_view.dart similarity index 51% rename from lib/boardview.dart rename to lib/board_view.dart index 49a443c..2e9ff8f 100644 --- a/lib/boardview.dart +++ b/lib/board_view.dart @@ -1,8 +1,6 @@ library boardview; -import 'dart:math'; - -import 'package:boardview/boardview_controller.dart'; +import 'package:boardview/board_view_controller.dart'; import 'package:flutter/material.dart'; import 'package:flutter/widgets.dart'; import 'dart:core'; @@ -22,7 +20,7 @@ class BoardView extends StatefulWidget { final Function(bool)? itemInMiddleWidget; final OnDropBottomWidget? onDropItemInMiddleWidget; - BoardView({ + const BoardView({ Key? key, this.itemInMiddleWidget, this.scrollbar, @@ -43,11 +41,13 @@ class BoardView extends StatefulWidget { } } -typedef void OnDropBottomWidget(int? listIndex, int? itemIndex,double percentX); -typedef void OnDropItem(int? listIndex, int? itemIndex); -typedef void OnDropList(int? listIndex); +typedef OnDropBottomWidget = void Function( + int? listIndex, int? itemIndex, double percentX); +typedef OnDropItem = void Function(int? listIndex, int? itemIndex); +typedef OnDropList = void Function(int? listIndex); -class BoardViewState extends State with AutomaticKeepAliveClientMixin { +class BoardViewState extends State + with AutomaticKeepAliveClientMixin { Widget? draggedItem; int? draggedItemIndex; int? draggedListIndex; @@ -71,7 +71,7 @@ class BoardViewState extends State with AutomaticKeepAliveClientMixin bool canDrag = true; - ScrollController boardViewController = new ScrollController(); + ScrollController boardViewController = ScrollController(); List listStates = []; @@ -82,9 +82,9 @@ class BoardViewState extends State with AutomaticKeepAliveClientMixin bool _isInWidget = false; - GlobalKey _middleWidgetKey = GlobalKey(); + final GlobalKey _middleWidgetKey = GlobalKey(); - var pointer; + PointerDownEvent? pointer; @override bool get wantKeepAlive => true; @@ -92,49 +92,65 @@ class BoardViewState extends State with AutomaticKeepAliveClientMixin @override void initState() { super.initState(); - if(widget.boardViewController != null){ + if (widget.boardViewController != null) { widget.boardViewController!.state = this; } } void moveDown() { - if(topItemY != null){ - topItemY = topItemY! + listStates[draggedListIndex!].itemStates[draggedItemIndex! + 1].height; - } - if(bottomItemY != null){ - bottomItemY = bottomItemY! + listStates[draggedListIndex!].itemStates[draggedItemIndex! + 1].height; + if (topItemY != null) { + topItemY = topItemY! + + listStates[draggedListIndex!] + .itemStates[draggedItemIndex! + 1] + .height; + } + if (bottomItemY != null) { + bottomItemY = bottomItemY! + + listStates[draggedListIndex!] + .itemStates[draggedItemIndex! + 1] + .height; } var item = widget.lists![draggedListIndex!].items![draggedItemIndex!]; widget.lists![draggedListIndex!].items!.removeAt(draggedItemIndex!); var itemState = listStates[draggedListIndex!].itemStates[draggedItemIndex!]; listStates[draggedListIndex!].itemStates.removeAt(draggedItemIndex!); - if(draggedItemIndex != null){ + if (draggedItemIndex != null) { draggedItemIndex = draggedItemIndex! + 1; } widget.lists![draggedListIndex!].items!.insert(draggedItemIndex!, item); - listStates[draggedListIndex!].itemStates.insert(draggedItemIndex!, itemState); - if(listStates[draggedListIndex!].mounted) { + listStates[draggedListIndex!] + .itemStates + .insert(draggedItemIndex!, itemState); + if (listStates[draggedListIndex!].mounted) { listStates[draggedListIndex!].setState(() {}); } } void moveUp() { - if(topItemY != null){ - topItemY = topItemY! - listStates[draggedListIndex!].itemStates[draggedItemIndex! - 1].height; - } - if(bottomItemY != null){ - bottomItemY = bottomItemY!-listStates[draggedListIndex!].itemStates[draggedItemIndex! - 1].height; + if (topItemY != null) { + topItemY = topItemY! - + listStates[draggedListIndex!] + .itemStates[draggedItemIndex! - 1] + .height; + } + if (bottomItemY != null) { + bottomItemY = bottomItemY! - + listStates[draggedListIndex!] + .itemStates[draggedItemIndex! - 1] + .height; } var item = widget.lists![draggedListIndex!].items![draggedItemIndex!]; widget.lists![draggedListIndex!].items!.removeAt(draggedItemIndex!); var itemState = listStates[draggedListIndex!].itemStates[draggedItemIndex!]; listStates[draggedListIndex!].itemStates.removeAt(draggedItemIndex!); - if(draggedItemIndex != null){ + if (draggedItemIndex != null) { draggedItemIndex = draggedItemIndex! - 1; } widget.lists![draggedListIndex!].items!.insert(draggedItemIndex!, item); - listStates[draggedListIndex!].itemStates.insert(draggedItemIndex!, itemState); - if(listStates[draggedListIndex!].mounted) { + listStates[draggedListIndex!] + .itemStates + .insert(draggedItemIndex!, itemState); + if (listStates[draggedListIndex!].mounted) { listStates[draggedListIndex!].setState(() {}); } } @@ -144,27 +160,29 @@ class BoardViewState extends State with AutomaticKeepAliveClientMixin var listState = listStates[draggedListIndex!]; widget.lists!.removeAt(draggedListIndex!); listStates.removeAt(draggedListIndex!); - if(draggedListIndex != null){ + if (draggedListIndex != null) { draggedListIndex = draggedListIndex! + 1; } widget.lists!.insert(draggedListIndex!, list); listStates.insert(draggedListIndex!, listState); canDrag = false; - if (boardViewController != null && boardViewController.hasClients) { + if (boardViewController.hasClients) { int? tempListIndex = draggedListIndex; boardViewController - .animateTo(draggedListIndex! * widget.width, duration: new Duration(milliseconds: 400), curve: Curves.ease) + .animateTo(draggedListIndex! * widget.width, + duration: const Duration(milliseconds: 400), curve: Curves.ease) .whenComplete(() { - RenderBox object = listStates[tempListIndex!].context.findRenderObject() as RenderBox; + RenderBox object = + listStates[tempListIndex!].context.findRenderObject() as RenderBox; Offset pos = object.localToGlobal(Offset.zero); leftListX = pos.dx; rightListX = pos.dx + object.size.width; - Future.delayed(new Duration(milliseconds: widget.dragDelay), () { + Future.delayed(Duration(milliseconds: widget.dragDelay), () { canDrag = true; }); }); } - if(mounted){ + if (mounted) { setState(() {}); } } @@ -174,17 +192,20 @@ class BoardViewState extends State with AutomaticKeepAliveClientMixin var itemState = listStates[draggedListIndex!].itemStates[draggedItemIndex!]; widget.lists![draggedListIndex!].items!.removeAt(draggedItemIndex!); listStates[draggedListIndex!].itemStates.removeAt(draggedItemIndex!); - if(listStates[draggedListIndex!].mounted) { + if (listStates[draggedListIndex!].mounted) { listStates[draggedListIndex!].setState(() {}); } - if(draggedListIndex != null){ + if (draggedListIndex != null) { draggedListIndex = draggedListIndex! + 1; } double closestValue = 10000; draggedItemIndex = 0; for (int i = 0; i < listStates[draggedListIndex!].itemStates.length; i++) { - if (listStates[draggedListIndex!].itemStates[i].mounted && listStates[draggedListIndex!].itemStates[i].context != null) { - RenderBox box = listStates[draggedListIndex!].itemStates[i].context.findRenderObject() as RenderBox; + if (listStates[draggedListIndex!].itemStates[i].mounted) { + RenderBox box = listStates[draggedListIndex!] + .itemStates[i] + .context + .findRenderObject() as RenderBox; Offset pos = box.localToGlobal(Offset.zero); var temp = (pos.dy - dy! + (box.size.height / 2)).abs(); if (temp < closestValue) { @@ -195,32 +216,39 @@ class BoardViewState extends State with AutomaticKeepAliveClientMixin } } widget.lists![draggedListIndex!].items!.insert(draggedItemIndex!, item); - listStates[draggedListIndex!].itemStates.insert(draggedItemIndex!, itemState); + listStates[draggedListIndex!] + .itemStates + .insert(draggedItemIndex!, itemState); canDrag = false; - if(listStates[draggedListIndex!].mounted) { + if (listStates[draggedListIndex!].mounted) { listStates[draggedListIndex!].setState(() {}); } - if (boardViewController != null && boardViewController.hasClients) { + if (boardViewController.hasClients) { int? tempListIndex = draggedListIndex; int? tempItemIndex = draggedItemIndex; boardViewController - .animateTo(draggedListIndex! * widget.width, duration: new Duration(milliseconds: 400), curve: Curves.ease) + .animateTo(draggedListIndex! * widget.width, + duration: const Duration(milliseconds: 400), curve: Curves.ease) .whenComplete(() { - RenderBox object = listStates[tempListIndex!].context.findRenderObject() as RenderBox; + RenderBox object = + listStates[tempListIndex!].context.findRenderObject() as RenderBox; Offset pos = object.localToGlobal(Offset.zero); leftListX = pos.dx; rightListX = pos.dx + object.size.width; - RenderBox box = listStates[tempListIndex].itemStates[tempItemIndex!].context.findRenderObject() as RenderBox; + RenderBox box = listStates[tempListIndex] + .itemStates[tempItemIndex!] + .context + .findRenderObject() as RenderBox; Offset itemPos = box.localToGlobal(Offset.zero); topItemY = itemPos.dy; bottomItemY = itemPos.dy + box.size.height; - Future.delayed(new Duration(milliseconds: widget.dragDelay), () { + Future.delayed(Duration(milliseconds: widget.dragDelay), () { canDrag = true; }); }); } - if(mounted){ - setState(() { }); + if (mounted) { + setState(() {}); } } @@ -229,27 +257,30 @@ class BoardViewState extends State with AutomaticKeepAliveClientMixin var listState = listStates[draggedListIndex!]; widget.lists!.removeAt(draggedListIndex!); listStates.removeAt(draggedListIndex!); - if(draggedListIndex != null){ + if (draggedListIndex != null) { draggedListIndex = draggedListIndex! - 1; } widget.lists!.insert(draggedListIndex!, list); listStates.insert(draggedListIndex!, listState); canDrag = false; - if (boardViewController != null && boardViewController.hasClients) { + if (boardViewController.hasClients) { int? tempListIndex = draggedListIndex; boardViewController - .animateTo(draggedListIndex! * widget.width, duration: new Duration(milliseconds: widget.dragDelay), curve: Curves.ease) + .animateTo(draggedListIndex! * widget.width, + duration: Duration(milliseconds: widget.dragDelay), + curve: Curves.ease) .whenComplete(() { - RenderBox object = listStates[tempListIndex!].context.findRenderObject() as RenderBox; + RenderBox object = + listStates[tempListIndex!].context.findRenderObject() as RenderBox; Offset pos = object.localToGlobal(Offset.zero); leftListX = pos.dx; rightListX = pos.dx + object.size.width; - Future.delayed(new Duration(milliseconds: widget.dragDelay), () { + Future.delayed(Duration(milliseconds: widget.dragDelay), () { canDrag = true; }); }); } - if(mounted) { + if (mounted) { setState(() {}); } } @@ -259,17 +290,20 @@ class BoardViewState extends State with AutomaticKeepAliveClientMixin var itemState = listStates[draggedListIndex!].itemStates[draggedItemIndex!]; widget.lists![draggedListIndex!].items!.removeAt(draggedItemIndex!); listStates[draggedListIndex!].itemStates.removeAt(draggedItemIndex!); - if(listStates[draggedListIndex!].mounted) { + if (listStates[draggedListIndex!].mounted) { listStates[draggedListIndex!].setState(() {}); } - if(draggedListIndex != null){ + if (draggedListIndex != null) { draggedListIndex = draggedListIndex! - 1; } double closestValue = 10000; draggedItemIndex = 0; for (int i = 0; i < listStates[draggedListIndex!].itemStates.length; i++) { - if (listStates[draggedListIndex!].itemStates[i].mounted && listStates[draggedListIndex!].itemStates[i].context != null) { - RenderBox box = listStates[draggedListIndex!].itemStates[i].context.findRenderObject() as RenderBox; + if (listStates[draggedListIndex!].itemStates[i].mounted) { + RenderBox box = listStates[draggedListIndex!] + .itemStates[i] + .context + .findRenderObject() as RenderBox; Offset pos = box.localToGlobal(Offset.zero); var temp = (pos.dy - dy! + (box.size.height / 2)).abs(); if (temp < closestValue) { @@ -280,31 +314,38 @@ class BoardViewState extends State with AutomaticKeepAliveClientMixin } } widget.lists![draggedListIndex!].items!.insert(draggedItemIndex!, item); - listStates[draggedListIndex!].itemStates.insert(draggedItemIndex!, itemState); + listStates[draggedListIndex!] + .itemStates + .insert(draggedItemIndex!, itemState); canDrag = false; - if(listStates[draggedListIndex!].mounted) { + if (listStates[draggedListIndex!].mounted) { listStates[draggedListIndex!].setState(() {}); } - if (boardViewController != null && boardViewController.hasClients) { + if (boardViewController.hasClients) { int? tempListIndex = draggedListIndex; int? tempItemIndex = draggedItemIndex; boardViewController - .animateTo(draggedListIndex! * widget.width, duration: new Duration(milliseconds: 400), curve: Curves.ease) + .animateTo(draggedListIndex! * widget.width, + duration: const Duration(milliseconds: 400), curve: Curves.ease) .whenComplete(() { - RenderBox object = listStates[tempListIndex!].context.findRenderObject() as RenderBox; + RenderBox object = + listStates[tempListIndex!].context.findRenderObject() as RenderBox; Offset pos = object.localToGlobal(Offset.zero); leftListX = pos.dx; rightListX = pos.dx + object.size.width; - RenderBox box = listStates[tempListIndex].itemStates[tempItemIndex!].context.findRenderObject() as RenderBox; + RenderBox box = listStates[tempListIndex] + .itemStates[tempItemIndex!] + .context + .findRenderObject() as RenderBox; Offset itemPos = box.localToGlobal(Offset.zero); topItemY = itemPos.dy; bottomItemY = itemPos.dy + box.size.height; - Future.delayed(new Duration(milliseconds: widget.dragDelay), () { + Future.delayed(Duration(milliseconds: widget.dragDelay), () { canDrag = true; }); }); } - if(mounted) { + if (mounted) { setState(() {}); } } @@ -313,16 +354,15 @@ class BoardViewState extends State with AutomaticKeepAliveClientMixin @override Widget build(BuildContext context) { - print("dy:${dy}"); - print("topListY:${topListY}"); - print("bottomListY:${bottomListY}"); - if(boardViewController.hasClients) { + super.build(context); + debugPrint("dy:$dy"); + debugPrint("topListY:$topListY"); + debugPrint("bottomListY:$bottomListY"); + if (boardViewController.hasClients) { WidgetsBinding.instance!.addPostFrameCallback((Duration duration) { - try { - boardViewController.position.didUpdateScrollPositionBy(0); - }catch(e){} - bool _shown = boardViewController.position.maxScrollExtent!=0; - if(_shown != shown){ + boardViewController.position.didUpdateScrollPositionBy(0); + bool _shown = boardViewController.position.maxScrollExtent != 0; + if (_shown != shown) { setState(() { shown = _shown; }); @@ -330,7 +370,7 @@ class BoardViewState extends State with AutomaticKeepAliveClientMixin }); } Widget listWidget = ListView.builder( - physics: ClampingScrollPhysics(), + physics: const ClampingScrollPhysics(), itemCount: widget.lists!.length, scrollDirection: Axis.horizontal, controller: boardViewController, @@ -383,31 +423,32 @@ class BoardViewState extends State with AutomaticKeepAliveClientMixin } }, ); - if(widget.scrollbar == true){ + if (widget.scrollbar == true) { listWidget = VsScrollbar( controller: boardViewController, - showTrackOnHover: true,// default false - isAlwaysShown: shown&&widget.lists!.length>1, // default false - scrollbarFadeDuration: Duration(milliseconds: 500), // default : Duration(milliseconds: 300) - scrollbarTimeToFade: Duration(milliseconds: 800),// default : Duration(milliseconds: 600) - style: widget.scrollbarStyle!=null?VsScrollbarStyle( - hoverThickness: widget.scrollbarStyle!.hoverThickness, - radius: widget.scrollbarStyle!.radius, - thickness: widget.scrollbarStyle!.thickness, - color: widget.scrollbarStyle!.color - ):VsScrollbarStyle(), - child:listWidget); - } - List stackWidgets = [ - listWidget - ]; + showTrackOnHover: true, // default false + isAlwaysShown: shown && widget.lists!.length > 1, // default false + scrollbarFadeDuration: const Duration( + milliseconds: 500), // default : Duration(milliseconds: 300) + scrollbarTimeToFade: const Duration( + milliseconds: 800), // default : Duration(milliseconds: 600) + style: widget.scrollbarStyle != null + ? VsScrollbarStyle( + hoverThickness: widget.scrollbarStyle!.hoverThickness, + radius: widget.scrollbarStyle!.radius, + thickness: widget.scrollbarStyle!.thickness, + color: widget.scrollbarStyle!.color) + : const VsScrollbarStyle(), + child: listWidget); + } + List stackWidgets = [listWidget]; bool isInBottomWidget = false; if (dy != null) { if (MediaQuery.of(context).size.height - dy! < 80) { isInBottomWidget = true; } } - if(widget.itemInMiddleWidget != null && _isInWidget != isInBottomWidget) { + if (widget.itemInMiddleWidget != null && _isInWidget != isInBottomWidget) { widget.itemInMiddleWidget!(isInBottomWidget); _isInWidget = isInBottomWidget; } @@ -417,18 +458,23 @@ class BoardViewState extends State with AutomaticKeepAliveClientMixin offsetY != null && dx != null && dy != null && - height != null && - widget.width != null) { + height != null) { if (canDrag && dxInit != null && dyInit != null && !isInBottomWidget) { - if (draggedItemIndex != null && draggedItem != null && topItemY != null && bottomItemY != null) { + if (draggedItemIndex != null && + draggedItem != null && + topItemY != null && + bottomItemY != null) { //dragging item if (0 <= draggedListIndex! - 1 && dx! < leftListX! + 45) { //scroll left - if (boardViewController != null && boardViewController.hasClients) { - boardViewController.animateTo(boardViewController.position.pixels - 5, - duration: new Duration(milliseconds: 10), curve: Curves.ease); - if(listStates[draggedListIndex!].mounted) { - RenderBox object = listStates[draggedListIndex!].context + if (boardViewController.hasClients) { + boardViewController.animateTo( + boardViewController.position.pixels - 5, + duration: const Duration(milliseconds: 10), + curve: Curves.ease); + if (listStates[draggedListIndex!].mounted) { + RenderBox object = listStates[draggedListIndex!] + .context .findRenderObject() as RenderBox; Offset pos = object.localToGlobal(Offset.zero); leftListX = pos.dx; @@ -436,13 +482,17 @@ class BoardViewState extends State with AutomaticKeepAliveClientMixin } } } - if (widget.lists!.length > draggedListIndex! + 1 && dx! > rightListX! - 45) { + if (widget.lists!.length > draggedListIndex! + 1 && + dx! > rightListX! - 45) { //scroll right - if (boardViewController != null && boardViewController.hasClients) { - boardViewController.animateTo(boardViewController.position.pixels + 5, - duration: new Duration(milliseconds: 10), curve: Curves.ease); - if(listStates[draggedListIndex!].mounted) { - RenderBox object = listStates[draggedListIndex!].context + if (boardViewController.hasClients) { + boardViewController.animateTo( + boardViewController.position.pixels + 5, + duration: const Duration(milliseconds: 10), + curve: Curves.ease); + if (listStates[draggedListIndex!].mounted) { + RenderBox object = listStates[draggedListIndex!] + .context .findRenderObject() as RenderBox; Offset pos = object.localToGlobal(Offset.zero); leftListX = pos.dx; @@ -454,86 +504,120 @@ class BoardViewState extends State with AutomaticKeepAliveClientMixin //move left moveLeft(); } - if (widget.lists!.length > draggedListIndex! + 1 && dx! > rightListX!) { + if (widget.lists!.length > draggedListIndex! + 1 && + dx! > rightListX!) { //move right moveRight(); } if (dy! < topListY! + 70) { //scroll up - if (listStates[draggedListIndex!].boardListController != null && - listStates[draggedListIndex!].boardListController.hasClients && !isScrolling) { + if (listStates[draggedListIndex!].boardListController.hasClients && + !isScrolling) { isScrolling = true; - double pos = listStates[draggedListIndex!].boardListController.position.pixels; - listStates[draggedListIndex!].boardListController.animateTo( - listStates[draggedListIndex!].boardListController.position.pixels - 5, - duration: new Duration(milliseconds: 10), - curve: Curves.ease).whenComplete((){ - - pos -= listStates[draggedListIndex!].boardListController.position.pixels; - if(initialY == null) - initialY = 0; + double pos = listStates[draggedListIndex!] + .boardListController + .position + .pixels; + listStates[draggedListIndex!] + .boardListController + .animateTo( + listStates[draggedListIndex!] + .boardListController + .position + .pixels - + 5, + duration: const Duration(milliseconds: 10), + curve: Curves.ease) + .whenComplete(() { + pos -= listStates[draggedListIndex!] + .boardListController + .position + .pixels; + initialY ??= 0; // if(widget.boardViewController != null) { // initialY -= pos; // } isScrolling = false; - if(topItemY != null) { + if (topItemY != null) { topItemY = topItemY! + pos; } - if(bottomItemY != null) { + if (bottomItemY != null) { bottomItemY = bottomItemY! + pos; } - if(mounted){ - setState(() { }); + if (mounted) { + setState(() {}); } }); } } if (0 <= draggedItemIndex! - 1 && - dy! < topItemY! - listStates[draggedListIndex!].itemStates[draggedItemIndex! - 1].height / 2) { + dy! < + topItemY! - + listStates[draggedListIndex!] + .itemStates[draggedItemIndex! - 1] + .height / + 2) { //move up moveUp(); } double? tempBottom = bottomListY; - if(widget.middleWidget != null){ - if(_middleWidgetKey.currentContext != null) { + if (widget.middleWidget != null) { + if (_middleWidgetKey.currentContext != null) { RenderBox _box = _middleWidgetKey.currentContext! .findRenderObject() as RenderBox; tempBottom = _box.size.height; - print("tempBottom:${tempBottom}"); + debugPrint("tempBottom:$tempBottom"); } } if (dy! > tempBottom! - 70) { //scroll down - if (listStates[draggedListIndex!].boardListController != null && - listStates[draggedListIndex!].boardListController.hasClients) { + if (listStates[draggedListIndex!].boardListController.hasClients) { isScrolling = true; - double pos = listStates[draggedListIndex!].boardListController.position.pixels; - listStates[draggedListIndex!].boardListController.animateTo( - listStates[draggedListIndex!].boardListController.position.pixels + 5, - duration: new Duration(milliseconds: 10), - curve: Curves.ease).whenComplete((){ - pos -= listStates[draggedListIndex!].boardListController.position.pixels; - if(initialY == null) - initialY = 0; + double pos = listStates[draggedListIndex!] + .boardListController + .position + .pixels; + listStates[draggedListIndex!] + .boardListController + .animateTo( + listStates[draggedListIndex!] + .boardListController + .position + .pixels + + 5, + duration: const Duration(milliseconds: 10), + curve: Curves.ease) + .whenComplete(() { + pos -= listStates[draggedListIndex!] + .boardListController + .position + .pixels; + initialY ??= 0; // if(widget.boardViewController != null) { // initialY -= pos; // } isScrolling = false; - if(topItemY != null) { + if (topItemY != null) { topItemY = topItemY! + pos; } - if(bottomItemY != null) { + if (bottomItemY != null) { bottomItemY = bottomItemY! + pos; } - if(mounted){ + if (mounted) { setState(() {}); } }); } } - if (widget.lists![draggedListIndex!].items!.length > draggedItemIndex! + 1 && - dy! > bottomItemY! + listStates[draggedListIndex!].itemStates[draggedItemIndex! + 1].height / 2) { + if (widget.lists![draggedListIndex!].items!.length > + draggedItemIndex! + 1 && + dy! > + bottomItemY! + + listStates[draggedListIndex!] + .itemStates[draggedItemIndex! + 1] + .height / + 2) { //move down moveDown(); } @@ -541,32 +625,38 @@ class BoardViewState extends State with AutomaticKeepAliveClientMixin //dragging list if (0 <= draggedListIndex! - 1 && dx! < leftListX! + 45) { //scroll left - if (boardViewController != null && boardViewController.hasClients) { - boardViewController.animateTo(boardViewController.position.pixels - 5, - duration: new Duration(milliseconds: 10), curve: Curves.ease); - if(leftListX != null){ + if (boardViewController.hasClients) { + boardViewController.animateTo( + boardViewController.position.pixels - 5, + duration: const Duration(milliseconds: 10), + curve: Curves.ease); + if (leftListX != null) { leftListX = leftListX! + 5; } - if(rightListX != null){ + if (rightListX != null) { rightListX = rightListX! + 5; } } } - if (widget.lists!.length > draggedListIndex! + 1 && dx! > rightListX! - 45) { + if (widget.lists!.length > draggedListIndex! + 1 && + dx! > rightListX! - 45) { //scroll right - if (boardViewController != null && boardViewController.hasClients) { - boardViewController.animateTo(boardViewController.position.pixels + 5, - duration: new Duration(milliseconds: 10), curve: Curves.ease); - if(leftListX != null){ + if (boardViewController.hasClients) { + boardViewController.animateTo( + boardViewController.position.pixels + 5, + duration: const Duration(milliseconds: 10), + curve: Curves.ease); + if (leftListX != null) { leftListX = leftListX! - 5; } - if(rightListX != null){ + if (rightListX != null) { rightListX = rightListX! - 5; } } } - if (widget.lists!.length > draggedListIndex! + 1 && dx! > rightListX!) { + if (widget.lists!.length > draggedListIndex! + 1 && + dx! > rightListX!) { //move right moveListRight(); } @@ -577,10 +667,11 @@ class BoardViewState extends State with AutomaticKeepAliveClientMixin } } if (widget.middleWidget != null) { - stackWidgets.add(Container(key:_middleWidgetKey,child:widget.middleWidget)); + stackWidgets + .add(Container(key: _middleWidgetKey, child: widget.middleWidget)); } WidgetsBinding.instance!.addPostFrameCallback((timeStamp) { - if(mounted){ + if (mounted) { setState(() {}); } }); @@ -593,101 +684,104 @@ class BoardViewState extends State with AutomaticKeepAliveClientMixin )); } - return Container( - child: Listener( - onPointerMove: (opm) { - if (draggedItem != null) { - if (dxInit == null) { - dxInit = opm.position.dx; - } - if (dyInit == null) { - dyInit = opm.position.dy; - } - dx = opm.position.dx; - dy = opm.position.dy; - if(mounted) { - setState(() {}); - } - } - }, - onPointerDown: (opd) { - RenderBox box = context.findRenderObject() as RenderBox; - Offset pos = box.localToGlobal(opd.position); - offsetX = pos.dx; - offsetY = pos.dy; - pointer = opd; - if(mounted) { - setState(() {}); - } - }, - onPointerUp: (opu) { - if (onDropItem != null) { - int? tempDraggedItemIndex = draggedItemIndex; - int? tempDraggedListIndex = draggedListIndex; - int? startDraggedItemIndex = startItemIndex; - int? startDraggedListIndex = startListIndex; - - if(_isInWidget && widget.onDropItemInMiddleWidget != null){ - onDropItem!(startDraggedListIndex, startDraggedItemIndex); - widget.onDropItemInMiddleWidget!(startDraggedListIndex, startDraggedItemIndex,opu.position.dx/MediaQuery.of(context).size.width); - }else{ - onDropItem!(tempDraggedListIndex, tempDraggedItemIndex); - } - } - if (onDropList != null) { - int? tempDraggedListIndex = draggedListIndex; - if(_isInWidget && widget.onDropItemInMiddleWidget != null){ - onDropList!(tempDraggedListIndex); - widget.onDropItemInMiddleWidget!(tempDraggedListIndex,null,opu.position.dx/MediaQuery.of(context).size.width); - }else{ - onDropList!(tempDraggedListIndex); - } - } - draggedItem = null; - offsetX = null; - offsetY = null; - initialX = null; - initialY = null; - dx = null; - dy = null; - draggedItemIndex = null; - draggedListIndex = null; - onDropItem = null; - onDropList = null; - dxInit = null; - dyInit = null; - leftListX = null; - rightListX = null; - topListY = null; - bottomListY = null; - topItemY = null; - bottomItemY = null; - startListIndex = null; - startItemIndex = null; - if(mounted) { - setState(() {}); - } - }, - child: new Stack( - children: stackWidgets, - ))); + return Listener( + onPointerMove: (opm) { + if (draggedItem != null) { + dxInit ??= opm.position.dx; + dyInit ??= opm.position.dy; + dx = opm.position.dx; + dy = opm.position.dy; + if (mounted) { + setState(() {}); + } + } + }, + onPointerDown: (PointerDownEvent pointerEvent) { + RenderBox box = context.findRenderObject() as RenderBox; + Offset pos = box.localToGlobal(pointerEvent.position); + offsetX = pos.dx; + offsetY = pos.dy; + pointer = pointerEvent; + if (mounted) { + setState(() {}); + } + }, + onPointerUp: (opu) { + if (onDropItem != null) { + int? tempDraggedItemIndex = draggedItemIndex; + int? tempDraggedListIndex = draggedListIndex; + int? startDraggedItemIndex = startItemIndex; + int? startDraggedListIndex = startListIndex; + + if (_isInWidget && widget.onDropItemInMiddleWidget != null) { + onDropItem!(startDraggedListIndex, startDraggedItemIndex); + widget.onDropItemInMiddleWidget!( + startDraggedListIndex, + startDraggedItemIndex, + opu.position.dx / MediaQuery.of(context).size.width); + } else { + onDropItem!(tempDraggedListIndex, tempDraggedItemIndex); + } + } + if (onDropList != null) { + int? tempDraggedListIndex = draggedListIndex; + if (_isInWidget && widget.onDropItemInMiddleWidget != null) { + onDropList!(tempDraggedListIndex); + widget.onDropItemInMiddleWidget!(tempDraggedListIndex, null, + opu.position.dx / MediaQuery.of(context).size.width); + } else { + onDropList!(tempDraggedListIndex); + } + } + draggedItem = null; + offsetX = null; + offsetY = null; + initialX = null; + initialY = null; + dx = null; + dy = null; + draggedItemIndex = null; + draggedListIndex = null; + onDropItem = null; + onDropList = null; + dxInit = null; + dyInit = null; + leftListX = null; + rightListX = null; + topListY = null; + bottomListY = null; + topItemY = null; + bottomItemY = null; + startListIndex = null; + startItemIndex = null; + if (mounted) { + setState(() {}); + } + }, + child: Stack( + children: stackWidgets, + )); } void run() { if (pointer != null) { - dx = pointer.position.dx; - dy = pointer.position.dy; - if(mounted) { + dx = pointer!.position.dx; + dy = pointer!.position.dy; + if (mounted) { setState(() {}); } } } } -class ScrollbarStyle{ +class ScrollbarStyle { double hoverThickness; double thickness; Radius radius; Color color; - ScrollbarStyle({this.radius = const Radius.circular(10),this.hoverThickness = 10,this.thickness = 10,this.color = Colors.black}); + ScrollbarStyle( + {this.radius = const Radius.circular(10), + this.hoverThickness = 10, + this.thickness = 10, + this.color = Colors.black}); } diff --git a/lib/board_view_controller.dart b/lib/board_view_controller.dart new file mode 100644 index 0000000..b12f65d --- /dev/null +++ b/lib/board_view_controller.dart @@ -0,0 +1,17 @@ +import 'package:flutter/animation.dart'; + +import 'board_view.dart'; + +class BoardViewController { + BoardViewController(); + + late BoardViewState state; + + Future animateTo(int index, {Duration? duration, Curve? curve}) async { + double offset = index * state.widget.width; + if (state.boardViewController.hasClients) { + await state.boardViewController + .animateTo(offset, duration: duration!, curve: curve!); + } + } +} diff --git a/lib/boardview_controller.dart b/lib/boardview_controller.dart deleted file mode 100644 index 0123e13..0000000 --- a/lib/boardview_controller.dart +++ /dev/null @@ -1,18 +0,0 @@ -import 'package:flutter/animation.dart'; - -import 'boardview.dart'; - -class BoardViewController{ - - BoardViewController(); - - late BoardViewState state; - - Future animateTo(int index,{Duration? duration,Curve? curve})async{ - double offset = index * state.widget.width; - if (state.boardViewController != null && state.boardViewController.hasClients) { - await state.boardViewController.animateTo( - offset, duration: duration!, curve: curve!); - } - } -} \ No newline at end of file diff --git a/pubspec.lock b/pubspec.lock index 69b2334..5d2ff95 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -7,7 +7,7 @@ packages: name: async url: "https://pub.dartlang.org" source: hosted - version: "2.5.0" + version: "2.8.1" boolean_selector: dependency: transitive description: @@ -28,7 +28,7 @@ packages: name: charcode url: "https://pub.dartlang.org" source: hosted - version: "1.2.0" + version: "1.3.1" clock: dependency: transitive description: @@ -55,11 +55,25 @@ packages: description: flutter source: sdk version: "0.0.0" + flutter_lints: + dependency: "direct dev" + description: + name: flutter_lints + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.4" flutter_test: dependency: "direct dev" description: flutter source: sdk version: "0.0.0" + lints: + dependency: transitive + description: + name: lints + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.1" matcher: dependency: transitive description: @@ -73,7 +87,7 @@ packages: name: meta url: "https://pub.dartlang.org" source: hosted - version: "1.3.0" + version: "1.7.0" path: dependency: transitive description: @@ -127,7 +141,7 @@ packages: name: test_api url: "https://pub.dartlang.org" source: hosted - version: "0.3.0" + version: "0.4.2" typed_data: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index a62a47a..07d87f0 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -14,5 +14,6 @@ dependencies: dev_dependencies: flutter_test: sdk: flutter + flutter_lints: ^1.0.0 flutter: diff --git a/test/boardview_test.dart b/test/boardview_test.dart index 6f79cb0..2013e1a 100644 --- a/test/boardview_test.dart +++ b/test/boardview_test.dart @@ -1,9 +1,10 @@ import 'package:flutter_test/flutter_test.dart'; -import 'package:boardview/boardview.dart'; +// import 'package:boardview/boardview.dart'; void main() { test('adds one to input values', () { - final boardview = BoardView(); + // TODO: create tests + // final boardview = BoardView(); }); } From 21d97d90655422e53e76fb28f6688eb88d7238b2 Mon Sep 17 00:00:00 2001 From: Ian Koerich Maciel Date: Wed, 15 Sep 2021 11:25:29 -0300 Subject: [PATCH 5/7] Make _onDropItem private --- lib/board_item.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/board_item.dart b/lib/board_item.dart index bae0802..edfe8d2 100644 --- a/lib/board_item.dart +++ b/lib/board_item.dart @@ -47,7 +47,7 @@ class BoardItemState extends State @override bool get wantKeepAlive => true; - void onDropItem(int? listIndex, int? itemIndex) { + void _onDropItem(int? listIndex, int? itemIndex) { if (widget.onDropItem != null) { widget.onDropItem!( listIndex, @@ -65,7 +65,7 @@ class BoardItemState extends State void _startDrag(Widget item, BuildContext context) { if (widget.boardList!.widget.boardView != null) { - widget.boardList!.widget.boardView!.onDropItem = onDropItem; + widget.boardList!.widget.boardView!.onDropItem = _onDropItem; if (widget.boardList!.mounted) { widget.boardList!.setState(() {}); } From 67e0090cd158536b53e095dfc31b1b378bd29224 Mon Sep 17 00:00:00 2001 From: Ian Koerich Maciel Date: Wed, 15 Sep 2021 11:39:03 -0300 Subject: [PATCH 6/7] Use onDragStart event The previous implementarion use onTapDown to start dragging instead of the events "onHorizontalDragStart" and "onVerticalDragStart" provided by GestureDetector. Using onTapDown might confuse users because it requires a few seconds before actually starting the drag and drop event which is not the expected behavior. --- lib/board_item.dart | 94 ++++++++++++++++++++++----------------------- lib/board_view.dart | 22 +++++++---- 2 files changed, 60 insertions(+), 56 deletions(-) diff --git a/lib/board_item.dart b/lib/board_item.dart index edfe8d2..e20efab 100644 --- a/lib/board_item.dart +++ b/lib/board_item.dart @@ -63,27 +63,50 @@ class BoardItemState extends State } } + bool get canStartDragging => + widget.boardList!.widget.boardView!.widget.isNotSelecting && + widget.draggable; + void _startDrag(Widget item, BuildContext context) { - if (widget.boardList!.widget.boardView != null) { - widget.boardList!.widget.boardView!.onDropItem = _onDropItem; - if (widget.boardList!.mounted) { - widget.boardList!.setState(() {}); - } - widget.boardList!.widget.boardView!.draggedItemIndex = widget.index; - widget.boardList!.widget.boardView!.height = context.size!.height; - widget.boardList!.widget.boardView!.draggedListIndex = - widget.boardList!.widget.index; - widget.boardList!.widget.boardView!.startListIndex = - widget.boardList!.widget.index; - widget.boardList!.widget.boardView!.startItemIndex = widget.index; - widget.boardList!.widget.boardView!.draggedItem = item; - if (widget.onStartDragItem != null) { - widget.onStartDragItem!( - widget.boardList!.widget.index, widget.index, this); - } - widget.boardList!.widget.boardView!.run(); - if (widget.boardList!.widget.boardView!.mounted) { - widget.boardList!.widget.boardView!.setState(() {}); + if (canStartDragging) { + RenderBox object = context.findRenderObject() as RenderBox; + Offset pos = object.localToGlobal(Offset.zero); + RenderBox box = widget.boardList!.context.findRenderObject() as RenderBox; + Offset listPos = box.localToGlobal(Offset.zero); + widget.boardList!.widget.boardView!.leftListX = listPos.dx; + widget.boardList!.widget.boardView!.topListY = listPos.dy; + widget.boardList!.widget.boardView!.topItemY = pos.dy; + widget.boardList!.widget.boardView!.bottomItemY = + pos.dy + object.size.height; + widget.boardList!.widget.boardView!.bottomListY = + listPos.dy + box.size.height; + widget.boardList!.widget.boardView!.rightListX = + listPos.dx + box.size.width; + + widget.boardList!.widget.boardView!.initialX = pos.dx; + widget.boardList!.widget.boardView!.initialY = pos.dy; + + if (widget.boardList!.widget.boardView != null) { + widget.boardList!.widget.boardView!.onDropItem = _onDropItem; + if (widget.boardList!.mounted) { + widget.boardList!.setState(() {}); + } + widget.boardList!.widget.boardView!.draggedItemIndex = widget.index; + widget.boardList!.widget.boardView!.height = context.size!.height; + widget.boardList!.widget.boardView!.draggedListIndex = + widget.boardList!.widget.index; + widget.boardList!.widget.boardView!.startListIndex = + widget.boardList!.widget.index; + widget.boardList!.widget.boardView!.startItemIndex = widget.index; + widget.boardList!.widget.boardView!.draggedItem = item; + if (widget.onStartDragItem != null) { + widget.onStartDragItem!( + widget.boardList!.widget.index, widget.index, this); + } + widget.boardList!.widget.boardView!.run(); + if (widget.boardList!.widget.boardView!.mounted) { + widget.boardList!.widget.boardView!.setState(() {}); + } } } } @@ -105,39 +128,14 @@ class BoardItemState extends State } widget.boardList!.itemStates.insert(widget.index!, this); return GestureDetector( - onTapDown: (otd) { - if (widget.draggable) { - RenderBox object = context.findRenderObject() as RenderBox; - Offset pos = object.localToGlobal(Offset.zero); - RenderBox box = - widget.boardList!.context.findRenderObject() as RenderBox; - Offset listPos = box.localToGlobal(Offset.zero); - widget.boardList!.widget.boardView!.leftListX = listPos.dx; - widget.boardList!.widget.boardView!.topListY = listPos.dy; - widget.boardList!.widget.boardView!.topItemY = pos.dy; - widget.boardList!.widget.boardView!.bottomItemY = - pos.dy + object.size.height; - widget.boardList!.widget.boardView!.bottomListY = - listPos.dy + box.size.height; - widget.boardList!.widget.boardView!.rightListX = - listPos.dx + box.size.width; - - widget.boardList!.widget.boardView!.initialX = pos.dx; - widget.boardList!.widget.boardView!.initialY = pos.dy; - } - }, - onTapCancel: () {}, onTap: () { if (widget.onTapItem != null) { widget.onTapItem!(widget.boardList!.widget.index, widget.index, this); } }, - onLongPress: () { - if (!widget.boardList!.widget.boardView!.widget.isSelecting && - widget.draggable) { - _startDrag(widget, context); - } - }, + onHorizontalDragStart: (DragStartDetails _) => + _startDrag(widget, context), + onVerticalDragStart: (DragStartDetails _) => _startDrag(widget, context), child: widget.item, ); } diff --git a/lib/board_view.dart b/lib/board_view.dart index 2e9ff8f..e541410 100644 --- a/lib/board_view.dart +++ b/lib/board_view.dart @@ -35,6 +35,8 @@ class BoardView extends StatefulWidget { this.bottomPadding, }) : super(key: key); + bool get isNotSelecting => !isSelecting; + @override State createState() { return BoardViewState(); @@ -529,10 +531,12 @@ class BoardViewState extends State duration: const Duration(milliseconds: 10), curve: Curves.ease) .whenComplete(() { - pos -= listStates[draggedListIndex!] - .boardListController - .position - .pixels; + if (draggedListIndex != null) { + pos -= listStates[draggedListIndex!] + .boardListController + .position + .pixels; + } initialY ??= 0; // if(widget.boardViewController != null) { // initialY -= pos; @@ -589,10 +593,12 @@ class BoardViewState extends State duration: const Duration(milliseconds: 10), curve: Curves.ease) .whenComplete(() { - pos -= listStates[draggedListIndex!] - .boardListController - .position - .pixels; + if (draggedListIndex != null) { + pos -= listStates[draggedListIndex!] + .boardListController + .position + .pixels; + } initialY ??= 0; // if(widget.boardViewController != null) { // initialY -= pos; From 1d85f582b52d874a1204618ef3967e08b94651b9 Mon Sep 17 00:00:00 2001 From: Ian Koerich Maciel Date: Wed, 15 Sep 2021 12:00:10 -0300 Subject: [PATCH 7/7] Update library version to 0.2.2 --- pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pubspec.yaml b/pubspec.yaml index 07d87f0..2deaf4f 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: boardview description: This is a custom Flutter widget that can create a draggable BoardView or also known as a kanban. The view can be reordered with drag and drop. -version: 0.2.1 +version: 0.2.2 homepage: https://github.com/jakebonk/FlutterBoardView environment: