@@ -2,108 +2,183 @@ import 'package:bloc/bloc.dart';
2
2
import 'package:bloc_concurrency/bloc_concurrency.dart' ;
3
3
import 'package:equatable/equatable.dart' ;
4
4
import 'package:ht_data_repository/ht_data_repository.dart' ; // Generic Data Repository
5
+ import 'package:ht_main/headlines-search/models/search_model_type.dart' ; // Import SearchModelType
5
6
import 'package:ht_shared/ht_shared.dart' ; // Shared models, including Headline
6
7
7
8
part 'headlines_search_event.dart' ;
8
9
part 'headlines_search_state.dart' ;
9
10
10
11
class HeadlinesSearchBloc
11
12
extends Bloc <HeadlinesSearchEvent , HeadlinesSearchState > {
12
- HeadlinesSearchBloc ({required HtDataRepository <Headline > headlinesRepository})
13
- : _headlinesRepository = headlinesRepository,
14
- super (const HeadlinesSearchInitial ()) {
15
- // Start with Initial state
13
+ HeadlinesSearchBloc ({
14
+ required HtDataRepository <Headline > headlinesRepository,
15
+ required HtDataRepository <Category > categoryRepository,
16
+ required HtDataRepository <Source > sourceRepository,
17
+ required HtDataRepository <Country > countryRepository,
18
+ }) : _headlinesRepository = headlinesRepository,
19
+ _categoryRepository = categoryRepository,
20
+ _sourceRepository = sourceRepository,
21
+ _countryRepository = countryRepository,
22
+ super (const HeadlinesSearchInitial ()) {
23
+ on < HeadlinesSearchModelTypeChanged > (_onHeadlinesSearchModelTypeChanged);
16
24
on < HeadlinesSearchFetchRequested > (
17
25
_onSearchFetchRequested,
18
26
transformer: restartable (), // Process only the latest search
19
27
);
20
28
}
21
29
22
30
final HtDataRepository <Headline > _headlinesRepository;
31
+ final HtDataRepository <Category > _categoryRepository;
32
+ final HtDataRepository <Source > _sourceRepository;
33
+ final HtDataRepository <Country > _countryRepository;
23
34
static const _limit = 10 ;
24
35
36
+ Future <void > _onHeadlinesSearchModelTypeChanged (
37
+ HeadlinesSearchModelTypeChanged event,
38
+ Emitter <HeadlinesSearchState > emit,
39
+ ) async {
40
+ // If there's an active search term, re-trigger search with new model type
41
+ final currentSearchTerm = state is HeadlinesSearchLoading
42
+ ? (state as HeadlinesSearchLoading ).lastSearchTerm
43
+ : state is HeadlinesSearchSuccess
44
+ ? (state as HeadlinesSearchSuccess ).lastSearchTerm
45
+ : state is HeadlinesSearchFailure
46
+ ? (state as HeadlinesSearchFailure ).lastSearchTerm
47
+ : null ;
48
+
49
+ emit (HeadlinesSearchInitial (selectedModelType: event.newModelType));
50
+
51
+ if (currentSearchTerm != null && currentSearchTerm.isNotEmpty) {
52
+ add (HeadlinesSearchFetchRequested (searchTerm: currentSearchTerm));
53
+ }
54
+ }
55
+
25
56
Future <void > _onSearchFetchRequested (
26
57
HeadlinesSearchFetchRequested event,
27
58
Emitter <HeadlinesSearchState > emit,
28
59
) async {
29
- if (event.searchTerm.isEmpty) {
60
+ final searchTerm = event.searchTerm;
61
+ final modelType = state.selectedModelType;
62
+
63
+ if (searchTerm.isEmpty) {
30
64
emit (
31
- const HeadlinesSearchSuccess (
32
- headlines : [],
65
+ HeadlinesSearchSuccess (
66
+ results : const [],
33
67
hasMore: false ,
34
68
lastSearchTerm: '' ,
69
+ selectedModelType: modelType,
35
70
),
36
71
);
37
72
return ;
38
73
}
39
74
40
- // Check if current state is success and if the search term is the same for pagination
75
+ // Handle pagination
41
76
if (state is HeadlinesSearchSuccess ) {
42
77
final successState = state as HeadlinesSearchSuccess ;
43
- if (event. searchTerm == successState.lastSearchTerm) {
44
- // This is a pagination request for the current search term
45
- if (! successState.hasMore) return ; // No more items to paginate
78
+ if (searchTerm == successState.lastSearchTerm &&
79
+ modelType == successState.selectedModelType) {
80
+ if (! successState.hasMore) return ;
46
81
47
- // It's a bit unusual to emit Loading here for pagination,
48
- // typically UI handles this. Let's keep it simple for now.
49
- // emit(HeadlinesSearchLoading(lastSearchTerm: event.searchTerm));
50
82
try {
51
- final response = await _headlinesRepository.readAllByQuery (
52
- {'q' : event.searchTerm},
53
- limit: _limit,
54
- startAfterId: successState.cursor,
55
- );
83
+ PaginatedResponse <dynamic > response;
84
+ switch (modelType) {
85
+ case SearchModelType .headline:
86
+ response = await _headlinesRepository.readAllByQuery (
87
+ {'q' : searchTerm, 'model' : modelType.toJson ()},
88
+ limit: _limit,
89
+ startAfterId: successState.cursor,
90
+ );
91
+ case SearchModelType .category:
92
+ response = await _categoryRepository.readAllByQuery (
93
+ {'q' : searchTerm, 'model' : modelType.toJson ()},
94
+ limit: _limit,
95
+ startAfterId: successState.cursor,
96
+ );
97
+ case SearchModelType .source:
98
+ response = await _sourceRepository.readAllByQuery (
99
+ {'q' : searchTerm, 'model' : modelType.toJson ()},
100
+ limit: _limit,
101
+ startAfterId: successState.cursor,
102
+ );
103
+ case SearchModelType .country:
104
+ response = await _countryRepository.readAllByQuery (
105
+ {'q' : searchTerm, 'model' : modelType.toJson ()},
106
+ limit: _limit,
107
+ startAfterId: successState.cursor,
108
+ );
109
+ }
56
110
emit (
57
- response.items.isEmpty
58
- ? successState.copyWith (hasMore: false )
59
- : successState.copyWith (
60
- headlines: List .of (successState.headlines)
61
- ..addAll (response.items),
62
- hasMore: response.hasMore,
63
- cursor: response.cursor,
64
- ),
111
+ successState.copyWith (
112
+ results: List .of (successState.results)..addAll (response.items),
113
+ hasMore: response.hasMore,
114
+ cursor: response.cursor,
115
+ ),
65
116
);
66
117
} on HtHttpException catch (e) {
67
118
emit (successState.copyWith (errorMessage: e.message));
68
119
} catch (e, st) {
69
- print ('Search pagination error: $e \n $st ' );
70
- emit (
71
- successState. copyWith ( errorMessage: 'Failed to load more results.' ) ,
72
- );
120
+ print ('Search pagination error ($ modelType ) : $e \n $st ' );
121
+ emit (successState. copyWith (
122
+ errorMessage: 'Failed to load more results.' ,
123
+ )) ;
73
124
}
74
- return ; // Pagination handled
125
+ return ;
75
126
}
76
127
}
77
128
78
- // If not paginating for the same term, it's a new search or different term
79
- emit (
80
- HeadlinesSearchLoading (lastSearchTerm: event.searchTerm),
81
- ); // Show loading for new search
129
+ // New search
130
+ emit (HeadlinesSearchLoading (
131
+ lastSearchTerm: searchTerm,
132
+ selectedModelType: modelType,
133
+ ));
82
134
try {
83
- final response = await _headlinesRepository.readAllByQuery ({
84
- 'q' : event.searchTerm,
85
- }, limit: _limit);
135
+ PaginatedResponse <dynamic > response;
136
+ switch (modelType) {
137
+ case SearchModelType .headline:
138
+ response = await _headlinesRepository.readAllByQuery (
139
+ {'q' : searchTerm, 'model' : modelType.toJson ()},
140
+ limit: _limit,
141
+ );
142
+ case SearchModelType .category:
143
+ response = await _categoryRepository.readAllByQuery (
144
+ {'q' : searchTerm, 'model' : modelType.toJson ()},
145
+ limit: _limit,
146
+ );
147
+ case SearchModelType .source:
148
+ response = await _sourceRepository.readAllByQuery (
149
+ {'q' : searchTerm, 'model' : modelType.toJson ()},
150
+ limit: _limit,
151
+ );
152
+ case SearchModelType .country:
153
+ response = await _countryRepository.readAllByQuery (
154
+ {'q' : searchTerm, 'model' : modelType.toJson ()},
155
+ limit: _limit,
156
+ );
157
+ }
86
158
emit (
87
159
HeadlinesSearchSuccess (
88
- headlines : response.items,
160
+ results : response.items,
89
161
hasMore: response.hasMore,
90
162
cursor: response.cursor,
91
- lastSearchTerm: event.searchTerm,
163
+ lastSearchTerm: searchTerm,
164
+ selectedModelType: modelType,
92
165
),
93
166
);
94
167
} on HtHttpException catch (e) {
95
168
emit (
96
169
HeadlinesSearchFailure (
97
170
errorMessage: e.message,
98
- lastSearchTerm: event.searchTerm,
171
+ lastSearchTerm: searchTerm,
172
+ selectedModelType: modelType,
99
173
),
100
174
);
101
175
} catch (e, st) {
102
- print ('Search error: $e \n $st ' );
176
+ print ('Search error ($ modelType ) : $e \n $st ' );
103
177
emit (
104
178
HeadlinesSearchFailure (
105
179
errorMessage: 'An unexpected error occurred during search.' ,
106
- lastSearchTerm: event.searchTerm,
180
+ lastSearchTerm: searchTerm,
181
+ selectedModelType: modelType,
107
182
),
108
183
);
109
184
}
0 commit comments