From c9b8fbb0c269210ce78c344511e92702e5b86048 Mon Sep 17 00:00:00 2001 From: mohammad Date: Thu, 17 Jul 2025 11:20:32 +0300 Subject: [PATCH] Refactor calendar event loading: replace parameters with LoadEventsParam class and implement memory caching for improved performance --- .../services/remote_calendar_service.dart | 9 ++-- .../domain/LoadEventsParam.dart | 28 ++++++++++++ .../services/calendar_system_service.dart | 5 +-- .../bloc/calendar/events_bloc.dart | 45 ++++++++----------- .../bloc/calendar/events_event.dart | 12 ++--- .../model/memory_bookable_space_service.dart | 35 +++++++++++++++ .../presentation/view/booking_page.dart | 11 +++-- .../view/widgets/weekly_calendar_page.dart | 2 +- 8 files changed, 100 insertions(+), 47 deletions(-) create mode 100644 lib/pages/access_management/booking_system/domain/LoadEventsParam.dart create mode 100644 lib/pages/access_management/booking_system/presentation/model/memory_bookable_space_service.dart diff --git a/lib/pages/access_management/booking_system/data/services/remote_calendar_service.dart b/lib/pages/access_management/booking_system/data/services/remote_calendar_service.dart index 15fb1fd9..55a5b0b8 100644 --- a/lib/pages/access_management/booking_system/data/services/remote_calendar_service.dart +++ b/lib/pages/access_management/booking_system/data/services/remote_calendar_service.dart @@ -1,4 +1,5 @@ import 'package:dio/dio.dart'; +import 'package:syncrow_web/pages/access_management/booking_system/domain/LoadEventsParam.dart'; import 'package:syncrow_web/pages/access_management/booking_system/domain/models/calendar_event_booking.dart'; import 'package:syncrow_web/pages/access_management/booking_system/domain/services/calendar_system_service.dart'; import 'package:syncrow_web/services/api/api_exception.dart'; @@ -13,17 +14,17 @@ class RemoteCalendarService implements CalendarSystemService { @override Future getCalendarEvents({ - required String spaceId, - required String month, - required String year, + required LoadEventsParam params, }) async { + final month = params.startDate.month.toString().padLeft(2, '0'); + final year = params.startDate.year.toString(); try { return await _httpService.get( path: ApiEndpoints.getBookings .replaceAll('{mm}', month) .replaceAll('{yyyy}', year) - .replaceAll('{space}', spaceId), + .replaceAll('{space}', params.id), expectedResponseModel: (json) { return CalendarEventsResponse.fromJson(json as Map); }, diff --git a/lib/pages/access_management/booking_system/domain/LoadEventsParam.dart b/lib/pages/access_management/booking_system/domain/LoadEventsParam.dart new file mode 100644 index 00000000..f5088b6e --- /dev/null +++ b/lib/pages/access_management/booking_system/domain/LoadEventsParam.dart @@ -0,0 +1,28 @@ +import 'package:equatable/equatable.dart'; + +class LoadEventsParam extends Equatable { + final DateTime startDate; + final DateTime endDate; + final String id; + + const LoadEventsParam({ + required this.startDate, + required this.endDate, + required this.id, + }); + + @override + List get props => [startDate, endDate, id]; + + LoadEventsParam copyWith({ + DateTime? startDate, + DateTime? endDate, + String? id, + }) { + return LoadEventsParam( + startDate: startDate ?? this.startDate, + endDate: endDate ?? this.endDate, + id: id ?? this.id, + ); + } +} diff --git a/lib/pages/access_management/booking_system/domain/services/calendar_system_service.dart b/lib/pages/access_management/booking_system/domain/services/calendar_system_service.dart index d999ef1a..3522054c 100644 --- a/lib/pages/access_management/booking_system/domain/services/calendar_system_service.dart +++ b/lib/pages/access_management/booking_system/domain/services/calendar_system_service.dart @@ -1,9 +1,8 @@ +import 'package:syncrow_web/pages/access_management/booking_system/domain/LoadEventsParam.dart'; import 'package:syncrow_web/pages/access_management/booking_system/domain/models/calendar_event_booking.dart'; abstract class CalendarSystemService { Future getCalendarEvents({ - required String spaceId, - required String month, - required String year, + required LoadEventsParam params, }); } diff --git a/lib/pages/access_management/booking_system/presentation/bloc/calendar/events_bloc.dart b/lib/pages/access_management/booking_system/presentation/bloc/calendar/events_bloc.dart index 1985348e..3945e5f5 100644 --- a/lib/pages/access_management/booking_system/presentation/bloc/calendar/events_bloc.dart +++ b/lib/pages/access_management/booking_system/presentation/bloc/calendar/events_bloc.dart @@ -2,8 +2,10 @@ import 'dart:async'; import 'package:bloc/bloc.dart'; import 'package:calendar_view/calendar_view.dart'; import 'package:flutter/material.dart'; +import 'package:syncrow_web/pages/access_management/booking_system/domain/LoadEventsParam.dart'; import 'package:syncrow_web/pages/access_management/booking_system/domain/models/calendar_event_booking.dart'; import 'package:syncrow_web/pages/access_management/booking_system/domain/services/calendar_system_service.dart'; +import 'package:syncrow_web/pages/access_management/booking_system/presentation/model/memory_bookable_space_service.dart'; part 'events_event.dart'; part 'events_state.dart'; @@ -11,12 +13,14 @@ class CalendarEventsBloc extends Bloc { final EventController eventController = EventController(); final CalendarSystemService calendarService; final Map> _eventsCache = {}; + final MemoryBookableSpaceService memoryService; - String? _lastSpaceId; - int? _lastMonth; - int? _lastYear; - CalendarEventsBloc({required this.calendarService}) : super(EventsInitial()) { + + CalendarEventsBloc({ + required this.calendarService, + required this.memoryService, + }) : super(EventsInitial()) { on(_onLoadEvents); on(_onAddEvent); on(_onDisposeResources); @@ -26,45 +30,32 @@ class CalendarEventsBloc extends Bloc { LoadEvents event, Emitter emit, ) async { - final month = event.weekEnd.month; - final year = event.weekEnd.year; - final cacheKey = - '${event.spaceId}-$year-${month.toString().padLeft(2, '0')}'; - - if (_eventsCache.containsKey(cacheKey)) { - final cachedEvents = _eventsCache[cacheKey]!; + final param = event.param; + final month = param.endDate.month; + final year = param.endDate.year; + final spaceId = param.id; + final cachedEvents = memoryService.getEvents(spaceId, year, month); + if (cachedEvents != null) { eventController.addAll(cachedEvents); emit(EventsLoaded( events: cachedEvents, - spaceId: event.spaceId, + spaceId: spaceId, month: month, year: year, )); return; } - if (_lastSpaceId == event.spaceId && - _lastMonth == month && - _lastYear == year) { - return; - } emit(EventsLoading()); try { - final response = await calendarService.getCalendarEvents( - month: month.toString().padLeft(2, '0'), - year: year.toString(), - spaceId: event.spaceId, - ); + final response = await calendarService.getCalendarEvents(params: param); final events = response.data.map(_toCalendarEventData).toList(); - _eventsCache[cacheKey] = events; + memoryService.setEvents(spaceId, year, month, events); eventController.addAll(events); - _lastSpaceId = event.spaceId; - _lastMonth = month; - _lastYear = year; emit(EventsLoaded( events: events, - spaceId: event.spaceId, + spaceId: spaceId, month: month, year: year, )); diff --git a/lib/pages/access_management/booking_system/presentation/bloc/calendar/events_event.dart b/lib/pages/access_management/booking_system/presentation/bloc/calendar/events_event.dart index 4f4cafcf..6a368e17 100644 --- a/lib/pages/access_management/booking_system/presentation/bloc/calendar/events_event.dart +++ b/lib/pages/access_management/booking_system/presentation/bloc/calendar/events_event.dart @@ -6,17 +6,11 @@ abstract class CalendarEventsEvent { } class LoadEvents extends CalendarEventsEvent { - final String spaceId; - final DateTime weekStart; - final DateTime weekEnd; - - const LoadEvents({ - required this.spaceId, - required this.weekStart, - required this.weekEnd, - }); + final LoadEventsParam param; + const LoadEvents(this.param); } + class AddEvent extends CalendarEventsEvent { final CalendarEventData event; const AddEvent(this.event); diff --git a/lib/pages/access_management/booking_system/presentation/model/memory_bookable_space_service.dart b/lib/pages/access_management/booking_system/presentation/model/memory_bookable_space_service.dart new file mode 100644 index 00000000..c9017d90 --- /dev/null +++ b/lib/pages/access_management/booking_system/presentation/model/memory_bookable_space_service.dart @@ -0,0 +1,35 @@ +import 'package:calendar_view/calendar_view.dart'; + +class MemoryBookableSpaceService { + final Map> _eventsCache = {}; + + List? getEvents(String spaceId, int year, int month) { + final key = _generateKey(spaceId, year, month); + return _eventsCache[key]; + } + + void setEvents( + String spaceId, + int year, + int month, + List events, + ) { + final key = _generateKey(spaceId, year, month); + _eventsCache[key] = events; + } + + void addEvent(String spaceId, int year, int month, CalendarEventData event) { + final key = _generateKey(spaceId, year, month); + final events = _eventsCache[key] ?? []; + events.add(event); + _eventsCache[key] = events; + } + + void clear() { + _eventsCache.clear(); + } + + String _generateKey(String spaceId, int year, int month) { + return '$spaceId-$year-${month.toString().padLeft(2, '0')}'; + } +} \ No newline at end of file diff --git a/lib/pages/access_management/booking_system/presentation/view/booking_page.dart b/lib/pages/access_management/booking_system/presentation/view/booking_page.dart index 8d04f932..1030462d 100644 --- a/lib/pages/access_management/booking_system/presentation/view/booking_page.dart +++ b/lib/pages/access_management/booking_system/presentation/view/booking_page.dart @@ -2,11 +2,13 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:calendar_view/calendar_view.dart'; import 'package:syncrow_web/pages/access_management/booking_system/data/services/remote_calendar_service.dart'; +import 'package:syncrow_web/pages/access_management/booking_system/domain/LoadEventsParam.dart'; import 'package:syncrow_web/pages/access_management/booking_system/presentation/bloc/calendar/events_bloc.dart'; import 'package:syncrow_web/pages/access_management/booking_system/presentation/bloc/date_selection/date_selection_bloc.dart'; import 'package:syncrow_web/pages/access_management/booking_system/presentation/bloc/date_selection/date_selection_event.dart'; import 'package:syncrow_web/pages/access_management/booking_system/presentation/bloc/date_selection/date_selection_state.dart'; import 'package:syncrow_web/pages/access_management/booking_system/presentation/bloc/selected_bookable_space_bloc/selected_bookable_space_bloc.dart'; +import 'package:syncrow_web/pages/access_management/booking_system/presentation/model/memory_bookable_space_service.dart'; import 'package:syncrow_web/pages/access_management/booking_system/presentation/view/widgets/booking_sidebar.dart'; import 'package:syncrow_web/pages/access_management/booking_system/presentation/view/widgets/custom_calendar_page.dart'; import 'package:syncrow_web/pages/access_management/booking_system/presentation/view/widgets/icon_text_button.dart'; @@ -46,9 +48,11 @@ class _BookingPageState extends State { if (selectedRoom != null) { context.read().add( LoadEvents( - spaceId: selectedRoom.uuid, - weekStart: dateState.weekStart, - weekEnd: dateState.weekStart.add(const Duration(days: 6)), + LoadEventsParam( + startDate: dateState.weekStart, + endDate: dateState.weekStart.add(const Duration(days: 6)), + id: selectedRoom.uuid, + ), ), ); } @@ -62,6 +66,7 @@ class _BookingPageState extends State { BlocProvider(create: (_) => DateSelectionBloc()), BlocProvider( create: (_) => CalendarEventsBloc( + memoryService: MemoryBookableSpaceService(), calendarService: RemoteCalendarService( HTTPService(), ), diff --git a/lib/pages/access_management/booking_system/presentation/view/widgets/weekly_calendar_page.dart b/lib/pages/access_management/booking_system/presentation/view/widgets/weekly_calendar_page.dart index 03972632..2bfd5429 100644 --- a/lib/pages/access_management/booking_system/presentation/view/widgets/weekly_calendar_page.dart +++ b/lib/pages/access_management/booking_system/presentation/view/widgets/weekly_calendar_page.dart @@ -24,7 +24,7 @@ class WeeklyCalendarPage extends StatelessWidget { }); static const double timeLineWidth = 65; static const int totalDays = 7; - static const double dayColumnWidth = 220; // or any width you want + static const double dayColumnWidth = 220; final double calendarContentWidth = timeLineWidth + (totalDays * dayColumnWidth);