@@ -101,6 +101,90 @@ class _HeadlinesFilterViewState extends State<_HeadlinesFilterView> {
101101 );
102102 }
103103
104+ /// Shows the dialog to let the user choose between applying the filter
105+ /// for one-time use or saving it for future use.
106+ Future <void > _showApplyOptionsDialog () async {
107+ final l10n = AppLocalizationsX (context).l10n;
108+ return showDialog <void >(
109+ context: context,
110+ builder: (BuildContext dialogContext) {
111+ return AlertDialog (
112+ title: Text (l10n.applyFilterDialogTitle),
113+ content: Text (l10n.applyFilterDialogContent),
114+ actions: < Widget > [
115+ TextButton (
116+ child: Text (l10n.applyFilterDialogApplyOnlyButton),
117+ onPressed: () {
118+ // Pop the dialog first.
119+ Navigator .of (dialogContext).pop ();
120+ // Apply the filter as a "custom" one-time filter.
121+ _applyAndExit (null );
122+ },
123+ ),
124+ FilledButton (
125+ child: Text (l10n.applyFilterDialogApplyAndSaveButton),
126+ onPressed: () {
127+ // Pop the dialog first.
128+ Navigator .of (dialogContext).pop ();
129+ // Initiate the save and apply flow.
130+ _saveAndApplyFilter ();
131+ },
132+ ),
133+ ],
134+ );
135+ },
136+ );
137+ }
138+
139+ /// Initiates the process of saving a filter by showing the naming dialog,
140+ /// and then applies it.
141+ void _saveAndApplyFilter () {
142+ final filterState = context.read <HeadlinesFilterBloc >().state;
143+ showDialog <void >(
144+ context: context,
145+ builder: (_) {
146+ return SaveFilterDialog (
147+ onSave: (name) {
148+ final newFilter = SavedFilter (
149+ id: const Uuid ().v4 (),
150+ name: name,
151+ topics: filterState.selectedTopics.toList (),
152+ sources: filterState.selectedSources.toList (),
153+ countries: filterState.selectedCountries.toList (),
154+ );
155+ // Add the filter to the global state.
156+ context.read <AppBloc >().add (SavedFilterAdded (filter: newFilter));
157+ // Apply the newly saved filter and exit the page.
158+ _applyAndExit (newFilter);
159+ },
160+ );
161+ },
162+ );
163+ }
164+
165+ /// Applies the current filter selections to the feed and pops the page.
166+ ///
167+ /// If a [savedFilter] is provided, it's passed to the event to ensure
168+ /// its chip is correctly selected on the feed. Otherwise, the filter is
169+ /// treated as a "custom" one.
170+ void _applyAndExit (SavedFilter ? savedFilter) {
171+ final filterState = context.read <HeadlinesFilterBloc >().state;
172+ final newFilter = HeadlineFilter (
173+ topics: filterState.selectedTopics.toList (),
174+ sources: filterState.selectedSources.toList (),
175+ eventCountries: filterState.selectedCountries.toList (),
176+ isFromFollowedItems: filterState.isUsingFollowedItems,
177+ );
178+ context.read <HeadlinesFeedBloc >().add (
179+ HeadlinesFeedFiltersApplied (
180+ filter: newFilter,
181+ savedFilter: savedFilter,
182+ adThemeStyle: AdThemeStyle .fromTheme (Theme .of (context)),
183+ ),
184+ );
185+ context.pop ();
186+ }
187+
104188 @override
105189 Widget build (BuildContext context) {
106190 final l10n = AppLocalizationsX (context).l10n;
@@ -134,63 +218,11 @@ class _HeadlinesFilterViewState extends State<_HeadlinesFilterView> {
134218 icon: const Icon (Icons .edit_note_outlined),
135219 onPressed: () => context.pushNamed (Routes .manageSavedFiltersName),
136220 ),
137- // Save Filter Button
138- IconButton (
139- tooltip: l10n.headlinesFilterSaveTooltip,
140- icon: const Icon (Icons .save_outlined),
141- onPressed: () {
142- showDialog <void >(
143- context: context,
144- builder: (_) {
145- final filterState = context.read <HeadlinesFilterBloc >().state;
146- return SaveFilterDialog (
147- onSave: (name) {
148- final newFilter = SavedFilter (
149- id: const Uuid ().v4 (),
150- name: name,
151- topics: filterState.selectedTopics.toList (),
152- sources: filterState.selectedSources.toList (),
153- countries: filterState.selectedCountries.toList (),
154- );
155- // Keep track of the newly saved filter.
156- setState (() => _newlySavedFilter = newFilter);
157- context.read <AppBloc >().add (
158- SavedFilterAdded (filter: newFilter),
159- );
160- },
161- );
162- },
163- );
164- },
165- ),
166221 // Apply Filters Button
167222 IconButton (
168223 icon: const Icon (Icons .check),
169224 tooltip: l10n.headlinesFeedFilterApplyButton,
170- onPressed: () {
171- final filterState = context.read <HeadlinesFilterBloc >().state;
172- final newFilter = HeadlineFilter (
173- topics: filterState.selectedTopics.isNotEmpty
174- ? filterState.selectedTopics.toList ()
175- : null ,
176- sources: filterState.selectedSources.isNotEmpty
177- ? filterState.selectedSources.toList ()
178- : null ,
179- eventCountries: filterState.selectedCountries.isNotEmpty
180- ? filterState.selectedCountries.toList ()
181- : null ,
182- isFromFollowedItems: filterState.isUsingFollowedItems,
183- );
184- context.read <HeadlinesFeedBloc >().add (
185- HeadlinesFeedFiltersApplied (
186- filter: newFilter,
187- // Pass the newly saved filter if it exists.
188- savedFilter: _newlySavedFilter,
189- adThemeStyle: AdThemeStyle .fromTheme (Theme .of (context)),
190- ),
191- );
192- context.pop ();
193- },
225+ onPressed: _showApplyOptionsDialog,
194226 ),
195227 ],
196228 ),
0 commit comments