diff --git a/lib/account/view/saved_headlines_page.dart b/lib/account/view/saved_headlines_page.dart index 8e50e49f..15c2d6e2 100644 --- a/lib/account/view/saved_headlines_page.dart +++ b/lib/account/view/saved_headlines_page.dart @@ -1,8 +1,18 @@ import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:go_router/go_router.dart'; +import 'package:ht_main/account/bloc/account_bloc.dart'; +import 'package:ht_main/headlines-feed/widgets/headline_item_widget.dart'; import 'package:ht_main/l10n/l10n.dart'; +import 'package:ht_main/router/routes.dart'; +import 'package:ht_main/shared/widgets/widgets.dart'; +import 'package:ht_shared/ht_shared.dart' show Headline; /// {@template saved_headlines_page} -/// A placeholder page for displaying user's saved headlines. +/// Displays the list of headlines saved by the user. +/// +/// Allows users to view details of a saved headline or remove it +/// from their saved list. /// {@endtemplate} class SavedHeadlinesPage extends StatelessWidget { /// {@macro saved_headlines_page} @@ -11,9 +21,69 @@ class SavedHeadlinesPage extends StatelessWidget { @override Widget build(BuildContext context) { final l10n = context.l10n; + return Scaffold( appBar: AppBar(title: Text(l10n.accountSavedHeadlinesTile)), - body: const Center(child: Text('SAVED HEADLINES PAGE (Placeholder)')), + body: BlocBuilder( + builder: (context, state) { + if (state.status == AccountStatus.loading && + state.preferences == null) { + return LoadingStateWidget( + icon: Icons.bookmarks_outlined, + headline: 'Loading Saved Headlines...', // Placeholder + subheadline: 'Please wait while we fetch your saved articles.', // Placeholder + ); + } + + if (state.status == AccountStatus.failure && + state.preferences == null) { + return FailureStateWidget( + message: + state.errorMessage ?? 'Could not load saved headlines.', // Placeholder + onRetry: () { + if (state.user?.id != null) { + context.read().add( + AccountLoadContentPreferencesRequested( + userId: state.user!.id, + ), + ); + } + }, + ); + } + + final savedHeadlines = state.preferences?.savedHeadlines ?? []; + + if (savedHeadlines.isEmpty) { + return InitialStateWidget( + icon: Icons.bookmark_add_outlined, + headline: 'No Saved Headlines', // Placeholder + subheadline: 'You haven\'t saved any articles yet. Start exploring!', // Placeholder + ); + } + + return ListView.separated( + itemCount: savedHeadlines.length, + separatorBuilder: (context, index) => const Divider(height: 1), + itemBuilder: (context, index) { + final headline = savedHeadlines[index]; + return HeadlineItemWidget( + headline: headline, + targetRouteName: Routes.accountArticleDetailsName, + trailing: IconButton( // Changed from trailingWidget + icon: const Icon(Icons.delete_outline), + tooltip: 'Remove from saved', // Placeholder + onPressed: () { + context.read().add( + AccountSaveHeadlineToggled(headline: headline), + ); + }, + ), + ); + }, + ); + }, + ), ); } } diff --git a/lib/headlines-feed/widgets/headline_item_widget.dart b/lib/headlines-feed/widgets/headline_item_widget.dart index 78a48d08..68c053be 100644 --- a/lib/headlines-feed/widgets/headline_item_widget.dart +++ b/lib/headlines-feed/widgets/headline_item_widget.dart @@ -10,6 +10,7 @@ class HeadlineItemWidget extends StatelessWidget { const HeadlineItemWidget({ required this.headline, required this.targetRouteName, // Add targetRouteName + this.trailing, // Add optional trailing widget super.key, }); @@ -19,6 +20,9 @@ class HeadlineItemWidget extends StatelessWidget { /// The named route to navigate to when the item is tapped. final String targetRouteName; // Add targetRouteName + /// An optional widget to display at the end of the row. + final Widget? trailing; + // Helper for date formatting static final _dateFormatter = DateFormat.yMd().add_jm(); @@ -159,6 +163,11 @@ class HeadlineItemWidget extends StatelessWidget { ], ), ), + // Add the trailing widget if provided + if (trailing != null) ...[ + const SizedBox(width: AppSpacing.md), + trailing!, + ], ], ), ), diff --git a/lib/router/router.dart b/lib/router/router.dart index ab4c0d4d..8aa2bc52 100644 --- a/lib/router/router.dart +++ b/lib/router/router.dart @@ -606,6 +606,22 @@ GoRouter createRouter({ child: Center(child: Text('SAVED HEADLINES PAGE')), ); }, + routes: [ + GoRoute( + path: Routes.accountArticleDetails, // 'article/:id' + name: Routes.accountArticleDetailsName, + builder: (context, state) { + final id = state.pathParameters['id']!; + return BlocProvider( + create: (context) => HeadlineDetailsBloc( + headlinesRepository: + context.read>(), + )..add(HeadlineDetailsRequested(headlineId: id)), + child: HeadlineDetailsPage(headlineId: id), + ); + }, + ), + ], ), ], ), diff --git a/lib/router/routes.dart b/lib/router/routes.dart index da4f74c3..2d1477d0 100644 --- a/lib/router/routes.dart +++ b/lib/router/routes.dart @@ -70,6 +70,10 @@ abstract final class Routes { static const manageFollowedItemsName = 'manageFollowedItems'; // Renamed static const accountSavedHeadlines = 'saved-headlines'; static const accountSavedHeadlinesName = 'accountSavedHeadlines'; + // New route for article details from saved headlines + static const String accountArticleDetails = + 'article/:id'; // Relative to accountSavedHeadlines + static const String accountArticleDetailsName = 'accountArticleDetails'; // --- Manage Followed Items Sub-Routes (relative to /account/manage-followed-items) --- static const followedCategoriesList = 'categories';