Sync playback progress locally between Apple Watch and phone on pause#4535
Sync playback progress locally between Apple Watch and phone on pause#4535dericleeyy wants to merge 5 commits into
Conversation
PCIOS-196: playback progress made via the Apple Watch (Watch play source) did not appear on the phone — and the reverse — without manually tapping "Refresh now" on both devices. On pause, each device now pushes its playback position directly to the other over WatchConnectivity and applies it to the local player/DB (last-write-wins on playedUpToModified, skipping the actively-playing device), so Now Playing/progress updates without a manual refresh. The existing server sync still propagates to other devices. Gated behind the new watchPlaybackProgressLocalSync feature flag (default on). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
Version |
There was a problem hiding this comment.
Pull request overview
This PR adds a WatchConnectivity “fast-path” to sync paused playback progress locally between Apple Watch and iPhone (in both directions), so Now Playing/progress updates without requiring a manual “Refresh now” or a server round-trip.
Changes:
- Introduces a
watchPlaybackProgressLocalSyncfeature flag (default on) to gate the behavior. - Adds a new WatchConnectivity message (
PlaybackProgressUpdate) plus a new now-playing field (playedUpToModified) to support last-write-wins conflict resolution. - Implements watch→phone progress push on pause, and phone→watch progress application when the phone’s now-playing state updates.
Reviewed changes
Copilot reviewed 8 out of 8 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| podcasts/WatchConstants.swift | Adds message keys for playback progress updates and a now-playing playedUpToModified field key. |
| podcasts/Watch Communication/WatchManager.swift | Receives/apply watch→phone progress updates and includes playedUpToModified in the phone→watch now-playing payload. |
| Pocket Casts Watch App/UI/WatchSyncManager.swift | Sends watch→phone progress update on pause when the feature flag is enabled. |
| Pocket Casts Watch App/Data & Communication/WatchDataManager.swift | Adds accessor for now-playing playedUpToModified from the phone-sent state. |
| Pocket Casts Watch App/Data & Communication/SessionManager+Send.swift | Adds sendPlaybackProgress(...) message with guaranteed-delivery fallback. |
| Pocket Casts Watch App/Data & Communication/SessionManager.swift | Applies phone→watch paused progress to the local watch player using playedUpToModified last-write-wins. |
| Modules/Sources/PocketCastsUtils/Feature Flags/FeatureFlag.swift | Adds the watchPlaybackProgressLocalSync feature flag with default enabled. |
| CHANGELOG.md | Adds release note entry for instant watch/phone progress sync on pause. |
SergioEstevao
left a comment
There was a problem hiding this comment.
I tested this today by installing the branch on my Watch and Phone.
[x] Update from Watch to Phone: where working correctly, when moving the position of the now play episode on the watch source and pausing after a couple of seconds the phone updated.
[x] Update from Phone to Watch: this didn't work for me. I move around the phone play position, paused. The Watch only updated when I force a refresh on the home screen on the watch.
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Fixes PCIOS-196
Playback progress made on the Apple Watch (Watch play source) didn't appear on the iPhone — and changes on the phone didn't appear on the watch — without manually tapping "Refresh now" on both devices, because the two apps only reconciled through a server sync/refresh.
Currently the Watch source only syncs to the cloud server, with a 2 minute throttle limit update. When the phone receives the update, it does not reflect it immediately and require an app restart. The idea now is for the watch to also send the update to the phone locally, without depending on cloud. The cloud sync is untouched.
On pause, each device now pushes its playback position directly to the other over WatchConnectivity and applies it to the local player/DB, so Now Playing and episode progress update without a manual refresh. Conflicts use last-write-wins on
playedUpToModified, the actively-playing device is never overridden, and the existing server sync still propagates to other devices (web, iPad). Gated behind a newwatchPlaybackProgressLocalSyncfeature flag (default on).Changes
watchPlaybackProgressLocalSyncfeature flag (FeatureFlag.swift).PlaybackProgressUpdateWatchConnectivity message and anowPlayingPlayedUpToModifiednow-playing key (WatchConstants.swift).WatchSyncManager.playbackPaused→SessionManager.sendPlaybackProgress); the phone applies it and moves the live mini-player viaseekToFromSync(WatchManager.handlePlaybackProgressUpdate).playedUpToModifiedin its now-playing state, and the watch applies the phone's paused position to its local player inSessionManager.handleStateUpdate(newWatchDataManageraccessor).To test
Use a paired iPhone + Apple Watch (or simulators) signed into the same Pocket Casts Plus account, with the
watchPlaybackProgressLocalSyncflag enabled.Watch → phone:
Phone → watch:
Flag off:
Phone to Watch local sync
Screen.Recording.2026-06-17.at.12.07.06.AM.mov
Watch to Phone local sync
Screen.Recording.2026-06-16.at.11.31.32.PM.mov
Checklist
CHANGELOG.mdif necessary.