Skip to content

Add global Hide Read Articles preference with per-feed overrides#5342

Open
brzzdev wants to merge 4 commits into
Ranchero-Software:mainfrom
brzzdev:feat/hide-read-articles
Open

Add global Hide Read Articles preference with per-feed overrides#5342
brzzdev wants to merge 4 commits into
Ranchero-Software:mainfrom
brzzdev:feat/hide-read-articles

Conversation

@brzzdev

@brzzdev brzzdev commented Jun 26, 2026

Copy link
Copy Markdown

What changed

Adds a global Hide Read Articles preference that defaults every feed to
showing only unread articles, while preserving per-feed overrides. A new
Hide Read Articles Settings… entry on each account opens a Global
Overrides
screen that lists every feed (favicon + name) with a switch; a
switch that is on means that feed keeps its own read-article visibility
instead of following the global preference, and Clear All resets them in
one step. Toggling hide-read in a timeline still sets that feed's own override
implicitly — it never changes the global preference. Works on macOS and iOS.

Screenshots

macOS iOS
macOS iOS

Why

Implements a long-requested global toggle (forum discussion + existing
repo issue). The per-account screen of switches is the minimal opt-out UI the
maintainers agreed on in the discussion, rather than scattering per-feed
controls through the app.

Deviations from the agreed design

This follows the design agreed in the discussion, with two deliberate
departures worth your eye:

  • Screen title. The thread specified "Override Global Hide Read Articles
    Setting"
    ; I shortened it to "Global Overrides" — the full string
    overflows the iOS navigation bar and reads as redundant once you're already
    inside the screen. Trivial to revert if you'd rather keep the original.
  • macOS state model (beyond the UI-only discussion). To make the new
    screen and the timeline agree on macOS, per-feed read-filter state now lives
    in feedReadFilterOverrides rather than window-state restoration — which
    also fixes a latent loss of pre-existing per-feed settings. Details below.

Things to look out for

  • macOS read-filter state model (most nuanced area). Per-feed hide-read
    was previously stored only in window-state restoration. This change makes
    feedReadFilterOverrides (UserDefaults) authoritative for feeds: legacy
    window-state feed entries are migrated into overrides on restore
    (no-clobber), and feeds are no longer persisted to window state. Folders and
    smart feeds remain window-state-backed. See aba1d896b.
  • One-time migrations. iOS migrates the legacy feedsHidingReadArticles
    UserDefaults dictionary; macOS migrates legacy window-state feed entries.
    Both run once and never overwrite an existing override.
  • Local, not synced. Overrides live in UserDefaults per device — consistent
    with hide-read having always been a local UI preference.
  • Adopts the SwiftUI favicon wrapper (IconImageView) introduced in ✨Add Account-level Notification Management on iOS #5095.

Related

Closes #3030

Test plan

  • Builds cleanly on macOS and iOS
  • Manually verified on both platforms: global toggle; per-feed override
    semantics; timeline toggle sets a per-feed override only; Clear All;
    persistence & state restoration; multi-account isolation
  • iOS legacy migration (feedsHidingReadArticles → overrides) verified
  • macOS legacy migration (window-state → overrides) verified, including
    that previously hidden feeds survive a later override change

Note on tooling

Per the contributing guidelines: this PR was developed with the help of Claude Code. All changes were orchestrated and reviewed by me and manually tested on macOS and iOS.

@brzzdev brzzdev requested a review from brentsimmons as a code owner June 26, 2026 23:05
@brzzdev brzzdev force-pushed the feat/hide-read-articles branch 2 times, most recently from e986bd2 to 6f00356 Compare July 1, 2026 15:39
brzzdev added 4 commits July 3, 2026 13:55
- Encapsulate override toggle logic in AppDefaults helpers so both
  inspector view controllers wire the view with one-line closures.
- Fix clearAll in FeedReadFilterOverridesView persisting N times by
  routing setOverride through the Toggle binding setter instead of
  .onChange, so programmatic resets no longer fire per-feed writes.
- Prune an account's overrides on Mac when it is deleted, matching
  the cleanup iOS already performs on save.
- Make the legacy migration path a static factory
  (FeedReadFilterOverrides.migrating(legacyFeedsHiding:)) to keep it
  off the type's general init surface.
- Drop unused override wrapper methods on HidingReadArticlesState
  and trim narrative comments.
Adopt the cross-platform IconImageView favicon wrapper from Ranchero-Software#5095: each feed
row shows its icon, refreshed on feedIconDidBecomeAvailable. Render rows with
switches on both platforms (per the agreed design), title the screen
"Global Overrides", and make the entry point consistent across platforms
("Hide Read Articles Settings…" on Mac, matching iOS).

Fix macOS layout surfaced during manual testing: size the entry button to its
label, and render the help text below the list because macOS clips List
section footers to a single line.
…d filtering

On macOS, per-feed hide-read state was double-backed by window-state
restoration (readFilterEnabledTable) and the new feedReadFilterOverrides, with
window state shadowing overrides. Legacy per-feed settings were therefore
invisible to the Global Overrides screen, and were silently dropped the first
time syncReadFilterTableFromDefaults ran after any override change.

- Migrate legacy window-state feed entries into feedReadFilterOverrides on
  restore (no-clobber), so existing settings surface in the overrides screen
  and survive subsequent override changes.
- Stop persisting feed entries to window state; folders and smart feeds remain
  window-state-backed.
- Seed the shown feed's override into the in-memory fetch cache when a feed
  timeline opens, since feeds no longer come from window state.
@brzzdev brzzdev force-pushed the feat/hide-read-articles branch from 6f00356 to 4ff1c16 Compare July 3, 2026 12:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Hide read articles should be available as a global option

1 participant