diff options
| author | Peter Stone <thepeterstone@gmail.com> | 2026-07-22 08:08:58 +0000 |
|---|---|---|
| committer | Peter Stone <thepeterstone@gmail.com> | 2026-07-22 08:08:58 +0000 |
| commit | d8ce4b3c0f383e844b125d2d3abd618715bb3c89 (patch) | |
| tree | b586ff9b42392f2c44645773c2a2f2aadb9db406 /app/src/main/java/org/terst/feedreader/data/Daos.kt | |
Initial commit: Feeds, an Android RSS reader
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
Diffstat (limited to 'app/src/main/java/org/terst/feedreader/data/Daos.kt')
| -rw-r--r-- | app/src/main/java/org/terst/feedreader/data/Daos.kt | 93 |
1 files changed, 93 insertions, 0 deletions
diff --git a/app/src/main/java/org/terst/feedreader/data/Daos.kt b/app/src/main/java/org/terst/feedreader/data/Daos.kt new file mode 100644 index 0000000..0a41f0c --- /dev/null +++ b/app/src/main/java/org/terst/feedreader/data/Daos.kt @@ -0,0 +1,93 @@ +package org.terst.feedreader.data + +import androidx.room.Dao +import androidx.room.Delete +import androidx.room.Insert +import androidx.room.OnConflictStrategy +import androidx.room.Query +import androidx.room.Update +import kotlinx.coroutines.flow.Flow + +@Dao +interface FeedDao { + @Query("SELECT * FROM feeds ORDER BY title ASC") + fun observeAll(): Flow<List<FeedEntity>> + + @Query("SELECT * FROM feeds ORDER BY title ASC") + suspend fun getAll(): List<FeedEntity> + + @Query("SELECT * FROM feeds WHERE id = :id") + suspend fun getById(id: String): FeedEntity? + + @Insert(onConflict = OnConflictStrategy.REPLACE) + suspend fun upsert(feed: FeedEntity) + + @Update + suspend fun update(feed: FeedEntity) + + @Query("DELETE FROM feeds WHERE id = :id") + suspend fun delete(id: String) +} + +data class FeedUnreadCount(val feedId: String, val count: Int) + +@Dao +interface ArticleDao { + // Unread-first, newest-first -- the default "what's new" view across every feed. + @Query("SELECT * FROM articles WHERE isRead = 0 ORDER BY publishedAt DESC") + fun observeUnread(): Flow<List<ArticleEntity>> + + @Query("SELECT feedId, COUNT(*) as count FROM articles WHERE isRead = 0 AND feedId IS NOT NULL GROUP BY feedId") + fun observeUnreadCounts(): Flow<List<FeedUnreadCount>> + + @Query("SELECT * FROM articles WHERE feedId = :feedId ORDER BY publishedAt DESC") + fun observeByFeed(feedId: String): Flow<List<ArticleEntity>> + + @Query("SELECT * FROM articles WHERE isSaved = 1 ORDER BY createdAt DESC") + fun observeSaved(): Flow<List<ArticleEntity>> + + @Query("SELECT * FROM articles WHERE id = :id") + suspend fun getById(id: String): ArticleEntity? + + // IGNORE, not REPLACE: a re-fetch of a feed re-parses items we already have: + // this keeps the existing row (read state, extracted content, saved state) + // untouched instead of clobbering it with the freshly-parsed feed data. + @Insert(onConflict = OnConflictStrategy.IGNORE) + suspend fun insertNew(articles: List<ArticleEntity>): List<Long> + + @Insert(onConflict = OnConflictStrategy.REPLACE) + suspend fun upsert(article: ArticleEntity) + + @Query("UPDATE articles SET isRead = :read WHERE id = :id") + suspend fun setRead(id: String, read: Boolean) + + @Query("UPDATE articles SET isRead = 1 WHERE feedId = :feedId") + suspend fun markAllReadForFeed(feedId: String) + + @Query("UPDATE articles SET extractedContent = :content WHERE id = :id") + suspend fun setExtractedContent(id: String, content: String) + + @Query("UPDATE articles SET isSaved = :saved WHERE id = :id") + suspend fun setSaved(id: String, saved: Boolean) + + @Query("UPDATE articles SET stashArtifactId = :artifactId WHERE id = :id") + suspend fun setStashArtifactId(id: String, artifactId: String) + + @Delete + suspend fun delete(article: ArticleEntity) +} + +@Dao +interface FilterRuleDao { + @Query("SELECT * FROM filter_rules ORDER BY createdAt DESC") + fun observeAll(): Flow<List<FilterRuleEntity>> + + @Query("SELECT * FROM filter_rules") + suspend fun getAll(): List<FilterRuleEntity> + + @Insert + suspend fun insert(rule: FilterRuleEntity): Long + + @Query("DELETE FROM filter_rules WHERE id = :id") + suspend fun delete(id: Long) +} |
