Skip to content

Commit c6f1e51

Browse files
committed
refactor(content_management): simplify country dropdown pagination
- Remove background fetching mechanism for countries list - Load all countries at once in CreateHeadlineBloc initialization - Remove unnecessary country-related state properties from CreateHeadlineState - Update CreateHeadlinePage to use pre-loaded countries list - Remove _FetchNextCountryPage event and related handling
1 parent cdc1b4c commit c6f1e51

File tree

3 files changed

+13
-93
lines changed

3 files changed

+13
-93
lines changed

lib/content_management/bloc/create_headline/create_headline_bloc.dart

Lines changed: 5 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,6 @@ import 'package:uuid/uuid.dart';
88
part 'create_headline_event.dart';
99
part 'create_headline_state.dart';
1010

11-
final class _FetchNextCountryPage extends CreateHeadlineEvent {
12-
const _FetchNextCountryPage();
13-
}
14-
1511
/// A BLoC to manage the state of creating a new headline.
1612
class CreateHeadlineBloc
1713
extends Bloc<CreateHeadlineEvent, CreateHeadlineState> {
@@ -20,12 +16,11 @@ class CreateHeadlineBloc
2016
required DataRepository<Headline> headlinesRepository,
2117
required DataRepository<Source> sourcesRepository,
2218
required DataRepository<Topic> topicsRepository,
23-
required DataRepository<Country> countriesRepository,
24-
}) : _headlinesRepository = headlinesRepository,
25-
_sourcesRepository = sourcesRepository,
26-
_topicsRepository = topicsRepository,
27-
_countriesRepository = countriesRepository,
28-
super(const CreateHeadlineState()) {
19+
required List<Country> countries,
20+
}) : _headlinesRepository = headlinesRepository,
21+
_sourcesRepository = sourcesRepository,
22+
_topicsRepository = topicsRepository,
23+
super(CreateHeadlineState(countries: countries)) {
2924
on<CreateHeadlineDataLoaded>(_onDataLoaded);
3025
on<CreateHeadlineTitleChanged>(_onTitleChanged);
3126
on<CreateHeadlineExcerptChanged>(_onExcerptChanged);
@@ -36,13 +31,11 @@ class CreateHeadlineBloc
3631
on<CreateHeadlineCountryChanged>(_onCountryChanged);
3732
on<CreateHeadlineStatusChanged>(_onStatusChanged);
3833
on<CreateHeadlineSubmitted>(_onSubmitted);
39-
on<_FetchNextCountryPage>(_onFetchNextCountryPage);
4034
}
4135

4236
final DataRepository<Headline> _headlinesRepository;
4337
final DataRepository<Source> _sourcesRepository;
4438
final DataRepository<Topic> _topicsRepository;
45-
final DataRepository<Country> _countriesRepository;
4639
final _uuid = const Uuid();
4740

4841
Future<void> _onDataLoaded(
@@ -65,26 +58,13 @@ class CreateHeadlineBloc
6558
final sources = (sourcesResponse as PaginatedResponse<Source>).items;
6659
final topics = (topicsResponse as PaginatedResponse<Topic>).items;
6760

68-
final countriesResponse = await _countriesRepository.readAll(
69-
sort: [const SortOption('name', SortOrder.asc)],
70-
);
71-
7261
emit(
7362
state.copyWith(
7463
status: CreateHeadlineStatus.initial,
7564
sources: sources,
7665
topics: topics,
77-
countries: countriesResponse.items,
78-
countriesCursor: countriesResponse.cursor,
79-
countriesHasMore: countriesResponse.hasMore,
8066
),
8167
);
82-
83-
// After the initial page of countries is loaded, start a background
84-
// process to fetch all remaining pages.
85-
if (state.countriesHasMore) {
86-
add(const _FetchNextCountryPage());
87-
}
8868
} on HttpException catch (e) {
8969
emit(state.copyWith(status: CreateHeadlineStatus.failure, exception: e));
9070
} catch (e) {
@@ -159,49 +139,6 @@ class CreateHeadlineBloc
159139
}
160140

161141
// --- Background Data Fetching for Dropdown ---
162-
// The DropdownButtonFormField widget does not natively support on-scroll
163-
// pagination. To preserve UI consistency across the application, this BLoC
164-
// employs an event-driven background fetching mechanism.
165-
//
166-
// After the first page of items is loaded, a chain of events is initiated
167-
// to progressively fetch all remaining pages. This process is throttled
168-
// and runs in the background, ensuring the UI remains responsive while the
169-
// full list of dropdown options is populated over time.
170-
Future<void> _onFetchNextCountryPage(
171-
_FetchNextCountryPage event,
172-
Emitter<CreateHeadlineState> emit,
173-
) async {
174-
if (!state.countriesHasMore || state.countriesIsLoadingMore) return;
175-
176-
try {
177-
emit(state.copyWith(countriesIsLoadingMore: true));
178-
179-
// ignore: inference_failure_on_instance_creation
180-
await Future.delayed(const Duration(milliseconds: 400));
181-
182-
final nextCountries = await _countriesRepository.readAll(
183-
pagination: PaginationOptions(cursor: state.countriesCursor),
184-
sort: [const SortOption('name', SortOrder.asc)],
185-
);
186-
187-
emit(
188-
state.copyWith(
189-
countries: List.of(state.countries)..addAll(nextCountries.items),
190-
countriesCursor: nextCountries.cursor,
191-
countriesHasMore: nextCountries.hasMore,
192-
countriesIsLoadingMore: false,
193-
),
194-
);
195-
196-
if (nextCountries.hasMore) {
197-
add(const _FetchNextCountryPage());
198-
}
199-
} catch (e) {
200-
emit(state.copyWith(countriesIsLoadingMore: false));
201-
// Optionally log the error without disrupting the user
202-
}
203-
}
204-
205142
Future<void> _onSubmitted(
206143
CreateHeadlineSubmitted event,
207144
Emitter<CreateHeadlineState> emit,

lib/content_management/bloc/create_headline/create_headline_state.dart

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,6 @@ final class CreateHeadlineState extends Equatable {
3232
this.sources = const [],
3333
this.topics = const [],
3434
this.countries = const [],
35-
this.countriesHasMore = true,
36-
this.countriesIsLoadingMore = false,
37-
this.countriesCursor,
3835
this.contentStatus = ContentStatus.active,
3936
this.exception,
4037
this.createdHeadline,
@@ -51,9 +48,6 @@ final class CreateHeadlineState extends Equatable {
5148
final List<Source> sources;
5249
final List<Topic> topics;
5350
final List<Country> countries;
54-
final bool countriesHasMore;
55-
final bool countriesIsLoadingMore;
56-
final String? countriesCursor;
5751
final ContentStatus contentStatus;
5852
final HttpException? exception;
5953
final Headline? createdHeadline;
@@ -80,9 +74,6 @@ final class CreateHeadlineState extends Equatable {
8074
List<Source>? sources,
8175
List<Topic>? topics,
8276
List<Country>? countries,
83-
bool? countriesHasMore,
84-
bool? countriesIsLoadingMore,
85-
String? countriesCursor,
8677
ContentStatus? contentStatus,
8778
HttpException? exception,
8879
Headline? createdHeadline,
@@ -99,10 +90,6 @@ final class CreateHeadlineState extends Equatable {
9990
sources: sources ?? this.sources,
10091
topics: topics ?? this.topics,
10192
countries: countries ?? this.countries,
102-
countriesHasMore: countriesHasMore ?? this.countriesHasMore,
103-
countriesIsLoadingMore:
104-
countriesIsLoadingMore ?? this.countriesIsLoadingMore,
105-
countriesCursor: countriesCursor ?? this.countriesCursor,
10693
contentStatus: contentStatus ?? this.contentStatus,
10794
exception: exception,
10895
createdHeadline: createdHeadline ?? this.createdHeadline,
@@ -122,9 +109,6 @@ final class CreateHeadlineState extends Equatable {
122109
sources,
123110
topics,
124111
countries,
125-
countriesHasMore,
126-
countriesIsLoadingMore,
127-
countriesCursor,
128112
contentStatus,
129113
exception,
130114
createdHeadline,

lib/content_management/view/create_headline_page.dart

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,16 @@ class CreateHeadlinePage extends StatelessWidget {
2020

2121
@override
2222
Widget build(BuildContext context) {
23+
// The list of all countries is fetched once and cached in the
24+
// ContentManagementBloc. We read it here and provide it to the
25+
// CreateHeadlineBloc.
26+
final allCountries = context.read<ContentManagementBloc>().state.allCountries;
2327
return BlocProvider(
2428
create: (context) => CreateHeadlineBloc(
2529
headlinesRepository: context.read<DataRepository<Headline>>(),
2630
sourcesRepository: context.read<DataRepository<Source>>(),
2731
topicsRepository: context.read<DataRepository<Topic>>(),
28-
countriesRepository: context.read<DataRepository<Country>>(),
32+
countries: allCountries,
2933
)..add(const CreateHeadlineDataLoaded()),
3034
child: const _CreateHeadlineView(),
3135
);
@@ -220,9 +224,6 @@ class _CreateHeadlineViewState extends State<_CreateHeadlineView> {
220224
decoration: InputDecoration(
221225
labelText: l10n.countryName,
222226
border: const OutlineInputBorder(),
223-
helperText: state.countriesIsLoadingMore
224-
? l10n.loadingFullList
225-
: null,
226227
),
227228
items: [
228229
DropdownMenuItem(value: null, child: Text(l10n.none)),
@@ -249,11 +250,9 @@ class _CreateHeadlineViewState extends State<_CreateHeadlineView> {
249250
),
250251
),
251252
],
252-
onChanged: state.countriesIsLoadingMore
253-
? null
254-
: (value) => context.read<CreateHeadlineBloc>().add(
255-
CreateHeadlineCountryChanged(value),
256-
),
253+
onChanged: (value) => context
254+
.read<CreateHeadlineBloc>()
255+
.add(CreateHeadlineCountryChanged(value)),
257256
),
258257
const SizedBox(height: AppSpacing.lg),
259258
DropdownButtonFormField<ContentStatus>(

0 commit comments

Comments
 (0)