@@ -9,6 +9,14 @@ import 'package:uuid/uuid.dart';
9
9
part 'create_source_event.dart' ;
10
10
part 'create_source_state.dart' ;
11
11
12
+ final class _FetchNextCountryPage extends CreateSourceEvent {
13
+ const _FetchNextCountryPage ();
14
+ }
15
+
16
+ final class _FetchNextLanguagePage extends CreateSourceEvent {
17
+ const _FetchNextLanguagePage ();
18
+ }
19
+
12
20
const _searchDebounceDuration = Duration (milliseconds: 300 );
13
21
14
22
/// A BLoC to manage the state of creating a new source.
@@ -18,10 +26,10 @@ class CreateSourceBloc extends Bloc<CreateSourceEvent, CreateSourceState> {
18
26
required DataRepository <Source > sourcesRepository,
19
27
required DataRepository <Country > countriesRepository,
20
28
required DataRepository <Language > languagesRepository,
21
- }) : _sourcesRepository = sourcesRepository,
22
- _countriesRepository = countriesRepository,
23
- _languagesRepository = languagesRepository,
24
- super (const CreateSourceState ()) {
29
+ }) : _sourcesRepository = sourcesRepository,
30
+ _countriesRepository = countriesRepository,
31
+ _languagesRepository = languagesRepository,
32
+ super (const CreateSourceState ()) {
25
33
on < CreateSourceDataLoaded > (_onDataLoaded);
26
34
on < CreateSourceNameChanged > (_onNameChanged);
27
35
on < CreateSourceDescriptionChanged > (_onDescriptionChanged);
@@ -31,6 +39,8 @@ class CreateSourceBloc extends Bloc<CreateSourceEvent, CreateSourceState> {
31
39
on < CreateSourceHeadquartersChanged > (_onHeadquartersChanged);
32
40
on < CreateSourceStatusChanged > (_onStatusChanged);
33
41
on < CreateSourceSubmitted > (_onSubmitted);
42
+ on < _FetchNextCountryPage > (_onFetchNextCountryPage);
43
+ on < _FetchNextLanguagePage > (_onFetchNextLanguagePage);
34
44
}
35
45
36
46
final DataRepository <Source > _sourcesRepository;
@@ -66,34 +76,13 @@ class CreateSourceBloc extends Bloc<CreateSourceEvent, CreateSourceState> {
66
76
),
67
77
);
68
78
69
- // Start background fetching for all countries
70
- while (state.countriesHasMore) {
71
- final nextCountries = await _countriesRepository.readAll (
72
- pagination: PaginationOptions (cursor: state.countriesCursor),
73
- sort: [const SortOption ('name' , SortOrder .asc)],
74
- );
75
- emit (
76
- state.copyWith (
77
- countries: List .of (state.countries)..addAll (nextCountries.items),
78
- countriesCursor: nextCountries.cursor,
79
- countriesHasMore: nextCountries.hasMore,
80
- ),
81
- );
79
+ // After the initial page is loaded, start background processes to
80
+ // fetch all remaining pages for countries and languages.
81
+ if (state.countriesHasMore) {
82
+ add (const _FetchNextCountryPage ());
82
83
}
83
-
84
- // Start background fetching for all languages
85
- while (state.languagesHasMore) {
86
- final nextLanguages = await _languagesRepository.readAll (
87
- pagination: PaginationOptions (cursor: state.languagesCursor),
88
- sort: [const SortOption ('name' , SortOrder .asc)],
89
- );
90
- emit (
91
- state.copyWith (
92
- languages: List .of (state.languages)..addAll (nextLanguages.items),
93
- languagesCursor: nextLanguages.cursor,
94
- languagesHasMore: nextLanguages.hasMore,
95
- ),
96
- );
84
+ if (state.languagesHasMore) {
85
+ add (const _FetchNextLanguagePage ());
97
86
}
98
87
} on HttpException catch (e) {
99
88
emit (state.copyWith (status: CreateSourceStatus .failure, exception: e));
@@ -161,6 +150,83 @@ class CreateSourceBloc extends Bloc<CreateSourceEvent, CreateSourceState> {
161
150
);
162
151
}
163
152
153
+ // --- Background Data Fetching for Dropdown ---
154
+ // The DropdownButtonFormField widget does not natively support on-scroll
155
+ // pagination. To preserve UI consistency across the application, this BLoC
156
+ // employs an event-driven background fetching mechanism.
157
+ //
158
+ // After the first page of items is loaded, a chain of events is initiated
159
+ // to progressively fetch all remaining pages. This process is throttled
160
+ // and runs in the background, ensuring the UI remains responsive while the
161
+ // full list of dropdown options is populated over time.
162
+ Future <void > _onFetchNextCountryPage (
163
+ _FetchNextCountryPage event,
164
+ Emitter <CreateSourceState > emit,
165
+ ) async {
166
+ if (! state.countriesHasMore || state.countriesIsLoadingMore) return ;
167
+
168
+ try {
169
+ emit (state.copyWith (countriesIsLoadingMore: true ));
170
+
171
+ await Future .delayed (const Duration (milliseconds: 400 ));
172
+
173
+ final nextCountries = await _countriesRepository.readAll (
174
+ pagination: PaginationOptions (cursor: state.countriesCursor),
175
+ sort: [const SortOption ('name' , SortOrder .asc)],
176
+ );
177
+
178
+ emit (
179
+ state.copyWith (
180
+ countries: List .of (state.countries)..addAll (nextCountries.items),
181
+ countriesCursor: nextCountries.cursor,
182
+ countriesHasMore: nextCountries.hasMore,
183
+ countriesIsLoadingMore: false ,
184
+ ),
185
+ );
186
+
187
+ if (nextCountries.hasMore) {
188
+ add (const _FetchNextCountryPage ());
189
+ }
190
+ } catch (e) {
191
+ emit (state.copyWith (countriesIsLoadingMore: false ));
192
+ // Optionally log the error without disrupting the user
193
+ }
194
+ }
195
+
196
+ Future <void > _onFetchNextLanguagePage (
197
+ _FetchNextLanguagePage event,
198
+ Emitter <CreateSourceState > emit,
199
+ ) async {
200
+ if (! state.languagesHasMore || state.languagesIsLoadingMore) return ;
201
+
202
+ try {
203
+ emit (state.copyWith (languagesIsLoadingMore: true ));
204
+
205
+ await Future .delayed (const Duration (milliseconds: 400 ));
206
+
207
+ final nextLanguages = await _languagesRepository.readAll (
208
+ pagination: PaginationOptions (cursor: state.languagesCursor),
209
+ sort: [const SortOption ('name' , SortOrder .asc)],
210
+ );
211
+
212
+ emit (
213
+ state.copyWith (
214
+ languages: List .of (state.languages)..addAll (nextLanguages.items),
215
+ languagesCursor: nextLanguages.cursor,
216
+ languagesHasMore: nextLanguages.hasMore,
217
+ languagesIsLoadingMore: false ,
218
+ ),
219
+ );
220
+
221
+ if (nextLanguages.hasMore) {
222
+ add (const _FetchNextLanguagePage ());
223
+ }
224
+ } catch (e) {
225
+ emit (state.copyWith (languagesIsLoadingMore: false ));
226
+ // Optionally log the error without disrupting the user
227
+ }
228
+ }
229
+
164
230
Future <void > _onSubmitted (
165
231
CreateSourceSubmitted event,
166
232
Emitter <CreateSourceState > emit,
0 commit comments