Align RSS styling with Tasks plugin conventions
Details
Article list items now use the same styling patterns as the Tasks
plugin: item-card class with ThemeRadiusMd corner radius, 10,8 padding,
and selected-state styles (ThemeHoverBrush background + subtle shadow)
matching the ListBox.sidebar ListBoxItem:selected pattern.
Category tags in both the list items and detail view now use
ThemeHoverBrush background with ThemeSecondaryBrush foreground and
ThemeRadiusXs corners — identical to how task tags are rendered.
Replaced all hardcoded CornerRadius="12" and CornerRadius="6" values
with ThemeRadiusMd dynamic resource for consistency across sidebar
feed buttons, empty state, summary box, and reader error panel.
Fix summary dedup not catching truncated summaries
Details
HasDistinctSummary was comparing the full summary (including trailing
"...") against the content via StartsWith. Since the content doesn't
contain "..." at the truncation point, the match always failed and
the redundant preamble kept showing.
Now strips trailing "..." from the summary before the prefix comparison.
Add article category tags, tag filtering, and summary dedup
Details
Parse <category> elements from RSS/Atom feeds into a new Categories
field on RssArticle. Both FetchFeedAsync and RefreshFeedAsync now
extract category terms via SyndicationItem.Categories.
Article detail view shows category tags as styled pills below the
author/date line. Article list items also display compact tag labels.
Tag filter dropdown in the toolbar lets users filter articles by any
tag present in the current article set. Clear button resets the filter.
Summary preamble box is now hidden when the summary text is just a
prefix repetition of the article content — detected via normalized
plain-text comparison in HasDistinctSummary on RssArticle. This
prevents the redundant preamble block seen with feeds like the
PrivStack changelog where summary == content.
Version bump 1.9.6 → 1.10.0
Fix RSS feed fetch hanging due to IPv6 connect failure
Details
Root cause: .NET's HttpClient resolves DNS and tries connecting to the
first address returned (typically IPv6 AAAA record). When the network
cannot route to the IPv6 address, the connect attempt blocks for the
full request timeout (30-60s) before giving up — unlike curl which uses
Happy Eyeballs (RFC 8305) to try both protocols in parallel.
Confirmed by testing: IPv6 connect to privstack.io hangs indefinitely
while IPv4 connects in ~45ms. This affects any host that publishes
AAAA records not routable on the user's network.
Fix: replace the default SocketsHttpHandler with a custom ConnectCallback
that implements Happy Eyeballs — resolves all addresses (IPv4 + IPv6),
initiates connections to all in parallel, uses whichever succeeds first,
and cancels the rest. This brings feed fetch from timeout (30-60s) down
to ~350ms for affected hosts.
Also adds gzip/deflate decompression support to the handler.
Fix RSS feed fetch timeout and add progressive streaming
Details
- Use HttpCompletionOption.ResponseHeadersRead in FetchFeedAsync and
RefreshFeedAsync so the response streams immediately after headers
arrive, enabling progressive XML parsing instead of buffering the
entire body first
- Add OperationCanceledException catch clauses that distinguish between
HttpClient timeout (user-friendly "server may be slow or unreachable"
message) and explicit user cancellation
- Increase default HttpClient timeout from 30s to 60s since RSS feeds
from smaller servers can be slow, and streaming now provides visual
feedback during the wait
- Add CancellationTokenSource to AddFeedAsync in RssViewModel so users
can cancel a slow feed fetch via CancelAddFeedCommand
Get notified about new releases