Skip to content

Commit

Permalink
build(widget): Version 0.4.5
Browse files Browse the repository at this point in the history
## [0.4.5] - 2024-08-11
* Two new callback functions
  * onListViewStateChanged
  * onEventsUpdated
  • Loading branch information
agfeo committed Aug 11, 2024
1 parent 5b9db07 commit 1cce02c
Show file tree
Hide file tree
Showing 5 changed files with 194 additions and 69 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
## [0.4.5] - 2024-08-11
* Two new callback functions
* onListViewStateChanged
* onEventsUpdated

## [0.4.4] - 2024-08-08
* Individual color values for date picker style exchange against ThemeData objects

Expand Down
68 changes: 68 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,22 @@ final ValueChanged<NeatCleanCalendarEvent>? onEventLongPressed;

Similar to `onEventSelected`, but for long press events.

#### `onListViewStateChanged`

´´´dart
final ValueChanged? onListViewStateChanged;
```
The parameter `onListViewStateChanged` is a callback function. It gets executed, when the state of list view changes.
#### `onEventsUpdated`
```dart
final ValueChanged<Map<DateTime, List<NeatCleanCalendarEvent>>>?
```

This callback function gets executed, when the `eventsMap` gets updated. This happens in the `initState` method. This callback function can be used to pass the content of the `eventsMap` to the parent widget. There are some cases, where this is useful.

### Options

### `isExpandable`
Expand Down Expand Up @@ -257,6 +273,58 @@ final ThemeData? datePickerDarkTheme;
```
Sets the `ColorScheme` and `TextButtonThemeData` for styling the date picker in dark mode

##### Using themes for the date picker

In order to apply a light theme and a dark theme to the date picker, your app must support a light theme and a dark theme. This means, your app needs to implement the following code block setting the properties of `MaterialApp`:

```dart
return MaterialApp(
title: 'Flutter Clean Calendar Demo',
theme: ThemeData.light(),
darkTheme: ThemeData.dark(),
themeMode: ThemeMode.system,
home: CalendarScreen(),
...
```

Then you can set the date picker themes when you initialize the Calendar widget like this:

```dart
...
child: Calendar(
startOnMonday: true,
weekDays: ['Mo', 'Di', 'Mi', 'Do', 'Fr', 'Sa', 'So'],
eventsList: _eventList,
...
datePickerDarkTheme: ThemeData.dark().copyWith(
colorScheme: ColorScheme.dark(
primary: Colors.blue,
onPrimary: Colors.yellow,
surface: Colors.grey,
onSurface: Colors.yellow,
),
textButtonTheme: TextButtonThemeData(
style: TextButton.styleFrom(
foregroundColor: Colors.orange,
),
),
),
datePickerLightTheme: ThemeData.dark().copyWith(
colorScheme: ColorScheme.dark(
primary: Colors.blue,
onPrimary: Colors.white,
surface: Colors.white,
onSurface: Colors.teal,
),
textButtonTheme: TextButtonThemeData(
style: TextButton.styleFrom(
foregroundColor: Colors.orange,
),
),
),
...
```

#### `todayButtonText`

```dart
Expand Down
186 changes: 118 additions & 68 deletions lib/flutter_neat_and_clean_calendar.dart
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,10 @@ class Range {
/// executed when an event of the event list is selected
/// [onEventLongPressed] is of type [ValueChanged<NeatCleanCalendarEvent>] and it contains a callback function
/// executed when an event of the event list is long pressed
/// [onListViewStateChanged] is of type [ValueChanged] and it contains a callback function
/// executed when the list view state changes
/// [onEventsUpdated] is of type [ValueChanged<Map<DateTime, List<NeatCleanCalendarEvent>>] and it contains a callback function
/// executed when the events are updated
/// [datePickerType] defines, if the date picker should get displayed and selects its type
/// Choose between datePickerType.hidden, datePickerType.year, datePickerType.date
/// [isExpandable] is a [bool]. With this parameter you can control, if the view can expand from week view
Expand Down Expand Up @@ -103,6 +107,9 @@ class Calendar extends StatefulWidget {
final ValueChanged? onRangeSelected;
final ValueChanged<NeatCleanCalendarEvent>? onEventSelected;
final ValueChanged<NeatCleanCalendarEvent>? onEventLongPressed;
final ValueChanged? onListViewStateChanged;
final ValueChanged<Map<DateTime, List<NeatCleanCalendarEvent>>>?
onEventsUpdated;
final bool isExpandable;
final DayBuilder? dayBuilder;
final EventListBuilder? eventListBuilder;
Expand Down Expand Up @@ -149,6 +156,8 @@ class Calendar extends StatefulWidget {
this.onExpandStateChanged,
this.onEventSelected,
this.onEventLongPressed,
this.onListViewStateChanged,
this.onEventsUpdated,
this.isExpandable = false,
this.eventsList,
this.dayBuilder,
Expand Down Expand Up @@ -210,6 +219,12 @@ class _CalendarState extends State<Calendar> {

isExpanded = widget.isExpanded;
showEventListView = widget.showEventListView;
// When setting the initial date, the eventsmap must be updated. The eventsmap is used to
// store the events for each day. The eventsmap is used to display the events in the calendar.
// It is basically the internal store of the events. Because the events are passed as a list
// to the calendar, the eventsmap must be created from the list. This is done in the
// _updateEventsMap method.
_updateEventsMap();

_selectedDate = widget.initialDate ?? DateTime.now();
initializeDateFormatting(widget.locale, null).then((_) => setState(() {
Expand All @@ -221,8 +236,9 @@ class _CalendarState extends State<Calendar> {
}

/// The method [_updateEventsMap] has the purpose to update the eventsMap, when the calendar widget
/// renders its view. When this method executes, it fills the eventsMap with the contents of the
/// is initiated. When this method executes, it fills the eventsMap with the contents of the
/// given eventsList. This can be used to update the events shown by the calendar.
/// This is done in the initState method.
void _updateEventsMap() {
eventsMap = {};
// If the user provided a list of events, then convert it to a map, but only if there
Expand Down Expand Up @@ -313,6 +329,13 @@ class _CalendarState extends State<Calendar> {
[];

print('eventsMap has ${eventsMap?.length} entries');

// If the eventsMap is updated, the eventsUpdated callback is invoked. In some cases it is useful
// to have a copy of the eventsMap in the parent widget. This can be done by providing a callback
// method to the calendar widget.
if (widget.onEventsUpdated != null) {
widget.onEventsUpdated!(eventsMap!);
}
}

Widget get nameAndIconRow {
Expand Down Expand Up @@ -450,6 +473,11 @@ class _CalendarState extends State<Calendar> {
onPressed: () {
setState(() {
showEventListView = !showEventListView;
if (widget.onListViewStateChanged != null) {
// If the onListViewStateChanged callback is provided, invoke it.
// This can be used to trigger actions in the parent widget.
widget.onListViewStateChanged!(showEventListView);
}
});
},
icon: Icon(
Expand Down Expand Up @@ -663,42 +691,6 @@ class _CalendarState extends State<Calendar> {
}
}

/// Returns a widget representing the event list.
///
/// This widget is used to display a list of events.
/// It can be used to show events for a specific date or a range of dates.
/// The events can be customized and styled according to the application's needs.
/// To use this widget, simply call the `eventList` getter and include it in your widget tree.
Widget get eventList {
// If eventListBuilder is provided, use it to build the list of events to show.
// Otherwise use the default list of events.
if (widget.eventListBuilder == null) {
return Expanded(
child: _selectedEvents != null && _selectedEvents!.isNotEmpty
// Create a list of events that are occurring on the currently selected day, if there are
// any. Otherwise, display an empty Container.
? ListView.builder(
padding: EdgeInsets.all(0.0),
itemBuilder: (BuildContext context, int index) {
final NeatCleanCalendarEvent event = _selectedEvents![index];
final String start =
DateFormat('HH:mm').format(event.startTime).toString();
final String end =
DateFormat('HH:mm').format(event.endTime).toString();
return widget.eventCellBuilder == null
? eventCell(event, start, end)
: widget.eventCellBuilder!(context, event, start, end);
},
itemCount: _selectedEvents!.length,
)
: Container(),
);
} else {
// eventListBuilder is not null
return widget.eventListBuilder!(context, _selectedEvents!);
}
}

Column singleDayTimeWidget(String start, String end) {
print('SingleDayEvent');
return Column(
Expand Down Expand Up @@ -756,8 +748,6 @@ class _CalendarState extends State<Calendar> {

@override
Widget build(BuildContext context) {
_updateEventsMap();

isDarkMode = Theme.of(context).brightness == Brightness.dark;

// If _selectedEvents is not null, then we sort the events by isAllDay propeerty, so that
Expand Down Expand Up @@ -789,43 +779,103 @@ class _CalendarState extends State<Calendar> {
isExpanded: isExpanded,
),
expansionButtonRow,
if (widget.showEvents) eventList
if (widget.showEvents) eventlistView
],
],
),
);
}

/// A getter that returns a list of widgets representing the events in the event card.
///
/// The `eventlistView` method creates a list of widgets that represent the events in the event card.
/// Each date in the `eventsMap` is represented by a container widget that displays the date.
/// Under each date, the associated events are listed, with each event represented by an `eventCell` widget.
///
/// The method iterates through the `eventsMap` to create the widgets for the events.
/// For each date, a container widget is created to display the date.
/// For each event, an `eventCell` widget is created that displays the event's start and end times.
///
/// - Return value: A list of widgets representing the events in the event card.
Widget get eventlistView {
List<Widget> eventWidgets = [];

eventsMap!.forEach((date, events) {
eventWidgets.add(
Container(
color: widget.bottomBarColor ?? Color.fromRGBO(200, 200, 200, 0.2),
height: 40,
margin: EdgeInsets.only(top: 8.0),
padding: const EdgeInsets.all(8.0),
child: Text(
DateFormat.yMMMMEEEEd(widget.locale).format(date),
style: widget.bottomBarTextStyle ?? TextStyle(fontSize: 13),
),
),
);
events.forEach((event) {
final String start =
DateFormat('HH:mm').format(event.startTime).toString();
final String end = DateFormat('HH:mm').format(event.endTime).toString();
eventWidgets.add(eventCell(event, start, end));
});
});
// If the list view is active, show the full list of events. Otherwise only the
// events for the selected day are shown.
List<NeatCleanCalendarEvent>? _listEvents =
showEventListView ? widget.eventsList : _selectedEvents;

return Expanded(
child: ListView(
children: eventWidgets,
shrinkWrap: true,
),
);
// If eventListBuilder is provided, use it to build the list of events to show.
// Otherwise use the default list of events.
if (widget.eventListBuilder == null) {
if (showEventListView == true) {
// If the list view is active a different kind of list is shown.
final List<dynamic> itemList = [];

eventsMap!.forEach((date, events) {
itemList.add(date); // Füge das Datum hinzu
itemList.addAll(events); // Füge die Events des Datums hinzu
});

return Expanded(
child: ListView.builder(
itemCount: itemList.length,
itemBuilder: (BuildContext context, int index) {
final item = itemList[index];

if (item is DateTime) {
// Date header for the list of events
return Container(
color: Color.fromRGBO(200, 200, 200, 0.2),
height: 40,
margin: EdgeInsets.only(top: 8.0),
padding: const EdgeInsets.all(8.0),
child: Text(
DateFormat.yMMMMEEEEd('de').format(item),
style: TextStyle(fontSize: 13),
),
);
} else if (item is NeatCleanCalendarEvent) {
// Event cell for the list of events
final NeatCleanCalendarEvent event = item;
final String start =
DateFormat('HH:mm').format(event.startTime).toString();
final String end =
DateFormat('HH:mm').format(event.endTime).toString();
if (widget.eventCellBuilder == null) {
return eventCell(event, start, end);
} else {
return widget.eventCellBuilder!(context, event, start, end);
}
}
return Container();
}),
);
} else {
// List view is not active
return Expanded(
child: _listEvents != null && _listEvents.isNotEmpty
// Create a list of events that are occurring on the currently selected day, if there are
// any. Otherwise, display an empty Container.
? ListView.builder(
padding: EdgeInsets.all(0.0),
itemBuilder: (BuildContext context, int index) {
final NeatCleanCalendarEvent event = _listEvents[index];
final String start =
DateFormat('HH:mm').format(event.startTime).toString();
final String end =
DateFormat('HH:mm').format(event.endTime).toString();
return widget.eventCellBuilder == null
? eventCell(event, start, end)
: widget.eventCellBuilder!(context, event, start, end);
},
itemCount: _listEvents.length,
)
: Container(),
);
}
} else {
// eventListBuilder is not null
return widget.eventListBuilder!(context, _selectedEvents!);
}
}

/// A widget that represents a cell for displaying an event in the calendar.
Expand Down
2 changes: 2 additions & 0 deletions lib/neat_and_clean_calendar_event.dart
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ class NeatCleanCalendarEvent {
Map<String, dynamic>? metadata;
String? icon;
bool? wide = false;
String? id;

NeatCleanCalendarEvent(
this.summary, {
Expand All @@ -35,5 +36,6 @@ class NeatCleanCalendarEvent {
this.metadata,
this.icon,
this.wide,
this.id,
});
}
2 changes: 1 addition & 1 deletion pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ description: >-
Simple and clean flutter calendar with ability to slide up/down to show
weekly/monthly calendar. Fork of
https://pub.dev/packages/flutter_clean_calendar
version: 0.4.4
version: 0.4.5
homepage: https://github.com/rwbr/flutter_neat_and_clean_calendar

environment:
Expand Down

0 comments on commit 1cce02c

Please sign in to comment.