| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177 |
- import 'package:easy_refresh/easy_refresh.dart';
- import 'package:flutter/material.dart';
- import 'package:flutter_riverpod/flutter_riverpod.dart';
- import 'package:go_router/go_router.dart';
- import 'package:tdesign_flutter/tdesign_flutter.dart';
- import '../../core/theme/app_colors.dart';
- import '../../shared/widgets/empty_state.dart';
- import '../shell/nav_bar_config.dart';
- import '../../core/i18n/app_localizations.dart';
- import '../../shared/widgets/loading_widget.dart';
- import '../../shared/widgets/message_item.dart';
- import 'message_controller.dart';
- import 'message_model.dart';
- class MessageListPage extends ConsumerWidget {
- const MessageListPage({super.key});
- @override
- Widget build(BuildContext context, WidgetRef ref) {
- final messagesAsync = ref.watch(messageListProvider);
- final location = GoRouterState.of(context).uri.toString();
- final l10n = AppLocalizations.of(context);
- if (location.startsWith('/messages')) {
- ref
- .read(navBarConfigProvider.notifier)
- .update(
- NavBarConfig(
- title: l10n.get('tabMessages'),
- showBack: true,
- leadingIcon: Icons.close,
- ),
- );
- }
- return EasyRefresh(
- header: TDRefreshHeader(),
- onRefresh: () async {
- ref.invalidate(messageListProvider);
- await ref.read(messageListProvider.future);
- },
- child: messagesAsync.when(
- loading: () => const SingleChildScrollView(
- physics: AlwaysScrollableScrollPhysics(),
- child: LoadingWidget(),
- ),
- error: (_, _) => SingleChildScrollView(
- physics: const AlwaysScrollableScrollPhysics(),
- child: EmptyState(message: l10n.get('loadFailed')),
- ),
- data: (messages) => messages.isEmpty
- ? SingleChildScrollView(
- physics: const AlwaysScrollableScrollPhysics(),
- child: EmptyState(message: l10n.get('noMessages')),
- )
- : ListView.separated(
- padding: const EdgeInsets.fromLTRB(16, 16, 16, 24),
- itemCount: messages.length,
- separatorBuilder: (_, _) => const SizedBox(height: 12),
- itemBuilder: (_, i) => _buildItem(context, messages[i]),
- ),
- ),
- );
- }
- Widget _buildItem(BuildContext context, MessageModel msg) {
- final l10n = AppLocalizations.of(context);
- final (icon, iconColor, iconBg) = _messageIconProps(msg.msgType);
- final sender = _messageSender(msg.msgType, l10n);
- return MessageItem(
- icon: icon,
- iconColor: iconColor,
- iconBackground: iconBg,
- title: msg.title,
- time: _formatTime(msg.createTime, l10n),
- sender: sender,
- summary: msg.content,
- unread: !msg.isRead,
- onTap: () => _navigateToBiz(context, msg),
- onPin: () {
- TDMessage.showMessage(
- context: context,
- content: '${l10n.get("pinnedToast")}${msg.title}',
- theme: MessageTheme.info,
- icon: true,
- duration: 3000,
- );
- },
- onToggleRead: () {
- final action = msg.isRead
- ? l10n.get('markUnread')
- : l10n.get('markRead');
- TDMessage.showMessage(
- context: context,
- content: '$action:${msg.title}',
- theme: MessageTheme.success,
- icon: true,
- duration: 3000,
- );
- },
- onDelete: () {
- TDMessage.showMessage(
- context: context,
- content: '${l10n.get("deletedToast")}${msg.title}',
- theme: MessageTheme.warning,
- icon: true,
- duration: 3000,
- );
- },
- );
- }
- (IconData, Color, Color) _messageIconProps(String msgType) {
- switch (msgType) {
- case 'announcement':
- return (Icons.campaign, AppColors.warning, AppColors.warningBg);
- case 'approval_result':
- return (
- Icons.check_circle_outline,
- AppColors.success,
- AppColors.successBg,
- );
- case 'approval_notice':
- default:
- return (
- Icons.assignment_outlined,
- AppColors.primary,
- AppColors.primaryLight,
- );
- }
- }
- String _messageSender(String msgType, AppLocalizations l10n) {
- switch (msgType) {
- case 'announcement':
- return l10n.get('systemNotice');
- case 'approval_notice':
- return l10n.get('approvalNotice');
- case 'approval_result':
- return l10n.get('systemMessage');
- default:
- return l10n.get('systemMessage');
- }
- }
- String _formatTime(DateTime time, AppLocalizations l10n) {
- final now = DateTime.now();
- final diff = now.difference(time);
- if (diff.inMinutes < 60)
- return '${diff.inMinutes}${l10n.get("minutesAgo")}';
- if (diff.inHours < 24) return '${diff.inHours}${l10n.get("hoursAgo")}';
- if (diff.inDays < 7) return '${diff.inDays}${l10n.get("daysAgo")}';
- return '${time.month}/${time.day}';
- }
- void _navigateToBiz(BuildContext context, MessageModel msg) {
- if (msg.bizType == null || msg.bizId == null) return;
- switch (msg.bizType) {
- case 'expense':
- context.push('/expense/detail/${msg.bizId}');
- break;
- case 'overtime':
- context.push('/overtime/detail/${msg.bizId}');
- break;
- case 'vehicle':
- context.push('/vehicle/detail/${msg.bizId}');
- break;
- case 'announcement':
- context.push('/announcement/detail/${msg.bizId}');
- break;
- case 'expense_application':
- context.push('/expense-apply/detail/${msg.bizId}');
- break;
- }
- }
- }
|