mirror of
https://github.com/Iconica-Development/flutter_agenda.git
synced 2025-05-18 21:03:45 +02:00
feat: add horizontal version of agenda
This commit is contained in:
parent
a0fdeb753f
commit
1bd7294ef4
10 changed files with 137 additions and 47 deletions
|
@ -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.
|
||||||
|
|
|
@ -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(
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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
11
lib/flutter_agenda.dart
Normal 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';
|
|
@ -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,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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(
|
||||||
|
|
Loading…
Reference in a new issue