diff options
Diffstat (limited to 'app/src/main/java/org/terst/feedreader/data')
3 files changed, 43 insertions, 10 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 index 2240ff4..f80cce3 100644 --- a/app/src/main/java/org/terst/feedreader/data/Daos.kt +++ b/app/src/main/java/org/terst/feedreader/data/Daos.kt @@ -31,20 +31,43 @@ interface FeedDao { data class FeedUnreadCount(val feedId: String, val count: Int) +// A projection excluding feedContentHtml/extractedContent -- the potentially +// large per-article content blobs that list views (row title/date/thumbnail) +// never need. Selecting them for every row of a big result set is what was +// crashing the Unread view once real feed volume (107 feeds worth of +// articles) hit it: Android's per-row/CursorWindow limits are sized for +// "many small rows," not "many rows each carrying a full article's HTML." +data class ArticleListItem( + val id: String, + override val feedId: String?, + override val title: String, + val link: String, + val author: String?, + val publishedAt: Long?, + val imageUrl: String?, + val isRead: Boolean, + val isSaved: Boolean, + val stashArtifactId: String?, + val createdAt: Long +) : Titled + +private const val ARTICLE_LIST_COLUMNS = + "id, feedId, title, link, author, publishedAt, imageUrl, isRead, isSaved, stashArtifactId, createdAt" + @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 $ARTICLE_LIST_COLUMNS FROM articles WHERE isRead = 0 ORDER BY publishedAt DESC") + fun observeUnread(): Flow<List<ArticleListItem>> @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 $ARTICLE_LIST_COLUMNS FROM articles WHERE feedId = :feedId ORDER BY publishedAt DESC") + fun observeByFeed(feedId: String): Flow<List<ArticleListItem>> - @Query("SELECT * FROM articles WHERE isSaved = 1 ORDER BY createdAt DESC") - fun observeSaved(): Flow<List<ArticleEntity>> + @Query("SELECT $ARTICLE_LIST_COLUMNS FROM articles WHERE isSaved = 1 ORDER BY createdAt DESC") + fun observeSaved(): Flow<List<ArticleListItem>> @Query("SELECT * FROM articles WHERE id = :id") suspend fun getById(id: String): ArticleEntity? diff --git a/app/src/main/java/org/terst/feedreader/data/Entities.kt b/app/src/main/java/org/terst/feedreader/data/Entities.kt index 190340c..29d4fe4 100644 --- a/app/src/main/java/org/terst/feedreader/data/Entities.kt +++ b/app/src/main/java/org/terst/feedreader/data/Entities.kt @@ -18,8 +18,8 @@ data class FeedEntity( @Entity(tableName = "articles") data class ArticleEntity( @PrimaryKey val id: String, // guid if the feed provides one, else a hash of the link - @ColumnInfo(index = true) val feedId: String?, // null for a standalone article saved via the share-sheet target, not tied to any feed - val title: String, + @ColumnInfo(index = true) override val feedId: String?, // null for a standalone article saved via the share-sheet target, not tied to any feed + override val title: String, val link: String, val author: String? = null, val publishedAt: Long? = null, @@ -30,7 +30,7 @@ data class ArticleEntity( val isSaved: Boolean = false, // explicitly kept (independent of read state) -- triggers a Stash save val stashArtifactId: String? = null, // set once successfully archived to Stash; null means not yet saved or save failed val createdAt: Long -) +) : Titled enum class FilterAction { MUTE, HIGHLIGHT } diff --git a/app/src/main/java/org/terst/feedreader/data/FilterRuleEngine.kt b/app/src/main/java/org/terst/feedreader/data/FilterRuleEngine.kt index c32e8e9..f095322 100644 --- a/app/src/main/java/org/terst/feedreader/data/FilterRuleEngine.kt +++ b/app/src/main/java/org/terst/feedreader/data/FilterRuleEngine.kt @@ -4,6 +4,16 @@ package org.terst.feedreader.data enum class FilterResult { NORMAL, HIGHLIGHTED, MUTED } /** + * The two fields filter rules actually need -- implemented by both + * ArticleEntity (full row) and ArticleListItem (list-view projection) so + * FilterRuleEngine works with either without depending on the heavy type. + */ +interface Titled { + val title: String + val feedId: String? +} + +/** * Plain case-insensitive substring matching against the article title -- * deliberately not regex, per the "simple design" scope. A rule with a * non-null feedId only applies to that feed; a null feedId applies @@ -11,7 +21,7 @@ enum class FilterResult { NORMAL, HIGHLIGHTED, MUTED } * over drawing attention). */ object FilterRuleEngine { - fun evaluate(article: ArticleEntity, rules: List<FilterRuleEntity>): FilterResult { + fun evaluate(article: Titled, rules: List<FilterRuleEntity>): FilterResult { val applicable = rules.filter { it.feedId == null || it.feedId == article.feedId } val title = article.title.lowercase() |
