import 'dart:async'; import 'package:flutter/material.dart'; import 'carousel_options.dart'; import 'carousel_state.dart'; import 'utils.dart'; abstract class CarouselController { bool get ready; Future get onReady; Future nextPage({Duration? duration, Curve? curve}); Future previousPage({Duration? duration, Curve? curve}); void jumpToPage(int page); Future animateToPage(int page, {Duration? duration, Curve? curve}); void startAutoPlay(); void stopAutoPlay(); factory CarouselController() => CarouselControllerImpl(); } class CarouselControllerImpl implements CarouselController { final Completer _readyCompleter = Completer(); CarouselState? _state; set state(CarouselState? state) { _state = state; if (!_readyCompleter.isCompleted) { _readyCompleter.complete(); } } void _setModeController() => _state!.changeMode(CarouselPageChangedReason.controller); @override bool get ready => _state != null; @override Future get onReady => _readyCompleter.future; /// Animates the controlled [CarouselSlider] to the next page. /// /// The animation lasts for the given duration and follows the given curve. /// The returned [Future] resolves when the animation completes. Future nextPage( {Duration? duration = const Duration(milliseconds: 300), Curve? curve = Curves.linear}) async { final bool isNeedResetTimer = _state!.options.pauseAutoPlayOnManualNavigate; if (isNeedResetTimer) { _state!.onResetTimer(); } _setModeController(); await _state!.pageController!.nextPage(duration: duration!, curve: curve!); if (isNeedResetTimer) { _state!.onResumeTimer(); } } /// Animates the controlled [CarouselSlider] to the previous page. /// /// The animation lasts for the given duration and follows the given curve. /// The returned [Future] resolves when the animation completes. Future previousPage( {Duration? duration = const Duration(milliseconds: 300), Curve? curve = Curves.linear}) async { final bool isNeedResetTimer = _state!.options.pauseAutoPlayOnManualNavigate; if (isNeedResetTimer) { _state!.onResetTimer(); } _setModeController(); await _state!.pageController! .previousPage(duration: duration!, curve: curve!); if (isNeedResetTimer) { _state!.onResumeTimer(); } } /// Changes which page is displayed in the controlled [CarouselSlider]. /// /// Jumps the page position from its current value to the given value, /// without animation, and without checking if the new value is in range. void jumpToPage(int page) { final index = getRealIndex(_state!.pageController!.page!.toInt(), _state!.realPage - _state!.initialPage, _state!.itemCount); _setModeController(); final int pageToJump = _state!.pageController!.page!.toInt() + page - index; return _state!.pageController!.jumpToPage(pageToJump); } /// Animates the controlled [CarouselSlider] from the current page to the given page. /// /// The animation lasts for the given duration and follows the given curve. /// The returned [Future] resolves when the animation completes. Future animateToPage(int page, {Duration? duration = const Duration(milliseconds: 300), Curve? curve = Curves.linear}) async { final bool isNeedResetTimer = _state!.options.pauseAutoPlayOnManualNavigate; if (isNeedResetTimer) { _state!.onResetTimer(); } final index = getRealIndex(_state!.pageController!.page!.toInt(), _state!.realPage - _state!.initialPage, _state!.itemCount); int smallestMovement = page - index; if (_state!.options.enableInfiniteScroll && _state!.itemCount != null && _state!.options.animateToClosest) { if ((page - index).abs() > (page + _state!.itemCount! - index).abs()) { smallestMovement = page + _state!.itemCount! - index; } else if ((page - index).abs() > (page - _state!.itemCount! - index).abs()) { smallestMovement = page - _state!.itemCount! - index; } } _setModeController(); await _state!.pageController!.animateToPage( _state!.pageController!.page!.toInt() + smallestMovement, duration: duration!, curve: curve!); if (isNeedResetTimer) { _state!.onResumeTimer(); } } /// Starts the controlled [CarouselSlider] autoplay. /// /// The carousel will only autoPlay if the [autoPlay] parameter /// in [CarouselOptions] is true. void startAutoPlay() { _state!.onResumeTimer(); } /// Stops the controlled [CarouselSlider] from autoplaying. /// /// This is a more on-demand way of doing this. Use the [autoPlay] /// parameter in [CarouselOptions] to specify the autoPlay behaviour of the carousel. void stopAutoPlay() { _state!.onResetTimer(); } }