diff --git a/lib/feeds/feed.dart b/lib/feeds/feed.dart index a88a3d4..9c53fe2 100644 --- a/lib/feeds/feed.dart +++ b/lib/feeds/feed.dart @@ -38,7 +38,7 @@ class Feed extends StatefulWidget { final IndexedFeedBuilder? indexedBuilder; - ///defines the height to offset the body + ///defines the height to offset the body, for external footers final double? footerHeight; ///Determines if the the feed should initially load, defaulted to true @@ -56,12 +56,15 @@ class Feed extends StatefulWidget { /// Loading widget final Widget? loading; + /// Header widget + final Widget? header; + + /// Footer widget + final Widget? footer; + ///Retrieves the item id, used to ensure the prevention of duplicate additions final RetrievalFunction? getItemID; - ///The optional function used to wrap the list view - final WidgetWrapper? wrapper; - /// Items that will be pinned to the top of the list on init final List? pinnedItems; @@ -71,10 +74,6 @@ class Feed extends StatefulWidget { /// The amount of items that are rendered at once final int? renderCount; - /// Determines if the place holder should be used when the feed is empty - /// Defaulted to true - final bool usePlaceholder; - /// Physics final ScrollPhysics? physics; @@ -91,16 +90,16 @@ class Feed extends StatefulWidget { this.footerHeight, this.placeholder, this.loading, + this.header, + this.footer, this.disableScroll, this.getItemID, - this.wrapper, this.scrollController, this.compact = false, this.initiallyLoad = true, this.pinnedItems, this.reverse = false, this.renderCount, - this.usePlaceholder = true, this.usePrimaryScrollController = false, this.physics }) : super(key: key); @@ -342,13 +341,6 @@ class _FeedState extends State { widget.controller?._update(); } - Widget wrapperBuilder({required BuildContext context, required Widget child, dynamic item}){ - if(widget.wrapper != null){ - return widget.wrapper!(context, child, item); - } - return child; - } - ///Keeps track of the added items are removes them from future loads void addItem(dynamic item){ @@ -369,7 +361,7 @@ class _FeedState extends State { Widget _buildFeed(bool loadMore, int size) { Widget view = SizedBox(); - if (size == 0 && !loadMore && widget.usePlaceholder) { + if (size == 0 && !loadMore) { if(widget.placeholder != null){ //No items placeholder view = widget.placeholder!; @@ -387,10 +379,11 @@ class _FeedState extends State { gridDelegate: widget.controller?.getGridDelegate(), disableScroll: widget.disableScroll == null ? false : widget.disableScroll, footerHeight: widget.footerHeight == null ? 0 : widget.footerHeight, - wrapper: widget.wrapper, onLoad: _loadMore, + footer: widget.footer, + header: widget.header, builder: (context, i, items){ - if (i == items.length) { + if (i == items.length + 1) { return loadMore ? load : SizedBox.shrink(); } return widget.indexedBuilder?.call(items, i) ?? widget.childBuilder!(items[i], items.length - 1 == i); diff --git a/lib/feeds/feed_list_view.dart b/lib/feeds/feed_list_view.dart index bd54fcb..c177158 100644 --- a/lib/feeds/feed_list_view.dart +++ b/lib/feeds/feed_list_view.dart @@ -51,10 +51,10 @@ class FeedListView extends StatefulWidget { final double? footerHeight; ///Loading widget - final Widget? loading; + final Widget? header; - ///The optional function used to wrap the list view - final WidgetWrapper? wrapper; + ///Loading widget + final Widget? footer; ///If defined builds this feed in grid mode final FeedGridViewDelegate? gridDelegate; @@ -65,7 +65,7 @@ class FeedListView extends StatefulWidget { /// Physics final ScrollPhysics? physics; - const FeedListView({ + const FeedListView({ Key? key, this.usePrimaryScrollController = false, this.disableScroll = false, @@ -75,8 +75,8 @@ class FeedListView extends StatefulWidget { required this.builder, required this.controller, this.footerHeight, - this.wrapper, - this.loading, + this.header, + this.footer, this.gridDelegate, this.physics }) : super(key: key); @@ -89,65 +89,91 @@ class _FeedListViewState extends State { ScrollController get scrollController => widget.controller; - Widget get loading => widget.loading == null ? Container() : widget.loading!; - - Widget wrapperBuilder({required BuildContext context, required Widget child, required dynamic item}){ - if(widget.wrapper != null){ - return widget.wrapper!(context, child, item); - } - return child; - } + Widget get header => widget.header ?? SizedBox.shrink(); + Widget get footer => widget.footer ?? SizedBox.shrink(); Widget listBuilder(BuildContext context, List items){ - ///Simple List - late Widget list; + final scrollPhysics = widget.physics != null ? widget.physics : widget.disableScroll == true ? NeverScrollableScrollPhysics() : BouncingScrollPhysics(parent: AlwaysScrollableScrollPhysics()); + final controller = widget.usePrimaryScrollController ? null : scrollController; + final footerHeightAdjustment = Container( + height: widget.footerHeight ?? 0, + ); if(items.isEmpty){ - list = SizedBox.shrink(); + return SizedBox.shrink(); } else if(widget.gridDelegate != null){ //Grid list - list = StaggeredGridView.countBuilder( - reverse: widget.reverse, - physics: NeverScrollableScrollPhysics(), - shrinkWrap: true, - addRepaintBoundaries: true, - crossAxisCount: widget.gridDelegate!.crossAxisCount, - mainAxisSpacing: widget.gridDelegate!.mainAxisSpacing, - crossAxisSpacing: widget.gridDelegate!.crossAxisSpacing, - padding: widget.gridDelegate!.padding, - itemCount: items.length + 1, - itemBuilder: (context, i) => widget.builder(context, i, items), - staggeredTileBuilder: (index) => StaggeredTile.fit(1), + Widget list = Column( + children: [ + + header, + + StaggeredGridView.countBuilder( + reverse: widget.reverse, + physics: NeverScrollableScrollPhysics(), + shrinkWrap: true, + addRepaintBoundaries: true, + crossAxisCount: widget.gridDelegate!.crossAxisCount, + mainAxisSpacing: widget.gridDelegate!.mainAxisSpacing, + crossAxisSpacing: widget.gridDelegate!.crossAxisSpacing, + padding: widget.gridDelegate!.padding, + itemCount: items.length + 1, + itemBuilder: (context, i) => widget.builder(context, i, items), + staggeredTileBuilder: (index) => StaggeredTile.fit(1), + ), + + footer, + + footerHeightAdjustment + ], ); + + if(widget.compact){ + return list; + } + else{ + return SingleChildScrollView( + reverse: widget.reverse, + physics: scrollPhysics, + controller: controller, + child: list, + ); + } } else{ - list = ListView.builder( + return ListView.builder( + controller: controller, reverse: widget.reverse, padding: EdgeInsets.zero, shrinkWrap: true, addRepaintBoundaries: true, - physics: NeverScrollableScrollPhysics(), - itemCount: items.length + 1, - itemBuilder: (context, i) => widget.builder(context, i, items), + physics: widget.compact ? NeverScrollableScrollPhysics() : scrollPhysics, + itemCount: items.length + 3, + itemBuilder: (context, i){ + if(i == 0){ + return header; + } + else if(i == items.length){ + //footer + return Column( + mainAxisSize: MainAxisSize.min, + children: [ + footer, + footerHeightAdjustment + ], + ); + } + else{ + //items + return widget.builder(context, i - 1, items); + } + }, ); } - return Column( - children: [ - wrapperBuilder( - context: context, - child: list, - item: items.isEmpty ? null : items[0] - ), - - Container( - height: widget.footerHeight ?? 0, - ) - ], - ); } @@ -164,21 +190,9 @@ class _FeedListViewState extends State { distinct: true, converter: (store) => store.state.items, builder: (context, items) { - - late Widget list = listBuilder(context, items); - - if(!widget.compact){ - list = SingleChildScrollView( - reverse: widget.reverse, - physics: widget.physics != null ? widget.physics : widget.disableScroll == true ? NeverScrollableScrollPhysics() : BouncingScrollPhysics(parent: AlwaysScrollableScrollPhysics()), - controller: widget.usePrimaryScrollController ? null : scrollController, - child: list, - ); - } - return Container( height: widget.compact ? null : MediaQuery.of(context).size.height, - child: list, + child: listBuilder(context, items), ); } ), diff --git a/lib/feeds/sliding_sheet_feed.dart b/lib/feeds/sliding_sheet_feed.dart index ace7935..de7b528 100644 --- a/lib/feeds/sliding_sheet_feed.dart +++ b/lib/feeds/sliding_sheet_feed.dart @@ -33,12 +33,15 @@ class SlidingSheetFeed extends StatelessWidget { /// Loading widget final Widget? loading; + /// Loading widget + final Widget? header; + + /// Loading widget + final Widget? footer; + ///Retrieves the item id, used to ensure the prevention of duplicate additions final RetrievalFunction? getItemID; - ///The optional function used to wrap the list view - final WidgetWrapper? wrapper; - /// Items that will be pinned to the top of the list on init final List? pinnedItems; @@ -92,8 +95,9 @@ class SlidingSheetFeed extends StatelessWidget { this.disableScroll, this.placeholder, this.loading, + this.header, + this.footer, this.getItemID, - this.wrapper, this.pinnedItems, this.sheetController, this.staticSheet = false, @@ -138,8 +142,9 @@ class SlidingSheetFeed extends StatelessWidget { disableScroll: disableScroll, placeholder: placeholder, loading: loading, + feedHeader: header, + feedFooter: footer, getItemID: getItemID, - wrapper: wrapper, pinnedItems: pinnedItems, header: headerBuilder, staticScrollModifier: staticScrollModifier @@ -175,12 +180,15 @@ class PerceiveSlidableSingleFeedDelegate extends ScrollablePerceiveSlidableDeleg /// Loading widget final Widget? loading; + /// Loading widget + final Widget? feedHeader; + + /// Loading widget + final Widget? feedFooter; + ///Retrieves the item id, used to ensure the prevention of duplicate additions final RetrievalFunction? getItemID; - ///The optional function used to wrap the list view - final WidgetWrapper? wrapper; - /// Items that will be pinned to the top of the list on init final List? pinnedItems; @@ -188,6 +196,8 @@ class PerceiveSlidableSingleFeedDelegate extends ScrollablePerceiveSlidableDeleg PerceiveSlidableSingleFeedDelegate({ required this.loader, + required this.feedHeader, + required this.feedFooter, required this.controller, required this.footerHeight, required this.lengthFactor, @@ -198,7 +208,6 @@ class PerceiveSlidableSingleFeedDelegate extends ScrollablePerceiveSlidableDeleg required this.placeholder, required this.loading, required this.getItemID, - required this.wrapper, required this.pinnedItems, required this.header, double staticScrollModifier = 0.0 @@ -216,6 +225,8 @@ class PerceiveSlidableSingleFeedDelegate extends ScrollablePerceiveSlidableDeleg footerHeight: (this.footerHeight ?? 0) + footerHeight, scrollController: scrollController, loader: loader, + header: feedHeader, + footer: feedFooter, controller: controller, lengthFactor: lengthFactor, initialLength: initialLength, @@ -225,7 +236,6 @@ class PerceiveSlidableSingleFeedDelegate extends ScrollablePerceiveSlidableDeleg placeholder: placeholder?.call(context, state?.extent ?? initialExtent), loading: loading, getItemID: getItemID, - wrapper: wrapper, pinnedItems: pinnedItems, ); } diff --git a/lib/feeds/sliding_sheet_multi_feed.dart b/lib/feeds/sliding_sheet_multi_feed.dart index 784bc97..67b084d 100644 --- a/lib/feeds/sliding_sheet_multi_feed.dart +++ b/lib/feeds/sliding_sheet_multi_feed.dart @@ -74,6 +74,8 @@ class SlidingSheetMultiFeed extends StatelessWidget { Widget? loading, RetrievalFunction? getItemID, IndexWidgetWrapper? wrapper, + final Widget? Function(BuildContext context, int pageIndex)? feedHeader, + final Widget? Function(BuildContext context, int pageIndex)? feedFooter, List>? pinnedItems, Widget Function(BuildContext context, dynamic pageObj, Widget spacer, double borderRadius)? headerBuilder, PerceiveSlidableController? sheetController, @@ -102,7 +104,8 @@ class SlidingSheetMultiFeed extends StatelessWidget { placeholders: placeholders, loading: loading, getItemID: getItemID, - wrapper: wrapper, + feedHeader: feedHeader, + feedFooter: feedFooter, pinnedItems: pinnedItems, header: headerBuilder, staticScrollModifier: staticScrollModifier @@ -202,7 +205,10 @@ class PerceiveSlidableMultiFeedDelegate extends ScrollablePerceiveSlidableDelega final RetrievalFunction? getItemID; ///The optional function used to wrap the list view - final IndexWidgetWrapper? wrapper; + final Widget? Function(BuildContext context, int pageIndex)? feedHeader; + + ///The optional function used to wrap the list view + final Widget? Function(BuildContext context, int pageIndex)? feedFooter; /// Items that will be pinned to the top of the list on init final List>? pinnedItems; @@ -221,7 +227,8 @@ class PerceiveSlidableMultiFeedDelegate extends ScrollablePerceiveSlidableDelega required this.placeholders, required this.loading, required this.getItemID, - required this.wrapper, + required this.feedHeader, + required this.feedFooter, required this.pinnedItems, required this.header, int? initialPage, @@ -229,8 +236,12 @@ class PerceiveSlidableMultiFeedDelegate extends ScrollablePerceiveSlidableDelega double staticScrollModifier = 0.0 }) : super(pageCount: loaders.length, initialPage: initialPage ?? ((loaders.length - 1)/2).ceil(), delegateObject: delegateObject, staticScrollModifier: staticScrollModifier); - Widget feedWrapperBuilder(BuildContext context, Widget child, dynamic item, int pageIndex){ - return wrapper?.call(context, child, pageIndex) ?? child; + Widget? feedHeaderBuilder(BuildContext context, int pageIndex){ + return feedHeader?.call(context, pageIndex); + } + + Widget? feedFooterBuilder(BuildContext context, int pageIndex){ + return feedFooter?.call(context, pageIndex); } Widget? placeholderBuilder(BuildContext context, double extent, int pageIndex){ @@ -266,7 +277,8 @@ class PerceiveSlidableMultiFeedDelegate extends ScrollablePerceiveSlidableDelega placeholder: placeholderBuilder(context, state?.extent ?? initialExtent, pageIndex), loading: loadingBuilder.call(context, pageIndex), getItemID: getItemID, - wrapper: (context, child, item) => feedWrapperBuilder(context, child, item, pageIndex), + header: feedHeaderBuilder(context, pageIndex), + footer: feedFooterBuilder(context, pageIndex), pinnedItems: pinnedItems?.where((e) => e.item2 == pageIndex).toList(), ); }