From 701b99b13812b6fdf3c89fb9ee52506970e98bcd Mon Sep 17 00:00:00 2001 From: zhutao <1812073942@qq.com> Date: Wed, 19 Nov 2025 23:20:51 +0800 Subject: [PATCH] =?UTF-8?q?=E5=B0=81=E8=A3=85webscoekts?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/data/models/student.dart | 16 +++++ lib/pages/teacher/room/t_room_page.dart | 60 ++++++++++-------- .../room/viewmodel/students_view_model.dart | 33 ++++++++++ lib/websocket/room_websocket.dart | 63 +++++++++++++++++++ 4 files changed, 146 insertions(+), 26 deletions(-) create mode 100644 lib/data/models/student.dart create mode 100644 lib/pages/teacher/room/viewmodel/students_view_model.dart create mode 100644 lib/websocket/room_websocket.dart diff --git a/lib/data/models/student.dart b/lib/data/models/student.dart new file mode 100644 index 0000000..e659cec --- /dev/null +++ b/lib/data/models/student.dart @@ -0,0 +1,16 @@ +///学生视频的模型 +class Student { + final String id; + final String name; + final bool cameraOn; + final bool micOn; + final bool muted; + + Student({ + required this.id, + required this.name, + this.cameraOn = true, + this.micOn = true, + this.muted = true, + }); +} diff --git a/lib/pages/teacher/room/t_room_page.dart b/lib/pages/teacher/room/t_room_page.dart index 4c54aee..2aae604 100644 --- a/lib/pages/teacher/room/t_room_page.dart +++ b/lib/pages/teacher/room/t_room_page.dart @@ -1,8 +1,9 @@ import 'package:flutter/material.dart'; - +import 'package:provider/provider.dart'; import 'controls/top_bar.dart'; import 'view/student_item.dart'; import 'view/waiting_start.dart'; +import 'viewmodel/students_view_model.dart'; class TRoomPage extends StatefulWidget { const TRoomPage({super.key}); @@ -14,32 +15,39 @@ class TRoomPage extends StatefulWidget { class _TRoomPageState extends State { @override Widget build(BuildContext context) { - return Scaffold( - backgroundColor: Color(0xff2c3032), - appBar: TopBar(), - body: true ? WaitingStart() : Padding( - padding: const EdgeInsets.all(10), - child: Row( - spacing: 15, - children: [ - Expanded( - child: StudentItem(), - ), - SizedBox( - width: 300, - child: ListView.separated( - itemBuilder: (_, index) { - return SizedBox( - height: 250, - child: StudentItem(), - ); - }, - separatorBuilder: (_, __) => SizedBox(height: 15), - itemCount: 7, + return ChangeNotifierProvider( + create: (BuildContext context) { + return StudentsViewModel(); + }, + child: Scaffold( + backgroundColor: Color(0xff2c3032), + appBar: TopBar(), + body: true + ? WaitingStart() + : Padding( + padding: const EdgeInsets.all(10), + child: Row( + spacing: 15, + children: [ + Expanded( + child: StudentItem(), + ), + SizedBox( + width: 300, + child: ListView.separated( + itemBuilder: (_, index) { + return SizedBox( + height: 250, + child: StudentItem(), + ); + }, + separatorBuilder: (_, __) => SizedBox(height: 15), + itemCount: 7, + ), + ), + ], + ), ), - ), - ], - ), ), ); } diff --git a/lib/pages/teacher/room/viewmodel/students_view_model.dart b/lib/pages/teacher/room/viewmodel/students_view_model.dart new file mode 100644 index 0000000..f213b6e --- /dev/null +++ b/lib/pages/teacher/room/viewmodel/students_view_model.dart @@ -0,0 +1,33 @@ +import 'package:app/data/models/student.dart'; +import 'package:app/websocket/room_websocket.dart'; +import 'package:flutter/cupertino.dart'; + +class StudentsViewModel extends ChangeNotifier { + ///学生摄像头列表 + List _students = []; + + List get students => _students; + + ///websocket管理 + late RoomWebSocket _ws; + + StudentsViewModel() { + _startRoom(); + } + + ///开始链接房间 + void _startRoom() { + _ws = RoomWebSocket(); + _ws.connect(); + + _ws.stream.listen((msg) { + _handleMessage(); + }); + notifyListeners(); + } + + ///发送命令 + void _handleMessage() { + print("监听webscoket传来的事件"); + } +} diff --git a/lib/websocket/room_websocket.dart b/lib/websocket/room_websocket.dart new file mode 100644 index 0000000..1e18775 --- /dev/null +++ b/lib/websocket/room_websocket.dart @@ -0,0 +1,63 @@ +import 'dart:async'; +import 'dart:io'; +import 'package:logger/logger.dart'; + +Logger logger = Logger(); + +class RoomWebSocket { + ///单例设计模式 + RoomWebSocket._(); + + static final RoomWebSocket _instance = RoomWebSocket._(); + + factory RoomWebSocket() => _instance; + + /// WebSocket和心跳定时器 + String url = ""; + WebSocket? _socket; + Timer? _heartbeatTimer; + + ///用 StreamController 分化消息给订阅者 + final StreamController> _msgController = StreamController.broadcast(); + + Stream> get stream => _msgController.stream; + + ///开始连接 + Future connect() async { + try { + _socket = await WebSocket.connect(url); + //监听消息 + _socket!.listen( + (data) {}, + onDone: () {}, + onError: (_) { + logger.e("连接异常断开"); + }, + ); + //心跳 + _heartbeatTimer?.cancel(); + _heartbeatTimer = Timer.periodic(Duration(seconds: 15), (_) { + logger.i("发送心跳"); + }); + } catch (e) { + _reconnect(); + } + } + + ///发送指令 + void send() { + _socket!.add(""); + } + + ///连接错误事件 + void _reconnect() { + logger.e("连接错误"); + Future.delayed(Duration(seconds: 3), connect); + } + + void dispose() { + _heartbeatTimer?.cancel(); + _socket?.close(); + _msgController.close(); + } +}