import 'package:flutter/material.dart'; import '../../../core/l10n/app_localizations.dart'; import '../../../core/theme/app_colors.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_widget_from_html_core/flutter_widget_from_html_core.dart'; import 'package:go_router/go_router.dart'; import '../../../core/network/dio_client.dart'; import '../../../data/models/announcement/announcement.dart'; import '../../../data/services/announcement_service.dart'; import '../../../providers/announcement_unread_provider.dart'; /// 公告详情 Provider(按 id 异步加载) final _announcementDetailProvider = FutureProvider.autoDispose.family((ref, id) { final dio = ref.read(dioClientProvider); return AnnouncementService(dio).getAnnouncementDetail(id); }); class NotificationDetailScreen extends ConsumerStatefulWidget { const NotificationDetailScreen({super.key, required this.id}); final String id; @override ConsumerState createState() => _NotificationDetailScreenState(); } class _NotificationDetailScreenState extends ConsumerState { @override void initState() { super.initState(); WidgetsBinding.instance.addPostFrameCallback((_) { final id = int.tryParse(widget.id); if (id != null) markAnnouncementsRead(ref, id: id); }); } @override Widget build(BuildContext context) { final cs = Theme.of(context).colorScheme; final isDark = Theme.of(context).brightness == Brightness.dark; final asyncDetail = ref.watch(_announcementDetailProvider(widget.id)); return Scaffold( appBar: AppBar( elevation: 0, leading: IconButton( icon: const Icon(Icons.chevron_left, size: 28), onPressed: () => context.pop(), ), title: Text( AppLocalizations.of(context)!.announcementDetail, style: const TextStyle(fontSize: 18, fontWeight: FontWeight.w600), ), centerTitle: true, ), body: RefreshIndicator( onRefresh: () => ref.refresh(_announcementDetailProvider(widget.id).future), child: asyncDetail.when( loading: () => SingleChildScrollView( physics: const AlwaysScrollableScrollPhysics(), child: SizedBox( height: MediaQuery.of(context).size.height - 100, child: const Center(child: CircularProgressIndicator()), ), ), error: (e, _) => SingleChildScrollView( physics: const AlwaysScrollableScrollPhysics(), child: SizedBox( height: MediaQuery.of(context).size.height - 100, child: Center( child: Text(AppLocalizations.of(context)!.loadFailed, style: TextStyle(color: cs.onSurface.withAlpha(153))), ), ), ), data: (detail) { if (detail == null) { return SingleChildScrollView( physics: const AlwaysScrollableScrollPhysics(), child: SizedBox( height: MediaQuery.of(context).size.height - 100, child: Center( child: Text(AppLocalizations.of(context)!.announcementNotFound, style: TextStyle(color: cs.onSurface.withAlpha(153))), ), ), ); } return SingleChildScrollView( physics: const AlwaysScrollableScrollPhysics(), padding: const EdgeInsets.all(16), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ // 标题卡片 Container( width: double.infinity, padding: const EdgeInsets.all(16), decoration: BoxDecoration( color: isDark ? AppColors.darkBgSecondary : AppColors.lightBgSecondary, borderRadius: BorderRadius.circular(10), ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( detail.title, style: TextStyle( color: cs.onSurface, fontSize: 15, fontWeight: FontWeight.w600, ), ), const SizedBox(height: 6), Text( detail.createTime, style: TextStyle( color: cs.onSurface.withAlpha(153), fontSize: 12, ), ), ], ), ), const SizedBox(height: 16), // HTML 正文 HtmlWidget( detail.content, textStyle: TextStyle( color: cs.onSurface, fontSize: 14, height: 1.7, ), ), ], ), ); }, ), ), ); } }