ux(provisioning): step 1 is now "Plug in power"

Frames will ship with the battery disconnected to preserve shelf life
— the setup screen polling is non-trivial draw on e-ink, and a unit
that sits on a shelf for weeks before unboxing would arrive flat.
Surface "plug in power" as the prerequisite step ahead of unlock and
scan, so the recipient can't miss it.

Step list grows from 4 to 5; pitch shrinks from 38 → 32 px to keep
the manual-help QR clear of the bottom edge.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-09 13:41:49 -04:00
parent 1399cc3756
commit f1d867c659
5 changed files with 9 additions and 6 deletions
Binary file not shown.
Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.
Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 12 KiB

+9 -6
View File
@@ -220,19 +220,22 @@ def gen_ap(accent=YL, header="SETUP MODE — STEP 1 OF 2", qr_label="SCAN TO C
bb = draw.textbbox((0,0), "WiFi", font=F_HEAD) bb = draw.textbbox((0,0), "WiFi", font=F_HEAD)
draw.rectangle([28, BODY_Y+82, 28+bb[2]+2, BODY_Y+85], fill=accent) draw.rectangle([28, BODY_Y+82, 28+bb[2]+2, BODY_Y+85], fill=accent)
# Steps — step 1 is the unlock-first prompt (iOS won't fire the # Steps — frames ship with battery unplugged to preserve shelf life
# captive UI from a locked-phone scan). Two-QR flow because iOS # (idle setup-screen polling is non-trivial draw on e-ink), so the
# in recent versions doesn't auto-open the captive portal even # very first prompt is "Plug in power". Step 2 is unlock-first (iOS
# after CNA detects it; scanning the second QR opens Safari # won't fire the captive UI from a locked-phone scan). Two-QR flow
# which forces the portal to render. # because iOS in recent versions doesn't auto-open the captive
# portal even after CNA detects it; scanning the second QR opens
# Safari which forces the portal to render.
steps = [ steps = [
("Plug in power", ""),
("Unlock your phone first", ""), ("Unlock your phone first", ""),
("Scan QR 1 →", "joins PictureFrame WiFi"), ("Scan QR 1 →", "joins PictureFrame WiFi"),
("Scan QR 2 →", "page opens in Safari"), ("Scan QR 2 →", "page opens in Safari"),
("Enter your WiFi password", "and tap Connect"), ("Enter your WiFi password", "and tap Connect"),
] ]
sy = BODY_Y + 95 sy = BODY_Y + 95
step_pitch = 38 step_pitch = 32
for i, (l1, l2) in enumerate(steps): for i, (l1, l2) in enumerate(steps):
bx, by = 28, sy + i*step_pitch bx, by = 28, sy + i*step_pitch
draw.rectangle([bx, by, bx+24, by+24], fill=BK) draw.rectangle([bx, by, bx+24, by+24], fill=BK)