refactored timetable
This commit is contained in:
@@ -1,5 +1,3 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:syncfusion_flutter_calendar/calendar.dart';
|
||||
@@ -12,12 +10,11 @@ import '../../../state/app/modules/settings/bloc/settings_cubit.dart';
|
||||
import 'custom_events/custom_event_edit_dialog.dart';
|
||||
import 'custom_events/custom_events_view.dart';
|
||||
import 'data/arbitrary_appointment.dart';
|
||||
import 'data/lesson_period_schedule.dart';
|
||||
import 'data/timetable_appointment_factory.dart';
|
||||
import 'details/appointment_details_dispatcher.dart';
|
||||
import 'widgets/appointment_tile.dart';
|
||||
import 'widgets/lesson_appointment_source.dart';
|
||||
import 'widgets/custom_workweek_calendar.dart';
|
||||
import 'widgets/special_regions_builder.dart';
|
||||
import 'widgets/time_region_tile.dart';
|
||||
|
||||
enum _CalendarAction { addEvent, viewEvents }
|
||||
|
||||
@@ -29,32 +26,15 @@ class Timetable extends StatefulWidget {
|
||||
}
|
||||
|
||||
class _TimetableState extends State<Timetable> {
|
||||
final CalendarController _controller = CalendarController();
|
||||
late Timer _highlightTicker;
|
||||
final GlobalKey<CustomWorkWeekCalendarState> _calendarKey = GlobalKey<CustomWorkWeekCalendarState>();
|
||||
|
||||
LessonAppointmentSource? _cachedSource;
|
||||
List<Appointment>? _cachedAppointments;
|
||||
int? _lastDataVersion;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_controller.displayDate = _initialDisplayDate();
|
||||
|
||||
_highlightTicker = Timer.periodic(const Duration(seconds: 30), (_) {
|
||||
if (mounted) setState(() => _cachedSource = null);
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_highlightTicker.cancel();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
DateTime _initialDisplayDate() => DateTime.now().add(const Duration(days: 2));
|
||||
|
||||
void _jumpToToday() {
|
||||
_controller.displayDate = _initialDisplayDate();
|
||||
_calendarKey.currentState?.jumpToDate(_initialDisplayDate());
|
||||
}
|
||||
|
||||
void _onAction(_CalendarAction action) {
|
||||
@@ -70,24 +50,27 @@ class _TimetableState extends State<Timetable> {
|
||||
}
|
||||
}
|
||||
|
||||
LessonAppointmentSource _appointmentSource(TimetableState state) {
|
||||
if (_cachedSource != null && _lastDataVersion == state.dataVersion) {
|
||||
return _cachedSource!;
|
||||
List<Appointment> _appointments(TimetableState state) {
|
||||
if (_cachedAppointments != null && _lastDataVersion == state.dataVersion) {
|
||||
return _cachedAppointments!;
|
||||
}
|
||||
_lastDataVersion = state.dataVersion;
|
||||
|
||||
final settings = context.read<SettingsCubit>();
|
||||
final appointments = TimetableAppointmentFactory(
|
||||
return _cachedAppointments = TimetableAppointmentFactory(
|
||||
lessons: state.getAllKnownLessons().toList(),
|
||||
customEvents: state.customEvents?.events ?? const [],
|
||||
rooms: state.rooms!,
|
||||
subjects: state.subjects!,
|
||||
settings: settings.val().timetableSettings,
|
||||
colorScheme: Theme.of(context).colorScheme,
|
||||
now: DateTime.now(),
|
||||
).build();
|
||||
}
|
||||
|
||||
return _cachedSource = LessonAppointmentSource(appointments);
|
||||
bool _isCrossedOut(Appointment appointment) {
|
||||
final id = appointment.id;
|
||||
if (id is WebuntisAppointment) return id.lesson.code == 'cancelled';
|
||||
return false;
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -126,54 +109,35 @@ class _TimetableState extends State<Timetable> {
|
||||
Widget _calendar(TimetableState state, TimetableBloc bloc) {
|
||||
if (!state.hasReferenceData) return const SizedBox.shrink();
|
||||
|
||||
return SfCalendar(
|
||||
timeZone: 'W. Europe Standard Time',
|
||||
view: CalendarView.workWeek,
|
||||
dataSource: _appointmentSource(state),
|
||||
maxDate: DateTime.now().add(const Duration(days: 7)).nextWeekday(DateTime.saturday),
|
||||
final schedule = LessonPeriodSchedule.fromState(state);
|
||||
final appointments = _appointments(state);
|
||||
final regions = SpecialRegionsBuilder(
|
||||
holidays: state.schoolHolidays!,
|
||||
schedule: schedule,
|
||||
colorScheme: Theme.of(context).colorScheme,
|
||||
disabledColor: Theme.of(context).disabledColor,
|
||||
).build();
|
||||
|
||||
return CustomWorkWeekCalendar(
|
||||
key: _calendarKey,
|
||||
schedule: schedule,
|
||||
appointments: appointments,
|
||||
timeRegions: regions,
|
||||
initialDate: _initialDisplayDate(),
|
||||
minDate: DateTime.now().subtract(const Duration(days: 14)).nextWeekday(DateTime.sunday),
|
||||
controller: _controller,
|
||||
onViewChanged: (details) {
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
if (!mounted) return;
|
||||
bloc.changeWeek(details.visibleDates.first, details.visibleDates.last);
|
||||
});
|
||||
},
|
||||
onTap: (tap) {
|
||||
if (tap.appointments == null || tap.appointments!.isEmpty) return;
|
||||
AppointmentDetailsDispatcher.show(context, bloc, tap.appointments!.first);
|
||||
},
|
||||
firstDayOfWeek: DateTime.monday,
|
||||
specialRegions: SpecialRegionsBuilder(
|
||||
holidays: state.schoolHolidays!,
|
||||
colorScheme: Theme.of(context).colorScheme,
|
||||
disabledColor: Theme.of(context).disabledColor,
|
||||
).build(),
|
||||
timeSlotViewSettings: const TimeSlotViewSettings(
|
||||
startHour: 7.5,
|
||||
endHour: 16.5,
|
||||
timeInterval: Duration(minutes: 30),
|
||||
timeFormat: 'HH:mm',
|
||||
dayFormat: 'EE',
|
||||
timeIntervalHeight: 40,
|
||||
),
|
||||
timeRegionBuilder: (_, details) => TimeRegionTile(details: details),
|
||||
appointmentBuilder: (_, details) => AppointmentTile(
|
||||
details: details,
|
||||
crossedOut: _isCrossedOut(details),
|
||||
),
|
||||
headerHeight: 0,
|
||||
selectionDecoration: const BoxDecoration(),
|
||||
allowAppointmentResize: false,
|
||||
allowDragAndDrop: false,
|
||||
allowViewNavigation: false,
|
||||
maxDate: DateTime.now().add(const Duration(days: 7)).nextWeekday(DateTime.saturday),
|
||||
onAppointmentTap: (apt) => AppointmentDetailsDispatcher.show(context, bloc, apt),
|
||||
onWeekChanged: (start, end) => bloc.changeWeek(start, end),
|
||||
isCrossedOut: _isCrossedOut,
|
||||
onCreateEvent: _onCreateEventAt,
|
||||
);
|
||||
}
|
||||
|
||||
bool _isCrossedOut(CalendarAppointmentDetails details) {
|
||||
final appointment = details.appointments.first;
|
||||
final id = appointment.id;
|
||||
if (id is WebuntisAppointment) return id.lesson.code == 'cancelled';
|
||||
return false;
|
||||
void _onCreateEventAt(DateTime start, DateTime end) {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (_) => CustomEventEditDialog(initialStart: start, initialEnd: end),
|
||||
barrierDismissible: false,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user