Siri: App Intents with phrases that need no setup: Resume, Pause, Skip forward, Skip back, Set a sleep timer, How many unread. The playback ones are AudioPlaybackIntents, run in the app and allowed to start audio from the background. Playback is now one shared instance (Playback.shared) so Siri and the widget reach it with no page loaded. It remembers the last episode and its place (LastPlayed), so Resume works with the app closed; the page, opened afterwards, does not know about an episode started that way. Widget: small and medium on the home screen, circular and rectangular on the lock screen. It shows the unread count and the last episode, with a Resume or Pause button (PlayPauseIntent, shared with Siri). It draws what the app writes to the App Group group.net.sdf1.ipx. The app asks for a redraw on play, pause, a new episode or a new count, not on every position, since iOS rations redraws. Shared/ builds into both targets, with WIDGET set in the widget's, where the player does not exist. ipx's push now carries content-available, which wakes the closed app for a moment to give the widget the count the icon just got (#433). Tested: unit tests for the snapshot and the remembered place, 19 in all; in the simulator, playing an episode wrote the snapshot to the App Group. Not testable there: Siri, and the widget drawn. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -71,6 +71,30 @@ on the `sdf1.net` zone) blocks every request to it except a bearer-token one for
|
||||
| `Sources/Playback.swift` | `AVPlayer`, the audio session, now playing, the remote commands, saving positions |
|
||||
| `Sources/CookieBridge.swift` | the web view's cookies into `HTTPCookieStorage.shared`, for the player |
|
||||
| `Sources/Server.swift` | which server |
|
||||
| `Sources/Intents.swift`, `Shared/PlayPauseIntent.swift` | Siri and Shortcuts (#427) |
|
||||
| `Sources/LastPlayed.swift` | the last episode and its place, so Resume works with the app closed |
|
||||
| `Widgets/`, `Shared/Snapshot.swift`, `Sources/WidgetFeed.swift` | the widget (#428), and what the app writes for it |
|
||||
|
||||
### Siri and Shortcuts
|
||||
|
||||
With nothing to set up, Siri answers "Resume iPX" (or "Play iPX"), "Pause iPX", "Skip forward
|
||||
in iPX", "Skip back in iPX", "Set a sleep timer in iPX" and "How many unread in iPX"; each is also
|
||||
an action in the Shortcuts app. The playback ones are `AudioPlaybackIntent`s, which iOS runs in the
|
||||
app and lets start audio with the phone locked. Resume carries on with what is loaded, or else the
|
||||
last episode from where it got to (`LastPlayed`), which plays without the page: opening the app
|
||||
afterwards shows the page with nothing in its player, while the lock screen has it.
|
||||
|
||||
### The widget
|
||||
|
||||
Small and medium on the home screen, circular and rectangular on the lock screen: All
|
||||
Subscriptions' unread count and the last episode, with a Resume or Pause button (the same
|
||||
`PlayPauseIntent`). The widget has no sign-in and no player, so it draws what the app last wrote
|
||||
to the App Group `group.net.sdf1.ipx` (`Snapshot`), and the app asks WidgetKit to redraw on a play,
|
||||
a pause, a new episode or a new count, not on every position saved, since iOS rations redraws.
|
||||
With the app closed, ipx's push (#433) carries `content-available`, which wakes the app for a
|
||||
moment to give the widget the new count; iOS rations those wakes too, so the widget can trail the
|
||||
icon. `Shared/` is built into both targets, with `WIDGET` set in the widget's, where the player
|
||||
does not exist.
|
||||
|
||||
## The messages
|
||||
|
||||
|
||||
Reference in New Issue
Block a user