import 'dart:collection'; import 'dart:convert'; import 'dart:io'; import 'package:flutter/foundation.dart'; import 'package:logging/logging.dart'; import 'package:result_monad/result_monad.dart'; import '../models/exec_error.dart'; 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; final _filters = {}; final _entryCache = {}; List get filters => UnmodifiableListView(_filters.values); TimelineEntryFilterService(this.filePath); void load() { final file = File(filePath); if (!file.existsSync()) { return; } try { final str = file.readAsStringSync(); final json = jsonDecode(str) as List; final filters = json.map((j) => TimelineEntryFilter.fromJson(j)).toList(); _filters.clear(); _filters.addEntries(filters.map((f) => MapEntry(f.id, f))); } catch (e) { _logger.severe('Error parsing filters file $filePath: $e'); } } void save() { try { final json = _filters.values.map((f) => f.toJson()).toList(); final str = jsonEncode(json); File(filePath).writeAsStringSync(str); } catch (e) { _logger.severe('Error writing filters file $filePath: $e'); } } Result getForId(String id) { if (!_filters.containsKey(id)) { return buildErrorResult( type: ErrorType.notFound, message: 'No filter with id: $id', ); } return Result.ok(_filters[id]!); } void upsertFilter(TimelineEntryFilter filter) { _filters[filter.id] = filter; _entryCache.clear(); save(); notifyListeners(); } void removeById(String id) { _filters.remove(id); _entryCache.clear(); save(); notifyListeners(); } FilterResult checkTimelineEntry(TimelineEntry entry) { if (entry == _entryCache[entry.id]?.entry) { return _entryCache[entry.id]!.result; } final result = runFilters(entry, _filters.values.toList()); _entryCache[entry.id] = _EntryCacheItem(entry, result); return result; } } class _EntryCacheItem { final TimelineEntry entry; final FilterResult result; _EntryCacheItem(this.entry, this.result); }