Updates for Zoom

haroon_dev
haroon amjad 4 days ago
parent 814b0ccd58
commit 636610acce

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

@ -2,3 +2,9 @@ const Map configs = {
'ZOOM_SDK_KEY': 'b9T74nhfTg-ioP9urm970A',
'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/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/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/todo_page.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(),
),
);
// 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!}'),
imageWidget: Selector<ProfileSettingsViewModel, String?>(
@ -314,6 +324,13 @@ class _LandingPageState extends State<LandingPage> {
onPressed: () async {
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(
// CustomPageRoute(
// // page: NotificationsListPage(),

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

@ -56,8 +56,9 @@ class _DateRangeSelectorState extends State<DateRangeSelector> {
late DateRangeSelectorRangeViewModel model;
PickerViewMode _viewMode = PickerViewMode.date;
// Cache for Hijri conversions to avoid repeated calculations
final Map<String, HijriGregDate> _hijriCache = {};
// Prevent Syncfusion's initial onViewChanged callback from scheduling an
// unnecessary second build of the same month.
late int _displayedMonthKey;
// Track the current Hijri month/year being displayed (for header display accuracy)
HijriGregDate? _currentHijriDisplay;
@ -65,10 +66,14 @@ class _DateRangeSelectorState extends State<DateRangeSelector> {
@override
void initState() {
_calendarController = DateRangePickerController();
final today = DateTime.now();
_displayedMonthKey = _monthKey(today);
if (widget.designType == CalendarDesignType.designV2) {
_calendarController.displayDate = today;
}
scheduleMicrotask(() {
if (widget.designType == CalendarDesignType.designV2) {
// For V2, select today's date by default
final today = DateTime.now();
_calendarController.selectedDate = today;
model.updateSelectedDate(today);
} else {
@ -83,7 +88,9 @@ class _DateRangeSelectorState extends State<DateRangeSelector> {
Widget build(BuildContext context) {
model = Provider.of<DateRangeSelectorRangeViewModel>(context);
_calendarController.selectedRange = PickerDateRange(model.fromDate, model.toDate);
if (widget.designType != CalendarDesignType.designV2) {
_calendarController.selectedRange = PickerDateRange(model.fromDate, model.toDate);
}
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())],
onTabChange: (index) {
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);
// Notify parent widget about calendar type change (e.g., AuthenticationViewModel)
final isGregorian = index == 0;
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,12 +312,17 @@ class _DateRangeSelectorState extends State<DateRangeSelector> {
child: Material(
color: AppColors.whiteColor,
// 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'),
child: _viewMode == PickerViewMode.month
? _buildMonthPicker(isArabic, calendarModel)
: _viewMode == PickerViewMode.year
? _buildYearPicker(isArabic, calendarModel)
: (calendarModel.isHijri ? _buildHijriCalendar(isArabic) : _buildGregorianCalendar(isArabic)),
? _buildYearPicker(isArabic, calendarModel)
: (calendarModel.isHijri ? _buildHijriCalendar(isArabic) : _buildGregorianCalendar(isArabic)),
),
),
],
@ -343,6 +354,8 @@ class _DateRangeSelectorState extends State<DateRangeSelector> {
// Build Gregorian calendar (Design V2 - Single Date Selection)
Widget _buildGregorianCalendar(bool isArabic) {
final today = DateTime.now();
return SfDateRangePicker(
controller: _calendarController,
selectionMode: DateRangePickerSelectionMode.single,
@ -366,7 +379,7 @@ class _DateRangeSelectorState extends State<DateRangeSelector> {
// Custom cell builder for square border selection
cellBuilder: (BuildContext context, DateRangePickerCellDetails cellDetails) {
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 &&
cellDetails.date.day == _calendarController.selectedDate!.day &&
cellDetails.date.month == _calendarController.selectedDate!.month &&
@ -414,12 +427,7 @@ class _DateRangeSelectorState extends State<DateRangeSelector> {
),
),
onViewChanged: (DateRangePickerViewChangedArgs args) {
// Trigger rebuild when month changes
WidgetsBinding.instance.addPostFrameCallback((_) {
if (mounted) {
setState(() {});
}
});
_handleCalendarViewChanged(args);
},
onSelectionChanged: (DateRangePickerSelectionChangedArgs args) {
if (args.value is DateTime) {
@ -433,105 +441,155 @@ class _DateRangeSelectorState extends State<DateRangeSelector> {
);
}
// Build Hijri calendar (Design V2 - Single Date Selection)
// Note: SfDateRangePicker doesn't have built-in Hijri support
// Using Gregorian calendar with Hijri date conversion in the model
// Build one complete Hijri month instead of relabelling the dates in a
// Gregorian month. A Gregorian month overlaps two Hijri months, which would
// otherwise produce sequences such as 16...30, 1...17 in the same grid.
Widget _buildHijriCalendar(bool isArabic) {
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(
controller: _calendarController,
selectionMode: DateRangePickerSelectionMode.single,
showNavigationArrow: false,
headerHeight: 0,
backgroundColor: AppColors.whiteColor,
monthViewSettings: DateRangePickerMonthViewSettings(
viewHeaderStyle: DateRangePickerViewHeaderStyle(
backgroundColor: AppColors.whiteColor,
textStyle: TextStyle(
fontSize: 12.f,
fontWeight: FontWeight.w600,
letterSpacing: -0.46,
color: AppColors.textColor,
return Column(
children: [
SizedBox(
height: 32.h,
child: Row(
children: weekdays
.map(
(weekday) => Expanded(
child: Center(
child: Text(
calendarModel.getWeekdayNameLocalized(weekday, isArabic),
style: TextStyle(
fontSize: 12.f,
fontWeight: FontWeight.w600,
letterSpacing: -0.46,
color: AppColors.textColor,
),
),
),
),
)
.toList(),
),
),
showTrailingAndLeadingDates: false,
dayFormat: "EEE",
),
cellBuilder: (BuildContext context, DateRangePickerCellDetails cellDetails) {
if (cellDetails.date != DateTime(0)) {
// Use cached Hijri conversion
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 isSelected = _calendarController.selectedDate != null &&
cellDetails.date.day == _calendarController.selectedDate!.day &&
cellDetails.date.month == _calendarController.selectedDate!.month &&
cellDetails.date.year == _calendarController.selectedDate!.year;
final hijriDate = HijriGregDate(day: hijriDay, month: displayedHijri.month, year: displayedHijri.year);
final gregorianDate = calendarModel.hijriToGregorian(hijriDate);
final isToday = _isSameDate(gregorianDate, today);
final isSelected = selectedDate != null && _isSameDate(gregorianDate, selectedDate);
return Container(
alignment: Alignment.center,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(8.h),
border: isSelected ? Border.all(color: AppColors.primaryRedColor, width: 2) : null,
color: Colors.transparent,
),
child: Text(
hijriDate.day.toString(),
style: TextStyle(
fontFamily: "Poppins",
fontSize: 12.f,
color: AppColors.textColor,
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,
return GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: () {
_calendarController.selectedDate = gregorianDate;
setState(() {
start = gregorianDate;
end = gregorianDate;
});
model.updateSelectedDate(gregorianDate);
},
child: Container(
alignment: Alignment.center,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(8.h),
border: isSelected ? Border.all(color: AppColors.primaryRedColor, width: 2) : null,
color: Colors.transparent,
),
child: Text(
hijriDay.toString(),
style: TextStyle(
fontFamily: "Poppins",
fontSize: 12.f,
color: AppColors.textColor,
fontWeight: isToday ? FontWeight.bold : (isSelected ? FontWeight.w600 : FontWeight.normal),
),
),
),
);
},
),
),
),
onViewChanged: (DateRangePickerViewChangedArgs args) {
// Clear cache when month changes to avoid stale data
_hijriCache.clear();
WidgetsBinding.instance.addPostFrameCallback((_) {
if (mounted) {
setState(() {});
}
});
},
onSelectionChanged: (DateRangePickerSelectionChangedArgs args) {
if (args.value is DateTime) {
setState(() {
start = args.value;
end = args.value;
});
model.updateSelectedDate(args.value);
}
},
],
);
}
bool _isSameDate(DateTime first, DateTime second) {
return first.year == second.year && first.month == second.month && first.day == second.day;
}
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((_) {
if (mounted) {
setState(() {});
}
});
}
// Build unified calendar header for both Gregorian and Hijri
Widget _buildCalendarHeader(bool isArabic, DateRangCalenderModel calendarModel) {
final displayedDate = _calendarController.displayDate ?? DateTime.now();
@ -609,12 +667,10 @@ class _DateRangeSelectorState extends State<DateRangeSelector> {
icon: Icon(Icons.chevron_left, color: AppColors.primaryRedColor),
onPressed: () {
if (_viewMode == PickerViewMode.date) {
_calendarController.backward!();
// Update tracked Hijri display when navigating months
if (calendarModel.isHijri) {
setState(() {
_currentHijriDisplay = null; // Will recalculate on next build
});
_changeHijriMonth(calendarModel, -1);
} else {
_calendarController.backward!();
}
} else if (_viewMode == PickerViewMode.year) {
// Navigate years backward by 12
@ -625,7 +681,7 @@ class _DateRangeSelectorState extends State<DateRangeSelector> {
try {
final newHijriDate = HijriGregDate(day: 1, month: hijriDate.month, year: hijriDate.year - 12);
final newGregorianDate = calendarModel.hijriToGregorian(newHijriDate);
_calendarController.displayDate = DateTime(newGregorianDate.year, newGregorianDate.month, 1);
_calendarController.displayDate = newGregorianDate;
_currentHijriDisplay = newHijriDate;
} catch (e) {
// Fallback
@ -645,12 +701,10 @@ class _DateRangeSelectorState extends State<DateRangeSelector> {
icon: Icon(Icons.chevron_right, color: AppColors.primaryRedColor),
onPressed: () {
if (_viewMode == PickerViewMode.date) {
_calendarController.forward!();
// Update tracked Hijri display when navigating months
if (calendarModel.isHijri) {
setState(() {
_currentHijriDisplay = null; // Will recalculate on next build
});
_changeHijriMonth(calendarModel, 1);
} else {
_calendarController.forward!();
}
} else if (_viewMode == PickerViewMode.year) {
// Navigate years forward by 12
@ -661,7 +715,7 @@ class _DateRangeSelectorState extends State<DateRangeSelector> {
try {
final newHijriDate = HijriGregDate(day: 1, month: hijriDate.month, year: hijriDate.year + 12);
final newGregorianDate = calendarModel.hijriToGregorian(newHijriDate);
_calendarController.displayDate = DateTime(newGregorianDate.year, newGregorianDate.month, 1);
_calendarController.displayDate = newGregorianDate;
_currentHijriDisplay = newHijriDate;
} catch (e) {
// Fallback
@ -696,7 +750,7 @@ class _DateRangeSelectorState extends State<DateRangeSelector> {
if (calendarModel.isHijri) {
// For Hijri calendar
final hijriCurrent = calendarModel.gregorianToHijri(currentDate);
final hijriDisplayed = calendarModel.gregorianToHijri(displayedDate);
final hijriDisplayed = _currentHijriDisplay ?? calendarModel.gregorianToHijri(displayedDate);
currentMonth = hijriCurrent.month;
currentYear = hijriCurrent.year;
displayedYear = hijriDisplayed.year;
@ -730,11 +784,9 @@ class _DateRangeSelectorState extends State<DateRangeSelector> {
try {
final hijriDate = HijriGregDate(day: 1, month: monthIndex, year: displayedYear);
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
_currentHijriDisplay = hijriDate;
// Clear cache since we changed the month
_hijriCache.clear();
} catch (e) {
// Fallback if conversion fails
_calendarController.displayDate = DateTime(displayedDate.year, monthIndex, 1);
@ -784,7 +836,7 @@ class _DateRangeSelectorState extends State<DateRangeSelector> {
if (calendarModel.isHijri) {
// For Hijri calendar
final hijriDisplayed = calendarModel.gregorianToHijri(displayedDate);
final hijriDisplayed = _currentHijriDisplay ?? calendarModel.gregorianToHijri(displayedDate);
final hijriCurrent = calendarModel.gregorianToHijri(DateTime.now());
displayedYear = hijriDisplayed.year;
currentDisplayYear = hijriCurrent.year;
@ -818,7 +870,7 @@ class _DateRangeSelectorState extends State<DateRangeSelector> {
final currentHijriMonth = _currentHijriDisplay?.month ?? calendarModel.gregorianToHijri(displayedDate).month;
final hijriDate = HijriGregDate(day: 1, month: currentHijriMonth, year: year);
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
_currentHijriDisplay = hijriDate;
} catch (e) {
@ -876,34 +928,34 @@ class _DateRangeSelectorState extends State<DateRangeSelector> {
}
displayDate(String label, String? date, bool isNotSelected) => Expanded(
child: Row(
spacing: 12.h,
child: Row(
spacing: 12.h,
children: [
Utils.buildSvgWithAssets(icon: AppAssets.rangeCalendar, iconColor: isNotSelected ? AppColors.borderOnlyColor : AppColors.blackColor, height: 24, width: 24),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Utils.buildSvgWithAssets(icon: AppAssets.rangeCalendar, iconColor: isNotSelected ? AppColors.borderOnlyColor : AppColors.blackColor, height: 24, width: 24),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
label,
style: TextStyle(
color: AppColors.inputLabelTextColor,
fontSize: 12.f,
fontWeight: FontWeight.w600,
),
),
Text(
date!,
style: TextStyle(
color: AppColors.textColor,
fontSize: 14.f,
fontWeight: FontWeight.w600,
),
)
],
Text(
label,
style: TextStyle(
color: AppColors.inputLabelTextColor,
fontSize: 12.f,
fontWeight: FontWeight.w600,
),
),
Text(
date!,
style: TextStyle(
color: AppColors.textColor,
fontSize: 14.f,
fontWeight: FontWeight.w600,
),
)
],
),
);
)
],
),
);
selectionChip(DateRangeSelectorRangeViewModel model) {
return Row(

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

@ -63,7 +63,7 @@ dependencies:
geolocator: ^14.0.2
dropdown_search: ^6.0.2
google_maps_flutter: ^2.13.1
# flutter_zoom_videosdk: 2.1.10
# flutter_zoom_videosdk: 2.1.10
flutter_zoom_videosdk: ^2.5.10
dart_jsonwebtoken: ^3.2.0
dartz: ^0.10.1

Loading…
Cancel
Save