fix: 完善直播结束通知与 WebSocket 连接

This commit is contained in:
2026-06-25 10:50:35 +08:00
parent 2281c98b1b
commit 80d4f692e0
12 changed files with 130 additions and 14 deletions

View File

@@ -43,6 +43,7 @@ class _PlayerPageState extends State<PlayerPage> {
bool _isRefreshing = false;
bool _isFullscreen = false;
bool _controlsVisible = true;
bool _streamEnded = false;
double _volume = kIsWeb ? 0.0 : 1.0;
int _playerVersion = 0;
String _selectedResolution = 'Source';
@@ -146,6 +147,10 @@ class _PlayerPageState extends State<PlayerPage> {
_chatService.messages.listen((msg) {
if (mounted) {
if (msg.type == "stream_end") {
_handleStreamEnded(msg.content);
return;
}
setState(() {
_messages.insert(0, msg);
if (!msg.isHistory && (msg.type == "chat" || msg.type == "danmaku")) {
@@ -158,6 +163,44 @@ class _PlayerPageState extends State<PlayerPage> {
});
}
void _handleStreamEnded(String message) {
if (_streamEnded) {
return;
}
final l10n = AppLocalizations.of(context)!;
final streamEndedMessage = l10n.liveStreamEnded;
setState(() {
_streamEnded = true;
_isRefreshing = false;
_danmakus.clear();
_messages.insert(
0,
ChatMessage(
type: "system",
username: "System",
content: streamEndedMessage,
roomId: widget.roomId,
),
);
if (!kIsWeb) {
_isError = true;
_errorMessage = streamEndedMessage;
}
});
ScaffoldMessenger.of(
context,
).showSnackBar(SnackBar(content: Text(streamEndedMessage)));
Future<void>.delayed(const Duration(seconds: 2), () {
if (mounted && Navigator.canPop(context)) {
Navigator.pop(context);
}
});
}
void _addDanmaku(String text) {
final key = UniqueKey();
final lane = DateTime.now().millisecondsSinceEpoch % 8;
@@ -180,7 +223,7 @@ class _PlayerPageState extends State<PlayerPage> {
}
void _sendMsg() {
if (_msgController.text.isNotEmpty) {
if (!_streamEnded && _msgController.text.isNotEmpty) {
final auth = context.read<AuthProvider>();
_chatService.sendMessage(
_msgController.text,
@@ -195,6 +238,9 @@ class _PlayerPageState extends State<PlayerPage> {
if (_isRefreshing) {
return;
}
if (_streamEnded) {
return;
}
await _loadPlaybackOptions();
@@ -625,7 +671,7 @@ class _PlayerPageState extends State<PlayerPage> {
_buildControlButton(
icon: Icons.refresh,
label: l10n.refresh,
onPressed: _refreshPlayer,
onPressed: _streamEnded ? null : _refreshPlayer,
),
_buildControlButton(
icon: _volume == 0
@@ -645,7 +691,9 @@ class _PlayerPageState extends State<PlayerPage> {
icon: _isFullscreen
? Icons.fullscreen_exit
: Icons.fullscreen,
label: _isFullscreen ? l10n.exitFullscreen : l10n.fullscreen,
label: _isFullscreen
? l10n.exitFullscreen
: l10n.fullscreen,
onPressed: _toggleFullscreen,
),
_buildControlButton(
@@ -665,13 +713,15 @@ class _PlayerPageState extends State<PlayerPage> {
Widget _buildControlButton({
required IconData icon,
required String label,
required FutureOr<void> Function() onPressed,
required FutureOr<void> Function()? onPressed,
}) {
return FilledButton.tonalIcon(
onPressed: () async {
_showControls();
await onPressed();
},
onPressed: onPressed == null
? null
: () async {
_showControls();
await onPressed();
},
icon: Icon(icon, size: 18),
label: Text(label),
style: FilledButton.styleFrom(
@@ -693,7 +743,10 @@ class _PlayerPageState extends State<PlayerPage> {
children: [
const Icon(Icons.chat_bubble_outline, size: 16),
const SizedBox(width: 8),
Text(l10n.liveChat, style: const TextStyle(fontWeight: FontWeight.bold)),
Text(
l10n.liveChat,
style: const TextStyle(fontWeight: FontWeight.bold),
),
],
),
),
@@ -716,8 +769,11 @@ class _PlayerPageState extends State<PlayerPage> {
Expanded(
child: TextField(
controller: _msgController,
enabled: !_streamEnded,
decoration: InputDecoration(
hintText: l10n.sendMessage,
hintText: _streamEnded
? l10n.liveStreamEndedShort
: l10n.sendMessage,
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(20),
),
@@ -734,7 +790,7 @@ class _PlayerPageState extends State<PlayerPage> {
Icons.send,
color: Theme.of(context).colorScheme.primary,
),
onPressed: _sendMsg,
onPressed: _streamEnded ? null : _sendMsg,
),
],
),