Updates for Zoom

pull/361/head
haroon amjad 6 days ago
parent 814b0ccd58
commit 636610acce

@ -211,7 +211,7 @@ class ApiClientImp implements ApiClient {
} }
// body['TokenID'] = "@dm!n"; // body['TokenID'] = "@dm!n";
// body['PatientID'] = 3310954; // body['PatientID'] = 945786;
// body['PatientID'] = 53320; // body['PatientID'] = 53320;
// body['PatientTypeID'] = 1; // body['PatientTypeID'] = 1;
// body['PatientOutSA'] = 0; // body['PatientOutSA'] = 0;

@ -2,3 +2,9 @@ const Map configs = {
'ZOOM_SDK_KEY': 'b9T74nhfTg-ioP9urm970A', 'ZOOM_SDK_KEY': 'b9T74nhfTg-ioP9urm970A',
'ZOOM_SDK_SECRET': 'KOzmjBNXQ1f4IPHpnngfL29uZvJMufSy2Fk8', 'ZOOM_SDK_SECRET': 'KOzmjBNXQ1f4IPHpnngfL29uZvJMufSy2Fk8',
}; };
// const Map configs = {
// 'ZOOM_SDK_KEY': 'jYHoRpSUMTTefOwLq94Kyf1Kak513TUHpu78',
// 'ZOOM_SDK_SECRET': 'MOqi1zc18VFOMEaBDshFSHKLB0C2n9M0K48H',
// };

@ -58,6 +58,7 @@ import 'package:hmg_patient_app_new/presentation/notifications/notifications_lis
import 'package:hmg_patient_app_new/presentation/offers_and_discounts/offers_and_discounts_page.dart'; import 'package:hmg_patient_app_new/presentation/offers_and_discounts/offers_and_discounts_page.dart';
import 'package:hmg_patient_app_new/presentation/offers_and_discounts/widgets/offers_and_discounts.dart'; import 'package:hmg_patient_app_new/presentation/offers_and_discounts/widgets/offers_and_discounts.dart';
import 'package:hmg_patient_app_new/presentation/rate_appointment/rate_appointment_doctor.dart'; import 'package:hmg_patient_app_new/presentation/rate_appointment/rate_appointment_doctor.dart';
import 'package:hmg_patient_app_new/presentation/tele_consultation/zoom/call_screen.dart';
import 'package:hmg_patient_app_new/presentation/todo_section/ancillary_procedures_details_page.dart'; import 'package:hmg_patient_app_new/presentation/todo_section/ancillary_procedures_details_page.dart';
import 'package:hmg_patient_app_new/presentation/todo_section/todo_page.dart'; import 'package:hmg_patient_app_new/presentation/todo_section/todo_page.dart';
import 'package:hmg_patient_app_new/presentation/todo_section/widgets/ancillary_orders_list.dart'; import 'package:hmg_patient_app_new/presentation/todo_section/widgets/ancillary_orders_list.dart';
@ -291,6 +292,15 @@ class _LandingPageState extends State<LandingPage> {
page: FamilyMedicalScreen(), page: FamilyMedicalScreen(),
), ),
); );
// Navigator.pushReplacementNamed(
// // context,
// GetIt.instance<NavigationService>().navigatorKey.currentContext!,
// AppRoutes.zoomCallPage,
// // arguments: CallArguments(appointmentID, "111", "Patient", "40", "1", true, 1),
// arguments: CallArguments("yosemite-338", "123", "Patient", "40", "0", true, 1),
// // arguments: CallArguments("SmallDailyStandup9875", "123", "Patient", "40", "0", false, int.parse(widget.incomingCallData!.appointmentNo!)),
// );
}, },
name: ('${appState.getAuthenticatedUser()!.firstName!} ${appState.getAuthenticatedUser()!.lastName!}'), name: ('${appState.getAuthenticatedUser()!.firstName!} ${appState.getAuthenticatedUser()!.lastName!}'),
imageWidget: Selector<ProfileSettingsViewModel, String?>( imageWidget: Selector<ProfileSettingsViewModel, String?>(
@ -314,6 +324,13 @@ class _LandingPageState extends State<LandingPage> {
onPressed: () async { onPressed: () async {
await authVM.onLoginPressed(); await authVM.onLoginPressed();
// Navigator.pushReplacementNamed(
// // context,
// GetIt.instance<NavigationService>().navigatorKey.currentContext!,
// AppRoutes.zoomCallPage,
// arguments: CallArguments("lake-tahoe-289", "123", "Patient", "40", "0", true, 1),
// );
// Navigator.of(context).push( // Navigator.of(context).push(
// CustomPageRoute( // CustomPageRoute(
// // page: NotificationsListPage(), // // page: NotificationsListPage(),

@ -84,7 +84,7 @@ class _CallScreenState extends State<CallScreen> {
//hide status bar //hide status bar
SystemChrome.setEnabledSystemUIMode(SystemUiMode.leanBack); SystemChrome.setEnabledSystemUIMode(SystemUiMode.leanBack);
var circleButtonSize = 65.0; var circleButtonSize = 65.h;
Color backgroundColor = const Color(0xFF232323); Color backgroundColor = const Color(0xFF232323);
Color buttonBackgroundColor = const Color.fromRGBO(0, 0, 0, 0.6); Color buttonBackgroundColor = const Color.fromRGBO(0, 0, 0, 0.6);
Color chatTextColor = const Color(0xFFAAAAAA); Color chatTextColor = const Color(0xFFAAAAAA);
@ -178,12 +178,12 @@ class _CallScreenState extends State<CallScreen> {
// "Join", // "Join",
// arguments: JoinArguments(args.isJoin, sessionName.value, sessionPassword.value, args.displayName, args.sessionIdleTimeoutMins, args.role), // arguments: JoinArguments(args.isJoin, sessionName.value, sessionPassword.value, args.displayName, args.sessionIdleTimeoutMins, args.role),
// ); // );
Navigator.pushAndRemoveUntil( // Navigator.pushAndRemoveUntil(
context, // context,
CustomPageRoute( // CustomPageRoute(
page: LandingNavigation(), // page: LandingNavigation(),
), // ),
(r) => false); // (r) => false);
}); });
final sessionNeedPasswordListener = eventListener.addListener(EventType.onSessionNeedPassword, (data) async { final sessionNeedPasswordListener = eventListener.addListener(EventType.onSessionNeedPassword, (data) async {
@ -1773,15 +1773,16 @@ class _CallScreenState extends State<CallScreen> {
alignment: Alignment.centerRight, alignment: Alignment.centerRight,
child: FractionallySizedBox( child: FractionallySizedBox(
widthFactor: 0.2, widthFactor: 0.2,
heightFactor: 0.6, heightFactor: 0.8,
child: Column( child: Column(
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
children: [ children: [
IconButton( IconButton(
onPressed: onPressAudio, onPressed: onPressAudio,
icon: isMuted.value ? Utils.buildImgWithAssets(icon: "assets/images/png/zoom/unmute@2x.png") : Utils.buildImgWithAssets(icon: "assets/images/png/zoom/mute@2x.png"), icon: isMuted.value
? Utils.buildImgWithAssets(icon: "assets/images/png/zoom/unmute@2x.png", width: circleButtonSize.h, height: circleButtonSize.h)
: Utils.buildImgWithAssets(icon: "assets/images/png/zoom/mute@2x.png", width: circleButtonSize.h, height: circleButtonSize.h),
iconSize: circleButtonSize, iconSize: circleButtonSize,
tooltip: isMuted.value == true ? "Unmute" : "Mute",
), ),
// IconButton( // IconButton(
// onPressed: onPressShare, // onPressed: onPressShare,
@ -1791,7 +1792,9 @@ class _CallScreenState extends State<CallScreen> {
IconButton( IconButton(
onPressed: onPressVideo, onPressed: onPressVideo,
iconSize: circleButtonSize, iconSize: circleButtonSize,
icon: isVideoOn.value ? Utils.buildImgWithAssets(icon: "assets/images/png/zoom/video-off@2x.png") : Utils.buildImgWithAssets(icon: "assets/images/png/zoom/video-on@2x.png"), icon: isVideoOn.value
? Utils.buildImgWithAssets(icon: "assets/images/png/zoom/video-off@2x.png", width: circleButtonSize.h, height: circleButtonSize.h)
: Utils.buildImgWithAssets(icon: "assets/images/png/zoom/video-on@2x.png", width: circleButtonSize.h, height: circleButtonSize.h),
), ),
Column( Column(
children: [ children: [
@ -1808,7 +1811,8 @@ class _CallScreenState extends State<CallScreen> {
), ),
], ],
), ),
)), ),
),
// Container( // Container(
// margin: const EdgeInsets.only(left: 16, right: 16, bottom: 40, top: 10), // margin: const EdgeInsets.only(left: 16, right: 16, bottom: 40, top: 10),
// alignment: Alignment.bottomCenter, // alignment: Alignment.bottomCenter,

@ -56,8 +56,9 @@ class _DateRangeSelectorState extends State<DateRangeSelector> {
late DateRangeSelectorRangeViewModel model; late DateRangeSelectorRangeViewModel model;
PickerViewMode _viewMode = PickerViewMode.date; PickerViewMode _viewMode = PickerViewMode.date;
// Cache for Hijri conversions to avoid repeated calculations // Prevent Syncfusion's initial onViewChanged callback from scheduling an
final Map<String, HijriGregDate> _hijriCache = {}; // unnecessary second build of the same month.
late int _displayedMonthKey;
// Track the current Hijri month/year being displayed (for header display accuracy) // Track the current Hijri month/year being displayed (for header display accuracy)
HijriGregDate? _currentHijriDisplay; HijriGregDate? _currentHijriDisplay;
@ -65,10 +66,14 @@ class _DateRangeSelectorState extends State<DateRangeSelector> {
@override @override
void initState() { void initState() {
_calendarController = DateRangePickerController(); _calendarController = DateRangePickerController();
final today = DateTime.now();
_displayedMonthKey = _monthKey(today);
if (widget.designType == CalendarDesignType.designV2) {
_calendarController.displayDate = today;
}
scheduleMicrotask(() { scheduleMicrotask(() {
if (widget.designType == CalendarDesignType.designV2) { if (widget.designType == CalendarDesignType.designV2) {
// For V2, select today's date by default // For V2, select today's date by default
final today = DateTime.now();
_calendarController.selectedDate = today; _calendarController.selectedDate = today;
model.updateSelectedDate(today); model.updateSelectedDate(today);
} else { } else {
@ -83,7 +88,9 @@ class _DateRangeSelectorState extends State<DateRangeSelector> {
Widget build(BuildContext context) { Widget build(BuildContext context) {
model = Provider.of<DateRangeSelectorRangeViewModel>(context); model = Provider.of<DateRangeSelectorRangeViewModel>(context);
if (widget.designType != CalendarDesignType.designV2) {
_calendarController.selectedRange = PickerDateRange(model.fromDate, model.toDate); _calendarController.selectedRange = PickerDateRange(model.fromDate, model.toDate);
}
return widget.designType == CalendarDesignType.designV2 ? _buildDesignV2(widget.btnTitle) : _buildDefaultUI(); return widget.designType == CalendarDesignType.designV2 ? _buildDesignV2(widget.btnTitle) : _buildDefaultUI();
} }
@ -273,18 +280,17 @@ class _DateRangeSelectorState extends State<DateRangeSelector> {
tabs: [CustomTabBarModel(null, LocaleKeys.gregorianDate.tr()), CustomTabBarModel(null, LocaleKeys.hijriDate.tr())], tabs: [CustomTabBarModel(null, LocaleKeys.gregorianDate.tr()), CustomTabBarModel(null, LocaleKeys.hijriDate.tr())],
onTabChange: (index) { onTabChange: (index) {
final calendarModel = Provider.of<DateRangCalenderModel>(context, listen: false); final calendarModel = Provider.of<DateRangCalenderModel>(context, listen: false);
if (calendarModel.getSelectedTabIndex == index) return;
// Update local fields before notifying the provider so
// the calendar changes with a single rebuild.
_viewMode = PickerViewMode.date;
_currentHijriDisplay = null;
calendarModel.setTabIndex(index); calendarModel.setTabIndex(index);
// Notify parent widget about calendar type change (e.g., AuthenticationViewModel) // Notify parent widget about calendar type change (e.g., AuthenticationViewModel)
final isGregorian = index == 0; final isGregorian = index == 0;
widget.onCalendarTypeChanged?.call(isGregorian); widget.onCalendarTypeChanged?.call(isGregorian);
print('📅 Calendar type changed: ${isGregorian ? "Gregorian" : "Hijri"}');
// Reset view mode and Hijri display when switching calendar types
setState(() {
_viewMode = PickerViewMode.date;
_currentHijriDisplay = null;
});
}, },
), ),
), ),
@ -306,6 +312,11 @@ class _DateRangeSelectorState extends State<DateRangeSelector> {
child: Material( child: Material(
color: AppColors.whiteColor, color: AppColors.whiteColor,
// Rebuild when view mode or calendar type changes // Rebuild when view mode or calendar type changes
// Syncfusion caches its rendered date cells. Include
// the calendar type in the key so Gregorian/Hijri day
// labels refresh immediately when the tab changes.
// Hijri conversion is now constant-time, so this
// targeted recreation remains responsive.
key: ValueKey('${calendarModel.getSelectedTabIndex}-$_viewMode'), key: ValueKey('${calendarModel.getSelectedTabIndex}-$_viewMode'),
child: _viewMode == PickerViewMode.month child: _viewMode == PickerViewMode.month
? _buildMonthPicker(isArabic, calendarModel) ? _buildMonthPicker(isArabic, calendarModel)
@ -343,6 +354,8 @@ class _DateRangeSelectorState extends State<DateRangeSelector> {
// Build Gregorian calendar (Design V2 - Single Date Selection) // Build Gregorian calendar (Design V2 - Single Date Selection)
Widget _buildGregorianCalendar(bool isArabic) { Widget _buildGregorianCalendar(bool isArabic) {
final today = DateTime.now();
return SfDateRangePicker( return SfDateRangePicker(
controller: _calendarController, controller: _calendarController,
selectionMode: DateRangePickerSelectionMode.single, selectionMode: DateRangePickerSelectionMode.single,
@ -366,7 +379,7 @@ class _DateRangeSelectorState extends State<DateRangeSelector> {
// Custom cell builder for square border selection // Custom cell builder for square border selection
cellBuilder: (BuildContext context, DateRangePickerCellDetails cellDetails) { cellBuilder: (BuildContext context, DateRangePickerCellDetails cellDetails) {
if (cellDetails.date != DateTime(0)) { if (cellDetails.date != DateTime(0)) {
final isToday = cellDetails.date.day == DateTime.now().day && cellDetails.date.month == DateTime.now().month && cellDetails.date.year == DateTime.now().year; final isToday = cellDetails.date.day == today.day && cellDetails.date.month == today.month && cellDetails.date.year == today.year;
final isSelected = _calendarController.selectedDate != null && final isSelected = _calendarController.selectedDate != null &&
cellDetails.date.day == _calendarController.selectedDate!.day && cellDetails.date.day == _calendarController.selectedDate!.day &&
cellDetails.date.month == _calendarController.selectedDate!.month && cellDetails.date.month == _calendarController.selectedDate!.month &&
@ -414,12 +427,7 @@ class _DateRangeSelectorState extends State<DateRangeSelector> {
), ),
), ),
onViewChanged: (DateRangePickerViewChangedArgs args) { onViewChanged: (DateRangePickerViewChangedArgs args) {
// Trigger rebuild when month changes _handleCalendarViewChanged(args);
WidgetsBinding.instance.addPostFrameCallback((_) {
if (mounted) {
setState(() {});
}
});
}, },
onSelectionChanged: (DateRangePickerSelectionChangedArgs args) { onSelectionChanged: (DateRangePickerSelectionChangedArgs args) {
if (args.value is DateTime) { if (args.value is DateTime) {
@ -433,44 +441,85 @@ class _DateRangeSelectorState extends State<DateRangeSelector> {
); );
} }
// Build Hijri calendar (Design V2 - Single Date Selection) // Build one complete Hijri month instead of relabelling the dates in a
// Note: SfDateRangePicker doesn't have built-in Hijri support // Gregorian month. A Gregorian month overlaps two Hijri months, which would
// Using Gregorian calendar with Hijri date conversion in the model // otherwise produce sequences such as 16...30, 1...17 in the same grid.
Widget _buildHijriCalendar(bool isArabic) { Widget _buildHijriCalendar(bool isArabic) {
final calendarModel = Provider.of<DateRangCalenderModel>(context, listen: false); final calendarModel = Provider.of<DateRangCalenderModel>(context, listen: false);
final today = DateTime.now();
final displayedGregorian = _calendarController.displayDate ?? today;
final displayedHijri = _currentHijriDisplay ?? calendarModel.gregorianToHijri(displayedGregorian);
final firstHijriDay = HijriGregDate(day: 1, month: displayedHijri.month, year: displayedHijri.year);
final firstGregorianDay = calendarModel.hijriToGregorian(firstHijriDay);
final leadingEmptyCells = firstGregorianDay.weekday % DateTime.daysPerWeek;
final daysInMonth = calendarModel.getDaysInMonth(displayedHijri.year, displayedHijri.month);
final selectedDate = _calendarController.selectedDate;
const weekdays = [
DateTime.sunday,
DateTime.monday,
DateTime.tuesday,
DateTime.wednesday,
DateTime.thursday,
DateTime.friday,
DateTime.saturday,
];
return SfDateRangePicker( return Column(
controller: _calendarController, children: [
selectionMode: DateRangePickerSelectionMode.single, SizedBox(
showNavigationArrow: false, height: 32.h,
headerHeight: 0, child: Row(
backgroundColor: AppColors.whiteColor, children: weekdays
monthViewSettings: DateRangePickerMonthViewSettings( .map(
viewHeaderStyle: DateRangePickerViewHeaderStyle( (weekday) => Expanded(
backgroundColor: AppColors.whiteColor, child: Center(
textStyle: TextStyle( child: Text(
calendarModel.getWeekdayNameLocalized(weekday, isArabic),
style: TextStyle(
fontSize: 12.f, fontSize: 12.f,
fontWeight: FontWeight.w600, fontWeight: FontWeight.w600,
letterSpacing: -0.46, letterSpacing: -0.46,
color: AppColors.textColor, color: AppColors.textColor,
), ),
), ),
showTrailingAndLeadingDates: false,
dayFormat: "EEE",
), ),
cellBuilder: (BuildContext context, DateRangePickerCellDetails cellDetails) { ),
if (cellDetails.date != DateTime(0)) { )
// Use cached Hijri conversion .toList(),
final dateKey = '${cellDetails.date.year}-${cellDetails.date.month}-${cellDetails.date.day}'; ),
final hijriDate = _hijriCache.putIfAbsent(dateKey, () => calendarModel.gregorianToHijri(cellDetails.date)); ),
Expanded(
child: GridView.builder(
padding: EdgeInsets.zero,
physics: const NeverScrollableScrollPhysics(),
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: DateTime.daysPerWeek,
mainAxisExtent: 36.h,
mainAxisSpacing: 4.h,
),
itemCount: 42,
itemBuilder: (context, index) {
final hijriDay = index - leadingEmptyCells + 1;
if (hijriDay < 1 || hijriDay > daysInMonth) {
return const SizedBox.shrink();
}
final isToday = cellDetails.date.day == DateTime.now().day && cellDetails.date.month == DateTime.now().month && cellDetails.date.year == DateTime.now().year; final hijriDate = HijriGregDate(day: hijriDay, month: displayedHijri.month, year: displayedHijri.year);
final isSelected = _calendarController.selectedDate != null && final gregorianDate = calendarModel.hijriToGregorian(hijriDate);
cellDetails.date.day == _calendarController.selectedDate!.day && final isToday = _isSameDate(gregorianDate, today);
cellDetails.date.month == _calendarController.selectedDate!.month && final isSelected = selectedDate != null && _isSameDate(gregorianDate, selectedDate);
cellDetails.date.year == _calendarController.selectedDate!.year;
return Container( return GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: () {
_calendarController.selectedDate = gregorianDate;
setState(() {
start = gregorianDate;
end = gregorianDate;
});
model.updateSelectedDate(gregorianDate);
},
child: Container(
alignment: Alignment.center, alignment: Alignment.center,
decoration: BoxDecoration( decoration: BoxDecoration(
borderRadius: BorderRadius.circular(8.h), borderRadius: BorderRadius.circular(8.h),
@ -478,7 +527,7 @@ class _DateRangeSelectorState extends State<DateRangeSelector> {
color: Colors.transparent, color: Colors.transparent,
), ),
child: Text( child: Text(
hijriDate.day.toString(), hijriDay.toString(),
style: TextStyle( style: TextStyle(
fontFamily: "Poppins", fontFamily: "Poppins",
fontSize: 12.f, fontSize: 12.f,
@ -486,50 +535,59 @@ class _DateRangeSelectorState extends State<DateRangeSelector> {
fontWeight: isToday ? FontWeight.bold : (isSelected ? FontWeight.w600 : FontWeight.normal), fontWeight: isToday ? FontWeight.bold : (isSelected ? FontWeight.w600 : FontWeight.normal),
), ),
), ),
),
); );
}
return Container();
}, },
selectionShape: DateRangePickerSelectionShape.rectangle,
selectionRadius: 8.h,
selectionColor: Colors.transparent,
selectionTextStyle: TextStyle(
fontFamily: "Poppins",
color: AppColors.textColor,
fontWeight: FontWeight.w600,
), ),
todayHighlightColor: Colors.transparent,
monthCellStyle: DateRangePickerMonthCellStyle(
textStyle: TextStyle(
fontFamily: "Poppins",
fontSize: 12.f,
color: AppColors.textColor,
), ),
todayTextStyle: TextStyle( ],
fontFamily: "Poppins", );
color: AppColors.textColor, }
fontWeight: FontWeight.bold,
), bool _isSameDate(DateTime first, DateTime second) {
), return first.year == second.year && first.month == second.month && first.day == second.day;
onViewChanged: (DateRangePickerViewChangedArgs args) { }
// Clear cache when month changes to avoid stale data
_hijriCache.clear(); int _monthKey(DateTime date) => (date.year * 100) + date.month;
void _changeHijriMonth(DateRangCalenderModel calendarModel, int monthDelta) {
final displayedDate = _calendarController.displayDate ?? DateTime.now();
final currentHijri = _currentHijriDisplay ?? calendarModel.gregorianToHijri(displayedDate);
final zeroBasedMonth = (currentHijri.year * 12) + currentHijri.month - 1 + monthDelta;
final nextHijriDate = HijriGregDate(
day: 1,
month: (zeroBasedMonth % 12) + 1,
year: zeroBasedMonth ~/ 12,
);
final nextGregorianDate = calendarModel.hijriToGregorian(nextHijriDate);
setState(() {
_currentHijriDisplay = nextHijriDate;
_calendarController.displayDate = nextGregorianDate;
_displayedMonthKey = _monthKey(nextGregorianDate);
});
}
void _handleCalendarViewChanged(DateRangePickerViewChangedArgs args) {
final rangeStart = args.visibleDateRange.startDate;
final rangeEnd = args.visibleDateRange.endDate;
final displayedDate = _calendarController.displayDate ??
(rangeEnd == null
? rangeStart
: rangeStart?.add(Duration(days: rangeEnd.difference(rangeStart).inDays ~/ 2)));
if (displayedDate == null) return;
final newMonthKey = _monthKey(displayedDate);
if (newMonthKey == _displayedMonthKey) return;
_displayedMonthKey = newMonthKey;
_currentHijriDisplay = null;
WidgetsBinding.instance.addPostFrameCallback((_) { WidgetsBinding.instance.addPostFrameCallback((_) {
if (mounted) { if (mounted) {
setState(() {}); setState(() {});
} }
}); });
},
onSelectionChanged: (DateRangePickerSelectionChangedArgs args) {
if (args.value is DateTime) {
setState(() {
start = args.value;
end = args.value;
});
model.updateSelectedDate(args.value);
}
},
);
} }
// Build unified calendar header for both Gregorian and Hijri // Build unified calendar header for both Gregorian and Hijri
@ -609,12 +667,10 @@ class _DateRangeSelectorState extends State<DateRangeSelector> {
icon: Icon(Icons.chevron_left, color: AppColors.primaryRedColor), icon: Icon(Icons.chevron_left, color: AppColors.primaryRedColor),
onPressed: () { onPressed: () {
if (_viewMode == PickerViewMode.date) { if (_viewMode == PickerViewMode.date) {
_calendarController.backward!();
// Update tracked Hijri display when navigating months
if (calendarModel.isHijri) { if (calendarModel.isHijri) {
setState(() { _changeHijriMonth(calendarModel, -1);
_currentHijriDisplay = null; // Will recalculate on next build } else {
}); _calendarController.backward!();
} }
} else if (_viewMode == PickerViewMode.year) { } else if (_viewMode == PickerViewMode.year) {
// Navigate years backward by 12 // Navigate years backward by 12
@ -625,7 +681,7 @@ class _DateRangeSelectorState extends State<DateRangeSelector> {
try { try {
final newHijriDate = HijriGregDate(day: 1, month: hijriDate.month, year: hijriDate.year - 12); final newHijriDate = HijriGregDate(day: 1, month: hijriDate.month, year: hijriDate.year - 12);
final newGregorianDate = calendarModel.hijriToGregorian(newHijriDate); final newGregorianDate = calendarModel.hijriToGregorian(newHijriDate);
_calendarController.displayDate = DateTime(newGregorianDate.year, newGregorianDate.month, 1); _calendarController.displayDate = newGregorianDate;
_currentHijriDisplay = newHijriDate; _currentHijriDisplay = newHijriDate;
} catch (e) { } catch (e) {
// Fallback // Fallback
@ -645,12 +701,10 @@ class _DateRangeSelectorState extends State<DateRangeSelector> {
icon: Icon(Icons.chevron_right, color: AppColors.primaryRedColor), icon: Icon(Icons.chevron_right, color: AppColors.primaryRedColor),
onPressed: () { onPressed: () {
if (_viewMode == PickerViewMode.date) { if (_viewMode == PickerViewMode.date) {
_calendarController.forward!();
// Update tracked Hijri display when navigating months
if (calendarModel.isHijri) { if (calendarModel.isHijri) {
setState(() { _changeHijriMonth(calendarModel, 1);
_currentHijriDisplay = null; // Will recalculate on next build } else {
}); _calendarController.forward!();
} }
} else if (_viewMode == PickerViewMode.year) { } else if (_viewMode == PickerViewMode.year) {
// Navigate years forward by 12 // Navigate years forward by 12
@ -661,7 +715,7 @@ class _DateRangeSelectorState extends State<DateRangeSelector> {
try { try {
final newHijriDate = HijriGregDate(day: 1, month: hijriDate.month, year: hijriDate.year + 12); final newHijriDate = HijriGregDate(day: 1, month: hijriDate.month, year: hijriDate.year + 12);
final newGregorianDate = calendarModel.hijriToGregorian(newHijriDate); final newGregorianDate = calendarModel.hijriToGregorian(newHijriDate);
_calendarController.displayDate = DateTime(newGregorianDate.year, newGregorianDate.month, 1); _calendarController.displayDate = newGregorianDate;
_currentHijriDisplay = newHijriDate; _currentHijriDisplay = newHijriDate;
} catch (e) { } catch (e) {
// Fallback // Fallback
@ -696,7 +750,7 @@ class _DateRangeSelectorState extends State<DateRangeSelector> {
if (calendarModel.isHijri) { if (calendarModel.isHijri) {
// For Hijri calendar // For Hijri calendar
final hijriCurrent = calendarModel.gregorianToHijri(currentDate); final hijriCurrent = calendarModel.gregorianToHijri(currentDate);
final hijriDisplayed = calendarModel.gregorianToHijri(displayedDate); final hijriDisplayed = _currentHijriDisplay ?? calendarModel.gregorianToHijri(displayedDate);
currentMonth = hijriCurrent.month; currentMonth = hijriCurrent.month;
currentYear = hijriCurrent.year; currentYear = hijriCurrent.year;
displayedYear = hijriDisplayed.year; displayedYear = hijriDisplayed.year;
@ -730,11 +784,9 @@ class _DateRangeSelectorState extends State<DateRangeSelector> {
try { try {
final hijriDate = HijriGregDate(day: 1, month: monthIndex, year: displayedYear); final hijriDate = HijriGregDate(day: 1, month: monthIndex, year: displayedYear);
final gregorianDate = calendarModel.hijriToGregorian(hijriDate); final gregorianDate = calendarModel.hijriToGregorian(hijriDate);
_calendarController.displayDate = DateTime(gregorianDate.year, gregorianDate.month, 1); _calendarController.displayDate = gregorianDate;
// Track the Hijri month/year for accurate header display // Track the Hijri month/year for accurate header display
_currentHijriDisplay = hijriDate; _currentHijriDisplay = hijriDate;
// Clear cache since we changed the month
_hijriCache.clear();
} catch (e) { } catch (e) {
// Fallback if conversion fails // Fallback if conversion fails
_calendarController.displayDate = DateTime(displayedDate.year, monthIndex, 1); _calendarController.displayDate = DateTime(displayedDate.year, monthIndex, 1);
@ -784,7 +836,7 @@ class _DateRangeSelectorState extends State<DateRangeSelector> {
if (calendarModel.isHijri) { if (calendarModel.isHijri) {
// For Hijri calendar // For Hijri calendar
final hijriDisplayed = calendarModel.gregorianToHijri(displayedDate); final hijriDisplayed = _currentHijriDisplay ?? calendarModel.gregorianToHijri(displayedDate);
final hijriCurrent = calendarModel.gregorianToHijri(DateTime.now()); final hijriCurrent = calendarModel.gregorianToHijri(DateTime.now());
displayedYear = hijriDisplayed.year; displayedYear = hijriDisplayed.year;
currentDisplayYear = hijriCurrent.year; currentDisplayYear = hijriCurrent.year;
@ -818,7 +870,7 @@ class _DateRangeSelectorState extends State<DateRangeSelector> {
final currentHijriMonth = _currentHijriDisplay?.month ?? calendarModel.gregorianToHijri(displayedDate).month; final currentHijriMonth = _currentHijriDisplay?.month ?? calendarModel.gregorianToHijri(displayedDate).month;
final hijriDate = HijriGregDate(day: 1, month: currentHijriMonth, year: year); final hijriDate = HijriGregDate(day: 1, month: currentHijriMonth, year: year);
final gregorianDate = calendarModel.hijriToGregorian(hijriDate); final gregorianDate = calendarModel.hijriToGregorian(hijriDate);
_calendarController.displayDate = DateTime(gregorianDate.year, gregorianDate.month, 1); _calendarController.displayDate = gregorianDate;
// Track the Hijri month/year for accurate header display // Track the Hijri month/year for accurate header display
_currentHijriDisplay = hijriDate; _currentHijriDisplay = hijriDate;
} catch (e) { } catch (e) {

@ -122,12 +122,12 @@ class HijriGregConverter {
static int _hijriYearStartJulian(int hijriYear) { static int _hijriYearStartJulian(int hijriYear) {
if (hijriYear <= 1) return _hijriEpoch; if (hijriYear <= 1) return _hijriEpoch;
int totalDays = 0; // A Hijri year has 354 days, with 11 leap days in every 30-year
for (int year = 1; year < hijriYear; year++) { // cycle. Calculate the completed years directly instead of iterating
totalDays += _hijriYearLength(year); // from year 1 for every calendar cell.
} final completedYears = hijriYear - 1;
final completedLeapDays = (3 + (11 * hijriYear)) ~/ 30;
return _hijriEpoch + totalDays; return _hijriEpoch + (completedYears * 354) + completedLeapDays;
} }
static int _hijriYearLength(int year) { static int _hijriYearLength(int year) {
@ -358,6 +358,8 @@ class DateRangCalenderModel extends ChangeNotifier {
} }
void setTabIndex(int index) { void setTabIndex(int index) {
if (_selectedTabIndex == index) return;
_selectedTabIndex = index; _selectedTabIndex = index;
_calendarType = index == 0 ? CalendarType.gregorian : CalendarType.hijri; _calendarType = index == 0 ? CalendarType.gregorian : CalendarType.hijri;
// Persist the selection for next time the widget opens // Persist the selection for next time the widget opens

Loading…
Cancel
Save