mirror of
https://github.com/Iconica-Development/flutter_agenda.git
synced 2025-05-18 21:03:45 +02:00
feat: added documentation and tests
This commit is contained in:
parent
c775e06f77
commit
0073d90212
10 changed files with 165 additions and 50 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -28,3 +28,5 @@ migrate_working_dir/
|
|||
.dart_tool/
|
||||
.packages
|
||||
build/
|
||||
|
||||
coverage/
|
|
@ -1,3 +1,3 @@
|
|||
## 0.0.1
|
||||
## [0.0.1] - 2 September 2022
|
||||
|
||||
* TODO: Describe initial release.
|
||||
* Initial release.
|
||||
|
|
22
README.md
22
README.md
|
@ -1,24 +1,20 @@
|
|||
[](https://github.com/Iconica-Development) [](URL TO GITHUB ACTIONS) [](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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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(),
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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);
|
||||
});
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue