Skip to content

Commit 24896d6

Browse files
committed
refactor(headlines-search): migrate to shared ContentType enum
- Replace SearchModelType with ContentType from ht_shared package - Update UI to use new ContentType enum for search model selection - Adjust localization and error handling to work with new enum - Update imports and remove unused widgets
1 parent 3a9e578 commit 24896d6

File tree

2 files changed

+57
-47
lines changed

2 files changed

+57
-47
lines changed

lib/headlines-search/view/headlines_search_page.dart

Lines changed: 55 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -7,16 +7,17 @@ import 'package:go_router/go_router.dart';
77
import 'package:ht_main/app/bloc/app_bloc.dart';
88
// HeadlineItemWidget import removed
99
import '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
1211
import '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';
1414
import 'package:ht_main/headlines-search/widgets/source_item_widget.dart';
1515
import 'package:ht_main/l10n/app_localizations.dart';
1616
import 'package:ht_main/l10n/l10n.dart';
1717
import 'package:ht_main/router/routes.dart';
1818
import 'package:ht_main/shared/shared.dart';
1919
import '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.
2223
class 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
}

lib/router/router.dart

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -396,8 +396,8 @@ GoRouter createRouter({
396396
create: (context) {
397397
final feedInjectorService = FeedInjectorService();
398398
return HeadlinesSearchBloc(
399-
headlinesRepository: context
400-
.read<HtDataRepository<Headline>>(),
399+
headlinesRepository:
400+
context.read<HtDataRepository<Headline>>(),
401401
topicRepository: context.read<HtDataRepository<Topic>>(),
402402
sourceRepository: context.read<HtDataRepository<Source>>(),
403403
appBloc: context.read<AppBloc>(),

0 commit comments

Comments
 (0)