LCOV - code coverage report
Current view: top level - src - lazy_load_scroll_view.dart (source / functions) Hit Total Coverage
Test: lcov.info Lines: 50 50 100.0 %
Date: 2021-05-27 10:59:48 Functions: 0 0 -

          Line data    Source code
       1             : import 'package:flutter/foundation.dart';
       2             : import 'package:flutter/widgets.dart';
       3             : 
       4          10 : enum _LoadingStatus { loading, stable }
       5             : 
       6             : /// Wrapper around a [Scrollable] which triggers [onEndOfPage]/[onStartOfPage] the Scrollable
       7             : /// reaches to the start or end of the view extent.
       8             : class LazyLoadScrollView extends StatefulWidget {
       9             :   /// Creates a new instance of [LazyLoadScrollView]. The parameter [child]
      10             :   /// must be supplied and not null.
      11           1 :   const LazyLoadScrollView({
      12             :     Key? key,
      13             :     required this.child,
      14             :     this.onStartOfPage,
      15             :     this.onEndOfPage,
      16             :     this.onPageScrollStart,
      17             :     this.onPageScrollEnd,
      18             :     this.onInBetweenOfPage,
      19             :     this.scrollOffset = 100,
      20           1 :   }) : super(key: key);
      21             : 
      22             :   /// The [Widget] that this widget watches for changes on
      23             :   final Widget child;
      24             : 
      25             :   /// Called when the [child] reaches the start of the list
      26             :   final AsyncCallback? onStartOfPage;
      27             : 
      28             :   /// Called when the [child] reaches the end of the list
      29             :   final AsyncCallback? onEndOfPage;
      30             : 
      31             :   /// Called when the list scrolling starts
      32             :   final VoidCallback? onPageScrollStart;
      33             : 
      34             :   /// Called when the list scrolling ends
      35             :   final VoidCallback? onPageScrollEnd;
      36             : 
      37             :   /// Called every time the [child] is in-between the list
      38             :   final VoidCallback? onInBetweenOfPage;
      39             : 
      40             :   /// The offset to take into account when triggering [onEndOfPage]/[onStartOfPage] in pixels
      41             :   final double scrollOffset;
      42             : 
      43           1 :   @override
      44           1 :   State<StatefulWidget> createState() => _LazyLoadScrollViewState();
      45             : }
      46             : 
      47             : class _LazyLoadScrollViewState extends State<LazyLoadScrollView> {
      48             :   var _loadMoreStatus = _LoadingStatus.stable;
      49             :   double _scrollPosition = 0;
      50             : 
      51           1 :   @override
      52             :   Widget build(BuildContext context) =>
      53           1 :       NotificationListener<ScrollNotification>(
      54           1 :         onNotification: _onNotification,
      55           2 :         child: widget.child,
      56             :       );
      57             : 
      58           1 :   bool _onNotification(ScrollNotification notification) {
      59           1 :     if (notification is ScrollStartNotification) {
      60           2 :       if (widget.onPageScrollStart != null) {
      61           3 :         widget.onPageScrollStart!();
      62             :         return true;
      63             :       }
      64             :     }
      65           1 :     if (notification is ScrollEndNotification) {
      66           2 :       if (widget.onPageScrollEnd != null) {
      67           3 :         widget.onPageScrollEnd!();
      68             :         return true;
      69             :       }
      70             :     }
      71           1 :     if (notification is ScrollUpdateNotification) {
      72           2 :       final pixels = notification.metrics.pixels;
      73           2 :       final maxScrollExtent = notification.metrics.maxScrollExtent;
      74           2 :       final minScrollExtent = notification.metrics.minScrollExtent;
      75           2 :       final scrollOffset = widget.scrollOffset;
      76             : 
      77           2 :       if (pixels > (minScrollExtent + scrollOffset) &&
      78           2 :           pixels < (maxScrollExtent - scrollOffset)) {
      79           2 :         if (widget.onInBetweenOfPage != null) {
      80           3 :           widget.onInBetweenOfPage!();
      81             :           return true;
      82             :         }
      83             :       }
      84             : 
      85           2 :       final extentBefore = notification.metrics.extentBefore;
      86           2 :       final extentAfter = notification.metrics.extentAfter;
      87           2 :       final scrollingDown = _scrollPosition < pixels;
      88             : 
      89             :       if (scrollingDown) {
      90           1 :         if (extentAfter <= scrollOffset) {
      91           1 :           _onEndOfPage();
      92             :           return true;
      93             :         }
      94             :       } else {
      95           1 :         if (extentBefore <= scrollOffset) {
      96           1 :           _onStartOfPage();
      97             :           return true;
      98             :         }
      99             :       }
     100             : 
     101           1 :       _scrollPosition = pixels;
     102             :     }
     103           1 :     if (notification is OverscrollNotification) {
     104           2 :       if (notification.overscroll > 0) {
     105           1 :         _onEndOfPage();
     106             :       }
     107           2 :       if (notification.overscroll < 0) {
     108           1 :         _onStartOfPage();
     109             :       }
     110             :       return true;
     111             :     }
     112             :     return false;
     113             :   }
     114             : 
     115           1 :   void _onEndOfPage() {
     116           2 :     if (_loadMoreStatus == _LoadingStatus.stable) {
     117           2 :       if (widget.onEndOfPage != null) {
     118           1 :         _loadMoreStatus = _LoadingStatus.loading;
     119           5 :         widget.onEndOfPage!().whenComplete(() {
     120           1 :           _loadMoreStatus = _LoadingStatus.stable;
     121             :         });
     122             :       }
     123             :     }
     124             :   }
     125             : 
     126           1 :   void _onStartOfPage() {
     127           2 :     if (_loadMoreStatus == _LoadingStatus.stable) {
     128           2 :       if (widget.onStartOfPage != null) {
     129           1 :         _loadMoreStatus = _LoadingStatus.loading;
     130           5 :         widget.onStartOfPage!().whenComplete(() {
     131           1 :           _loadMoreStatus = _LoadingStatus.stable;
     132             :         });
     133             :       }
     134             :     }
     135             :   }
     136             : }

Generated by: LCOV version 1.14