LCOV - code coverage report
Current view: top level - lib/Provider - LiquidProvider.dart (source / functions) Hit Total Coverage
Test: lcov.info Lines: 119 154 77.3 %
Date: 2021-03-10 21:05:26 Functions: 0 0 -

          Line data    Source code
       1             : import 'dart:async';
       2             : 
       3             : import 'package:flutter/cupertino.dart';
       4             : import 'package:liquid_swipe/Helpers/Helpers.dart';
       5             : import 'package:liquid_swipe/Helpers/slide_update.dart';
       6             : import 'package:liquid_swipe/PageHelpers/animated_page_dragger.dart';
       7             : import 'package:liquid_swipe/PageHelpers/page_dragger.dart';
       8             : import 'package:liquid_swipe/liquid_swipe.dart';
       9             : import 'package:provider/provider.dart';
      10             : 
      11             : /// Internal Class
      12             : ///
      13             : /// A [ChangeNotifierProvider] to manage [LiquidSwipe] State.
      14             : /// Every Change is notified from it.
      15             : /// Methods Included :
      16             : ///  -  [animateToPage]
      17             : ///  -  [_animateDirectlyToPage]
      18             : ///  -  [jumpToPage]
      19             : ///  -  [updateData]
      20             : ///  -  some more, soon.
      21             : class LiquidProvider extends ChangeNotifier {
      22             :   /// A [SlideUpdate] type for storing the current Slide Update.
      23             :   SlideUpdate? slideUpdate;
      24             : 
      25             :   /// [AnimatedPageDragger] required for completing the animation when [UpdateType] is [UpdateType.doneAnimating]
      26             :   late AnimatedPageDragger animatedPageDragger;
      27             : 
      28             :   /// Storing ActivePage Index
      29             :   /// default = 0
      30             :   int activePageIndex = 0;
      31             : 
      32             :   ///Storing next Page Index
      33             :   ///default = 0
      34             :   int nextPageIndex = 0;
      35             : 
      36             :   ///Storing the Swipe Direction using [SlideDirection]
      37             :   SlideDirection slideDirection = SlideDirection.none;
      38             : 
      39             :   /// percentage of slide both Horizontal and Vertical, during touch
      40             :   double slidePercentHor = 0.00;
      41             :   double slidePercentVer = 0.00;
      42             : 
      43             :   ///Storing Previous [UpdateType]
      44             :   UpdateType? prevUpdate;
      45             : 
      46             :   ///user manageable bool to make Enable and Disable loop within the Pages
      47             :   bool enableLoop = true;
      48             : 
      49             :   ///Number of Page.
      50             :   int pagesLength = 0;
      51             : 
      52             :   ///Ticker Provider from [LiquidSwipe], cause need to use it in [AnimatedPageDragger]
      53             :   late TickerProviderStateMixin singleTickerProviderStateMixin;
      54             : 
      55             :   ///SlideIcon position, always Horizontal, used in [PageDragger]
      56             :   late double positionSlideIcon;
      57             : 
      58             :   ///see [CurrentUpdateTypeCallback]
      59             :   CurrentUpdateTypeCallback? _currentUpdateTypeCallback;
      60             : 
      61             :   ///see [OnPageChangeCallback]
      62             :   OnPageChangeCallback? _onPageChangeCallback;
      63             : 
      64             :   ///see [SlidePercentCallback]
      65             :   SlidePercentCallback? _slidePercentCallback;
      66             : 
      67             :   ///bool variable to set if Liquid Swipe is currently in Progress
      68             :   bool isInProgress = false;
      69             : 
      70             :   ///bool to store is its still animating
      71             :   bool _isAnimating = false;
      72             : 
      73             :   ///A user handled value if user want, just only to use programmatic pages changes
      74             :   ///default = false
      75             :   bool shouldDisableUserGesture = false;
      76             : 
      77             :   Size iconSize = Size.zero;
      78             : 
      79             :   Timer? _timer;
      80             :   Timer? _timerInner;
      81             : 
      82             :   ///Constructor
      83             :   ///Contains Default value or Developer desired Values
      84             :   /// [initialPage] - Initial Page of the LiquidSwipe (0 - n)
      85             :   /// [loop]  - Should Enable Loop between Pages
      86             :   /// [length]  - Total Number of Pages
      87           1 :   LiquidProvider(
      88             :       {required int initialPage,
      89             :       required bool loop,
      90             :       required int length,
      91             :       required TickerProviderStateMixin vsync,
      92             :       required double slideIcon,
      93             :       required OnPageChangeCallback? onPageChangeCallback,
      94             :       required CurrentUpdateTypeCallback? currentUpdateTypeCallback,
      95             :       required SlidePercentCallback? slidePercentCallback,
      96             :       required bool disableGesture}) {
      97           1 :     slidePercentHor = 0.00;
      98           1 :     slidePercentVer = 0.00;
      99           1 :     activePageIndex = initialPage;
     100           1 :     nextPageIndex = initialPage;
     101           1 :     enableLoop = loop;
     102           1 :     pagesLength = length;
     103           1 :     singleTickerProviderStateMixin = vsync;
     104           1 :     positionSlideIcon = slideIcon;
     105           1 :     _currentUpdateTypeCallback = currentUpdateTypeCallback;
     106           1 :     _slidePercentCallback = slidePercentCallback;
     107           1 :     _onPageChangeCallback = onPageChangeCallback;
     108           1 :     shouldDisableUserGesture = disableGesture;
     109             : 
     110           2 :     updateSlide(SlideUpdate(
     111             :       SlideDirection.rightToLeft,
     112             :       0.00,
     113           1 :       positionSlideIcon,
     114             :       UpdateType.dragging,
     115             :     ));
     116             :   }
     117             : 
     118             :   ///Animating page to the mentioned page
     119             :   ///
     120             :   ///Known Issue : First we have to jump to the previous screen.
     121             :   ///
     122             :   ///Current Behaviour : Lets say there are 3 pages,
     123             :   ///current page is Red and next is Blue and and last is Green.
     124             :   ///if [page] in this method came to ne 2 i.e., we need to animate directly to Green Page
     125             :   ///but currently I have to jump to page 1 i.e., Blue and than perform Animation using [updateSlide]
     126             :   ///
     127             :   ///Required Behaviour : I Don't want Blue to be there in between the transition of Red and Green i.e.,
     128             :   ///If we are animating [activePageIndex] should be 0 and [nextPageIndex] should be 2, which is not possible through current implementation.
     129             :   ///
     130             :   /// If you encounter this and have suggestions don't forget to raise an Issue.
     131             :   ///
     132             :   ///Not making it for Public usage for now due to the mentioned Issue
     133             :   /// _animateDirectlyToPage(int page, int duration) {
     134             :   ///   if (isInProgress || activePageIndex == page) return;
     135             :   ///   isInProgress = true;
     136             :   ///   activePageIndex = page - 1;
     137             :   ///   nextPageIndex = page;
     138             :   ///   if (activePageIndex < 0) {
     139             :   ///     activePageIndex = 0;
     140             :   ///     jumpToPage(page);
     141             :   ///     return;
     142             :   ///   }
     143             :   ///   _timer = Timer.periodic(const Duration(milliseconds: 1), (t) {
     144             :   ///     if (t.tick < duration / 2) {
     145             :   ///       updateSlide(SlideUpdate(SlideDirection.rightToLeft, t.tick / duration,
     146             :   ///           1, UpdateType.dragging));
     147             :   ///     } else if (t.tick < duration) {
     148             :   ///       updateSlide(SlideUpdate(SlideDirection.rightToLeft, t.tick / duration,
     149             :   ///           1, UpdateType.animating));
     150             :   ///     } else {
     151             :   ///       updateSlide(SlideUpdate(
     152             :   ///           SlideDirection.rightToLeft, 1, 1, UpdateType.doneAnimating));
     153             :   ///       t.cancel();
     154             :   ///       isInProgress = false;
     155             :   ///     }
     156             :   ///   });
     157             :   /// }
     158             :   ///
     159             :   ///Animating to the Page in One-by-One manner
     160             :   ///Required parameters :
     161             :   /// - [page], the page index you want to animate to.
     162             :   /// - [duration], of [Duration] type, for complete animation
     163           1 :   animateToPage(int page, int duration) {
     164           3 :     if (isInProgress || activePageIndex == page) return;
     165           1 :     isInProgress = true;
     166             :     int diff = 0;
     167           1 :     _timer?.cancel();
     168           1 :     _timerInner?.cancel();
     169           2 :     if (activePageIndex < page) {
     170           2 :       diff = page - activePageIndex;
     171           1 :       int newDuration = duration ~/ diff;
     172           3 :       _timer = Timer.periodic(Duration(milliseconds: newDuration), (callback) {
     173           0 :         _timerInner = Timer.periodic(const Duration(milliseconds: 1), (t) {
     174           0 :           if (t.tick < newDuration / 2) {
     175           0 :             updateSlide(SlideUpdate(SlideDirection.rightToLeft,
     176           0 :                 t.tick / newDuration, positionSlideIcon, UpdateType.dragging));
     177           0 :           } else if (t.tick < newDuration) {
     178           0 :             updateSlide(SlideUpdate(SlideDirection.rightToLeft,
     179           0 :                 t.tick / newDuration, positionSlideIcon, UpdateType.animating));
     180             :           } else {
     181           0 :             updateSlide(SlideUpdate(SlideDirection.rightToLeft, 1,
     182           0 :                 positionSlideIcon, UpdateType.doneAnimating));
     183           0 :             t.cancel();
     184             :           }
     185             :         });
     186           0 :         if (callback.tick >= diff) {
     187           0 :           callback.cancel();
     188           0 :           isInProgress = false;
     189             :         }
     190             :       });
     191             :     } else {
     192           2 :       diff = activePageIndex - page;
     193           1 :       int newDuration = duration ~/ diff;
     194           3 :       _timer = Timer.periodic(Duration(milliseconds: newDuration), (callback) {
     195           0 :         _timerInner = Timer.periodic(const Duration(milliseconds: 1), (t) {
     196           0 :           if (t.tick < newDuration / 2) {
     197           0 :             updateSlide(SlideUpdate(SlideDirection.leftToRight,
     198           0 :                 t.tick / newDuration, positionSlideIcon, UpdateType.dragging));
     199           0 :           } else if (t.tick < newDuration) {
     200           0 :             updateSlide(SlideUpdate(SlideDirection.leftToRight,
     201           0 :                 t.tick / newDuration, positionSlideIcon, UpdateType.animating));
     202             :           } else {
     203           0 :             updateSlide(SlideUpdate(SlideDirection.leftToRight, 1,
     204           0 :                 positionSlideIcon, UpdateType.doneAnimating));
     205           0 :             t.cancel();
     206             :           }
     207             :         });
     208           0 :         if (callback.tick >= diff) {
     209           0 :           callback.cancel();
     210           0 :           isInProgress = false;
     211             :         }
     212             :       });
     213             :     }
     214             :   }
     215             : 
     216             :   ///Directly Jump to the mentioned [page] without any animation
     217           1 :   jumpToPage(int page) {
     218           3 :     if (page == activePageIndex || isInProgress) return;
     219           4 :     if (page > pagesLength - 1 || page < 0) {
     220           0 :       throw ("Index $page not found in the Pages list");
     221             :     }
     222           1 :     isInProgress = true;
     223           2 :     activePageIndex = page - 1;
     224           1 :     nextPageIndex = page;
     225           3 :     if (nextPageIndex >= pagesLength) nextPageIndex = 0;
     226           3 :     updateSlide(SlideUpdate(SlideDirection.rightToLeft, 1, positionSlideIcon,
     227             :         UpdateType.doneAnimating));
     228           1 :     isInProgress = false;
     229             :   }
     230             : 
     231             :   ///Method to update the [slideUpdate] and it directly calls [updateData]
     232           1 :   updateSlide(SlideUpdate slidUpdate) {
     233           1 :     slideUpdate = slidUpdate;
     234           1 :     updateData(slidUpdate);
     235           1 :     notifyListeners();
     236             :   }
     237             : 
     238             :   ///updating data using [SlideUpdate], generally we are handling and managing the Animation [UpdateType]
     239             :   ///in this methods,
     240             :   ///All callbacks and factors are also managed by this method.
     241           1 :   updateData(SlideUpdate event) {
     242           4 :     if (prevUpdate != event.updateType && _currentUpdateTypeCallback != null)
     243           3 :       _currentUpdateTypeCallback!(event.updateType);
     244             : 
     245           1 :     if (_slidePercentCallback != null &&
     246           2 :         event.updateType != UpdateType.doneAnimating) {
     247           3 :       String hor = (event.slidePercentHor * 100).toStringAsExponential(2);
     248           3 :       String ver = (event.slidePercentVer * 100).toStringAsExponential(2);
     249           2 :       _slidePercentCallback!(
     250           4 :           double.parse(hor), (((double.parse(ver)) * 100) / 100));
     251             :     }
     252             : 
     253           2 :     prevUpdate = event.updateType;
     254             : 
     255             :     //if the user is dragging then
     256           2 :     if (event.updateType == UpdateType.dragging) {
     257           2 :       slideDirection = event.direction;
     258           2 :       slidePercentHor = event.slidePercentHor;
     259           2 :       slidePercentVer = event.slidePercentVer;
     260             : 
     261             :       // making pages to be in loop
     262           2 :       nextPageIndex = activePageIndex;
     263           1 :       if (enableLoop) {
     264             :         //conditions on slide direction
     265           2 :         if (slideDirection == SlideDirection.leftToRight) {
     266           3 :           nextPageIndex = activePageIndex - 1;
     267           2 :         } else if (slideDirection == SlideDirection.rightToLeft) {
     268           3 :           nextPageIndex = activePageIndex + 1;
     269             :         }
     270             : 
     271           4 :         if (nextPageIndex > pagesLength - 1) {
     272           0 :           nextPageIndex = 0;
     273           2 :         } else if (nextPageIndex < 0) {
     274           3 :           nextPageIndex = pagesLength - 1;
     275             :         }
     276             :         return;
     277             :       }
     278             : 
     279             :       //conditions on slide direction
     280           2 :       if (slideDirection == SlideDirection.leftToRight &&
     281           0 :           activePageIndex != 0) {
     282           0 :         nextPageIndex = activePageIndex - 1;
     283           2 :       } else if (slideDirection == SlideDirection.rightToLeft &&
     284           4 :           activePageIndex != pagesLength - 1) {
     285           3 :         nextPageIndex = activePageIndex + 1;
     286             :       }
     287             :       return;
     288             :     }
     289             :     //if the user has done dragging
     290           2 :     else if (event.updateType == UpdateType.doneDragging) {
     291             :       // slidepercent > 0.2 so that it wont reveal itself unless this condition is true
     292           2 :       if (slidePercentHor > 0.2) {
     293           1 :         isAnimating = true; // Page started to animate
     294             : 
     295           2 :         animatedPageDragger = AnimatedPageDragger(
     296             :           slideUpdateStream: this,
     297           1 :           slideDirection: slideDirection,
     298             :           transitionGoal: TransitionGoal.open,
     299           1 :           slidePercentHor: slidePercentHor,
     300           1 :           slidePercentVer: slidePercentVer,
     301           1 :           vsync: singleTickerProviderStateMixin,
     302             :         );
     303             :       } else {
     304           2 :         animatedPageDragger = AnimatedPageDragger(
     305             :           slideUpdateStream: this,
     306           1 :           slideDirection: slideDirection,
     307             :           transitionGoal: TransitionGoal.close,
     308           1 :           slidePercentHor: slidePercentHor,
     309           1 :           slidePercentVer: slidePercentVer,
     310           1 :           vsync: singleTickerProviderStateMixin,
     311             :         );
     312             : 
     313           2 :         nextPageIndex = activePageIndex;
     314             :       }
     315             :       //Run the animation
     316           2 :       animatedPageDragger.run();
     317             :       return;
     318             :     }
     319             :     //when animating
     320           2 :     else if (event.updateType == UpdateType.animating) {
     321           2 :       slideDirection = event.direction;
     322           2 :       slidePercentHor = event.slidePercentHor;
     323           2 :       slidePercentVer = event.slidePercentVer;
     324             :       return;
     325             :     }
     326             : 
     327             :     //done animating
     328           1 :     if (_onPageChangeCallback != null) {
     329           3 :       _onPageChangeCallback!(nextPageIndex);
     330             :     }
     331           2 :     activePageIndex = nextPageIndex;
     332           1 :     slideDirection = SlideDirection.rightToLeft;
     333           1 :     slidePercentHor = 0.00;
     334           2 :     slidePercentVer = positionSlideIcon;
     335           2 :     nextPageIndex = activePageIndex;
     336             : 
     337           1 :     if (enableLoop) {
     338             :       //conditions on slide direction
     339           2 :       if (slideDirection == SlideDirection.leftToRight) {
     340           0 :         nextPageIndex = activePageIndex - 1;
     341           2 :       } else if (slideDirection == SlideDirection.rightToLeft) {
     342           3 :         nextPageIndex = activePageIndex + 1;
     343             :       }
     344             : 
     345           4 :       if (nextPageIndex > pagesLength - 1) {
     346           1 :         nextPageIndex = 0;
     347           2 :       } else if (nextPageIndex < 0) {
     348           0 :         nextPageIndex = pagesLength - 1;
     349             :       }
     350             :     } else {
     351           2 :       if (slideDirection == SlideDirection.leftToRight &&
     352           0 :           activePageIndex != 0) {
     353           0 :         nextPageIndex = activePageIndex - 1;
     354           2 :       } else if (slideDirection == SlideDirection.rightToLeft &&
     355           4 :           activePageIndex != pagesLength - 1) {
     356           0 :         nextPageIndex = activePageIndex + 1;
     357             :       }
     358             :     }
     359             : 
     360           1 :     isAnimating = false; // Page stopped animating
     361             :     return;
     362             :   }
     363             : 
     364             :   ///Setter for [_isAnimating]
     365           1 :   set isAnimating(bool newValue) {
     366           1 :     this._isAnimating = newValue;
     367           1 :     notifyListeners();
     368             :   }
     369             : 
     370             :   ///Getter for [_isAnimating]
     371           2 :   bool get isAnimating => _isAnimating;
     372             : 
     373             :   ///Setter for [isUserGestureDisabled]
     374           1 :   set setUserGesture(bool disable) {
     375           1 :     this.shouldDisableUserGesture = disable;
     376           1 :     notifyListeners();
     377             :   }
     378             : 
     379             :   ///Setter for [isUserGestureDisabled]
     380           2 :   bool get isUserGestureDisabled => shouldDisableUserGesture;
     381             : 
     382             :   ///Method to set [iconSize]
     383           1 :   setIconSize(Size size) {
     384           1 :     iconSize = size;
     385           1 :     notifyListeners();
     386             :   }
     387             : 
     388           1 :   @override
     389             :   void dispose() {
     390           2 :     _timer?.cancel();
     391           1 :     _timerInner?.cancel();
     392           1 :     super.dispose();
     393             :   }
     394             : }

Generated by: LCOV version 1.15