import 'package:carousel_slider/carousel_slider.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; import 'package:hoshan/core/routes/route_generator.dart'; import 'package:hoshan/data/model/banner_model.dart'; import 'package:hoshan/data/model/chat_args.dart'; import 'package:hoshan/ui/screens/main/home_page.dart'; import 'package:hoshan/ui/theme/colors.dart'; import 'package:hoshan/ui/theme/responsive.dart'; import 'package:hoshan/ui/widgets/components/image/network_image.dart'; import 'package:hoshan/ui/widgets/components/slider/custom_carousel_controller.dart'; import 'package:smooth_page_indicator/smooth_page_indicator.dart'; import 'package:string_validator/string_validator.dart'; import 'package:url_launcher/url_launcher.dart'; class CarousleSliderBanners extends StatefulWidget { final List banners; final bool autoPlay; final bool enableInfiniteScroll; final Function(Banners banner)? onClick; const CarousleSliderBanners( {super.key, required this.banners, this.autoPlay = true, this.enableInfiniteScroll = true, this.onClick}); @override State createState() => _CarousleSliderBannersState(); } class _CarousleSliderBannersState extends State { final CustomCarouselController _buttonCarouselController = CustomCarouselController(); @override Widget build(BuildContext context) { final isWeb = Responsive(context).isDesktop(); // Check if the platform is web final isTab = Responsive(context).isTablet(); // Check if the platform is tablet final CarouselOptions carouselOptions = CarouselOptions( viewportFraction: isWeb ? 0.25 // Show 4 banners per slide on web : isTab ? 0.33 // Show 3 banners per slide on tablets : 1, // Default to 1 banner per slide initialPage: 0, disableCenter: false, enableInfiniteScroll: widget.enableInfiniteScroll, reverse: false, autoPlay: widget.autoPlay, autoPlayCurve: Curves.fastOutSlowIn, enlargeCenterPage: true, enlargeFactor: 0, onPageChanged: (index, _) {}, scrollDirection: Axis.horizontal, aspectRatio: 16 / 9, height: isWeb ? MediaQuery.sizeOf(context).height * 0.2 : isTab ? MediaQuery.sizeOf(context).height * 0.25 : null, // Adjust height for web and tablets ); return Column( children: [ CarouselSlider.builder( carouselController: _buttonCarouselController, itemCount: widget.banners.length, itemBuilder: (context, index, realIndex) { final banner = widget.banners[index]; return GestureDetector( onTap: () async { if (banner.bot != null) { if (banner.bot?.tool ?? false) { context.go(Routes.assistant, extra: banner.bot!.id); } else { context.go(Routes.chat, extra: ChatArgs(bot: banner.bot!)); } } else if (banner.link != null) { if (banner.link!.isURL()) { await launchUrl(Uri.parse(banner.link!), mode: LaunchMode.externalApplication) .onError( (error, stackTrace) { if (kDebugMode) { print('error open Link is: $error'); } return false; }, ); } else { try { if (banner.link!.contains('navigate')) { int? index; if (banner.link!.contains('home')) { index = 0; } else if (banner.link!.contains('assisstant')) { index = 1; } else if (banner.link!.contains('media')) { index = 2; } else if (banner.link!.contains('characters')) { index = 3; } else if (banner.link!.contains('setting')) { index = 4; } screenIndex.value = index!; } else { context.go(banner.link!); } } catch (e) { if (kDebugMode) { print('Error is: $e'); } } } } widget.onClick?.call(banner); }, child: sliderView(banner)); }, options: carouselOptions), if (widget.banners.length > 1) sliderIndicator(), ], ); } Widget sliderView(Banners banner) { return Padding( padding: const EdgeInsets.all(16), child: ImageNetwork( width: double.infinity, url: banner.image ?? '', fit: BoxFit.contain, radius: 16, ), ); } Widget sliderIndicator() { return FutureBuilder( future: _buttonCarouselController.onReady, builder: (context, snapshot) { if (snapshot.connectionState == ConnectionState.done) { _buttonCarouselController.state!.pageController!.addListener(() {}); return SmoothPageIndicator( controller: _buttonCarouselController.state!.pageController!, count: widget.banners.length, effect: ScrollingDotsEffect( dotWidth: 8, dotHeight: 8, activeDotColor: AppColors.secondryColor.defaultShade, dotColor: AppColors.secondryColor[100])); } return const SizedBox(); }); } }