11import 'package:bloc/bloc.dart' ;
2+ import 'package:bloc_concurrency/bloc_concurrency.dart' ;
23import 'package:core/core.dart' ;
34import 'package:data_repository/data_repository.dart' ;
45import 'package:equatable/equatable.dart' ;
@@ -8,6 +9,8 @@ import 'package:uuid/uuid.dart';
89part 'create_headline_event.dart' ;
910part 'create_headline_state.dart' ;
1011
12+ const _searchDebounceDuration = Duration (milliseconds: 300 );
13+
1114/// A BLoC to manage the state of creating a new headline.
1215class CreateHeadlineBloc
1316 extends Bloc <CreateHeadlineEvent , CreateHeadlineState > {
@@ -32,6 +35,12 @@ class CreateHeadlineBloc
3235 on < CreateHeadlineCountryChanged > (_onCountryChanged);
3336 on < CreateHeadlineStatusChanged > (_onStatusChanged);
3437 on < CreateHeadlineSubmitted > (_onSubmitted);
38+ on < CreateHeadlineCountrySearchChanged > (
39+ _onCountrySearchChanged,
40+ transformer: restartable (),
41+ );
42+ on < CreateHeadlineLoadMoreCountriesRequested > (
43+ _onLoadMoreCountriesRequested);
3544 }
3645
3746 final DataRepository <Headline > _headlinesRepository;
@@ -46,33 +55,30 @@ class CreateHeadlineBloc
4655 ) async {
4756 emit (state.copyWith (status: CreateHeadlineStatus .loading));
4857 try {
49- final [
50- sourcesResponse,
51- topicsResponse,
52- countriesResponse,
53- ] = await Future .wait ([
58+ final [sourcesResponse, topicsResponse] = await Future .wait ([
5459 _sourcesRepository.readAll (
5560 sort: [const SortOption ('updatedAt' , SortOrder .desc)],
5661 ),
5762 _topicsRepository.readAll (
5863 sort: [const SortOption ('updatedAt' , SortOrder .desc)],
5964 ),
60- _countriesRepository.readAll (
61- sort: [const SortOption ('name' , SortOrder .asc)],
62- ),
6365 ]);
6466
6567 final sources = (sourcesResponse as PaginatedResponse <Source >).items;
6668 final topics = (topicsResponse as PaginatedResponse <Topic >).items;
67- final countries =
68- (countriesResponse as PaginatedResponse <Country >).items;
69+
70+ final countriesResponse = await _countriesRepository.readAll (
71+ sort: [const SortOption ('name' , SortOrder .asc)],
72+ );
6973
7074 emit (
7175 state.copyWith (
7276 status: CreateHeadlineStatus .initial,
7377 sources: sources,
7478 topics: topics,
75- countries: countries,
79+ countries: countriesResponse.items,
80+ countriesCursor: countriesResponse.cursor,
81+ countriesHasMore: countriesResponse.hasMore,
7682 ),
7783 );
7884 } on HttpException catch (e) {
@@ -189,4 +195,72 @@ class CreateHeadlineBloc
189195 );
190196 }
191197 }
198+
199+ Future <void > _onCountrySearchChanged (
200+ CreateHeadlineCountrySearchChanged event,
201+ Emitter <CreateHeadlineState > emit,
202+ ) async {
203+ await Future <void >.delayed (_searchDebounceDuration);
204+ emit (state.copyWith (countrySearchTerm: event.searchTerm));
205+ try {
206+ final countriesResponse = await _countriesRepository.readAll (
207+ filter:
208+ event.searchTerm.isNotEmpty ? {'name' : event.searchTerm} : null ,
209+ sort: [const SortOption ('name' , SortOrder .asc)],
210+ );
211+
212+ emit (
213+ state.copyWith (
214+ countries: countriesResponse.items,
215+ countriesCursor: countriesResponse.cursor,
216+ countriesHasMore: countriesResponse.hasMore,
217+ ),
218+ );
219+ } on HttpException catch (e) {
220+ emit (state.copyWith (status: CreateHeadlineStatus .failure, exception: e));
221+ } catch (e) {
222+ emit (
223+ state.copyWith (
224+ status: CreateHeadlineStatus .failure,
225+ exception: UnknownException ('An unexpected error occurred: $e ' ),
226+ ),
227+ );
228+ }
229+ }
230+
231+ Future <void > _onLoadMoreCountriesRequested (
232+ CreateHeadlineLoadMoreCountriesRequested event,
233+ Emitter <CreateHeadlineState > emit,
234+ ) async {
235+ if (! state.countriesHasMore) return ;
236+
237+ try {
238+ final countriesResponse = await _countriesRepository.readAll (
239+ pagination: state.countriesCursor != null
240+ ? PaginationOptions (cursor: state.countriesCursor)
241+ : null ,
242+ filter: state.countrySearchTerm.isNotEmpty
243+ ? {'name' : state.countrySearchTerm}
244+ : null ,
245+ sort: [const SortOption ('name' , SortOrder .asc)],
246+ );
247+
248+ emit (
249+ state.copyWith (
250+ countries: List .of (state.countries)..addAll (countriesResponse.items),
251+ countriesCursor: countriesResponse.cursor,
252+ countriesHasMore: countriesResponse.hasMore,
253+ ),
254+ );
255+ } on HttpException catch (e) {
256+ emit (state.copyWith (status: CreateHeadlineStatus .failure, exception: e));
257+ } catch (e) {
258+ emit (
259+ state.copyWith (
260+ status: CreateHeadlineStatus .failure,
261+ exception: UnknownException ('An unexpected error occurred: $e ' ),
262+ ),
263+ );
264+ }
265+ }
192266}
0 commit comments