Fix ShareExtension "Open Marks first" + add widget + BookmarkListRow polish
All checks were successful
CI / build-and-deploy (push) Successful in 41s

- Save serverConfig to App Group on every app launch so ShareExtension
  can always find credentials without requiring a disconnect/reconnect flow
- Add MarksWidget target with RandomBookmarkWidget (random saved bookmark,
  reloads hourly) using file-based App Group storage to avoid CFPreferences issues
- Extract BookmarkListRow as shared component with editorial typography tweaks
  (17pt semibold title, 13pt domain, relative date, 32×32 favicon, italic AI summary,
  20pt podcast icon, 16pt horizontal insets)
- Add MarksWidget and ShareExtension Xcode schemes for direct run/debug

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Krishna Kumar
2026-05-24 13:11:05 -05:00
parent d87500a7dc
commit 199fc2d043
23 changed files with 1437 additions and 172 deletions

View File

@@ -6,6 +6,7 @@ struct PodcastEntry: Codable, Identifiable {
let filename: String
var title: String?
let createdAt: Date
var parentBookmarkUrl: String?
}
enum PodcastIndex {
@@ -35,14 +36,19 @@ enum PodcastIndex {
return entries.sorted { $0.createdAt > $1.createdAt }
}
static func upsert(articleUrl: String, filename: String, title: String?) {
static func upsert(articleUrl: String, filename: String, title: String?, parentBookmarkUrl: String? = nil) {
var entries = all()
entries.removeAll { $0.articleUrl == articleUrl }
entries.insert(PodcastEntry(articleUrl: articleUrl, filename: filename,
title: title, createdAt: Date()), at: 0)
title: title, createdAt: Date(),
parentBookmarkUrl: parentBookmarkUrl), at: 0)
save(entries)
}
static func find(for bookmarkUrl: String) -> [PodcastEntry] {
all().filter { $0.parentBookmarkUrl == bookmarkUrl || $0.articleUrl == bookmarkUrl }
}
static func remove(articleUrl: String) {
var entries = all()
entries.removeAll { $0.articleUrl == articleUrl }
@@ -52,5 +58,8 @@ enum PodcastIndex {
private static func save(_ entries: [PodcastEntry]) {
guard let data = try? encoder.encode(entries) else { return }
try? data.write(to: indexURL, options: .atomic)
WidgetDataStore.savePodcasts(entries.prefix(10).map {
WidgetPodcast(articleUrl: $0.articleUrl, title: $0.title ?? $0.articleUrl, createdAt: $0.createdAt)
})
}
}