@@ -2,108 +2,188 @@ 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
+ // ignore: unused_local_variable
42
+ final currentSearchTerm =
43
+ state is HeadlinesSearchLoading
44
+ ? (state as HeadlinesSearchLoading ).lastSearchTerm
45
+ : state is HeadlinesSearchSuccess
46
+ ? (state as HeadlinesSearchSuccess ).lastSearchTerm
47
+ : state is HeadlinesSearchFailure
48
+ ? (state as HeadlinesSearchFailure ).lastSearchTerm
49
+ : null ;
50
+
51
+ emit (HeadlinesSearchInitial (selectedModelType: event.newModelType));
52
+
53
+ // Removed automatic re-search:
54
+ // if (currentSearchTerm != null && currentSearchTerm.isNotEmpty) {
55
+ // add(HeadlinesSearchFetchRequested(searchTerm: currentSearchTerm));
56
+ // }
57
+ }
58
+
25
59
Future <void > _onSearchFetchRequested (
26
60
HeadlinesSearchFetchRequested event,
27
61
Emitter <HeadlinesSearchState > emit,
28
62
) async {
29
- if (event.searchTerm.isEmpty) {
63
+ final searchTerm = event.searchTerm;
64
+ final modelType = state.selectedModelType;
65
+
66
+ if (searchTerm.isEmpty) {
30
67
emit (
31
- const HeadlinesSearchSuccess (
32
- headlines : [],
68
+ HeadlinesSearchSuccess (
69
+ results : const [],
33
70
hasMore: false ,
34
71
lastSearchTerm: '' ,
72
+ selectedModelType: modelType,
35
73
),
36
74
);
37
75
return ;
38
76
}
39
77
40
- // Check if current state is success and if the search term is the same for pagination
78
+ // Handle pagination
41
79
if (state is HeadlinesSearchSuccess ) {
42
80
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
81
+ if (searchTerm == successState.lastSearchTerm &&
82
+ modelType == successState.selectedModelType) {
83
+ if (! successState.hasMore) return ;
46
84
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
85
try {
51
- final response = await _headlinesRepository.readAllByQuery (
52
- {'q' : event.searchTerm},
53
- limit: _limit,
54
- startAfterId: successState.cursor,
55
- );
86
+ PaginatedResponse <dynamic > response;
87
+ switch (modelType) {
88
+ case SearchModelType .headline:
89
+ response = await _headlinesRepository.readAllByQuery (
90
+ {'q' : searchTerm, 'model' : modelType.toJson ()},
91
+ limit: _limit,
92
+ startAfterId: successState.cursor,
93
+ );
94
+ case SearchModelType .category:
95
+ response = await _categoryRepository.readAllByQuery (
96
+ {'q' : searchTerm, 'model' : modelType.toJson ()},
97
+ limit: _limit,
98
+ startAfterId: successState.cursor,
99
+ );
100
+ case SearchModelType .source:
101
+ response = await _sourceRepository.readAllByQuery (
102
+ {'q' : searchTerm, 'model' : modelType.toJson ()},
103
+ limit: _limit,
104
+ startAfterId: successState.cursor,
105
+ );
106
+ case SearchModelType .country:
107
+ response = await _countryRepository.readAllByQuery (
108
+ {'q' : searchTerm, 'model' : modelType.toJson ()},
109
+ limit: _limit,
110
+ startAfterId: successState.cursor,
111
+ );
112
+ }
56
113
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
- ),
114
+ successState.copyWith (
115
+ results: List .of (successState.results)..addAll (response.items),
116
+ hasMore: response.hasMore,
117
+ cursor: response.cursor,
118
+ ),
65
119
);
66
120
} on HtHttpException catch (e) {
67
121
emit (successState.copyWith (errorMessage: e.message));
68
122
} catch (e, st) {
69
- print ('Search pagination error: $e \n $st ' );
123
+ print ('Search pagination error ($ modelType ) : $e \n $st ' );
70
124
emit (
71
125
successState.copyWith (errorMessage: 'Failed to load more results.' ),
72
126
);
73
127
}
74
- return ; // Pagination handled
128
+ return ;
75
129
}
76
130
}
77
131
78
- // If not paginating for the same term, it's a new search or different term
132
+ // New search
79
133
emit (
80
- HeadlinesSearchLoading (lastSearchTerm: event.searchTerm),
81
- ); // Show loading for new search
134
+ HeadlinesSearchLoading (
135
+ lastSearchTerm: searchTerm,
136
+ selectedModelType: modelType,
137
+ ),
138
+ );
82
139
try {
83
- final response = await _headlinesRepository.readAllByQuery ({
84
- 'q' : event.searchTerm,
85
- }, limit: _limit);
140
+ PaginatedResponse <dynamic > response;
141
+ switch (modelType) {
142
+ case SearchModelType .headline:
143
+ response = await _headlinesRepository.readAllByQuery ({
144
+ 'q' : searchTerm,
145
+ 'model' : modelType.toJson (),
146
+ }, limit: _limit,);
147
+ case SearchModelType .category:
148
+ response = await _categoryRepository.readAllByQuery ({
149
+ 'q' : searchTerm,
150
+ 'model' : modelType.toJson (),
151
+ }, limit: _limit,);
152
+ case SearchModelType .source:
153
+ response = await _sourceRepository.readAllByQuery ({
154
+ 'q' : searchTerm,
155
+ 'model' : modelType.toJson (),
156
+ }, limit: _limit,);
157
+ case SearchModelType .country:
158
+ response = await _countryRepository.readAllByQuery ({
159
+ 'q' : searchTerm,
160
+ 'model' : modelType.toJson (),
161
+ }, limit: _limit,);
162
+ }
86
163
emit (
87
164
HeadlinesSearchSuccess (
88
- headlines : response.items,
165
+ results : response.items,
89
166
hasMore: response.hasMore,
90
167
cursor: response.cursor,
91
- lastSearchTerm: event.searchTerm,
168
+ lastSearchTerm: searchTerm,
169
+ selectedModelType: modelType,
92
170
),
93
171
);
94
172
} on HtHttpException catch (e) {
95
173
emit (
96
174
HeadlinesSearchFailure (
97
175
errorMessage: e.message,
98
- lastSearchTerm: event.searchTerm,
176
+ lastSearchTerm: searchTerm,
177
+ selectedModelType: modelType,
99
178
),
100
179
);
101
180
} catch (e, st) {
102
- print ('Search error: $e \n $st ' );
181
+ print ('Search error ($ modelType ) : $e \n $st ' );
103
182
emit (
104
183
HeadlinesSearchFailure (
105
184
errorMessage: 'An unexpected error occurred during search.' ,
106
- lastSearchTerm: event.searchTerm,
185
+ lastSearchTerm: searchTerm,
186
+ selectedModelType: modelType,
107
187
),
108
188
);
109
189
}
0 commit comments