feat(podcasts): #8 follow-ups — AI summary + in-app Open Bookmark
Resolves the two deviations from the episode detail sheet: - AI summary now shows in the detail sheet. Added a URL-keyed AISummaryStore that BookmarksViewModel populates as it enriches/loads bookmarks, so the decoupled Podcasts tab can surface a summary from just the episode URL — without recoupling to BookmarksViewModel. - "Open Bookmark" opens the in-app BrowserView as a nested sheet (generator threaded through PodcastLibraryView / EpisodePickerView), alongside the existing "Open in Safari" and Share. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
27
Marks/Services/AISummaryStore.swift
Normal file
27
Marks/Services/AISummaryStore.swift
Normal file
@@ -0,0 +1,27 @@
|
||||
import Foundation
|
||||
|
||||
/// URL-keyed cache of AI summaries so views that only know a URL — e.g. the
|
||||
/// deliberately-decoupled Podcasts tab — can show a bookmark's summary without
|
||||
/// holding the full `Bookmark`. Written by `BookmarksViewModel` as it enriches
|
||||
/// and loads bookmarks; read by the episode detail sheet.
|
||||
enum AISummaryStore {
|
||||
private static let key = "aiSummaryByURL"
|
||||
|
||||
static func summary(for url: String) -> String? {
|
||||
let store = UserDefaults.standard.dictionary(forKey: key) as? [String: String] ?? [:]
|
||||
let value = store[url]
|
||||
return (value?.isEmpty ?? true) ? nil : value
|
||||
}
|
||||
|
||||
static func set(_ summary: String?, for url: String) {
|
||||
var store = UserDefaults.standard.dictionary(forKey: key) as? [String: String] ?? [:]
|
||||
if let summary, !summary.isEmpty {
|
||||
guard store[url] != summary else { return } // no-op if unchanged
|
||||
store[url] = summary
|
||||
} else {
|
||||
guard store[url] != nil else { return }
|
||||
store.removeValue(forKey: url)
|
||||
}
|
||||
UserDefaults.standard.set(store, forKey: key)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user