planner 0.3.1
planner: ^0.3.1 copied to clipboard
A scrollable, zoomable day-grid widget for showing and editing events across labelled columns, with drag-to-move, drag-to-resize, and context-menu actions.
Changelog #
0.3.1 - 2026-06-08 #
- Fixed the README screenshots not rendering on the pub.flutter-io.cn package page. They
were raw HTML
<img>tags with relativesrcpaths, and pub.flutter-io.cn's README sanitizer strips relativesrcfrom raw HTML images (it only rewrites relative URLs in Markdown links), so every screenshot showed as bracketed alt text. The<img>tags now use absoluteraw.githubusercontent.comURLs. Docs/packaging only — no code or API change.
0.3.0 - 2026-06-08 #
- Overhauled the documentation, examples, and screenshots ahead of this release:
a slim, screenshot-led
README.mdwith the reference split intodoc/pages, the example app restructured into a gallery of progressive examples over richer sample data,CONTRIBUTING.mdcarrying the architecture notes (retiringPROJECT_OVERVIEW.md), and the README/docs screenshots generated reproducibly from the example app via an integration test (#88, #89, #90, #91, #92, #93). - Added fully custom widget builders, so a host can own the visuals while the
package stays the time-grid engine (geometry, scroll, zoom, hit-testing,
overlap, accessibility). All opt-in and non-breaking — defaults are unchanged:
Planner.dayHeaderBuilder— a custom widget per day/column header (#79). The signature carries noDateTime(the core stays date-agnostic, ADR 0001); close over aCalendarWindowto recover the date. Headers track day-axis pan, and a drag across them still pans.Planner.entryBuilder— a custom widget per timed event, layered over the canvas at the event's live on-screen rect so it tracks scroll/zoom/drag (#78).PlannerEntryLayout.sizelets a widget shed detail by pixel height.Planner.allDayEntryBuilder— the same for all-day chips, withPlannerEntryLayout.allDay == true(#80).- The overlays are visual-only (
IgnorePointer/ExcludeSemantics), so every gesture and accessibility action still falls through to the canvas and fires the usualonEntry*callbacks.
- Made
PlannerEntrygeneric:PlannerEntry<T>adds an optional typeddatapayload for your own per-event metadata (#77).Tthreads throughPlanner<T>,PlannerConfig<T>and theonEntry*callbacks, so a builder readsentry.dataalready typed — no cast, no side-map keyed byid. An untypedPlannerEntry(...)infersT == dynamicand is unchanged, so this is backward compatible. - Added a public
PlannerControllerfor driving and observing the planner's zoom from outside the widget — e.g. a host's own zoom toolbar. Construct one, pass it toPlanner(controller: …), and callzoomIn([factor]),zoomOut([factor])orzoomTo(target)(clamped tominZoom/maxZoom); read backzoom,minZoom,maxZoom,dayScroll,timeScrollandisAttached. It is aChangeNotifier, so a toolbar can listen and rebuild (e.g. disable+atmaxZoom). It attaches to the planner's internal zoom/scroll state — the single source of truth, no duplicated state — so the controller, pinch,Ctrl+wheel and the built-in buttons all move the same zoom. Pair it withshowZoomControls: falseto replace the on-canvas buttons. Optional and fully backward compatible: omit it and nothing changes. - Added optional, non-core calendar helpers in
package:planner/calendar.dart(a separate import — not part of the mainplanner.dartbarrel) so building an ordinary date-based week calendar on top of the date-agnostic widget is a few lines, withoutDateTimeentering the widget API (ADR 0001 / #49). ACalendarWindowowns thedate ↔ column-indexmapping for a window of N days: build it directly or week-align it withCalendarWindow.week(anchor: …), map dates to columns (indexOf/dateAt/contains), step weeks (next/previous), derivePlannerConfig.labels(labels(), defaulting to a localizedEEE dviaintl) and thehighlightedColumn"today" index (todayColumn), and convert your own dated events intoPlannerEntry/PlannerTimefor the current window (timeFor/entriesFor, with column-spanning support via anenddate). Addsintlas a dependency (used only by these helpers for the default label format). - Fixed event accessibility semantics not updating when the canvas is scrolled or zoomed. A screen reader now reaches every event — not just those that were on screen the last time the data changed or the canvas was laid out — and each event's semantics node now tracks the scroll/zoom so its hit-area and focus highlight stay aligned as the user pans. Previously off-viewport events were culled and never re-exposed (the canvas has no a11y scroll action to bring them back), and a scrolled event kept a stale node rect.
- Added
PlannerConfig.onEntryLongPress, fired with the long-pressedPlannerEntry. This is the primary way to act on an event by touch (touch has no right-click, and a one-finger drag now pans, so long-press is the freed-up gesture); a desktop long-press fires it too. The widget stays presentation-only — it takes no action of its own (no built-in selection, highlight, or menu), so the host decides the response.null(the default) and a long-press on empty space are both no-ops. - Added column-spanning (multi-day) events. Set
PlannerTime.endDayto a column index afterdayand the event renders across the wholeday..endDayrange;null(the default) or any value<= dayis a single-column event, so existing entries are unaffected. The span stays index-based — noDateTimeenters the model (ADR 0001). Spanning events are read-only in this first cut (they can't be dragged or resized) but stay tappable for edit/delete. A newPlannerConfig.spanOverlapchooses how a span coexists with the per-column overlap split:SpanOverlap.fullWidth(the default) draws it as one box across its columns;SpanOverlap.splitfolds it into each column's sub-column layout. - Added an optional column highlight (a "today"-style emphasis). Set
PlannerConfig.highlightedColumnto a column index (intolabels) and the grid fills that column behind the lines and events;highlightColumnColor(default a subtle translucent white wash) sets the fill. The widget stays date-agnostic — a calendar consumer mapsDateTime.now()to an index itself (ADR 0001).null(the default) or an out-of-range index highlights nothing.
0.2.0 - 2026-06-06 #
- Made the on-canvas zoom +/- buttons configurable: hide them with
PlannerConfig.showZoomControls: false, and recolour them withzoomButtonColor(fill — falls back to the theme's secondary colour when unset) andzoomButtonIconColor(default white). - Made mouse-wheel scrolling zoom-aware: the step now scales with the zoom level
(configurable base via
PlannerConfig.scrollStep, default20), so one wheel notch advances the same amount of time at any zoom instead of moving less the further you zoomed in. - Centered the date and hour labels within their columns (and removed the hardcoded pixel offsets they previously used).
- Added accessibility for the event canvas: each event now exposes a
Semanticsnode describing it (title, day-column label, time span and duration) and its actions to assistive technology — activate or "Edit" to edit, "Delete", and "Move earlier"/"Move later" (which nudge the event by an hour, the accessible equivalent of a drag-move). Actions route through the existingonEntryEdit/onEntryDelete/onEntryMovecallbacks; only the ones the host wires up are offered. The singleCustomPaintcanvas was previously opaque to screen readers. - Unified event-time snapping: creating an event by tapping and dragging/resizing
one now snap to a single configurable interval,
PlannerConfig.snapMinutes(default15), instead of separate ad-hoc, zoom-dependent thresholds. PassPlannerConfig.snapMinutesForZoomto vary the interval with the zoom level, or setsnapMinutes <= 1for minute precision. Create and drag now land on the same grid. - Fixed an off-by-one in the hour column:
maxHournow defaults to23(inclusive last hour), so the default planner no longer paints a spurious 25th row labelled "24", and a tap below the grid clamps to hour 23. - Added an optional
PlannerConfig.hourLabelFormatterto control how each hour renders in the left column (e.g. zero-padding, AM/PM, orintl).
0.0.4 - 2025-03-03 #
- Updated dependencies and raised the minimum Dart SDK to 3.0.
0.0.1 0.0.3 #
Initial public releases of the rewritten widget (the package was rebuilt from scratch in 2022). Highlights:
- Day-grid planner rendered on a single
CustomPaintcanvas. - Horizontal panning across labelled columns; vertical pan, drag, and mouse-wheel scrolling across hours.
- Zoom the time axis via pinch gestures or on-canvas +/- buttons, with finer grid lines fading in at higher zoom levels.
- Drag-to-move and handle-based drag-to-resize for events.
- Right-click / double-tap context menu to create, edit, and delete events via
callbacks (
onEntryCreate,onEntryEdit,onEntryDelete,onEntryMove). - Customizable colors and text styles for the grid, labels, events, and menu.