import 'package:carousel_slider/carousel_controller.dart'; import 'package:flutter/material.dart'; import 'package:proxibuy/presentation/ui/theme/responsive.dart'; import 'package:proxibuy/presentation/ui/widgets/carousel/carousel_slider_widget.dart'; // TutorialOverlay class ImageGallary extends ModalRoute { final List urls; final String initialUrl; final CarouselSliderController carouselSliderController = CarouselSliderController(); ImageGallary({required this.urls, required this.initialUrl}); @override Duration get transitionDuration => Duration(milliseconds: 500); @override bool get opaque => false; @override bool get barrierDismissible => true; @override Color get barrierColor => Colors.black.withAlpha(210); @override String get barrierLabel => 'Images'; @override bool get maintainState => true; @override Widget buildPage( BuildContext context, Animation animation, Animation secondaryAnimation, ) { return Material( type: MaterialType.transparency, child: SafeArea( child: _buildOverlayContent(context), ), ); } late final ValueNotifier initialImage = ValueNotifier(initialUrl); Widget _buildOverlayContent(BuildContext context) { double viewportFraction = (1 / (urls.length * (MediaQuery.sizeOf(context).width / 1300))); return Stack( children: [ Column( mainAxisSize: MainAxisSize.max, mainAxisAlignment: MainAxisAlignment.center, children: [ ConstrainedBox( constraints: BoxConstraints( maxHeight: MediaQuery.sizeOf(context).height / 2), child: ValueListenableBuilder( valueListenable: initialImage, builder: (context, value, child) { return InteractiveViewer( boundaryMargin: EdgeInsets.all(80), minScale: 0.5, maxScale: 4, panEnabled: true, child: AspectRatio( aspectRatio: Responsive(context).isMobile() ? 1 / 1 : 16 / 9, child: Container( margin: const EdgeInsets.all(32.0), child: GestureDetector( onHorizontalDragEnd: (details) { if (details.primaryVelocity! < 0) { // Swiped left carouselSliderController.nextPage(); } else if (details.primaryVelocity! > 0) { // Swiped right carouselSliderController.previousPage(); } }, child: ClipRRect( borderRadius: BorderRadius.circular(8), child: Image.network( value, ), ), ), ), ), ); }, ), ), CarouselSliderWidget( controller: carouselSliderController ..onReady.then( (value) { carouselSliderController .jumpToPage(urls.indexOf(initialImage.value)); }, ), items: urls, withInds: false, autoPlay: false, enableInfiniteScroll: false, enlargeCenterPage: false, viewportFraction: viewportFraction, aspectRatio: 1 / 1, height: 120, onPageChanged: (index, reason) { initialImage.value = urls[index]; }, onPageBuilder: (context, item, index) { return Container( decoration: BoxDecoration( color: Theme.of(context).colorScheme.surface, borderRadius: BorderRadius.only( topLeft: index == 0 ? Radius.circular(16) : Radius.zero, bottomLeft: index == 0 ? Radius.circular(16) : Radius.zero, bottomRight: index == urls.length - 1 ? Radius.circular(16) : Radius.zero, topRight: index == urls.length - 1 ? Radius.circular(16) : Radius.zero)), padding: EdgeInsets.all(16), child: InkWell( onTap: () { carouselSliderController.animateToPage(index); }, child: SizedBox( child: Image.network( item, fit: BoxFit.cover, ), ), ), ); }, ), ], ), Positioned( top: 32, left: 32, child: InkWell( onTap: () { Navigator.pop(context); }, child: Container( decoration: BoxDecoration( color: Theme.of(context).colorScheme.surface, borderRadius: BorderRadius.circular(8)), padding: EdgeInsets.all(8), child: Icon(Icons.arrow_back_ios_new_rounded), ), ), ), ], ); } @override Widget buildTransitions(BuildContext context, Animation animation, Animation secondaryAnimation, Widget child) { // You can add your own animations for the overlay content return FadeTransition( opacity: animation, child: ScaleTransition( scale: animation, child: child, ), ); } }