APIClient:
- markAllRead(storyIds💊) — POST /me/read/bulk with device ID, timestamp,
source label, and pill name so backend can record context
Models:
- PaginatedStories gains unreadCount, readSuppressedCount, lastReadSyncAt,
activePill — backend now returns these so the UI can report honest state
SignalFeedView:
- Header "…" menu replaces the standalone settings button; menu contains
"Mark all as read" (disabled while pending or when nothing is unread) and
a Settings item
- markAllRead() captures all visible unread IDs, optimistically inserts
ReadStory for each, shows toast ("Marked N stories as read"), then fires
the bulk API; on failure deletes the optimistic ReadStory records and
shows an honest error toast ("Sync failed. Stories may reappear until retry.")
- Toast auto-dismisses after 3.5s, appears at the bottom of the ZStack
with a slide-up + opacity animation
Cross-pill suppression was already in place — backend applies
unread_story_condition() to every /stories request regardless of tags,
so stories marked read in All disappear from Tech, Sport, etc. on the
next pill fetch.
Co-Authored-By: Kutesir <tqwyy79vzn@privaterelay.appleid.com>