158 lines
4.6 KiB
Dart
158 lines
4.6 KiB
Dart
import 'package:agora_rtc_engine/agora_rtc_engine.dart';
|
||
import 'package:app/global/config.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';
|
||
|
||
class ContentView extends StatefulWidget {
|
||
const ContentView({super.key});
|
||
|
||
@override
|
||
State<ContentView> createState() => _ContentViewState();
|
||
}
|
||
|
||
class _ContentViewState extends State<ContentView> {
|
||
//声网数据
|
||
RtcEngine? _engine;
|
||
|
||
@override
|
||
void initState() {
|
||
super.initState();
|
||
_initRtc();
|
||
}
|
||
|
||
@override
|
||
void dispose() {
|
||
super.dispose();
|
||
WakelockPlus.disable();
|
||
_dispose();
|
||
}
|
||
|
||
void _initRtc() async {
|
||
final vm = context.read<TchRoomVM>();
|
||
_engine = createAgoraRtcEngine();
|
||
//初始化 RtcEngine,设置频道场景为 channelProfileLiveBroadcasting(直播场景)
|
||
await _engine!.initialize(
|
||
RtcEngineContext(
|
||
appId: Config.swAppId,
|
||
channelProfile: ChannelProfileType.channelProfileCommunication,
|
||
),
|
||
);
|
||
// 启用视频模块
|
||
await _engine!.enableVideo();
|
||
// 开启本地预览
|
||
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,
|
||
),
|
||
);
|
||
}
|
||
}
|
||
|
||
//销毁
|
||
Future<void> _dispose() async {
|
||
if (_engine != null) {
|
||
await _engine!.leaveChannel();
|
||
await _engine!.release();
|
||
}
|
||
}
|
||
|
||
@override
|
||
Widget build(BuildContext context) {
|
||
return Consumer<TchRoomVM>(
|
||
builder: (context, vm, _) {
|
||
if (vm.students.isEmpty) {
|
||
return Align(
|
||
child: Text(
|
||
'学生还没入场',
|
||
style: TextStyle(color: Colors.white),
|
||
),
|
||
);
|
||
}
|
||
//选中的学生
|
||
final activeStudent = vm.students.firstWhere((t) => t.userId == vm.activeSId);
|
||
//其他学生
|
||
final otherStudents = vm.students.where((t) => t.userId != vm.activeSId).toList()
|
||
..sort((a, b) => b.handup.compareTo(a.handup));
|
||
|
||
return Padding(
|
||
padding: const EdgeInsets.all(10),
|
||
child: Row(
|
||
spacing: 15,
|
||
children: [
|
||
Expanded(
|
||
child: Stack(
|
||
children: [
|
||
StudentItem(
|
||
user: activeStudent,
|
||
engine: _engine,
|
||
),
|
||
Positioned(
|
||
top: 10,
|
||
right: 10,
|
||
child: Container(
|
||
width: 200,
|
||
color: Colors.black,
|
||
child: AspectRatio(
|
||
aspectRatio: 16 / 9,
|
||
child: AgoraVideoView(
|
||
controller: VideoViewController(
|
||
rtcEngine: _engine!,
|
||
canvas: const VideoCanvas(uid: 0),
|
||
),
|
||
),
|
||
),
|
||
),
|
||
),
|
||
],
|
||
),
|
||
),
|
||
Visibility(
|
||
visible: otherStudents.isNotEmpty,
|
||
child: SizedBox(
|
||
width: 300,
|
||
child: ListView.separated(
|
||
itemBuilder: (_, index) {
|
||
var item = otherStudents.elementAt(index);
|
||
return SizedBox(
|
||
height: 250,
|
||
child: StudentItem(
|
||
user: item,
|
||
engine: _engine,
|
||
),
|
||
);
|
||
},
|
||
separatorBuilder: (_, __) => SizedBox(height: 15),
|
||
itemCount: otherStudents.length,
|
||
),
|
||
),
|
||
),
|
||
],
|
||
),
|
||
);
|
||
},
|
||
);
|
||
}
|
||
}
|