自习室优化ok
This commit is contained in:
@@ -1,8 +1,8 @@
|
||||
import 'package:agora_rtc_engine/agora_rtc_engine.dart';
|
||||
import 'package:app/config/config.dart';
|
||||
import 'package:app/providers/user_store.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:wakelock_plus/wakelock_plus.dart';
|
||||
|
||||
import '../viewmodel/tch_room_vm.dart';
|
||||
import 'student_item.dart';
|
||||
@@ -27,11 +27,11 @@ class _ContentViewState extends State<ContentView> {
|
||||
@override
|
||||
void dispose() {
|
||||
super.dispose();
|
||||
WakelockPlus.disable();
|
||||
_dispose();
|
||||
}
|
||||
|
||||
void _initRtc() async {
|
||||
UserStore userStore = context.read<UserStore>();
|
||||
final vm = context.read<TchRoomVM>();
|
||||
_engine = createAgoraRtcEngine();
|
||||
//初始化 RtcEngine,设置频道场景为 channelProfileLiveBroadcasting(直播场景)
|
||||
@@ -41,39 +41,33 @@ class _ContentViewState extends State<ContentView> {
|
||||
channelProfile: ChannelProfileType.channelProfileCommunication,
|
||||
),
|
||||
);
|
||||
//添加回调
|
||||
_engine!.registerEventHandler(
|
||||
RtcEngineEventHandler(
|
||||
// 成功加入频道回调
|
||||
onJoinChannelSuccess: (RtcConnection connection, int elapsed) {
|
||||
setState(() {});
|
||||
},
|
||||
// 远端用户或主播加入当前频道回调
|
||||
onUserJoined: (RtcConnection connection, int remoteUid, int elapsed) {},
|
||||
// 远端用户或主播离开当前频道回调
|
||||
onUserOffline: (RtcConnection connection, int remoteUid, UserOfflineReasonType reason) {},
|
||||
),
|
||||
);
|
||||
//启动视频模块
|
||||
// 启用视频模块
|
||||
await _engine!.enableVideo();
|
||||
//加入频道
|
||||
await _engine!.joinChannel(
|
||||
token: vm.rtcToken!.token,
|
||||
channelId: vm.rtcToken!.channel,
|
||||
uid: userStore.userInfo!.id,
|
||||
options: ChannelMediaOptions(
|
||||
// 自动订阅所有视频流
|
||||
autoSubscribeVideo: true,
|
||||
// 自动订阅所有音频流
|
||||
autoSubscribeAudio: true,
|
||||
// 发布摄像头采集的视频
|
||||
publishCameraTrack: true,
|
||||
// 发布麦克风采集的音频
|
||||
publishMicrophoneTrack: true,
|
||||
// 设置用户角色为 clientRoleBroadcaster(主播)或 clientRoleAudience(观众)
|
||||
clientRoleType: ClientRoleType.clientRoleBroadcaster,
|
||||
),
|
||||
);
|
||||
// 开启本地预览
|
||||
await _engine!.startPreview();
|
||||
|
||||
final status = await _engine!.getConnectionState();
|
||||
WakelockPlus.enable();
|
||||
if (status == ConnectionStateType.connectionStateDisconnected) {
|
||||
//加入频道
|
||||
await _engine!.joinChannel(
|
||||
token: vm.rtcToken!.token,
|
||||
channelId: vm.rtcToken!.channel,
|
||||
uid: vm.rtcToken!.uid,
|
||||
options: ChannelMediaOptions(
|
||||
// 自动订阅所有视频流
|
||||
autoSubscribeVideo: true,
|
||||
// 自动订阅所有音频流
|
||||
autoSubscribeAudio: true,
|
||||
// 发布摄像头采集的视频
|
||||
publishCameraTrack: true,
|
||||
// 发布麦克风采集的音频
|
||||
publishMicrophoneTrack: true,
|
||||
// 设置用户角色为 clientRoleBroadcaster(主播)或 clientRoleAudience(观众)
|
||||
clientRoleType: ClientRoleType.clientRoleBroadcaster,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
//销毁
|
||||
@@ -89,8 +83,11 @@ class _ContentViewState extends State<ContentView> {
|
||||
return Consumer<TchRoomVM>(
|
||||
builder: (context, vm, _) {
|
||||
if (vm.students.isEmpty) {
|
||||
return Center(
|
||||
child: Text('准备中'),
|
||||
return Align(
|
||||
child: Text(
|
||||
'学生还没入场',
|
||||
style: TextStyle(color: Colors.white),
|
||||
),
|
||||
);
|
||||
}
|
||||
//选中的学生
|
||||
@@ -105,9 +102,30 @@ class _ContentViewState extends State<ContentView> {
|
||||
spacing: 15,
|
||||
children: [
|
||||
Expanded(
|
||||
child: StudentItem(
|
||||
user: activeStudent,
|
||||
engine: _engine,
|
||||
child: Stack(
|
||||
children: [
|
||||
StudentItem(
|
||||
user: activeStudent,
|
||||
engine: _engine,
|
||||
),
|
||||
Positioned(
|
||||
top: 0,
|
||||
left: 0,
|
||||
child: Container(
|
||||
width: 150,
|
||||
color: Colors.black,
|
||||
child: AspectRatio(
|
||||
aspectRatio: 1 / 1.2,
|
||||
child: AgoraVideoView(
|
||||
controller: VideoViewController(
|
||||
rtcEngine: _engine!,
|
||||
canvas: const VideoCanvas(uid: 0),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
SizedBox(
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:app/utils/time.dart';
|
||||
import 'package:app/widgets/base/dialog/config_dialog.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_easyloading/flutter_easyloading.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
import '../../../../widgets/room/core/count_down_vm.dart';
|
||||
import 'content_view.dart';
|
||||
import '../viewmodel/tch_room_vm.dart';
|
||||
|
||||
@@ -17,40 +17,12 @@ class StatusView extends StatefulWidget {
|
||||
}
|
||||
|
||||
class _StatusViewState extends State<StatusView> {
|
||||
int _seconds = 0;
|
||||
Timer? _timer;
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_timer?.cancel();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
void _startCountDown(DateTime startTime) {
|
||||
// 避免重复计时器
|
||||
if (_timer != null) return;
|
||||
|
||||
final now = DateTime.now();
|
||||
int diff = startTime.difference(now).inSeconds;
|
||||
|
||||
if (diff <= 0) {
|
||||
return;
|
||||
}
|
||||
setState(() {
|
||||
_seconds = diff;
|
||||
});
|
||||
|
||||
_timer = Timer.periodic(const Duration(seconds: 1), (timer) {
|
||||
if (!mounted) return;
|
||||
setState(() {
|
||||
_seconds--;
|
||||
});
|
||||
|
||||
if (_seconds <= 0) {
|
||||
_timer?.cancel();
|
||||
_timer = null;
|
||||
}
|
||||
});
|
||||
void initState() {
|
||||
super.initState();
|
||||
final countVM = context.read<CountDownVM>();
|
||||
countVM.removeListener(_onCountDownEnd);
|
||||
countVM.addListener(_onCountDownEnd);
|
||||
}
|
||||
|
||||
///开播中返回拦截弹窗
|
||||
@@ -72,55 +44,65 @@ class _StatusViewState extends State<StatusView> {
|
||||
);
|
||||
}
|
||||
|
||||
///监听会议室倒计时结束的时候
|
||||
void _onCountDownEnd() {
|
||||
final countVM = context.read<CountDownVM>();
|
||||
if (countVM.endCountDown == 0) {
|
||||
EasyLoading.showToast("自习室已到结束时间,请记得关闭会议室");
|
||||
countVM.removeListener(_onCountDownEnd);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final vm = context.watch<TchRoomVM>();
|
||||
final tchVM = context.watch<TchRoomVM>();
|
||||
var roomStatus = tchVM.roomInfo.roomStatus;
|
||||
|
||||
/// 1. 未加载
|
||||
if (vm.roomStatus == -1) {
|
||||
if (roomStatus == -1) {
|
||||
return const Align(
|
||||
child: Text("加载中", style: TextStyle(color: Colors.white)),
|
||||
);
|
||||
}
|
||||
|
||||
/// 2. 未开始的房间
|
||||
if (vm.roomStatus == 0) {
|
||||
if (vm.canEnterRoom) {
|
||||
// 到时间了 → 自动开播
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
vm.toggleRoom(isOpen: true);
|
||||
});
|
||||
} else {
|
||||
// 没到时间 → 启动倒计时
|
||||
_startCountDown(parseTime(vm.roomInfo.startTime));
|
||||
}
|
||||
|
||||
return Align(
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
const Text(
|
||||
"未到开播时间,到点后自动开播",
|
||||
style: TextStyle(color: Colors.white),
|
||||
),
|
||||
Container(
|
||||
margin: const EdgeInsets.symmetric(vertical: 10),
|
||||
child: Text(
|
||||
formatSeconds(_seconds),
|
||||
style: const TextStyle(
|
||||
color: Colors.white,
|
||||
fontSize: 26,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
if (roomStatus == 0) {
|
||||
return Consumer<CountDownVM>(
|
||||
builder: (_, countVM, __) {
|
||||
if (countVM.canEnterRoom) {
|
||||
tchVM.toggleRoom(isOpen: true);
|
||||
return SizedBox();
|
||||
} else {
|
||||
countVM.startStartCountdown();
|
||||
return Align(
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
const Text(
|
||||
"未到开播时间,到点后自动开播",
|
||||
style: TextStyle(color: Colors.white),
|
||||
),
|
||||
Container(
|
||||
margin: const EdgeInsets.symmetric(vertical: 10),
|
||||
child: Text(
|
||||
formatSeconds(countVM.startCountDown),
|
||||
style: const TextStyle(
|
||||
color: Colors.white,
|
||||
fontSize: 26,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
/// 3. 已开播
|
||||
if (vm.roomStatus == 1) {
|
||||
if (roomStatus == 1) {
|
||||
return PopScope(
|
||||
canPop: false,
|
||||
onPopInvokedWithResult: (didPop, _) {
|
||||
|
||||
@@ -2,6 +2,7 @@ import 'package:agora_rtc_engine/agora_rtc_engine.dart';
|
||||
import 'package:app/pages/teacher/room/viewmodel/type.dart';
|
||||
import 'package:app/request/dto/room/room_user_dto.dart';
|
||||
import 'package:app/widgets/room/file_drawer.dart';
|
||||
import 'package:app/widgets/room/other_widget.dart';
|
||||
import 'package:app/widgets/room/video_surface.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
@@ -26,7 +27,11 @@ class StudentItem extends StatefulWidget {
|
||||
class _StudentItemState extends State<StudentItem> {
|
||||
///打开文件列表
|
||||
void _openFileList() {
|
||||
showFileDialog(context, isUpload: false);
|
||||
showFileDialog(
|
||||
context,
|
||||
isUpload: false,
|
||||
files: widget.user.filesList,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -40,7 +45,6 @@ class _StudentItemState extends State<StudentItem> {
|
||||
|
||||
///声音是否开启
|
||||
bool isSpeakerOpen = widget.user.speekerStatus == 1;
|
||||
|
||||
return ClipRRect(
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
child: Container(
|
||||
@@ -51,15 +55,18 @@ class _StudentItemState extends State<StudentItem> {
|
||||
child: SizedBox(
|
||||
width: double.infinity,
|
||||
child: Stack(
|
||||
alignment: Alignment.bottomCenter,
|
||||
children: [
|
||||
if (widget.engine != null)
|
||||
AgoraVideoView(
|
||||
controller: VideoViewController(
|
||||
rtcEngine: widget.engine!,
|
||||
canvas: VideoCanvas(uid: widget.user.rtcUid),
|
||||
VideoSurface(
|
||||
user: widget.user,
|
||||
child: AgoraVideoView(
|
||||
controller: VideoViewController(
|
||||
rtcEngine: widget.engine!,
|
||||
canvas: VideoCanvas(uid: widget.user.rtcUid),
|
||||
),
|
||||
),
|
||||
),
|
||||
// VideoSurface(),
|
||||
Positioned(
|
||||
bottom: 0,
|
||||
left: 0,
|
||||
@@ -79,6 +86,8 @@ class _StudentItemState extends State<StudentItem> {
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
///右上角选中
|
||||
if (widget.user.userId != vm.activeSId)
|
||||
Positioned(
|
||||
right: 5,
|
||||
@@ -99,6 +108,17 @@ class _StudentItemState extends State<StudentItem> {
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
///举手
|
||||
if (widget.user.handup == 1)
|
||||
Positioned(
|
||||
bottom: 40,
|
||||
child: HandRaiseButton(
|
||||
onTap: () {
|
||||
vm.clearHandUp(widget.user.userId);
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
@@ -106,6 +126,7 @@ class _StudentItemState extends State<StudentItem> {
|
||||
ColoredBox(
|
||||
color: Color(0xFF232426),
|
||||
child: Row(
|
||||
spacing: 1,
|
||||
children: [
|
||||
_actionItem(
|
||||
icon: isCameraOpen ? RemixIcons.video_on_fill : RemixIcons.video_off_fill,
|
||||
|
||||
Reference in New Issue
Block a user