import 'package:auto_route/auto_route.dart'; import 'package:flutter/material.dart'; import '../../../common/theme/theme.dart'; import '../../../sample/news_sample_data.dart'; import '../../components/delegate/filter_bar_delegate.dart'; import '../../router/app_router.gr.dart'; import 'widgets/news_headline_card.dart'; import 'widgets/news_list_tile.dart'; @RoutePage() class NewsPage extends StatefulWidget { const NewsPage({super.key}); @override State createState() => _NewsPageState(); } class _NewsPageState extends State { /// `null` berarti semua kategori. static const List _filters = [null, ...NewsCategory.values]; NewsCategory? _category; /// Terbaru di atas. final List _articles = newsSamples ..sort((a, b) => b.publishedAt.compareTo(a.publishedAt)); void _open(NewsArticle article) => context.router.push(NewsDetailRoute(article: article)); @override Widget build(BuildContext context) { final visible = _articles .where((a) => _category == null || a.category == _category) .toList(); // Berita utama hanya di "Semua"; di kategori lain semua jadi daftar. final headline = _category == null ? visible.where((a) => a.isHeadline).firstOrNull : null; final rest = visible.where((a) => a != headline).toList(); return Scaffold( backgroundColor: AppColor.background, appBar: AppBar(title: const Text('EnakNews')), body: CustomScrollView( slivers: [ SliverPersistentHeader( pinned: true, delegate: FilterBarDelegate( values: _filters, selected: _category, labelOf: (category) => category?.label ?? 'Semua', onSelected: (category) => setState(() => _category = category), ), ), if (headline != null) SliverPadding( padding: const EdgeInsets.fromLTRB(16, 4, 16, 20), sliver: SliverToBoxAdapter( child: NewsHeadlineCard( article: headline, onTap: () => _open(headline), ), ), ), if (visible.isEmpty) SliverFillRemaining(hasScrollBody: false, child: _buildEmpty()) else if (rest.isNotEmpty) ...[ SliverPadding( padding: const EdgeInsets.fromLTRB(16, 4, 16, 10), sliver: SliverToBoxAdapter( child: Text( _category?.label ?? 'Terbaru', style: AppStyle.md.copyWith(fontWeight: FontWeight.w700), ), ), ), SliverPadding( padding: const EdgeInsets.symmetric(horizontal: 16), sliver: SliverToBoxAdapter(child: _buildList(rest)), ), ], const SliverToBoxAdapter(child: SizedBox(height: 24)), ], ), ); } Widget _buildList(List articles) { return Material( color: AppColor.white, borderRadius: BorderRadius.circular(16), clipBehavior: Clip.antiAlias, child: Column( children: [ for (var i = 0; i < articles.length; i++) ...[ if (i > 0) const Divider( height: 1, indent: 16, endIndent: 16, color: AppColor.borderLight, ), NewsListTile(article: articles[i], onTap: () => _open(articles[i])), ], ], ), ); } Widget _buildEmpty() { return Padding( padding: const EdgeInsets.fromLTRB(32, 32, 32, 64), child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ const Text('📰', style: TextStyle(fontSize: 44)), const SizedBox(height: 16), Text( 'Belum ada berita', textAlign: TextAlign.center, style: AppStyle.lg.copyWith(fontWeight: FontWeight.w700), ), const SizedBox(height: 6), Text( 'Berita terbaru dari outlet akan muncul di sini.', textAlign: TextAlign.center, style: AppStyle.sm.copyWith(color: AppColor.textSecondary), ), ], ), ); } }