@@ -8,6 +8,10 @@ import 'package:flutter/foundation.dart';
88part 'edit_headline_event.dart' ;
99part 'edit_headline_state.dart' ;
1010
11+ final class _FetchNextCountryPage extends EditHeadlineEvent {
12+ const _FetchNextCountryPage ();
13+ }
14+
1115const _searchDebounceDuration = Duration (milliseconds: 300 );
1216
1317/// A BLoC to manage the state of editing a single headline.
@@ -19,12 +23,12 @@ class EditHeadlineBloc extends Bloc<EditHeadlineEvent, EditHeadlineState> {
1923 required DataRepository <Topic > topicsRepository,
2024 required DataRepository <Country > countriesRepository,
2125 required String headlineId,
22- }) : _headlinesRepository = headlinesRepository,
23- _sourcesRepository = sourcesRepository,
24- _topicsRepository = topicsRepository,
25- _countriesRepository = countriesRepository,
26- _headlineId = headlineId,
27- super (const EditHeadlineState ()) {
26+ }) : _headlinesRepository = headlinesRepository,
27+ _sourcesRepository = sourcesRepository,
28+ _topicsRepository = topicsRepository,
29+ _countriesRepository = countriesRepository,
30+ _headlineId = headlineId,
31+ super (const EditHeadlineState ()) {
2832 on < EditHeadlineLoaded > (_onLoaded);
2933 on < EditHeadlineTitleChanged > (_onTitleChanged);
3034 on < EditHeadlineExcerptChanged > (_onExcerptChanged);
@@ -35,6 +39,7 @@ class EditHeadlineBloc extends Bloc<EditHeadlineEvent, EditHeadlineState> {
3539 on < EditHeadlineCountryChanged > (_onCountryChanged);
3640 on < EditHeadlineStatusChanged > (_onStatusChanged);
3741 on < EditHeadlineSubmitted > (_onSubmitted);
42+ on < _FetchNextCountryPage > (_onFetchNextCountryPage);
3843 }
3944
4045 final DataRepository <Headline > _headlinesRepository;
@@ -89,26 +94,8 @@ class EditHeadlineBloc extends Bloc<EditHeadlineEvent, EditHeadlineState> {
8994
9095 // After the initial page of countries is loaded, start a background
9196 // process to fetch all remaining pages.
92- //
93- // This approach is used for the following reasons:
94- // 1. UI Consistency: It allows us to use the standard
95- // `DropdownButtonFormField`, which is used elsewhere in the app.
96- // 2. Technical Limitation: The standard dropdown does not expose a
97- //
98- // The UI will update progressively and silently in the background as
99- // more data arrives.
100- while (state.countriesHasMore) {
101- final nextCountries = await _countriesRepository.readAll (
102- pagination: PaginationOptions (cursor: state.countriesCursor),
103- sort: [const SortOption ('name' , SortOrder .asc)],
104- );
105- emit (
106- state.copyWith (
107- countries: List .of (state.countries)..addAll (nextCountries.items),
108- countriesCursor: nextCountries.cursor,
109- countriesHasMore: nextCountries.hasMore,
110- ),
111- );
97+ if (state.countriesHasMore) {
98+ add (const _FetchNextCountryPage ());
11299 }
113100 } on HttpException catch (e) {
114101 emit (state.copyWith (status: EditHeadlineStatus .failure, exception: e));
@@ -210,6 +197,49 @@ class EditHeadlineBloc extends Bloc<EditHeadlineEvent, EditHeadlineState> {
210197 );
211198 }
212199
200+ // --- Background Data Fetching for Dropdown ---
201+ // The DropdownButtonFormField widget does not natively support on-scroll
202+ // pagination. To preserve UI consistency across the application, this BLoC
203+ // employs an event-driven background fetching mechanism.
204+ //
205+ // After the first page of items is loaded, a chain of events is initiated
206+ // to progressively fetch all remaining pages. This process is throttled
207+ // and runs in the background, ensuring the UI remains responsive while the
208+ // full list of dropdown options is populated over time.
209+ Future <void > _onFetchNextCountryPage (
210+ _FetchNextCountryPage event,
211+ Emitter <EditHeadlineState > emit,
212+ ) async {
213+ if (! state.countriesHasMore || state.countriesIsLoadingMore) return ;
214+
215+ try {
216+ emit (state.copyWith (countriesIsLoadingMore: true ));
217+
218+ await Future .delayed (const Duration (milliseconds: 400 ));
219+
220+ final nextCountries = await _countriesRepository.readAll (
221+ pagination: PaginationOptions (cursor: state.countriesCursor),
222+ sort: [const SortOption ('name' , SortOrder .asc)],
223+ );
224+
225+ emit (
226+ state.copyWith (
227+ countries: List .of (state.countries)..addAll (nextCountries.items),
228+ countriesCursor: nextCountries.cursor,
229+ countriesHasMore: nextCountries.hasMore,
230+ countriesIsLoadingMore: false ,
231+ ),
232+ );
233+
234+ if (nextCountries.hasMore) {
235+ add (const _FetchNextCountryPage ());
236+ }
237+ } catch (e) {
238+ emit (state.copyWith (countriesIsLoadingMore: false ));
239+ // Optionally log the error without disrupting the user
240+ }
241+ }
242+
213243 Future <void > _onSubmitted (
214244 EditHeadlineSubmitted event,
215245 Emitter <EditHeadlineState > emit,
0 commit comments