import 'package:flutter/material.dart'; import 'package:media_kit/media_kit.dart'; import 'package:media_kit_video/media_kit_video.dart'; import '../../core/config/test_stream.dart'; import '../../core/network/api_exception.dart'; import '../../core/theme/app_theme.dart'; import '../../core/storage/watch_dedup_store.dart'; import '../../models/video_item.dart'; import '../../services/video_service.dart'; import '../feed/widgets/feed_overlays.dart'; /// 单视频播放页(搜索结果/用户主页/作品/收藏/历史共用): /// 与 Feed 一致的观看计费(开始播放即上报,按 video_id+日期本地去重), /// 游客超限 2002 / 积分不足 2001 弹窗逻辑复用 feed_overlays。 class SimplePlayerScreen extends StatefulWidget { const SimplePlayerScreen({super.key, required this.item}); final VideoItem item; @override State createState() => _SimplePlayerScreenState(); } class _SimplePlayerScreenState extends State { late final Player _player = Player(); late final VideoController _controller = VideoController(_player); bool _playing = true; @override void initState() { super.initState(); _player.open(Media(resolvePlayUrl(widget.item))); _reportWatch(); } @override void dispose() { _player.dispose(); super.dispose(); } /// 观看上报(计费):本地去重后上报,扣费 Toast / 超限弹窗 Future _reportWatch() async { final dedup = WatchDedupStore.I; if (dedup.hasWatched(widget.item.videoId)) return; await dedup.markWatched(widget.item.videoId); try { final result = await VideoService.reportWatch(widget.item.videoId); if (!mounted) return; if (result.isPointsCost) { showTopToast(context, '本次消耗 ${result.costPoints} 积分'); } } on ApiException catch (e) { if (!mounted) return; _player.pause(); if (e.isGuestLimit) { showGuestLimitDialog(context); } else if (e.isPointsInsufficient) { showPointsInsufficientDialog( context, (e.data?['points'] as num?)?.toInt() ?? 0, ); } else { showTopToast(context, e.message); } } catch (_) {} } void _toggle() { setState(() => _playing = !_playing); _playing ? _player.play() : _player.pause(); } @override Widget build(BuildContext context) { return Scaffold( backgroundColor: Colors.black, body: GestureDetector( onTap: _toggle, child: Stack( fit: StackFit.expand, children: [ // 播放器 Center( child: Video( controller: _controller, controls: NoVideoControls, fit: BoxFit.contain, ), ), // 暂停态大播放图标 if (!_playing) const IgnorePointer( child: Center( child: Icon( Icons.play_circle_outline, size: 72, color: Colors.white70, ), ), ), // 返回按钮 const SafeArea( child: Align( alignment: Alignment.topLeft, child: BackButton(color: Colors.white), ), ), // 底部标题/作者 Positioned( left: 12, right: 12, bottom: 24, child: IgnorePointer( child: Column( crossAxisAlignment: CrossAxisAlignment.start, mainAxisSize: MainAxisSize.min, children: [ Text( '@${widget.item.author.nickname}', style: const TextStyle( fontSize: 15, fontWeight: FontWeight.w600, ), ), const SizedBox(height: 6), Text( widget.item.title, style: const TextStyle( fontSize: 14, color: AppColors.textSecondary, ), ), ], ), ), ), ], ), ), ); } }