Skip to content

Commit 84a311d

Browse files
committed
feat: Implement Content Management BLoC
- Manages Headlines, Categories, Sources - Implements CRUD operations - Implements pagination - Handles loading states
1 parent 5d12be5 commit 84a311d

File tree

1 file changed

+395
-0
lines changed

1 file changed

+395
-0
lines changed
Lines changed: 395 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,395 @@
1+
import 'package:bloc/bloc.dart';
2+
import 'package:equatable/equatable.dart';
3+
import 'package:ht_data_repository/ht_data_repository.dart';
4+
import 'package:ht_shared/ht_shared.dart';
5+
6+
part 'content_management_event.dart';
7+
part 'content_management_state.dart';
8+
9+
/// Defines the tabs available in the content management section.
10+
enum ContentManagementTab {
11+
/// Represents the Headlines tab.
12+
headlines,
13+
14+
/// Represents the Categories tab.
15+
categories,
16+
17+
/// Represents the Sources tab.
18+
sources,
19+
}
20+
21+
class ContentManagementBloc
22+
extends Bloc<ContentManagementEvent, ContentManagementState> {
23+
ContentManagementBloc({
24+
required HtDataRepository<Headline> headlinesRepository,
25+
required HtDataRepository<Category> categoriesRepository,
26+
required HtDataRepository<Source> sourcesRepository,
27+
}) : _headlinesRepository = headlinesRepository,
28+
_categoriesRepository = categoriesRepository,
29+
_sourcesRepository = sourcesRepository,
30+
super(const ContentManagementState()) {
31+
on<ContentManagementTabChanged>(_onContentManagementTabChanged);
32+
on<LoadHeadlinesRequested>(_onLoadHeadlinesRequested);
33+
on<CreateHeadlineRequested>(_onCreateHeadlineRequested);
34+
on<UpdateHeadlineRequested>(_onUpdateHeadlineRequested);
35+
on<DeleteHeadlineRequested>(_onDeleteHeadlineRequested);
36+
on<LoadCategoriesRequested>(_onLoadCategoriesRequested);
37+
on<CreateCategoryRequested>(_onCreateCategoryRequested);
38+
on<UpdateCategoryRequested>(_onUpdateCategoryRequested);
39+
on<DeleteCategoryRequested>(_onDeleteCategoryRequested);
40+
on<LoadSourcesRequested>(_onLoadSourcesRequested);
41+
on<CreateSourceRequested>(_onCreateSourceRequested);
42+
on<UpdateSourceRequested>(_onUpdateSourceRequested);
43+
on<DeleteSourceRequested>(_onOnDeleteSourceRequested);
44+
}
45+
46+
final HtDataRepository<Headline> _headlinesRepository;
47+
final HtDataRepository<Category> _categoriesRepository;
48+
final HtDataRepository<Source> _sourcesRepository;
49+
50+
void _onContentManagementTabChanged(
51+
ContentManagementTabChanged event,
52+
Emitter<ContentManagementState> emit,
53+
) {
54+
emit(state.copyWith(activeTab: event.tab));
55+
}
56+
57+
Future<void> _onLoadHeadlinesRequested(
58+
LoadHeadlinesRequested event,
59+
Emitter<ContentManagementState> emit,
60+
) async {
61+
emit(state.copyWith(headlinesStatus: ContentManagementStatus.loading));
62+
try {
63+
final paginatedHeadlines = await _headlinesRepository.readAll(
64+
startAfterId: event.startAfterId,
65+
limit: event.limit,
66+
);
67+
emit(
68+
state.copyWith(
69+
headlinesStatus: ContentManagementStatus.success,
70+
headlines: paginatedHeadlines.items,
71+
headlinesCursor: paginatedHeadlines.cursor,
72+
headlinesHasMore: paginatedHeadlines.hasMore,
73+
),
74+
);
75+
} on HtHttpException catch (e) {
76+
emit(
77+
state.copyWith(
78+
headlinesStatus: ContentManagementStatus.failure,
79+
errorMessage: e.message,
80+
),
81+
);
82+
} catch (e) {
83+
emit(
84+
state.copyWith(
85+
headlinesStatus: ContentManagementStatus.failure,
86+
errorMessage: e.toString(),
87+
),
88+
);
89+
}
90+
}
91+
92+
Future<void> _onCreateHeadlineRequested(
93+
CreateHeadlineRequested event,
94+
Emitter<ContentManagementState> emit,
95+
) async {
96+
emit(state.copyWith(headlinesStatus: ContentManagementStatus.loading));
97+
try {
98+
await _headlinesRepository.create(item: event.headline);
99+
// Reload headlines after creation
100+
add(const LoadHeadlinesRequested());
101+
} on HtHttpException catch (e) {
102+
emit(
103+
state.copyWith(
104+
headlinesStatus: ContentManagementStatus.failure,
105+
errorMessage: e.message,
106+
),
107+
);
108+
} catch (e) {
109+
emit(
110+
state.copyWith(
111+
headlinesStatus: ContentManagementStatus.failure,
112+
errorMessage: e.toString(),
113+
),
114+
);
115+
}
116+
}
117+
118+
Future<void> _onUpdateHeadlineRequested(
119+
UpdateHeadlineRequested event,
120+
Emitter<ContentManagementState> emit,
121+
) async {
122+
emit(state.copyWith(headlinesStatus: ContentManagementStatus.loading));
123+
try {
124+
await _headlinesRepository.update(id: event.id, item: event.headline);
125+
// Reload headlines after update
126+
add(const LoadHeadlinesRequested());
127+
} on HtHttpException catch (e) {
128+
emit(
129+
state.copyWith(
130+
headlinesStatus: ContentManagementStatus.failure,
131+
errorMessage: e.message,
132+
),
133+
);
134+
} catch (e) {
135+
emit(
136+
state.copyWith(
137+
headlinesStatus: ContentManagementStatus.failure,
138+
errorMessage: e.toString(),
139+
),
140+
);
141+
}
142+
}
143+
144+
Future<void> _onDeleteHeadlineRequested(
145+
DeleteHeadlineRequested event,
146+
Emitter<ContentManagementState> emit,
147+
) async {
148+
emit(state.copyWith(headlinesStatus: ContentManagementStatus.loading));
149+
try {
150+
await _headlinesRepository.delete(id: event.id);
151+
// Reload headlines after deletion
152+
add(const LoadHeadlinesRequested());
153+
} on HtHttpException catch (e) {
154+
emit(
155+
state.copyWith(
156+
headlinesStatus: ContentManagementStatus.failure,
157+
errorMessage: e.message,
158+
),
159+
);
160+
} catch (e) {
161+
emit(
162+
state.copyWith(
163+
headlinesStatus: ContentManagementStatus.failure,
164+
errorMessage: e.toString(),
165+
),
166+
);
167+
}
168+
}
169+
170+
Future<void> _onLoadCategoriesRequested(
171+
LoadCategoriesRequested event,
172+
Emitter<ContentManagementState> emit,
173+
) async {
174+
emit(state.copyWith(categoriesStatus: ContentManagementStatus.loading));
175+
try {
176+
final paginatedCategories = await _categoriesRepository.readAll(
177+
startAfterId: event.startAfterId,
178+
limit: event.limit,
179+
);
180+
emit(
181+
state.copyWith(
182+
categoriesStatus: ContentManagementStatus.success,
183+
categories: paginatedCategories.items,
184+
categoriesCursor: paginatedCategories.cursor,
185+
categoriesHasMore: paginatedCategories.hasMore,
186+
),
187+
);
188+
} on HtHttpException catch (e) {
189+
emit(
190+
state.copyWith(
191+
categoriesStatus: ContentManagementStatus.failure,
192+
errorMessage: e.message,
193+
),
194+
);
195+
} catch (e) {
196+
emit(
197+
state.copyWith(
198+
categoriesStatus: ContentManagementStatus.failure,
199+
errorMessage: e.toString(),
200+
),
201+
);
202+
}
203+
}
204+
205+
Future<void> _onCreateCategoryRequested(
206+
CreateCategoryRequested event,
207+
Emitter<ContentManagementState> emit,
208+
) async {
209+
emit(state.copyWith(categoriesStatus: ContentManagementStatus.loading));
210+
try {
211+
await _categoriesRepository.create(item: event.category);
212+
// Reload categories after creation
213+
add(const LoadCategoriesRequested());
214+
} on HtHttpException catch (e) {
215+
emit(
216+
state.copyWith(
217+
categoriesStatus: ContentManagementStatus.failure,
218+
errorMessage: e.message,
219+
),
220+
);
221+
} catch (e) {
222+
emit(
223+
state.copyWith(
224+
categoriesStatus: ContentManagementStatus.failure,
225+
errorMessage: e.toString(),
226+
),
227+
);
228+
}
229+
}
230+
231+
Future<void> _onUpdateCategoryRequested(
232+
UpdateCategoryRequested event,
233+
Emitter<ContentManagementState> emit,
234+
) async {
235+
emit(state.copyWith(categoriesStatus: ContentManagementStatus.loading));
236+
try {
237+
await _categoriesRepository.update(id: event.id, item: event.category);
238+
// Reload categories after update
239+
add(const LoadCategoriesRequested());
240+
} on HtHttpException catch (e) {
241+
emit(
242+
state.copyWith(
243+
categoriesStatus: ContentManagementStatus.failure,
244+
errorMessage: e.message,
245+
),
246+
);
247+
} catch (e) {
248+
emit(
249+
state.copyWith(
250+
categoriesStatus: ContentManagementStatus.failure,
251+
errorMessage: e.toString(),
252+
),
253+
);
254+
}
255+
}
256+
257+
Future<void> _onDeleteCategoryRequested(
258+
DeleteCategoryRequested event,
259+
Emitter<ContentManagementState> emit,
260+
) async {
261+
emit(state.copyWith(categoriesStatus: ContentManagementStatus.loading));
262+
try {
263+
await _categoriesRepository.delete(id: event.id);
264+
// Reload categories after deletion
265+
add(const LoadCategoriesRequested());
266+
} on HtHttpException catch (e) {
267+
emit(
268+
state.copyWith(
269+
categoriesStatus: ContentManagementStatus.failure,
270+
errorMessage: e.message,
271+
),
272+
);
273+
} catch (e) {
274+
emit(
275+
state.copyWith(
276+
categoriesStatus: ContentManagementStatus.failure,
277+
errorMessage: e.toString(),
278+
),
279+
);
280+
}
281+
}
282+
283+
Future<void> _onLoadSourcesRequested(
284+
LoadSourcesRequested event,
285+
Emitter<ContentManagementState> emit,
286+
) async {
287+
emit(state.copyWith(sourcesStatus: ContentManagementStatus.loading));
288+
try {
289+
final paginatedSources = await _sourcesRepository.readAll(
290+
startAfterId: event.startAfterId,
291+
limit: event.limit,
292+
);
293+
emit(
294+
state.copyWith(
295+
sourcesStatus: ContentManagementStatus.success,
296+
sources: paginatedSources.items,
297+
sourcesCursor: paginatedSources.cursor,
298+
sourcesHasMore: paginatedSources.hasMore,
299+
),
300+
);
301+
} on HtHttpException catch (e) {
302+
emit(
303+
state.copyWith(
304+
sourcesStatus: ContentManagementStatus.failure,
305+
errorMessage: e.message,
306+
),
307+
);
308+
} catch (e) {
309+
emit(
310+
state.copyWith(
311+
sourcesStatus: ContentManagementStatus.failure,
312+
errorMessage: e.toString(),
313+
),
314+
);
315+
}
316+
}
317+
318+
Future<void> _onCreateSourceRequested(
319+
CreateSourceRequested event,
320+
Emitter<ContentManagementState> emit,
321+
) async {
322+
emit(state.copyWith(sourcesStatus: ContentManagementStatus.loading));
323+
try {
324+
await _sourcesRepository.create(item: event.source);
325+
// Reload sources after creation
326+
add(const LoadSourcesRequested());
327+
} on HtHttpException catch (e) {
328+
emit(
329+
state.copyWith(
330+
sourcesStatus: ContentManagementStatus.failure,
331+
errorMessage: e.message,
332+
),
333+
);
334+
} catch (e) {
335+
emit(
336+
state.copyWith(
337+
sourcesStatus: ContentManagementStatus.failure,
338+
errorMessage: e.toString(),
339+
),
340+
);
341+
}
342+
}
343+
344+
Future<void> _onUpdateSourceRequested(
345+
UpdateSourceRequested event,
346+
Emitter<ContentManagementState> emit,
347+
) async {
348+
emit(state.copyWith(sourcesStatus: ContentManagementStatus.loading));
349+
try {
350+
await _sourcesRepository.update(id: event.id, item: event.source);
351+
// Reload sources after update
352+
add(const LoadSourcesRequested());
353+
} on HtHttpException catch (e) {
354+
emit(
355+
state.copyWith(
356+
sourcesStatus: ContentManagementStatus.failure,
357+
errorMessage: e.message,
358+
),
359+
);
360+
} catch (e) {
361+
emit(
362+
state.copyWith(
363+
sourcesStatus: ContentManagementStatus.failure,
364+
errorMessage: e.toString(),
365+
),
366+
);
367+
}
368+
}
369+
370+
Future<void> _onOnDeleteSourceRequested(
371+
DeleteSourceRequested event,
372+
Emitter<ContentManagementState> emit,
373+
) async {
374+
emit(state.copyWith(sourcesStatus: ContentManagementStatus.loading));
375+
try {
376+
await _sourcesRepository.delete(id: event.id);
377+
// Reload sources after deletion
378+
add(const LoadSourcesRequested());
379+
} on HtHttpException catch (e) {
380+
emit(
381+
state.copyWith(
382+
sourcesStatus: ContentManagementStatus.failure,
383+
errorMessage: e.message,
384+
),
385+
);
386+
} catch (e) {
387+
emit(
388+
state.copyWith(
389+
sourcesStatus: ContentManagementStatus.failure,
390+
errorMessage: e.toString(),
391+
),
392+
);
393+
}
394+
}
395+
}

0 commit comments

Comments
 (0)