import 'dart:collection'; import 'package:flutter/material.dart'; import 'package:intl/intl.dart'; import 'CacheAavatar.dart'; import 'StringTool.dart'; // 全局消息显示时长(可修改) Duration GlobalMessage_BakDuration = const Duration(seconds: 5); class GlobalData { final String? image; final String title; final String content; final dynamic payload; GlobalData({ this.image, required this.title, required this.content, this.payload, }); } class GlobalMessage_Bak { static final GlobalMessage_Bak _instance = GlobalMessage_Bak._internal(); static BuildContext? _context; // 消息队列 static final Queue<_MessageItem> _queue = Queue(); factory GlobalMessage_Bak() => _instance; GlobalMessage_Bak._internal(); static void init(BuildContext context) { _context = context; } static void push({ required GlobalData data, required Function(BuildContext) onTap, BuildContext? context, Duration? duration, }) { final useContext = context ?? _context; if (useContext == null) { throw Exception('GlobalMessage_Bak not initialized. Call GlobalMessage_Bak.init() first.'); } final controller = AnimationController( vsync: Navigator.of(useContext), duration: const Duration(milliseconds: 300), ); final slideAnimation = Tween( begin: const Offset(0, -1), end: Offset.zero, ).animate(CurvedAnimation(parent: controller, curve: Curves.easeOut)); final entry = OverlayEntry( builder: (_) => Positioned( top: MediaQuery.of(useContext).padding.top, left: 0, right: 0, child: SlideTransition( position: slideAnimation, child: _MessageContent( data: data, onTap: () { GlobalMessage_Bak.hide(); // 统一通过 GlobalMessage_Bak.hide() 隐藏 onTap(useContext); }, ), ), ), ); // 添加到队列 _queue.add(_MessageItem(entry: entry, controller: controller, duration: duration ?? GlobalMessage_BakDuration)); // 如果队列只有这一条,立即显示 if (_queue.length == 1) { _showNext(); } } static void _showNext() { if (_queue.isEmpty) return; final item = _queue.first; Overlay.of(_context!)!.insert(item.entry); item.controller.forward(); // 自动隐藏 Future.delayed(item.duration, () => hideCurrent()); } static void hideCurrent() { if (_queue.isEmpty) return; final item = _queue.first; item.controller.reverse().then((_) { item.entry.remove(); item.controller.dispose(); _queue.removeFirst(); _showNext(); // 显示队列中的下一条消息 }); } // 手动隐藏当前显示的消息 static void hide() => hideCurrent(); } // 队列中的消息项 class _MessageItem { final OverlayEntry entry; final AnimationController controller; final Duration duration; _MessageItem({required this.entry, required this.controller, required this.duration}); } class _MessageContent extends StatefulWidget { final GlobalData data; final VoidCallback onTap; const _MessageContent({Key? key, required this.data, required this.onTap}) : super(key: key); @override __MessageContentState createState() => __MessageContentState(); } class __MessageContentState extends State<_MessageContent> { late Offset _dragStartOffset; @override Widget build(BuildContext context) { final now = DateTime.now(); final formattedTime = DateFormat('HH:mm').format(now); return GestureDetector( onTap: widget.onTap, onVerticalDragStart: (details) { _dragStartOffset = details.globalPosition; }, onVerticalDragUpdate: (details) { if (details.globalPosition.dy < _dragStartOffset.dy - 50) { GlobalMessage_Bak.hide(); } }, child: Dismissible( key: Key(DateTime.now().millisecondsSinceEpoch.toString()), direction: DismissDirection.horizontal, onDismissed: (direction) => GlobalMessage_Bak.hide(), background: Container(color: Colors.transparent), child: Container( margin: const EdgeInsets.symmetric(horizontal: 12.0, vertical: 4.0), decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(12.0), boxShadow: [BoxShadow(color: Colors.black26, blurRadius: 8, offset: Offset(0, 4))], ), child: Padding( padding: const EdgeInsets.all(16.0), child: Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ if (widget.data.image != null) Padding( padding: const EdgeInsets.only(right: 16.0), child: CacheAvatar(url: widget.data.image!,), ), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Expanded( child: Text( widget.data.title, style: const TextStyle( fontWeight: FontWeight.bold, fontSize: 16, color: Colors.black87, decoration: TextDecoration.none), maxLines: 1, overflow: TextOverflow.ellipsis, ), ), Text( formattedTime, style: const TextStyle(fontSize: 12, color: Colors.grey,decoration: TextDecoration.none), ), ], ), const SizedBox(height: 6), Text( StringTool.stripMarkdown(widget.data.content), style: TextStyle( color: Colors.grey[500], fontSize: 12, decoration: TextDecoration.none), maxLines: 2, overflow: TextOverflow.ellipsis, ), ], ), ), ], ), ), ), ), ); } }