summaryrefslogtreecommitdiff
path: root/app/src/main/java/org/terst/feedreader/data
diff options
context:
space:
mode:
Diffstat (limited to 'app/src/main/java/org/terst/feedreader/data')
-rw-r--r--app/src/main/java/org/terst/feedreader/data/Daos.kt35
-rw-r--r--app/src/main/java/org/terst/feedreader/data/Entities.kt6
-rw-r--r--app/src/main/java/org/terst/feedreader/data/FilterRuleEngine.kt12
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()