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