2023-05-07 23:07:32 +00:00
|
|
|
import 'dart:collection';
|
|
|
|
import 'dart:convert';
|
|
|
|
import 'dart:io';
|
|
|
|
|
|
|
|
import 'package:flutter/foundation.dart';
|
|
|
|
import 'package:logging/logging.dart';
|
2023-05-08 00:10:43 +00:00
|
|
|
import 'package:result_monad/result_monad.dart';
|
2023-05-07 23:07:32 +00:00
|
|
|
|
2023-05-08 00:10:43 +00:00
|
|
|
import '../models/exec_error.dart';
|
2023-05-07 23:07:32 +00:00
|
|
|
import '../models/filters/timeline_entry_filter.dart';
|
|
|
|
import '../models/timeline_entry.dart';
|
|
|
|
import '../utils/filter_runner.dart';
|
|
|
|
|
|
|
|
class TimelineEntryFilterService extends ChangeNotifier {
|
|
|
|
static final _logger = Logger('$TimelineEntryFilterService');
|
|
|
|
final String filePath;
|
2023-05-08 00:10:43 +00:00
|
|
|
final _filters = <String, TimelineEntryFilter>{};
|
2023-05-07 23:07:32 +00:00
|
|
|
final _entryCache = <String, _EntryCacheItem>{};
|
|
|
|
|
2023-05-08 00:10:43 +00:00
|
|
|
List<TimelineEntryFilter> get filters =>
|
|
|
|
UnmodifiableListView(_filters.values);
|
2023-05-07 23:07:32 +00:00
|
|
|
|
|
|
|
TimelineEntryFilterService(this.filePath);
|
|
|
|
|
|
|
|
void load() {
|
|
|
|
final file = File(filePath);
|
|
|
|
if (!file.existsSync()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
try {
|
|
|
|
final str = file.readAsStringSync();
|
|
|
|
final json = jsonDecode(str) as List<dynamic>;
|
|
|
|
final filters = json.map((j) => TimelineEntryFilter.fromJson(j)).toList();
|
|
|
|
_filters.clear();
|
2023-05-08 00:10:43 +00:00
|
|
|
_filters.addEntries(filters.map((f) => MapEntry(f.id, f)));
|
2023-05-07 23:07:32 +00:00
|
|
|
} catch (e) {
|
|
|
|
_logger.severe('Error parsing filters file $filePath: $e');
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void save() {
|
|
|
|
try {
|
2023-05-08 00:10:43 +00:00
|
|
|
final json = _filters.values.map((f) => f.toJson()).toList();
|
2023-05-07 23:07:32 +00:00
|
|
|
final str = jsonEncode(json);
|
|
|
|
File(filePath).writeAsStringSync(str);
|
|
|
|
} catch (e) {
|
|
|
|
_logger.severe('Error writing filters file $filePath: $e');
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-05-08 00:10:43 +00:00
|
|
|
Result<TimelineEntryFilter, ExecError> getForId(String id) {
|
|
|
|
if (!_filters.containsKey(id)) {
|
|
|
|
return buildErrorResult(
|
|
|
|
type: ErrorType.notFound,
|
|
|
|
message: 'No filter with id: $id',
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
return Result.ok(_filters[id]!);
|
|
|
|
}
|
|
|
|
|
2023-05-07 23:07:32 +00:00
|
|
|
void upsertFilter(TimelineEntryFilter filter) {
|
2023-05-08 00:10:43 +00:00
|
|
|
_filters[filter.id] = filter;
|
2023-05-07 23:07:32 +00:00
|
|
|
_entryCache.clear();
|
|
|
|
save();
|
|
|
|
notifyListeners();
|
|
|
|
}
|
|
|
|
|
2023-05-08 00:10:43 +00:00
|
|
|
void removeById(String id) {
|
|
|
|
_filters.remove(id);
|
2023-05-07 23:07:32 +00:00
|
|
|
_entryCache.clear();
|
|
|
|
save();
|
|
|
|
notifyListeners();
|
|
|
|
}
|
|
|
|
|
2023-05-08 11:18:09 +00:00
|
|
|
FilterResult checkTimelineEntry(TimelineEntry entry) {
|
2023-05-07 23:07:32 +00:00
|
|
|
if (entry == _entryCache[entry.id]?.entry) {
|
|
|
|
return _entryCache[entry.id]!.result;
|
|
|
|
}
|
|
|
|
|
2023-05-08 00:10:43 +00:00
|
|
|
final result = runFilters(entry, _filters.values.toList());
|
2023-05-07 23:07:32 +00:00
|
|
|
_entryCache[entry.id] = _EntryCacheItem(entry, result);
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
class _EntryCacheItem {
|
|
|
|
final TimelineEntry entry;
|
|
|
|
final FilterResult result;
|
|
|
|
|
|
|
|
_EntryCacheItem(this.entry, this.result);
|
|
|
|
}
|