<feed xmlns='http://www.w3.org/2005/Atom'>
<title>feedreader.git/app/src/main/java/org/terst/feedreader/ui/ImageZoomLinks.kt, branch master</title>
<subtitle>FeeDreader — personal Android RSS reader
</subtitle>
<id>https://git.terst.org/feedreader.git/atom?h=master</id>
<link rel='self' href='https://git.terst.org/feedreader.git/atom?h=master'/>
<link rel='alternate' type='text/html' href='https://git.terst.org/feedreader.git/'/>
<updated>2026-11-13T08:44:07+00:00</updated>
<entry>
<title>Close the class: a caller can no longer forget where the article lives</title>
<updated>2026-11-13T08:44:07+00:00</updated>
<author>
<name>Peter Stone</name>
<email>thepeterstone@gmail.com</email>
</author>
<published>2026-11-13T08:44:07+00:00</published>
<link rel='alternate' type='text/html' href='https://git.terst.org/feedreader.git/commit/?id=17643797517693664e6d4f5e5911b9855d6c484b'/>
<id>urn:sha1:17643797517693664e6d4f5e5911b9855d6c484b</id>
<content type='text'>
The fix before this made site-relative images zoomable by resolving them
against the article's own address. It left the parameter optional, which leaves
the bug one forgetful call site away from coming back -- and coming back
silently, as every image on a site-relative feed quietly refusing to zoom,
which is exactly how it went unnoticed on Ftrain in the first place.

It has no default now. Null is still a legitimate answer, because an article
with no address genuinely cannot resolve anything, but it has to be given on
purpose. A future reader surface that omits it fails to compile rather than
shipping the old behaviour.

Nothing about what the app does changed: the same 157 tests pass, and the six
test call sites that relied on the default now say baseUrl = null, which is
what they always meant.

Co-Authored-By: Claude Opus 5 &lt;noreply@anthropic.com&gt;
Claude-Session: https://claude.ai/code/session_018AwnALZL6bD4VBtATDVv3B
</content>
</entry>
<entry>
<title>Make an image zoomable even when the feed didn't spell out where it lives</title>
<updated>2026-11-13T08:40:44+00:00</updated>
<author>
<name>Peter Stone</name>
<email>thepeterstone@gmail.com</email>
</author>
<published>2026-11-13T08:40:44+00:00</published>
<link rel='alternate' type='text/html' href='https://git.terst.org/feedreader.git/commit/?id=fc25307e7f258b1043e1367a44a8800d03085c66'/>
<id>urn:sha1:fc25307e7f258b1043e1367a44a8800d03085c66</id>
<content type='text'>
Tapping an image in a Ftrain article did nothing. The zoom affordance was
there, and the rendering path was the ordinary one -- the feed's own HTML, with
reader mode off -- but a tap went nowhere at all.

Tap detection works by wrapping every article image in a link to a scheme
nothing can navigate to, which the WebView then hands to
shouldOverrideUrlLoading. That href has to carry the complete image URL on its
own, so an image whose src was relative got no wrapper and no tap: better an
image that can't be zoomed, the reasoning went, than a link that goes nowhere.
Ftrain's &lt;content:encoded&gt; is entirely site-relative -- every image in it is
src="/art/uploads/..." -- so not one of them was zoomable.

That reasoning had an unexamined premise. The page itself resolves those srcs
perfectly well, against the base URL loadReaderHtml already hands
loadDataWithBaseURL: the article's own link. Resolving them the same way at
HTML-assembly time produces exactly the URL the WebView went and fetched, so
the wrapper can be built after all. Both reader surfaces now pass that base URL
down to the zoom pass. Where there genuinely is no base URL to resolve
against -- nothing else in the app loads reader HTML without one today -- the
old behavior stands and the image stays un-zoomable rather than acquiring a
dead link, and a data: or javascript: src is still refused however it was
reached, since the viewer could never open one.

This is why the report could only have come from a feed with reader mode off.
Reader mode never hits it: Readability rewrites every src to an absolute URL
before the extracted HTML reaches us, which is also why the same images zoom
fine the moment the feed's reader toggle is on.

TDD: site-relative and path-relative resolution, and the whole trip through
wrapReaderHtml, were written first against the unused parameter and went red on
assertion mismatches (3 of 38 in ImageZoomTest), green on the resolution
itself. The data:-src case was written at the same time and passed immediately
-- it pins existing behavior against the new code path rather than having
driven it.

Verified on the emulator against the reported article itself, subscribed live
from ftrain.com/feed.xml with reader mode off: on the previous build, a tap on
the header image left the screen byte-identical; on this one the same tap at
the same point opens the full-screen viewer.

Co-Authored-By: Claude Opus 5 &lt;noreply@anthropic.com&gt;
Claude-Session: https://claude.ai/code/session_018AwnALZL6bD4VBtATDVv3B
</content>
</entry>
<entry>
<title>Reflow reader text live while pinching, and let a zoomed image pan</title>
<updated>2026-09-29T07:12:48+00:00</updated>
<author>
<name>Peter Stone</name>
<email>thepeterstone@gmail.com</email>
</author>
<published>2026-09-29T07:12:48+00:00</published>
<link rel='alternate' type='text/html' href='https://git.terst.org/feedreader.git/commit/?id=a492e2def3dabe5e8de5ef4486b92859850503db'/>
<id>urn:sha1:a492e2def3dabe5e8de5ef4486b92859850503db</id>
<content type='text'>
Pinching in the reader used to scale the whole WebView like a photo and snap
back to the real font size on release. It now drives WebSettings.textZoom as
the fingers move, so the text itself resizes and reflows during the gesture
with nothing to snap back from; images and margins stay put. The reload at the
new saved size is what returns textZoom to 100%, so the two never overlap --
and loading reader HTML now goes through ReaderWebView.loadReaderHtml, which
does both together, so a future load site can't forget the reset.

Reader view for a tapped link now honors the saved font size and the same
pinch gesture, instead of always rendering at the 18px default.

A zoomed image can be panned again. The viewer computed its pan bounds from
values captured when the dialog first composed -- an empty viewport around a
not-yet-decoded image -- because a pointerInput(Unit) block keeps the lambda it
was created with. Those bounds allowed exactly one offset, 0, so zooming worked
and dragging did nothing. The whole pinch/pan step is now one pure function the
gesture callback calls with values it reads fresh each time.
</content>
</entry>
</feed>
