Files
espresso_frame/server/app/widgets/calendar.py
T
tfaour 99069ba5fe
Build and push server image / test (push) Successful in 19s
Build and push server image / build-and-push (push) Successful in 1m58s
Widget system Phase 3: calendar widgets become size-aware
calendar_render.py's _build_* functions now take a real target box
and pick font sizes/margins from three discrete size tiers (nearest
pixel-area fit) instead of always laying out at full panel size and
resizing after the fact -- a calendar widget placed smaller than the
full panel gets an actually-legible layout instead of shrunk text.
Month view falls back to agenda below the smallest tier, where 7
columns can no longer stay readable.

The old photo-inlay split (inlay_region/_content_region/_paste_inlay)
is deleted along with it -- arbitrary widget placement already
subsumes what a fixed half-panel split did, and every call site has
passed photo_inlay=None since the Phase 2 cutover.

Also adds HTTP-level test coverage for GET .../preview/calendar,
which had none before this -- it's what caught a stale photo_inlay
kwarg left over from the _build signature change that would have
TypeError'd on every request.
2026-07-24 09:38:10 -04:00

75 lines
3.1 KiB
Python

"""Calendar widget: merged-event agenda/week/month view into the
widget's own region -- the widget-system analogue of routers/device.py's
old _render_calendar_mode/_advance_calendar_mode/_back_calendar_mode.
render() builds directly at whatever target box it's asked for --
calendar_render.py's layout math picks from discrete size tiers (see
its own _size_tier) rather than always laying out at full panel size and
resizing after the fact, so a small placed calendar widget gets an
actually-legible small-size layout instead of a shrunk-down full-size
one.
"Photo inlay" (calendar mode's old half-and-half photo split) has no
widget-system equivalent -- place an independent photo widget alongside
instead; arbitrary placement is strictly more flexible than one fixed
split ever was."""
from __future__ import annotations
from PIL import Image
from sqlalchemy.orm import Session
from ..calendar_render import _build
from ..db import widget_locked
from ..models import CalendarWidgetConfig, Frame, Widget
from ..routers.common import (
get_or_refresh_calendar_events_for_widget,
get_or_refresh_tasks_for_widget,
get_or_refresh_weather_for_widget,
)
ACTION_LABELS = {"advance": "Next period", "back": "Previous period"}
def render(db: Session, frame: Frame, widget: Widget, target_w: int, target_h: int,
is_normal_wake: bool = True) -> Image.Image:
"""is_normal_wake=True (an ordinary /frame/image GET, not a button
press) resets browse_offset back to "today" if it had drifted --
mirrors the old _render_calendar_mode's identical behavior. A button
press explicitly moved the browse position on purpose, so it passes
is_normal_wake=False to render its own already-updated offset instead
of immediately snapping back to 0."""
if is_normal_wake:
with widget_locked(db, frame.id, widget.id) as (_, _, locked_cfg):
if locked_cfg.browse_offset != 0:
locked_cfg.browse_offset = 0
cfg = db.get(CalendarWidgetConfig, widget.id)
events, fetch_summary = get_or_refresh_calendar_events_for_widget(db, frame, widget)
weather_cities = get_or_refresh_weather_for_widget(db, frame, widget) if cfg.weather_enabled else None
tasks = (
get_or_refresh_tasks_for_widget(db, frame, widget)
if (cfg.view == "week" and cfg.tasks_enabled) else None
)
return _build(
events, view=cfg.view, browse_offset=cfg.browse_offset, target_w=target_w, target_h=target_h,
timezone=frame.timezone, fetch_summary=fetch_summary, week_start=cfg.week_start,
palette_rgb=frame.palette_rgb, weather_cities=weather_cities, weather_units=cfg.weather_units,
week_days=cfg.week_days, week_layout=cfg.week_layout, tasks=tasks,
week_start_offset=cfg.week_start_offset,
)
def _advance(db: Session, frame: Frame, widget: Widget) -> None:
with widget_locked(db, frame.id, widget.id) as (_, _, cfg):
cfg.browse_offset += 1
def _back(db: Session, frame: Frame, widget: Widget) -> None:
with widget_locked(db, frame.id, widget.id) as (_, _, cfg):
cfg.browse_offset -= 1
ACTIONS = {"advance": _advance, "back": _back}