Skip to content

Commit a5feff7

Browse files
committed
refactor(shared): update headline tile to use new models
- Replaced `EntityType` with `ContentType`. - Updated widget to use `headline.createdAt` and `headline.topic`. - Removed null check for `imageUrl` as it's now required. - Adjusted metadata display and navigation logic for topics.
1 parent 283db77 commit a5feff7

File tree

1 file changed

+153
-32
lines changed

1 file changed

+153
-32
lines changed

lib/shared/widgets/headline_tile_image_start.dart

Lines changed: 153 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
11
import 'package:flutter/material.dart';
2-
import 'package:go_router/go_router.dart'; // Added
3-
import 'package:ht_main/entity_details/models/entity_type.dart';
4-
import 'package:ht_main/entity_details/view/entity_details_page.dart'; // Added for Page Arguments
2+
import 'package:go_router/go_router.dart';
3+
import 'package:ht_main/entity_details/view/entity_details_page.dart';
54
import 'package:ht_main/l10n/app_localizations.dart';
65
import 'package:ht_main/l10n/l10n.dart';
7-
import 'package:ht_main/router/routes.dart'; // Added
8-
import 'package:ht_shared/ht_shared.dart' show Headline;
6+
import 'package:ht_main/router/routes.dart';
7+
import 'package:ht_shared/ht_shared.dart';
98
import 'package:ht_ui_kit/ht_ui_kit.dart';
109
// timeago import removed from here, handled by utility
1110

@@ -33,7 +32,7 @@ class HeadlineTileImageStart extends StatelessWidget {
3332
final Widget? trailing;
3433

3534
/// The type of the entity currently being viewed in detail (e.g., on a category page).
36-
final EntityType? currentContextEntityType;
35+
final ContentType? currentContextEntityType;
3736

3837
/// The ID of the entity currently being viewed in detail.
3938
final String? currentContextEntityId;
@@ -62,32 +61,154 @@ class HeadlineTileImageStart extends StatelessWidget {
6261
height: 72,
6362
child: ClipRRect(
6463
borderRadius: BorderRadius.circular(AppSpacing.xs),
65-
child: headline.imageUrl != null
66-
? Image.network(
67-
headline.imageUrl,
68-
fit: BoxFit.cover,
69-
loadingBuilder: (context, child, loadingProgress) {
70-
if (loadingProgress == null) return child;
71-
return ColoredBox(
72-
color: colorScheme.surfaceContainerHighest,
73-
child: const Center(
74-
child: CircularProgressIndicator(
75-
strokeWidth: 2,
76-
),
77-
),
78-
);
79-
},
80-
errorBuilder: (context, error, stackTrace) =>
81-
ColoredBox(
82-
color: colorScheme.surfaceContainerHighest,
83-
child: Icon(
84-
Icons.broken_image_outlined,
85-
color: colorScheme.onSurfaceVariant,
86-
size: AppSpacing.xl,
87-
),
88-
),
89-
)
90-
: ColoredBox(
64+
child: Image.network(
65+
headline.imageUrl,
66+
fit: BoxFit.cover,
67+
loadingBuilder: (context, child, loadingProgress) {
68+
if (loadingProgress == null) return child;
69+
return ColoredBox(
70+
color: colorScheme.surfaceContainerHighest,
71+
child: const Center(
72+
child: CircularProgressIndicator(strokeWidth: 2),
73+
),
74+
);
75+
},
76+
errorBuilder: (context, error, stackTrace) => ColoredBox(
77+
color: colorScheme.surfaceContainerHighest,
78+
child: Icon(
79+
Icons.broken_image_outlined,
80+
color: colorScheme.onSurfaceVariant,
81+
size: AppSpacing.xl,
82+
),
83+
),
84+
),
85+
),
86+
),
87+
const SizedBox(width: AppSpacing.md),
88+
Expanded(
89+
child: Column(
90+
crossAxisAlignment: CrossAxisAlignment.start,
91+
children: [
92+
Text(
93+
headline.title,
94+
style: textTheme.titleMedium
95+
?.copyWith(fontWeight: FontWeight.w500),
96+
maxLines: 2,
97+
overflow: TextOverflow.ellipsis,
98+
),
99+
const SizedBox(height: AppSpacing.sm),
100+
_HeadlineMetadataRow(
101+
headline: headline,
102+
l10n: l10n,
103+
colorScheme: colorScheme,
104+
textTheme: textTheme,
105+
currentContextEntityType: currentContextEntityType,
106+
currentContextEntityId: currentContextEntityId,
107+
),
108+
],
109+
),
110+
),
111+
if (trailing != null) ...[
112+
const SizedBox(width: AppSpacing.sm),
113+
trailing!,
114+
],
115+
],
116+
),
117+
),
118+
),
119+
);
120+
}
121+
}
122+
123+
/// Private helper widget to build the metadata row.
124+
class _HeadlineMetadataRow extends StatelessWidget {
125+
const _HeadlineMetadataRow({
126+
required this.headline,
127+
required this.l10n,
128+
required this.colorScheme,
129+
required this.textTheme,
130+
this.currentContextEntityType,
131+
this.currentContextEntityId,
132+
});
133+
134+
final Headline headline;
135+
final AppLocalizations l10n;
136+
final ColorScheme colorScheme;
137+
final TextTheme textTheme;
138+
final ContentType? currentContextEntityType;
139+
final String? currentContextEntityId;
140+
141+
@override
142+
Widget build(BuildContext context) {
143+
// TODO(all): Use a utility function for relative time formatting.
144+
final formattedDate = ''; // formatRelativeTime(context, headline.createdAt);
145+
146+
final metadataTextStyle = textTheme.bodySmall?.copyWith(
147+
color: colorScheme.primary.withOpacity(0.7),
148+
);
149+
final iconColor = colorScheme.primary.withOpacity(0.7);
150+
const iconSize = AppSpacing.sm;
151+
152+
return Wrap(
153+
spacing: AppSpacing.sm,
154+
runSpacing: AppSpacing.xs,
155+
crossAxisAlignment: WrapCrossAlignment.center,
156+
children: [
157+
if (formattedDate.isNotEmpty)
158+
Row(
159+
mainAxisSize: MainAxisSize.min,
160+
children: [
161+
Icon(
162+
Icons.calendar_today_outlined,
163+
size: iconSize,
164+
color: iconColor,
165+
),
166+
const SizedBox(width: AppSpacing.xs / 2),
167+
Text(formattedDate, style: metadataTextStyle),
168+
],
169+
),
170+
if (headline.topic.name.isNotEmpty &&
171+
!(currentContextEntityType == ContentType.topic &&
172+
headline.topic.id == currentContextEntityId)) ...[
173+
if (formattedDate.isNotEmpty)
174+
Padding(
175+
padding: const EdgeInsets.symmetric(horizontal: AppSpacing.xs),
176+
child: Text('•', style: metadataTextStyle),
177+
),
178+
GestureDetector(
179+
onTap: () {
180+
context.push(
181+
Routes.topicDetails,
182+
extra: EntityDetailsPageArguments(entity: headline.topic),
183+
);
184+
},
185+
child: Text(headline.topic.name, style: metadataTextStyle),
186+
),
187+
],
188+
if (!(currentContextEntityType == ContentType.source &&
189+
headline.source.id == currentContextEntityId)) ...[
190+
if (formattedDate.isNotEmpty ||
191+
(headline.topic.name.isNotEmpty &&
192+
!(currentContextEntityType == ContentType.topic &&
193+
headline.topic.id == currentContextEntityId)))
194+
Padding(
195+
padding: const EdgeInsets.symmetric(horizontal: AppSpacing.xs),
196+
child: Text('•', style: metadataTextStyle),
197+
),
198+
GestureDetector(
199+
onTap: () {
200+
context.push(
201+
Routes.sourceDetails,
202+
extra: EntityDetailsPageArguments(entity: headline.source),
203+
);
204+
},
205+
child: Text(headline.source.name, style: metadataTextStyle),
206+
),
207+
],
208+
],
209+
);
210+
}
211+
}
91212
color: colorScheme.surfaceContainerHighest,
92213
child: Icon(
93214
Icons.image_not_supported_outlined,

0 commit comments

Comments
 (0)