| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147 |
- 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<WebInfoContent?, String>((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<NotificationDetailScreen> createState() =>
- _NotificationDetailScreenState();
- }
- class _NotificationDetailScreenState
- extends ConsumerState<NotificationDetailScreen> {
- @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,
- ),
- ),
- ],
- ),
- );
- },
- ),
- ),
- );
- }
- }
|