Task lists used to be a week-view-only sub-feature bolted onto calendar widgets (CalendarWidgetConfig.tasks_*), so a task list could only exist tied to a calendar's view and only inside its footprint. Tasks are now a standalone widget type (TaskWidgetConfig, app/widgets/tasks.py) that can be placed and sized independently, same as photos/calendar/ whiteboard -- no separate "enabled" flag either, since being on the grid at all is the on/off switch, matching every other widget type. Migration 17 creates task_widget_configs, extracts any existing calendar widget's configured task source into a new sibling tasks widget (auto-placed in open grid space, source dropped+logged if truly none is left), then drops calendar_widget_configs' now-dead tasks_* columns in the same migration -- this project's usual same-migration- drop convention. Also handles the rarer case of a database jumping straight from before the widget system existed to after this split in one boot, via the legacy Frame.calendar_tasks_* columns. Verified live in the browser at desktop and mobile widths: adding a Tasks widget, its own dialog (task-list source picker + preview), and confirming the calendar widget's dialog no longer mentions tasks at all. Full test suite (180 tests, including new coverage for the widget render/actions, the migration's data-extraction path, and the permission-boundary shape for tasks-source) passes.
47 lines
2.0 KiB
Python
47 lines
2.0 KiB
Python
"""Registry mapping a Widget's widget_type to its render/action module --
|
|
the widget-system's analogue of routers/device.py's old RENDERERS/
|
|
ADVANCE_RENDERERS/BACK_RENDERERS dicts, generalized from "one mode owns
|
|
the whole panel" to "each widget renders into its own region and
|
|
optionally responds to named button actions."
|
|
|
|
Each module in this package exposes:
|
|
|
|
render(db, frame, widget, target_w, target_h, is_normal_wake=True) -> Image.Image
|
|
An RGB image exactly target_w x target_h, unquantized -- the
|
|
widget's content composed into its own region. Never returns
|
|
packed panel bytes or raises for a foreseeable failure (a
|
|
widget's own fetch hiccup shows a small placeholder instead) --
|
|
image_pipeline.render_panel composites every widget's own
|
|
render() result onto one shared canvas and quantizes/packs the
|
|
whole thing once (see its own docstring). is_normal_wake
|
|
distinguishes an ordinary /frame/image GET from a button-
|
|
triggered re-render -- only app/widgets/calendar.py's render()
|
|
actually uses it (resetting browse_offset back to "today" on a
|
|
normal wake), but every module accepts it for one uniform call
|
|
signature regardless.
|
|
|
|
ACTIONS: dict[str, Callable[[Session, Frame, Widget], None]]
|
|
Named button actions this widget type supports (e.g. "advance",
|
|
"back", "check_now") -- see models.FrameButtonAction. Each
|
|
function mutates the widget's own state via db.widget_locked
|
|
internally; none return a value or re-render themselves --
|
|
whatever dispatches a button press (routers/device.py, once the
|
|
widget-system cutover lands) re-renders the whole panel once
|
|
after running every assigned action.
|
|
|
|
ACTION_LABELS: dict[str, str]
|
|
Human-readable labels for ACTIONS' keys, for the button-
|
|
assignment UI.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from . import calendar, photos, tasks, whiteboard
|
|
|
|
WIDGET_TYPES = {
|
|
"photos": photos,
|
|
"calendar": calendar,
|
|
"whiteboard": whiteboard,
|
|
"tasks": tasks,
|
|
}
|