@@ -7,27 +7,22 @@ import 'package:flutter/foundation.dart';
77part 'edit_source_event.dart' ;
88part 'edit_source_state.dart' ;
99
10- final class _FetchNextCountryPage extends EditSourceEvent {
11- const _FetchNextCountryPage ();
12- }
13-
14- final class _FetchNextLanguagePage extends EditSourceEvent {
15- const _FetchNextLanguagePage ();
16- }
17-
1810/// A BLoC to manage the state of editing a single source.
1911class EditSourceBloc extends Bloc <EditSourceEvent , EditSourceState > {
2012 /// {@macro edit_source_bloc}
2113 EditSourceBloc ({
2214 required DataRepository <Source > sourcesRepository,
23- required DataRepository <Country > countriesRepository ,
24- required DataRepository <Language > languagesRepository ,
15+ required List <Country > countries ,
16+ required List <Language > languages ,
2517 required String sourceId,
26- }) : _sourcesRepository = sourcesRepository,
27- _countriesRepository = countriesRepository,
28- _languagesRepository = languagesRepository,
29- _sourceId = sourceId,
30- super (const EditSourceState ()) {
18+ }) : _sourcesRepository = sourcesRepository,
19+ _sourceId = sourceId,
20+ super (
21+ EditSourceState (
22+ countries: countries,
23+ languages: languages,
24+ ),
25+ ) {
3126 on < EditSourceLoaded > (_onLoaded);
3227 on < EditSourceNameChanged > (_onNameChanged);
3328 on < EditSourceDescriptionChanged > (_onDescriptionChanged);
@@ -37,13 +32,9 @@ class EditSourceBloc extends Bloc<EditSourceEvent, EditSourceState> {
3732 on < EditSourceHeadquartersChanged > (_onHeadquartersChanged);
3833 on < EditSourceStatusChanged > (_onStatusChanged);
3934 on < EditSourceSubmitted > (_onSubmitted);
40- on < _FetchNextCountryPage > (_onFetchNextCountryPage);
41- on < _FetchNextLanguagePage > (_onFetchNextLanguagePage);
4235 }
4336
4437 final DataRepository <Source > _sourcesRepository;
45- final DataRepository <Country > _countriesRepository;
46- final DataRepository <Language > _languagesRepository;
4738 final String _sourceId;
4839
4940 Future <void > _onLoaded (
@@ -52,32 +43,7 @@ class EditSourceBloc extends Bloc<EditSourceEvent, EditSourceState> {
5243 ) async {
5344 emit (state.copyWith (status: EditSourceStatus .loading));
5445 try {
55- final responses = await Future .wait <dynamic >([
56- _sourcesRepository.read (id: _sourceId),
57- _countriesRepository.readAll (
58- sort: [const SortOption ('name' , SortOrder .asc)],
59- filter: {'status' : ContentStatus .active.name},
60- ),
61- _languagesRepository.readAll (
62- sort: [const SortOption ('name' , SortOrder .asc)],
63- filter: {'status' : ContentStatus .active.name},
64- ),
65- ]);
66-
67- final source = responses[0 ] as Source ;
68- final countriesPaginated = responses[1 ] as PaginatedResponse <Country >;
69- final languagesPaginated = responses[2 ] as PaginatedResponse <Language >;
70-
71- Language ? selectedLanguage;
72- try {
73- // Find the equivalent language object from the full list.
74- // This ensures the DropdownButton can identify it by reference.
75- selectedLanguage = languagesPaginated.items.firstWhere (
76- (listLanguage) => listLanguage.id == source.language.id,
77- );
78- } catch (_) {
79- selectedLanguage = source.language;
80- }
46+ final source = await _sourcesRepository.read (id: _sourceId);
8147
8248 emit (
8349 state.copyWith (
@@ -87,26 +53,11 @@ class EditSourceBloc extends Bloc<EditSourceEvent, EditSourceState> {
8753 description: source.description,
8854 url: source.url,
8955 sourceType: () => source.sourceType,
90- language: () => selectedLanguage ,
56+ language: () => source.language ,
9157 headquarters: () => source.headquarters,
9258 contentStatus: source.status,
93- countries: countriesPaginated.items,
94- countriesCursor: countriesPaginated.cursor,
95- countriesHasMore: countriesPaginated.hasMore,
96- languages: languagesPaginated.items,
97- languagesCursor: languagesPaginated.cursor,
98- languagesHasMore: languagesPaginated.hasMore,
9959 ),
10060 );
101-
102- // After the initial page is loaded, start background processes to
103- // fetch all remaining pages for countries and languages.
104- if (state.countriesHasMore) {
105- add (const _FetchNextCountryPage ());
106- }
107- if (state.languagesHasMore) {
108- add (const _FetchNextLanguagePage ());
109- }
11061 } on HttpException catch (e) {
11162 emit (state.copyWith (status: EditSourceStatus .failure, exception: e));
11263 } catch (e) {
@@ -194,84 +145,6 @@ class EditSourceBloc extends Bloc<EditSourceEvent, EditSourceState> {
194145 }
195146
196147 // --- Background Data Fetching for Dropdown ---
197- // The DropdownButtonFormField widget does not natively support on-scroll
198- // pagination. To preserve UI consistency across the application, this BLoC
199- // employs an event-driven background fetching mechanism.
200- //
201- // After the first page of items is loaded, a chain of events is initiated
202- // to progressively fetch all remaining pages. This process is throttled
203- // and runs in the background, ensuring the UI remains responsive while the
204- // full list of dropdown options is populated over time.
205- Future <void > _onFetchNextCountryPage (
206- _FetchNextCountryPage event,
207- Emitter <EditSourceState > emit,
208- ) async {
209- if (! state.countriesHasMore || state.countriesIsLoadingMore) return ;
210-
211- try {
212- emit (state.copyWith (countriesIsLoadingMore: true ));
213-
214- // ignore: inference_failure_on_instance_creation
215- await Future .delayed (const Duration (milliseconds: 400 ));
216-
217- final nextCountries = await _countriesRepository.readAll (
218- pagination: PaginationOptions (cursor: state.countriesCursor),
219- sort: [const SortOption ('name' , SortOrder .asc)],
220- );
221-
222- emit (
223- state.copyWith (
224- countries: List .of (state.countries)..addAll (nextCountries.items),
225- countriesCursor: nextCountries.cursor,
226- countriesHasMore: nextCountries.hasMore,
227- countriesIsLoadingMore: false ,
228- ),
229- );
230-
231- if (nextCountries.hasMore) {
232- add (const _FetchNextCountryPage ());
233- }
234- } catch (e) {
235- emit (state.copyWith (countriesIsLoadingMore: false ));
236- // Optionally log the error without disrupting the user
237- }
238- }
239-
240- Future <void > _onFetchNextLanguagePage (
241- _FetchNextLanguagePage event,
242- Emitter <EditSourceState > emit,
243- ) async {
244- if (! state.languagesHasMore || state.languagesIsLoadingMore) return ;
245-
246- try {
247- emit (state.copyWith (languagesIsLoadingMore: true ));
248-
249- // ignore: inference_failure_on_instance_creation
250- await Future .delayed (const Duration (milliseconds: 400 ));
251-
252- final nextLanguages = await _languagesRepository.readAll (
253- pagination: PaginationOptions (cursor: state.languagesCursor),
254- sort: [const SortOption ('name' , SortOrder .asc)],
255- );
256-
257- emit (
258- state.copyWith (
259- languages: List .of (state.languages)..addAll (nextLanguages.items),
260- languagesCursor: nextLanguages.cursor,
261- languagesHasMore: nextLanguages.hasMore,
262- languagesIsLoadingMore: false ,
263- ),
264- );
265-
266- if (nextLanguages.hasMore) {
267- add (const _FetchNextLanguagePage ());
268- }
269- } catch (e) {
270- emit (state.copyWith (languagesIsLoadingMore: false ));
271- // Optionally log the error without disrupting the user
272- }
273- }
274-
275148 Future <void > _onSubmitted (
276149 EditSourceSubmitted event,
277150 Emitter <EditSourceState > emit,
0 commit comments