import 'package:flutter/material.dart'; import 'package:flutter_svga/flutter_svga.dart'; import 'package:get/get.dart'; import 'package:dating_touchme_app/controller/discover/svga_player_manager.dart'; /// SVGA 动画播放 Widget /// 监听 SvgaPlayerManager 的队列,自动播放 SVGA 动画 class SvgaPlayerWidget extends StatefulWidget { const SvgaPlayerWidget({super.key}); @override State createState() => _SvgaPlayerWidgetState(); } class _SvgaPlayerWidgetState extends State with TickerProviderStateMixin { final SvgaPlayerManager _manager = SvgaPlayerManager.instance; SVGAAnimationController? _controller; SvgaAnimationItem? _currentItem; @override void initState() { super.initState(); // 监听队列变化 ever(_manager.currentItem, (item) { print( '📢 currentItem 变化: ${item?.svgaFile ?? "null"}, 当前 _currentItem: ${_currentItem?.svgaFile ?? "null"}', ); if (item != null) { // 如果当前没有播放,或者新的 item 与当前不同,则播放 if (_currentItem == null || item.svgaFile != _currentItem!.svgaFile) { print('🎯 准备播放新动画: ${item.svgaFile}'); _playAnimation(item); } else { print('⚠️ 相同的动画,跳过播放'); } } else { // currentItem 变为 null,但不立即清理,等待播放完成回调 print('📢 currentItem 变为 null,等待播放完成回调'); } }); } @override void dispose() { _controller?.dispose(); super.dispose(); } /// 播放动画 Future _playAnimation(SvgaAnimationItem item) async { print( '🎬 开始播放动画: ${item.svgaFile}, 当前状态: _controller=${_controller != null}, _currentItem=${_currentItem?.svgaFile ?? "null"}', ); // 如果正在播放,先停止并清理 if (_controller != null) { print('🛑 停止当前播放'); _controller!.stop(); _controller!.dispose(); _controller = null; } // 设置当前项并创建新的 controller _currentItem = item; _controller = SVGAAnimationController(vsync: this); print('✅ 创建新的 controller,准备加载动画'); try { // 判断是网络 URL 还是本地资源 if (item.svgaFile.startsWith('http://') || item.svgaFile.startsWith('https://')) { // 网络 URL SVGAParser.shared .decodeFromURL(item.svgaFile) .then((video) { if (!mounted) return; // 检查是否还是当前要播放的动画 if (_currentItem != item || _controller == null) { print('⚠️ 动画已变更,取消播放: ${item.svgaFile}'); return; } _controller!.videoItem = video; // 播放动画(repeat 会循环播放,我们需要监听完成) _controller!.repeat(); // 获取动画时长,如果为 null 则使用默认值 3 秒 final duration = _controller!.duration; final playDuration = duration != null && duration > Duration.zero ? duration : const Duration(seconds: 3); print( '✅ SVGA 动画加载成功(网络): ${item.svgaFile}, 播放时长: ${playDuration.inMilliseconds}ms', ); // 在动画时长后停止并通知完成 Future.delayed(playDuration, () { if (!mounted) { print('⚠️ Widget 已卸载,取消完成回调'); return; } // 再次检查是否还是当前动画 if (_currentItem == item && _controller != null) { print('✅ SVGA 动画播放完成(网络): ${item.svgaFile}'); // 先停止动画 _controller!.stop(); // 清理当前项和 controller final wasCurrentItem = _currentItem; _currentItem = null; _controller?.dispose(); _controller = null; // 通知管理器播放完成(这会触发下一个动画) if (wasCurrentItem == item) { _manager.onAnimationFinished(); } } else { print( '⚠️ 动画已变更,跳过完成回调: _currentItem=${_currentItem?.svgaFile ?? "null"}, item=${item.svgaFile}', ); } }); }) .catchError((error) { print('❌ SVGA 动画加载失败(网络): $error'); _currentItem = null; _controller?.dispose(); _controller = null; _manager.onAnimationError(error.toString()); }); } else { // 本地资源(assets) SVGAParser.shared .decodeFromAssets(item.svgaFile) .then((video) { if (!mounted) return; // 检查是否还是当前要播放的动画 if (_currentItem != item || _controller == null) { print('⚠️ 动画已变更,取消播放: ${item.svgaFile}'); return; } _controller!.videoItem = video; // 播放动画(repeat 会循环播放,我们需要监听完成) _controller!.repeat(); // 获取动画时长,如果为 null 则使用默认值 3 秒 final duration = _controller!.duration; final playDuration = duration != null && duration > Duration.zero ? duration : const Duration(seconds: 3); print( '✅ SVGA 动画加载成功(本地): ${item.svgaFile}, 播放时长: ${playDuration.inMilliseconds}ms', ); // 在动画时长后停止并通知完成 Future.delayed(playDuration, () { if (!mounted) { print('⚠️ Widget 已卸载,取消完成回调'); return; } // 再次检查是否还是当前动画 if (_currentItem == item && _controller != null) { print('✅ SVGA 动画播放完成(本地): ${item.svgaFile}'); // 先停止动画 _controller!.stop(); // 清理当前项和 controller final wasCurrentItem = _currentItem; _currentItem = null; _controller?.dispose(); _controller = null; // 通知管理器播放完成(这会触发下一个动画) if (wasCurrentItem == item) { _manager.onAnimationFinished(); } } else { print( '⚠️ 动画已变更,跳过完成回调: _currentItem=${_currentItem?.svgaFile ?? "null"}, item=${item.svgaFile}', ); } }); }) .catchError((error) { print('❌ SVGA 动画加载失败(本地): $error'); _currentItem = null; _controller?.dispose(); _controller = null; _manager.onAnimationError(error.toString()); }); } } catch (e) { print('❌ SVGA 播放异常: $e'); _currentItem = null; _controller?.dispose(); _controller = null; _manager.onAnimationError(e.toString()); } } @override Widget build(BuildContext context) { return Obx(() { final currentItem = _manager.currentItem.value; final isPlaying = _manager.isPlaying.value; if (!isPlaying || currentItem == null || _controller == null) { return const SizedBox.shrink(); } return Positioned.fill( child: IgnorePointer(child: SVGAImage(_controller!)), ); }); } }