- 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>
- 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>
Without a UI delegate, WKWebView hands target="_blank" and window.open()
links to the system (Safari). createWebViewWith now loads them in the
existing webview instead.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Device auto-registers on first launch using hardcoded backend URL
and anon key (MarksAuth.swift). 90-day JWT stored in UserDefaults,
refreshed transparently. No settings fields needed — ClaudeService
is always active and non-optional throughout the app.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- BrowserState: inject scroll-tracking JS after page load, report position
via WKScriptMessageHandler (weak ref to avoid retain cycle)
- BrowserView: thin blue progress bar at top of viewport; saves progress
to UserDefaults on dismiss; restores scroll position on revisit
- BookmarkRow: 2px progress bar below tags for partially-read articles
- BookmarksView: loads ReadingProgress.all() on appear, refreshes when
browser sheet dismisses
- ReadingProgress: static helper for UserDefaults-backed [url: Double] store;
removes entry when article is fully read (≥99%)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Tapping a bookmark now opens an in-app WKWebView instead of bouncing to
Safari. Reader mode injects JS to extract article content and rerender
with clean serif typography and dark-mode support. Bottom toolbar has
back/forward, reader toggle, share, and open-in-Safari escape hatch.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>