@@ -8,26 +8,20 @@ import 'package:uuid/uuid.dart';
88part 'create_source_event.dart' ;
99part 'create_source_state.dart' ;
1010
11- final class _FetchNextCountryPage extends CreateSourceEvent {
12- const _FetchNextCountryPage ();
13- }
14-
15- final class _FetchNextLanguagePage extends CreateSourceEvent {
16- const _FetchNextLanguagePage ();
17- }
18-
1911/// A BLoC to manage the state of creating a new source.
2012class CreateSourceBloc extends Bloc <CreateSourceEvent , CreateSourceState > {
2113 /// {@macro create_source_bloc}
2214 CreateSourceBloc ({
2315 required DataRepository <Source > sourcesRepository,
24- required DataRepository <Country > countriesRepository,
25- required DataRepository <Language > languagesRepository,
26- }) : _sourcesRepository = sourcesRepository,
27- _countriesRepository = countriesRepository,
28- _languagesRepository = languagesRepository,
29- super (const CreateSourceState ()) {
30- on < CreateSourceDataLoaded > (_onDataLoaded);
16+ required List <Country > countries,
17+ required List <Language > languages,
18+ }) : _sourcesRepository = sourcesRepository,
19+ super (
20+ CreateSourceState (
21+ countries: countries,
22+ languages: languages,
23+ ),
24+ ) {
3125 on < CreateSourceNameChanged > (_onNameChanged);
3226 on < CreateSourceDescriptionChanged > (_onDescriptionChanged);
3327 on < CreateSourceUrlChanged > (_onUrlChanged);
@@ -36,65 +30,11 @@ class CreateSourceBloc extends Bloc<CreateSourceEvent, CreateSourceState> {
3630 on < CreateSourceHeadquartersChanged > (_onHeadquartersChanged);
3731 on < CreateSourceStatusChanged > (_onStatusChanged);
3832 on < CreateSourceSubmitted > (_onSubmitted);
39- on < _FetchNextCountryPage > (_onFetchNextCountryPage);
40- on < _FetchNextLanguagePage > (_onFetchNextLanguagePage);
4133 }
4234
4335 final DataRepository <Source > _sourcesRepository;
44- final DataRepository <Country > _countriesRepository;
45- final DataRepository <Language > _languagesRepository;
4636 final _uuid = const Uuid ();
4737
48- Future <void > _onDataLoaded (
49- CreateSourceDataLoaded event,
50- Emitter <CreateSourceState > emit,
51- ) async {
52- emit (state.copyWith (status: CreateSourceStatus .loading));
53- try {
54- final responses = await Future .wait ([
55- _countriesRepository.readAll (
56- sort: [const SortOption ('name' , SortOrder .asc)],
57- filter: {'status' : ContentStatus .active.name},
58- ),
59- _languagesRepository.readAll (
60- sort: [const SortOption ('name' , SortOrder .asc)],
61- filter: {'status' : ContentStatus .active.name},
62- ),
63- ]);
64- final countriesPaginated = responses[0 ] as PaginatedResponse <Country >;
65- final languagesPaginated = responses[1 ] as PaginatedResponse <Language >;
66- emit (
67- state.copyWith (
68- status: CreateSourceStatus .initial,
69- countries: countriesPaginated.items,
70- countriesCursor: countriesPaginated.cursor,
71- countriesHasMore: countriesPaginated.hasMore,
72- languages: languagesPaginated.items,
73- languagesCursor: languagesPaginated.cursor,
74- languagesHasMore: languagesPaginated.hasMore,
75- ),
76- );
77-
78- // After the initial page is loaded, start background processes to
79- // fetch all remaining pages for countries and languages.
80- if (state.countriesHasMore) {
81- add (const _FetchNextCountryPage ());
82- }
83- if (state.languagesHasMore) {
84- add (const _FetchNextLanguagePage ());
85- }
86- } on HttpException catch (e) {
87- emit (state.copyWith (status: CreateSourceStatus .failure, exception: e));
88- } catch (e) {
89- emit (
90- state.copyWith (
91- status: CreateSourceStatus .failure,
92- exception: UnknownException ('An unexpected error occurred: $e ' ),
93- ),
94- );
95- }
96- }
97-
9838 void _onNameChanged (
9939 CreateSourceNameChanged event,
10040 Emitter <CreateSourceState > emit,
@@ -150,84 +90,6 @@ class CreateSourceBloc extends Bloc<CreateSourceEvent, CreateSourceState> {
15090 }
15191
15292 // --- Background Data Fetching for Dropdown ---
153- // The DropdownButtonFormField widget does not natively support on-scroll
154- // pagination. To preserve UI consistency across the application, this BLoC
155- // employs an event-driven background fetching mechanism.
156- //
157- // After the first page of items is loaded, a chain of events is initiated
158- // to progressively fetch all remaining pages. This process is throttled
159- // and runs in the background, ensuring the UI remains responsive while the
160- // full list of dropdown options is populated over time.
161- Future <void > _onFetchNextCountryPage (
162- _FetchNextCountryPage event,
163- Emitter <CreateSourceState > emit,
164- ) async {
165- if (! state.countriesHasMore || state.countriesIsLoadingMore) return ;
166-
167- try {
168- emit (state.copyWith (countriesIsLoadingMore: true ));
169-
170- // ignore: inference_failure_on_instance_creation
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- // ignore: inference_failure_on_instance_creation
206- await Future .delayed (const Duration (milliseconds: 400 ));
207-
208- final nextLanguages = await _languagesRepository.readAll (
209- pagination: PaginationOptions (cursor: state.languagesCursor),
210- sort: [const SortOption ('name' , SortOrder .asc)],
211- );
212-
213- emit (
214- state.copyWith (
215- languages: List .of (state.languages)..addAll (nextLanguages.items),
216- languagesCursor: nextLanguages.cursor,
217- languagesHasMore: nextLanguages.hasMore,
218- languagesIsLoadingMore: false ,
219- ),
220- );
221-
222- if (nextLanguages.hasMore) {
223- add (const _FetchNextLanguagePage ());
224- }
225- } catch (e) {
226- emit (state.copyWith (languagesIsLoadingMore: false ));
227- // Optionally log the error without disrupting the user
228- }
229- }
230-
23193 Future <void > _onSubmitted (
23294 CreateSourceSubmitted event,
23395 Emitter <CreateSourceState > emit,
0 commit comments