import 'package:carousel_slider/carousel_slider.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:hoshan/ui/theme/colors.dart'; import 'package:hoshan/ui/theme/cubit/theme_mode_cubit.dart'; import 'package:hoshan/ui/theme/text.dart'; import 'package:hoshan/ui/widgets/components/dropdown/simple_dropdown.dart'; import 'package:shamsi_date/shamsi_date.dart'; class PersianDatePicker extends StatefulWidget { final double dateHeight; final Function(List)? onDates; final Function(List)? onConfirm; final Function()? onDismise; final bool hasConfirm; final bool weekSelect; final int? dateCounts; final List? selectedDates; const PersianDatePicker({ super.key, this.dateHeight = 32, this.onDates, this.dateCounts, this.onConfirm, this.hasConfirm = true, this.onDismise, this.selectedDates, this.weekSelect = false, }); @override State createState() => _PersianDatePickerState(); } class _PersianDatePickerState extends State { final Jalali initialDate = Jalali.now(); final Jalali startDate = Jalali(1390); late int persianMonthIndex = initialDate.month; late String persianYearSelected = initialDate.year.toString(); final CarouselSliderControllerImpl controllerImpl = CarouselSliderControllerImpl(); late final List selectedDates = widget.selectedDates ?? []; List persianMonths = [ "فروردین", "اردیبهشت", "خرداد", "تیر", "مرداد", "شهریور", "مهر", "آبان", "آذر", "دی", "بهمن", "اسفند" ]; List daysOfWeek = [ "شنبه", "یک شنبه", "دو شنبه", "سه شنبه", "چهار شنبه", "پنج شنبه", "جمعه" ]; List days = []; List getDaysOfMonth() { final List days = []; final date = Jalali(int.parse(persianYearSelected), persianMonthIndex); int monthLength = date.monthLength; final day = Jalali(int.parse(persianYearSelected), persianMonthIndex, 1); int index = daysOfWeek.indexOf(day.formatter.wN); for (var i = 0; i < index; i++) { days.add(0); } for (var i = 1; i <= monthLength; i++) { days.add(i); } this.days = days; return days; } List years = []; @override void initState() { super.initState(); for (var i = 0; i <= initialDate.year - startDate.year; i++) { years.add((startDate.year + i).toString()); } years = years.reversed.toList(); } @override Widget build(BuildContext context) { return Directionality( textDirection: TextDirection.rtl, child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( 'انتخاب تاریخ', style: AppTextStyles.body4.copyWith( fontWeight: FontWeight.bold, color: Theme.of(context).colorScheme.onSurface), ), const SizedBox( height: 8, ), Text( 'تاریخ روز: ${initialDate.day} ${persianMonths[initialDate.month - 1]} ${initialDate.year}', style: AppTextStyles.body4.copyWith( color: AppColors .gray[context.read().isDark() ? 600 : 900]), ), const SizedBox( height: 16, ), Row( children: [ Expanded( child: SimpleDropdown( initialItem: years.first, list: years, onSelect: (selected) { setState(() { persianYearSelected = years[selected]; }); }, ), ), const SizedBox( width: 12, ), Expanded( child: SimpleDropdown( initialItem: persianMonths[persianMonthIndex - 1], list: persianMonths, onSelect: (selected) { controllerImpl .animateToPage(selected) .then((value) => setState(() { persianMonthIndex = selected + 1; })); }, ), ), ], ), GridView.builder( shrinkWrap: true, itemCount: daysOfWeek.length, gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount( crossAxisCount: 7, crossAxisSpacing: 16, mainAxisSpacing: 16), itemBuilder: (context, index) { return Container( alignment: Alignment.center, child: Text( daysOfWeek[index].split(' ').first, style: AppTextStyles.body5, maxLines: 1, overflow: TextOverflow.ellipsis, ), ); }, ), CarouselSlider.builder( carouselController: controllerImpl, itemBuilder: (context, index, realIndex) { return GridView.builder( shrinkWrap: true, itemCount: getDaysOfMonth().length, gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( crossAxisCount: 7, crossAxisSpacing: 8, mainAxisSpacing: 8, mainAxisExtent: widget.dateHeight), itemBuilder: (context, index) { return days[index] == 0 ? const SizedBox() : GestureDetector( onTap: () { setState(() { final date = Jalali( int.parse(persianYearSelected), persianMonthIndex, days[index]); if (date > Jalali.now()) return; if (widget.weekSelect) { if (selectedDates.isEmpty) { selectedDates.add(date); } else if (selectedDates.length == 7) { selectedDates.clear(); selectedDates.add(date); } else { final today = Jalali.now(); if (date == selectedDates.first) { selectedDates.remove(date); } else if (date > selectedDates.first) { if (selectedDates.first.addDays(6) <= today) { for (int i = 1; i <= 6; i++) { selectedDates.add( selectedDates.first.addDays(i)); } } } else { for (int i = 1; i <= 6; i++) { selectedDates .add(selectedDates.first.addDays(-i)); } } } } else { if (selectedDates.contains(date)) { selectedDates.remove(date); } else { if (widget.dateCounts != null && selectedDates.length == widget.dateCounts) { if (selectedDates.length == 1 && widget.dateCounts == 1) { selectedDates.clear(); selectedDates.add(date); } return; } selectedDates.add(date); } } }); }, child: Container( width: widget.dateHeight, height: widget.dateHeight, alignment: Alignment.center, decoration: BoxDecoration( shape: BoxShape.circle, border: persianMonthIndex == (initialDate.month) && (days[index]) == initialDate.day && (selectedDates.contains(Jalali( int.parse(persianYearSelected), persianMonthIndex, days[index]))) ? Border.all( width: 2, color: Theme.of(context) .colorScheme .secondary) : null, color: persianMonthIndex == (initialDate.month) && (days[index]) == initialDate.day ? context.read().isDark() ? Theme.of(context) .colorScheme .onSurface .withAlpha(80) : AppColors.primaryColor[50] : selectedDates.contains(Jalali( int.parse(persianYearSelected), persianMonthIndex, days[index])) ? Theme.of(context) .colorScheme .secondary : null), child: Text( '${days[index]}', style: AppTextStyles.body5.copyWith( color: selectedDates.contains(Jalali( int.parse(persianYearSelected), persianMonthIndex, days[index])) && !(persianMonthIndex == (initialDate.month) && (days[index]) == initialDate.day) ? Colors.white : Theme.of(context) .colorScheme .onSurface), ), ), ); }, ); }, itemCount: persianMonths.length, options: CarouselOptions( viewportFraction: 1, initialPage: persianMonthIndex - 1, disableCenter: false, enableInfiniteScroll: true, reverse: false, autoPlay: false, autoPlayCurve: Curves.fastOutSlowIn, enlargeCenterPage: true, enlargeFactor: 0.3, height: 6 * widget.dateHeight + 16, onPageChanged: (index, reason) { setState(() { if (reason == CarouselPageChangedReason.manual) { persianMonthIndex = index + 1; } }); }, scrollDirection: Axis.horizontal, ), ), if (widget.hasConfirm) Column( children: [ Divider( color: AppColors.gray.defaultShade, ), Padding( padding: const EdgeInsets.symmetric(vertical: 8, horizontal: 12), child: Row( mainAxisAlignment: MainAxisAlignment.end, children: [ GestureDetector( onTap: () { widget.onDismise?.call(); }, child: Text( 'انصراف', style: AppTextStyles.body4.copyWith( color: AppColors.gray[ context.read().isDark() ? 600 : 900]), ), ), const SizedBox( width: 24, ), GestureDetector( onTap: () { widget.onConfirm?.call(selectedDates); }, child: Text( 'تایید', style: AppTextStyles.body4.copyWith( color: Theme.of(context).colorScheme.primary), ), ), ], ), ) ], ), ], ), ); } }