diff --git a/lib/src/models/node.dart b/lib/src/models/node.dart index 16ac91a..acc8aec 100644 --- a/lib/src/models/node.dart +++ b/lib/src/models/node.dart @@ -33,7 +33,7 @@ class Node { final T? data; /// The sub [Node]s of this object. - final List children; + final List> children; /// Force the node to be a parent so that node can show expander without /// having children node. @@ -52,7 +52,7 @@ class Node { /// Creates a [Node] from a string value. It generates a unique key. factory Node.fromLabel(String label) { String _key = Utilities.generateRandom(); - return Node( + return Node( key: '${_key}_$label', label: label, ); @@ -68,7 +68,7 @@ class Node { String? _key = map['key']; String _label = map['label']; var _data = map['data']; - List _children = []; + List> _children = []; if (_key == null) { _key = Utilities.generateRandom(); } @@ -86,10 +86,10 @@ class Node { if (map['children'] != null) { List> _childrenMap = List.from(map['children']); _children = _childrenMap - .map((Map child) => Node.fromMap(child)) + .map((Map child) => Node.fromMap(child)) .toList(); } - return Node( + return Node( key: '$_key', label: _label, data: _data, @@ -101,16 +101,16 @@ class Node { /// Creates a copy of this object but with the given fields /// replaced with the new values. - Node copyWith({ + Node copyWith({ String? key, String? label, - List? children, + List>? children, bool? expanded, bool? parent, IconData? icon, T? data, }) => - Node( + Node( key: key ?? this.key, label: label ?? this.label, icon: icon ?? this.icon, @@ -167,7 +167,7 @@ class Node { bool operator ==(Object other) { if (identical(this, other)) return true; if (other.runtimeType != runtimeType) return false; - return other is Node && + return other is Node && other.key == key && other.label == label && other.icon == icon && diff --git a/lib/src/tree_node.dart b/lib/src/tree_node.dart index 2e4ab6a..2181641 100644 --- a/lib/src/tree_node.dart +++ b/lib/src/tree_node.dart @@ -19,17 +19,17 @@ const double _kBorderWidth = 0.75; /// __This class should not be used directly!__ /// The [TreeView] and [TreeViewController] handlers the data and rendering /// of the nodes. -class TreeNode extends StatefulWidget { +class TreeNode extends StatefulWidget { /// The node object used to display the widget state - final Node node; + final Node node; const TreeNode({Key? key, required this.node}) : super(key: key); @override - _TreeNodeState createState() => _TreeNodeState(); + _TreeNodeState createState() => _TreeNodeState(); } -class _TreeNodeState extends State +class _TreeNodeState extends State> with SingleTickerProviderStateMixin { static final Animatable _easeInTween = CurveTween(curve: Curves.easeIn); @@ -51,8 +51,10 @@ class _TreeNodeState extends State @override void didChangeDependencies() { super.didChangeDependencies(); - TreeView? _treeView = TreeView.of(context); - _controller.duration = _treeView!.theme.expandSpeed; + TreeView? _treeView = TreeView.of(context); + if (_treeView != null) { + _controller.duration = _treeView.theme.expandSpeed; + } } @override @@ -62,7 +64,7 @@ class _TreeNodeState extends State } @override - void didUpdateWidget(TreeNode oldWidget) { + void didUpdateWidget(TreeNode oldWidget) { if (widget.node.expanded != oldWidget.node.expanded) { setState(() { _isExpanded = widget.node.expanded; @@ -82,7 +84,7 @@ class _TreeNodeState extends State } void _handleExpand() { - TreeView? _treeView = TreeView.of(context); + TreeView? _treeView = TreeView.of(context); assert(_treeView != null, 'TreeView must exist in context'); setState(() { _isExpanded = !_isExpanded; @@ -100,7 +102,7 @@ class _TreeNodeState extends State } void _handleTap() { - TreeView? _treeView = TreeView.of(context); + TreeView? _treeView = TreeView.of(context); assert(_treeView != null, 'TreeView must exist in context'); if (_treeView!.onNodeTap != null) { _treeView.onNodeTap!(widget.node.key); @@ -108,7 +110,7 @@ class _TreeNodeState extends State } void _handleDoubleTap() { - TreeView? _treeView = TreeView.of(context); + TreeView? _treeView = TreeView.of(context); assert(_treeView != null, 'TreeView must exist in context'); if (_treeView!.onNodeDoubleTap != null) { _treeView.onNodeDoubleTap!(widget.node.key); @@ -116,7 +118,7 @@ class _TreeNodeState extends State } Widget _buildNodeExpander() { - TreeView? _treeView = TreeView.of(context); + TreeView? _treeView = TreeView.of(context); assert(_treeView != null, 'TreeView must exist in context'); TreeViewTheme _theme = _treeView!.theme; return widget.node.isParent @@ -132,7 +134,7 @@ class _TreeNodeState extends State } Widget _buildNodeIcon() { - TreeView? _treeView = TreeView.of(context); + TreeView? _treeView = TreeView.of(context); assert(_treeView != null, 'TreeView must exist in context'); TreeViewTheme _theme = _treeView!.theme; bool isSelected = _treeView.controller.selectedKey != null && @@ -154,7 +156,7 @@ class _TreeNodeState extends State } Widget _buildNodeLabel() { - TreeView? _treeView = TreeView.of(context); + TreeView? _treeView = TreeView.of(context); assert(_treeView != null, 'TreeView must exist in context'); TreeViewTheme _theme = _treeView!.theme; bool isSelected = _treeView.controller.selectedKey != null && @@ -198,7 +200,7 @@ class _TreeNodeState extends State } Widget _buildNodeWidget() { - TreeView? _treeView = TreeView.of(context); + TreeView? _treeView = TreeView.of(context); assert(_treeView != null, 'TreeView must exist in context'); TreeViewTheme _theme = _treeView!.theme; bool isSelected = _treeView.controller.selectedKey != null && @@ -265,7 +267,7 @@ class _TreeNodeState extends State @override Widget build(BuildContext context) { - TreeView? _treeView = TreeView.of(context); + TreeView? _treeView = TreeView.of(context); assert(_treeView != null, 'TreeView must exist in context'); final bool closed = (!_isExpanded || !widget.node.expanded) && _controller.isDismissed; @@ -295,8 +297,8 @@ class _TreeNodeState extends State _treeView.theme.iconTheme.size!), child: Column( mainAxisSize: MainAxisSize.min, - children: widget.node.children.map((Node node) { - return TreeNode(node: node); + children: widget.node.children.map((Node node) { + return TreeNode(node: node); }).toList()), ), ) diff --git a/lib/src/tree_view.dart b/lib/src/tree_view.dart index cfa9d90..057bc1d 100644 --- a/lib/src/tree_view.dart +++ b/lib/src/tree_view.dart @@ -25,15 +25,15 @@ import 'models/node.dart'; /// theme: treeViewTheme /// ), /// ``` -class TreeView extends InheritedWidget { +class TreeView extends InheritedWidget { /// The controller for the [TreeView]. It manages the data and selected key. - final TreeViewController controller; + final TreeViewController controller; /// The tap handler for a node. Passes the node key. final Function(String)? onNodeTap; /// Custom builder for nodes. Parameters are the build context and tree node. - final Widget Function(BuildContext, Node)? nodeBuilder; + final Widget Function(BuildContext, Node)? nodeBuilder; /// The double tap handler for a node. Passes the node key. final Function(String)? onNodeDoubleTap; @@ -92,7 +92,7 @@ class TreeView extends InheritedWidget { }) : this.theme = theme ?? const TreeViewTheme(), super( key: key, - child: _TreeViewData( + child: _TreeViewData( controller, shrinkWrap: shrinkWrap, primary: primary, @@ -100,7 +100,7 @@ class TreeView extends InheritedWidget { ), ); - static TreeView? of(BuildContext context) => + static TreeView? of(BuildContext context) => context.dependOnInheritedWidgetOfExactType(aspect: TreeView); @override @@ -114,8 +114,8 @@ class TreeView extends InheritedWidget { } } -class _TreeViewData extends StatelessWidget { - final TreeViewController _controller; +class _TreeViewData extends StatelessWidget { + final TreeViewController _controller; final bool? shrinkWrap; final bool? primary; final ScrollPhysics? physics; @@ -133,8 +133,8 @@ class _TreeViewData extends StatelessWidget { primary: primary, physics: physics, padding: EdgeInsets.zero, - children: _controller.children.map((Node node) { - return TreeNode(node: node); + children: _controller.children.map>((Node node) { + return TreeNode(node: node); }).toList(), ), ); diff --git a/lib/src/tree_view_controller.dart b/lib/src/tree_view_controller.dart index 6f1fa9c..f3818b9 100644 --- a/lib/src/tree_view_controller.dart +++ b/lib/src/tree_view_controller.dart @@ -30,9 +30,9 @@ enum InsertMode { /// List newChildren = controller.updateNode(node.key, updatedNode); /// controller = TreeViewController(children: newChildren); /// ``` -class TreeViewController { +class TreeViewController { /// The data for the [TreeView]. - final List children; + final List> children; /// The key of the select node in the [TreeView]. final String? selectedKey; @@ -44,8 +44,9 @@ class TreeViewController { /// Creates a copy of this controller but with the given fields /// replaced with the new values. - TreeViewController copyWith({List? children, String? selectedKey}) { - return TreeViewController( + TreeViewController copyWith( + {List>? children, String? selectedKey}) { + return TreeViewController( children: children ?? this.children, selectedKey: selectedKey ?? this.selectedKey, ); @@ -74,8 +75,8 @@ class TreeViewController { /// }); /// ``` TreeViewController loadMap({List> list: const []}) { - List treeData = - list.map((Map item) => Node.fromMap(item)).toList(); + List> treeData = + list.map((Map item) => Node.fromMap(item)).toList(); return TreeViewController( children: treeData, selectedKey: this.selectedKey, @@ -96,12 +97,12 @@ class TreeViewController { /// ``` TreeViewController withAddNode( String key, - Node newNode, { - Node? parent, + Node newNode, { + Node? parent, int? index, InsertMode mode: InsertMode.append, }) { - List _data = + List> _data = addNode(key, newNode, parent: parent, mode: mode, index: index); return TreeViewController( children: _data, @@ -121,8 +122,9 @@ class TreeViewController { /// controller = controller.withUpdateNode(key, newNode); /// }); /// ``` - TreeViewController withUpdateNode(String key, Node newNode, {Node? parent}) { - List _data = updateNode(key, newNode, parent: parent); + TreeViewController withUpdateNode(String key, Node newNode, + {Node? parent}) { + List> _data = updateNode(key, newNode, parent: parent); return TreeViewController( children: _data, selectedKey: this.selectedKey, @@ -141,8 +143,8 @@ class TreeViewController { /// controller = controller.withDeleteNode(key); /// }); /// ``` - TreeViewController withDeleteNode(String key, {Node? parent}) { - List _data = deleteNode(key, parent: parent); + TreeViewController withDeleteNode(String key, {Node? parent}) { + List> _data = deleteNode(key, parent: parent); return TreeViewController( children: _data, selectedKey: this.selectedKey, @@ -161,8 +163,8 @@ class TreeViewController { /// controller = controller.withToggleNode(key, newNode); /// }); /// ``` - TreeViewController withToggleNode(String key, {Node? parent}) { - List _data = toggleNode(key, parent: parent); + TreeViewController withToggleNode(String key, {Node? parent}) { + List> _data = toggleNode(key, parent: parent); return TreeViewController( children: _data, selectedKey: this.selectedKey, @@ -182,7 +184,7 @@ class TreeViewController { /// }); /// ``` TreeViewController withExpandToNode(String key) { - List _data = expandToNode(key); + List> _data = expandToNode(key); return TreeViewController( children: _data, selectedKey: this.selectedKey, @@ -202,7 +204,7 @@ class TreeViewController { /// }); /// ``` TreeViewController withCollapseToNode(String key) { - List _data = collapseToNode(key); + List> _data = collapseToNode(key); return TreeViewController( children: _data, selectedKey: this.selectedKey, @@ -221,8 +223,8 @@ class TreeViewController { /// controller = controller.withExpandAll(); /// }); /// ``` - TreeViewController withExpandAll({Node? parent}) { - List _data = expandAll(parent: parent); + TreeViewController withExpandAll({Node? parent}) { + List> _data = expandAll(parent: parent); return TreeViewController( children: _data, selectedKey: this.selectedKey, @@ -241,8 +243,8 @@ class TreeViewController { /// controller = controller.withCollapseAll(); /// }); /// ``` - TreeViewController withCollapseAll({Node? parent}) { - List _data = collapseAll(parent: parent); + TreeViewController withCollapseAll({Node? parent}) { + List> _data = collapseAll(parent: parent); return TreeViewController( children: _data, selectedKey: this.selectedKey, @@ -250,12 +252,12 @@ class TreeViewController { } /// Gets the node that has a key value equal to the specified key. - Node? getNode(String key, {Node? parent}) { - Node? _found; - List _children = parent == null ? this.children : parent.children; + Node? getNode(String key, {Node? parent}) { + Node? _found; + List> _children = parent == null ? this.children : parent.children; Iterator iter = _children.iterator; while (iter.moveNext()) { - Node child = iter.current; + Node child = iter.current; if (child.key == key) { _found = child; break; @@ -272,12 +274,12 @@ class TreeViewController { } /// Expands all node that are children of the parent node parameter. If no parent is passed, uses the root node as the parent. - List expandAll({Node? parent}) { - List _children = []; + List> expandAll({Node? parent}) { + List> _children = []; Iterator iter = parent == null ? this.children.iterator : parent.children.iterator; while (iter.moveNext()) { - Node child = iter.current; + Node child = iter.current; if (child.isParent) { _children.add(child.copyWith( expanded: true, @@ -291,12 +293,12 @@ class TreeViewController { } /// Collapses all node that are children of the parent node parameter. If no parent is passed, uses the root node as the parent. - List collapseAll({Node? parent}) { - List _children = []; + List> collapseAll({Node? parent}) { + List> _children = []; Iterator iter = parent == null ? this.children.iterator : parent.children.iterator; while (iter.moveNext()) { - Node child = iter.current; + Node child = iter.current; if (child.isParent) { _children.add(child.copyWith( expanded: false, @@ -310,12 +312,12 @@ class TreeViewController { } /// Gets the parent of the node identified by specified key. - Node? getParent(String key, {Node? parent}) { - Node? _found; - List _children = parent == null ? this.children : parent.children; + Node? getParent(String key, {Node? parent}) { + Node? _found; + List> _children = parent == null ? this.children : parent.children; Iterator iter = _children.iterator; while (iter.moveNext()) { - Node child = iter.current; + Node child = iter.current; if (child.key == key) { _found = parent ?? child; break; @@ -333,23 +335,23 @@ class TreeViewController { /// Expands a node and all of the node's ancestors so that the node is /// visible without the need to manually expand each node. - List expandToNode(String key) { + List> expandToNode(String key) { List _ancestors = []; String _currentKey = key; _ancestors.add(_currentKey); - Node? _parent = this.getParent(_currentKey); + Node? _parent = this.getParent(_currentKey); if (_parent != null) { while (_parent!.key != _currentKey) { _currentKey = _parent.key; _ancestors.add(_currentKey); _parent = this.getParent(_currentKey); } - TreeViewController _this = this; + TreeViewController _this = this; _ancestors.forEach((String k) { - Node _node = _this.getNode(k)!; - Node _updated = _node.copyWith(expanded: true); + Node _node = _this.getNode(k)!; + Node _updated = _node.copyWith(expanded: true); _this = _this.withUpdateNode(k, _updated); }); return _this.children; @@ -359,23 +361,23 @@ class TreeViewController { /// Collapses a node and all of the node's ancestors without the need to /// manually collapse each node. - List collapseToNode(String key) { + List> collapseToNode(String key) { List _ancestors = []; String _currentKey = key; _ancestors.add(_currentKey); - Node? _parent = this.getParent(_currentKey); + Node? _parent = this.getParent(_currentKey); if (_parent != null) { while (_parent!.key != _currentKey) { _currentKey = _parent.key; _ancestors.add(_currentKey); _parent = this.getParent(_currentKey); } - TreeViewController _this = this; + TreeViewController _this = this; _ancestors.forEach((String k) { - Node _node = _this.getNode(k)!; - Node _updated = _node.copyWith(expanded: false); + Node _node = _this.getNode(k)!; + Node _updated = _node.copyWith(expanded: false); _this = _this.withUpdateNode(k, _updated); }); return _this.children; @@ -387,17 +389,17 @@ class TreeViewController { /// accepts an [InsertMode] and index. If no [InsertMode] is specified, /// it appends the new node as a child at the end. This method returns /// a new list with the added node. - List addNode( + List> addNode( String key, - Node newNode, { - Node? parent, + Node newNode, { + Node? parent, int? index, InsertMode mode: InsertMode.append, }) { - List _children = parent == null ? this.children : parent.children; - return _children.map((Node child) { + List> _children = parent == null ? this.children : parent.children; + return _children.map((Node child) { if (child.key == key) { - List _children = child.children.toList(growable: true); + List> _children = child.children.toList(growable: true); if (mode == InsertMode.prepend) { _children.insert(0, newNode); } else if (mode == InsertMode.insert) { @@ -422,9 +424,9 @@ class TreeViewController { /// Updates an existing node identified by specified key. This method /// returns a new list with the updated node. - List updateNode(String key, Node newNode, {Node? parent}) { - List _children = parent == null ? this.children : parent.children; - return _children.map((Node child) { + List> updateNode(String key, Node newNode, {Node? parent}) { + List> _children = parent == null ? this.children : parent.children; + return _children.map((Node child) { if (child.key == key) { return newNode; } else { @@ -444,19 +446,19 @@ class TreeViewController { /// Toggles an existing node identified by specified key. This method /// returns a new list with the specified node toggled. - List toggleNode(String key, {Node? parent}) { - Node? _node = getNode(key, parent: parent); + List> toggleNode(String key, {Node? parent}) { + Node? _node = getNode(key, parent: parent); return updateNode(key, _node!.copyWith(expanded: !_node.expanded)); } /// Deletes an existing node identified by specified key. This method /// returns a new list with the specified node removed. - List deleteNode(String key, {Node? parent}) { - List _children = parent == null ? this.children : parent.children; - List _filteredChildren = []; + List> deleteNode(String key, {Node? parent}) { + List> _children = parent == null ? this.children : parent.children; + List> _filteredChildren = []; Iterator iter = _children.iterator; while (iter.moveNext()) { - Node child = iter.current; + Node child = iter.current; if (child.key != key) { if (child.isParent) { _filteredChildren.add(child.copyWith( @@ -471,13 +473,13 @@ class TreeViewController { } /// Get the current selected node. Returns null if there is no selectedKey - Node? get selectedNode { + Node? get selectedNode { return this.selectedKey!.isEmpty ? null : getNode(this.selectedKey!); } /// Map representation of this object List> get asMap { - return children.map((Node child) => child.asMap).toList(); + return children.map((Node child) => child.asMap).toList(); } @override diff --git a/pubspec.yaml b/pubspec.yaml index 6beff3c..86e0044 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: flutter_treeview description: A tree widget for Flutter that can be used to display nested, hierarchical data. It includes a number of features like styling labels, icons, and import and export utilities. -version: 1.0.3+2 +version: 1.0.3+16 homepage: https://bitbucket.org/kevinandre/flutter_treeview/src/master/ repository: https://bitbucket.org/kevinandre/flutter_treeview/src/master/ issue_tracker: https://bitbucket.org/kevinandre/flutter_treeview/issues