summaryrefslogtreecommitdiff
path: root/app/src/main/java/org
diff options
context:
space:
mode:
Diffstat (limited to 'app/src/main/java/org')
-rw-r--r--app/src/main/java/org/terst/feedreader/data/FilterRuleEngine.kt18
-rw-r--r--app/src/main/java/org/terst/feedreader/ui/ArticleListScreen.kt3
2 files changed, 17 insertions, 4 deletions
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 f095322..1f45a9f 100644
--- a/app/src/main/java/org/terst/feedreader/data/FilterRuleEngine.kt
+++ b/app/src/main/java/org/terst/feedreader/data/FilterRuleEngine.kt
@@ -20,15 +20,27 @@ interface Titled {
* globally. MUTE wins over HIGHLIGHT if both match (hiding takes priority
* over drawing attention).
*/
+// Pre-lowercased once per rule, not re-derived from FilterRuleEntity.pattern on every
+// evaluate() call -- ArticleListScreen calls evaluate() once per VISIBLE ARTICLE against
+// the same rule set (re-run on every emission of either the article or filter-rule Flow,
+// i.e. on essentially any read-state change to any article in the list), so with a couple
+// hundred articles and a handful of rules, calling pattern.lowercase() inside the old
+// per-article evaluate() meant thousands of redundant String allocations of the exact same
+// small set of strings.
+data class CompiledRule(val feedId: String?, val action: FilterAction, val lowerPattern: String)
+
object FilterRuleEngine {
- fun evaluate(article: Titled, rules: List<FilterRuleEntity>): FilterResult {
+ fun compile(rules: List<FilterRuleEntity>): List<CompiledRule> =
+ rules.map { CompiledRule(it.feedId, it.action, it.pattern.lowercase()) }
+
+ fun evaluate(article: Titled, rules: List<CompiledRule>): FilterResult {
val applicable = rules.filter { it.feedId == null || it.feedId == article.feedId }
val title = article.title.lowercase()
- val muted = applicable.any { it.action == FilterAction.MUTE && title.contains(it.pattern.lowercase()) }
+ val muted = applicable.any { it.action == FilterAction.MUTE && title.contains(it.lowerPattern) }
if (muted) return FilterResult.MUTED
- val highlighted = applicable.any { it.action == FilterAction.HIGHLIGHT && title.contains(it.pattern.lowercase()) }
+ val highlighted = applicable.any { it.action == FilterAction.HIGHLIGHT && title.contains(it.lowerPattern) }
return if (highlighted) FilterResult.HIGHLIGHTED else FilterResult.NORMAL
}
}
diff --git a/app/src/main/java/org/terst/feedreader/ui/ArticleListScreen.kt b/app/src/main/java/org/terst/feedreader/ui/ArticleListScreen.kt
index a852288..6f2db12 100644
--- a/app/src/main/java/org/terst/feedreader/ui/ArticleListScreen.kt
+++ b/app/src/main/java/org/terst/feedreader/ui/ArticleListScreen.kt
@@ -72,7 +72,8 @@ fun ArticleListScreen(
}
val visibleArticles by remember(feedId) {
combine(articleFlow, db.filterRuleDao().observeAll()) { articles, rules ->
- articles.map { it to FilterRuleEngine.evaluate(it, rules) }
+ val compiledRules = FilterRuleEngine.compile(rules)
+ articles.map { it to FilterRuleEngine.evaluate(it, compiledRules) }
.filter { (_, result) -> result != FilterResult.MUTED }
}
}.collectAsState(initial = emptyList())