Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added example/assets/images/birthday_background.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added example/assets/images/meeting_background.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added example/assets/images/reminder_background.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added example/assets/images/task_background.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
10 changes: 10 additions & 0 deletions example/lib/enumerations.dart
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,13 @@ enum Months {
november,
december,
}

/// A fixed, Google-Calendar-style set of predefined event types the user can
/// pick from on the create-event page.
///
/// [EventType.event] is the neutral default: picking it preconfigures nothing
/// and leaves the form at its plain defaults. Every other type carries a
/// preset (see [kEventTypeConfigs]) that seeds the color, the whole-day /
/// duration behaviour, and the default recurrence — all of which the user can
/// still override before saving.
enum EventType { event, birthday, task, outOfOffice, meeting, reminder }
69 changes: 69 additions & 0 deletions example/lib/event_types.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import 'package:calendar_view/calendar_view.dart';
import 'package:flutter/material.dart';

import 'enumerations.dart';

/// The parameters a non-default [EventType] preconfigures on the form.
class EventTypeConfig {
/// Default event color for this type.
final Color color;

/// Whether the type defaults to a whole-day event (no start/end time).
final bool isWholeDay;

/// Default duration applied when the type is timed (`!isWholeDay`).
final Duration defaultDuration;

/// Default recurrence frequency; [RepeatFrequency.doNotRepeat] means none.
final RepeatFrequency recurrence;

/// Default event background image path for [ScheduleView]
final String? imagePath;

const EventTypeConfig({
required this.color,
this.isWholeDay = false,
this.defaultDuration = const Duration(hours: 1),
this.recurrence = RepeatFrequency.doNotRepeat,
this.imagePath,
});
}

/// Presets for every type except [EventType.event] (which intentionally has no
/// preset — selecting it resets the form to its neutral defaults).
const Map<EventType, EventTypeConfig> kEventTypeConfigs = {
EventType.birthday: EventTypeConfig(
color: Colors.pink,
isWholeDay: true,
recurrence: RepeatFrequency.yearly,
imagePath: 'assets/images/birthday_background.jpg',
),
EventType.task: EventTypeConfig(
color: Colors.green,
defaultDuration: Duration(minutes: 30),
imagePath: 'assets/images/task_background.jpg',
),
EventType.outOfOffice: EventTypeConfig(
color: Colors.orange,
isWholeDay: true,
imagePath: 'assets/images/out_of_office_background.jpg',
),
EventType.meeting: EventTypeConfig(
color: Colors.indigo,
imagePath: 'assets/images/meeting_background.jpg',
),
EventType.reminder: EventTypeConfig(
color: Colors.teal,
defaultDuration: Duration(minutes: 15),
imagePath: 'assets/images/reminder_background.jpg',
),
};

/// The payload stored on [CalendarEventData.event] so the chosen type travels
/// with the event (e.g. to display it on the details page) without changing
/// the package API.
class EventMetadata {
final EventType type;

const EventMetadata(this.type);
}
55 changes: 55 additions & 0 deletions example/lib/extension.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import 'package:flutter/material.dart';
import 'package:intl/intl.dart';

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

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

/// Reads the [EventType] back off an event's generic payload.
///
/// Returns `null` when the event carries no [EventMetadata] (e.g. events
/// created before this feature, or seeded without a type).
extension EventTypeAccess<T> on CalendarEventData<T> {
EventType? get eventType {
final payload = event;
return payload is EventMetadata ? payload.type : null;
}
}

// TODO(Lavi): Refactor this as a getter to [EventType] after upgrading dart version
/// Localized display label for each type, mirroring the example's
/// `context.translate.<key>` pattern.
extension EventTypeLabel on EventType {
String label(AppLocalizations translate) {
switch (this) {
case EventType.event:
return translate.eventTypeEvent;
case EventType.birthday:
return translate.eventTypeBirthday;
case EventType.task:
return translate.eventTypeTask;
case EventType.outOfOffice:
return translate.eventTypeOutOfOffice;
case EventType.meeting:
return translate.eventTypeMeeting;
case EventType.reminder:
return translate.eventTypeReminder;
}
}

/// A realistic default description prefilled on the create-event form when
/// this type is selected. [EventType.event] carries no preset, so it returns
/// `null` and leaves the description field empty.
String? description(AppLocalizations translate) {
switch (this) {
case EventType.event:
return null;
case EventType.birthday:
return translate.eventTypeBirthdayDescription;
case EventType.task:
return translate.eventTypeTaskDescription;
case EventType.outOfOffice:
return translate.eventTypeOutOfOfficeDescription;
case EventType.meeting:
return translate.eventTypeMeetingDescription;
case EventType.reminder:
return translate.eventTypeReminderDescription;
}
}
}

extension DateUtils on DateTime {
DateTime copyWith({
int? year,
Expand Down
12 changes: 12 additions & 0 deletions example/lib/l10n/app_ar.arb
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,18 @@
"darkMode": "الوضع المظلم:",
"eventTitle": "عنوان الحدث",
"pleaseEnterEventTitle": "الرجاء إدخال عنوان الحدث.",
"eventType": "النوع",
"eventTypeEvent": "حدث",
"eventTypeBirthday": "عيد ميلاد",
"eventTypeTask": "مهمة",
"eventTypeOutOfOffice": "خارج المكتب",
"eventTypeMeeting": "اجتماع",
"eventTypeReminder": "تذكير",
"eventTypeBirthdayDescription": "لا تنسَ إرسال تهانيك والتخطيط للاحتفال.",
"eventTypeTaskDescription": "دوّن ما يجب إنجازه، ثم ضع علامة عليه عند الانتهاء.",
"eventTypeOutOfOfficeDescription": "خارج العمل مع توفر محدود. تواصل معي عبر البريد الإلكتروني للأمور العاجلة.",
"eventTypeMeetingDescription": "جدول الأعمال: مشاركة المستجدات والاتفاق على الخطوات التالية. أضف الحضور ورابط الاجتماع.",
"eventTypeReminderDescription": "تذكير سريع حتى لا تفوتك المهمة.",
"recurringEvent": "حدث متكرر",
"startDate": "تاريخ البدء",
"pleaseSelectStartDate": "الرجاء تحديد تاريخ البدء.",
Expand Down
12 changes: 12 additions & 0 deletions example/lib/l10n/app_en.arb
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,18 @@
"darkMode": "Dark mode:",
"eventTitle": "Event Title",
"pleaseEnterEventTitle": "Please enter event title.",
"eventType": "Type",
"eventTypeEvent": "Event",
"eventTypeBirthday": "Birthday",
"eventTypeTask": "Task",
"eventTypeOutOfOffice": "Out of office",
"eventTypeMeeting": "Meeting",
"eventTypeReminder": "Reminder",
"eventTypeBirthdayDescription": "Remember to send your wishes and plan something to celebrate.",
"eventTypeTaskDescription": "Note what needs to get done, then check it off once it's complete.",
"eventTypeOutOfOfficeDescription": "Away from work with limited availability. Reach me by email for anything urgent.",
"eventTypeMeetingDescription": "Agenda: share updates and align on next steps. Add the attendees and meeting link.",
"eventTypeReminderDescription": "A quick reminder so this doesn't slip through the cracks.",
"recurringEvent": "Recurring Event",
"startDate": "Start Date",
"pleaseSelectStartDate": "Please select start date.",
Expand Down
12 changes: 12 additions & 0 deletions example/lib/l10n/app_es.arb
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,18 @@
"darkMode": "Modo oscuro:",
"eventTitle": "Título del Evento",
"pleaseEnterEventTitle": "Por favor, introduce el título del evento.",
"eventType": "Tipo",
"eventTypeEvent": "Evento",
"eventTypeBirthday": "Cumpleaños",
"eventTypeTask": "Tarea",
"eventTypeOutOfOffice": "Fuera de la oficina",
"eventTypeMeeting": "Reunión",
"eventTypeReminder": "Recordatorio",
"eventTypeBirthdayDescription": "Recuerda enviar tus felicitaciones y planear algo para celebrar.",
"eventTypeTaskDescription": "Anota lo que hay que hacer y márcalo como completado al terminar.",
"eventTypeOutOfOfficeDescription": "Fuera del trabajo con disponibilidad limitada. Escríbeme por correo para cualquier asunto urgente.",
"eventTypeMeetingDescription": "Agenda: compartir novedades y acordar los próximos pasos. Añade los asistentes y el enlace de la reunión.",
"eventTypeReminderDescription": "Un recordatorio rápido para que no se te pase.",
"recurringEvent": "Evento Recurrente",
"startDate": "Fecha de Inicio",
"pleaseSelectStartDate": "Por favor, selecciona la fecha de inicio.",
Expand Down
6 changes: 6 additions & 0 deletions example/lib/pages/event_details_page.dart
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,12 @@ class DetailsPage extends StatelessWidget {
"${translate.date} ${event.date.dateToStringWithFormat(format: "dd/MM/yyyy")}",
),
SizedBox(height: 15.0),
if (event.eventType != null) ...[
Text(
"${translate.eventType}: ${event.eventType!.label(translate)}",
),
SizedBox(height: 15.0),
],
if (event.startTime != null && event.endTime != null) ...[
Row(
children: [
Expand Down
7 changes: 6 additions & 1 deletion example/lib/pages/home_page.dart
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import 'package:calendar_view/calendar_view.dart';
import 'package:example/enumerations.dart';
import 'package:example/event_types.dart';
import 'package:example/extension.dart';
import 'package:flutter/material.dart';

Expand Down Expand Up @@ -38,7 +40,7 @@ class _HomePageState extends State<HomePage> {

final translate = context.translate;
//#region Calendar Events
final events = [
final List<CalendarEventData<Object?>> events = [
// ========== EDGE CASE 1: Midnight boundary events ==========
// Event that spans across midnight (23:00 to 01:00 next day)
CalendarEventData.timeRanged(
Expand Down Expand Up @@ -221,6 +223,7 @@ class _HomePageState extends State<HomePage> {
recurrenceEndOn: RecurrenceEnd.never,
),
color: Colors.lightGreen,
event: EventMetadata(EventType.reminder),
),

// ========== EDGE CASE 12: Event with custom styles ==========
Expand Down Expand Up @@ -318,6 +321,7 @@ class _HomePageState extends State<HomePage> {
date: _now.add(Duration(days: 7)),
endDate: _now.add(Duration(days: 9)),
color: Colors.green,
event: EventMetadata(EventType.outOfOffice),
),

// ===== EDGE CASE 21: Multi-day event with end time before start time =====
Expand All @@ -342,6 +346,7 @@ class _HomePageState extends State<HomePage> {
color: Colors.blue,
date: shortDate(_now.subtract(Duration(days: 2)), 14, 0),
endDate: shortDate(_now.subtract(Duration(days: 2)), 16, 0),
event: EventMetadata(EventType.meeting),
),
];
//#endregion
Expand Down
Loading