import 'dart:async'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import 'package:video_player/video_player.dart'; import '../providers/settings_provider.dart'; import '../services/chat_service.dart'; class PlayerPage extends StatefulWidget { final String title; final String rtmpUrl; final String roomId; const PlayerPage({ Key? key, required this.title, required this.rtmpUrl, required this.roomId, }) : super(key: key); @override _PlayerPageState createState() => _PlayerPageState(); } class _PlayerPageState extends State { late VideoPlayerController _controller; final ChatService _chatService = ChatService(); final TextEditingController _msgController = TextEditingController(); final List _messages = []; final List _danmakus = []; // 为简单起见,这里存储弹幕 Widget bool _isError = false; String? _errorMessage; @override void initState() { super.initState(); _initializePlayer(); _initializeChat(); } void _initializePlayer() async { _controller = VideoPlayerController.networkUrl(Uri.parse(widget.rtmpUrl)); try { await _controller.initialize(); _controller.play(); if (mounted) setState(() {}); } catch (e) { if (mounted) setState(() { _isError = true; _errorMessage = e.toString(); }); } } void _initializeChat() { final settings = context.read(); _chatService.connect(settings.baseUrl, widget.roomId, "User_${widget.roomId}"); // 暂定用户名 _chatService.messages.listen((msg) { if (mounted) { setState(() { _messages.insert(0, msg); if (msg.type == "chat" || msg.type == "danmaku") { _addDanmaku(msg.content); } }); } }); } void _addDanmaku(String text) { final id = DateTime.now().millisecondsSinceEpoch; final top = 20.0 + (id % 5) * 30.0; // 简单的多轨道显示 final danmaku = _DanmakuItem( key: ValueKey(id), text: text, top: top, onFinished: () { if (mounted) setState(() => _danmakus.removeWhere((w) => w.key == ValueKey(id))); }, ); setState(() => _danmakus.add(danmaku)); } void _sendMsg() { if (_msgController.text.isNotEmpty) { _chatService.sendMessage(_msgController.text, "Me", widget.roomId); _msgController.clear(); } } @override void dispose() { _controller.dispose(); _chatService.dispose(); _msgController.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: Text(widget.title)), body: Column( children: [ // 视频播放器 + 弹幕层 Container( color: Colors.black, width: double.infinity, height: 250, child: Stack( children: [ Center( child: _isError ? Text("Error: $_errorMessage", style: TextStyle(color: Colors.white)) : _controller.value.isInitialized ? AspectRatio(aspectRatio: _controller.value.aspectRatio, child: VideoPlayer(_controller)) : CircularProgressIndicator(), ), // 弹幕层 ..._danmakus, ], ), ), // 评论区标题 Container( padding: EdgeInsets.symmetric(horizontal: 16, vertical: 8), color: Theme.of(context).colorScheme.surfaceVariant, child: Row( children: [ Icon(Icons.chat_bubble_outline, size: 16), SizedBox(width: 8), Text("Live Chat", style: TextStyle(fontWeight: FontWeight.bold)), ], ), ), // 消息列表 Expanded( child: ListView.builder( reverse: true, itemCount: _messages.length, itemBuilder: (context, index) { final m = _messages[index]; return ListTile( dense: true, title: Text( "${m.username}: ${m.content}", style: TextStyle(color: m.type == "system" ? Colors.blue : null), ), ); }, ), ), // 输入框 Padding( padding: const EdgeInsets.all(8.0), child: Row( children: [ Expanded( child: TextField( controller: _msgController, decoration: InputDecoration( hintText: "Say something...", border: OutlineInputBorder(borderRadius: BorderRadius.circular(20)), contentPadding: EdgeInsets.symmetric(horizontal: 16), ), onSubmitted: (_) => _sendMsg(), ), ), SizedBox(width: 8), IconButton(icon: Icon(Icons.send, color: Colors.blue), onPressed: _sendMsg), ], ), ), ], ), ); } } class _DanmakuItem extends StatefulWidget { final String text; final double top; final VoidCallback onFinished; const _DanmakuItem({Key? key, required this.text, required this.top, required this.onFinished}) : super(key: key); @override __DanmakuItemState createState() => __DanmakuItemState(); } class __DanmakuItemState extends State<_DanmakuItem> with SingleTickerProviderStateMixin { late AnimationController _animationController; late Animation _animation; @override void initState() { super.initState(); _animationController = AnimationController(duration: const Duration(seconds: 8), vsync: this); _animation = Tween(begin: Offset(1.5, 0), end: Offset(-1.5, 0)).animate(_animationController); _animationController.forward().then((_) => widget.onFinished()); } @override void dispose() { _animationController.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return Positioned( top: widget.top, width: 300, child: SlideTransition( position: _animation, child: Text( widget.text, style: TextStyle(color: Colors.white, fontWeight: FontWeight.bold, fontSize: 16, shadows: [Shadow(blurRadius: 2, color: Colors.black)]), ), ), ); } }