Skip to content

Commit a99afd3

Browse files
✨ Add predefined event-type system to create-event form
1 parent dc7f19b commit a99afd3

16 files changed

Lines changed: 384 additions & 75 deletions
37.8 KB
Loading
29.7 KB
Loading
30.3 KB
Loading
34.7 KB
Loading
30.3 KB
Loading

example/lib/enumerations.dart

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,3 +16,13 @@ enum Months {
1616
november,
1717
december,
1818
}
19+
20+
/// A fixed, Google-Calendar-style set of predefined event types the user can
21+
/// pick from on the create-event page.
22+
///
23+
/// [EventType.event] is the neutral default: picking it preconfigures nothing
24+
/// and leaves the form at its plain defaults. Every other type carries a
25+
/// preset (see [kEventTypeConfigs]) that seeds the color, the whole-day /
26+
/// duration behaviour, and the default recurrence — all of which the user can
27+
/// still override before saving.
28+
enum EventType { event, birthday, task, outOfOffice, meeting, reminder }

example/lib/event_types.dart

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
import 'package:calendar_view/calendar_view.dart';
2+
import 'package:flutter/material.dart';
3+
4+
import 'enumerations.dart';
5+
6+
/// The parameters a non-default [EventType] preconfigures on the form.
7+
class EventTypeConfig {
8+
/// Default event color for this type.
9+
final Color color;
10+
11+
/// Whether the type defaults to a whole-day event (no start/end time).
12+
final bool isWholeDay;
13+
14+
/// Default duration applied when the type is timed (`!isWholeDay`).
15+
final Duration defaultDuration;
16+
17+
/// Default recurrence frequency; [RepeatFrequency.doNotRepeat] means none.
18+
final RepeatFrequency recurrence;
19+
20+
/// Default event background image path for [ScheduleView]
21+
final String? imagePath;
22+
23+
const EventTypeConfig({
24+
required this.color,
25+
this.isWholeDay = false,
26+
this.defaultDuration = const Duration(hours: 1),
27+
this.recurrence = RepeatFrequency.doNotRepeat,
28+
this.imagePath,
29+
});
30+
}
31+
32+
/// Presets for every type except [EventType.event] (which intentionally has no
33+
/// preset — selecting it resets the form to its neutral defaults).
34+
const Map<EventType, EventTypeConfig> kEventTypeConfigs = {
35+
EventType.birthday: EventTypeConfig(
36+
color: Colors.pink,
37+
isWholeDay: true,
38+
recurrence: RepeatFrequency.yearly,
39+
imagePath: 'assets/images/birthday_background.jpg',
40+
),
41+
EventType.task: EventTypeConfig(
42+
color: Colors.green,
43+
defaultDuration: Duration(minutes: 30),
44+
imagePath: 'assets/images/task_background.jpg',
45+
),
46+
EventType.outOfOffice: EventTypeConfig(
47+
color: Colors.orange,
48+
isWholeDay: true,
49+
imagePath: 'assets/images/out_of_office_background.jpg',
50+
),
51+
EventType.meeting: EventTypeConfig(
52+
color: Colors.indigo,
53+
imagePath: 'assets/images/meeting_background.jpg',
54+
),
55+
EventType.reminder: EventTypeConfig(
56+
color: Colors.teal,
57+
defaultDuration: Duration(minutes: 15),
58+
imagePath: 'assets/images/reminder_background.jpg',
59+
),
60+
};
61+
62+
/// The payload stored on [CalendarEventData.event] so the chosen type travels
63+
/// with the event (e.g. to display it on the details page) without changing
64+
/// the package API.
65+
class EventMetadata {
66+
final EventType type;
67+
68+
const EventMetadata(this.type);
69+
}

example/lib/extension.dart

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import 'package:flutter/material.dart';
33
import 'package:intl/intl.dart';
44

55
import 'enumerations.dart';
6+
import 'event_types.dart';
67
import 'l10n/app_localizations.dart';
78
import 'localization/locale_controller.dart';
89
import 'theme/app_colors.dart';
@@ -24,6 +25,7 @@ extension NavigatorExtention on BuildContext {
2425
..showSnackBar(SnackBar(content: Text(text), duration: duration));
2526
}
2627

28+
// TODO(Lavi): Refactor this as a getter of [Months] after upgrading dart version
2729
extension MonthHeaderImageExtension on Months {
2830
/// Returns the asset path for this month's header image.
2931
String get imagePath {
@@ -45,6 +47,59 @@ extension MonthHeaderImageExtension on Months {
4547
}
4648
}
4749

50+
/// Reads the [EventType] back off an event's generic payload.
51+
///
52+
/// Returns `null` when the event carries no [EventMetadata] (e.g. events
53+
/// created before this feature, or seeded without a type).
54+
extension EventTypeAccess<T> on CalendarEventData<T> {
55+
EventType? get eventType {
56+
final payload = event;
57+
return payload is EventMetadata ? payload.type : null;
58+
}
59+
}
60+
61+
// TODO(Lavi): Refactor this as a getter to [EventType] after upgrading dart version
62+
/// Localized display label for each type, mirroring the example's
63+
/// `context.translate.<key>` pattern.
64+
extension EventTypeLabel on EventType {
65+
String label(AppLocalizations translate) {
66+
switch (this) {
67+
case EventType.event:
68+
return translate.eventTypeEvent;
69+
case EventType.birthday:
70+
return translate.eventTypeBirthday;
71+
case EventType.task:
72+
return translate.eventTypeTask;
73+
case EventType.outOfOffice:
74+
return translate.eventTypeOutOfOffice;
75+
case EventType.meeting:
76+
return translate.eventTypeMeeting;
77+
case EventType.reminder:
78+
return translate.eventTypeReminder;
79+
}
80+
}
81+
82+
/// A realistic default description prefilled on the create-event form when
83+
/// this type is selected. [EventType.event] carries no preset, so it returns
84+
/// `null` and leaves the description field empty.
85+
String? description(AppLocalizations translate) {
86+
switch (this) {
87+
case EventType.event:
88+
return null;
89+
case EventType.birthday:
90+
return translate.eventTypeBirthdayDescription;
91+
case EventType.task:
92+
return translate.eventTypeTaskDescription;
93+
case EventType.outOfOffice:
94+
return translate.eventTypeOutOfOfficeDescription;
95+
case EventType.meeting:
96+
return translate.eventTypeMeetingDescription;
97+
case EventType.reminder:
98+
return translate.eventTypeReminderDescription;
99+
}
100+
}
101+
}
102+
48103
extension DateUtils on DateTime {
49104
DateTime copyWith({
50105
int? year,

example/lib/l10n/app_ar.arb

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,18 @@
3030
"darkMode": "الوضع المظلم:",
3131
"eventTitle": "عنوان الحدث",
3232
"pleaseEnterEventTitle": "الرجاء إدخال عنوان الحدث.",
33+
"eventType": "النوع",
34+
"eventTypeEvent": "حدث",
35+
"eventTypeBirthday": "عيد ميلاد",
36+
"eventTypeTask": "مهمة",
37+
"eventTypeOutOfOffice": "خارج المكتب",
38+
"eventTypeMeeting": "اجتماع",
39+
"eventTypeReminder": "تذكير",
40+
"eventTypeBirthdayDescription": "لا تنسَ إرسال تهانيك والتخطيط للاحتفال.",
41+
"eventTypeTaskDescription": "دوّن ما يجب إنجازه، ثم ضع علامة عليه عند الانتهاء.",
42+
"eventTypeOutOfOfficeDescription": "خارج العمل مع توفر محدود. تواصل معي عبر البريد الإلكتروني للأمور العاجلة.",
43+
"eventTypeMeetingDescription": "جدول الأعمال: مشاركة المستجدات والاتفاق على الخطوات التالية. أضف الحضور ورابط الاجتماع.",
44+
"eventTypeReminderDescription": "تذكير سريع حتى لا تفوتك المهمة.",
3345
"recurringEvent": "حدث متكرر",
3446
"startDate": "تاريخ البدء",
3547
"pleaseSelectStartDate": "الرجاء تحديد تاريخ البدء.",

example/lib/l10n/app_en.arb

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,18 @@
3030
"darkMode": "Dark mode:",
3131
"eventTitle": "Event Title",
3232
"pleaseEnterEventTitle": "Please enter event title.",
33+
"eventType": "Type",
34+
"eventTypeEvent": "Event",
35+
"eventTypeBirthday": "Birthday",
36+
"eventTypeTask": "Task",
37+
"eventTypeOutOfOffice": "Out of office",
38+
"eventTypeMeeting": "Meeting",
39+
"eventTypeReminder": "Reminder",
40+
"eventTypeBirthdayDescription": "Remember to send your wishes and plan something to celebrate.",
41+
"eventTypeTaskDescription": "Note what needs to get done, then check it off once it's complete.",
42+
"eventTypeOutOfOfficeDescription": "Away from work with limited availability. Reach me by email for anything urgent.",
43+
"eventTypeMeetingDescription": "Agenda: share updates and align on next steps. Add the attendees and meeting link.",
44+
"eventTypeReminderDescription": "A quick reminder so this doesn't slip through the cracks.",
3345
"recurringEvent": "Recurring Event",
3446
"startDate": "Start Date",
3547
"pleaseSelectStartDate": "Please select start date.",

0 commit comments

Comments
 (0)