diff options
Diffstat (limited to 'app/src/main/java/org/terst/feedreader/data')
| -rw-r--r-- | app/src/main/java/org/terst/feedreader/data/AppDatabase.kt | 17 | ||||
| -rw-r--r-- | app/src/main/java/org/terst/feedreader/data/FeedParser.kt | 10 |
2 files changed, 23 insertions, 4 deletions
diff --git a/app/src/main/java/org/terst/feedreader/data/AppDatabase.kt b/app/src/main/java/org/terst/feedreader/data/AppDatabase.kt index 441556b..66722fd 100644 --- a/app/src/main/java/org/terst/feedreader/data/AppDatabase.kt +++ b/app/src/main/java/org/terst/feedreader/data/AppDatabase.kt @@ -9,7 +9,7 @@ import androidx.room.migration.Migration @Database( entities = [FeedEntity::class, ArticleEntity::class, FilterRuleEntity::class], - version = 4, + version = 5, exportSchema = false ) abstract class AppDatabase : RoomDatabase() { @@ -77,12 +77,25 @@ abstract class AppDatabase : RoomDatabase() { } } + // v5: a feed with a literal empty <guid>/<id> element (confirmed live: a Mother + // Jones entry) produced an ArticleEntity with id = "" -- FeedParser fell back to + // itemLink only when the guid was null, not when it was blank. An empty-string + // primary key broke Navigation Compose's route matching and crashed on tap. The + // parser is fixed for future fetches; this cleans out any row already on-device + // with the bad id so it doesn't keep crashing. It'll come back with a real, + // hash-based id on the next fetch of that feed. + private val MIGRATION_4_5 = object : Migration(4, 5) { + override fun migrate(db: SupportSQLiteDatabase) { + db.execSQL("DELETE FROM articles WHERE trim(id) = ''") + } + } + fun get(context: Context): AppDatabase = instance ?: synchronized(this) { instance ?: Room.databaseBuilder( context.applicationContext, AppDatabase::class.java, "feedreader.db" - ).addMigrations(MIGRATION_1_2, MIGRATION_2_3, MIGRATION_3_4).build().also { instance = it } + ).addMigrations(MIGRATION_1_2, MIGRATION_2_3, MIGRATION_3_4, MIGRATION_4_5).build().also { instance = it } } } } diff --git a/app/src/main/java/org/terst/feedreader/data/FeedParser.kt b/app/src/main/java/org/terst/feedreader/data/FeedParser.kt index 629afe6..8b37e55 100644 --- a/app/src/main/java/org/terst/feedreader/data/FeedParser.kt +++ b/app/src/main/java/org/terst/feedreader/data/FeedParser.kt @@ -120,7 +120,12 @@ object FeedParser { inItem = false val content = itemContent ?: itemDescription items += ParsedItem( - guid = itemGuid ?: itemLink.ifBlank { null }, + // .ifBlank, not just ?: -- a feed with a literal empty <guid></guid> + // (confirmed live: a Mother Jones entry) gives itemGuid = "" here, + // which is non-null and so passed straight through a plain `?:`, + // landing as the article's primary key. An empty-string id broke + // Navigation Compose's route matching and crashed on tap. + guid = itemGuid?.ifBlank { null } ?: itemLink.ifBlank { null }, title = itemTitle, link = itemLink, author = itemAuthor, @@ -195,7 +200,8 @@ object FeedParser { inEntry = false val content = entryContent ?: entrySummary items += ParsedItem( - guid = entryId ?: entryLink.ifBlank { null }, + // Same blank-vs-null fix as the RSS path above. + guid = entryId?.ifBlank { null } ?: entryLink.ifBlank { null }, title = entryTitle, link = entryLink, author = entryAuthor, |
