relatica/lib/utils/filter_runner.dart

141 wiersze
3.8 KiB
Dart

import 'package:relatica/utils/html_to_edit_text_helper.dart';
import '../models/filters/string_filter.dart';
import '../models/filters/timeline_entry_filter.dart';
import '../models/timeline_entry.dart';
class FilterResult {
static const show = FilterResult(
false,
TimelineEntryFilterAction.warn,
'',
);
final TimelineEntryFilterAction action;
final bool isFiltered;
final String trippingFilterName;
const FilterResult(
this.isFiltered,
this.action,
this.trippingFilterName,
);
String toActionString() {
return isFiltered ? action.name : 'show';
}
@override
bool operator ==(Object other) =>
identical(this, other) ||
other is FilterResult &&
runtimeType == other.runtimeType &&
action == other.action &&
isFiltered == other.isFiltered &&
trippingFilterName == other.trippingFilterName;
@override
int get hashCode =>
action.hashCode ^ isFiltered.hashCode ^ trippingFilterName.hashCode;
}
FilterResult runFilters(
TimelineEntry entry,
List<TimelineEntryFilter> filters,
) {
var isFiltered = false;
var action = TimelineEntryFilterAction.warn;
var trippingFilterName = '';
for (final filter in filters.where((f) => f.enabled)) {
if (filter.isFiltered(entry)) {
isFiltered = true;
if (trippingFilterName.isEmpty) {
trippingFilterName = filter.name;
}
if (filter.action == TimelineEntryFilterAction.hide) {
action = TimelineEntryFilterAction.hide;
trippingFilterName = filter.name;
break;
}
}
}
return FilterResult(isFiltered, action, trippingFilterName);
}
extension StringFilterOps on StringFilter {
bool isFiltered(String value) {
switch (type) {
case ComparisonType.contains:
return value.contains(filterString);
case ComparisonType.containsIgnoreCase:
final lv = value.toLowerCase();
final lf = filterString.toLowerCase();
final c = lv.contains(lf);
return c;
case ComparisonType.equals:
return value == filterString;
case ComparisonType.equalsIgnoreCase:
return value.toLowerCase() == filterString.toLowerCase();
case ComparisonType.endsWithIgnoreCase:
return value.toLowerCase().endsWith(filterString.toLowerCase());
}
}
}
extension TimelineEntryFilterOps on TimelineEntryFilter {
bool isFiltered(TimelineEntry entry) {
if (authorFilters.isEmpty &&
domainFilters.isEmpty &&
hashtagFilters.isEmpty &&
keywordFilters.isEmpty) {
return false;
}
var authorFiltered = authorFilters.isEmpty ? true : false;
for (final filter in authorFilters) {
if (filter.isFiltered(entry.authorId) ||
filter.isFiltered(entry.parentAuthorId)) {
authorFiltered = true;
break;
}
}
var hashtagFiltered = hashtagFilters.isEmpty ? true : false;
for (final filter in hashtagFilters) {
for (final tag in entry.tags) {
if (filter.isFiltered(tag)) {
hashtagFiltered = true;
break;
}
}
}
var domainFiltered = domainFilters.isEmpty ? true : false;
for (final filter in domainFilters) {
final domain =
Uri.tryParse(entry.externalLink)?.host ?? entry.externalLink;
if (filter.isFiltered(domain)) {
domainFiltered = true;
break;
}
}
var contentFiltered = keywordFilters.isEmpty ? true : false;
final simplifiedBody = keywordFilters.isNotEmpty
? htmlToSimpleText(entry.body).toLowerCase()
: '';
for (final filter in keywordFilters) {
if (filter.isFiltered(simplifiedBody)) {
contentFiltered = true;
break;
}
}
return authorFiltered &&
domainFiltered &&
hashtagFiltered &&
contentFiltered;
}
}