diff options
Diffstat (limited to 'app/src/main/java/org')
| -rw-r--r-- | app/src/main/java/org/terst/feedreader/data/FilterRuleEngine.kt | 18 | ||||
| -rw-r--r-- | app/src/main/java/org/terst/feedreader/ui/ArticleListScreen.kt | 3 |
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()) |
