{"id":17679458,"url":"https://github.com/jonaswanke/timetable","last_synced_at":"2025-04-08T01:37:17.510Z","repository":{"id":38243348,"uuid":"235408956","full_name":"JonasWanke/timetable","owner":"JonasWanke","description":"📅 Customizable flutter calendar widget including day and week views","archived":false,"fork":false,"pushed_at":"2025-02-03T09:08:56.000Z","size":94107,"stargazers_count":308,"open_issues_count":37,"forks_count":81,"subscribers_count":10,"default_branch":"main","last_synced_at":"2025-04-01T00:34:20.039Z","etag":null,"topics":["calendar","calendar-view","dart","flutter","hacktoberfest","material-design","package","week-view"],"latest_commit_sha":null,"homepage":"https://pub.dev/packages/timetable","language":"Dart","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/JonasWanke.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null},"funding":{"github":"JonasWanke"}},"created_at":"2020-01-21T18:09:37.000Z","updated_at":"2025-02-07T15:56:01.000Z","dependencies_parsed_at":"2024-10-24T10:50:17.560Z","dependency_job_id":"2b9b13d0-4bf5-4054-8ce0-803ff5f2426c","html_url":"https://github.com/JonasWanke/timetable","commit_stats":{"total_commits":497,"total_committers":11,"mean_commits":45.18181818181818,"dds":"0.11670020120724345","last_synced_commit":"275aaccc7d96a16917aa69297ef895cb7fa663fb"},"previous_names":[],"tags_count":31,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/JonasWanke%2Ftimetable","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/JonasWanke%2Ftimetable/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/JonasWanke%2Ftimetable/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/JonasWanke%2Ftimetable/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/JonasWanke","download_url":"https://codeload.github.com/JonasWanke/timetable/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247761051,"owners_count":20991531,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["calendar","calendar-view","dart","flutter","hacktoberfest","material-design","package","week-view"],"created_at":"2024-10-24T08:42:07.238Z","updated_at":"2025-04-08T01:37:12.495Z","avatar_url":"https://github.com/JonasWanke.png","language":"Dart","funding_links":["https://github.com/sponsors/JonasWanke"],"categories":[],"sub_categories":[],"readme":"📅 Customizable, animated calendar widget including day, week, and month views.\r\n\r\n|                                       Navigation                                        |                                       Animation                                        |\r\n| :-------------------------------------------------------------------------------------: | :------------------------------------------------------------------------------------: |\r\n| ![](https://github.com/JonasWanke/timetable/raw/main/doc/demo-navigation.webp?raw=true) | ![](https://github.com/JonasWanke/timetable/raw/main/doc/demo-animation.webp?raw=true) |\r\n\r\n|                                       Callbacks                                        |                               Changing the [`VisibleDateRange`]                               |\r\n| :------------------------------------------------------------------------------------: | :-------------------------------------------------------------------------------------------: |\r\n| ![](https://github.com/JonasWanke/timetable/raw/main/doc/demo-callbacks.webp?raw=true) | ![](https://github.com/JonasWanke/timetable/raw/main/doc/demo-visibleDateRange.webp?raw=true) |\r\n\r\n- [Available Layouts](#available-layouts)\r\n  - [`MultiDateTimetable`](#multidatetimetable)\r\n  - [`RecurringMultiDateTimetable`](#recurringmultidatetimetable)\r\n  - [`CompactMonthTimetable`](#compactmonthtimetable)\r\n- [Getting started](#getting-started)\r\n  - [0. General Information](#0-general-information)\r\n  - [1. Define your `Event`s](#1-define-your-events)\r\n  - [2. Create a `DateController` (optional)](#2-create-a-datecontroller-optional)\r\n  - [3. Create a `TimeController` (optional)](#3-create-a-timecontroller-optional)\r\n  - [4. Create your Timetable widget](#4-create-your-timetable-widget)\r\n- [Theming](#theming)\r\n- [Advanced Features](#advanced-features)\r\n  - [Drag and Drop](#drag-and-drop)\r\n  - [Time Overlays](#time-overlays)\r\n\r\n## Available Layouts\r\n\r\n### [`MultiDateTimetable`]\r\n\r\nA Timetable widget that displays multiple consecutive days.\r\n\r\n|                                                 Light Mode                                                  |                                                 Dark Mode                                                  |\r\n| :---------------------------------------------------------------------------------------------------------: | :--------------------------------------------------------------------------------------------------------: |\r\n| ![](https://github.com/JonasWanke/timetable/raw/main/doc/screenshot-MultiDateTimetable-light.webp?raw=true) | ![](https://github.com/JonasWanke/timetable/raw/main/doc/screenshot-MultiDateTimetable-dark.webp?raw=true) |\r\n\r\n### [`RecurringMultiDateTimetable`]\r\n\r\nA Timetable widget that displays multiple consecutive days without their dates and without a week indicator.\r\n\r\n|                                                      Light Mode                                                      |                                                      Dark Mode                                                      |\r\n| :------------------------------------------------------------------------------------------------------------------: | :-----------------------------------------------------------------------------------------------------------------: |\r\n| ![](https://github.com/JonasWanke/timetable/raw/main/doc/screenshot-RecurringMultiDateTimetable-light.webp?raw=true) | ![](https://github.com/JonasWanke/timetable/raw/main/doc/screenshot-RecurringMultiDateTimetable-dark.webp?raw=true) |\r\n\r\n### [`CompactMonthTimetable`]\r\n\r\nA Timetable widget that displays [`MonthWidget`]s in a page view.\r\n\r\n|                                                   Light Mode                                                   |                                                   Dark Mode                                                   |\r\n| :------------------------------------------------------------------------------------------------------------: | :-----------------------------------------------------------------------------------------------------------: |\r\n| ![](https://github.com/JonasWanke/timetable/raw/main/doc/screenshot-CompactMonthTimetable-light.webp?raw=true) | ![](https://github.com/JonasWanke/timetable/raw/main/doc/screenshot-CompactMonthTimetable-dark.webp?raw=true) |\r\n\r\n## Getting started\r\n\r\n### 0. General Information\r\n\r\nTimetable doesn't care about any time-zone related stuff.\r\nAll supplied `DateTime`s must have `isUtc` set to `true`, but the actual time zone is then ignored when displaying events.\r\n\r\nSome date/time-related parameters also have special suffixes:\r\n\r\n- `date`: A `DateTime` with a time of zero.\r\n- `month`: A `DateTime` with a time of zero and a day of one.\r\n- `timeOfDay`: A `Duration` between zero and 24 hours.\r\n- `dayOfWeek`: An `int` between one and seven ([`DateTime.monday`](https://api.flutter.dev/flutter/dart-core/DateTime/monday-constant.html) through [`DateTime.sunday`](https://api.flutter.dev/flutter/dart-core/DateTime/sunday-constant.html)).\r\n\r\nTimetable currently offers localizations for Chinese, English, French, German, Hungarian, Italian, Japanese, Portuguese, and Spanish.\r\nEven if you're just supporting English in your app, you have to add Timetable's localization delegate to your `MaterialApp`/`CupertinoApp`/`WidgetsApp`:\r\n\r\n```dart\r\nMaterialApp(\r\n  localizationsDelegates: [\r\n    TimetableLocalizationsDelegate(),\r\n    // Other delegates, e.g., `GlobalMaterialLocalizations.delegate`\r\n  ],\r\n  // ...\r\n);\r\n```\r\n\r\n\u003e You want to contribute a new localization?\r\n\u003e Awesome!\r\n\u003e Please follow the steps listed in the doc comment of [`TimetableLocalizationsDelegate`].\r\n\r\n### 1. Define your [`Event`]s\r\n\r\nEvents are provided as instances of [`Event`].\r\nTo get you started, there's the subclass [`BasicEvent`], which you can instantiate directly.\r\nIf you want to be more specific, you can also implement your own class extending [`Event`].\r\n\r\n\u003e ⚠️ Most of Timetable's classes accept a type-parameter `E extends Event`.\r\n\u003e Please set it to your chosen [`Event`]-subclass (e.g., [`BasicEvent`]) to avoid runtime exceptions.\r\n\r\nIn addition, you also need a `Widget` to display your events.\r\nWhen using [`BasicEvent`], this can simply be [`BasicEventWidget`].\r\n\r\n### 2. Create a [`DateController`] (optional)\r\n\r\nSimilar to a [`ScrollController`] or a [`TabController`], a [`DateController`] is responsible for interacting with Timetable's widgets and managing their state.\r\nAs the name suggests, you can use a [`DateController`] to access the currently visible dates, and also animate or jump to different days.\r\nAnd by supplying a [`VisibleDateRange`], you can also customize how many days are visible at once and whether they, e.g., snap to weeks.\r\n\r\n```dart\r\nfinal myDateController = DateController(\r\n  // All parameters are optional and displayed with their default value.\r\n  initialDate: DateTimeTimetable.today(),\r\n  visibleRange: VisibleDateRange.week(startOfWeek: DateTime.monday),\r\n);\r\n```\r\n\r\n\u003e Don't forget to [`dispose`][`DateController.dispose`] your controller, e.g., in [`State.dispose`]!\r\n\r\nHere are some of the available [`VisibleDateRange`]s:\r\n\r\n- [`VisibleDateRange.days`]: displays `visibleDayCount` consecutive days, snapping to every `swipeRange` days (aligned to `alignmentDate`) in the range from `minDate` to `maxDate`\r\n- [`VisibleDateRange.week`]: displays and snaps to whole weeks with a customizable `startOfWeek` in the range from `minDate` to `maxDate`\r\n- [`VisibleDateRange.weekAligned`]: displays `visibleDayCount` consecutive days while snapping to whole weeks with a customizable `firstDay` in the range from `minDate` to `maxDate` – can be used, e.g., to display a five-day workweek\r\n\r\n### 3. Create a [`TimeController`] (optional)\r\n\r\nSimilar to the [`DateController`] above, a [`TimeController`] is also responsible for interacting with Timetable's widgets and managing their state.\r\nMore specifically, it controls the visible time range and zoom factor in a [`MultiDateTimetable`] or [`RecurringMultiDateTimetable`].\r\nYou can also programmatically change those and, e.g., animate out to reveal the full day.\r\n\r\n```dart\r\nfinal myTimeController = TimeController(\r\n  // All parameters are optional. By default, the whole day is revealed\r\n  // initially and you can zoom in to view just a single minute.\r\n  minDuration: 15.minutes, // The closest you can zoom in.\r\n  maxDuration: 23.hours, // The farthest you can zoom out.\r\n  initialRange: TimeRange(9.hours, 17.hours),\r\n  maxRange: TimeRange(0.hours, 24.hours),\r\n);\r\n```\r\n\r\n\u003e This example uses some of [\u003ckbd\u003etime\u003c/kbd\u003e]'s extension methods on `int` to create a [`Duration`] more concisely.\r\n\r\n\u003e Don't forget to [`dispose`][`TimeController.dispose`] your controller, e.g., in [`State.dispose`]!\r\n\r\n### 4. Create your Timetable widget\r\n\r\nThe configuration for Timetable's widgets is provided via inherited widgets.\r\nYou can use a [`TimetableConfig\u003cE\u003e`] to provide all at once:\r\n\r\n```dart\r\nTimetableConfig\u003cBasicEvent\u003e(\r\n  // Required:\r\n  dateController: _dateController,\r\n  timeController: _timeController,\r\n  eventBuilder: (context, event) =\u003e BasicEventWidget(event),\r\n  child: MultiDateTimetable\u003cBasicEvent\u003e(),\r\n  // Optional:\r\n  eventProvider: (date) =\u003e someListOfEvents,\r\n  allDayEventBuilder: (context, event, info) =\u003e\r\n      BasicAllDayEventWidget(event, info: info),\r\n  allDayOverflowBuilder: (date, overflowedEvents) =\u003e /* … */,\r\n  callbacks: TimetableCallbacks(\r\n    // onWeekTap, onDateTap, onDateBackgroundTap, onDateTimeBackgroundTap, and\r\n    // onMultiDateHeaderOverflowTap\r\n  ),\r\n  theme: TimetableThemeData(\r\n    context,\r\n    // startOfWeek: DateTime.monday,\r\n    // See the \"Theming\" section below for more options.\r\n  ),\r\n)\r\n```\r\n\r\nAnd you're done 🎉\r\n\r\n## Theming\r\n\r\nTimetable already supports light and dark themes out of the box, adapting to the ambient `ThemeData`.\r\nYou can, however, customize the styles of almost all components by providing a custom [`TimetableThemeData`].\r\n\r\nTo apply your own theme, specify it in the [`TimetableConfig\u003cE\u003e`] (or directly in a [`TimetableTheme`]):\r\n\r\n```dart\r\nTimetableConfig\u003cBasicEvent\u003e(\r\n  theme: TimetableThemeData(\r\n    context,\r\n    startOfWeek: DateTime.monday,\r\n    dateDividersStyle: DateDividersStyle(\r\n      context,\r\n      color: Colors.blue.withOpacity(.3),\r\n      width: 2,\r\n    ),\r\n    dateHeaderStyleProvider: (date) =\u003e\r\n        DateHeaderStyle(context, date, tooltip: 'My custom tooltip'),\r\n    nowIndicatorStyle: NowIndicatorStyle(\r\n      context,\r\n      lineColor: Colors.green,\r\n      shape: TriangleNowIndicatorShape(color: Colors.green),\r\n    ),\r\n    // See the \"Theming\" section below for more.\r\n  ),\r\n  // Other properties...\r\n)\r\n```\r\n\r\n\u003e [`TimetableThemeData`] and all component styles provide two constructors each:\r\n\u003e\r\n\u003e - The default constructor takes a `BuildContext` and sometimes a day or month, using information from the ambient theme and locale to generate default values.\r\n\u003e   You can still override all options via optional, named parameters.\r\n\u003e - The named `raw` constructor is usually `const` and has required parameters for all options.\r\n\r\n## Advanced Features\r\n\r\n### Drag and Drop\r\n\r\n\u003cimg src=\"https://github.com/JonasWanke/timetable/raw/main/doc/demo-dragAndDrop.webp?raw=true\" width=\"400px\" alt=\"Drag and Drop demo\" /\u003e\r\n\r\nYou can easily make events inside the content area of [`MultiDateTimetable`] or [`RecurringMultiDateTimetable`] draggable by wrapping them in a [`PartDayDraggableEvent`]:\r\n\r\n```dart\r\nPartDayDraggableEvent(\r\n  // The user started dragging this event.\r\n  onDragStart: () {},\r\n  // The event was dragged to the given [DateTime].\r\n  onDragUpdate: (dateTime) {},\r\n  // The user finished dragging the event and landed on the given [DateTime].\r\n  onDragEnd: (dateTime) {},\r\n  child: MyEventWidget(),\r\n  // By default, the child is displayed with a reduced opacity when it's\r\n  // dragged. But, of course, you can customize this:\r\n  childWhileDragging: OptionalChildWhileDragging(),\r\n)\r\n```\r\n\r\nTimetable doesn't automatically show a moving feedback widget at the current pointer position.\r\nInstead, you can customize this and, e.g., snap event starts to multiples of 15 minutes.\r\nHave a look at the included example app where we implemented exactly that by displaying the drag feedback as a time overlay.\r\n\r\nIf you have widgets outside of timetable that can be dragged into timetable, you have to give your [`MultiDateContent`] and each [`PartDayDraggableEvent`] a `geometryKey`.\r\nA `geometryKey` is a [`GlobalKey`]`\u003c`[`MultiDateContentGeometry`]`\u003e` with which the current drag offset can be converted to a [`DateTime`].\r\n\r\n```dart\r\nfinal geometryKey = GlobalKey\u003cMultiDateContentGeometry\u003e();\r\n\r\nfinal timetable = MultiDateTimetable(contentGeometryKey: geometryKey);\r\n// Or `MultiDateContent(geometryKey: geometryKey)` if you build your timetable\r\n// from the provided, modular widgets.\r\n\r\nfinal draggableEvent = PartDayDraggableEvent.forGeometryKeys(\r\n  {geometryKey},\r\n  // `child`, `childWhileDragging`, and the callbacks are available here as\r\n  // well.\r\n);\r\n\r\n// Alternatively, you can manually convert an offset to a `DateTime:`\r\nfinal dateTime = geometryKey.currentState!.resolveOffset(globalOffset);\r\n```\r\n\r\nYou could even offer to drag the event into one of multiple timetables:\r\nGive each timetable its own `geometryKey` and pass all of them to [`PartDayDraggableEvent.forGeometryKeys`].\r\nIn the callbacks, you receive the `geometryKey` of the timetable that the event is currently being dragged over.\r\nSee [`PartDayDraggableEvent.geometryKeys`] for the exact behavior.\r\n\r\n### Time Overlays\r\n\r\n\u003cimg src=\"https://github.com/JonasWanke/timetable/raw/main/doc/screenshot-timeOverlays.webp?raw=true\" width=\"400px\" alt=\"Drag and Drop demo\" /\u003e\r\n\r\nIn addition to displaying events, [`MultiDateTimetable`] and [`RecurringMultiDateTimetable`] can display overlays for time ranges on every day.\r\nIn the screenshot above, a light gray overlay is displayed on weekdays before 8 a.m. and after 8 p.m., and over the full day for weekends.\r\nTime overlays are provided similarly to events: Just add a timeOverlayProvider to your [`TimetableConfig\u003cE\u003e`] (or use a [`DefaultTimeOverlayProvider`] directly).\r\n\r\n```dart\r\nTimetableConfig\u003cMyEvent\u003e(\r\n  timeOverlayProvider: (context, date) =\u003e \u003cTimeOverlay\u003e[\r\n    TimeOverlay(\r\n      start: 0.hours,\r\n      end: 8.hours,\r\n      widget: ColoredBox(color: Colors.black12),\r\n      position: TimeOverlayPosition.behindEvents, // the default, alternatively `inFrontOfEvents`\r\n    ),\r\n    TimeOverlay(\r\n      start: 20.hours,\r\n      end: 24.hours,\r\n      widget: ColoredBox(color: Colors.black12),\r\n    ),\r\n  ],\r\n  // Other properties...\r\n)\r\n```\r\n\r\nThe provider is just a function that receives a date and returns a list of [`TimeOverlay`] for that date.\r\nThe example above therefore draws a light gray background before 8 a.m. and after 8 p.m. on every day.\r\n\r\n\u003c!-- Flutter --\u003e\r\n\r\n[`DateTime`]: https://api.flutter.dev/flutter/dart-core/DateTime-class.html\r\n[`Duration`]: https://api.flutter.dev/flutter/dart-core/Duration-class.html\r\n[`GlobalKey`]: https://api.flutter.dev/flutter/widgets/GlobalKey-class.html\r\n[`ScrollController`]: https://api.flutter.dev/flutter/widgets/ScrollController-class.html\r\n[`State.dispose`]: https://api.flutter.dev/flutter/widgets/State/dispose.html\r\n[`TabController`]: https://api.flutter.dev/flutter/material/TabController-class.html\r\n\r\n\u003c!-- timetable --\u003e\r\n\r\n[`BasicEvent`]: https://pub.dev/documentation/timetable/latest/timetable/BasicEvent-class.html\r\n[`BasicEventWidget`]: https://pub.dev/documentation/timetable/latest/timetable/BasicEventWidget-class.html\r\n[`CompactMonthTimetable`]: https://pub.dev/documentation/timetable/latest/timetable/CompactMonthTimetable-class.html\r\n[`DateController`]: https://pub.dev/documentation/timetable/latest/timetable/DateController-class.html\r\n[`DateController.dispose`]: https://pub.dev/documentation/timetable/latest/timetable/DateController/dispose.html\r\n[`DefaultTimeOverlayProvider`]: https://pub.dev/documentation/timetable/latest/timetable/DefaultTimeOverlayProvider-class.html\r\n[`Event`]: https://pub.dev/documentation/timetable/latest/timetable/Event-class.html\r\n[`MonthWidget`]: https://pub.dev/documentation/timetable/latest/timetable/MonthWidget-class.html\r\n[`MultiDateContent`]: https://pub.dev/documentation/timetable/latest/timetable/MultiDateContent-class.html\r\n[`MultiDateContentGeometry`]: https://pub.dev/documentation/timetable/latest/timetable/MultiDateContentGeometry-class.html\r\n[`MultiDateTimetable`]: https://pub.dev/documentation/timetable/latest/timetable/MultiDateTimetable-class.html\r\n[`PartDayDraggableEvent`]: https://pub.dev/documentation/timetable/latest/timetable/PartDayDraggableEvent-class.html\r\n[`PartDayDraggableEvent.forGeometryKeys`]: https://pub.dev/documentation/timetable/latest/timetable/PartDayDraggableEvent/PartDayDraggableEvent.forGeometryKeys.html\r\n[`PartDayDraggableEvent.geometryKeys`]: https://pub.dev/documentation/timetable/latest/timetable/PartDayDraggableEvent/geometryKeys.html\r\n[`RecurringMultiDateTimetable`]: https://pub.dev/documentation/timetable/latest/timetable/RecurringMultiDateTimetable-class.html\r\n[`TimeController`]: https://pub.dev/documentation/timetable/latest/timetable/TimeController-class.html\r\n[`TimeController.dispose`]: https://pub.dev/documentation/timetable/latest/timetable/TimeController/dispose.html\r\n[`TimeOverlay`]: https://pub.dev/documentation/timetable/latest/timetable/TimeOverlay-class.html\r\n[`TimetableConfig\u003cE\u003e`]: https://pub.dev/documentation/timetable/latest/timetable/TimetableConfig-class.html\r\n[`TimetableLocalizationsDelegate`]: https://pub.dev/documentation/timetable/latest/timetable/TimetableLocalizationsDelegate-class.html\r\n[`TimetableTheme`]: https://pub.dev/documentation/timetable/latest/timetable/TimetableTheme-class.html\r\n[`TimetableThemeData`]: https://pub.dev/documentation/timetable/latest/timetable/TimetableThemeData-class.html\r\n[`VisibleDateRange`]: https://pub.dev/documentation/timetable/latest/timetable/VisibleDateRange-class.html\r\n[`VisibleDateRange.days`]: https://pub.dev/documentation/timetable/latest/timetable/VisibleDateRange/days.html\r\n[`VisibleDateRange.week`]: https://pub.dev/documentation/timetable/latest/timetable/VisibleDateRange/week.html\r\n[`VisibleDateRange.weekAligned`]: https://pub.dev/documentation/timetable/latest/timetable/VisibleDateRange/foo.html\r\n\r\n\u003c!-- time --\u003e\r\n\r\n[\u003ckbd\u003etime\u003c/kbd\u003e]: https://pub.dev/packages/time\r\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjonaswanke%2Ftimetable","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjonaswanke%2Ftimetable","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjonaswanke%2Ftimetable/lists"}