class ContentBlocker { ContentBlockerTrigger trigger; ContentBlockerAction action; ContentBlocker(this.trigger, this.action); Map> toMap() { return { "trigger": trigger.toMap(), "action": action.toMap() }; } } class ContentBlockerTriggerResourceType { final String _value; const ContentBlockerTriggerResourceType._internal(this._value); toValue() => _value; static const DOCUMENT = const ContentBlockerTriggerResourceType._internal('document'); static const IMAGE = const ContentBlockerTriggerResourceType._internal('image'); static const STYLE_SHEET = const ContentBlockerTriggerResourceType._internal('style-sheet'); static const SCRIPT = const ContentBlockerTriggerResourceType._internal('script'); static const FONT = const ContentBlockerTriggerResourceType._internal('font'); static const MEDIA = const ContentBlockerTriggerResourceType._internal('media'); static const SVG_DOCUMENT = const ContentBlockerTriggerResourceType._internal('svg-document'); static const RAW = const ContentBlockerTriggerResourceType._internal('raw'); } class ContentBlockerTriggerLoadType { final String _value; const ContentBlockerTriggerLoadType._internal(this._value); toValue() => _value; static const FIRST_PARTY = const ContentBlockerTriggerLoadType._internal('first-party'); static const THIRD_PARTY = const ContentBlockerTriggerLoadType._internal('third-party'); } class ContentBlockerTrigger { String urlFilter; bool urlFilterIsCaseSensitive; List resourceType; List ifDomain; List unlessDomain; List loadType; List ifTopUrl; List unlessTopUrl; ContentBlockerTrigger(String urlFilter, {bool urlFilterIsCaseSensitive = false, List resourceType = const [], List ifDomain = const [], List unlessDomain = const [], List loadType = const [], List ifTopUrl = const [], List unlessTopUrl = const []}) { this.urlFilter = urlFilter; this.resourceType = resourceType; this.urlFilterIsCaseSensitive = urlFilterIsCaseSensitive; this.ifDomain = ifDomain; this.unlessDomain = unlessDomain; assert(!(this.ifDomain.isEmpty || this.unlessDomain.isEmpty) == false); this.loadType = loadType; assert(this.loadType.length <= 2); this.ifTopUrl = ifTopUrl; this.unlessTopUrl = unlessTopUrl; assert(!(this.ifTopUrl.isEmpty || this.unlessTopUrl.isEmpty) == false); } Map toMap() { List resourceTypeStringList = []; resourceType.forEach((type) { resourceTypeStringList.add(type.toValue()); }); List loadTypeStringList = []; loadType.forEach((type) { loadTypeStringList.add(type.toValue()); }); Map map = { "url-filter": urlFilter, "url-filter-is-case-sensitive": urlFilterIsCaseSensitive, "if-domain": ifDomain, "unless-domain": unlessDomain, "resource-type": resourceTypeStringList, "load-type": loadTypeStringList, "if-top-url": ifTopUrl, "unless-top-url": unlessTopUrl }; map.keys .where((key) => map[key] == null || (map[key] is List && (map[key] as List).length == 0)) // filter keys .toList() // create a copy to avoid concurrent modifications .forEach(map.remove); return map; } } class ContentBlockerActionType { final String _value; const ContentBlockerActionType._internal(this._value); toValue() => _value; static const BLOCK = const ContentBlockerActionType._internal('block'); static const CSS_DISPLAY_NONE = const ContentBlockerActionType._internal('css-display-none'); static const MAKE_HTTPS = const ContentBlockerActionType._internal('make-https'); } class ContentBlockerAction { ContentBlockerActionType type; String selector; ContentBlockerAction(ContentBlockerActionType type, {String selector}) { this.type = type; if (this.type == ContentBlockerActionType.CSS_DISPLAY_NONE) { assert(selector != null); } this.selector = selector; } Map toMap() { Map map = { "type": type.toValue(), "selector": selector }; map.keys .where((key) => map[key] == null || (map[key] is List && (map[key] as List).length == 0)) // filter keys .toList() // create a copy to avoid concurrent modifications .forEach(map.remove); return map; } }