Skip to content

Commit c7143e7

Browse files
committed
fix(feed): correctly identify custom filters on apply
Refactors the `_onHeadlinesFeedFiltersApplied` handler in `HeadlinesFeedBloc` to robustly determine the active filter ID. Previously, applying a modified saved filter would incorrectly retain the original filter's ID, causing the wrong UI chip to be selected. This change introduces logic to compare the contents of the incoming `HeadlineFilter` against all existing `savedFilters`. If an exact match is found, its ID is used. If no match is found (indicating a modification or a new unsaved filter), the `activeFilterId` is explicitly set to 'custom'. This resolves the bug and ensures the UI accurately reflects the filter state.
1 parent 7990c4f commit c7143e7

File tree

1 file changed

+23
-14
lines changed

1 file changed

+23
-14
lines changed

lib/headlines-feed/bloc/headlines_feed_bloc.dart

Lines changed: 23 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import 'dart:async';
22

33
import 'package:bloc/bloc.dart';
44
import 'package:bloc_concurrency/bloc_concurrency.dart';
5+
import 'package:collection/collection.dart';
56
import 'package:core/core.dart';
67
import 'package:data_repository/data_repository.dart';
78
import 'package:equatable/equatable.dart';
@@ -265,20 +266,28 @@ class HeadlinesFeedBloc extends Bloc<HeadlinesFeedEvent, HeadlinesFeedState> {
265266
HeadlinesFeedFiltersApplied event,
266267
Emitter<HeadlinesFeedState> emit,
267268
) async {
268-
String? newActiveFilterId;
269-
270-
// If a saved filter was explicitly passed (e.g., just created), use its ID.
271-
if (event.savedFilter != null) {
272-
newActiveFilterId = event.savedFilter!.id;
273-
} else {
274-
// Otherwise, determine if this is a pre-existing saved filter being
275-
// re-applied or a custom one.
276-
final isSavedFilter =
277-
state.activeFilterId != 'all' &&
278-
state.activeFilterId != 'custom' &&
279-
state.activeFilterId != null;
280-
newActiveFilterId = isSavedFilter ? state.activeFilterId : 'custom';
281-
}
269+
// Determine if the applied filter matches an existing saved filter.
270+
// This logic is crucial for correctly setting the active filter chip in
271+
// the UI. It compares the content of the applied filter with each saved
272+
// filter, ignoring the order of items within the lists.
273+
final matchingSavedFilter = state.savedFilters.firstWhereOrNull((
274+
savedFilter,
275+
) {
276+
// Use sets for order-agnostic comparison of filter contents.
277+
final appliedTopics = event.filter.topics?.toSet() ?? {};
278+
final savedTopics = savedFilter.topics.toSet();
279+
final appliedSources = event.filter.sources?.toSet() ?? {};
280+
final savedSources = savedFilter.sources.toSet();
281+
final appliedCountries = event.filter.eventCountries?.toSet() ?? {};
282+
final savedCountries = savedFilter.countries.toSet();
283+
284+
return const SetEquality<Topic>().equals(appliedTopics, savedTopics) &&
285+
const SetEquality<Source>().equals(appliedSources, savedSources) &&
286+
const SetEquality<Country>().equals(appliedCountries, savedCountries);
287+
});
288+
289+
// If a match is found, use its ID. Otherwise, mark it as 'custom'.
290+
final newActiveFilterId = matchingSavedFilter?.id ?? 'custom';
282291

283292
// When applying new filters, this is considered a major feed change,
284293
// so we clear the ad cache to get a fresh set of relevant ads.

0 commit comments

Comments
 (0)