@@ -7,16 +7,17 @@ import 'package:go_router/go_router.dart';
77import 'package:ht_main/app/bloc/app_bloc.dart' ;
88// HeadlineItemWidget import removed
99import 'package:ht_main/headlines-search/bloc/headlines_search_bloc.dart' ;
10- import 'package:ht_main/headlines-search/models/search_model_type.dart' ;
1110// Import new item widgets
1211import 'package:ht_main/headlines-search/widgets/category_item_widget.dart' ;
12+ import 'package:ht_main/shared/extensions/content_type_extensions.dart' ;
1313// import 'package:ht_main/headlines-search/widgets/country_item_widget.dart';
1414import 'package:ht_main/headlines-search/widgets/source_item_widget.dart' ;
1515import 'package:ht_main/l10n/app_localizations.dart' ;
1616import 'package:ht_main/l10n/l10n.dart' ;
1717import 'package:ht_main/router/routes.dart' ;
1818import 'package:ht_main/shared/shared.dart' ;
1919import 'package:ht_shared/ht_shared.dart' ;
20+ import 'package:ht_ui_kit/ht_ui_kit.dart' ;
2021
2122/// Page widget responsible for providing the BLoC for the headlines search feature.
2223class HeadlinesSearchPage extends StatelessWidget {
@@ -46,7 +47,7 @@ class _HeadlinesSearchViewState extends State<_HeadlinesSearchView> {
4647 final _scrollController = ScrollController ();
4748 final _textController = TextEditingController ();
4849 bool _showClearButton = false ;
49- SearchModelType _selectedModelType = SearchModelType .headline;
50+ ContentType _selectedModelType = ContentType .headline;
5051
5152 @override
5253 void initState () {
@@ -57,9 +58,15 @@ class _HeadlinesSearchViewState extends State<_HeadlinesSearchView> {
5758 _showClearButton = _textController.text.isNotEmpty;
5859 });
5960 });
60- // Ensure _selectedModelType is valid (it should be, as .country is removed from enum)
61- if (! SearchModelType .values.contains (_selectedModelType)) {
62- _selectedModelType = SearchModelType .headline;
61+ // TODO(user): This logic might need adjustment if not all ContentType values are searchable.
62+ // For now, we default to headline if the current selection is not in the allowed list.
63+ final searchableTypes = [
64+ ContentType .headline,
65+ ContentType .topic,
66+ ContentType .source
67+ ];
68+ if (! searchableTypes.contains (_selectedModelType)) {
69+ _selectedModelType = ContentType .headline;
6370 }
6471 context.read <HeadlinesSearchBloc >().add (
6572 HeadlinesSearchModelTypeChanged (_selectedModelType),
@@ -99,16 +106,21 @@ class _HeadlinesSearchViewState extends State<_HeadlinesSearchView> {
99106
100107 @override
101108 Widget build (BuildContext context) {
102- final l10n = context.l10n;
109+ final l10n = AppLocalizationsX ( context) .l10n;
103110 final theme = Theme .of (context);
104111 final colorScheme = theme.colorScheme;
105112 final textTheme = theme.textTheme;
106113 final appBarTheme = theme.appBarTheme;
107114
108- final availableSearchModelTypes = SearchModelType .values.toList ();
115+ // TODO(user): Replace this with a filtered list of searchable content types.
116+ final availableSearchModelTypes = [
117+ ContentType .headline,
118+ ContentType .topic,
119+ ContentType .source,
120+ ];
109121
110122 if (! availableSearchModelTypes.contains (_selectedModelType)) {
111- _selectedModelType = SearchModelType .headline;
123+ _selectedModelType = ContentType .headline;
112124 WidgetsBinding .instance.addPostFrameCallback ((_) {
113125 if (mounted) {
114126 context.read <HeadlinesSearchBloc >().add (
@@ -127,7 +139,7 @@ class _HeadlinesSearchViewState extends State<_HeadlinesSearchView> {
127139 children: [
128140 SizedBox (
129141 width: 150 ,
130- child: DropdownButtonFormField <SearchModelType >(
142+ child: DropdownButtonFormField <ContentType >(
131143 value: _selectedModelType,
132144 decoration: const InputDecoration (
133145 border: InputBorder .none,
@@ -149,22 +161,14 @@ class _HeadlinesSearchViewState extends State<_HeadlinesSearchView> {
149161 appBarTheme.iconTheme? .color ??
150162 colorScheme.onSurfaceVariant,
151163 ),
152- items: availableSearchModelTypes.map ((SearchModelType type) {
153- String displayLocalizedName;
154- switch (type) {
155- case SearchModelType .headline:
156- displayLocalizedName = l10n.searchModelTypeHeadline;
157- case SearchModelType .category:
158- displayLocalizedName = l10n.searchModelTypeCategory;
159- case SearchModelType .source:
160- displayLocalizedName = l10n.searchModelTypeSource;
161- }
162- return DropdownMenuItem <SearchModelType >(
164+ // TODO(user): Use the new localization extension here.
165+ items: availableSearchModelTypes.map ((ContentType type) {
166+ return DropdownMenuItem <ContentType >(
163167 value: type,
164- child: Text (displayLocalizedName ),
168+ child: Text (type. displayName (context) ),
165169 );
166170 }).toList (),
167- onChanged: (SearchModelType ? newValue) {
171+ onChanged: (ContentType ? newValue) {
168172 if (newValue != null ) {
169173 setState (() {
170174 _selectedModelType = newValue;
@@ -185,7 +189,8 @@ class _HeadlinesSearchViewState extends State<_HeadlinesSearchView> {
185189 controller: _textController,
186190 style: appBarTheme.titleTextStyle ?? textTheme.titleMedium,
187191 decoration: InputDecoration (
188- hintText: _getHintTextForModelType (_selectedModelType, l10n),
192+ // TODO(user): Create a similar localization extension for hint text.
193+ hintText: 'Search...' ,
189194 hintStyle: textTheme.bodyMedium? .copyWith (
190195 color:
191196 (appBarTheme.titleTextStyle? .color ??
@@ -243,7 +248,7 @@ class _HeadlinesSearchViewState extends State<_HeadlinesSearchView> {
243248 icon: Icons .search_outlined,
244249 headline: l10n.headlinesFeedLoadingHeadline,
245250 subheadline:
246- 'Searching ${state .selectedModelType .displayName .toLowerCase ()}...' ,
251+ 'Searching ${state .selectedModelType .displayName ( context ) .toLowerCase ()}...' ,
247252 ),
248253 HeadlinesSearchSuccess (
249254 items: final items,
@@ -254,19 +259,20 @@ class _HeadlinesSearchViewState extends State<_HeadlinesSearchView> {
254259 ) =>
255260 errorMessage != null
256261 ? FailureStateWidget (
257- message : errorMessage,
262+ exception : UnknownException ( errorMessage) ,
258263 onRetry: () => context.read <HeadlinesSearchBloc >().add (
259264 HeadlinesSearchFetchRequested (
260265 searchTerm: lastSearchTerm,
261266 ),
262267 ),
263268 )
264269 : items.isEmpty
265- ? FailureStateWidget (
266- // Use FailureStateWidget for no results
267- message:
268- '${l10n .headlinesSearchNoResultsHeadline } for "$lastSearchTerm " in ${resultsModelType .displayName .toLowerCase ()}.\n ${l10n .headlinesSearchNoResultsSubheadline }' ,
269- // No retry button for "no results"
270+ ? InitialStateWidget (
271+ // Use InitialStateWidget for no results as it's not a failure
272+ icon: Icons .search_off_outlined,
273+ headline: l10n.headlinesSearchNoResultsHeadline,
274+ subheadline:
275+ 'For "$lastSearchTerm " in ${resultsModelType .displayName (context ).toLowerCase ()}.\n ${l10n .headlinesSearchNoResultsSubheadline }' ,
270276 )
271277 : ListView .separated (
272278 controller: _scrollController,
@@ -327,8 +333,9 @@ class _HeadlinesSearchViewState extends State<_HeadlinesSearchView> {
327333 );
328334 }
329335 return tile;
330- } else if (feedItem is Category ) {
331- return CategoryItemWidget (category: feedItem);
336+ } else if (feedItem is Topic ) {
337+ // TODO(user): Create a TopicItemWidget similar to CategoryItemWidget
338+ return ListTile (title: Text (feedItem.name));
332339 } else if (feedItem is Source ) {
333340 return SourceItemWidget (source: feedItem);
334341 } else if (feedItem is Ad ) {
@@ -361,29 +368,28 @@ class _HeadlinesSearchViewState extends State<_HeadlinesSearchView> {
361368 ),
362369 const SizedBox (height: AppSpacing .sm),
363370 Text (
364- 'Placeholder Ad: ${feedItem .adType .name ?? 'Generic' }' ,
371+ 'Placeholder Ad: ${feedItem .adType .name }' ,
365372 style: currentTextTheme.titleSmall,
366373 ),
367374 Text (
368- 'Placement: ${feedItem .placement .name ?? 'Default' }' ,
375+ 'Placement: ${feedItem .placement .name }' ,
369376 style: currentTextTheme.bodySmall,
370377 ),
371378 ],
372379 ),
373380 ),
374381 );
375- } else if (feedItem is AccountAction ) {
382+ } else if (feedItem is FeedAction ) {
376383 return Card (
377384 margin: const EdgeInsets .symmetric (
378385 vertical: AppSpacing .xs,
379386 ),
380387 color: currentColorScheme.secondaryContainer,
381388 child: ListTile (
382389 leading: Icon (
383- feedItem.accountActionType ==
384- AccountActionType .linkAccount
385- ? Icons
386- .link_outlined // Outlined
390+ feedItem.feedActionType ==
391+ FeedActionType .linkAccount
392+ ? Icons .link_outlined // Outlined
387393 : Icons .upgrade_outlined,
388394 color: currentColorScheme.onSecondaryContainer,
389395 ),
@@ -450,8 +456,9 @@ class _HeadlinesSearchViewState extends State<_HeadlinesSearchView> {
450456 selectedModelType: final failedModelType,
451457 ) =>
452458 FailureStateWidget (
453- message:
454- 'Failed to search "$lastSearchTerm " in ${failedModelType .displayName .toLowerCase ()}:\n $errorMessage ' ,
459+ exception: UnknownException (
460+ 'Failed to search "$lastSearchTerm " in ${failedModelType .displayName (context ).toLowerCase ()}:\n $errorMessage ' ,
461+ ),
455462 onRetry: () => context.read <HeadlinesSearchBloc >().add (
456463 HeadlinesSearchFetchRequested (searchTerm: lastSearchTerm),
457464 ),
@@ -463,18 +470,21 @@ class _HeadlinesSearchViewState extends State<_HeadlinesSearchView> {
463470 );
464471 }
465472
473+ // TODO(user): This method should be removed and replaced with a localization extension.
466474 String _getHintTextForModelType (
467- SearchModelType modelType,
475+ ContentType modelType,
468476 AppLocalizations l10n,
469477 ) {
470478 // The switch is now exhaustive for the remaining SearchModelType values
471479 switch (modelType) {
472- case SearchModelType .headline:
480+ case ContentType .headline:
473481 return l10n.searchHintTextHeadline;
474- case SearchModelType .category :
482+ case ContentType .topic :
475483 return l10n.searchHintTextCategory;
476- case SearchModelType .source:
484+ case ContentType .source:
477485 return l10n.searchHintTextSource;
486+ default :
487+ return 'Search...' ;
478488 }
479489 }
480490}
0 commit comments