Bidirectional progress sync, reliable background history, MB-accurate download ring
- Bidirectional progress sync: server's `lastUpdate` now parsed correctly; pull timer (60s) + scenePhase hook reconcile against local state. Server-newer while paused/playing stashes a `pendingServerProgress` and surfaces a prompt on next Play; server-older triggers an immediate push. - History: lockscreen/Control-Center skip & scrub now route through AppState via `onRemoteSkip`/`onRemoteSeek` callbacks (previously bypassed history). `AppState.skip(by:)` itself now records the pre-skip position. - Chapter detection moved to the AVPlayer periodic time observer — fires reliably while the app is backgrounded or the device is locked, where the 5s runloop Timer can be throttled. - Always fetch item detail when online (even for downloaded items) so `item.chapters` is populated and history entries get chapter titles. - DownloadManager: per-track byte-fraction progress, so single-track 1+GB audiobooks' ring grows smoothly instead of staying at 0% until done. - PlayerBar: extracted ScrubberView into its own struct so per-second time updates no longer re-render the parent (fixes iOS history-popup flicker). - App icon: re-embedded sRGB profile in marketing icon; bumped version 2.0 to 2.1. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -167,10 +167,15 @@ final class ABSClient {
|
||||
currentTime: dto.currentTime ?? 0,
|
||||
duration: dto.duration ?? 0,
|
||||
isFinished: dto.isFinished ?? false,
|
||||
updatedAt: Date()
|
||||
updatedAt: Self.parseLastUpdate(dto.lastUpdate)
|
||||
)
|
||||
}
|
||||
|
||||
private static func parseLastUpdate(_ ms: Double?) -> Date {
|
||||
guard let ms, ms > 0 else { return Date() }
|
||||
return Date(timeIntervalSince1970: ms / 1000)
|
||||
}
|
||||
|
||||
func saveProgress(_ progress: PlaybackProgress) async throws {
|
||||
let body: [String: Any] = [
|
||||
"currentTime": progress.currentTime,
|
||||
@@ -200,7 +205,7 @@ final class ABSClient {
|
||||
currentTime: p.currentTime ?? 0,
|
||||
duration: p.duration ?? 0,
|
||||
isFinished: p.isFinished ?? false,
|
||||
updatedAt: Date()
|
||||
updatedAt: Self.parseLastUpdate(p.lastUpdate)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user