summaryrefslogtreecommitdiff
path: root/BACKLOG.md
blob: 2918517198b734412c7c32bc1cdc1aebb4e39193 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
# Backlog

## Feed health: recency/frequency tracking + dead-feed detection

**Motivation:** migrating 108 feeds from Inoreader surfaced ~19 feeds the
user had manually flagged "dead?" over there — there's currently no way
for this app to tell that on its own. Want automatic detection instead of
relying on manual tagging carried over from another tool.

**What's needed:**
- Track each feed's normal posting cadence (e.g. median interval between
  the last N articles' `publishedAt` — already stored on `ArticleEntity`,
  no new fetch required, just a read-side computation).
- Surface a "stale" indicator on the feed list when a feed has gone
  quiet for meaningfully longer than *its own* historical cadence — not
  a fixed global threshold. A feed that normally posts yearly shouldn't
  be flagged after 3 quiet months; a feed that normally posts daily
  should be flagged after a couple of quiet weeks.
- Treat "feed URL itself is broken" as a distinct, stronger signal from
  "author's just gone quiet": `FeedEntity.lastError` already records
  fetch failures (404s, parked domains, etc.) — a feed with several
  consecutive failures is a different case than a live, fetchable feed
  that simply has no new posts.

**Rough shape (not yet built):**
- Compute per-feed on read (no new table needed at first): take the last
  N `publishedAt` values for a feed, find the median gap, compare against
  time since the most recent post. Flag if the current gap is some
  multiple (e.g. 3x) of the historical median.
- `FeedListScreen`: a small badge next to the feed row when flagged,
  distinguishing "quiet" (posting-cadence signal) from "broken"
  (`lastError` signal) since they call for different user action (wait
  it out vs. go look for a replacement feed).
- Out of scope for now: any automated "find where the author moved"
  logic — that's a manual research task when a feed's actually declared
  dead, not something to build detection for.

## YouTube embeds (done)

**Motivation:** the reader's WebView runs with JavaScript off (feed/extracted
content never needs it, and it keeps articles from running arbitrary
scripts) — so a YouTube iframe embedded in an article used to just show
as a broken/blank box instead of a playable video or thumbnail.

**Built, and further than originally scoped:** `ReaderExtractor` detects a
YouTube iframe/embed during extraction and swaps it for a tap-to-play
thumbnail (an `hq720` still + a "▶ Watch on YouTube" caption). Tapping it
doesn't just hand off to the YouTube app/browser as originally planned —
`ReaderWebView.YouTubePlayerDialog` plays it in-app via a sandboxed
`youtube-nocookie.com` WebView (JS/DOM storage enabled only inside that one
dialog, main-frame navigation locked to YouTube's own domains), so watching
a video doesn't leave the reader.

## Bottom action strip (partially done)

**Done:** swipe-to-next-article dropped entirely (two different attempts at
keeping it from interfering with WebView scrolling both failed to actually
fix the reported jerkiness, and the second broke swipe outright). Replaced
with explicit Previous/Next buttons in a new bottom bar -- no gesture to
disambiguate with scrolling at all now.

**Still open:** the top bar is still crowded (reader-toggle, open-in-browser,
bookmark, Stash, overflow) and top-heavy for one-handed use. Move those
action icons + the overflow menu down into the bottom bar alongside
Previous/Next, and auto-hide both the top and bottom bars together on
scroll (hide on scroll-down, reveal on scroll-up or tap), matching the
common "immersive reading" pattern other reader apps use.

## Scroll jerkiness (still open, root cause unknown)

Reported as "jerky, loses track of my motion." Two theories tried and
ruled out live, not just in code review:
- An orientation-aware Compose gesture detector wrapping the WebView (for
  swipe-to-next-article) -- kept working correctly for paging, but didn't
  fix the reported jerkiness either, so it likely wasn't (only) about
  gesture-arbitration overhead from that detector.
- A passive native OnTouchListener replacing the above -- broke swipe
  outright, reverted, and jerkiness was never re-tested in isolation since
  swipe was still present in that build.

Swipe is now gone entirely (see "Bottom action strip" above), which removes
one whole category of possible interference. Worth a fresh look at whether
scrolling still feels jerky now that nothing above the WebView is doing any
gesture detection at all -- if it still does, the cause is something else
(WebView rendering/compositing itself, the emulator's software rendering
not reflecting real-device feel, etc.), not gesture interception.

**Confirmed on a real device (2026-07):** scrolling measurably improved
once swipe-to-next was dropped. So any future attempt to bring back a
swipe-to-next gesture needs to be judged against that baseline -- it must
not regress scroll feel back to the pre-removal state. Two arbitration
approaches already tried and failed (see above); a fresh approach (e.g.
a much larger/edge-only swipe hit target that never competes with
vertical scroll gestures at all, rather than trying to disambiguate axis
mid-gesture) would need to be prototyped and felt out live, not just
reasoned about in code review.

## Extraction test coverage for WHT / Ars Technica (not yet built)

**Motivation:** both sites' Readability extraction has needed repeat fixes
(lazy-loaded images, doubled captions, paywall-targeted un-hide) and each
fix so far has been diagnosed by hand against a single live article rather
than against a standing set of known-tricky pages. Reported as still
inconsistent after multiple rounds of fixes -- regressions are easy to
reintroduce without something to check against.

**Rough shape (not yet built):** save a handful of representative fixture
HTML pages from each site (lazy-image markup, a paywalled article, one
with duplicate captions) alongside the expected extracted output, and run
them through `ReaderExtractor`'s pipeline in an instrumented test (it needs
a real WebView to run Readability.js, so this can't be a plain JVM unit
test) on every change to the extraction/paywall-unhide logic, instead of
re-fetching a live article by hand each time.

**Also confirmed live (2026-07):** the same Ars Technica article extracted
with its gallery photos included on one run and without them on another,
with no code change in between. Ars's gallery section appears to render
in client-side JS some time after the page's initial HTML document load
(`onPageFinished`, which is when `ReaderExtractor` currently runs
Readability) -- so whether it's finished by the time our script executes
is a real race, not something the `loading="lazy"` fix (also added this
round) addresses. A proper fix likely means waiting for the page to go
network-idle (or a short fixed settle delay) before parsing, which trades
against `TIMEOUT_MS` and adds latency to every single extraction -- worth
deciding deliberately rather than bolting on, so left for this backlog
item rather than this round's quick fixes.

## Bug report tool (reviewed, working as intended)

An audit flagged `ReaderScreen`'s "Report bug" dialog as looking like an
unfinished feature, since it builds a full diagnostic report (title, URL,
feed state, reader-mode state) but only copies it to the clipboard -- no
submission endpoint exists anywhere in the code. Confirmed intentional:
there's no backend to submit to (single-user personal app), and the real
destination is pasting it straight into a message during the normal
hands-on-testing workflow. Not a gap to fill.

## AGP / compileSdk upgrade (not yet built)

**Motivation:** a routine dependency-freshness pass found that essentially
the entire Compose/Activity/Navigation/Lifecycle/Room/WorkManager family's
current releases now require `compileSdk 35`+ and AGP `8.6.0`+ (several
need AGP `9.1.0`). This project is pinned at AGP `8.3.2` / `compileSdk 34`.
Only 4 of the ~14 outdated dependencies found could be safely bumped in
place (DataStore, security-crypto out of alpha, and the two androidx.test
libs) -- everything else was reverted back to its original version after
hitting AAR-metadata errors. This gap will only widen as androidx keeps
releasing.

**Rough shape (not yet built):** bump AGP (and correspondingly Gradle,
since AGP 8.6+ needs a newer Gradle than the current 8.6 wrapper) and
`compileSdk`/`targetSdk`, then re-run the dependency-freshness pass. A
real change, not a version-number edit -- test on a real device
afterward, not just a clean build, since a `compileSdk`/`targetSdk` jump
can change runtime behavior (permission dialogs, back-gesture handling,
etc.), independent of whatever library versions ride along with it.

**Also surfaced by the same pass:** bumping `security-crypto` out of alpha
(1.1.0-alpha06 -> 1.1.0, done) made `EncryptedSharedPreferences`/`MasterKey`
(used in `Settings.kt` for the Stash API key) show up as deprecated. Not
migrated yet -- the replacement API wasn't investigated this round.