|
|
|
@ -1,8 +1,10 @@ |
|
|
|
import 'package:agora_rtc_engine/agora_rtc_engine.dart'; |
|
|
|
import 'package:cached_network_image/cached_network_image.dart'; |
|
|
|
import 'package:dating_touchme_app/controller/message/call_controller.dart'; |
|
|
|
import 'package:dating_touchme_app/extension/ex_widget.dart'; |
|
|
|
import 'package:dating_touchme_app/generated/assets.dart'; |
|
|
|
import 'package:dating_touchme_app/pages/message/video_call_page.dart'; |
|
|
|
import 'package:dating_touchme_app/rtc/rtc_manager.dart'; |
|
|
|
import 'package:flutter/material.dart'; |
|
|
|
import 'package:flutter_screenutil/flutter_screenutil.dart'; |
|
|
|
import 'package:get/get.dart'; |
|
|
|
@ -30,6 +32,7 @@ class _VideoCallOverlayWidgetState extends State<VideoCallOverlayWidget> { |
|
|
|
Offset _position = Offset.zero; |
|
|
|
bool _isDragging = false; |
|
|
|
final CallController _callController = CallController.instance; |
|
|
|
final RTCManager _rtcManager = RTCManager.instance; |
|
|
|
|
|
|
|
@override |
|
|
|
void initState() { |
|
|
|
@ -59,6 +62,76 @@ class _VideoCallOverlayWidgetState extends State<VideoCallOverlayWidget> { |
|
|
|
}); |
|
|
|
} |
|
|
|
|
|
|
|
/// 构建背景(视频或头像) |
|
|
|
Widget _buildBackground() { |
|
|
|
return Obx(() { |
|
|
|
// 在 Obx 中访问响应式变量,确保建立监听关系 |
|
|
|
final callSession = _callController.currentCall.value; |
|
|
|
final isVideoCall = callSession != null && callSession.callType == CallType.video; |
|
|
|
final isConnected = callSession != null && _callController.callDurationSeconds.value > 0; |
|
|
|
final remoteUid = _callController.remoteUid.value; |
|
|
|
final remoteUsers = _rtcManager.remoteUsersNotifier.value; |
|
|
|
|
|
|
|
// 如果是视频通话且已接通,显示远端视频 |
|
|
|
if (isVideoCall && isConnected && remoteUid != null) { |
|
|
|
final engine = _rtcManager.engine; |
|
|
|
if (engine != null) { |
|
|
|
final remoteVideoViewController = VideoViewController( |
|
|
|
rtcEngine: engine, |
|
|
|
canvas: VideoCanvas(uid: remoteUid), |
|
|
|
); |
|
|
|
return SizedBox( |
|
|
|
width: 100.w, |
|
|
|
height: 100.w, |
|
|
|
child: AgoraVideoView( |
|
|
|
controller: remoteVideoViewController, |
|
|
|
), |
|
|
|
); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// 如果 remoteUid 为空,尝试从 RTCManager 的远端用户列表中获取 |
|
|
|
if (isVideoCall && isConnected && remoteUid == null && remoteUsers.isNotEmpty) { |
|
|
|
final firstRemoteUid = remoteUsers.first; |
|
|
|
final engine = _rtcManager.engine; |
|
|
|
if (engine != null) { |
|
|
|
_callController.remoteUid.value = firstRemoteUid; |
|
|
|
final remoteVideoViewController = VideoViewController( |
|
|
|
rtcEngine: engine, |
|
|
|
canvas: VideoCanvas(uid: firstRemoteUid), |
|
|
|
); |
|
|
|
return SizedBox( |
|
|
|
width: 100.w, |
|
|
|
height: 100.w, |
|
|
|
child: AgoraVideoView( |
|
|
|
controller: remoteVideoViewController, |
|
|
|
), |
|
|
|
); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// 默认显示头像 |
|
|
|
return Container( |
|
|
|
width: 100.w, |
|
|
|
height: 100.w, |
|
|
|
color: Colors.black, |
|
|
|
child: widget.targetAvatarUrl != null && widget.targetAvatarUrl!.isNotEmpty |
|
|
|
? CachedNetworkImage( |
|
|
|
imageUrl: widget.targetAvatarUrl!, |
|
|
|
fit: BoxFit.cover, |
|
|
|
errorWidget: (context, url, error) => Image.asset( |
|
|
|
Assets.imagesUserAvatar, |
|
|
|
fit: BoxFit.cover, |
|
|
|
), |
|
|
|
) |
|
|
|
: Image.asset( |
|
|
|
Assets.imagesUserAvatar, |
|
|
|
fit: BoxFit.cover, |
|
|
|
), |
|
|
|
); |
|
|
|
}); |
|
|
|
} |
|
|
|
|
|
|
|
/// 格式化通话时长 |
|
|
|
String _formatDuration(int seconds) { |
|
|
|
String twoDigits(int n) => n.toString().padLeft(2, '0'); |
|
|
|
@ -123,25 +196,8 @@ class _VideoCallOverlayWidgetState extends State<VideoCallOverlayWidget> { |
|
|
|
borderRadius: BorderRadius.circular(8.w), |
|
|
|
child: Stack( |
|
|
|
children: [ |
|
|
|
// 背景:头像 |
|
|
|
Container( |
|
|
|
width: 100.w, |
|
|
|
height: 100.w, |
|
|
|
color: Colors.black, |
|
|
|
child: widget.targetAvatarUrl != null && widget.targetAvatarUrl!.isNotEmpty |
|
|
|
? CachedNetworkImage( |
|
|
|
imageUrl: widget.targetAvatarUrl!, |
|
|
|
fit: BoxFit.cover, |
|
|
|
errorWidget: (context, url, error) => Image.asset( |
|
|
|
Assets.imagesUserAvatar, |
|
|
|
fit: BoxFit.cover, |
|
|
|
), |
|
|
|
) |
|
|
|
: Image.asset( |
|
|
|
Assets.imagesUserAvatar, |
|
|
|
fit: BoxFit.cover, |
|
|
|
), |
|
|
|
), |
|
|
|
// 背景:视频通话接通时显示远端视频,否则显示头像 |
|
|
|
_buildBackground(), |
|
|
|
// 半透明遮罩 |
|
|
|
Container( |
|
|
|
color: Colors.black.withOpacity(0.4), |
|
|
|
|