@@ -8,6 +8,10 @@ import 'package:flutter/foundation.dart';
8
8
part 'edit_headline_event.dart' ;
9
9
part 'edit_headline_state.dart' ;
10
10
11
+ final class _FetchNextCountryPage extends EditHeadlineEvent {
12
+ const _FetchNextCountryPage ();
13
+ }
14
+
11
15
const _searchDebounceDuration = Duration (milliseconds: 300 );
12
16
13
17
/// A BLoC to manage the state of editing a single headline.
@@ -19,12 +23,12 @@ class EditHeadlineBloc extends Bloc<EditHeadlineEvent, EditHeadlineState> {
19
23
required DataRepository <Topic > topicsRepository,
20
24
required DataRepository <Country > countriesRepository,
21
25
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 ()) {
28
32
on < EditHeadlineLoaded > (_onLoaded);
29
33
on < EditHeadlineTitleChanged > (_onTitleChanged);
30
34
on < EditHeadlineExcerptChanged > (_onExcerptChanged);
@@ -35,6 +39,7 @@ class EditHeadlineBloc extends Bloc<EditHeadlineEvent, EditHeadlineState> {
35
39
on < EditHeadlineCountryChanged > (_onCountryChanged);
36
40
on < EditHeadlineStatusChanged > (_onStatusChanged);
37
41
on < EditHeadlineSubmitted > (_onSubmitted);
42
+ on < _FetchNextCountryPage > (_onFetchNextCountryPage);
38
43
}
39
44
40
45
final DataRepository <Headline > _headlinesRepository;
@@ -89,26 +94,8 @@ class EditHeadlineBloc extends Bloc<EditHeadlineEvent, EditHeadlineState> {
89
94
90
95
// After the initial page of countries is loaded, start a background
91
96
// 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 ());
112
99
}
113
100
} on HttpException catch (e) {
114
101
emit (state.copyWith (status: EditHeadlineStatus .failure, exception: e));
@@ -210,6 +197,49 @@ class EditHeadlineBloc extends Bloc<EditHeadlineEvent, EditHeadlineState> {
210
197
);
211
198
}
212
199
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
+
213
243
Future <void > _onSubmitted (
214
244
EditHeadlineSubmitted event,
215
245
Emitter <EditHeadlineState > emit,
0 commit comments