11import 'dart:async' ;
22
33import 'package:logging/logging.dart' ;
4+ import 'package:meta/meta.dart' ;
45import 'package:rxdart/rxdart.dart' ;
56
7+ import 'disposable.dart' ;
8+ import 'disposable_mixin.dart' ;
69import 'filter.dart' ;
710import 'filter_group.dart' ;
811import 'filters.dart' ;
9- import 'immutable_filters.dart' ;
1012import 'logger.dart' ;
1113
1214/// [FilterState] holds one or several filters, organized in groups.
1315/// [filters] streams filters changes of added or removed filters,
1416/// which will be applied to searches performed by the connected Searcher.
15- class FilterState {
17+ @sealed
18+ abstract class FilterState implements Disposable {
19+ /// FilterState's factory.
20+ factory FilterState () => _FilterState ();
21+
22+ /// Filters groups stream (facet, tag, numeric and hierarchical).
23+ Stream <Filters > get filters;
24+
25+ /// Adds [filters] to the provided [groupID] .
26+ void add (FilterGroupID groupID, Iterable <Filter > filters);
27+
28+ /// Overrides [filters] with the provided [map] .
29+ void set (Map <FilterGroupID , Set <Filter >> map);
30+
31+ /// Removes [filters] from [groupID] .
32+ void remove (FilterGroupID groupID, Iterable <Filter > filters);
33+
34+ /// Toggles [filter] in given [groupID] .
35+ void toggle (FilterGroupID groupID, Filter filter);
36+
37+ /// Checks if [filter] exists in [groupID] .
38+ bool contains (FilterGroupID groupID, Filter filter);
39+
40+ /// Adds [hierarchicalFilter] to given [attribute] .
41+ void addHierarchical (
42+ String attribute,
43+ HierarchicalFilter hierarchicalFilter,
44+ );
45+
46+ /// Removes [HierarchicalFilter] of given [attribute] .
47+ void removeHierarchical (String attribute);
48+
49+ /// Clears [groupIDs] .
50+ /// If none provided, all filters will be cleared.
51+ void clear ([Iterable <FilterGroupID >? groupIDs]);
52+
53+ /// Clears all except [groupIDs] .
54+ void clearExcept (Iterable <FilterGroupID > groupIDs);
55+
56+ /// Get current [filters] value.
57+ Filters snapshot ();
58+
59+ /// **Asynchronous** updates [filters] by applying [builder] to current
60+ /// filters value.
61+ /// Useful to apply multiple consecutive update operations without firing
62+ /// multiple filters events.
63+ Future <void > modify (AsyncFiltersBuilder builder);
64+ }
65+
66+ /// Asynchronous stateless filters builder.
67+ typedef AsyncFiltersBuilder = Future <StatelessFilters > Function (
68+ StatelessFilters filters,
69+ );
70+
71+ /// Default implementation of [FilterState] .
72+ class _FilterState with DisposableMixin implements FilterState {
1673 /// Filters groups stream (facet, tag, numeric and hierarchical).
74+ @override
1775 Stream <Filters > get filters => _filters.stream.distinct ();
1876
1977 /// Events logger
2078 final Logger _log = algoliaLogger ('FilterState' );
2179
22- /// Hot stream controller of [ImmutableFilters ] .
23- final BehaviorSubject <ImmutableFilters > _filters =
24- BehaviorSubject .seeded (const ImmutableFilters ());
80+ /// Hot stream controller of [StatelessFilters ] .
81+ final BehaviorSubject <StatelessFilters > _filters =
82+ BehaviorSubject .seeded (StatelessFilters ());
2583
2684 /// Adds [filters] to the provided [groupID] .
85+ @override
2786 void add (FilterGroupID groupID, Iterable <Filter > filters) {
2887 _modify ((it) => it.add (groupID, filters));
2988 }
3089
3190 /// Overrides [filters] with the provided [map] .
91+ @override
3292 void set (Map <FilterGroupID , Set <Filter >> map) {
3393 _modify ((it) => it.set (map));
3494 }
3595
3696 /// Removes [filters] from [groupID] .
97+ @override
3798 void remove (FilterGroupID groupID, Iterable <Filter > filters) {
3899 _modify ((it) => it.remove (groupID, filters));
39100 }
40101
41102 /// Toggles [filter] in given [groupID] .
103+ @override
42104 void toggle (FilterGroupID groupID, Filter filter) =>
43105 _modify ((it) => it.toggle (groupID, filter));
44106
45107 /// Checks if [filter] exists in [groupID] .
108+ @override
46109 bool contains (FilterGroupID groupID, Filter filter) =>
47110 _filters.value.contains (groupID, filter);
48111
49112 /// Adds [hierarchicalFilter] to given [attribute] .
113+ @override
50114 void addHierarchical (
51115 String attribute,
52116 HierarchicalFilter hierarchicalFilter,
@@ -55,49 +119,61 @@ class FilterState {
55119 }
56120
57121 /// Removes [HierarchicalFilter] of given [attribute] .
122+ @override
58123 void removeHierarchical (String attribute) {
59124 _modify ((it) => it.removeHierarchical (attribute));
60125 }
61126
62127 /// Clears [groupIDs] .
63128 /// If none provided, all filters will be cleared.
129+ @override
64130 void clear ([Iterable <FilterGroupID >? groupIDs]) {
65131 _modify ((it) => it.clear (groupIDs));
66132 }
67133
68134 /// Clears all except [groupIDs] .
135+ @override
69136 void clearExcept (Iterable <FilterGroupID > groupIDs) {
70137 _modify ((it) => it.clearExcept (groupIDs));
71138 }
72139
73140 /// Get current [filters] value.
141+ @override
74142 Filters snapshot () => _filters.value;
75143
76144 /// Dispose of underlying resources.
77- void dispose () {
145+ @override
146+ void doDispose () {
78147 _log.finest ('FilterState disposed' );
79148 _filters.close ();
80149 }
81150
82- /// Updates [filters] by applying [action] to current filters value.
151+ /// **Asynchronous** updates [filters] by applying [builder] to current
152+ /// filters value.
83153 /// Useful to apply multiple consecutive update operations without firing
84154 /// multiple filters events.
85- void _modify (ImmutableFilters Function (ImmutableFilters filters) action) {
155+ @override
156+ Future <void > modify (AsyncFiltersBuilder builder) async {
157+ if (_filters.isClosed) {
158+ _log.warning ('modifying disposed instance' );
159+ return ;
160+ }
86161 final current = _filters.value;
87- final updated = action (current);
162+ final updated = await builder (current);
88163 _filters.sink.add (updated);
89164 _log.finest ('FilterState updated: $updated ' );
90165 }
91166
92- /// **Asynchronous** updates [filters] by applying [action] to current filters
93- /// value.
167+ /// Updates [filters] by applying [builder] to current filters value.
94168 /// Useful to apply multiple consecutive update operations without firing
95169 /// multiple filters events.
96- Future <void > modify (
97- Future <ImmutableFilters > Function (ImmutableFilters filters) action,
98- ) async {
170+ void _modify (StatelessFilters Function (StatelessFilters ) builder) {
171+ if (_filters.isClosed) {
172+ _log.warning ('modifying disposed instance' );
173+ return ;
174+ }
99175 final current = _filters.value;
100- final updated = await action (current);
176+ final updated = builder (current);
101177 _filters.sink.add (updated);
102178 _log.finest ('FilterState updated: $updated ' );
103179 }
0 commit comments