From 34b663c6e75a2c360de154418dafb8f616b546a1 Mon Sep 17 00:00:00 2001 From: Peter Stone Date: Wed, 22 Jul 2026 20:37:41 +0000 Subject: Fix extraction regression on kottke; add Older view, mark-read-from-here - ReaderExtractor: the un-hide-before-extracting fix (for soft paywalls like West Hawaii Today) was unconditional -- it also un-hid normal, legitimately-collapsed chrome (kottke's footer/membership notice), which Readability then folded into the result alongside the real article. Reported live with a screenshot showing the extracted content wrapped in site footer boilerplate. Now tries the normal (hidden-respecting) pass first and only falls back to the un-hide pass if that came back thin (<500 chars), keeping whichever pass actually found more text. Verified live: the same kottke article now stays clean and stable (no delayed switch to the footer version). - New Unread/Older split: the default Unread view is now clamped to the last 72 hours (RECENT_WINDOW_MS); the rest of the unread backlog moved to a new "Older" view (new FeedListScreen row, ArticleDao.observeUnread now takes a cutoff, observeOlderUnread/observeUnreadCount/ observeOlderUnreadCount added). Undated articles are kept in the main Unread view rather than silently dropped from both. Verified live: 150 recent / 1172 older, summing to the prior combined total. - "Mark read from here": long-press an article row to mark it and everything older in that same filtered list as read in one batch (re-added ArticleDao.markReadBatch, this time as an explicit, confirmed action -- not the implicit on-scroll version that was reverted earlier). Verified live: confirmed a 147-article batch: the tapped article and older were marked read, newer ones above it were not. - BACKLOG.md: added a YouTube-embeds note (JS is off in the reader WebView, so embeds currently show broken -- rough shape is a tap-to-play thumbnail rather than turning JS on for third-party content). --- .../main/java/org/terst/feedreader/data/Daos.kt | 37 +++++++++++++++++++--- 1 file changed, 33 insertions(+), 4 deletions(-) (limited to 'app/src/main/java/org/terst/feedreader/data') diff --git a/app/src/main/java/org/terst/feedreader/data/Daos.kt b/app/src/main/java/org/terst/feedreader/data/Daos.kt index d089885..22f1d22 100644 --- a/app/src/main/java/org/terst/feedreader/data/Daos.kt +++ b/app/src/main/java/org/terst/feedreader/data/Daos.kt @@ -61,10 +61,34 @@ private const val ARTICLE_LIST_FROM = "articles LEFT JOIN feeds ON articles.feed @Dao interface ArticleDao { - // Unread-first, newest-first -- the default "what's new" view across every feed. - @Query("SELECT $ARTICLE_LIST_COLUMNS FROM $ARTICLE_LIST_FROM WHERE articles.isRead = 0 ORDER BY articles.publishedAt DESC") - fun observeUnread(): Flow> - + // The default "what's new" view -- clamped to the last RECENT_WINDOW_MS (see + // MainActivity) so a backlog of hundreds of older unread items doesn't bury + // what's actually new. Undated articles (publishedAt failed to parse) are kept + // here rather than silently dropped from both views. + @Query( + "SELECT $ARTICLE_LIST_COLUMNS FROM $ARTICLE_LIST_FROM " + + "WHERE articles.isRead = 0 AND (articles.publishedAt IS NULL OR articles.publishedAt >= :cutoff) " + + "ORDER BY articles.publishedAt DESC" + ) + fun observeUnread(cutoff: Long): Flow> + + // The rest of the unread backlog, older than the cutoff -- its own view rather + // than mixed into the main one. + @Query( + "SELECT $ARTICLE_LIST_COLUMNS FROM $ARTICLE_LIST_FROM " + + "WHERE articles.isRead = 0 AND articles.publishedAt IS NOT NULL AND articles.publishedAt < :cutoff " + + "ORDER BY articles.publishedAt DESC" + ) + fun observeOlderUnread(cutoff: Long): Flow> + + @Query("SELECT COUNT(*) FROM articles WHERE isRead = 0 AND (publishedAt IS NULL OR publishedAt >= :cutoff)") + fun observeUnreadCount(cutoff: Long): Flow + + @Query("SELECT COUNT(*) FROM articles WHERE isRead = 0 AND publishedAt IS NOT NULL AND publishedAt < :cutoff") + fun observeOlderUnreadCount(cutoff: Long): Flow + + // Per-feed unread badge counts in the feed list -- deliberately NOT time-clamped, + // so a feed's number reflects its whole backlog regardless of the Unread/Older split. @Query("SELECT feedId, COUNT(*) as count FROM articles WHERE isRead = 0 AND feedId IS NOT NULL GROUP BY feedId") fun observeUnreadCounts(): Flow> @@ -89,6 +113,11 @@ interface ArticleDao { @Query("UPDATE articles SET isRead = :read WHERE id = :id") suspend fun setRead(id: String, read: Boolean) + // Explicit bulk action ("mark read from here") -- batched per confirmed tap, + // never called implicitly (e.g. by scrolling). + @Query("UPDATE articles SET isRead = 1 WHERE id IN (:ids)") + suspend fun markReadBatch(ids: List) + @Query("UPDATE articles SET isRead = 1 WHERE feedId = :feedId") suspend fun markAllReadForFeed(feedId: String) -- cgit v1.2.3