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