Skip to content

Commit

Permalink
✨ Add delete recurrence event
Browse files Browse the repository at this point in the history
  • Loading branch information
shubham-jitiya-simform committed Nov 8, 2024
1 parent 51a1bcb commit 752f513
Show file tree
Hide file tree
Showing 5 changed files with 188 additions and 37 deletions.
56 changes: 35 additions & 21 deletions example/lib/pages/event_details_page.dart
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import 'package:calendar_view/calendar_view.dart';
import 'package:example/pages/web/delete_event_dialog.dart';
import 'package:flutter/material.dart';

import '../extension.dart';
Expand All @@ -16,6 +17,8 @@ class DetailsPage extends StatelessWidget {

@override
Widget build(BuildContext context) {
debugPrint('date details page: ${date}');

return Scaffold(
appBar: AppBar(
backgroundColor: event.color,
Expand Down Expand Up @@ -96,26 +99,8 @@ class DetailsPage extends StatelessWidget {
children: [
Expanded(
child: ElevatedButton(
onPressed: () {
// Delete following events
// final updatedRecurrenceSettings =
// event.recurrenceSettings?.copyWith(endDate: date);
// final updatedEvent = event.copyWith(
// recurrenceSettings: updatedRecurrenceSettings);
// CalendarControllerProvider.of(context)
// .controller
// .update(event, updatedEvent);
List<DateTime> excludeDates =
event.recurrenceSettings?.excludeDates ?? [];
excludeDates.add(date);
final updatedRecurrenceSettings = event.recurrenceSettings
?.copyWith(excludeDates: excludeDates);
final updatedEvent = event.copyWith(
recurrenceSettings: updatedRecurrenceSettings);
CalendarControllerProvider.of(context)
.controller
.update(event, updatedEvent);
// .remove(event);
onPressed: () async {
await _handleDeleteEvent(context);
Navigator.of(context).pop();
},
child: Text('Delete Event'),
Expand All @@ -133,7 +118,7 @@ class DetailsPage extends StatelessWidget {
),
);

if (result) {
if (result != null) {
Navigator.of(context).pop();
}
},
Expand All @@ -146,4 +131,33 @@ class DetailsPage extends StatelessWidget {
),
);
}

/// Handles the deletion of an event, showing a dialog for repeating events.
///
/// This method checks if the event is a repeating event. If it is, it shows
/// a dialog to the user to choose the deletion type (e.g., delete this
/// event, delete following events, delete all events).
/// If the event is not repeating, it defaults to deleting all occurrences
/// of the event.
Future<void> _handleDeleteEvent(BuildContext context) async {
DeleteEvent? result;
final isRepeatingEvent = event.recurrenceSettings != null &&
(event.recurrenceSettings?.frequency != RepeatFrequency.doNotRepeat);

if (isRepeatingEvent) {
result = await showDialog(
context: context,
builder: (_) => DeleteEventDialog(),
);
} else {
result = DeleteEvent.all;
}
if (result != null) {
CalendarControllerProvider.of(context).controller.deleteRecurrenceEvent(
date: date,
event: event,
deleteEventType: result,
);
}
}
}
63 changes: 63 additions & 0 deletions example/lib/pages/web/delete_event_dialog.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import 'package:calendar_view/calendar_view.dart';
import 'package:flutter/material.dart';

class DeleteEventDialog extends StatefulWidget {
@override
_RadioDialogState createState() => _RadioDialogState();
}

class _RadioDialogState extends State<DeleteEventDialog> {
DeleteEvent _selectedOption = DeleteEvent.current;

@override
Widget build(BuildContext context) {
return AlertDialog(
title: Text('Delete recurring event '),
content: Column(
mainAxisSize: MainAxisSize.min,
children: [
RadioListTile<DeleteEvent>(
title: Text('This event'),
value: DeleteEvent.current,
groupValue: _selectedOption,
onChanged: (deleteType) {
if (deleteType != null) {
setState(() => _selectedOption = deleteType);
}
},
),
RadioListTile<DeleteEvent>(
title: Text('This and following events'),
value: DeleteEvent.following,
groupValue: _selectedOption,
onChanged: (deleteType) {
if (deleteType != null) {
setState(() => _selectedOption = deleteType);
}
},
),
RadioListTile<DeleteEvent>(
title: Text('All events'),
value: DeleteEvent.all,
groupValue: _selectedOption,
onChanged: (deleteType) {
if (deleteType != null) {
setState(() => _selectedOption = deleteType);
}
},
),
],
),
actions: [
TextButton(
onPressed: () => Navigator.of(context).pop(),
child: Text('Cancel'),
),
TextButton(
onPressed: () => Navigator.of(context).pop(_selectedOption),
child: Text('Done'),
),
],
);
}
}
6 changes: 6 additions & 0 deletions lib/src/calendar_event_data.dart
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,12 @@ class CalendarEventData<T extends Object?> {
}
}

/// Checks if the given date is in the list of excluded dates.
/// Returns true if the date is excluded, otherwise false.
bool isExcluded(DateTime date) {
return recurrenceSettings?.excludeDates?.contains(date) ?? false;
}

/// Returns a boolean that defines whether current event is occurring on
/// [currentDate] or not.
///
Expand Down
7 changes: 7 additions & 0 deletions lib/src/enumerations.dart
Original file line number Diff line number Diff line change
Expand Up @@ -67,3 +67,10 @@ enum RecurrenceEnd {
on,
after,
}

// TODO(Shubham): Add docs
enum DeleteEvent {
all,
current,
following,
}
93 changes: 77 additions & 16 deletions lib/src/event_controller.dart
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,9 @@ class EventController<T extends Object?> extends ChangeNotifier {
required DateTime eventEndDate,
required RecurrenceSettings recurrenceSettings,
}) {
if (recurrenceSettings.excludeDates?.contains(currentDate) ?? false) {
return false;
}
switch (recurrenceSettings.frequency) {
case RepeatFrequency.daily:
return _isDailyRecurrence(
Expand Down Expand Up @@ -197,9 +200,69 @@ class EventController<T extends Object?> extends ChangeNotifier {
}
return false;
}

void _deleteCurrentEvent(DateTime date, CalendarEventData<T> event) {
List<DateTime> excludeDates = event.recurrenceSettings?.excludeDates ?? [];
excludeDates.add(date);
final updatedRecurrenceSettings =
event.recurrenceSettings?.copyWith(excludeDates: excludeDates);
final updatedEvent =
event.copyWith(recurrenceSettings: updatedRecurrenceSettings);
update(event, updatedEvent);
}

/// If the selected date to delete the event is the same as the event's start date, delete all recurrences.
/// Otherwise, delete the event on the selected date and all subsequent recurrences.
void _deleteFollowingEvents(DateTime date, CalendarEventData<T> event) {
final updatedRecurrenceSettings = event.recurrenceSettings?.copyWith(
endDate: date.subtract(
Duration(days: 1),
),
);
if (date == event.date) {
remove(event);
} else {
debugPrint('Event: delete event ${event}');
final updatedEvent =
event.copyWith(recurrenceSettings: updatedRecurrenceSettings);
update(event, updatedEvent);
}
}
//#endregion

//#region Public Methods
/// Deletes a recurring event based on the specified deletion type.
///
/// This method handles the deletion of recurring events by determining the type of deletion
/// requested (all events, the current event, or following events) and performing the appropriate action.
///
/// Takes the following parameters:
/// - [date]: The date of the event to be deleted.
/// - [event]: The event data to be deleted.
/// - [deleteEventType]: The `DeleteEventType` of deletion to perform (all events, the current event, or following events).
///
/// The method performs the following actions based on the [deleteEventType]:
/// - [DeleteEvent.all]: Removes the entire series of events.
/// - [DeleteEvent.current]: Deletes only the current event.
/// - [DeleteEvent.following]: Deletes the current event and all subsequent events.
void deleteRecurrenceEvent({
required DateTime date,
required CalendarEventData<T> event,
required DeleteEvent deleteEventType,
}) {
switch (deleteEventType) {
case DeleteEvent.all:
remove(event);
break;
case DeleteEvent.current:
_deleteCurrentEvent(date, event);
break;
case DeleteEvent.following:
_deleteFollowingEvents(date, event);
break;
}
}

/// Add all the events in the list
/// If there is an event with same date then
void addAll(List<CalendarEventData<T>> events) {
Expand Down Expand Up @@ -267,19 +330,20 @@ class EventController<T extends Object?> extends ChangeNotifier {
includeFullDayEvents: includeFullDayEvents);
}

/// Get all events including repeated events on that day
/// Retrieves all events for a given date, including repeated events that are not excluded on that day.
///
/// This method combines events that occur on the specified date with repeated events that are not excluded.
/// It filters out any events that are marked as excluded for the given date.
///
/// Takes a [date] parameter representing the date for which to retrieve events.
/// Returns a list of [CalendarEventData] objects representing all events on the specified date.
List<CalendarEventData<T>> getAllEventsOnDay(DateTime date) {
final events = getEventsOnDay(date);

debugPrint('Day: ${date.day} Events: ${events}');
final repeatedEvents = getRepeatedEvents(date);
final events =
getEventsOnDay(date).where((event) => !event.isExcluded(date)).toList();
final repeatedEvents =
getRepeatedEvents(date).where((event) => !event.isExcluded(date));
events.addAll(repeatedEvents);

// For range of events having occurrence add only single time
for (final event in repeatedEvents) {
if (!events.contains(event)) {
events.add(event);
}
}
return events;
}

Expand All @@ -299,15 +363,12 @@ class EventController<T extends Object?> extends ChangeNotifier {
continue;
}
final recurrenceSettings = event.recurrenceSettings;
debugPrint('Date: ${date} | Recurrence settings: ${recurrenceSettings}');
// debugPrint('Date: ${date} | Recurrence settings: ${recurrenceSettings}');
// if event is not repeating or date is in excluded
if (recurrenceSettings == null ||
(recurrenceSettings.excludeDates?.contains(date) ?? false)) {
if (recurrenceSettings == null) {
continue;
}

debugPrint(
'Date: ${date} | Is excluded dates: ${recurrenceSettings.excludeDates}');
final isRecurrence = _handleRecurrence(
currentDate: date,
eventStartDate: event.date,
Expand Down

0 comments on commit 752f513

Please sign in to comment.