- Batteries: one card per battery with On/Off, the mode list (cheap hours and selling greyed out until OPT-11 P3), level, and Now / Today / Why lines built in homeview.py. Replaces the OPT-11 P1 minimal cards and uses the existing pack_use / pack_mode actions and store keys. - An Off battery the peak limit still needs says so with its figure; no line shows 0 W beside moving power (OPT-11 P1 test F2). Today says "Not planned yet" until OPT-11 P3/P4. - Home's plan leaves Off batteries out, except for the peak limit. - Settings opens on Simple: the layout's simple fields with an applies chip and a note, plus the battery switches and modes. Installer is one tap. - English and Dutch words in app/ui_text; test_batteries_screen.py; browser check tools/ux13_browser_check.py (CHECK=1 ux13_screenshots.sh); new and changed screenshots only. No control, allocator, arbiter or command module changed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UBtqPrG1mDLXzTEBnhEkkV
111 lines
4.2 KiB
Python
111 lines
4.2 KiB
Python
"""UX-13 P5: the DOCS screenshots of the new screens, taken from the real page.
|
|
|
|
Run by tools/ux13_screenshots.sh, which serves tools/ux13_demo.py fixtures and
|
|
runs this inside the Playwright image. Each shot fails the run on a page
|
|
error, so a broken screen is never pictured.
|
|
|
|
python3 ux13_screenshots.py OUT_DIR # DEMO_<STATE> = the fixture's URL
|
|
|
|
P3 adds the Batteries screen and Settings, Simple (the default Settings
|
|
view), so the Installer shots click Installer first.
|
|
"""
|
|
|
|
import os
|
|
import sys
|
|
|
|
from playwright.sync_api import sync_playwright
|
|
|
|
OUT = sys.argv[1]
|
|
DESKTOP = {"width": 1000, "height": 900}
|
|
PHONE = {"width": 390, "height": 844}
|
|
|
|
|
|
def url(state):
|
|
return os.environ[f"DEMO_{state.upper()}"]
|
|
|
|
|
|
def shot(browser, name, state, route, *, lang="en-GB", size=DESKTOP,
|
|
full=True, act=None, only=None):
|
|
ctx = browser.new_context(locale=lang, viewport=size,
|
|
color_scheme="light", reduced_motion="reduce")
|
|
page = ctx.new_page()
|
|
errors = []
|
|
page.on("pageerror", lambda e: errors.append(str(e)))
|
|
page.goto(url(state) + route)
|
|
page.wait_for_load_state("networkidle")
|
|
page.wait_for_timeout(1500) # the first /status and checks
|
|
if act:
|
|
act(page)
|
|
page.wait_for_timeout(1500) # the debounced start checks
|
|
path = os.path.join(OUT, name + ".png")
|
|
if only:
|
|
page.locator(only).screenshot(path=path)
|
|
else:
|
|
page.screenshot(path=path, full_page=full)
|
|
ctx.close()
|
|
if errors:
|
|
raise SystemExit(f"{name}: page errors {errors}")
|
|
print(f" {name}.png")
|
|
|
|
|
|
def installer(page):
|
|
page.locator("#set-view [data-v=installer]").click()
|
|
|
|
|
|
def open_tariff(page):
|
|
installer(page)
|
|
page.locator("details.grp[data-g=tariff] > summary").click()
|
|
page.locator("details.grp[data-g=meter] > summary").click() # close it
|
|
# The fixture site is on a dynamic contract: its fallback gets windows.
|
|
page.get_by_role("radiogroup", name="Price when the feed is down") \
|
|
.get_by_role("radio", name="Other time windows").click()
|
|
|
|
|
|
def windows(page, overlap=False):
|
|
open_tariff(page)
|
|
add = page.get_by_role("button", name="+ Add a time window")
|
|
rows = (("07:00", "23:00" if overlap else "22:00", "mon-fri", "0.34"),
|
|
("22:00", "07:00", "mon-fri", "0.26"),
|
|
("00:00", "24:00", "sat,sun", "0.24"))
|
|
for i, (a, b, days, price) in enumerate(rows, start=1):
|
|
add.click()
|
|
page.get_by_label(f"Window {i}, From").fill(a)
|
|
page.get_by_label(f"Window {i}, To").fill(b)
|
|
page.get_by_label(f"Window {i}, Days").select_option(days)
|
|
page.get_by_label(f"Window {i}, Price").fill(price)
|
|
page.locator("[data-key='ui.periods']").scroll_into_view_if_needed()
|
|
|
|
|
|
def main():
|
|
os.makedirs(OUT, exist_ok=True)
|
|
with sync_playwright() as p:
|
|
b = p.chromium.launch()
|
|
shot(b, "home-running", "running", "#home")
|
|
shot(b, "home-running-nl", "running", "#home", lang="nl-BE")
|
|
shot(b, "home-shadow", "shadow", "#home")
|
|
shot(b, "home-phone", "running", "#home", size=PHONE)
|
|
shot(b, "home-setup-only", "setup", "#home", full=False)
|
|
shot(b, "settings-installer", "running", "#settings", act=installer)
|
|
shot(b, "settings-installer-nl", "running", "#settings", lang="nl-BE",
|
|
act=installer)
|
|
shot(b, "batteries", "modes", "#batteries")
|
|
shot(b, "batteries-nl", "modes", "#batteries", lang="nl-BE")
|
|
shot(b, "batteries-off-peak", "off_peak", "#batteries")
|
|
shot(b, "batteries-phone", "refusal", "#batteries", size=PHONE,
|
|
full=False)
|
|
shot(b, "batteries-modes-off", "running", "#batteries", full=False)
|
|
shot(b, "settings-simple", "modes", "#settings")
|
|
shot(b, "settings-simple-nl", "modes", "#settings", lang="nl-BE")
|
|
tariff = "details.grp[data-g=tariff]"
|
|
shot(b, "settings-time-windows", "running", "#settings",
|
|
act=windows, only=tariff)
|
|
shot(b, "settings-time-windows-overlap", "running", "#settings",
|
|
act=lambda page: windows(page, overlap=True), only=tariff)
|
|
shot(b, "setup-step-1", "new", "#setup")
|
|
shot(b, "setup-step-1-nl", "new", "#setup", lang="nl-BE")
|
|
b.close()
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|