feat: add horizontal version of agenda

This commit is contained in:
Freek van de Ven 2022-12-27 10:19:05 +01:00
parent a0fdeb753f
commit 1bd7294ef4
10 changed files with 137 additions and 47 deletions

View file

@ -1,3 +1,9 @@
## [1.0.0] - 27 December 2022
* Added option for custom Widget when there are no events for a given day
* Support for both horizontal and vertical variant
* Adjustable size for the component
## [0.0.1] - 2 September 2022 ## [0.0.1] - 2 September 2022
* Initial release. * Initial release.

View file

@ -2,8 +2,8 @@
// //
// SPDX-License-Identifier: BSD-3-Clause // SPDX-License-Identifier: BSD-3-Clause
import 'package:agenda/agenda.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_agenda/flutter_agenda.dart';
void main() { void main() {
runApp( runApp(
@ -25,7 +25,7 @@ class AgendaDemo extends StatelessWidget {
'Agenda', 'Agenda',
style: Theme.of(context).textTheme.headline6, style: Theme.of(context).textTheme.headline6,
), ),
blockWidth: 50, blockDimension: 50,
highlightToday: false, highlightToday: false,
blocks: [ blocks: [
AgendaEvent( AgendaEvent(

View file

@ -1,13 +1,6 @@
# Generated by pub # Generated by pub
# See https://dart.dev/tools/pub/glossary#lockfile # See https://dart.dev/tools/pub/glossary#lockfile
packages: packages:
agenda:
dependency: "direct main"
description:
path: ".."
relative: true
source: path
version: "0.0.1"
async: async:
dependency: transitive dependency: transitive
description: description:
@ -62,6 +55,13 @@ packages:
description: flutter description: flutter
source: sdk source: sdk
version: "0.0.0" version: "0.0.0"
flutter_agenda:
dependency: "direct main"
description:
path: ".."
relative: true
source: path
version: "1.0.0"
flutter_date_time_picker: flutter_date_time_picker:
dependency: transitive dependency: transitive
description: description:

View file

@ -13,7 +13,7 @@ dependencies:
sdk: flutter sdk: flutter
cupertino_icons: ^1.0.2 cupertino_icons: ^1.0.2
agenda: flutter_agenda:
path: ../ path: ../
dev_dependencies: dev_dependencies:

View file

@ -1,11 +0,0 @@
// SPDX-FileCopyrightText: 2022 Iconica
//
// SPDX-License-Identifier: BSD-3-Clause
library agenda;
export 'package:agenda/src/agenda.dart';
export 'package:agenda/src/models/agenda_event.dart';
export 'package:agenda/src/models/agenda_theme.dart';
export 'package:timetable/timetable.dart';

11
lib/flutter_agenda.dart Normal file
View file

@ -0,0 +1,11 @@
// SPDX-FileCopyrightText: 2022 Iconica
//
// SPDX-License-Identifier: BSD-3-Clause
library agenda;
export 'package:flutter_agenda/src/agenda.dart';
export 'package:flutter_agenda/src/models/agenda_event.dart';
export 'package:flutter_agenda/src/models/agenda_theme.dart';
export 'package:timetable/timetable.dart';

View file

@ -2,9 +2,9 @@
// //
// SPDX-License-Identifier: BSD-3-Clause // SPDX-License-Identifier: BSD-3-Clause
import 'package:agenda/src/models/agenda_event.dart';
import 'package:agenda/src/models/agenda_theme.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_agenda/src/models/agenda_event.dart';
import 'package:flutter_agenda/src/models/agenda_theme.dart';
import 'package:flutter_date_time_picker/flutter_date_time_picker.dart'; import 'package:flutter_date_time_picker/flutter_date_time_picker.dart';
import 'package:timetable/timetable.dart'; import 'package:timetable/timetable.dart';
@ -14,26 +14,43 @@ class AgendaWidget extends StatefulWidget {
/// All styling can be configured through the [AgendaTheme] class. /// All styling can be configured through the [AgendaTheme] class.
const AgendaWidget({ const AgendaWidget({
required this.blocks, required this.blocks,
this.tableDirection = Axis.vertical,
this.size,
this.highlightedDates = const [], this.highlightedDates = const [],
this.disabledDates = const [], this.disabledDates = const [],
this.initialDate, this.initialDate,
this.alwaysUse24HourFormat,
this.header, this.header,
this.childIfEmptyRoster,
this.scrollController, this.scrollController,
this.scrollPhysics, this.scrollPhysics,
this.onTapDay, this.onTapDay,
this.tableTopPadding = 0,
this.datePickerExpansion = 0,
this.startHour = 0, this.startHour = 0,
this.endHour = 24, this.endHour = 24,
this.hourHeight = 80, this.hourDimension = 80,
this.highlightToday = true, this.highlightToday = true,
this.blockWidth = 50, this.updateEmptyChildPosition = true,
this.blockDimension = 50,
this.blockColor = const Color(0x80FF0000), this.blockColor = const Color(0x80FF0000),
this.theme = const AgendaTheme(), this.theme = const AgendaTheme(),
super.key, super.key,
}); });
/// The [Axis] along which the timetable markings are lined out
final Axis tableDirection;
/// Header widget that is displayed above the datepicker. /// Header widget that is displayed above the datepicker.
final Widget? header; final Widget? header;
/// The Widget displayed instead of the timetable when no events are available
final Widget? childIfEmptyRoster;
/// Whether to change the position of the Empty Child Widget
/// when the datepicker is opened
final bool updateEmptyChildPosition;
/// The blocks that are displayed in the agenda /// The blocks that are displayed in the agenda
final List<AgendaEvent> blocks; final List<AgendaEvent> blocks;
@ -58,11 +75,21 @@ class AgendaWidget extends StatefulWidget {
/// Hour at which the timetable ends. /// Hour at which the timetable ends.
final int endHour; final int endHour;
/// The heigh of one hour in the timetable. /// The amount of pixels above the timetable
final double hourHeight; final double tableTopPadding;
/// The width of the agendaItem if there is no child /// The extra height of the datePicker when it is expanded
final double blockWidth; final double datePickerExpansion;
/// [bool] to set the clock on [TimePickerDialog] to a fixed 24 format.
/// By default this gets determined by the settings on the user device.
final bool? alwaysUse24HourFormat;
/// The dimension in pixels of one hour in the timetable.
final double hourDimension;
/// The dimension in pixels of the rosterItem if there is no child
final double blockDimension;
/// The color of the agendaItem if there is no child /// The color of the agendaItem if there is no child
final Color blockColor; final Color blockColor;
@ -71,6 +98,9 @@ class AgendaWidget extends StatefulWidget {
/// The [TableTheme] used by the timetable is included. /// The [TableTheme] used by the timetable is included.
final AgendaTheme theme; final AgendaTheme theme;
/// The [Size] of the timetable.
final Size? size;
/// The scroll controller to control the scrolling of the timetable. /// The scroll controller to control the scrolling of the timetable.
final ScrollController? scrollController; final ScrollController? scrollController;
@ -83,6 +113,7 @@ class AgendaWidget extends StatefulWidget {
class _AgendaWidgetState extends State<AgendaWidget> { class _AgendaWidgetState extends State<AgendaWidget> {
late DateTime _selectedDate; late DateTime _selectedDate;
double _scrollOffset = 0.0;
@override @override
void initState() { void initState() {
@ -94,28 +125,71 @@ class _AgendaWidgetState extends State<AgendaWidget> {
Widget build(BuildContext context) { Widget build(BuildContext context) {
var events = _filterEventsOnDay(widget.blocks, _selectedDate); var events = _filterEventsOnDay(widget.blocks, _selectedDate);
return DragDownDateTimePicker( return DragDownDateTimePicker(
alwaysUse24HourFormat: widget.alwaysUse24HourFormat,
initialDate: _selectedDate, initialDate: _selectedDate,
pickTime: false, pickTime: false,
highlightToday: widget.highlightToday, highlightToday: widget.highlightToday,
header: widget.header, header: widget.header,
onTapDay: (p0) { onTapDay: (selected) {
widget.onTapDay?.call(selected);
setState(() { setState(() {
_selectedDate = p0; _selectedDate = selected;
}); });
}, },
onTimerPickerSheetChange: (p0) {
if (widget.updateEmptyChildPosition) {
setState(() {
_scrollOffset = p0 - widget.tableTopPadding;
});
}
},
disabledDates: widget.disabledDates, disabledDates: widget.disabledDates,
markedDates: widget.highlightedDates, markedDates: widget.highlightedDates,
dateTimePickerTheme: widget.theme.timePickerTheme, dateTimePickerTheme: widget.theme.timePickerTheme,
child: Timetable( child: Column(
scrollPhysics: widget.scrollPhysics, children: [
scrollController: widget.scrollController, SizedBox(
blockColor: widget.blockColor, height: widget.tableTopPadding,
startHour: widget.startHour, ),
endHour: widget.endHour, SizedBox(
timeBlocks: events, height: (widget.size != null)
theme: widget.theme.tableTheme, ? widget.size!.height - widget.tableTopPadding
combineBlocks: true, : null,
mergeBlocks: true, width: (widget.size != null) ? widget.size!.width : null,
child: (widget.childIfEmptyRoster != null && events.isEmpty)
? Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
// add empty space between the top of the widget
//and the child if the datepicker is expanded
SizedBox(
height: _scrollOffset,
),
widget.childIfEmptyRoster!,
],
)
: Timetable(
tableDirection: widget.tableDirection,
scrollPhysics: widget.scrollPhysics,
scrollController: widget.scrollController,
blockColor: widget.blockColor,
blockDimension: widget.blockDimension,
hourDimension: widget.hourDimension,
startHour: widget.startHour,
endHour: widget.endHour,
timeBlocks: events,
theme: widget.theme.tableTheme,
combineBlocks: true,
mergeBlocks: true,
size: (widget.size != null)
? Size(
widget.size!.width,
widget.size!.height - widget.tableTopPadding,
)
: null,
),
),
],
), ),
); );
} }
@ -146,6 +220,7 @@ class _AgendaWidgetState extends State<AgendaWidget> {
minute: e.end.minute, minute: e.end.minute,
), ),
id: e.id ?? 0, id: e.id ?? 0,
childDimension: e.childDimension,
child: e.content, child: e.content,
), ),
) )

View file

@ -12,6 +12,7 @@ class AgendaEvent {
required this.end, required this.end,
this.id, this.id,
this.content, this.content,
this.childDimension,
}) : assert(start.isBefore(end), 'start must be before end'); }) : assert(start.isBefore(end), 'start must be before end');
/// The start time of the event. /// The start time of the event.
@ -20,9 +21,14 @@ class AgendaEvent {
/// The end time of the event. /// The end time of the event.
final DateTime end; final DateTime end;
/// /// The [Widget] displayed inside the roster at the event time
final Widget? content; final Widget? content;
/// The dimension of the child in the axis of the timetable which it expands.
/// Only needed when child is not null and the horizontalvariant is used.
/// This is used to make the timetable background as large as all the blocks.
final double? childDimension;
/// The identifier of the event that is used to combine events /// The identifier of the event that is used to combine events
/// with the same id. Leave empty or 0 if you don't want to combine events. /// with the same id. Leave empty or 0 if you don't want to combine events.
final int? id; final int? id;

View file

@ -1,7 +1,7 @@
name: agenda name: flutter_agenda
description: Agenda widget with timetable description: Agenda widget with an underlying timetable included
version: 0.0.1 version: 1.0.0
homepage: https://github.com/Iconica-Development/agenda homepage: https://github.com/Iconica-Development/flutter_agenda
publish_to: none publish_to: none

View file

@ -2,8 +2,8 @@
// //
// SPDX-License-Identifier: BSD-3-Clause // SPDX-License-Identifier: BSD-3-Clause
import 'package:agenda/agenda.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_agenda/flutter_agenda.dart';
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
void main() { void main() {
@ -13,6 +13,7 @@ void main() {
const MaterialApp( const MaterialApp(
home: Scaffold( home: Scaffold(
body: AgendaWidget( body: AgendaWidget(
size: const Size(500, 500),
header: Text('Agenda'), header: Text('Agenda'),
blocks: [], blocks: [],
), ),
@ -30,6 +31,7 @@ void main() {
MaterialApp( MaterialApp(
home: Scaffold( home: Scaffold(
body: AgendaWidget( body: AgendaWidget(
size: const Size(500, 500),
blocks: [ blocks: [
AgendaEvent( AgendaEvent(
start: DateTime.now().subtract(const Duration(days: 3)), start: DateTime.now().subtract(const Duration(days: 3)),
@ -66,6 +68,7 @@ void main() {
MaterialApp( MaterialApp(
home: Scaffold( home: Scaffold(
body: AgendaWidget( body: AgendaWidget(
size: const Size(500, 500),
initialDate: DateTime.now(), initialDate: DateTime.now(),
blocks: [ blocks: [
AgendaEvent( AgendaEvent(