Skip to content

Apple Watch W1.1: Now alive on one screen, pages without scrolling, graphic complications - #49

Merged
frahlg merged 6 commits into
mainfrom
claude/watch-w1.1
Oct 14, 2026
Merged

frahlg merged 6 commits into
mainfrom
claude/watch-w1.1

Conversation

@frahlg

@frahlg frahlg commented Oct 14, 2026 •

Copy link
Copy Markdown
Member

Polish for the Apple Watch app after W1 (#43), from Fredrik's notes on 0.4.0 and 0.4.1 (14 Oct 2026):

  • "i watch widget låt text lite utanför (och ska det ens vara text i en widget?)"
  • "vill jag ha med den där härlig alive vy och inte behöva scrolla heller utan isf är det mellan olika sidor. men kanske den där dial kan finnas med här?"

The app: four pages, nothing to scroll

watchOS's vertical paging (TabView with .verticalPage), one idea per page, each on one screen at 41 and 46 mm. The Crown turns the pages, except on the plan, where it steps the hand; a swipe goes on from there.

  1. Now, alive. The status line (● LIVE · FTW STYR), one node's figure large, and the phone's live trace under it: LiveSeries drawn by LiveTraceSurface in TraceInk, the node view's material from iPhone: the node view streams, the live trace as its hero (WP6) #41 and iPhone: history and ahead on the engine, in the live trace's material, the chart small and growing (WP7) #44. The trace keeps three minutes. It glows only while the phone passes on live frames, and holds still in ink when it does not. Under it the other nodes sit small, as a glyph and a figure. A tap on one traces it, and the watch remembers the choice. The home's use is traced first, because it moves whenever something in the house switches. The mode sits behind the toolbar's button.
  2. The plan dial with the Crown, drawn by the face the phone and its widget share since iPhone: the plan dial as one turn, shared with the watch, and its widget (WP11) #53. The line under the dial says what comes next ("Batteriet laddar till 24:00"); VoiceOver still reads the whole plan.
  3. The car: level, with the 10-cell meter beside it or, when the line is full, under it, what it does and when the box said so, the goal and the next window, and Charge now, Pause and Back to the plan as one row of glyph buttons. Each button names itself in full in its question and to VoiceOver. After a command, the box's receipt takes the place of what the car does, so nothing moves when it lands; once it has settled, leaving the page lets it go. With more than one charger, the one with a car plugged in shows.
  4. The price: price now, block bars, cheapest hours, when fetched.

At text sizes too large for the watch, a page scrolls rather than cut a reading off.

No dial on Now. Now already holds the status line, the large figure, the trace and four small figures. A dial small enough to fit beside them reads as texture, and the plan is one turn of the Crown away.

Complications: pictures, at most one figure

Family W1 Now
Circular the dial, battery level in the middle the shared dial from #53; the level is the only figure
Rectangular three lines of sentences and block bars a glyph for what comes next, one time ("till 20:30" or "22:00"), the price now, and the plan unrolled over 12 h: price in eight levels as bar heights, coloured by what the battery does, the car's charging as dots
Corner price and "billigast nu" the price as one figure, the day's range as a gauge along the corner
Inline price now price now
Cheap card "Billigt nu", a range and price, "HÄMTAT 10:37" a glyph, the window's hours, one figure, and the hours ahead with the window standing out

Every text has one line and may shrink rather than run outside. A plan older than an hour turns grey, and its time shows where the next event's time was. A fresh plan no longer prints its age in the rectangle; the box replans every quarter hour.

Pictures

Watch simulators on watchOS 27, paired with an iPhone simulator that runs the demo, taken after merging main (#53's shared dial). Pages come from the WatchTour UI test.

46 mm

Now Plan Car Price
Now Plan Car Price
Inline, rectangular, circular Corner Smart Stack: plan Smart Stack: cheap card (before the merge)
Face Corner Plan card Cheap card

41 mm

Now Plan Car Price
Now Plan Car Price
Inline and circular
Face

On 41 mm the face's middle module shows the Smart Stack's top, which on this simulator holds other apps. The rectangle, the corner and the cheap card on 41 mm still need pictures: this watch has no Infograph face and no FTW card pinned in its stack, and setting those up needs the simulator panel's grant for this watch.

Recordings

Paging, 46 mm The Crown on the plan, 46 mm
Paging Crown

MP4: paging, Crown.

The Crown clip comes from testCrownScrub, which turns the Crown through XCUIDevice.rotateDigitalCrown. In the simulator each synthesized turn takes about five seconds, even with the laptop idle, so the clip shows each frame once and drops the frames where nothing moved. Each turn in the test moves the hand several quarters. The paging clip runs at real speed.

Outside the watch targets

  • FTWCharts/LiveTrace.swift: LiveTraceSurface takes paused (default false). The phone draws as before.
  • FTWShared/Watch: WatchNow.Reading.signedW and Node.floorW (the phone's scaleFloorW), and CheapWindow.short.

The shared dial (#53)

Main is merged in. W1.1 draws the plan page and the circular complication with #53's PlanDialView, and the rectangle's strip (DialStrip) reads PlanDial. BlockBars keeps its highlight and takes PlanDial.levels.

One change in the shared face: on a watch-sized dial the car's goal ("80 %") landed on the hand's time and price in the middle, so PlanDialFace now shows the goal only on a dial at least 200 pt across. The phone's dial (up to 340 pt) still shows it. The plan lane knows.

The strip and WP10's PlanStrip (#52) both unroll the plan. The view is named DialStrip so the names do not meet. Drawing the rectangle from PlanStrip is a possible follow-up; WP10's drawing carries hour labels and readouts made for the phone.

Proof

  • swift test after the merge: 214 and 365 tests, all pass.
  • The iPhone app with the watch app inside, and the FTWWatch scheme, build.
  • WatchTour after the merge: testPaging passes on 41 and 46 mm, testCrownScrub on 46 mm.

Not checked

  • 45 mm and Ultra did not run. They sit between 41 and 46 mm in width and height.
  • Text sizes above the default. simctl cannot set a watch simulator's text size, and the launch argument that works on the phone changed nothing here. Each page falls back to scrolling rather than cutting a reading.
  • The cheap card shows 15 min before the cheapest window. The demo's window is 00–02, so its picture comes from a local build that showed the card six hours early, taken before the merge. That build was not committed. After the merge the same build did not bring the card into the stack within a few minutes; its code is unchanged.
  • A real watch: the glow and frame rate on the wrist, and the Crown's feel.

🤖 Generated with Claude Code

frahlg and others added 6 commits October 14, 2026 17:22
…nd graphic complications

Fredrik's notes on W1 (14 Oct 2026): the watch widgets let text run
outside and should hold little text; the app should have the phone's
live view and pages instead of scrolling.

- Now: the status line, one node's figure large, the phone's live
  trace (LiveSeries drawn by LiveTraceSurface in TraceInk), glowing
  only while live, and the other nodes small. A tap on a small one
  traces it. The mode sits behind a toolbar button.
- Every page fits one screen at the standard sizes; at text sizes too
  large for the watch it scrolls rather than cut a reading off. The
  car's commands are one row of glyph buttons.
- Complications: no sentences. Rectangular is a glyph, one time, the
  price now and the plan unrolled as a strip; corner is the price with
  the day's range as a gauge; inline is the price; the cheap card is a
  glyph, its hours, one figure and the hours ahead with the window
  standing out. Every text has one line and may shrink.
- LiveTraceSurface takes `paused`, so a trace that is not live holds
  still. WatchNow.Reading gives its signed watts for the trace, and
  each node the phone's scale floor.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…omes next, Now waits for live in the tour

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The receipt now takes the place of what the car does, its goal and next
window, until the page is left; a settled receipt then goes. The page no
longer keeps a room of its own for the receipt, so it fits 46 mm without
scrolling and the swipe turns the page. The commands are one row of glyph
buttons, 30 pt high.

The watch's strip view is now DialStrip, so it does not shadow the
PlanStrip value that the phone's plan lane adds to FTWShared.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Now's trace takes the height that is left, at least 24 pt, so the page
fits 41 mm without scrolling and the swipe turns the page. On 46 mm the
trace is as tall as before.

The car's meter goes under its level when both do not fit on one line,
as with "20 % antaget", rather than cutting the word.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
BlockBars keeps W1.1's highlight and takes PlanDial.levels from #53.
DialStrip, the rectangle's strip, now reads PlanDial.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Since #53 the watch's plan page draws the shared face at the app size,
and on a dial about 100 pt across the goal ("80 %") landed on the hand's
time and price in the middle. The goal now shows only on a dial at least
200 pt across, which the phone's always is.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@frahlg
frahlg marked this pull request as ready for review October 14, 2026 19:53
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 14, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-14T19:57:33.616546Z 06c185a Draft marked ready
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@frahlg
frahlg merged commit 85a9204 into main Oct 14, 2026
1 check passed

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 06c185acd9

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

/// 19:30". The whole plan is the dial.
private func next(_ m: PlanGlance.Moment) -> String {
guard let what = m.nextWhat else { return m.summary }
return [what, m.nextUntil].compactMap { $0 }.joined(separator: " ")

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Include the start time for future plan events

When the next event has not started, this still combines its description only with nextUntil, so a plan whose next charge runs from 01:00–04:45 is presented as “Car charges … until 04:45,” incorrectly implying that charging is already underway. PlanGlance exposes nextWhen specifically to distinguish future events; include it or use the existing future-event sentence formatting.

Useful? React with 👍 / 👎.

}
.animation(Theme.spring, value: figure.value)
.accessibilityElement(children: .combine)
.accessibilityLabel("\(figure.title), \(figure.value) \(figure.unit), \(figure.word)")

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Announce the hero node's displayed charge level

When the battery or car is selected as the hero, the visible trailing text is figure.level, but this explicit accessibility label replaces the combined child content with figure.word and omits that percentage. VoiceOver users therefore lose the battery/car level that the previous combined row exposed; include figure.level in the label when present.

Useful? React with 👍 / 👎.

Comment on lines +110 to +111
.accessibilityElement(children: .ignore)
.accessibilityLabel(face.plan.summary)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Announce when the rectangular plan is stale

For a plan older than an hour, the rectangular complication visually replaces the event with a clock and the plan's read time, but ignoring its children and labeling it only with face.plan.summary drops that staleness information. VoiceOver consequently reads the old plan without saying that it is old; include the plan age/read time in the replacement label when face.plan.isGrey.

Useful? React with 👍 / 👎.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant