Skip to content

Commit b00cf36

Browse files
committed
feat(archived_content): implement ArchivedContentBloc
- Add ArchivedContentBloc for managing archived content - Implement logic for handling headlines, topics, and sources - Include functionality for loading, restoring, and deleting archived items - Handle pagination and state management for archived content
1 parent 6c723b6 commit b00cf36

File tree

1 file changed

+280
-0
lines changed

1 file changed

+280
-0
lines changed
Lines changed: 280 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,280 @@
1+
import 'package:bloc/bloc.dart';
2+
import 'package:core/core.dart';
3+
import 'package:data_repository/data_repository.dart';
4+
import 'package:equatable/equatable.dart';
5+
6+
part 'archived_content_event.dart';
7+
part 'archived_content_state.dart';
8+
9+
class ArchivedContentBloc
10+
extends Bloc<ArchivedContentEvent, ArchivedContentState> {
11+
ArchivedContentBloc({
12+
required DataRepository<Headline> headlinesRepository,
13+
required DataRepository<Topic> topicsRepository,
14+
required DataRepository<Source> sourcesRepository,
15+
}) : _headlinesRepository = headlinesRepository,
16+
_topicsRepository = topicsRepository,
17+
_sourcesRepository = sourcesRepository,
18+
super(const ArchivedContentState()) {
19+
on<ArchivedContentTabChanged>(_onArchivedContentTabChanged);
20+
on<LoadArchivedHeadlinesRequested>(_onLoadArchivedHeadlinesRequested);
21+
on<RestoreHeadlineRequested>(_onRestoreHeadlineRequested);
22+
on<DeleteHeadlineForeverRequested>(_onDeleteHeadlineForeverRequested);
23+
on<LoadArchivedTopicsRequested>(_onLoadArchivedTopicsRequested);
24+
on<RestoreTopicRequested>(_onRestoreTopicRequested);
25+
on<LoadArchivedSourcesRequested>(_onLoadArchivedSourcesRequested);
26+
on<RestoreSourceRequested>(_onRestoreSourceRequested);
27+
}
28+
29+
final DataRepository<Headline> _headlinesRepository;
30+
final DataRepository<Topic> _topicsRepository;
31+
final DataRepository<Source> _sourcesRepository;
32+
33+
void _onArchivedContentTabChanged(
34+
ArchivedContentTabChanged event,
35+
Emitter<ArchivedContentState> emit,
36+
) {
37+
emit(state.copyWith(activeTab: event.tab));
38+
}
39+
40+
Future<void> _onLoadArchivedHeadlinesRequested(
41+
LoadArchivedHeadlinesRequested event,
42+
Emitter<ArchivedContentState> emit,
43+
) async {
44+
emit(state.copyWith(headlinesStatus: ArchivedContentStatus.loading));
45+
try {
46+
final isPaginating = event.startAfterId != null;
47+
final previousHeadlines = isPaginating ? state.headlines : <Headline>[];
48+
49+
final paginatedHeadlines = await _headlinesRepository.readAll(
50+
filter: {'status': ContentStatus.archived.name},
51+
sort: [const SortOption('updatedAt', SortOrder.desc)],
52+
pagination: PaginationOptions(
53+
cursor: event.startAfterId,
54+
limit: event.limit,
55+
),
56+
);
57+
emit(
58+
state.copyWith(
59+
headlinesStatus: ArchivedContentStatus.success,
60+
headlines: [...previousHeadlines, ...paginatedHeadlines.items],
61+
headlinesCursor: paginatedHeadlines.cursor,
62+
headlinesHasMore: paginatedHeadlines.hasMore,
63+
),
64+
);
65+
} on HttpException catch (e) {
66+
emit(
67+
state.copyWith(
68+
headlinesStatus: ArchivedContentStatus.failure,
69+
exception: e,
70+
),
71+
);
72+
} catch (e) {
73+
emit(
74+
state.copyWith(
75+
headlinesStatus: ArchivedContentStatus.failure,
76+
exception: UnknownException('An unexpected error occurred: $e'),
77+
),
78+
);
79+
}
80+
}
81+
82+
Future<void> _onRestoreHeadlineRequested(
83+
RestoreHeadlineRequested event,
84+
Emitter<ArchivedContentState> emit,
85+
) async {
86+
final originalHeadlines = List<Headline>.from(state.headlines);
87+
final headlineIndex = originalHeadlines.indexWhere((h) => h.id == event.id);
88+
if (headlineIndex == -1) return;
89+
90+
final headlineToRestore = originalHeadlines[headlineIndex];
91+
final updatedHeadlines = originalHeadlines..removeAt(headlineIndex);
92+
93+
emit(state.copyWith(headlines: updatedHeadlines));
94+
95+
try {
96+
await _headlinesRepository.update(
97+
id: event.id,
98+
item: headlineToRestore.copyWith(status: ContentStatus.active),
99+
);
100+
} on HttpException catch (e) {
101+
emit(state.copyWith(headlines: originalHeadlines, exception: e));
102+
} catch (e) {
103+
emit(
104+
state.copyWith(
105+
headlines: originalHeadlines,
106+
exception: UnknownException('An unexpected error occurred: $e'),
107+
),
108+
);
109+
}
110+
}
111+
112+
Future<void> _onDeleteHeadlineForeverRequested(
113+
DeleteHeadlineForeverRequested event,
114+
Emitter<ArchivedContentState> emit,
115+
) async {
116+
final originalHeadlines = List<Headline>.from(state.headlines);
117+
final headlineIndex = originalHeadlines.indexWhere((h) => h.id == event.id);
118+
if (headlineIndex == -1) return;
119+
120+
final updatedHeadlines = originalHeadlines..removeAt(headlineIndex);
121+
emit(state.copyWith(headlines: updatedHeadlines));
122+
123+
try {
124+
await _headlinesRepository.delete(id: event.id);
125+
} on HttpException catch (e) {
126+
emit(state.copyWith(headlines: originalHeadlines, exception: e));
127+
} catch (e) {
128+
emit(
129+
state.copyWith(
130+
headlines: originalHeadlines,
131+
exception: UnknownException('An unexpected error occurred: $e'),
132+
),
133+
);
134+
}
135+
}
136+
137+
Future<void> _onLoadArchivedTopicsRequested(
138+
LoadArchivedTopicsRequested event,
139+
Emitter<ArchivedContentState> emit,
140+
) async {
141+
emit(state.copyWith(topicsStatus: ArchivedContentStatus.loading));
142+
try {
143+
final isPaginating = event.startAfterId != null;
144+
final previousTopics = isPaginating ? state.topics : <Topic>[];
145+
146+
final paginatedTopics = await _topicsRepository.readAll(
147+
filter: {'status': ContentStatus.archived.name},
148+
sort: [const SortOption('updatedAt', SortOrder.desc)],
149+
pagination: PaginationOptions(
150+
cursor: event.startAfterId,
151+
limit: event.limit,
152+
),
153+
);
154+
emit(
155+
state.copyWith(
156+
topicsStatus: ArchivedContentStatus.success,
157+
topics: [...previousTopics, ...paginatedTopics.items],
158+
topicsCursor: paginatedTopics.cursor,
159+
topicsHasMore: paginatedTopics.hasMore,
160+
),
161+
);
162+
} on HttpException catch (e) {
163+
emit(
164+
state.copyWith(
165+
topicsStatus: ArchivedContentStatus.failure,
166+
exception: e,
167+
),
168+
);
169+
} catch (e) {
170+
emit(
171+
state.copyWith(
172+
topicsStatus: ArchivedContentStatus.failure,
173+
exception: UnknownException('An unexpected error occurred: $e'),
174+
),
175+
);
176+
}
177+
}
178+
179+
Future<void> _onRestoreTopicRequested(
180+
RestoreTopicRequested event,
181+
Emitter<ArchivedContentState> emit,
182+
) async {
183+
final originalTopics = List<Topic>.from(state.topics);
184+
final topicIndex = originalTopics.indexWhere((t) => t.id == event.id);
185+
if (topicIndex == -1) return;
186+
187+
final topicToRestore = originalTopics[topicIndex];
188+
final updatedTopics = originalTopics..removeAt(topicIndex);
189+
190+
emit(state.copyWith(topics: updatedTopics));
191+
192+
try {
193+
await _topicsRepository.update(
194+
id: event.id,
195+
item: topicToRestore.copyWith(status: ContentStatus.active),
196+
);
197+
} on HttpException catch (e) {
198+
emit(state.copyWith(topics: originalTopics, exception: e));
199+
} catch (e) {
200+
emit(
201+
state.copyWith(
202+
topics: originalTopics,
203+
exception: UnknownException('An unexpected error occurred: $e'),
204+
),
205+
);
206+
}
207+
}
208+
209+
Future<void> _onLoadArchivedSourcesRequested(
210+
LoadArchivedSourcesRequested event,
211+
Emitter<ArchivedContentState> emit,
212+
) async {
213+
emit(state.copyWith(sourcesStatus: ArchivedContentStatus.loading));
214+
try {
215+
final isPaginating = event.startAfterId != null;
216+
final previousSources = isPaginating ? state.sources : <Source>[];
217+
218+
final paginatedSources = await _sourcesRepository.readAll(
219+
filter: {'status': ContentStatus.archived.name},
220+
sort: [const SortOption('updatedAt', SortOrder.desc)],
221+
pagination: PaginationOptions(
222+
cursor: event.startAfterId,
223+
limit: event.limit,
224+
),
225+
);
226+
emit(
227+
state.copyWith(
228+
sourcesStatus: ArchivedContentStatus.success,
229+
sources: [...previousSources, ...paginatedSources.items],
230+
sourcesCursor: paginatedSources.cursor,
231+
sourcesHasMore: paginatedSources.hasMore,
232+
),
233+
);
234+
} on HttpException catch (e) {
235+
emit(
236+
state.copyWith(
237+
sourcesStatus: ArchivedContentStatus.failure,
238+
exception: e,
239+
),
240+
);
241+
} catch (e) {
242+
emit(
243+
state.copyWith(
244+
sourcesStatus: ArchivedContentStatus.failure,
245+
exception: UnknownException('An unexpected error occurred: $e'),
246+
),
247+
);
248+
}
249+
}
250+
251+
Future<void> _onRestoreSourceRequested(
252+
RestoreSourceRequested event,
253+
Emitter<ArchivedContentState> emit,
254+
) async {
255+
final originalSources = List<Source>.from(state.sources);
256+
final sourceIndex = originalSources.indexWhere((s) => s.id == event.id);
257+
if (sourceIndex == -1) return;
258+
259+
final sourceToRestore = originalSources[sourceIndex];
260+
final updatedSources = originalSources..removeAt(sourceIndex);
261+
262+
emit(state.copyWith(sources: updatedSources));
263+
264+
try {
265+
await _sourcesRepository.update(
266+
id: event.id,
267+
item: sourceToRestore.copyWith(status: ContentStatus.active),
268+
);
269+
} on HttpException catch (e) {
270+
emit(state.copyWith(sources: originalSources, exception: e));
271+
} catch (e) {
272+
emit(
273+
state.copyWith(
274+
sources: originalSources,
275+
exception: UnknownException('An unexpected error occurred: $e'),
276+
),
277+
);
278+
}
279+
}
280+
}

0 commit comments

Comments
 (0)