Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 6a2c49a

Browse files
authored
Merge pull request #17 from headlines-toolkit/fix_data_fetching_in_content_management
Fix data fetching in content management
2 parents 6db818d + a476def commit 6a2c49a

File tree

11 files changed

+198
-75
lines changed

11 files changed

+198
-75
lines changed

‎lib/content_management/bloc/content_management_bloc.dart‎

Lines changed: 40 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import 'package:bloc/bloc.dart';
22
import 'package:equatable/equatable.dart';
33
import 'package:ht_data_repository/ht_data_repository.dart';
4+
import 'package:ht_dashboard/shared/constants/pagination_constants.dart';
45
import 'package:ht_shared/ht_shared.dart';
56

67
part 'content_management_event.dart';
@@ -60,14 +61,17 @@ class ContentManagementBloc
6061
) async {
6162
emit(state.copyWith(headlinesStatus: ContentManagementStatus.loading));
6263
try {
64+
final isPaginating = event.startAfterId != null;
65+
final previousHeadlines = isPaginating ? state.headlines : <Headline>[];
66+
6367
final paginatedHeadlines = await _headlinesRepository.readAll(
6468
startAfterId: event.startAfterId,
6569
limit: event.limit,
6670
);
6771
emit(
6872
state.copyWith(
6973
headlinesStatus: ContentManagementStatus.success,
70-
headlines: paginatedHeadlines.items,
74+
headlines: [...previousHeadlines, ...paginatedHeadlines.items],
7175
headlinesCursor: paginatedHeadlines.cursor,
7276
headlinesHasMore: paginatedHeadlines.hasMore,
7377
),
@@ -97,7 +101,9 @@ class ContentManagementBloc
97101
try {
98102
await _headlinesRepository.create(item: event.headline);
99103
// Reload headlines after creation
100-
add(const LoadHeadlinesRequested());
104+
add(
105+
const LoadHeadlinesRequested(limit: kDefaultRowsPerPage),
106+
);
101107
} on HtHttpException catch (e) {
102108
emit(
103109
state.copyWith(
@@ -123,7 +129,9 @@ class ContentManagementBloc
123129
try {
124130
await _headlinesRepository.update(id: event.id, item: event.headline);
125131
// Reload headlines after update
126-
add(const LoadHeadlinesRequested());
132+
add(
133+
const LoadHeadlinesRequested(limit: kDefaultRowsPerPage),
134+
);
127135
} on HtHttpException catch (e) {
128136
emit(
129137
state.copyWith(
@@ -149,7 +157,9 @@ class ContentManagementBloc
149157
try {
150158
await _headlinesRepository.delete(id: event.id);
151159
// Reload headlines after deletion
152-
add(const LoadHeadlinesRequested());
160+
add(
161+
const LoadHeadlinesRequested(limit: kDefaultRowsPerPage),
162+
);
153163
} on HtHttpException catch (e) {
154164
emit(
155165
state.copyWith(
@@ -173,14 +183,17 @@ class ContentManagementBloc
173183
) async {
174184
emit(state.copyWith(categoriesStatus: ContentManagementStatus.loading));
175185
try {
186+
final isPaginating = event.startAfterId != null;
187+
final previousCategories = isPaginating ? state.categories : <Category>[];
188+
176189
final paginatedCategories = await _categoriesRepository.readAll(
177190
startAfterId: event.startAfterId,
178191
limit: event.limit,
179192
);
180193
emit(
181194
state.copyWith(
182195
categoriesStatus: ContentManagementStatus.success,
183-
categories: paginatedCategories.items,
196+
categories: [...previousCategories, ...paginatedCategories.items],
184197
categoriesCursor: paginatedCategories.cursor,
185198
categoriesHasMore: paginatedCategories.hasMore,
186199
),
@@ -210,7 +223,9 @@ class ContentManagementBloc
210223
try {
211224
await _categoriesRepository.create(item: event.category);
212225
// Reload categories after creation
213-
add(const LoadCategoriesRequested());
226+
add(
227+
const LoadCategoriesRequested(limit: kDefaultRowsPerPage),
228+
);
214229
} on HtHttpException catch (e) {
215230
emit(
216231
state.copyWith(
@@ -236,7 +251,9 @@ class ContentManagementBloc
236251
try {
237252
await _categoriesRepository.update(id: event.id, item: event.category);
238253
// Reload categories after update
239-
add(const LoadCategoriesRequested());
254+
add(
255+
const LoadCategoriesRequested(limit: kDefaultRowsPerPage),
256+
);
240257
} on HtHttpException catch (e) {
241258
emit(
242259
state.copyWith(
@@ -262,7 +279,9 @@ class ContentManagementBloc
262279
try {
263280
await _categoriesRepository.delete(id: event.id);
264281
// Reload categories after deletion
265-
add(const LoadCategoriesRequested());
282+
add(
283+
const LoadCategoriesRequested(limit: kDefaultRowsPerPage),
284+
);
266285
} on HtHttpException catch (e) {
267286
emit(
268287
state.copyWith(
@@ -286,14 +305,17 @@ class ContentManagementBloc
286305
) async {
287306
emit(state.copyWith(sourcesStatus: ContentManagementStatus.loading));
288307
try {
308+
final isPaginating = event.startAfterId != null;
309+
final previousSources = isPaginating ? state.sources : <Source>[];
310+
289311
final paginatedSources = await _sourcesRepository.readAll(
290312
startAfterId: event.startAfterId,
291313
limit: event.limit,
292314
);
293315
emit(
294316
state.copyWith(
295317
sourcesStatus: ContentManagementStatus.success,
296-
sources: paginatedSources.items,
318+
sources: [...previousSources, ...paginatedSources.items],
297319
sourcesCursor: paginatedSources.cursor,
298320
sourcesHasMore: paginatedSources.hasMore,
299321
),
@@ -323,7 +345,9 @@ class ContentManagementBloc
323345
try {
324346
await _sourcesRepository.create(item: event.source);
325347
// Reload sources after creation
326-
add(const LoadSourcesRequested());
348+
add(
349+
const LoadSourcesRequested(limit: kDefaultRowsPerPage),
350+
);
327351
} on HtHttpException catch (e) {
328352
emit(
329353
state.copyWith(
@@ -349,7 +373,9 @@ class ContentManagementBloc
349373
try {
350374
await _sourcesRepository.update(id: event.id, item: event.source);
351375
// Reload sources after update
352-
add(const LoadSourcesRequested());
376+
add(
377+
const LoadSourcesRequested(limit: kDefaultRowsPerPage),
378+
);
353379
} on HtHttpException catch (e) {
354380
emit(
355381
state.copyWith(
@@ -375,7 +401,9 @@ class ContentManagementBloc
375401
try {
376402
await _sourcesRepository.delete(id: event.id);
377403
// Reload sources after deletion
378-
add(const LoadSourcesRequested());
404+
add(
405+
const LoadSourcesRequested(limit: kDefaultRowsPerPage),
406+
);
379407
} on HtHttpException catch (e) {
380408
emit(
381409
state.copyWith(

‎lib/content_management/view/categories_page.dart‎

Lines changed: 42 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import 'package:ht_dashboard/content_management/bloc/content_management_bloc.dar
66
import 'package:ht_dashboard/l10n/app_localizations.dart';
77
import 'package:ht_dashboard/l10n/l10n.dart';
88
import 'package:ht_dashboard/router/routes.dart';
9+
import 'package:ht_dashboard/shared/constants/pagination_constants.dart';
910
import 'package:ht_dashboard/shared/constants/app_spacing.dart';
1011
import 'package:ht_dashboard/shared/widgets/failure_state_widget.dart';
1112
import 'package:ht_dashboard/shared/widgets/loading_state_widget.dart';
@@ -23,14 +24,12 @@ class CategoriesPage extends StatefulWidget {
2324
}
2425

2526
class _CategoriesPageState extends State<CategoriesPage> {
26-
static const int _rowsPerPage = 10;
27-
2827
@override
2928
void initState() {
3029
super.initState();
3130
context.read<ContentManagementBloc>().add(
32-
const LoadCategoriesRequested(limit: _rowsPerPage),
33-
);
31+
const LoadCategoriesRequested(limit: kDefaultRowsPerPage),
32+
);
3433
}
3534

3635
@override
@@ -53,8 +52,8 @@ class _CategoriesPageState extends State<CategoriesPage> {
5352
return FailureStateWidget(
5453
message: state.errorMessage ?? l10n.unknownError,
5554
onRetry: () => context.read<ContentManagementBloc>().add(
56-
const LoadCategoriesRequested(limit: _rowsPerPage),
57-
),
55+
const LoadCategoriesRequested(limit: kDefaultRowsPerPage),
56+
),
5857
);
5958
}
6059

@@ -82,20 +81,23 @@ class _CategoriesPageState extends State<CategoriesPage> {
8281
source: _CategoriesDataSource(
8382
context: context,
8483
categories: state.categories,
84+
isLoading: state.categoriesStatus == ContentManagementStatus.loading,
85+
hasMore: state.categoriesHasMore,
8586
l10n: l10n,
8687
),
87-
rowsPerPage: _rowsPerPage,
88-
availableRowsPerPage: const [_rowsPerPage],
88+
rowsPerPage: kDefaultRowsPerPage,
89+
availableRowsPerPage: const [kDefaultRowsPerPage],
8990
onPageChanged: (pageIndex) {
90-
final newOffset = pageIndex * _rowsPerPage;
91+
final newOffset = pageIndex * kDefaultRowsPerPage;
9192
if (newOffset >= state.categories.length &&
92-
state.categoriesHasMore) {
93+
state.categoriesHasMore &&
94+
state.categoriesStatus != ContentManagementStatus.loading) {
9395
context.read<ContentManagementBloc>().add(
94-
LoadCategoriesRequested(
95-
startAfterId: state.categoriesCursor,
96-
limit: _rowsPerPage,
97-
),
98-
);
96+
LoadCategoriesRequested(
97+
startAfterId: state.categoriesCursor,
98+
limit: kDefaultRowsPerPage,
99+
),
100+
);
99101
}
100102
},
101103
empty: Center(child: Text(l10n.noCategoriesFound)),
@@ -117,16 +119,27 @@ class _CategoriesDataSource extends DataTableSource {
117119
_CategoriesDataSource({
118120
required this.context,
119121
required this.categories,
122+
required this.isLoading,
123+
required this.hasMore,
120124
required this.l10n,
121125
});
122126

123127
final BuildContext context;
124128
final List<Category> categories;
129+
final bool isLoading;
130+
final bool hasMore;
125131
final AppLocalizations l10n;
126132

127133
@override
128134
DataRow? getRow(int index) {
129135
if (index >= categories.length) {
136+
// This can happen if hasMore is true and the user is on the last page.
137+
// If we are loading, show a spinner. Otherwise, we've reached the end.
138+
if (isLoading) {
139+
return DataRow2(
140+
cells: List.generate(3, (_) => const DataCell(Center(child: CircularProgressIndicator()))),
141+
);
142+
}
130143
return null;
131144
}
132145
final category = categories[index];
@@ -152,8 +165,8 @@ class _CategoriesDataSource extends DataTableSource {
152165
onPressed: () {
153166
// Dispatch delete event
154167
context.read<ContentManagementBloc>().add(
155-
DeleteCategoryRequested(category.id),
156-
);
168+
DeleteCategoryRequested(category.id),
169+
);
157170
},
158171
),
159172
],
@@ -164,10 +177,20 @@ class _CategoriesDataSource extends DataTableSource {
164177
}
165178

166179
@override
167-
bool get isRowCountApproximate => false;
180+
bool get isRowCountApproximate => hasMore;
168181

169182
@override
170-
int get rowCount => categories.length;
183+
int get rowCount {
184+
// If we have more items to fetch, we add 1 to the current length.
185+
// This signals to PaginatedDataTable2 that there is at least one more page,
186+
// which enables the 'next page' button.
187+
if (hasMore) {
188+
// When loading, we show an extra row for the spinner.
189+
// Otherwise, we just indicate that there are more rows.
190+
return isLoading ? categories.length + 1 : categories.length + kDefaultRowsPerPage;
191+
}
192+
return categories.length;
193+
}
171194

172195
@override
173196
int get selectedRowCount => 0;

‎lib/content_management/view/create_category_page.dart‎

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import 'package:go_router/go_router.dart';
44
import 'package:ht_dashboard/content_management/bloc/content_management_bloc.dart';
55
import 'package:ht_dashboard/content_management/bloc/create_category/create_category_bloc.dart';
66
import 'package:ht_dashboard/l10n/l10n.dart';
7+
import 'package:ht_dashboard/shared/constants/pagination_constants.dart';
78
import 'package:ht_dashboard/shared/shared.dart';
89
import 'package:ht_data_repository/ht_data_repository.dart';
910
import 'package:ht_shared/ht_shared.dart';
@@ -82,7 +83,9 @@ class _CreateCategoryViewState extends State<_CreateCategoryView> {
8283
),
8384
);
8485
context.read<ContentManagementBloc>().add(
85-
const LoadCategoriesRequested(),
86+
const LoadCategoriesRequested(
87+
limit: kDefaultRowsPerPage,
88+
),
8689
);
8790
context.pop();
8891
}

‎lib/content_management/view/create_headline_page.dart‎

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import 'package:go_router/go_router.dart';
44
import 'package:ht_dashboard/content_management/bloc/content_management_bloc.dart';
55
import 'package:ht_dashboard/content_management/bloc/create_headline/create_headline_bloc.dart';
66
import 'package:ht_dashboard/l10n/l10n.dart';
7+
import 'package:ht_dashboard/shared/constants/pagination_constants.dart';
78
import 'package:ht_dashboard/shared/shared.dart';
89
import 'package:ht_data_repository/ht_data_repository.dart';
910
import 'package:ht_shared/ht_shared.dart';
@@ -84,7 +85,9 @@ class _CreateHeadlineViewState extends State<_CreateHeadlineView> {
8485
),
8586
);
8687
context.read<ContentManagementBloc>().add(
87-
const LoadHeadlinesRequested(),
88+
const LoadHeadlinesRequested(
89+
limit: kDefaultRowsPerPage,
90+
),
8891
);
8992
context.pop();
9093
}

‎lib/content_management/view/create_source_page.dart‎

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import 'package:ht_dashboard/content_management/bloc/content_management_bloc.dar
55
import 'package:ht_dashboard/content_management/bloc/create_source/create_source_bloc.dart';
66
import 'package:ht_dashboard/content_management/bloc/edit_source/edit_source_bloc.dart';
77
import 'package:ht_dashboard/l10n/l10n.dart';
8+
import 'package:ht_dashboard/shared/constants/pagination_constants.dart';
89
import 'package:ht_dashboard/shared/shared.dart';
910
import 'package:ht_data_repository/ht_data_repository.dart';
1011
import 'package:ht_shared/ht_shared.dart';
@@ -82,7 +83,9 @@ class _CreateSourceViewState extends State<_CreateSourceView> {
8283
SnackBar(content: Text(l10n.sourceCreatedSuccessfully)),
8384
);
8485
context.read<ContentManagementBloc>().add(
85-
const LoadSourcesRequested(),
86+
const LoadSourcesRequested(
87+
limit: kDefaultRowsPerPage,
88+
),
8689
);
8790
context.pop();
8891
}

‎lib/content_management/view/edit_category_page.dart‎

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import 'package:go_router/go_router.dart';
44
import 'package:ht_dashboard/content_management/bloc/content_management_bloc.dart';
55
import 'package:ht_dashboard/content_management/bloc/edit_category/edit_category_bloc.dart';
66
import 'package:ht_dashboard/l10n/l10n.dart';
7+
import 'package:ht_dashboard/shared/constants/pagination_constants.dart';
78
import 'package:ht_dashboard/shared/shared.dart';
89
import 'package:ht_data_repository/ht_data_repository.dart';
910
import 'package:ht_shared/ht_shared.dart';
@@ -108,7 +109,9 @@ class _EditCategoryViewState extends State<_EditCategoryView> {
108109
const SnackBar(content: Text('Category updated successfully.')),
109110
);
110111
context.read<ContentManagementBloc>().add(
111-
const LoadCategoriesRequested(),
112+
const LoadCategoriesRequested(
113+
limit: kDefaultRowsPerPage,
114+
),
112115
);
113116
context.pop();
114117
}

‎lib/content_management/view/edit_headline_page.dart‎

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import 'package:go_router/go_router.dart';
44
import 'package:ht_dashboard/content_management/bloc/content_management_bloc.dart';
55
import 'package:ht_dashboard/content_management/bloc/edit_headline/edit_headline_bloc.dart';
66
import 'package:ht_dashboard/l10n/l10n.dart';
7+
import 'package:ht_dashboard/shared/constants/pagination_constants.dart';
78
import 'package:ht_dashboard/shared/shared.dart';
89
import 'package:ht_data_repository/ht_data_repository.dart';
910
import 'package:ht_shared/ht_shared.dart';
@@ -114,7 +115,9 @@ class _EditHeadlineViewState extends State<_EditHeadlineView> {
114115
),
115116
);
116117
context.read<ContentManagementBloc>().add(
117-
const LoadHeadlinesRequested(),
118+
const LoadHeadlinesRequested(
119+
limit: kDefaultRowsPerPage,
120+
),
118121
);
119122
context.pop();
120123
}

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /