A native player bar, and the Glass look it sits in #2

Closed
opened 2026-09-19 16:56:08 -07:00 by rays · 1 comment
Owner

The first native surface, and the one that establishes how the rest will look.

Blocked by #1 -- a native bar shows an episode the host fetched, not one the page handed over.

Playback already owns the audio, the audio session, now-playing and the remote commands, and it knows nothing about the web view. What it has no face of its own: the bar at the bottom is the page's, driven through the bridge.

Glass is the theme to build, and only Glass. It is already an approximation of what UIKit gives for free -- its panels are color-mix(panel 70%, transparent) under backdrop-filter: blur(24px) saturate(180%) with an inset top highlight, which is UIBlurEffect systemUltraThinMaterial, and its palette is Apple's own by its own comments: #f5f5f7 is the label colour, #409cff is systemBlue's accessible dark variant, #ff9f0a is systemOrange. Built natively it is not a port of the theme, it is the thing the theme was imitating: real backdrop sampling, vibrancy, dynamic type, light and dark at no cost.

What this ticket settles for everything after it: the material treatment, the palette as system colours, the body wash (three radial gradients over the base, a MeshGradient or a stack of radials), and the icon set, where Font Awesome's SVGs map close to one-for-one onto SF Symbols.

The first native surface, and the one that establishes how the rest will look. **Blocked by #1** -- a native bar shows an episode the host fetched, not one the page handed over. Playback already owns the audio, the audio session, now-playing and the remote commands, and it knows nothing about the web view. What it has no face of its own: the bar at the bottom is the page's, driven through the bridge. Glass is the theme to build, and only Glass. It is already an approximation of what UIKit gives for free -- its panels are `color-mix(panel 70%, transparent)` under `backdrop-filter: blur(24px) saturate(180%)` with an inset top highlight, which is `UIBlurEffect` `systemUltraThinMaterial`, and its palette is Apple's own by its own comments: `#f5f5f7` is the label colour, `#409cff` is systemBlue's accessible dark variant, `#ff9f0a` is systemOrange. Built natively it is not a port of the theme, it is the thing the theme was imitating: real backdrop sampling, vibrancy, dynamic type, light and dark at no cost. What this ticket settles for everything after it: the material treatment, the palette as system colours, the body wash (three radial gradients over the base, a MeshGradient or a stack of radials), and the icon set, where Font Awesome's SVGs map close to one-for-one onto SF Symbols.
rays added the enhancement label 2026-09-19 16:56:08 -07:00
rays added a new dependency 2026-09-19 16:58:52 -07:00
rays added a new dependency 2026-09-19 16:58:57 -07:00
Author
Owner

Done in cacf992.

Sources/Glass.swift is the design system, and it is not a port of the stylesheet. Where the CSS had to write #409cff in dark and #0055aa in light — because no single blue clears AA over the wash — this asks for the system blue and gets both, along with contrast settings and dynamic type. Panels are .ultraThinMaterial with the inset top highlight the CSS draws with box-shadow. Only the wash keeps its hex values: there the colour is the design and there is no system equivalent to ask for.

Sources/PlayerBarView.swift draws what Playback knows, and Playback is the same object the lock screen and remote commands drive, so all of them agree without anything kept in step by hand. Back 15 and forward 30 match the page. Seeking waits for the finger to lift rather than sending a stream of seeks at a player still answering the last one.

The page's own bar is hidden. Its play buttons still work — they post to the host either way — but two bars for one player would be two sets of buttons disagreeing about what is playing.

One test had to be rewritten rather than the code. It asserted that one of the fixture's two episodes had a file, which stops being true the moment the event test asks the daemon to scan; the daemon is shared and keeps what earlier tests did to it. It now asks what the downloaded filter means rather than how many things match it today. Thirteen tests pass, twice over the same accumulated state.

Done in cacf992. `Sources/Glass.swift` is the design system, and it is not a port of the stylesheet. Where the CSS had to write `#409cff` in dark and `#0055aa` in light — because no single blue clears AA over the wash — this asks for the system blue and gets both, along with contrast settings and dynamic type. Panels are `.ultraThinMaterial` with the inset top highlight the CSS draws with `box-shadow`. Only the wash keeps its hex values: there the colour is the design and there is no system equivalent to ask for. `Sources/PlayerBarView.swift` draws what `Playback` knows, and `Playback` is the same object the lock screen and remote commands drive, so all of them agree without anything kept in step by hand. Back 15 and forward 30 match the page. Seeking waits for the finger to lift rather than sending a stream of seeks at a player still answering the last one. The page's own bar is hidden. Its play buttons still work — they post to the host either way — but two bars for one player would be two sets of buttons disagreeing about what is playing. One test had to be rewritten rather than the code. It asserted that one of the fixture's two episodes had a file, which stops being true the moment the event test asks the daemon to scan; the daemon is shared and keeps what earlier tests did to it. It now asks what the downloaded filter *means* rather than how many things match it today. Thirteen tests pass, twice over the same accumulated state.
rays closed this issue 2026-09-20 06:19:26 -07:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Reference: rays/ipodderx-app#2