Add mini-player, per-row podcast button, and resume-from-position
Some checks failed
CI / build-and-deploy (push) Failing after 9s

- MiniPlayerView: persistent bar above tab bar, shows title/progress,
  play/pause and close buttons, slides in when audio starts
- PodcastPlayerViewModel lifted to BookmarksViewModel so it persists
  across sheet dismissals — audio keeps playing in background
- Headphone button on every bookmark row (filled = cached, outline = not)
- start() is idempotent: re-tapping same article resumes without restart
- stop() saves playback position before teardown (PodcastProgress)
- setupPlayer restores saved position on next open
- BrowserView keeps its own local VM (stopOnDismiss: true)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Krishna Kumar
2026-05-22 16:19:21 -05:00
parent 65efe708ee
commit abe35f47d6
5 changed files with 238 additions and 43 deletions

View File

@@ -3,6 +3,7 @@ import SwiftUI
struct BookmarkRow: View {
let bookmark: Bookmark
var readingProgress: Double = 0
var onPodcast: (() -> Void)? = nil
var body: some View {
VStack(alignment: .leading, spacing: 6) {
@@ -29,6 +30,18 @@ struct BookmarkRow: View {
.font(.system(size: 16))
.foregroundStyle(.tertiary)
}
Spacer()
if let onPodcast {
Button(action: onPodcast) {
Image(systemName: podcastCached ? "headphones.circle.fill" : "headphones.circle")
.font(.system(size: 26))
.foregroundStyle(podcastCached ? .blue : Color(.systemGray3))
}
.buttonStyle(.plain)
.padding(.top, 1)
}
}
if let summary = bookmark.aiSummary {
@@ -76,6 +89,10 @@ struct BookmarkRow: View {
.contentShape(Rectangle())
}
private var podcastCached: Bool {
FileManager.default.fileExists(atPath: ClaudeService.cachedPodcastURL(for: bookmark.url).path)
}
private var effectiveTags: [String] {
let base = bookmark.tagNames
let ai = bookmark.aiTags ?? []