import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:go_router/go_router.dart'; import '../../core/constants.dart'; import '../../data/models/briefing_feed.dart'; import '../../providers/api_client_provider.dart'; import '../../providers/news_provider.dart'; import '../../widgets/news_card.dart'; class NewsScreen extends ConsumerStatefulWidget { const NewsScreen({super.key}); @override ConsumerState createState() => _NewsScreenState(); } class _NewsScreenState extends ConsumerState { final Set _openingChat = {}; Future _handleDiscuss(int itemId) async { if (_openingChat.contains(itemId)) return; setState(() => _openingChat.add(itemId)); try { final conversationId = await ref.read(chatApiProvider).openArticleInChat(itemId); if (mounted) { context.push(Routes.chat.replaceFirst(':id', '$conversationId')); } } catch (_) { if (mounted) { ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text('Failed to open article in chat.')), ); } } finally { if (mounted) setState(() => _openingChat.remove(itemId)); } } Future _loadMore() async { try { await ref.read(newsProvider.notifier).loadMore(); } catch (_) { if (mounted) { ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text('Failed to load more articles.')), ); } } } @override Widget build(BuildContext context) { final newsAsync = ref.watch(newsProvider); final feedsAsync = ref.watch(feedsProvider); final scheme = Theme.of(context).colorScheme; return Scaffold( appBar: AppBar( title: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text('News', style: Theme.of(context).textTheme.titleLarge), Text( 'Last 90 days', style: Theme.of(context).textTheme.labelSmall?.copyWith( color: scheme.onSurfaceVariant, ), ), ], ), ), body: newsAsync.when( loading: () => const Center(child: CircularProgressIndicator()), error: (e, _) => Center( child: Column( mainAxisSize: MainAxisSize.min, children: [ const Text('Could not load news.'), const SizedBox(height: 12), FilledButton.tonal( onPressed: () => ref.invalidate(newsProvider), child: const Text('Retry'), ), ], ), ), data: (news) => Column( children: [ _FeedFilter( feeds: feedsAsync.value ?? [], selectedFeedId: news.selectedFeedId, onChanged: (feedId) => ref.read(newsProvider.notifier).setFeed(feedId), ), const Divider(height: 1), Expanded( child: RefreshIndicator( onRefresh: () => ref.read(newsProvider.notifier).refresh(), child: ListView.builder( padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 8), itemCount: news.items.length + 1, itemBuilder: (_, i) { if (i == news.items.length) { if (!news.hasMore) return const SizedBox.shrink(); return Padding( padding: const EdgeInsets.symmetric(vertical: 8), child: Center( child: news.loadingMore ? const CircularProgressIndicator() : FilledButton.tonal( onPressed: _loadMore, child: const Text('Load more'), ), ), ); } final item = news.items[i]; return NewsCard( item: RssItemMeta.fromNewsItem(item), reaction: news.reactions[item.id], onReaction: (itemId, reaction) => ref .read(newsProvider.notifier) .toggleReaction(itemId, reaction), onDiscuss: _openingChat.contains(item.id) ? null : () => _handleDiscuss(item.id), ); }, ), ), ), ], ), ), ); } } class _FeedFilter extends StatelessWidget { final List feeds; final int? selectedFeedId; final void Function(int? feedId) onChanged; const _FeedFilter({ required this.feeds, required this.selectedFeedId, required this.onChanged, }); @override Widget build(BuildContext context) { return Padding( padding: const EdgeInsets.fromLTRB(16, 6, 16, 6), child: Row( children: [ Text( 'Feed:', style: Theme.of(context).textTheme.labelMedium?.copyWith( color: Theme.of(context).colorScheme.onSurfaceVariant, ), ), const SizedBox(width: 8), DropdownButton( value: selectedFeedId, underline: const SizedBox.shrink(), items: [ const DropdownMenuItem( value: null, child: Text('All feeds'), ), ...feeds.map( (f) => DropdownMenuItem( value: f.id, child: Text(f.title), ), ), ], onChanged: (v) => onChanged(v), ), ], ), ); } }