Sync watch progress on natural video completion and backgrounding

Naturally finished videos only saved their 100% progress locally
(play() deliberately skips the sync-on-switch when videoEndedNaturally
is set), so the watched state never reached other devices in the
autoplay flow. Save completion through updateWatchProgress, which
queues the iCloud sync.

Also queue the current playback position when the app enters
background, so backgrounding mid-video hands the position off to other
devices instead of only syncing on explicit stop or video switch.
This commit is contained in:
Arkadiusz Fal
2026-07-14 23:08:39 +02:00
parent 9467ac4dba
commit 959641b642
2 changed files with 14 additions and 2 deletions

View File

@@ -2563,8 +2563,10 @@ final class PlayerService {
let completedDuration = video.duration > 0 ? video.duration : state.duration
guard completedDuration > 0 else { return }
// Save the full duration as watched time when video completes
dataManager.updateWatchProgressLocal(for: video, seconds: completedDuration, duration: completedDuration)
// Save the full duration as watched time and queue for iCloud sync.
// This is the only save for a naturally finished video play() skips
// saveProgressAndSync() when videoEndedNaturally is set.
dataManager.updateWatchProgress(for: video, seconds: completedDuration, duration: completedDuration)
// Update Handoff activity with completed time
handoffManager?.updatePlaybackTime(completedDuration)
@@ -2584,6 +2586,12 @@ final class PlayerService {
NotificationCenter.default.post(name: .watchHistoryDidChange, object: nil)
}
/// Saves current progress and queues it for iCloud sync without ending playback.
/// Called when the app enters background so the position reaches other devices.
func syncWatchProgress() {
saveProgressAndSync()
}
private func checkSponsorBlockSegments(at time: Double) {
// Read settings - use defaults if settings manager not available
let enabled = settingsManager?.sponsorBlockEnabled ?? true

View File

@@ -282,6 +282,8 @@ struct YatteeApp: App {
// Flush pending CloudKit changes when entering background
if newPhase == .background {
appEnvironment.cloudKitSync.stopForegroundPolling()
// Queue current watch progress so the position reaches other devices
appEnvironment.playerService.syncWatchProgress()
Task {
await appEnvironment.cloudKitSync.flushPendingChanges()
}
@@ -330,6 +332,8 @@ struct YatteeApp: App {
// Flush pending CloudKit changes when entering background
if newPhase == .background {
appEnvironment.cloudKitSync.stopForegroundPolling()
// Queue current watch progress so the position reaches other devices
appEnvironment.playerService.syncWatchProgress()
#if os(iOS)
// Persist pending SwiftData changes and run the CloudKit flush