|
|
@ -1,7 +1,7 @@ |
|
|
import 'package:agora_rtc_engine/agora_rtc_engine.dart'; |
|
|
import 'package:agora_rtc_engine/agora_rtc_engine.dart'; |
|
|
import 'package:agora_token_generator/agora_token_generator.dart'; |
|
|
|
|
|
import 'package:dating_touchme_app/model/live/live_chat_message.dart'; |
|
|
import 'package:dating_touchme_app/model/live/live_chat_message.dart'; |
|
|
import 'package:dating_touchme_app/model/rtc/rtc_channel_data.dart'; |
|
|
import 'package:dating_touchme_app/model/rtc/rtc_channel_data.dart'; |
|
|
|
|
|
import 'package:dating_touchme_app/model/rtc/rtc_channel_detail.dart'; |
|
|
import 'package:dating_touchme_app/network/network_service.dart'; |
|
|
import 'package:dating_touchme_app/network/network_service.dart'; |
|
|
import 'package:dating_touchme_app/rtc/rtc_manager.dart'; |
|
|
import 'package:dating_touchme_app/rtc/rtc_manager.dart'; |
|
|
import 'package:dating_touchme_app/service/live_chat_message_service.dart'; |
|
|
import 'package:dating_touchme_app/service/live_chat_message_service.dart'; |
|
|
@ -12,18 +12,20 @@ import 'package:permission_handler/permission_handler.dart'; |
|
|
/// 直播房间相关控制器 |
|
|
/// 直播房间相关控制器 |
|
|
class RoomController extends GetxController { |
|
|
class RoomController extends GetxController { |
|
|
RoomController({NetworkService? networkService}) |
|
|
RoomController({NetworkService? networkService}) |
|
|
: _networkService = networkService ?? Get.find<NetworkService>(); |
|
|
|
|
|
|
|
|
: _networkService = networkService ?? Get.find<NetworkService>(); |
|
|
|
|
|
|
|
|
final NetworkService _networkService; |
|
|
final NetworkService _networkService; |
|
|
|
|
|
|
|
|
/// 当前频道信息 |
|
|
/// 当前频道信息 |
|
|
final Rxn<RtcChannelData> rtcChannel = Rxn<RtcChannelData>(); |
|
|
final Rxn<RtcChannelData> rtcChannel = Rxn<RtcChannelData>(); |
|
|
|
|
|
final Rxn<RtcChannelDetail> rtcChannelDetail = Rxn<RtcChannelDetail>(); |
|
|
|
|
|
|
|
|
/// 聊天消息列表 |
|
|
/// 聊天消息列表 |
|
|
final RxList<LiveChatMessage> chatMessages = <LiveChatMessage>[].obs; |
|
|
final RxList<LiveChatMessage> chatMessages = <LiveChatMessage>[].obs; |
|
|
|
|
|
|
|
|
/// 消息服务实例 |
|
|
/// 消息服务实例 |
|
|
final LiveChatMessageService _messageService = LiveChatMessageService.instance; |
|
|
|
|
|
|
|
|
final LiveChatMessageService _messageService = |
|
|
|
|
|
LiveChatMessageService.instance; |
|
|
|
|
|
|
|
|
@override |
|
|
@override |
|
|
void onInit() { |
|
|
void onInit() { |
|
|
@ -54,10 +56,12 @@ class RoomController extends GetxController { |
|
|
/// 添加消息到列表(带去重和数量限制) |
|
|
/// 添加消息到列表(带去重和数量限制) |
|
|
void _addMessage(LiveChatMessage message) { |
|
|
void _addMessage(LiveChatMessage message) { |
|
|
// 去重:检查是否已存在相同的消息(基于 userId + content + timestamp) |
|
|
// 去重:检查是否已存在相同的消息(基于 userId + content + timestamp) |
|
|
final exists = chatMessages.any((m) => |
|
|
|
|
|
m.userId == message.userId && |
|
|
|
|
|
m.content == message.content && |
|
|
|
|
|
(m.timestamp - message.timestamp).abs() < 1000); // 1秒内的相同消息视为重复 |
|
|
|
|
|
|
|
|
final exists = chatMessages.any( |
|
|
|
|
|
(m) => |
|
|
|
|
|
m.userId == message.userId && |
|
|
|
|
|
m.content == message.content && |
|
|
|
|
|
(m.timestamp - message.timestamp).abs() < 1000, |
|
|
|
|
|
); // 1秒内的相同消息视为重复 |
|
|
|
|
|
|
|
|
if (exists) { |
|
|
if (exists) { |
|
|
print('⚠️ 消息已存在,跳过添加'); |
|
|
print('⚠️ 消息已存在,跳过添加'); |
|
|
@ -84,7 +88,12 @@ class RoomController extends GetxController { |
|
|
final base = response.data; |
|
|
final base = response.data; |
|
|
if (base.isSuccess && base.data != null) { |
|
|
if (base.isSuccess && base.data != null) { |
|
|
rtcChannel.value = base.data; |
|
|
rtcChannel.value = base.data; |
|
|
await _joinRtcChannel(base.data!.token, base.data!.channelId, base.data!.uid, ClientRoleType.clientRoleBroadcaster); |
|
|
|
|
|
|
|
|
await _joinRtcChannel( |
|
|
|
|
|
base.data!.token, |
|
|
|
|
|
base.data!.channelId, |
|
|
|
|
|
base.data!.uid, |
|
|
|
|
|
ClientRoleType.clientRoleBroadcaster, |
|
|
|
|
|
); |
|
|
} else { |
|
|
} else { |
|
|
final message = base.message.isNotEmpty ? base.message : '创建频道失败'; |
|
|
final message = base.message.isNotEmpty ? base.message : '创建频道失败'; |
|
|
SmartDialog.showToast(message); |
|
|
SmartDialog.showToast(message); |
|
|
@ -100,7 +109,12 @@ class RoomController extends GetxController { |
|
|
final base = response.data; |
|
|
final base = response.data; |
|
|
if (base.isSuccess && base.data != null) { |
|
|
if (base.isSuccess && base.data != null) { |
|
|
rtcChannel.value = base.data; |
|
|
rtcChannel.value = base.data; |
|
|
await _joinRtcChannel(base.data!.token, channelName, base.data!.uid, ClientRoleType.clientRoleAudience); |
|
|
|
|
|
|
|
|
await _joinRtcChannel( |
|
|
|
|
|
base.data!.token, |
|
|
|
|
|
channelName, |
|
|
|
|
|
base.data!.uid, |
|
|
|
|
|
ClientRoleType.clientRoleAudience, |
|
|
|
|
|
); |
|
|
} |
|
|
} |
|
|
} catch (e) { |
|
|
} catch (e) { |
|
|
SmartDialog.showToast('加入频道异常:$e'); |
|
|
SmartDialog.showToast('加入频道异常:$e'); |
|
|
@ -111,9 +125,10 @@ class RoomController extends GetxController { |
|
|
String token, |
|
|
String token, |
|
|
String channelName, |
|
|
String channelName, |
|
|
int uid, |
|
|
int uid, |
|
|
ClientRoleType roleType |
|
|
|
|
|
|
|
|
ClientRoleType roleType, |
|
|
) async { |
|
|
) async { |
|
|
try { |
|
|
try { |
|
|
|
|
|
await _fetchRtcChannelDetail(channelName); |
|
|
await RTCManager.instance.joinChannel( |
|
|
await RTCManager.instance.joinChannel( |
|
|
token: token, |
|
|
token: token, |
|
|
channelId: channelName, |
|
|
channelId: channelName, |
|
|
@ -125,9 +140,24 @@ class RoomController extends GetxController { |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
Future<void> _fetchRtcChannelDetail(String channelName) async { |
|
|
|
|
|
try { |
|
|
|
|
|
final response = await _networkService.rtcApi.getRtcChannelDetail( |
|
|
|
|
|
channelName, |
|
|
|
|
|
); |
|
|
|
|
|
final base = response.data; |
|
|
|
|
|
if (base.isSuccess && base.data != null) { |
|
|
|
|
|
rtcChannelDetail.value = base.data; |
|
|
|
|
|
} |
|
|
|
|
|
} catch (e) { |
|
|
|
|
|
print('获取 RTC 频道详情失败:$e'); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
/// 发送公屏消息 |
|
|
/// 发送公屏消息 |
|
|
Future<void> sendChatMessage(String content) async { |
|
|
Future<void> sendChatMessage(String content) async { |
|
|
final channelName = rtcChannel.value?.channelId ?? RTCManager.instance.currentChannelId; |
|
|
|
|
|
|
|
|
final channelName = |
|
|
|
|
|
rtcChannel.value?.channelId ?? RTCManager.instance.currentChannelId; |
|
|
|
|
|
|
|
|
final result = await _messageService.sendMessage( |
|
|
final result = await _messageService.sendMessage( |
|
|
content: content, |
|
|
content: content, |
|
|
@ -152,8 +182,9 @@ class RoomController extends GetxController { |
|
|
return true; |
|
|
return true; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
final permanentlyDenied = |
|
|
|
|
|
statuses.values.any((status) => status.isPermanentlyDenied); |
|
|
|
|
|
|
|
|
final permanentlyDenied = statuses.values.any( |
|
|
|
|
|
(status) => status.isPermanentlyDenied, |
|
|
|
|
|
); |
|
|
if (permanentlyDenied) { |
|
|
if (permanentlyDenied) { |
|
|
SmartDialog.showToast('请在系统设置中开启摄像头和麦克风权限'); |
|
|
SmartDialog.showToast('请在系统设置中开启摄像头和麦克风权限'); |
|
|
await openAppSettings(); |
|
|
await openAppSettings(); |
|
|
@ -167,4 +198,3 @@ class RoomController extends GetxController { |
|
|
await RTCManager.instance.leaveChannel(); |
|
|
await RTCManager.instance.leaveChannel(); |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|