calendar implementation contd.
							parent
							
								
									73f8baa77e
								
							
						
					
					
						commit
						6f745f3666
					
				| @ -0,0 +1,8 @@ | ||||
| class TimeSlot { | ||||
|   String? isoTime; | ||||
|   DateTime? start; | ||||
|   DateTime? end; | ||||
|   String? vidaDate; | ||||
| 
 | ||||
|   TimeSlot({required this.isoTime, required this.start, required this.end, this.vidaDate}); | ||||
| } | ||||
| @ -0,0 +1,242 @@ | ||||
| import 'dart:async'; | ||||
| 
 | ||||
| import 'package:easy_localization/easy_localization.dart'; | ||||
| import 'package:flutter/cupertino.dart'; | ||||
| import 'package:flutter/material.dart'; | ||||
| import 'package:hmg_patient_app_new/core/app_export.dart'; | ||||
| import 'package:hmg_patient_app_new/core/app_state.dart'; | ||||
| import 'package:hmg_patient_app_new/core/dependencies.dart'; | ||||
| import 'package:hmg_patient_app_new/core/utils/date_util.dart'; | ||||
| import 'package:hmg_patient_app_new/extensions/string_extensions.dart'; | ||||
| import 'package:hmg_patient_app_new/features/book_appointments/book_appointments_view_model.dart'; | ||||
| import 'package:hmg_patient_app_new/features/book_appointments/models/free_slot.dart'; | ||||
| import 'package:hmg_patient_app_new/features/book_appointments/models/timeslots.dart'; | ||||
| import 'package:hmg_patient_app_new/theme/colors.dart'; | ||||
| import 'package:hmg_patient_app_new/widgets/chip/app_custom_chip_widget.dart'; | ||||
| import 'package:provider/provider.dart'; | ||||
| import 'package:smooth_corner/smooth_corner.dart'; | ||||
| import 'package:syncfusion_flutter_calendar/calendar.dart'; | ||||
| 
 | ||||
| class AppointmentCalendar extends StatefulWidget { | ||||
|   const AppointmentCalendar({super.key}); | ||||
| 
 | ||||
|   @override | ||||
|   State<AppointmentCalendar> createState() => _AppointmentCalendarState(); | ||||
| } | ||||
| 
 | ||||
| class _AppointmentCalendarState extends State<AppointmentCalendar> { | ||||
|   late CalendarController _calendarController; | ||||
| 
 | ||||
|   late AppState appState; | ||||
|   late BookAppointmentsViewModel bookAppointmentsViewModel; | ||||
| 
 | ||||
|   var selectedDate = ""; | ||||
|   var selectedNextDate = ""; | ||||
| 
 | ||||
|   int selectedButtonIndex = 0; | ||||
|   int selectedNextDayButtonIndex = -1; | ||||
| 
 | ||||
|   List<TimeSlot> dayEvents = []; | ||||
|   List<TimeSlot> nextDayEvents = []; | ||||
| 
 | ||||
|   late Map<DateTime, List> _events; | ||||
| 
 | ||||
|   static String? selectedTime; | ||||
| 
 | ||||
|   bool isWaitingAppointmentAvailable = false; | ||||
|   final _selectedDay = DateTime.now(); | ||||
| 
 | ||||
|   @override | ||||
|   void initState() { | ||||
|     scheduleMicrotask(() { | ||||
|       _calendarController = CalendarController(); | ||||
|       _events = { | ||||
|         _selectedDay: ['Event A0'] | ||||
|       }; | ||||
|       _onDaySelected(DateUtil.convertStringToDate(bookAppointmentsViewModel.freeSlotsResponse[0])); | ||||
|     }); | ||||
|     super.initState(); | ||||
|   } | ||||
| 
 | ||||
|   @override | ||||
|   Widget build(BuildContext context) { | ||||
|     bookAppointmentsViewModel = Provider.of<BookAppointmentsViewModel>(context, listen: false); | ||||
|     appState = getIt.get<AppState>(); | ||||
|     return Column( | ||||
|       crossAxisAlignment: CrossAxisAlignment.start, | ||||
|       children: [ | ||||
|         SizedBox( | ||||
|           height: 380.h, | ||||
|           child: SfCalendar( | ||||
|             controller: _calendarController, | ||||
|             minDate: DateTime.now(), | ||||
|             showNavigationArrow: true, | ||||
|             headerHeight: 60.h, | ||||
|             headerStyle: CalendarHeaderStyle( | ||||
|               backgroundColor: AppColors.scaffoldBgColor, | ||||
|               textAlign: TextAlign.start, | ||||
|               textStyle: TextStyle(fontSize: 18.fSize, fontWeight: FontWeight.w600, letterSpacing: -0.46, color: AppColors.primaryRedColor, fontFamily: "Poppins"), | ||||
|             ), | ||||
|             viewHeaderStyle: ViewHeaderStyle( | ||||
|               backgroundColor: AppColors.scaffoldBgColor, | ||||
|               dayTextStyle: TextStyle(fontSize: 14.fSize, fontWeight: FontWeight.w600, letterSpacing: -0.46, color: AppColors.textColor), | ||||
|             ), | ||||
|             view: CalendarView.month, | ||||
|             todayHighlightColor: Colors.transparent, | ||||
|             todayTextStyle: TextStyle(color: AppColors.textColor), | ||||
|             selectionDecoration: ShapeDecoration( | ||||
|               color: AppColors.transparent, | ||||
|               shape: SmoothRectangleBorder( | ||||
|                 borderRadius: BorderRadius.circular(12 ?? 0), | ||||
|                 smoothness: 1, | ||||
|                 side: BorderSide(color: AppColors.primaryRedColor, width: 1.5), | ||||
|               ), | ||||
|             ), | ||||
|             cellBorderColor: AppColors.transparent, | ||||
|             dataSource: MeetingDataSource(_getDataSource()), | ||||
|             monthCellBuilder: (context, details) => Padding( | ||||
|               padding: EdgeInsets.all(12.h), | ||||
|               child: details.date.day.toString().toText14( | ||||
|                     isCenter: true, | ||||
|                     color: details.date == _calendarController.selectedDate ? AppColors.primaryRedColor : AppColors.textColor, | ||||
|                   ), | ||||
|             ), | ||||
|             monthViewSettings: MonthViewSettings( | ||||
|               dayFormat: "EEE", | ||||
|               appointmentDisplayMode: MonthAppointmentDisplayMode.indicator, | ||||
|               showTrailingAndLeadingDates: false, | ||||
|               appointmentDisplayCount: 1, | ||||
|               monthCellStyle: MonthCellStyle( | ||||
|                 textStyle: TextStyle(fontSize: 19.fSize), | ||||
|               ), | ||||
|             ), | ||||
|             onTap: (CalendarTapDetails details) { | ||||
|               _calendarController.selectedDate = details.date; | ||||
|               _onDaySelected(details.date!); | ||||
|             }, | ||||
|           ), | ||||
|         ), | ||||
|         //TODO: Add Next Day Span here | ||||
|         Container( | ||||
|           height: 40, | ||||
|           child: ListView.builder( | ||||
|             scrollDirection: Axis.horizontal, | ||||
|             itemCount: dayEvents.length, | ||||
|             itemBuilder: (context, index) { | ||||
|               return Container( | ||||
|                 margin: EdgeInsets.only(right: (index == dayEvents.length - 1) ? 16 : 5.0, left: index == 0 ? 16 : 5), | ||||
|                 child: AppCustomChipWidget( | ||||
|                   labelText: dayEvents[index].isoTime, | ||||
|                   backgroundColor: AppColors.whiteColor, | ||||
|                 ), | ||||
|                 // index == selectedButtonIndex ? getSelectedButton(index) : getNormalButton(index), | ||||
|               ); | ||||
|             }, | ||||
|           ), | ||||
|         ), | ||||
|       ], | ||||
|     ); | ||||
|   } | ||||
| 
 | ||||
|   List<Meeting> _getDataSource() { | ||||
|     final List<Meeting> meetings = <Meeting>[]; | ||||
|     for (var slot in bookAppointmentsViewModel.freeSlotsResponse) { | ||||
|       final startTime = DateUtil.convertStringToDate(slot); | ||||
| 
 | ||||
|       final endTime = startTime.add(const Duration(minutes: 15)); | ||||
| 
 | ||||
|       meetings.add(Meeting( | ||||
|           "Available", // Or leave empty with "" | ||||
|           startTime, | ||||
|           endTime, | ||||
|           AppColors.primaryRedColor, | ||||
|           false, | ||||
|           "" // Optional notes | ||||
|           )); | ||||
|     } | ||||
|     return meetings; | ||||
|   } | ||||
| 
 | ||||
|   // TODO: | ||||
|   openTimeSlotsPickerForDate(DateTime dateStart, List<TimeSlot> freeSlots) { | ||||
|     dayEvents.clear(); | ||||
|     DateTime dateStartObj = new DateTime(dateStart.year, dateStart.month, dateStart.day, 0, 0, 0, 0, 0); | ||||
|     if (isWaitingAppointmentAvailable && DateUtils.isSameDay(dateStart, DateTime.now())) { | ||||
|       dayEvents.add(TimeSlot(isoTime: "Waiting Appointment", start: DateTime.now(), end: DateTime.now(), vidaDate: "")); | ||||
|     } | ||||
|     freeSlots.forEach((v) { | ||||
|       if (v.start == dateStartObj) dayEvents.add(v); | ||||
|     }); | ||||
|     selectedButtonIndex = 0; | ||||
|     List<Map<String, dynamic>> timeList = []; | ||||
|     for (var i = 0; i < dayEvents.length; i++) { | ||||
|       Map<String, dynamic> timeSlot = {"isoTime": dayEvents[i].isoTime, "start": dayEvents[i].start.toString(), "end": dayEvents[i].end.toString(), "vidaDate": dayEvents[i].vidaDate}; | ||||
|       timeList.add(timeSlot); | ||||
|     } | ||||
|     selectedTime = dayEvents[selectedButtonIndex].isoTime; | ||||
|   } | ||||
| 
 | ||||
|   void _onDaySelected(DateTime day) { | ||||
|     final DateFormat formatter = DateFormat('yyyy-MM-dd'); | ||||
|     setState(() { | ||||
|       selectedDate = DateUtil.getWeekDayMonthDayYearDateFormatted(day, "en"); | ||||
|       selectedNextDate = DateUtil.getWeekDayMonthDayYearDateFormatted(day.add(Duration(days: 1)), "en"); | ||||
|       _calendarController.selectedDate = day; | ||||
|       openTimeSlotsPickerForDate(day, bookAppointmentsViewModel.docFreeSlots); | ||||
|       selectedDate = formatter.format(day); | ||||
|       selectedNextDayButtonIndex = -1; | ||||
|       print(_calendarController.selectedDate); | ||||
|     }); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| class MeetingDataSource extends CalendarDataSource { | ||||
|   MeetingDataSource(List<Meeting> source) { | ||||
|     appointments = source; | ||||
|   } | ||||
| 
 | ||||
|   @override | ||||
|   DateTime getStartTime(int index) { | ||||
|     return _getMeetingData(index)!.from; | ||||
|   } | ||||
| 
 | ||||
|   @override | ||||
|   DateTime getEndTime(int index) { | ||||
|     return _getMeetingData(index)!.to; | ||||
|   } | ||||
| 
 | ||||
|   @override | ||||
|   String getSubject(int index) { | ||||
|     return _getMeetingData(index)!.eventName; | ||||
|   } | ||||
| 
 | ||||
|   @override | ||||
|   Color getColor(int index) { | ||||
|     return _getMeetingData(index)!.background; | ||||
|   } | ||||
| 
 | ||||
|   @override | ||||
|   bool isAllDay(int index) { | ||||
|     return _getMeetingData(index)!.isAllDay; | ||||
|   } | ||||
| 
 | ||||
|   Meeting? _getMeetingData(int index) { | ||||
|     final dynamic meeting = appointments?[index]; | ||||
|     Meeting? meetingData; | ||||
|     if (meeting is Meeting) { | ||||
|       meetingData = meeting; | ||||
|     } | ||||
|     return meetingData; | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| class Meeting { | ||||
|   Meeting(this.eventName, this.from, this.to, this.background, this.isAllDay, this.notes); | ||||
| 
 | ||||
|   String eventName; | ||||
|   DateTime from; | ||||
|   DateTime to; | ||||
|   Color background; | ||||
|   bool isAllDay; | ||||
|   String notes; | ||||
| } | ||||
					Loading…
					
					
				
		Reference in New Issue