M1-03: Design pass — static UI on sample data #15

Merged
wk merged 1 commit from m1-03-design-pass into main 2026-08-06 14:38:54 -04:00
Member

Issue #3. First visual pass in code, stock SwiftUI throughout, no audio anywhere.

What changed

Four screens, plus the model they are built against:

  • Stash/Model/Memo.swiftMemo and SyncState. The three sync icons are stock SF Symbols and match Wes's description: icloud.slash, arrow.triangle.2.circlepath.icloud, checkmark.icloud. Symbol names were checked against the system's name_availability.plist, because a bad symbol name renders as nothing rather than failing to compile.
  • Stash/Model/SampleMemos.swift — synthetic sample data, labelled as such in its own doc comment, and deleted when capture lands. Titles are the date-stamped default names the app will generate, since M1 has no naming UI.
  • Stash/Views/MemoListView.swift — the root view. Record toggles the recording bar; it touches no audio session and adds no memo.
  • Stash/Views/MemoRow.swift — one row, plus the sync indicator.
  • Stash/Views/RecordingBar.swift — level meter, live elapsed timer, stop button. Pinned with safeAreaInset so the last row still scrolls clear of it.
  • Stash/Views/SettingsView.swift — a Form with the version. The VTT-first/audio-first preference is deliberately absent; it controls something that does not exist until M3.
  • ContentView.swift is gone, replaced by MemoListView.

README.md and AGENTS.md updated in the same commit: the README no longer claims the app is an empty scaffold, and AGENTS.md gains the design section (stock components first, no Figma step, placeholder data must admit it is placeholder) and the new source layout.

Deliberate choices worth a sentence

Every sample memo is notSynced. That is the only honest state in M1. The other two cases exist in the type so the row is designed against the states it will really have, instead of being redesigned when sync arrives.

Stock components everywhere they existContentUnavailableView for empty, Form for settings, safeAreaInset for the bar, system materials for backgrounds. The level meter is the only hand-drawn control, it is driven by a sine wave rather than a microphone, and it says so.

Dark and light are entirely system-managed. No per-mode colours anywhere.

Validated

  • swiftlint lint --strict — 0 violations, 7 files.
  • Simulator build succeeded; installed and launched on iPhone 17 Pro Max, confirmed still running afterwards.
  • All four screens plus dark mode screenshotted — attached to issue #3.
  • On device: built signed, installed and launched on wes-iphone (iPhone 17 Pro), confirmed alive in the process list. Wes confirmed the screens look right. Exact commands are in a comment on issue #3.

One layout bug was found by looking at the screenshots rather than trusting the code: the recording bar's material hugged its content instead of spanning the width, so the bar rendered as a floating box mid-screen. Fixed before the screenshots that are attached.

Nothing signing-related is in the repository. DEVELOPMENT_TEAM was passed on the xcodebuild command line, because this repo is public.

Not validated

  • Dynamic Type at large sizes, landscape, and iPad.
  • VoiceOver actually reading the rows. Accessibility labels are written but I have not run VoiceOver over them.
  • CI has not run this. .woodpecker/lint.yml can run, but the simulator build still has no macOS agent.

Issue #3 stays open after this merges — the design pass is expected to iterate.

Issue #3. First visual pass in code, stock SwiftUI throughout, no audio anywhere. ## What changed Four screens, plus the model they are built against: - **`Stash/Model/Memo.swift`** — `Memo` and `SyncState`. The three sync icons are stock SF Symbols and match Wes's description: `icloud.slash`, `arrow.triangle.2.circlepath.icloud`, `checkmark.icloud`. Symbol names were checked against the system's `name_availability.plist`, because a bad symbol name renders as nothing rather than failing to compile. - **`Stash/Model/SampleMemos.swift`** — synthetic sample data, labelled as such in its own doc comment, and deleted when capture lands. Titles are the date-stamped default names the app will generate, since M1 has no naming UI. - **`Stash/Views/MemoListView.swift`** — the root view. Record toggles the recording bar; it touches no audio session and adds no memo. - **`Stash/Views/MemoRow.swift`** — one row, plus the sync indicator. - **`Stash/Views/RecordingBar.swift`** — level meter, live elapsed timer, stop button. Pinned with `safeAreaInset` so the last row still scrolls clear of it. - **`Stash/Views/SettingsView.swift`** — a `Form` with the version. The VTT-first/audio-first preference is deliberately absent; it controls something that does not exist until M3. - `ContentView.swift` is gone, replaced by `MemoListView`. `README.md` and `AGENTS.md` updated in the same commit: the README no longer claims the app is an empty scaffold, and `AGENTS.md` gains the design section (stock components first, no Figma step, placeholder data must admit it is placeholder) and the new source layout. ## Deliberate choices worth a sentence **Every sample memo is `notSynced`.** That is the only honest state in M1. The other two cases exist in the type so the row is designed against the states it will really have, instead of being redesigned when sync arrives. **Stock components everywhere they exist** — `ContentUnavailableView` for empty, `Form` for settings, `safeAreaInset` for the bar, system materials for backgrounds. The level meter is the only hand-drawn control, it is driven by a sine wave rather than a microphone, and it says so. **Dark and light are entirely system-managed.** No per-mode colours anywhere. ## Validated - `swiftlint lint --strict` — 0 violations, 7 files. - Simulator build succeeded; installed and launched on iPhone 17 Pro Max, confirmed still running afterwards. - All four screens plus dark mode screenshotted — attached to issue #3. - **On device:** built signed, installed and launched on `wes-iphone` (iPhone 17 Pro), confirmed alive in the process list. Wes confirmed the screens look right. Exact commands are in a comment on issue #3. One layout bug was found by looking at the screenshots rather than trusting the code: the recording bar's material hugged its content instead of spanning the width, so the bar rendered as a floating box mid-screen. Fixed before the screenshots that are attached. Nothing signing-related is in the repository. `DEVELOPMENT_TEAM` was passed on the xcodebuild command line, because this repo is public. ## Not validated - Dynamic Type at large sizes, landscape, and iPad. - VoiceOver actually reading the rows. Accessibility labels are written but I have not run VoiceOver over them. - CI has not run this. `.woodpecker/lint.yml` can run, but the simulator build still has no macOS agent. Issue #3 stays open after this merges — the design pass is expected to iterate.
Four screens in code, with stock SwiftUI throughout. No audio anywhere; every
value on screen comes from SampleMemos, which says so in its own doc comment.

Memo list, with the three sync icons Wes described — icloud.slash,
arrow.triangle.2.circlepath.icloud, checkmark.icloud. All sample memos are
notSynced, which is the truth in M1; the other two states exist so the row is
designed against the states it will really have rather than redesigned when
sync arrives.

Empty state uses ContentUnavailableView. Settings is a Form with the version
and nothing else — the sync-order preference is deliberately absent, because a
switch that changes nothing is worse than no switch.

The recording bar pins with safeAreaInset so the last row can still scroll
clear of it, and shows a level meter, a live elapsed timer and a stop button.
The meter is the one hand-drawn thing here and is driven by a sine wave, not a
microphone; it is replaced outright when capture lands.

Dark and light are left entirely to the system.
wk merged commit dc141f8b1a into main 2026-08-06 14:38:54 -04:00
wk deleted branch m1-03-design-pass 2026-08-06 14:38:55 -04:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
Stash/stash-ios!15
No description provided.