Skip to content

Commit f456092

Browse files
✨ Add Schedule View with customizable event display, navigation, localization, and theming
1 parent 420a9a4 commit f456092

60 files changed

Lines changed: 3773 additions & 101 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
# [Unreleased - 29 May 2026]
22

3+
- Added `ScheduleView`, a scrollable, agenda-style calendar that groups events by day and month. [#101](https://github.com/SimformSolutionsPvtLtd/flutter_calendar_view/issues/101)
4+
- Added localized `months` and `monthsAbbr` fields to `CalendarLocalizations`, with the `DateTime.getMonthName({abbreviated})` and `DateTime.getMonthYear({abbreviatedMonth})` extensions.
5+
- Added `BuildContextThemeExtension` to public API for accessing calendar view themes via `context.dayViewColors`, `context.weekViewColors`, etc.
36
- [BREAKING] Changed `RecurrenceSettings.weekdays` type from `List<int>` to `List<WeekDays>`. [#509](https://github.com/SimformSolutionsPvtLtd/flutter_calendar_view/issues/509)
47
- [BREAKING] `WeekDayBuilder`'s parameter changed from `int day` to `WeekDays weekDay`.
58
- [BREAKING] Removed `startTime` and `endTime` from `CalendarEventData` constructor and `copyWith` parameters. Time is now embedded in the `date` and `endDate` `DateTime` parameters. [#231](https://github.com/SimformSolutionsPvtLtd/flutter_calendar_view/issues/231)

doc/documentation.md

Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ This package is a comprehensive Flutter solution that enables you to easily impl
1414
- Day View
1515
- Week View
1616
- MultiDay View
17+
- Schedule View
1718
- Highly customisable UI components
1819
- Manage events (add, remove, update)
1920
- Manage reminders (add, remove, update)
@@ -109,6 +110,14 @@ Scaffold(
109110
);
110111
```
111112

113+
### Schedule View
114+
115+
```dart
116+
Scaffold(
117+
body: ScheduleView(),
118+
);
119+
```
120+
112121
## Managing Events
113122

114123
### Adding an event
@@ -557,6 +566,84 @@ MultiDayView(
557566
);
558567
```
559568

569+
## Schedule View Customization
570+
571+
`ScheduleView` is a scrollable, agenda-style calendar that groups events by day and month. Months are built lazily as they scroll into view, and the list is anchored at `initialDay`.
572+
573+
```dart
574+
ScheduleView(
575+
controller: EventController(),
576+
// Anchor and date boundaries
577+
initialDay: DateTime.now(), // Date pinned to the top of the viewport
578+
minDay: DateTime(2000), // Earliest date the view will display
579+
maxDay: DateTime(2050), // Latest date the view will display
580+
// Which days/months are rendered
581+
showEmptyMonths: true, // Render months that contain no events (default true)
582+
showDaysWithoutEvents: false, // Render a row for every day, even empty ones (default false)
583+
// Date placement
584+
dateLayout: ScheduleDateLayout.left, // .left (date column) or .top (full-width date header)
585+
// Custom builders
586+
monthHeaderBuilder: (date) => Text(date.getMonthYear()),
587+
dateHeaderBuilder: (date, events, layout) => Text('${date.day}'),
588+
// dayDetectorBuilder takes full control of the date column, including gestures.
589+
// When set, onDateTap / onDateLongPress are ignored.
590+
dayDetectorBuilder: (date, events, layout) => Container(),
591+
eventTileBuilder: (event, date) => ListTile(
592+
leading: CircleAvatar(backgroundColor: event.color),
593+
title: Text(event.title),
594+
),
595+
emptyMonthBuilder: (date) => Text('No events this month'), // Replaces empty months (showEmptyMonths must be true)
596+
emptyTextWidget: Text('No events'), // Empty-day placeholder (needs showDaysWithoutEvents: true)
597+
todayEmptyWidget: Text('Nothing planned today'), // Takes precedence over emptyTextWidget for today
598+
// Floating month header pinned above the scroll view
599+
floatingMonthHeaderBuilder: (context, visibleMonth) => Padding(
600+
padding: const EdgeInsets.all(12),
601+
child: Text(visibleMonth.getMonthYear()),
602+
),
603+
onVisibleMonthChanged: (month) => print('Visible month: $month'),
604+
// Sentinels shown once the scroll limits are reached
605+
pastSentinelBuilder: (context) => const Center(child: Text('Start of calendar')),
606+
futureSentinelBuilder: (context) => const Center(child: Text('End of calendar')),
607+
// I18n / formatting for the default renderers
608+
dateStringBuilder: (date, {secondaryDate}) => date.getMonthYear(),
609+
weekDayStringBuilder: (weekday) => ['M', 'T', 'W', 'T', 'F', 'S', 'S'][weekday - 1],
610+
// Sort events within a single day (defaults to ascending start time)
611+
eventSorter: (a, b) => a.title.compareTo(b.title),
612+
// Divider beneath the default date header in ScheduleDateLayout.top
613+
defaultDateHeaderDividerSettings: DividerSettings(thickness: 1, color: Colors.grey),
614+
// Event callbacks (each receives a single-element list + the date)
615+
onEventTap: (events, date) => print(events),
616+
onEventDoubleTap: (events, date) => print(events),
617+
onEventLongTap: (events, date) => print(events),
618+
onDateTap: (date) => print('Tapped: $date'),
619+
onDateLongPress: (date) => print('Long pressed: $date'),
620+
// Boundary callbacks (fire once when each end of the range is reached)
621+
onHasReachedStart: () => print('Reached earliest available month'),
622+
onHasReachedEnd: () => print('Reached latest available month'),
623+
// Appearance
624+
backgroundColor: Colors.white,
625+
width: 400, // Explicit width; null fills available space
626+
scrollPhysics: const BouncingScrollPhysics(),
627+
);
628+
```
629+
630+
### Navigating programmatically
631+
632+
Use a `GlobalKey<ScheduleViewState>` to jump to a specific date. The target date is pinned to the top of the viewport, with earlier days reachable by scrolling up.
633+
634+
```dart
635+
final key = GlobalKey<ScheduleViewState>();
636+
637+
ScheduleView(key: key);
638+
639+
key.currentState?.jumpToDate(DateTime(2026, 1, 1));
640+
```
641+
642+
### Sparse vs. dense rendering
643+
644+
- **Sparse (default)**`showEmptyMonths: false` and `showDaysWithoutEvents: false`. Only days with events (plus today) render, and the scrollable range is clamped to the actual extent of the controller's events. This keeps the view responsive even when `minDay`/`maxDay` span decades.
645+
- **Dense** — set `showEmptyMonths: true` (default) to always render every month in range, and/or `showDaysWithoutEvents: true` to render a row for every day.
646+
560647
## Show Only Working Days in `WeekView`
561648

562649
You can control visible weekdays using the `weekDays` parameter:
@@ -833,6 +920,7 @@ The package supports dark mode out of the box. Each calendar view has a dedicate
833920
| `DayViewThemeData` | `DayView` |
834921
| `WeekViewThemeData` | `WeekView` |
835922
| `MultiDayViewThemeData` | `MultiDayView` |
923+
| `ScheduleViewThemeData` | `ScheduleView` |
836924

837925
## Default colours
838926

@@ -902,6 +990,25 @@ The package supports dark mode out of the box. Each calendar view has a dedicate
902990
| `headerTextColor` | `onPrimary` |
903991
| `headerBackgroundColor` | `primary` |
904992

993+
### ScheduleViewThemeData
994+
995+
| Property | Default (light) |
996+
|----------|----------------|
997+
| `todayHighlightColor` | `primary` |
998+
| `todayTextColor` | `onPrimary` |
999+
| `dateTextColor` | `onSurface` |
1000+
| `weekdayTextColor` | `outlineVariant` |
1001+
| `dateDividerColor` | `outlineVariant` |
1002+
| `emptyContentColor` | `emptyContent` |
1003+
| `eventTitleColor` | `onSurface` |
1004+
| `eventSecondaryTextColor` | `outline` |
1005+
| `eventTileAlpha` | `28` (light) / `45` (dark) |
1006+
| `eventTimeColorLightnessAdjust` | `-0.1` (light) / `0.0` (dark) |
1007+
| `monthHeaderTextColor` | `monthHeaderText` |
1008+
| `monthHeaderGradientStartColor` | `transparent` |
1009+
| `monthHeaderGradientEndColor` | `monthHeaderGradientEnd` |
1010+
| `monthHeaderTextShadowColor` | `monthHeaderTextShadow` |
1011+
9051012
To customise `MonthView`, `DayView`, `WeekView` & `MultiDayView` page header use `HeaderStyle`.
9061013

9071014
```dart
@@ -929,6 +1036,7 @@ There are two main ways to customize the theme for calendar views:
9291036
dayViewTheme: DayViewThemeData.light(),
9301037
weekViewTheme: WeekViewThemeData.light(),
9311038
multiDayViewTheme: MultiDayViewThemeData.light(),
1039+
scheduleViewTheme: ScheduleViewThemeData.light(),
9321040
),
9331041
child: YourApp(),
9341042
)
@@ -949,6 +1057,7 @@ There are two main ways to customize the theme for calendar views:
9491057
DayViewThemeData.light(),
9501058
WeekViewThemeData.light(),
9511059
MultiDayViewThemeData.light(),
1060+
ScheduleViewThemeData.light(),
9521061
],
9531062
);
9541063
```
@@ -1091,6 +1200,30 @@ Hide divider in multiday view.
10911200
dividerSettings: DividerSettings.none(),
10921201
```
10931202

1203+
### Schedule View
1204+
* All schedule colours resolve from `ScheduleViewThemeData` (`context.scheduleViewColors`), falling back to `.light()` / `.dark()` based on `Theme.of(context).brightness`.
1205+
* Today's date badge uses `todayHighlightColor` (background) and `todayTextColor` (number). Other dates use `dateTextColor`, and weekday abbreviations use `weekdayTextColor`.
1206+
* Event tiles tint the event's own colour by `eventTileAlpha`; the time label is adjusted by `eventTimeColorLightnessAdjust`. Title and secondary text use `eventTitleColor` and `eventSecondaryTextColor`.
1207+
* Empty-state labels (per-day placeholder and the past/future sentinels) use `emptyContentColor`.
1208+
* The month-header image overlay uses `monthHeaderGradientStartColor``monthHeaderGradientEndColor`, with `monthHeaderTextColor` and `monthHeaderTextShadowColor` for the title.
1209+
* In `ScheduleDateLayout.top`, the divider beneath the default date header uses `dateDividerColor`; override it per-widget with `defaultDateHeaderDividerSettings` (use `DividerSettings.none()` to hide it).
1210+
1211+
```dart
1212+
CalendarThemeProvider(
1213+
calendarTheme: CalendarThemeData(
1214+
monthViewTheme: MonthViewThemeData.light(),
1215+
dayViewTheme: DayViewThemeData.light(),
1216+
weekViewTheme: WeekViewThemeData.light(),
1217+
multiDayViewTheme: MultiDayViewThemeData.light(),
1218+
scheduleViewTheme: ScheduleViewThemeData.light().copyWith(
1219+
todayHighlightColor: Colors.blue,
1220+
eventTileAlpha: 40,
1221+
),
1222+
),
1223+
child: YourApp(),
1224+
)
1225+
```
1226+
10941227
# Migration Guides
10951228

10961229
## Migrating from 2.x.x to latest
53 KB
Loading
62.8 KB
Loading
75.9 KB
Loading
53 KB
Loading
49.3 KB
Loading
49.8 KB
Loading
44.6 KB
Loading
60.3 KB
Loading

0 commit comments

Comments
 (0)