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 c5c7fdb..c616282 100644 --- a/example/example.dart +++ b/example/example.dart @@ -1,27 +1,23 @@ 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 { - - - - List _listData = [ + final List _listData = [ BoardListObject(title: "List title 1"), BoardListObject(title: "List title 2"), BoardListObject(title: "List title 3") ]; - //Can be used to animate to different sections of the BoardView - BoardViewController boardViewController = new BoardViewController(); - + final BoardViewController boardViewController = BoardViewController(); + BoardViewExample({Key? key}) : super(key: key); @override Widget build(BuildContext context) { @@ -37,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), @@ -65,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 c00cd2f..e20efab 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,58 +39,88 @@ class BoardItem extends StatefulWidget { } } -class BoardItemState extends State with AutomaticKeepAliveClientMixin{ +class BoardItemState extends State + with AutomaticKeepAliveClientMixin { late double height; double? width; @override bool get wantKeepAlive => true; - void onDropItem(int? listIndex, int? itemIndex) { + 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(() {}); } } + 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(() {}); + } } } } void afterFirstLayout(BuildContext context) { - try { + if (context.size != null) { height = context.size!.height; width = context.size!.width; - }catch(e){} + } } @override Widget build(BuildContext context) { + super.build(context); WidgetsBinding.instance! .addPostFrameCallback((_) => afterFirstLayout(context)); if (widget.boardList!.itemStates.length > widget.index!) { @@ -96,37 +128,14 @@ class BoardItemState extends State with AutomaticKeepAliveClientMixin } 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_list.dart b/lib/board_list.dart index f9d95ec..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(() {}); } } @@ -78,20 +80,17 @@ 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); - if (widget.headerBackgroundColor != null) { - headerBackgroundColor = widget.headerBackgroundColor; - } 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; @@ -103,62 +102,62 @@ 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); } }, child: Container( - color: widget.headerBackgroundColor, + color: widget.headerBackgroundColor ?? + const Color.fromARGB(255, 255, 255, 255), child: Row( mainAxisSize: MainAxisSize.max, 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; @@ -169,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/board_view.dart b/lib/board_view.dart new file mode 100644 index 0000000..e541410 --- /dev/null +++ b/lib/board_view.dart @@ -0,0 +1,793 @@ +library boardview; + +import 'package:boardview/board_view_controller.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/widgets.dart'; +import 'dart:core'; +import 'package:boardview/board_list.dart'; +import 'package:vs_scrollbar/vs_scrollbar.dart'; + +class BoardView extends StatefulWidget { + final List? lists; + final double width; + 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; + + const 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); + + bool get isNotSelecting => !isSelecting; + + @override + State createState() { + return BoardViewState(); + } +} + +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 { + Widget? draggedItem; + int? draggedItemIndex; + int? draggedListIndex; + double? dx; + double? dxInit; + double? dyInit; + double? dy; + double? offsetX; + double? offsetY; + double? initialX = 0; + double? initialY = 0; + double? rightListX; + double? leftListX; + double? topListY; + double? bottomListY; + double? topItemY; + double? bottomItemY; + double? height; + int? startListIndex; + int? startItemIndex; + + bool canDrag = true; + + ScrollController boardViewController = ScrollController(); + + List listStates = []; + + OnDropItem? onDropItem; + OnDropList? onDropList; + + bool isScrolling = false; + + bool _isInWidget = false; + + final GlobalKey _middleWidgetKey = GlobalKey(); + + PointerDownEvent? pointer; + + @override + bool get wantKeepAlive => true; + + @override + void initState() { + super.initState(); + 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; + } + 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) { + draggedItemIndex = draggedItemIndex! + 1; + } + widget.lists![draggedListIndex!].items!.insert(draggedItemIndex!, item); + 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; + } + 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) { + draggedItemIndex = draggedItemIndex! - 1; + } + widget.lists![draggedListIndex!].items!.insert(draggedItemIndex!, item); + listStates[draggedListIndex!] + .itemStates + .insert(draggedItemIndex!, itemState); + if (listStates[draggedListIndex!].mounted) { + listStates[draggedListIndex!].setState(() {}); + } + } + + void moveListRight() { + var list = widget.lists![draggedListIndex!]; + var listState = listStates[draggedListIndex!]; + widget.lists!.removeAt(draggedListIndex!); + listStates.removeAt(draggedListIndex!); + if (draggedListIndex != null) { + draggedListIndex = draggedListIndex! + 1; + } + widget.lists!.insert(draggedListIndex!, list); + listStates.insert(draggedListIndex!, listState); + canDrag = false; + if (boardViewController.hasClients) { + int? tempListIndex = draggedListIndex; + boardViewController + .animateTo(draggedListIndex! * widget.width, + duration: const Duration(milliseconds: 400), curve: Curves.ease) + .whenComplete(() { + 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(Duration(milliseconds: widget.dragDelay), () { + canDrag = true; + }); + }); + } + if (mounted) { + setState(() {}); + } + } + + void moveRight() { + var item = widget.lists![draggedListIndex!].items![draggedItemIndex!]; + var itemState = listStates[draggedListIndex!].itemStates[draggedItemIndex!]; + widget.lists![draggedListIndex!].items!.removeAt(draggedItemIndex!); + listStates[draggedListIndex!].itemStates.removeAt(draggedItemIndex!); + if (listStates[draggedListIndex!].mounted) { + listStates[draggedListIndex!].setState(() {}); + } + 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) { + 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) { + closestValue = temp; + draggedItemIndex = i; + dyInit = dy; + } + } + } + widget.lists![draggedListIndex!].items!.insert(draggedItemIndex!, item); + listStates[draggedListIndex!] + .itemStates + .insert(draggedItemIndex!, itemState); + canDrag = false; + if (listStates[draggedListIndex!].mounted) { + listStates[draggedListIndex!].setState(() {}); + } + if (boardViewController.hasClients) { + int? tempListIndex = draggedListIndex; + int? tempItemIndex = draggedItemIndex; + boardViewController + .animateTo(draggedListIndex! * widget.width, + duration: const Duration(milliseconds: 400), curve: Curves.ease) + .whenComplete(() { + 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; + Offset itemPos = box.localToGlobal(Offset.zero); + topItemY = itemPos.dy; + bottomItemY = itemPos.dy + box.size.height; + Future.delayed(Duration(milliseconds: widget.dragDelay), () { + canDrag = true; + }); + }); + } + if (mounted) { + setState(() {}); + } + } + + void moveListLeft() { + var list = widget.lists![draggedListIndex!]; + var listState = listStates[draggedListIndex!]; + widget.lists!.removeAt(draggedListIndex!); + listStates.removeAt(draggedListIndex!); + if (draggedListIndex != null) { + draggedListIndex = draggedListIndex! - 1; + } + widget.lists!.insert(draggedListIndex!, list); + listStates.insert(draggedListIndex!, listState); + canDrag = false; + if (boardViewController.hasClients) { + int? tempListIndex = draggedListIndex; + boardViewController + .animateTo(draggedListIndex! * widget.width, + duration: Duration(milliseconds: widget.dragDelay), + curve: Curves.ease) + .whenComplete(() { + 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(Duration(milliseconds: widget.dragDelay), () { + canDrag = true; + }); + }); + } + if (mounted) { + setState(() {}); + } + } + + void moveLeft() { + var item = widget.lists![draggedListIndex!].items![draggedItemIndex!]; + var itemState = listStates[draggedListIndex!].itemStates[draggedItemIndex!]; + widget.lists![draggedListIndex!].items!.removeAt(draggedItemIndex!); + listStates[draggedListIndex!].itemStates.removeAt(draggedItemIndex!); + if (listStates[draggedListIndex!].mounted) { + listStates[draggedListIndex!].setState(() {}); + } + 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) { + 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) { + closestValue = temp; + draggedItemIndex = i; + dyInit = dy; + } + } + } + widget.lists![draggedListIndex!].items!.insert(draggedItemIndex!, item); + listStates[draggedListIndex!] + .itemStates + .insert(draggedItemIndex!, itemState); + canDrag = false; + if (listStates[draggedListIndex!].mounted) { + listStates[draggedListIndex!].setState(() {}); + } + if (boardViewController.hasClients) { + int? tempListIndex = draggedListIndex; + int? tempItemIndex = draggedItemIndex; + boardViewController + .animateTo(draggedListIndex! * widget.width, + duration: const Duration(milliseconds: 400), curve: Curves.ease) + .whenComplete(() { + 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; + Offset itemPos = box.localToGlobal(Offset.zero); + topItemY = itemPos.dy; + bottomItemY = itemPos.dy + box.size.height; + Future.delayed(Duration(milliseconds: widget.dragDelay), () { + canDrag = true; + }); + }); + } + if (mounted) { + setState(() {}); + } + } + + bool shown = true; + + @override + Widget build(BuildContext context) { + super.build(context); + debugPrint("dy:$dy"); + debugPrint("topListY:$topListY"); + debugPrint("bottomListY:$bottomListY"); + if (boardViewController.hasClients) { + WidgetsBinding.instance!.addPostFrameCallback((Duration duration) { + boardViewController.position.didUpdateScrollPositionBy(0); + bool _shown = boardViewController.position.maxScrollExtent != 0; + if (_shown != shown) { + setState(() { + shown = _shown; + }); + } + }); + } + Widget listWidget = ListView.builder( + physics: const ClampingScrollPhysics(), + itemCount: widget.lists!.length, + scrollDirection: Axis.horizontal, + controller: boardViewController, + itemBuilder: (BuildContext context, int index) { + if (widget.lists![index].boardView == null) { + widget.lists![index] = BoardList( + items: widget.lists![index].items, + headerBackgroundColor: widget.lists![index].headerBackgroundColor, + backgroundColor: widget.lists![index].backgroundColor, + footer: widget.lists![index].footer, + header: widget.lists![index].header, + boardView: this, + draggable: widget.lists![index].draggable, + onDropList: widget.lists![index].onDropList, + onTapList: widget.lists![index].onTapList, + onStartDragList: widget.lists![index].onStartDragList, + ); + } + if (widget.lists![index].index != index) { + widget.lists![index] = BoardList( + items: widget.lists![index].items, + headerBackgroundColor: widget.lists![index].headerBackgroundColor, + backgroundColor: widget.lists![index].backgroundColor, + footer: widget.lists![index].footer, + header: widget.lists![index].header, + boardView: this, + draggable: widget.lists![index].draggable, + index: index, + onDropList: widget.lists![index].onDropList, + onTapList: widget.lists![index].onTapList, + onStartDragList: widget.lists![index].onStartDragList, + ); + } + + var temp = Container( + width: widget.width, + padding: EdgeInsets.fromLTRB(0, 0, 0, widget.bottomPadding ?? 0), + child: Row( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.start, + children: [Expanded(child: widget.lists![index])], + )); + if (draggedListIndex == index && draggedItemIndex == null) { + return Opacity( + opacity: 0.0, + child: temp, + ); + } else { + return temp; + } + }, + ); + if (widget.scrollbar == true) { + listWidget = VsScrollbar( + controller: boardViewController, + 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) { + widget.itemInMiddleWidget!(isInBottomWidget); + _isInWidget = isInBottomWidget; + } + if (initialX != null && + initialY != null && + offsetX != null && + offsetY != null && + dx != null && + dy != null && + height != null) { + if (canDrag && dxInit != null && dyInit != null && !isInBottomWidget) { + if (draggedItemIndex != null && + draggedItem != null && + topItemY != null && + bottomItemY != null) { + //dragging item + if (0 <= draggedListIndex! - 1 && dx! < leftListX! + 45) { + //scroll left + 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; + rightListX = pos.dx + object.size.width; + } + } + } + if (widget.lists!.length > draggedListIndex! + 1 && + dx! > rightListX! - 45) { + //scroll right + 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; + rightListX = pos.dx + object.size.width; + } + } + } + if (0 <= draggedListIndex! - 1 && dx! < leftListX!) { + //move left + moveLeft(); + } + if (widget.lists!.length > draggedListIndex! + 1 && + dx! > rightListX!) { + //move right + moveRight(); + } + if (dy! < topListY! + 70) { + //scroll up + 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: const Duration(milliseconds: 10), + curve: Curves.ease) + .whenComplete(() { + if (draggedListIndex != null) { + pos -= listStates[draggedListIndex!] + .boardListController + .position + .pixels; + } + initialY ??= 0; +// if(widget.boardViewController != null) { +// initialY -= pos; +// } + isScrolling = false; + if (topItemY != null) { + topItemY = topItemY! + pos; + } + if (bottomItemY != null) { + bottomItemY = bottomItemY! + pos; + } + if (mounted) { + setState(() {}); + } + }); + } + } + if (0 <= draggedItemIndex! - 1 && + dy! < + topItemY! - + listStates[draggedListIndex!] + .itemStates[draggedItemIndex! - 1] + .height / + 2) { + //move up + moveUp(); + } + double? tempBottom = bottomListY; + if (widget.middleWidget != null) { + if (_middleWidgetKey.currentContext != null) { + RenderBox _box = _middleWidgetKey.currentContext! + .findRenderObject() as RenderBox; + tempBottom = _box.size.height; + debugPrint("tempBottom:$tempBottom"); + } + } + if (dy! > tempBottom! - 70) { + //scroll down + + 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: const Duration(milliseconds: 10), + curve: Curves.ease) + .whenComplete(() { + if (draggedListIndex != null) { + pos -= listStates[draggedListIndex!] + .boardListController + .position + .pixels; + } + initialY ??= 0; +// if(widget.boardViewController != null) { +// initialY -= pos; +// } + isScrolling = false; + if (topItemY != null) { + topItemY = topItemY! + pos; + } + if (bottomItemY != null) { + bottomItemY = bottomItemY! + pos; + } + if (mounted) { + setState(() {}); + } + }); + } + } + if (widget.lists![draggedListIndex!].items!.length > + draggedItemIndex! + 1 && + dy! > + bottomItemY! + + listStates[draggedListIndex!] + .itemStates[draggedItemIndex! + 1] + .height / + 2) { + //move down + moveDown(); + } + } else { + //dragging list + if (0 <= draggedListIndex! - 1 && dx! < leftListX! + 45) { + //scroll left + 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) { + rightListX = rightListX! + 5; + } + } + } + + if (widget.lists!.length > draggedListIndex! + 1 && + dx! > rightListX! - 45) { + //scroll right + 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) { + rightListX = rightListX! - 5; + } + } + } + if (widget.lists!.length > draggedListIndex! + 1 && + dx! > rightListX!) { + //move right + moveListRight(); + } + if (0 <= draggedListIndex! - 1 && dx! < leftListX!) { + //move left + moveListLeft(); + } + } + } + if (widget.middleWidget != null) { + stackWidgets + .add(Container(key: _middleWidgetKey, child: widget.middleWidget)); + } + WidgetsBinding.instance!.addPostFrameCallback((timeStamp) { + if (mounted) { + setState(() {}); + } + }); + stackWidgets.add(Positioned( + width: widget.width, + height: height, + child: Opacity(opacity: .7, child: draggedItem), + left: (dx! - offsetX!) + initialX!, + top: (dy! - offsetY!) + initialY!, + )); + } + + 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) { + setState(() {}); + } + } + } +} + +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}); +} 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.dart b/lib/boardview.dart deleted file mode 100644 index dfbe9b2..0000000 --- a/lib/boardview.dart +++ /dev/null @@ -1,680 +0,0 @@ -library boardview; - -import 'dart:math'; - -import 'package:boardview/boardview_controller.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter/widgets.dart'; -import 'dart:core'; -import 'package:boardview/board_list.dart'; -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); - - @override - State createState() { - return BoardViewState(); - } -} - -typedef void OnDropBottomWidget(int? listIndex, int? itemIndex,double percentX); -typedef void OnDropItem(int? listIndex, int? itemIndex); -typedef void OnDropList(int? listIndex); - -class BoardViewState extends State with AutomaticKeepAliveClientMixin { - Widget? draggedItem; - int? draggedItemIndex; - int? draggedListIndex; - double? dx; - double? dxInit; - double? dyInit; - double? dy; - double? offsetX; - double? offsetY; - double? initialX = 0; - double? initialY = 0; - double? rightListX; - double? leftListX; - double? topListY; - double? bottomListY; - double? topItemY; - double? bottomItemY; - double? height; - int? startListIndex; - int? startItemIndex; - - bool canDrag = true; - - ScrollController boardViewController = new ScrollController(); - - List listStates = []; - - OnDropItem? onDropItem; - OnDropList? onDropList; - - bool isScrolling = false; - - bool _isInWidget = false; - - GlobalKey _middleWidgetKey = GlobalKey(); - - var pointer; - - @override - bool get wantKeepAlive => true; - - @override - void initState() { - super.initState(); - 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; - } - 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){ - draggedItemIndex = draggedItemIndex! + 1; - } - widget.lists![draggedListIndex!].items!.insert(draggedItemIndex!, item); - 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; - } - 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){ - draggedItemIndex = draggedItemIndex! - 1; - } - widget.lists![draggedListIndex!].items!.insert(draggedItemIndex!, item); - listStates[draggedListIndex!].itemStates.insert(draggedItemIndex!, itemState); - if(listStates[draggedListIndex!].mounted) { - listStates[draggedListIndex!].setState(() {}); - } - } - - void moveListRight() { - var list = widget.lists![draggedListIndex!]; - var listState = listStates[draggedListIndex!]; - widget.lists!.removeAt(draggedListIndex!); - listStates.removeAt(draggedListIndex!); - if(draggedListIndex != null){ - draggedListIndex = draggedListIndex! + 1; - } - widget.lists!.insert(draggedListIndex!, list); - listStates.insert(draggedListIndex!, listState); - canDrag = false; - if (boardViewController != null && boardViewController.hasClients) { - int? tempListIndex = draggedListIndex; - boardViewController - .animateTo(draggedListIndex! * widget.width, duration: new Duration(milliseconds: 400), curve: Curves.ease) - .whenComplete(() { - 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), () { - canDrag = true; - }); - }); - } - if(mounted){ - setState(() {}); - } - } - - void moveRight() { - var item = widget.lists![draggedListIndex!].items![draggedItemIndex!]; - var itemState = listStates[draggedListIndex!].itemStates[draggedItemIndex!]; - widget.lists![draggedListIndex!].items!.removeAt(draggedItemIndex!); - listStates[draggedListIndex!].itemStates.removeAt(draggedItemIndex!); - if(listStates[draggedListIndex!].mounted) { - listStates[draggedListIndex!].setState(() {}); - } - 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; - Offset pos = box.localToGlobal(Offset.zero); - var temp = (pos.dy - dy! + (box.size.height / 2)).abs(); - if (temp < closestValue) { - closestValue = temp; - draggedItemIndex = i; - dyInit = dy; - } - } - } - widget.lists![draggedListIndex!].items!.insert(draggedItemIndex!, item); - listStates[draggedListIndex!].itemStates.insert(draggedItemIndex!, itemState); - canDrag = false; - if(listStates[draggedListIndex!].mounted) { - listStates[draggedListIndex!].setState(() {}); - } - if (boardViewController != null && boardViewController.hasClients) { - int? tempListIndex = draggedListIndex; - int? tempItemIndex = draggedItemIndex; - boardViewController - .animateTo(draggedListIndex! * widget.width, duration: new Duration(milliseconds: 400), curve: Curves.ease) - .whenComplete(() { - 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; - Offset itemPos = box.localToGlobal(Offset.zero); - topItemY = itemPos.dy; - bottomItemY = itemPos.dy + box.size.height; - Future.delayed(new Duration(milliseconds: widget.dragDelay), () { - canDrag = true; - }); - }); - } - if(mounted){ - setState(() { }); - } - } - - void moveListLeft() { - var list = widget.lists![draggedListIndex!]; - var listState = listStates[draggedListIndex!]; - widget.lists!.removeAt(draggedListIndex!); - listStates.removeAt(draggedListIndex!); - if(draggedListIndex != null){ - draggedListIndex = draggedListIndex! - 1; - } - widget.lists!.insert(draggedListIndex!, list); - listStates.insert(draggedListIndex!, listState); - canDrag = false; - if (boardViewController != null && boardViewController.hasClients) { - int? tempListIndex = draggedListIndex; - boardViewController - .animateTo(draggedListIndex! * widget.width, duration: new Duration(milliseconds: widget.dragDelay), curve: Curves.ease) - .whenComplete(() { - 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), () { - canDrag = true; - }); - }); - } - if(mounted) { - setState(() {}); - } - } - - void moveLeft() { - var item = widget.lists![draggedListIndex!].items![draggedItemIndex!]; - var itemState = listStates[draggedListIndex!].itemStates[draggedItemIndex!]; - widget.lists![draggedListIndex!].items!.removeAt(draggedItemIndex!); - listStates[draggedListIndex!].itemStates.removeAt(draggedItemIndex!); - if(listStates[draggedListIndex!].mounted) { - listStates[draggedListIndex!].setState(() {}); - } - 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; - Offset pos = box.localToGlobal(Offset.zero); - var temp = (pos.dy - dy! + (box.size.height / 2)).abs(); - if (temp < closestValue) { - closestValue = temp; - draggedItemIndex = i; - dyInit = dy; - } - } - } - widget.lists![draggedListIndex!].items!.insert(draggedItemIndex!, item); - listStates[draggedListIndex!].itemStates.insert(draggedItemIndex!, itemState); - canDrag = false; - if(listStates[draggedListIndex!].mounted) { - listStates[draggedListIndex!].setState(() {}); - } - if (boardViewController != null && boardViewController.hasClients) { - int? tempListIndex = draggedListIndex; - int? tempItemIndex = draggedItemIndex; - boardViewController - .animateTo(draggedListIndex! * widget.width, duration: new Duration(milliseconds: 400), curve: Curves.ease) - .whenComplete(() { - 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; - Offset itemPos = box.localToGlobal(Offset.zero); - topItemY = itemPos.dy; - bottomItemY = itemPos.dy + box.size.height; - Future.delayed(new Duration(milliseconds: widget.dragDelay), () { - canDrag = true; - }); - }); - } - if(mounted) { - setState(() {}); - } - } - - bool shown = true; - - @override - Widget build(BuildContext context) { - print("dy:${dy}"); - print("topListY:${topListY}"); - print("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){ - setState(() { - shown = _shown; - }); - } - }); - } - Widget listWidget = ListView.builder( - physics: ClampingScrollPhysics(), - itemCount: widget.lists!.length, - scrollDirection: Axis.horizontal, - controller: boardViewController, - itemBuilder: (BuildContext context, int index) { - if (widget.lists![index].boardView == null) { - widget.lists![index] = BoardList( - items: widget.lists![index].items, - headerBackgroundColor: widget.lists![index].headerBackgroundColor, - backgroundColor: widget.lists![index].backgroundColor, - footer: widget.lists![index].footer, - header: widget.lists![index].header, - boardView: this, - draggable: widget.lists![index].draggable, - onDropList: widget.lists![index].onDropList, - onTapList: widget.lists![index].onTapList, - onStartDragList: widget.lists![index].onStartDragList, - ); - } - if (widget.lists![index].index != index) { - widget.lists![index] = BoardList( - items: widget.lists![index].items, - headerBackgroundColor: widget.lists![index].headerBackgroundColor, - backgroundColor: widget.lists![index].backgroundColor, - footer: widget.lists![index].footer, - header: widget.lists![index].header, - boardView: this, - draggable: widget.lists![index].draggable, - index: index, - onDropList: widget.lists![index].onDropList, - onTapList: widget.lists![index].onTapList, - onStartDragList: widget.lists![index].onStartDragList, - ); - } - - var temp = Container( - width: widget.width, - padding: EdgeInsets.fromLTRB(0, 0, 0, widget.bottomPadding ?? 0), - child: Row( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisAlignment: MainAxisAlignment.start, - children: [Expanded(child: widget.lists![index])], - )); - if (draggedListIndex == index && draggedItemIndex == null) { - return Opacity( - opacity: 0.0, - child: temp, - ); - } else { - return temp; - } - }, - ); - 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 - ]; - bool isInBottomWidget = false; - if (dy != null) { - if (MediaQuery.of(context).size.height - dy! < 80) { - isInBottomWidget = true; - } - } - if(widget.itemInMiddleWidget != null && _isInWidget != isInBottomWidget) { - widget.itemInMiddleWidget!(isInBottomWidget); - _isInWidget = isInBottomWidget; - } - if (initialX != null && - initialY != null && - offsetX != null && - offsetY != null && - dx != null && - dy != null && - height != null && - widget.width != null) { - if (canDrag && dxInit != null && dyInit != null && !isInBottomWidget) { - 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 - .findRenderObject() as RenderBox; - Offset pos = object.localToGlobal(Offset.zero); - leftListX = pos.dx; - rightListX = pos.dx + object.size.width; - } - } - } - 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 - .findRenderObject() as RenderBox; - Offset pos = object.localToGlobal(Offset.zero); - leftListX = pos.dx; - rightListX = pos.dx + object.size.width; - } - } - } - if (0 <= draggedListIndex! - 1 && dx! < leftListX!) { - //move left - moveLeft(); - } - 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) { - 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; -// if(widget.boardViewController != null) { -// initialY -= pos; -// } - isScrolling = false; - if(topItemY != null) { - topItemY = topItemY! + pos; - } - if(bottomItemY != null) { - bottomItemY = bottomItemY! + pos; - } - if(mounted){ - setState(() { }); - } - }); - } - } - if (0 <= draggedItemIndex! - 1 && - dy! < topItemY! - listStates[draggedListIndex!].itemStates[draggedItemIndex! - 1].height / 2) { - //move up - moveUp(); - } - double? tempBottom = bottomListY; - if(widget.middleWidget != null){ - if(_middleWidgetKey.currentContext != null) { - RenderBox _box = _middleWidgetKey.currentContext! - .findRenderObject() as RenderBox; - tempBottom = _box.size.height; - print("tempBottom:${tempBottom}"); - } - } - if (dy! > tempBottom! - 70) { - //scroll down - - if (listStates[draggedListIndex!].boardListController != null && - 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; -// if(widget.boardViewController != null) { -// initialY -= pos; -// } - isScrolling = false; - if(topItemY != null) { - topItemY = topItemY! + pos; - } - if(bottomItemY != null) { - bottomItemY = bottomItemY! + pos; - } - if(mounted){ - setState(() {}); - } - }); - } - } - if (widget.lists![draggedListIndex!].items!.length > draggedItemIndex! + 1 && - dy! > bottomItemY! + listStates[draggedListIndex!].itemStates[draggedItemIndex! + 1].height / 2) { - //move down - moveDown(); - } - } else { - //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){ - leftListX = leftListX! + 5; - } - if(rightListX != null){ - rightListX = rightListX! + 5; - } - } - } - - 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){ - leftListX = leftListX! - 5; - } - if(rightListX != null){ - rightListX = rightListX! - 5; - } - } - } - if (widget.lists!.length > draggedListIndex! + 1 && dx! > rightListX!) { - //move right - moveListRight(); - } - if (0 <= draggedListIndex! - 1 && dx! < leftListX!) { - //move left - moveListLeft(); - } - } - } - if (widget.middleWidget != null) { - stackWidgets.add(Container(key:_middleWidgetKey,child:widget.middleWidget)); - } - WidgetsBinding.instance!.addPostFrameCallback((timeStamp) { - if(mounted){ - setState(() {}); - } - }); - stackWidgets.add(Positioned( - width: widget.width, - height: height, - child: Opacity(opacity: .7, child: draggedItem), - left: (dx! - offsetX!) + initialX!, - top: (dy! - offsetY!) + initialY!, - )); - } - - 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, - ))); - } - - void run() { - if (pointer != null) { - dx = pointer.position.dx; - dy = pointer.position.dy; - if(mounted) { - setState(() {}); - } - } - } -} - -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}); -} 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..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: @@ -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(); }); }