Skip to content

Commit 1b13a0f

Browse files
authored
Merge pull request #43 from flutter-news-app-full-source-code/fix-countrries-and-languages-uncomplete-list-in-the-con,tent-managment
Fix countrries and languages uncomplete list in the con,tent managment
2 parents 0cd3394 + 3bb633b commit 1b13a0f

20 files changed

+1108
-160
lines changed

lib/content_management/bloc/create_headline/create_headline_bloc.dart

Lines changed: 85 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import 'package:bloc/bloc.dart';
2+
import 'package:bloc_concurrency/bloc_concurrency.dart';
23
import 'package:core/core.dart';
34
import 'package:data_repository/data_repository.dart';
45
import 'package:equatable/equatable.dart';
@@ -8,6 +9,8 @@ import 'package:uuid/uuid.dart';
89
part 'create_headline_event.dart';
910
part 'create_headline_state.dart';
1011

12+
const _searchDebounceDuration = Duration(milliseconds: 300);
13+
1114
/// A BLoC to manage the state of creating a new headline.
1215
class 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
}

lib/content_management/bloc/create_headline/create_headline_event.dart

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,3 +83,17 @@ final class CreateHeadlineStatusChanged extends CreateHeadlineEvent {
8383
final class CreateHeadlineSubmitted extends CreateHeadlineEvent {
8484
const CreateHeadlineSubmitted();
8585
}
86+
87+
/// Event for when the country search term is changed.
88+
final class CreateHeadlineCountrySearchChanged extends CreateHeadlineEvent {
89+
const CreateHeadlineCountrySearchChanged(this.searchTerm);
90+
final String searchTerm;
91+
@override
92+
List<Object?> get props => [searchTerm];
93+
}
94+
95+
/// Event to request loading more countries.
96+
final class CreateHeadlineLoadMoreCountriesRequested
97+
extends CreateHeadlineEvent {
98+
const CreateHeadlineLoadMoreCountriesRequested();
99+
}

lib/content_management/bloc/create_headline/create_headline_state.dart

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,9 @@ final class CreateHeadlineState extends Equatable {
3232
this.sources = const [],
3333
this.topics = const [],
3434
this.countries = const [],
35+
this.countriesHasMore = true,
36+
this.countriesCursor,
37+
this.countrySearchTerm = '',
3538
this.contentStatus = ContentStatus.active,
3639
this.exception,
3740
this.createdHeadline,
@@ -48,6 +51,9 @@ final class CreateHeadlineState extends Equatable {
4851
final List<Source> sources;
4952
final List<Topic> topics;
5053
final List<Country> countries;
54+
final bool countriesHasMore;
55+
final String? countriesCursor;
56+
final String countrySearchTerm;
5157
final ContentStatus contentStatus;
5258
final HttpException? exception;
5359
final Headline? createdHeadline;
@@ -74,6 +80,9 @@ final class CreateHeadlineState extends Equatable {
7480
List<Source>? sources,
7581
List<Topic>? topics,
7682
List<Country>? countries,
83+
bool? countriesHasMore,
84+
String? countriesCursor,
85+
String? countrySearchTerm,
7786
ContentStatus? contentStatus,
7887
HttpException? exception,
7988
Headline? createdHeadline,
@@ -90,6 +99,9 @@ final class CreateHeadlineState extends Equatable {
9099
sources: sources ?? this.sources,
91100
topics: topics ?? this.topics,
92101
countries: countries ?? this.countries,
102+
countriesHasMore: countriesHasMore ?? this.countriesHasMore,
103+
countriesCursor: countriesCursor ?? this.countriesCursor,
104+
countrySearchTerm: countrySearchTerm ?? this.countrySearchTerm,
93105
contentStatus: contentStatus ?? this.contentStatus,
94106
exception: exception,
95107
createdHeadline: createdHeadline ?? this.createdHeadline,
@@ -109,6 +121,9 @@ final class CreateHeadlineState extends Equatable {
109121
sources,
110122
topics,
111123
countries,
124+
countriesHasMore,
125+
countriesCursor,
126+
countrySearchTerm,
112127
contentStatus,
113128
exception,
114129
createdHeadline,

0 commit comments

Comments
 (0)