Skip to content

Commit 2d33a9f

Browse files
committed
feat: Implement CreateHeadlineBloc
- Manage headline creation state - Load sources and categories - Handle form input changes - Submit new headline to repository
1 parent af93511 commit 2d33a9f

File tree

1 file changed

+152
-0
lines changed

1 file changed

+152
-0
lines changed
Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
import 'package:bloc/bloc.dart';
2+
import 'package:equatable/equatable.dart';
3+
import 'package:flutter/foundation.dart' hide Category;
4+
import 'package:ht_data_repository/ht_data_repository.dart';
5+
import 'package:ht_shared/ht_shared.dart';
6+
7+
part 'create_headline_event.dart';
8+
part 'create_headline_state.dart';
9+
10+
/// A BLoC to manage the state of creating a new headline.
11+
class CreateHeadlineBloc
12+
extends Bloc<CreateHeadlineEvent, CreateHeadlineState> {
13+
/// {@macro create_headline_bloc}
14+
CreateHeadlineBloc({
15+
required HtDataRepository<Headline> headlinesRepository,
16+
required HtDataRepository<Source> sourcesRepository,
17+
required HtDataRepository<Category> categoriesRepository,
18+
}) : _headlinesRepository = headlinesRepository,
19+
_sourcesRepository = sourcesRepository,
20+
_categoriesRepository = categoriesRepository,
21+
super(const CreateHeadlineState()) {
22+
on<CreateHeadlineDataLoaded>(_onDataLoaded);
23+
on<CreateHeadlineTitleChanged>(_onTitleChanged);
24+
on<CreateHeadlineDescriptionChanged>(_onDescriptionChanged);
25+
on<CreateHeadlineUrlChanged>(_onUrlChanged);
26+
on<CreateHeadlineImageUrlChanged>(_onImageUrlChanged);
27+
on<CreateHeadlineSourceChanged>(_onSourceChanged);
28+
on<CreateHeadlineCategoryChanged>(_onCategoryChanged);
29+
on<CreateHeadlineSubmitted>(_onSubmitted);
30+
}
31+
32+
final HtDataRepository<Headline> _headlinesRepository;
33+
final HtDataRepository<Source> _sourcesRepository;
34+
final HtDataRepository<Category> _categoriesRepository;
35+
36+
Future<void> _onDataLoaded(
37+
CreateHeadlineDataLoaded event,
38+
Emitter<CreateHeadlineState> emit,
39+
) async {
40+
emit(state.copyWith(status: CreateHeadlineStatus.loading));
41+
try {
42+
final [sourcesResponse, categoriesResponse] = await Future.wait([
43+
_sourcesRepository.readAll(),
44+
_categoriesRepository.readAll(),
45+
]);
46+
47+
final sources = (sourcesResponse as PaginatedResponse<Source>).items;
48+
final categories =
49+
(categoriesResponse as PaginatedResponse<Category>).items;
50+
51+
emit(
52+
state.copyWith(
53+
status: CreateHeadlineStatus.initial,
54+
sources: sources,
55+
categories: categories,
56+
),
57+
);
58+
} on HtHttpException catch (e) {
59+
emit(
60+
state.copyWith(
61+
status: CreateHeadlineStatus.failure,
62+
errorMessage: e.message,
63+
),
64+
);
65+
} catch (e) {
66+
emit(
67+
state.copyWith(
68+
status: CreateHeadlineStatus.failure,
69+
errorMessage: e.toString(),
70+
),
71+
);
72+
}
73+
}
74+
75+
void _onTitleChanged(
76+
CreateHeadlineTitleChanged event,
77+
Emitter<CreateHeadlineState> emit,
78+
) {
79+
emit(state.copyWith(title: event.title));
80+
}
81+
82+
void _onDescriptionChanged(
83+
CreateHeadlineDescriptionChanged event,
84+
Emitter<CreateHeadlineState> emit,
85+
) {
86+
emit(state.copyWith(description: event.description));
87+
}
88+
89+
void _onUrlChanged(
90+
CreateHeadlineUrlChanged event,
91+
Emitter<CreateHeadlineState> emit,
92+
) {
93+
emit(state.copyWith(url: event.url));
94+
}
95+
96+
void _onImageUrlChanged(
97+
CreateHeadlineImageUrlChanged event,
98+
Emitter<CreateHeadlineState> emit,
99+
) {
100+
emit(state.copyWith(imageUrl: event.imageUrl));
101+
}
102+
103+
void _onSourceChanged(
104+
CreateHeadlineSourceChanged event,
105+
Emitter<CreateHeadlineState> emit,
106+
) {
107+
emit(state.copyWith(source: () => event.source));
108+
}
109+
110+
void _onCategoryChanged(
111+
CreateHeadlineCategoryChanged event,
112+
Emitter<CreateHeadlineState> emit,
113+
) {
114+
emit(state.copyWith(category: () => event.category));
115+
}
116+
117+
Future<void> _onSubmitted(
118+
CreateHeadlineSubmitted event,
119+
Emitter<CreateHeadlineState> emit,
120+
) async {
121+
if (!state.isFormValid) return;
122+
123+
emit(state.copyWith(status: CreateHeadlineStatus.submitting));
124+
try {
125+
final newHeadline = Headline(
126+
title: state.title,
127+
description: state.description.isNotEmpty ? state.description : null,
128+
url: state.url.isNotEmpty ? state.url : null,
129+
imageUrl: state.imageUrl.isNotEmpty ? state.imageUrl : null,
130+
source: state.source,
131+
category: state.category,
132+
);
133+
134+
await _headlinesRepository.create(item: newHeadline);
135+
emit(state.copyWith(status: CreateHeadlineStatus.success));
136+
} on HtHttpException catch (e) {
137+
emit(
138+
state.copyWith(
139+
status: CreateHeadlineStatus.failure,
140+
errorMessage: e.message,
141+
),
142+
);
143+
} catch (e) {
144+
emit(
145+
state.copyWith(
146+
status: CreateHeadlineStatus.failure,
147+
errorMessage: e.toString(),
148+
),
149+
);
150+
}
151+
}
152+
}

0 commit comments

Comments
 (0)