feat: added documentation and tests

This commit is contained in:
Freek van de Ven 2022-09-02 16:21:52 +02:00
parent c775e06f77
commit 0073d90212
10 changed files with 165 additions and 50 deletions

2
.gitignore vendored
View file

@ -28,3 +28,5 @@ migrate_working_dir/
.dart_tool/
.packages
build/
coverage/

View file

@ -1,3 +1,3 @@
## 0.0.1
## [0.0.1] - 2 September 2022
* TODO: Describe initial release.
* Initial release.

View file

@ -1,24 +1,20 @@
[![pub package](https://img.shields.io/pub/v/[PACKAGE NAME ON PUB].svg)](https://github.com/Iconica-Development) [![Build status](https://github.com/Iconica-Development/agenda)](URL TO GITHUB ACTIONS) [![style: effective dart](https://img.shields.io/badge/style-effective_dart-40c4ff.svg)](https://github.com/tenhobi/effective_dart)
Short description of what your package is, why you created it. What issues it fixes and how it works. Also mention the available platforms
# Agenda
A Flutter package for creating an agenda that displays events per day with an included calendar for picking the date. Multiple events at the same time are alongside each other. There is also the option to stack multiple items at the same time.
The underlying datepicker widget supports marking dates and disabling dates.
## Setup
What setup steps are neccesarry and why>
<details>
<summary>PLATFORM</summary>
specific platform steps
Supports all Flutter platforms.
</details>
## Usage
## How to use
To use this package, add `agenda` as a [dependency in your pubspec.yaml file](https://flutter.dev/docs/development/platform-integration/platform-channels).
How can we use the package descibe the most common ways with examples in
```dart
codeblocks
```
### Example
See [Example Code](example/lib/main.dart) for more info.
## Issues

View file

@ -57,6 +57,10 @@ class AgendaDemo extends StatelessWidget {
start: DateTime.now().subtract(const Duration(hours: 2)),
end: DateTime.now().add(const Duration(hours: 1)),
),
AgendaEvent(
start: DateTime.now().add(const Duration(days: 2)),
end: DateTime.now().add(const Duration(days: 3)),
),
],
disabledDates: [
// yesterday

View file

@ -66,9 +66,9 @@ packages:
dependency: transitive
description:
path: "."
ref: main
resolved-ref: "7a3c66d28c2d29c1983d186435ed559a19fe34ff"
url: "https://github.com/Iconica-Development/flutter_date_time_picker"
ref: stable
resolved-ref: "6b3f1f5d12c1762bc208a1f1a4b9384dcb3369d4"
url: "git@github.com:Iconica-Development/flutter_date_time_picker.git"
source: git
version: "0.0.1"
flutter_lints:
@ -178,7 +178,7 @@ packages:
path: "."
ref: "v0.0.2"
resolved-ref: "62fdaa443818bd646058b536a12304725d1619fd"
url: "https://github.com/Iconica-Development/timetable"
url: "git@github.com:Iconica-Development/timetable.git"
source: git
version: "0.0.1"
vector_math:

View file

@ -5,6 +5,9 @@ import 'package:flutter_date_time_picker/flutter_date_time_picker.dart';
import 'package:timetable/timetable.dart';
class AgendaWidget extends StatefulWidget {
/// [AgendaWidget] is a widget that displays a timetable with events.
/// It is stateful and sorts the events based on the selected date.
/// All styling can be configured through the [AgendaTheme] class.
const AgendaWidget({
required this.blocks,
this.highlightedDates = const [],
@ -13,6 +16,7 @@ class AgendaWidget extends StatefulWidget {
this.header,
this.scrollController,
this.scrollPhysics,
this.onTapDay,
this.startHour = 0,
this.endHour = 24,
this.hourHeight = 80,
@ -26,15 +30,22 @@ class AgendaWidget extends StatefulWidget {
/// Header widget that is displayed above the datepicker.
final Widget? header;
/// The blocks that are displayed in the agenda
final List<AgendaEvent> blocks;
/// The highlighted dates that are displayed in the agenda
final List<DateTime> highlightedDates;
/// The disabled dates that are displayed in the agenda
final List<DateTime> disabledDates;
/// The date that is initially selected.
final DateTime? initialDate;
/// Function called when the user taps on a day in the datepicker.
final Function(DateTime)? onTapDay;
/// Whether to highlight the current date in the agenda.
final bool highlightToday;
/// Hour at which the timetable starts.
@ -67,7 +78,7 @@ class AgendaWidget extends StatefulWidget {
}
class _AgendaWidgetState extends State<AgendaWidget> {
DateTime? _selectedDate;
late DateTime _selectedDate;
@override
void initState() {
@ -77,9 +88,7 @@ class _AgendaWidgetState extends State<AgendaWidget> {
@override
Widget build(BuildContext context) {
// filter out the blocks that are not on the selected date.
var events =
widget.blocks.where((block) => block.start.day == _selectedDate?.day);
var events = _filterEventsOnDay(widget.blocks, _selectedDate);
return DateTimePicker(
initialDate: _selectedDate,
pickTime: false,
@ -101,28 +110,43 @@ class _AgendaWidgetState extends State<AgendaWidget> {
hourHeight: widget.hourHeight,
startHour: widget.startHour,
endHour: widget.endHour,
timeBlocks: events.isEmpty
? []
: events
.map(
(e) => TimeBlock(
start: TimeOfDay(
hour: e.start.hour,
minute: e.start.minute,
),
end: TimeOfDay(
hour: e.end.hour,
minute: e.end.minute,
),
id: e.id ?? 0,
child: e.content,
),
)
.toList(),
timeBlocks: events,
theme: widget.theme.tableTheme,
combineBlocks: true,
mergeBlocks: true,
),
);
}
List<TimeBlock> _filterEventsOnDay(List<AgendaEvent> events, DateTime day) {
return events
.where(
(e) =>
(e.start.day == day.day &&
e.start.month == day.month &&
e.start.year == day.year) ||
(e.end.day == day.day &&
e.end.month == day.month &&
e.end.year == day.year),
)
.map(
(e) => TimeBlock(
start: (e.start.day != day.day)
? TimeOfDay(hour: widget.startHour, minute: 0)
: TimeOfDay(
hour: e.start.hour,
minute: e.start.minute,
),
end: (e.end.day != day.day)
? TimeOfDay(hour: widget.endHour, minute: 0)
: TimeOfDay(
hour: e.end.hour,
minute: e.end.minute,
),
id: e.id ?? 0,
child: e.content,
),
)
.toList();
}
}

View file

@ -1,20 +1,22 @@
import 'package:flutter/material.dart';
class AgendaEvent {
const AgendaEvent({
/// The model used for a single event in the [AgendaWidget].
/// AgendaEvent can be multiple days long.
AgendaEvent({
required this.start,
required this.end,
this.id,
this.content,
});
}) : assert(start.isBefore(end), 'start must be before end');
/// The start time of the event.
final DateTime start;
/// The end time of the event.
final DateTime end;
///
///
final Widget? content;
/// The identifier of the event that is used to combine events

View file

@ -2,6 +2,10 @@ import 'package:flutter_date_time_picker/flutter_date_time_picker.dart';
import 'package:timetable/timetable.dart';
class AgendaTheme {
/// [AgendaTheme] is a class that contains all styling options
/// for the [AgendaWidget].
/// The underlying [TableTheme] is used for the timetable.
/// The [DateTimePickerTheme] is used for the datepicker.
const AgendaTheme({
this.tableTheme = const TableTheme(),
this.timePickerTheme = const DateTimePickerTheme(),

View file

@ -14,11 +14,11 @@ dependencies:
sdk: flutter
flutter_date_time_picker:
git:
url: https://github.com/Iconica-Development/flutter_date_time_picker
ref: main
url: git@github.com:Iconica-Development/flutter_date_time_picker.git
ref: stable
timetable:
git:
url: https://github.com/Iconica-Development/timetable
url: git@github.com:Iconica-Development/timetable.git
ref: v0.0.2
dev_dependencies:

View file

@ -1,7 +1,90 @@
import 'package:agenda/agenda.dart';
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
void main() {
test('test', () {
expect(true, true);
testWidgets('header is shown', (tester) async {
// Act
await tester.pumpWidget(
const MaterialApp(
home: Scaffold(
body: AgendaWidget(
header: Text('Agenda'),
blocks: [],
),
),
),
);
// Assert
expect(find.text('Agenda'), findsOneWidget);
});
testWidgets('blocks are shown', (tester) async {
// Act
await tester.pumpWidget(
MaterialApp(
home: Scaffold(
body: AgendaWidget(
blocks: [
AgendaEvent(
start: DateTime.now().subtract(const Duration(days: 3)),
end: DateTime.now().subtract(const Duration(days: 2)),
content: const Text('not shown'),
),
AgendaEvent(
start: DateTime.now().add(const Duration(hours: 3)),
end: DateTime.now().add(const Duration(hours: 4)),
id: 4,
content: const Text('event 4'),
),
AgendaEvent(
start: DateTime.now().add(const Duration(hours: 3)),
end: DateTime.now().add(const Duration(hours: 4)),
id: 4,
content: const Text('event 5'),
),
],
),
),
),
);
// Assert
expect(find.text('event 4'), findsOneWidget);
expect(find.text('event 5'), findsOneWidget);
expect(find.text('not shown'), findsNothing);
});
testWidgets('event is removed on tap', (tester) async {
// Act
await tester.pumpWidget(
MaterialApp(
home: Scaffold(
body: AgendaWidget(
initialDate: DateTime.now(),
blocks: [
AgendaEvent(
start: DateTime.now(),
end: DateTime.now().add(const Duration(days: 1)),
content: const Text('single day event'),
),
],
),
),
),
);
var firstDay = find.text('single day event');
expect(firstDay, findsOneWidget);
var nextDay = DateTime.now().add(const Duration(days: 2));
// if nextDay is monday or tuesday we need to go back 4 days
if (nextDay.weekday == DateTime.tuesday ||
nextDay.weekday == DateTime.monday) {
nextDay = nextDay.subtract(const Duration(days: 4));
}
await tester.tap(find.text(nextDay.day.toString()));
await tester.pump();
expect(find.text('single day event'), findsNothing);
});
}