summaryrefslogtreecommitdiff
path: root/app/src/main/java/org
AgeCommit message (Collapse)Author
2026-07-22Un-hide CSS-gated content before running ReadabilityPeter Stone
Some "soft" paywalls (West Hawaii Today's included) deliver the full article in the initial HTML response to every visitor, then hide it with CSS (inline or via stylesheet) pending a client-side subscription check -- the content itself isn't withheld by the server, only its visibility. Readability has a built-in heuristic that skips anything hidden this way, treating it as boilerplate, which is exactly what was discarding real, already-delivered article text and leaving only the visible teaser/ subscribe prompt. Before parsing, walk the live document (getComputedStyle needs an attached node) and force display/visibility back on for anything hidden via display:none or visibility:hidden, then clone and hand that off to Readability as before. Verified live against a real West Hawaii Today article: extractedContent went from 588 characters (the RSS teaser) to 3458 (the full body).
2026-07-22Fix scroll regression and feed-setting reset on re-importPeter Stone
- ReaderScreen: the direction-ratio gesture rewrite (using a generic, non-oriented detectDragGestures to compute a custom dx/dy ratio) broke scrolling entirely -- reported live as "the article view doesn't scroll at all anymore." Root cause: detectDragGestures' touch-slop detection is isotropic (claims the first bit of movement in ANY direction before it knows which way the gesture is going), unlike detectHorizontalDragGestures which is orientation-aware and simply never engages for a vertical- dominant drag. Reverted to detectHorizontalDragGestures, keeping the distance-based (not edge-anchored) commit threshold from the previous fix. Verified live: a long article now scrolls properly on a diagonal swipe, and a deliberate horizontal swipe still changes pages. - AddFeedScreen: both the OPML import and single-URL add built a bare FeedEntity(id, title, siteUrl) and upserted it (REPLACE) even when a feed with that id already existed -- silently wiping readerModeDisabled (and etag/lastModified/lastError) back to defaults on every re-import or re-add. This is exactly what made a feed's reader-mode toggle appear not to persist. Now preserves the existing row via .copy() when one exists. Verified live: set kottke.org's readerModeDisabled=1, re-imported the same OPML file (107 feeds), and confirmed the flag was still 1 afterward.
2026-07-22Remove mark-as-read-on-scrollPeter Stone
Explicitly asked to revert: scrolling the article list shouldn't mark anything read on its own -- only opening an article (or the existing manual actions) should. Removed the LazyListState/snapshotFlow tracking in ArticleListScreen and the now-unused ArticleDao.markReadBatch. Verified: unread count in the DB is unchanged after scrolling through the list (1332 before and after).
2026-07-22Fix accidental page-swipe while scrolling; bring linked-article reader to parityPeter Stone
- ReaderScreen: HorizontalPager's full-surface drag detection was treating ordinary vertical scrolling inside the embedded WebView (a native View, which doesn't arbitrate with Compose's gesture system the way a pure-Compose scrollable child would) as an attempted horizontal page-turn on anything less than a perfectly vertical swipe -- i.e. most real thumb scrolling. Tried gating it to edge-zone-only drags first, but that collides with Android's own edge-swipe-back gesture on gesture-nav devices (reproduced live: an edge swipe triggered system back, not the pager). Landed on disabling the Pager's built-in gesture and driving it from a custom detector that works anywhere on screen but only commits to a page turn once a drag is clearly horizontal-dominant (>2x the vertical movement) -- ordinary scrolling, even sloppy/diagonal, is left completely unconsumed for the WebView. Verified live: a deliberately diagonal mid-screen scroll now stays on the same article; a decisive horizontal swipe still changes pages. - LinkReaderScreen: was missing the bookmark/Stash/reader-toggle/menu actions entirely -- reported after tapping a link left "all my icons... gone." Brought to parity with the main article reader: save locally and save to Stash now lazily create a standalone ArticleEntity (feedId=null, id = hash of the URL, same scheme ShareReceiverActivity uses) on first use; reader-mode toggle falls back to the live page (JS on) instead of always forcing extraction; same login/find-another-source menu. Verified live: all 5 icons present once extraction finishes, bookmarking a linked article correctly creates a standalone DB row.
2026-07-22Add site login and alternate-source search for paywalled articlesPeter Stone
Deliberately not a paywall-bypass mechanism -- that space (archive.today-style proxies, "Bypass Paywalls" extensions) is legally grey, adversarial toward publishers, and constantly breaking. Instead: - BrowserScreen: a real interactive mini-browser (JS + DOM storage on, ordinary navigation, no Readability interception) for the two cases where the user needs to actually USE a page rather than read it. Reached from a new overflow menu on the article reader: - "Log in to this site" opens the article's own URL there so the user can sign into a site they already subscribe to. Needs no extra plumbing: Android's CookieManager is one process-wide store shared by every WebView in the app, so a session cookie set here is picked up automatically by the reader's (JS-off) extraction WebView on the next visit to that domain -- same as a normal browser remembering you're signed in. - "Find another source" runs a web search on the article's title in the same browser, so the user can pick a different, non-paywalled outlet covering the same story themselves -- plain search/discovery, not circumvention. Verified live: search opened a real, interactive Google results page with working title-bar sync; back navigation (via BackHandler, goBack() when the WebView has history, else pop the screen) returned cleanly to the article.
2026-07-22Split save/Stash actions, follow links in-app via reader pipeline, tune ↵Peter Stone
scroll, fix title entities - ReaderScreen: bookmark icon is now a purely local save (just flips isSaved, no network) -- Stash archiving is a separate explicit action (new cloud icon), since it's a heavier networked action the user should trigger on purpose rather than have bundled into "save." Verified via direct DB queries and (once I stopped misreading small screenshots) the icon updates immediately in-session for both actions. - New ReaderWebView.kt: shared WebView factory for the dark reader palette and link handling, used by both ReaderScreen and the new LinkReaderScreen. Links tapped inside an article's WebView now open in a lightweight in-app reader (extracted via the same Readability pipeline, no DB persistence) instead of falling through to the system browser -- recursive, so a chain of links stays in-app. Verified live: tapping a link mid-article navigated to a real extracted page with a working back stack. - WebView scroll tuning: overscroll glow and scrollbars off, on both the article reader and the new link reader -- aimed at the reported "still a little choppy" scrolling on top of the previous reload-on-recompose fix. - FeedParser: some feeds (kottke.org among them) double-encode titles -- the XML parser resolves outer XML escaping, but leftover HTML entities like "“" were showing up literally in the title text. Titles are now run through a second HTML-entity decode pass. Verified: a kottke title that previously showed a literal “ now renders the actual curly quote. All changes verified live on the emulator against the real 107-feed dataset.
2026-07-22Smooth scrolling, dark reader, mark-read-on-scroll, feed names, per-feed ↵Peter Stone
reader-mode opt-out - ReaderScreen: AndroidView's update() was reloading the WebView's HTML on every recomposition (e.g. isSaving flipping mid-read), resetting scroll position -- this is what made scrolling feel unsmooth. Now only reloads when the content string actually changes. - ReaderScreen: reader content now uses a hardcoded dark palette instead of browser-default white, matching the app's always-dark theme. - ArticleListScreen: mark-as-read-on-scroll -- once an article has scrolled fully above the viewport it's marked read, the standard feed-reader behavior, via a new batched ArticleDao.markReadBatch(). Verified against the on-device DB (scrolled-past articles flipped to isRead=1, the still-visible one stayed unread). - ArticleListItem/queries: LEFT JOIN feeds for a feedTitle column, shown per row in the Unread/Saved aggregated views and as a reader subtitle; the per-feed article list's top bar now shows the real feed title instead of a generic "Articles". - FeedEntity.readerModeDisabled (schema v3, migration 2->3): per-feed opt-out of the Readability fallback/toggle, toggled from a new icon in FeedListScreen. Added for kottke.org specifically -- confirmed its thin linkblog posts were making Readability extract the page footer instead of the actual post; disabling reader mode for that feed now shows its own (short but correct) content instead. All verified live on the emulator against the real 107-feed dataset.
2026-07-22Fix crash loop: WebView touched off main thread during extraction cancellationPeter Stone
Root-caused via emulator stress test (rapid swiping through many articles): withTimeoutOrNull's cancellation, and LaunchedEffect disposal when a page is swiped away, both invoke invokeOnCancellation on kotlinx.coroutines.DefaultExecutor rather than the calling coroutine's Main dispatcher. The handler called webView.stopLoading()/destroy() directly, crashing with "A WebView method was called on thread ..." on essentially every session once enough thin-content articles were swiped past mid-extraction -- the reported crash loop. Now hops back to the main looper before touching the WebView, and guards against a double destroy() race between the JS-callback and cancellation paths. Also fixed a real (non-crashing) leak: the visible reader WebView in ReaderScreen was never destroy()-ed when its page left the pager, via AndroidView's onRelease. Reproduced pre-fix in ~80 rapid swipes on an emulator; post-fix, 320+ swipes with real 107-feed data ran clean with stable native heap.
2026-07-22Fix Unread/startup crash; add reader-mode toggle and swipe navigationPeter Stone
- Root cause of the reported crashes: observeUnread/observeByFeed/ observeSaved used SELECT *, pulling feedContentHtml/extractedContent (potentially large per-article blobs) just to render a list row. With 107 feeds worth of real articles this blows past Android's CursorWindow/memory limits, scaling with item count -- and since Unread is now the landing screen, it crashed at startup too. Added an ArticleListItem projection excluding the heavy content columns; list queries now only select what a row actually renders. - FilterRuleEngine now takes a small Titled interface (title/feedId) instead of the full entity, so it works with both ArticleEntity and the new lighter projection. - Reader-mode toggle: a button in the reader to manually switch between feed-provided content and Readability-extracted full text, matching Inoreader's full-text-view toggle (previously only an automatic fallback when feed content was thin). - Swipe between articles: ReaderScreen now wraps a HorizontalPager over a snapshot of the current list's article-id order, so swiping moves to the next/previous article. Snapshotted rather than live, since marking an article read would otherwise drop it from the live Unread query mid-swipe and shift every later page underneath the user. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EZ7ikw2ukGJFTHE3bJS7zL
2026-07-22First round of testing feedback: images, unread landing, dark, deletePeter Stone
- Fix OPML import status message reporting the raw pre-dedup count (144) instead of the actual unique feed count after Room's upsert collapses duplicates (108) -- cosmetic bug, the DB was already correct. - Article thumbnails: extract media:thumbnail/enclosure or the first <img> in feed content, show via Coil in the article list. - App now lands on Unread instead of the feed list; a top-bar icon gets from there to the feed list (forward nav, not back-stack pop, since Unread is now the root). - Dark color scheme by default. - Delete-feed action (with confirmation) on each feed row -- was entirely missing. Deletes its non-saved articles too, so they don't linger as orphaned rows in the cross-feed Unread view; saved articles are kept regardless. - Room migration 1->2 for the new imageUrl column (real migration, not destructive fallback, since there's now real on-device subscription data from testing). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EZ7ikw2ukGJFTHE3bJS7zL
2026-07-22Initial commit: Feeds, an Android RSS readerPeter Stone
Feed subscriptions (RSS 2.0 + Atom, hand-rolled parser), OPML import/export, WorkManager periodic fetch with conditional GET, Room-backed local storage (feeds/articles/filter rules), keyword mute/highlight filtering. Reader mode: on-device extraction via Mozilla's Readability.js (vendored from github.com/mozilla/readability, pinned to release 0.6.0) run in a hidden WebView, for feed articles whose provided content is too thin to be the real article body. Save: explicit action (from a feed article, or the Android share-sheet target for any URL) archives to Stash via POST /artifacts?sync=true, while a local on-device copy (Readability-extracted) is always kept so saved articles read offline regardless of Stash's reachability. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EZ7ikw2ukGJFTHE3bJS7zL