4262 lines
181 KiB
Objective-C
4262 lines
181 KiB
Objective-C
//
|
||
// YMRoomViewController.m
|
||
// YUMI
|
||
//
|
||
// Created by YUMI on 2021/10/11.
|
||
//
|
||
|
||
#import "XPRoomViewController.h"
|
||
///Third
|
||
#import <Masonry/Masonry.h>
|
||
#import <NIMSDK/NIMSDK.h>
|
||
///Tool
|
||
#import "YUMIMacroUitls.h"
|
||
#import "YUMIConstant.h"
|
||
#import "AccountInfoStorage.h"
|
||
#import "RtcManager.h"
|
||
#import "XPRoomMiniManager.h"
|
||
#import "TTPopup.h"
|
||
#import "TurboModeStateManager.h"
|
||
#import "Api+ArrangeMic.h"
|
||
#import "Api+Room.h"
|
||
#import "DESEncrypt.h"
|
||
#import "NSArray+Safe.h"
|
||
#import "NSMutableDictionary+Saft.h"
|
||
#import "XPSkillCardPlayerManager.h"
|
||
#import "XCCurrentVCStackManager.h"
|
||
#import "CountDownHelper.h"
|
||
///Model
|
||
#import "RoomInfoModel.h"
|
||
#import "UserInfoModel.h"
|
||
#import "AttachmentModel.h"
|
||
#import "ArrangeMicModel.h"
|
||
#import "XPReleaseRadioModel.h"
|
||
#import "GuildSuperAdminInfoModel.h"
|
||
#import "XPKickUserModel.h"
|
||
#import "ContentLevelUpgradeModel.h"
|
||
#import "XPReceiveRedPacketModel.h"
|
||
#import "XPRedPacketModel.h"
|
||
#import "XPFreeGiftModel.h"
|
||
#import "XPUserCardInfoModel.h"
|
||
///View
|
||
#import "BaseNavigationController.h"
|
||
#import "XPRoomBackContainerView.h"
|
||
#import "XPRoomMenuContainerView.h"
|
||
#import "XPRoomQuickMessageContainView.h"
|
||
#import "MsRoomMessageMainView.h"
|
||
#import "RoomHeaderView.h"
|
||
#import "SocialStageView.h"
|
||
#import "TenMicStageView.h"
|
||
#import "FifteenMicStageView.h"
|
||
#import "NineteenMicStageView.h"
|
||
#import "TwentyMicStageView.h"
|
||
#import "DatingStageView.h"
|
||
#import "AnchorStageView.h"
|
||
#import "AnchorPkStageView.h"
|
||
//#import "XPRoomAnimationView.h"
|
||
#import "RoomAnimationView.h"
|
||
#import "XPRoomFunctionContainerView.h"
|
||
#import "XPArrangeMicViewController.h"
|
||
#import "XPRoomSettingInputView.h"
|
||
#import "AnchorRoomScrollView.h"
|
||
#import "AnchorRoomSrollTipView.h"
|
||
#import "XPReceiveRedPacketView.h"
|
||
#import "XPWebViewController.h"
|
||
#import "SessionViewController.h"
|
||
#import "XPFreeGiftsObtainView.h"
|
||
|
||
///P
|
||
#import "XPRoomPresenter.h"
|
||
#import "XPRoomProtocol.h"
|
||
#import "XPWeakTimer.h"
|
||
#import "RoomHostDelegate.h"
|
||
#import "RoomGuestDelegate.h"
|
||
#import "Api+RoomSetting.h"
|
||
#import "XNDJTDDLoadingTool.h"
|
||
#import "ClientConfig.h"
|
||
#import "LittleGameStageView.h"
|
||
#import "LittleGameScrollStageView.h"
|
||
#import "XPRoomLittleGameContainerView.h"
|
||
#import "StageViewManager.h"
|
||
#import "PIRoomEnterRedPacketView.h"
|
||
#import "XPIAPRechargeViewController.h"
|
||
#import "XPCandyTreeInsufficientBalanceView.h"
|
||
|
||
#import "GiftComboManager.h"
|
||
#import "LuckyGiftWinningFlagView.h"
|
||
|
||
#import "RoomBoomResultView.h"
|
||
#import "RoomBoomManager.h"
|
||
#import "RoomBoomExplosionView.h"
|
||
#import "RoomBoomResultView.h"
|
||
|
||
#import "XPSendGiftView.h"
|
||
#import "RoomSideMenu.h"
|
||
#import "RoomResourceManager.h"
|
||
#import "LuckyPackageLogicManager.h"
|
||
|
||
#import "MicCpInfoModel.h"
|
||
#import "XPMessageRemoteExtModel.h"
|
||
#import "MicMidpointRectManager.h"
|
||
|
||
// 🔧 新增:Turbo Mode Tips 相关
|
||
#import "XPTurboModeTipsManager.h"
|
||
#import "BuglyManager.h"
|
||
|
||
//#import "XPMineHallAnchorIncomeStatisViewController.h"
|
||
|
||
UIKIT_EXTERN NSString * const kRoomGiftEffectUpdateNotificationKey;
|
||
UIKIT_EXTERN NSString * const kRoomMiniNotificationKey;
|
||
UIKIT_EXTERN NSString * kNewUserRechargeKey;
|
||
UIKIT_EXTERN NSString * const kMessageFromPublicRoomWithAttachmentNotification;
|
||
UIKIT_EXTERN NSString * const kFreeGiftCountdownNotification;
|
||
NSString * const kHadShowAnchorRoomTipKey = @"kHadShowAnchorRoomTipKey";//是否展示过个播房上划用户引导
|
||
NSString * const kHadQuitOtherRoomKey = @"kHadQuitOtherRoomKey";//是否退出过非自己房间
|
||
|
||
@interface XPRoomViewController ()<
|
||
XPRoomProtocol,
|
||
RoomHostDelegate,
|
||
NIMChatroomManagerDelegate,
|
||
NIMChatManagerDelegate,
|
||
NIMConversationManagerDelegate,
|
||
NIMLoginManagerDelegate,
|
||
XPRoomSettingInputViewDelegate,
|
||
AnchorRoomScrollViewDelegate,
|
||
NIMBroadcastManagerDelegate,
|
||
XPRoomLittleGameContainerViewDelegate,
|
||
CountDownHelperDelegate,
|
||
PIRoomEnterRedPacketViewDelegate,
|
||
XPReceiveRedPacketViewDelegate,
|
||
XPCandyTreeInsufficientBalanceViewDelegate>
|
||
|
||
///背景
|
||
@property (nonatomic,strong) XPRoomBackContainerView *backContainerView;
|
||
///个播上下切换view
|
||
@property (nonatomic, strong) AnchorRoomScrollView *anchorScrollView;
|
||
///房间信息
|
||
@property (nonatomic,strong) RoomHeaderView *roomHeaderView;
|
||
///坑位信息
|
||
@property (nonatomic,strong) StageView *stageView;
|
||
@property (nonatomic,strong) StageViewManager *stageViewManager;
|
||
@property (nonatomic,strong) TenMicStageView *tenMicStageView;
|
||
@property (nonatomic,strong) FifteenMicStageView *fifteenMicStageView;
|
||
@property (nonatomic,strong) TwentyMicStageView *twentyMicStageView;
|
||
@property(nonatomic, strong) NineteenMicStageView *nineteenMicStageView;
|
||
///公屏
|
||
@property (nonatomic,strong) MsRoomMessageMainView *messageContainerView;
|
||
///快捷发言
|
||
@property (nonatomic, strong) XPRoomQuickMessageContainView *quickMessageContainerView;
|
||
///底部操作栏
|
||
@property (nonatomic,strong) XPRoomMenuContainerView *menuContainerView;
|
||
///活动
|
||
@property(nonatomic, strong) RoomSideMenu *sideMenu;
|
||
|
||
///动画的view
|
||
@property (nonatomic,strong) RoomAnimationView *animationView;
|
||
///功能view的的容器
|
||
@property (nonatomic,strong) XPRoomFunctionContainerView *functionView;
|
||
///小游戏的容器
|
||
@property (nonatomic,strong) XPRoomLittleGameContainerView *littleGameView;
|
||
|
||
///房间的Uid
|
||
@property (nonatomic,copy) NSString * roomUid;
|
||
///小游戏的id
|
||
@property (nonatomic,copy) NSString *mgId;
|
||
///礼物id
|
||
@property (nonatomic, copy) NSString *giftId;
|
||
///用户信息
|
||
@property (nonatomic,strong) UserInfoModel *userInfo;
|
||
///房间信息
|
||
@property (nonatomic,strong) RoomInfoModel *roomInfo;
|
||
///本地是否修改过礼物特效显示 当前房间如果设置过礼物特效是否显示的话 就不再跟随房间礼物特效的更新而更新
|
||
@property (nonatomic,assign) BOOL hasAnimationEffect;
|
||
///跟随的
|
||
@property (nonatomic,copy) NSString *fromNick;
|
||
@property (nonatomic,assign) UserEnterRoomFromType fromType;
|
||
@property (nonatomic,copy) NSString *fromUid;
|
||
///超管列表
|
||
@property (nonatomic,strong) NSArray<GuildSuperAdminInfoModel *> *superMangerList;
|
||
///是否请求过了超管
|
||
@property (nonatomic,assign) BOOL isRequestSuperAdmin;
|
||
///是否是最小化进房
|
||
@property (nonatomic,assign) BOOL isMiniEnter;
|
||
///个播上划引导
|
||
@property (nonatomic, strong) AnchorRoomSrollTipView *anchorScrollTipView;
|
||
|
||
///滚动过的个播列表
|
||
@property (nonatomic,strong) NSMutableArray<NSString *> *anchorRoomList;
|
||
///序号
|
||
@property (nonatomic,assign) NSInteger anchorIndex;
|
||
|
||
///免费礼物数量
|
||
@property (nonatomic,strong) XPFreeGiftModel *freeModel;
|
||
///免费礼物弹窗
|
||
@property (nonatomic,strong) XPFreeGiftsObtainView *freeView;
|
||
///全服红包id
|
||
@property(nonatomic,copy) NSString *redEnvelopeId;
|
||
///红包
|
||
@property(nonatomic,strong) PIRoomEnterRedPacketView *redPacketView;
|
||
///是否正在显示红包弹窗,防止显示多个弹窗
|
||
@property(nonatomic,assign) BOOL isShowRedPacket;
|
||
@property(nonatomic,copy) NSString *releaseCoins;
|
||
|
||
// 🔧 防护机制:房间状态标志位
|
||
@property (atomic, assign) BOOL isExitingRoom; // 是否正在退出房间
|
||
@property (atomic, assign) BOOL isViewActive; // VC 是否可见/活跃
|
||
@property(nonatomic,copy) NSString *myCoins;
|
||
|
||
@property(nonatomic,strong) UIButton *exitGameButton;
|
||
|
||
/// 上麦请求弹窗定时器,用于10秒后自动移除弹窗
|
||
@property(nonatomic,strong) NSTimer *upMicAskTimer;
|
||
|
||
/// 🔧 修复:保存 block 形式的通知观察者,防止内存泄漏
|
||
@property(nonatomic,strong) id<NSObject> exchangeRoomAnimationViewObserver;
|
||
|
||
/// 当前房间的CP关系列表(用于在中点关系位播放对应cp等级的SVGA)
|
||
@property (nonatomic, strong) NSArray<MicCpInfoModel *> *currentCpList;
|
||
@property (nonatomic, assign) BOOL currentUserMicStatusChanged; // 当前用户麦位状态是否发生变化(上麦、下麦、换位)
|
||
@property (nonatomic, assign) BOOL currentUserWasOnMic; // 当前用户之前是否在麦上
|
||
@property (nonatomic, assign) NSInteger currentUserMicPosition; // 当前用户的麦位位置(-1表示不在麦上)
|
||
@property (nonatomic, assign) BOOL hasCompletedRoomInitialization; // 是否已完成进房初始化
|
||
|
||
@end
|
||
|
||
@implementation XPRoomViewController
|
||
|
||
+ (BOOL)openRoom:(NSString *)roomUid viewController:(UIViewController *)viewController {
|
||
return [self openRoom:roomUid fromNick:nil fromType:0 fromUid:nil viewController:viewController];
|
||
}
|
||
+ (BOOL)openRoom:(NSString *)roomUid viewController:(UIViewController *)viewController redEnvelopeId:(NSString *)redEnvelopeId{
|
||
XPRoomViewController * roomVC = [[self alloc] init];
|
||
roomVC.roomUid = roomUid;
|
||
roomVC.fromUid = nil;
|
||
roomVC.fromType = 0;
|
||
roomVC.fromNick = nil;
|
||
roomVC.redEnvelopeId = redEnvelopeId;
|
||
BaseNavigationController * baseNav = [[BaseNavigationController alloc] initWithRootViewController:roomVC];
|
||
baseNav.modalPresentationStyle = UIModalPresentationFullScreen;
|
||
[viewController presentViewController:baseNav animated:YES completion:nil];
|
||
return YES;
|
||
}
|
||
+ (BOOL)openRoom:(NSString*)roomUid fromNick:(NSString * __nullable)fromNick fromType:(UserEnterRoomFromType)fromType fromUid:(NSString * __nullable)fromUid viewController:(UIViewController*)viewController {
|
||
XPRoomViewController * roomVC = [[self alloc] init];
|
||
roomVC.roomUid = roomUid;
|
||
roomVC.fromUid = fromUid;
|
||
roomVC.fromType = fromType;
|
||
roomVC.fromNick = fromNick;
|
||
BaseNavigationController * baseNav = [[BaseNavigationController alloc] initWithRootViewController:roomVC];
|
||
baseNav.modalPresentationStyle = UIModalPresentationFullScreen;
|
||
[viewController presentViewController:baseNav animated:YES completion:nil];
|
||
return YES;
|
||
}
|
||
|
||
/**最小化进房
|
||
* @params roomUid 房主uid
|
||
* @params viewController 启动方
|
||
*/
|
||
+ (BOOL)openMiniRoom:(NSString*)roomUid viewController:(UIViewController*)viewController {
|
||
XPRoomViewController * roomVC = [[self alloc] init];
|
||
roomVC.roomUid = roomUid;
|
||
roomVC.isMiniEnter = YES;
|
||
BaseNavigationController * baseNav = [[BaseNavigationController alloc] initWithRootViewController:roomVC];
|
||
baseNav.modalPresentationStyle = UIModalPresentationFullScreen;
|
||
[viewController presentViewController:baseNav animated:YES completion:nil];
|
||
return roomVC;
|
||
}
|
||
/**最小化进房
|
||
* @params roomUid 房主uid
|
||
* @params viewController 启动方
|
||
* @params redEnvelopeId 全服红包id
|
||
*/
|
||
+ (BOOL)openMiniRoom:(NSString*)roomUid viewController:(UIViewController*)viewController redEnvelopeId:(NSString *)redEnvelopeId{
|
||
XPRoomViewController * roomVC = [[self alloc] init];
|
||
roomVC.roomUid = roomUid;
|
||
roomVC.isMiniEnter = YES;
|
||
roomVC.redEnvelopeId = redEnvelopeId;
|
||
BaseNavigationController * baseNav = [[BaseNavigationController alloc] initWithRootViewController:roomVC];
|
||
baseNav.modalPresentationStyle = UIModalPresentationFullScreen;
|
||
[viewController presentViewController:baseNav animated:YES completion:nil];
|
||
return roomVC;
|
||
}
|
||
/** XPRoomViewController 不允许外部 init ,请通过该方法启动房间。
|
||
* @params roomUid 房主uid
|
||
* @params viewController 启动方
|
||
* @params mgId 小游戏的id
|
||
*/
|
||
+ (BOOL)openRoom:(NSString*)roomUid mgId:(NSString *)mgId viewController:(UIViewController*)viewController {
|
||
XPRoomViewController * roomVC = [[self alloc] init];
|
||
roomVC.roomUid = roomUid;
|
||
roomVC.mgId = mgId;
|
||
BaseNavigationController * baseNav = [[BaseNavigationController alloc] initWithRootViewController:roomVC];
|
||
baseNav.modalPresentationStyle = UIModalPresentationFullScreen;
|
||
[viewController presentViewController:baseNav animated:YES completion:nil];
|
||
return YES;
|
||
}
|
||
|
||
/// h5进房并弹出礼物面板
|
||
/// @param roomUid 房主Uid
|
||
/// @param giftId 礼物id
|
||
/// @param viewController 启动方
|
||
+ (BOOL)openRoom:(NSString *)roomUid giftId:(NSString *)giftId viewController:(UIViewController *)viewController {
|
||
XPRoomViewController * roomVC = [[self alloc] init];
|
||
roomVC.roomUid = roomUid;
|
||
roomVC.giftId = giftId;
|
||
BaseNavigationController * baseNav = [[BaseNavigationController alloc] initWithRootViewController:roomVC];
|
||
baseNav.modalPresentationStyle = UIModalPresentationFullScreen;
|
||
[viewController presentViewController:baseNav animated:YES completion:nil];
|
||
return YES;
|
||
}
|
||
|
||
- (void)dealloc {
|
||
|
||
NSLog(@"🔄 XPRoomViewController: 开始销毁");
|
||
|
||
// 🔧 防护:强制清理 TRTC 连接,防止资源泄漏
|
||
[[RtcManager instance] exitRoom];
|
||
|
||
// 🔧 防护:标记房间正在退出,防止后续异步回调
|
||
self.isExitingRoom = YES;
|
||
self.isViewActive = NO;
|
||
|
||
[[RoomBoomManager sharedManager] leaveRoom];
|
||
|
||
[XPSkillCardPlayerManager shareInstance].photoIdList = nil;
|
||
[XPSkillCardPlayerManager shareInstance].isInRoomVC = NO;
|
||
[XPSkillCardPlayerManager shareInstance].isInRoomFirstRecharge = NO;
|
||
[XPSkillCardPlayerManager shareInstance].isInRoom = NO;
|
||
[XPSkillCardPlayerManager shareInstance].roomUid = @"";
|
||
|
||
if([[XPRoomMiniManager shareManager] getRoomInfo]==nil){
|
||
[XPSkillCardPlayerManager shareInstance].isMineInMic = NO;
|
||
}
|
||
|
||
[[CountDownHelper shareHelper] stopCountDown];
|
||
[CountDownHelper shareHelper].delegate = nil;
|
||
|
||
[[NIMSDK sharedSDK].chatroomManager removeDelegate:self];
|
||
[[NIMSDK sharedSDK].chatManager removeDelegate:self];
|
||
[[NIMSDK sharedSDK].loginManager removeDelegate:self];
|
||
[[NIMSDK sharedSDK].conversationManager removeDelegate:self];
|
||
[[NIMSDK sharedSDK].broadcastManager removeDelegate:self];
|
||
|
||
[[RoomBoomManager sharedManager] removeEventListenerForTarget:self];
|
||
|
||
// 🔧 修复:移除 block 形式的通知观察者
|
||
if (self.exchangeRoomAnimationViewObserver) {
|
||
[[NSNotificationCenter defaultCenter] removeObserver:self.exchangeRoomAnimationViewObserver];
|
||
self.exchangeRoomAnimationViewObserver = nil;
|
||
}
|
||
|
||
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
||
|
||
// 🔧 修复:清理 RoomAnimationView
|
||
if (_animationView) {
|
||
NSLog(@"🔄 XPRoomViewController: 清理 RoomAnimationView");
|
||
[_animationView removeItSelf];
|
||
[_animationView removeFromSuperview];
|
||
_animationView = nil;
|
||
}
|
||
|
||
// 清理上麦请求弹窗定时器
|
||
if (self.upMicAskTimer) {
|
||
[self.upMicAskTimer invalidate];
|
||
self.upMicAskTimer = nil;
|
||
}
|
||
|
||
NSLog(@"🔄 XPRoomViewController: 销毁完成");
|
||
}
|
||
|
||
- (XPRoomPresenter *)createPresenter {
|
||
return [[XPRoomPresenter alloc] init];
|
||
}
|
||
|
||
- (BOOL)isHiddenNavBar {
|
||
return YES;
|
||
}
|
||
|
||
- (void)viewDidLoad {
|
||
[super viewDidLoad];
|
||
|
||
[self exitOldRoom];
|
||
|
||
[self preLoadGifts];
|
||
|
||
[self initSubViews];
|
||
[self initSubViewConstraints];
|
||
|
||
[self setupNimSDK];
|
||
|
||
[self loadRoomDataAndUsers];
|
||
|
||
[self setupNotifications];
|
||
|
||
[self handleActivityContainerViewEvents];
|
||
|
||
///获取房间超管列表
|
||
[self.presenter getRoomSuperAdmin:self.roomUid];
|
||
|
||
[XPSkillCardPlayerManager shareInstance].isInRoom = YES;
|
||
|
||
[CountDownHelper shareHelper].delegate = self;
|
||
|
||
[self setupForBoom];
|
||
|
||
[self handleGiftComboCallBack];
|
||
|
||
[self setupStageViewManager];
|
||
|
||
// 🔧 新增:启动 Turbo Mode Tips 监听
|
||
[[XPTurboModeTipsManager sharedManager] startTipsMonitoringInRoom];
|
||
}
|
||
|
||
//- (void)test {
|
||
// XPMineHallAnchorIncomeStatisViewController *vc = [[XPMineHallAnchorIncomeStatisViewController alloc] init];
|
||
// [self.navigationController pushViewController:vc animated:YES];
|
||
//}
|
||
|
||
- (void)handleGiftComboCallBack {
|
||
@kWeakify(self);
|
||
[[GiftComboManager sharedManager] setHandleRoomUIChanged:^(BOOL comboViewDisplay) {
|
||
@kStrongify(self);
|
||
dispatch_async(dispatch_get_main_queue(), ^{
|
||
self.sideMenu.hidden = comboViewDisplay;
|
||
self.menuContainerView.hidden = comboViewDisplay;
|
||
|
||
// 添加状态验证:如果要隐藏UI,确保连击确实在进行
|
||
if (comboViewDisplay && ![[GiftComboManager sharedManager] isActive]) {
|
||
NSLog(@"⚠️ 检测到UI隐藏请求但连击未进行,执行强制重置");
|
||
[self forceBoomStateReset];
|
||
}
|
||
});
|
||
}];
|
||
}
|
||
|
||
- (void)setupForBoom {
|
||
@kWeakify(self);
|
||
[[RoomBoomManager sharedManager] registerBoomExplosion:^(id _Nonnull sth) {
|
||
@kStrongify(self);
|
||
[self.presenter getBoomDetail:self.roomUid];
|
||
|
||
if (![sth isKindOfClass:[NSArray class]]) {
|
||
return;
|
||
}
|
||
dispatch_async(dispatch_get_main_queue(), ^{
|
||
[RoomBoomExplosionView display:self.view with:sth complete:^{ }];
|
||
});
|
||
} target:self];
|
||
|
||
[[RoomBoomManager sharedManager] registerBoomGiftDisplay:^(id _Nonnull sth) {
|
||
@kStrongify(self);
|
||
dispatch_async(dispatch_get_main_queue(), ^{
|
||
[RoomBoomResultView display:self.view attachment:sth];
|
||
});
|
||
} target:self];
|
||
|
||
[[RoomBoomManager sharedManager] registerBoomEnterRoomExplosion:^(id _Nonnull sth) {
|
||
@kStrongify(self);
|
||
if (![sth isKindOfClass:[NSArray class]]) {
|
||
return;
|
||
}
|
||
dispatch_async(dispatch_get_main_queue(), ^{
|
||
[RoomBoomExplosionView display:self.view with:sth complete:^{
|
||
|
||
}];
|
||
});
|
||
} target:self];
|
||
}
|
||
|
||
- (void)requestBoomData {
|
||
[self.presenter getBoomRocketAnimationInfo:self.roomUid];
|
||
[self.presenter getBoomDetail:self.roomUid];
|
||
}
|
||
|
||
- (void)loadRoomDataAndUsers {
|
||
[XNDJTDDLoadingTool showAnchorLoading:self.navigationController.view];
|
||
[self.presenter initEnterRoom:self.roomUid user:[AccountInfoStorage instance].getUid];
|
||
}
|
||
|
||
- (void)setupNotifications {
|
||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(myGiftEffectUpdate:) name:kRoomGiftEffectUpdateNotificationKey object:nil];
|
||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(openRedPacketNotification:) name:@"kOpenRedPacketNotification" object:nil];
|
||
|
||
// 添加公共房间消息转发通知监听
|
||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||
selector:@selector(handlePublicRoomMessageForward:)
|
||
name:@"MessageFromPublicRoomWithAttachmentNotification"
|
||
object:nil];
|
||
|
||
// 添加应用生命周期保护
|
||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||
selector:@selector(applicationDidEnterBackground:)
|
||
name:UIApplicationDidEnterBackgroundNotification
|
||
object:nil];
|
||
|
||
@kWeakify(self);
|
||
// 🔧 修复:保存 block 观察者的返回值,防止内存泄漏
|
||
self.exchangeRoomAnimationViewObserver = [[NSNotificationCenter defaultCenter] addObserverForName:@"kExchangeRoomAnimationViewAndGameViewIndex"
|
||
object:nil
|
||
queue:NSOperationQueue.mainQueue
|
||
usingBlock:^(NSNotification * _Nonnull notification) {
|
||
@kStrongify(self);
|
||
if (self.view.subviews.count > 0) {
|
||
UIView *topView = self.view.subviews.lastObject;
|
||
UIView *secondView = [self.view.subviews xpSafeObjectAtIndex:self.view.subviews.count-2];
|
||
if (secondView && secondView.tag == 913) {
|
||
NSInteger index1 = [self.view.subviews indexOfObject:topView];
|
||
NSInteger index2 = [self.view.subviews indexOfObject:secondView];
|
||
[self.view exchangeSubviewAtIndex:index1 withSubviewAtIndex:index2];
|
||
}
|
||
}
|
||
}];
|
||
}
|
||
|
||
- (void)setupNimSDK {
|
||
//监听云信消息
|
||
[[NIMSDK sharedSDK].chatroomManager addDelegate:self];
|
||
[[NIMSDK sharedSDK].chatManager addDelegate:self];
|
||
[[NIMSDK sharedSDK].loginManager addDelegate:self];
|
||
[[NIMSDK sharedSDK].conversationManager addDelegate:self];
|
||
[[NIMSDK sharedSDK].broadcastManager addDelegate:self];
|
||
}
|
||
|
||
/// 禮物面板緩存-2: 進房後,用當前的 roomUid 加載最新數據,並緩存
|
||
- (void)preLoadGifts {
|
||
[self.presenter getNormalGiftList:self.roomUid];
|
||
|
||
///获取免费礼物
|
||
[self.presenter getFreeGiftData];
|
||
|
||
if(![NSString isEmpty:self.redEnvelopeId]){
|
||
[self.presenter getRedPacketInft:self.redEnvelopeId];
|
||
}
|
||
}
|
||
|
||
#pragma mark - MSSessionReleaseHeadlinesViewDelegate
|
||
-(void)releaseHeadlinesWithText:(NSString *)text{
|
||
XPCandyTreeInsufficientBalanceView *balanceView = [[XPCandyTreeInsufficientBalanceView alloc]initWithFrame:CGRectMake(0, 0, KScreenWidth, KScreenHeight)];
|
||
balanceView.delegate = self;
|
||
[self.view addSubview:balanceView];
|
||
|
||
}
|
||
#pragma mark - XPCandyTreeInsufficientBalanceViewDelegate
|
||
- (void)payBalanceAction{
|
||
XPIAPRechargeViewController * webVC =[[XPIAPRechargeViewController alloc] init];
|
||
webVC.type = @"4";
|
||
[self.navigationController pushViewController:webVC animated:YES];
|
||
}
|
||
///打开红包通知
|
||
-(void)openRedPacketNotification:(NSNotification *)not{
|
||
NSDictionary *redPacketDic = not.userInfo;
|
||
NSInteger type = [redPacketDic[@"type"] integerValue];
|
||
NSInteger userId = [redPacketDic[@"uid"] integerValue];
|
||
// NSString *roomUid = redPacketDic[@"roomUId"];
|
||
if(type == 2){
|
||
[self.messageContainerView showUserCard:userId];
|
||
}else if (type == 3){
|
||
// [self.roomHeaderView showSharePanel];
|
||
}else if (type == 4){
|
||
NSString *scrolling = redPacketDic[@"scrolling"];
|
||
[self.menuContainerView showInputView:scrolling];
|
||
}
|
||
}
|
||
|
||
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
|
||
[self.menuContainerView menuResignFirstResponder];
|
||
}
|
||
|
||
- (void)viewWillAppear:(BOOL)animated {
|
||
[super viewWillAppear:animated];
|
||
[UIApplication sharedApplication].statusBarStyle = UIStatusBarStyleLightContent;
|
||
|
||
[self.menuContainerView recheckMicState];
|
||
}
|
||
-(void)viewWillDisappear:(BOOL)animated{
|
||
[super viewWillDisappear:animated];
|
||
self.freeView.hidden = YES;
|
||
|
||
// 🔧 防护:标记 VC 即将不可见
|
||
self.isViewActive = NO;
|
||
|
||
// 🔧 防护:如果 VC 被移除或 dismiss,强制清理 TRTC
|
||
if (self.isMovingFromParentViewController || self.isBeingDismissed) {
|
||
[[RtcManager instance] exitRoom];
|
||
self.isExitingRoom = YES;
|
||
}
|
||
|
||
// 如果连击正在进行,强制重置
|
||
if ([[GiftComboManager sharedManager] isActive]) {
|
||
NSLog(@"📱 房间即将退出,检查连击状态");
|
||
[self forceBoomStateReset];
|
||
}
|
||
}
|
||
|
||
- (void)viewDidDisappear:(BOOL)animated{
|
||
[super viewDidDisappear:animated];
|
||
self.navigationController.interactivePopGestureRecognizer.enabled = YES;
|
||
[XPSkillCardPlayerManager shareInstance].isInRoomVC = NO;
|
||
|
||
// 🔧 防护:确保标记为不可见
|
||
self.isViewActive = NO;
|
||
|
||
// 🔧 修复:发送房间退出通知,让 BuglyManager 知道用户已退出房间
|
||
[[NSNotificationCenter defaultCenter] postNotificationName:@"RoomDidExit"
|
||
object:nil
|
||
userInfo:@{@"roomId": self.roomUid ?: @"unknown"}];
|
||
NSLog(@"🎮 房间退出通知已发送 - RoomID: %@", self.roomUid);
|
||
}
|
||
- (void)viewDidAppear:(BOOL)animated {
|
||
[super viewDidAppear:animated];
|
||
self.freeView.hidden = NO;
|
||
self.navigationController.interactivePopGestureRecognizer.enabled = NO;
|
||
[XPSkillCardPlayerManager shareInstance].isInRoomVC = YES;
|
||
|
||
// 🔧 防护:标记 VC 可见
|
||
self.isViewActive = YES;
|
||
|
||
// 🔧 修复:发送房间进入通知,让 BuglyManager 知道用户已进入房间
|
||
[[NSNotificationCenter defaultCenter] postNotificationName:@"RoomDidEnter"
|
||
object:nil
|
||
userInfo:@{@"roomId": self.roomUid ?: @"unknown"}];
|
||
NSLog(@"🎮 房间进入通知已发送 - RoomID: %@", self.roomUid);
|
||
}
|
||
|
||
#pragma mark - 连击状态管理
|
||
|
||
// 强制重置连击状态和恢复UI
|
||
- (void)forceBoomStateReset {
|
||
NSLog(@"🔧 XPRoomViewController 强制重置连击状态");
|
||
|
||
// 1. 直接重置连击管理器(会自动发送通知给所有相关组件)
|
||
[[GiftComboManager sharedManager] forceBoomStateReset];
|
||
|
||
// 2. 确保UI恢复(双重保障)
|
||
dispatch_async(dispatch_get_main_queue(), ^{
|
||
self.sideMenu.hidden = NO;
|
||
self.menuContainerView.hidden = NO;
|
||
NSLog(@"🔄 强制恢复底部操作栏和侧栏显示");
|
||
});
|
||
}
|
||
|
||
// 应用生命周期保护
|
||
- (void)applicationDidEnterBackground:(NSNotification *)notification {
|
||
if ([[GiftComboManager sharedManager] isActive]) {
|
||
NSLog(@"📱 应用进入后台,检查连击状态");
|
||
[self forceBoomStateReset];
|
||
}
|
||
}
|
||
|
||
// 内存警告保护
|
||
- (void)didReceiveMemoryWarning {
|
||
[super didReceiveMemoryWarning];
|
||
|
||
if ([[GiftComboManager sharedManager] isActive]) {
|
||
NSLog(@"⚠️ 收到内存警告,检查连击状态");
|
||
[self forceBoomStateReset];
|
||
}
|
||
}
|
||
|
||
#pragma mark - Private Method
|
||
- (void)initSubViews {
|
||
self.view.backgroundColor = [UIColor darkGrayColor];
|
||
[self.view addSubview:self.backContainerView];
|
||
[self.view addSubview:self.littleGameView];
|
||
[self.view addSubview:self.messageContainerView];
|
||
|
||
[self.view addSubview:self.quickMessageContainerView];
|
||
[self.view addSubview:self.menuContainerView];
|
||
[self.view addSubview:self.sideMenu];
|
||
[self.view addSubview:self.redPacketView];
|
||
[self.view addSubview:self.roomHeaderView];
|
||
[self.view addSubview:self.functionView];
|
||
[self.view addSubview:self.animationView];
|
||
|
||
}
|
||
|
||
- (void)__layoutTwentyMicStage {
|
||
[self.stageView mas_makeConstraints:^(MASConstraintMaker *make) {
|
||
make.leading.trailing.mas_equalTo(self.view);
|
||
make.top.mas_equalTo(self.roomHeaderView.mas_bottom);
|
||
make.height.mas_equalTo(self.stageView.hightForStageView);
|
||
}];
|
||
}
|
||
|
||
- (void)__layoutNineteenMicStage {
|
||
[self.stageView mas_makeConstraints:^(MASConstraintMaker *make) {
|
||
make.leading.trailing.mas_equalTo(self.view);
|
||
make.top.mas_equalTo(self.roomHeaderView.mas_bottom);
|
||
make.height.mas_equalTo(self.stageView.hightForStageView);
|
||
}];
|
||
}
|
||
|
||
- (void)__layoutFifteenMicStage {
|
||
[self.stageView mas_makeConstraints:^(MASConstraintMaker *make) {
|
||
make.leading.trailing.mas_equalTo(self.view);
|
||
make.top.mas_equalTo(self.roomHeaderView.mas_bottom);
|
||
make.height.mas_equalTo(self.stageView.hightForStageView);
|
||
}];
|
||
}
|
||
|
||
- (void)__layoutTenMicStage {
|
||
[self.stageView mas_makeConstraints:^(MASConstraintMaker *make) {
|
||
make.leading.trailing.mas_equalTo(self.view);
|
||
make.top.mas_equalTo(self.roomHeaderView.mas_bottom);
|
||
make.height.mas_equalTo(self.stageView.hightForStageView);
|
||
}];
|
||
}
|
||
|
||
- (void)initSubViewConstraints {
|
||
[self.backContainerView mas_makeConstraints:^(MASConstraintMaker *make) {
|
||
make.edges.mas_equalTo(self.view);
|
||
}];
|
||
[self.littleGameView mas_makeConstraints:^(MASConstraintMaker *make) {
|
||
make.edges.mas_equalTo(self.view);
|
||
}];
|
||
[self.roomHeaderView mas_makeConstraints:^(MASConstraintMaker *make) {
|
||
make.leading.trailing.top.mas_equalTo(self.view);
|
||
make.height.mas_equalTo(kNavigationHeight);
|
||
}];
|
||
|
||
[self.messageContainerView mas_makeConstraints:^(MASConstraintMaker *make) {
|
||
make.top.equalTo(self.roomHeaderView.mas_bottom);
|
||
make.bottom.equalTo(self.quickMessageContainerView.mas_top).offset(-5);
|
||
make.leading.equalTo(self.view);
|
||
make.trailing.equalTo(self.sideMenu.mas_leading).offset(-10);
|
||
}];
|
||
CGFloat quickMsgHeight = 30;
|
||
//记录最后关闭时间
|
||
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
|
||
NSNumber *closeCount = [defaults objectForKey:kRoomQuickMessageCloseCount];
|
||
if (closeCount.intValue > 3) {
|
||
quickMsgHeight = 0;
|
||
} else {
|
||
quickMsgHeight = 30;
|
||
}
|
||
[self.quickMessageContainerView mas_makeConstraints:^(MASConstraintMaker *make) {
|
||
make.bottom.mas_equalTo(self.view).offset(- 52 - kSafeAreaBottomHeight);
|
||
make.height.mas_equalTo(0);
|
||
make.leading.trailing.mas_equalTo(self.view);
|
||
}];
|
||
[self.menuContainerView mas_makeConstraints:^(MASConstraintMaker *make) {
|
||
make.leading.trailing.mas_equalTo(self.view);
|
||
if (iPhoneXSeries) {
|
||
make.bottom.mas_equalTo(self.view);
|
||
} else {
|
||
make.bottom.mas_equalTo(-10);
|
||
}
|
||
make.height.mas_equalTo(52 + kSafeAreaBottomHeight);
|
||
}];
|
||
|
||
[self.sideMenu mas_makeConstraints:^(MASConstraintMaker *make) {
|
||
make.top.mas_equalTo(self.messageContainerView);
|
||
make.trailing.mas_equalTo(self.view);
|
||
make.bottom.mas_equalTo(self.quickMessageContainerView.mas_top).offset(-5);
|
||
make.width.mas_equalTo(87);
|
||
}];
|
||
[self.redPacketView mas_makeConstraints:^(MASConstraintMaker *make) {
|
||
make.width.height.mas_equalTo(kGetScaleWidth(58));
|
||
make.trailing.mas_equalTo(-kGetScaleWidth(6));
|
||
make.bottom.mas_equalTo(-160);
|
||
}];
|
||
[self.animationView mas_makeConstraints:^(MASConstraintMaker *make) {
|
||
make.edges.mas_equalTo(self.view);
|
||
}];
|
||
|
||
[self.functionView mas_makeConstraints:^(MASConstraintMaker *make) {
|
||
make.edges.mas_equalTo(self.view);
|
||
}];
|
||
}
|
||
|
||
- (void)updateViewConstraintsOnAnchorRoom {
|
||
[self.anchorScrollView mas_makeConstraints:^(MASConstraintMaker *make) {
|
||
make.edges.mas_equalTo(self.view);
|
||
}];
|
||
[self.backContainerView mas_makeConstraints:^(MASConstraintMaker *make) {
|
||
make.edges.mas_equalTo(self.anchorScrollView.middleImageView);
|
||
}];
|
||
[self.roomHeaderView mas_makeConstraints:^(MASConstraintMaker *make) {
|
||
make.leading.trailing.top.mas_equalTo(self.anchorScrollView.middleImageView);
|
||
make.height.mas_equalTo(kNavigationHeight);
|
||
}];
|
||
[self.stageView mas_makeConstraints:^(MASConstraintMaker *make) {
|
||
make.leading.trailing.mas_equalTo(self.anchorScrollView.middleImageView);
|
||
make.top.mas_equalTo(self.roomHeaderView.mas_bottom);
|
||
make.height.mas_equalTo(self.stageView.hightForStageView);
|
||
}];
|
||
[self.messageContainerView mas_makeConstraints:^(MASConstraintMaker *make) {
|
||
make.top.equalTo(self.stageView.mas_bottom);
|
||
make.bottom.mas_equalTo(self.quickMessageContainerView.mas_top).mas_offset(-5);
|
||
make.leading.equalTo(self.anchorScrollView.middleImageView);
|
||
make.trailing.equalTo(self.sideMenu.mas_leading).offset(-10);
|
||
}];
|
||
[self.quickMessageContainerView mas_makeConstraints:^(MASConstraintMaker *make) {
|
||
make.height.mas_equalTo(0);
|
||
make.bottom.mas_equalTo(self.backContainerView).mas_offset(-5-40-8-kSafeAreaBottomHeight);
|
||
make.leading.equalTo(self.anchorScrollView.middleImageView);
|
||
make.trailing.equalTo(self.sideMenu.mas_leading).offset(-10);
|
||
}];
|
||
[self.menuContainerView mas_makeConstraints:^(MASConstraintMaker *make) {
|
||
make.leading.trailing.mas_equalTo(self.anchorScrollView.middleImageView);
|
||
if (iPhoneXSeries) {
|
||
make.bottom.mas_equalTo(self.view);
|
||
} else {
|
||
make.bottom.mas_equalTo(self.view).offset(-10);
|
||
}
|
||
make.height.mas_equalTo(52 + kSafeAreaBottomHeight);
|
||
}];
|
||
[self.sideMenu mas_makeConstraints:^(MASConstraintMaker *make) {
|
||
make.top.mas_equalTo(self.messageContainerView);
|
||
make.trailing.mas_equalTo(self.anchorScrollView.middleImageView);
|
||
make.bottom.mas_equalTo(self.quickMessageContainerView.mas_top).mas_offset(-5);
|
||
make.width.mas_equalTo(87);
|
||
}];
|
||
|
||
[self.functionView mas_makeConstraints:^(MASConstraintMaker *make) {
|
||
make.edges.mas_equalTo(self.anchorScrollView.middleImageView);
|
||
}];
|
||
}
|
||
|
||
- (void)handleActivityContainerViewEvents {
|
||
@kWeakify(self);
|
||
self.sideMenu.openRedPacketHandle = ^(XPRedPacketModel * _Nullable redModel,RoomType type,BOOL isChangeRoom) {
|
||
@kStrongify(self);
|
||
if(isChangeRoom == YES){
|
||
self.redPacketView.type = type;
|
||
self.redPacketView.redPacketList = self.sideMenu.redPacketList;
|
||
return;
|
||
}
|
||
|
||
XPReceiveRedPacketView *view = [[XPReceiveRedPacketView alloc] initWithFrame:CGRectMake(0, 0, KScreenWidth, KScreenHeight)];
|
||
view.delegate = self;
|
||
self.isShowRedPacket = YES;
|
||
view.receiveModel = redModel;
|
||
for (UIView *subView in self.view.subviews) {
|
||
if([subView isKindOfClass:[XPReceiveRedPacketView class]]) {
|
||
view.alphaView.backgroundColor = [UIColor clearColor];
|
||
break;
|
||
}
|
||
}
|
||
[self.view addSubview:view];
|
||
[self.view bringSubviewToFront:view];
|
||
};
|
||
|
||
self.sideMenu.showSendGiftView = ^{
|
||
@kStrongify(self);
|
||
NSString * roomUid = [NSString stringWithFormat:@"%ld", [self getRoomInfo].uid];
|
||
XPSendGiftView * giftView = [[XPSendGiftView alloc] initWithType:SendGiftType_Room uid:roomUid];
|
||
giftView.delegate = self;
|
||
NSArray * giftUses = [self configGiftUsers:[self getMicroQueue]];
|
||
[giftView configGiftUsers:giftUses];
|
||
[self.getCurrentNav presentViewController:giftView animated:YES completion:nil];
|
||
};
|
||
}
|
||
|
||
- (NSArray<XPGiftUserInfoModel *> *)configGiftUsers:(NSMutableDictionary<NSString *,MicroQueueModel *> *)queue {
|
||
NSMutableArray * array = [NSMutableArray array];
|
||
for (MicroQueueModel * microModel in queue.allValues) {
|
||
if (microModel.userInfo && microModel.userInfo.uid >0) {
|
||
UserInfoModel * userInfo = microModel.userInfo;
|
||
XPGiftUserInfoModel * userModel = [[XPGiftUserInfoModel alloc] init];
|
||
userModel.avatar = userInfo.avatar;
|
||
userModel.vipMic = userInfo.vipMic;
|
||
userModel.position = [NSString stringWithFormat:@"%d", microModel.microState.position];
|
||
userModel.uid = userInfo.uid;
|
||
if (self.getRoomInfo.type == RoomType_Anchor && microModel.microState.position == -1) {///个播房一直为离开模式,不需要添加房主位
|
||
continue;
|
||
}
|
||
[array addObject:userModel];
|
||
}
|
||
}
|
||
|
||
if (self.getRoomInfo.leaveMode) {
|
||
RoomInfoModel * roomInfo= self.getRoomInfo;
|
||
XPGiftUserInfoModel * userModel = [[XPGiftUserInfoModel alloc] init];
|
||
userModel.avatar = roomInfo.avatar;
|
||
userModel.position = @"-1";
|
||
userModel.uid = roomInfo.uid;
|
||
[array addObject:userModel];
|
||
} else if (self.getRoomInfo.type == RoomType_Anchor) {
|
||
RoomInfoModel * roomInfo= self.getRoomInfo;
|
||
BOOL hadContainerOwner = NO;
|
||
for (UserInfoModel *userModel in array) {
|
||
if (userModel.uid == roomInfo.uid) {
|
||
hadContainerOwner = YES;
|
||
break;
|
||
}
|
||
}
|
||
if (!hadContainerOwner) {
|
||
XPGiftUserInfoModel * userModel = [[XPGiftUserInfoModel alloc] init];
|
||
userModel.avatar = roomInfo.avatar;
|
||
userModel.position = @"-1";
|
||
userModel.uid = roomInfo.uid;
|
||
[array addObject:userModel];
|
||
}
|
||
}
|
||
return array;
|
||
}
|
||
|
||
- (void)exitOldRoom {
|
||
NSString * roomUid = [NSString stringWithFormat:@"%ld", [XPRoomMiniManager shareManager].getRoomInfo.uid];
|
||
if (roomUid.integerValue > 0) {
|
||
if ([roomUid isEqualToString:self.roomUid]) {
|
||
self.isMiniEnter = YES;
|
||
} else {
|
||
//有最小化房间 并且要进入的房间和最小化的房间不一样的话 就先退掉 最小化的房间
|
||
NSString * roomId = [NSString stringWithFormat:@"%ld", [XPRoomMiniManager shareManager].getRoomInfo.roomId];
|
||
[self.presenter exitNIMRoom:roomId];
|
||
[[RtcManager instance] exitRoom];
|
||
[[XPRoomMiniManager shareManager] resetLocalMessage];
|
||
[self.presenter reportUserOutRoom:roomUid];
|
||
[XPSkillCardPlayerManager shareInstance].micState = MICState_None;
|
||
}
|
||
}
|
||
}
|
||
-(BOOL)getIsMiniEnter{
|
||
return self.isMiniEnter;
|
||
}
|
||
- (void)userEnterRoomSuccess {
|
||
AttachmentModel *attachment = [[AttachmentModel alloc]init];
|
||
attachment.first = CustomMessageType_Car_Notify;
|
||
attachment.second = Custom_Message_Sub_Car_EnterRoom;
|
||
NSMutableDictionary *att = [NSMutableDictionary dictionary];
|
||
if (self.userInfo.userVipInfoVO.enterHide) {///VIP隐身进房,不发座驾消息
|
||
return;
|
||
}
|
||
if (self.userInfo.platformRole == 1) {
|
||
return;
|
||
}
|
||
if (self.userInfo.viewUrl.length > 0) {
|
||
[att safeSetObject:self.userInfo.nick forKey:@"nick"];
|
||
[att safeSetObject:self.userInfo.viewUrl forKey:@"viewUrl"];
|
||
[att safeSetObject:@(self.userInfo.otherViewType) forKey:@"otherViewType"];
|
||
} else if (self.userInfo.carEffect.length > 0) {
|
||
[att safeSetObject:self.userInfo.carEffect forKey:@"effect"];
|
||
[att safeSetObject:self.userInfo.nick forKey:@"nick"];
|
||
} else {
|
||
return;
|
||
}
|
||
attachment.data = att;
|
||
NSString *sessionID = [NSString stringWithFormat:@"%ld",self.roomInfo.roomId];
|
||
NIMMessage *message = [[NIMMessage alloc]init];
|
||
NIMCustomObject *object = [[NIMCustomObject alloc] init];
|
||
object.attachment = attachment;
|
||
message.messageObject = object;
|
||
//构造会话
|
||
NIMSession *session = [NIMSession session:sessionID type:NIMSessionTypeChatroom];
|
||
[[NIMSDK sharedSDK].chatManager sendMessage:message toSession:session error:nil];
|
||
}
|
||
|
||
- (BOOL)updateStageView {
|
||
NSLog(@"🔄 updateStageView: 开始更新 stageView,当前 alpha = %.2f", self.stageView.alpha);
|
||
|
||
// 优先使用 StageViewManager 来管理 stageView
|
||
if (self.stageViewManager) {
|
||
NSLog(@"🔧 updateStageView: 使用 StageViewManager");
|
||
BOOL success = [self.stageViewManager updateStageViewForRoomType:self.roomInfo.type
|
||
roomInfo:self.roomInfo
|
||
container:self.view
|
||
delegate:self];
|
||
if (success) {
|
||
self.stageView = self.stageViewManager.currentStageView;
|
||
if (self.stageView) {
|
||
NSLog(@"🔧 updateStageView: StageViewManager 设置 alpha = 0 (之前 = %.2f)", self.stageView.alpha);
|
||
self.stageView.alpha = 0;
|
||
NSLog(@"✅ StageViewManager 成功更新 stageView: %@", NSStringFromClass([self.stageView class]));
|
||
return YES;
|
||
}
|
||
}
|
||
NSLog(@"⚠️ StageViewManager 更新失败,降级到原有逻辑");
|
||
}
|
||
|
||
// 降级处理:原有逻辑
|
||
// NSLog(@"🔧 updateStageView: 使用降级逻辑");
|
||
// Class stageViewClass = [self stageViewClassForRoomInfo:self.roomInfo];
|
||
// if (stageViewClass) { //&& ![self.stageView isKindOfClass:stageViewClass]) {
|
||
// NSLog(@"🔧 updateStageView: 创建新的 stageView: %@", NSStringFromClass(stageViewClass));
|
||
// [self.stageView removeFromSuperview];
|
||
// self.stageView = nil;
|
||
// self.stageView = [[stageViewClass alloc] initWithDelegate:self];
|
||
// NSLog(@"🔧 updateStageView: 降级逻辑设置 alpha = 0 (之前 = %.2f)", self.stageView.alpha);
|
||
// self.stageView.alpha = 0;
|
||
// NSLog(@"✅ 降级逻辑成功更新 stageView: %@", NSStringFromClass([self.stageView class]));
|
||
// return YES;
|
||
// }
|
||
|
||
NSLog(@"❌ 所有 stageView 更新方法都失败了");
|
||
return NO;
|
||
}
|
||
|
||
- (Class)stageViewClassForRoomInfo:(RoomInfoModel *)roomInfo {
|
||
if (roomInfo.roomModeType == RoomModeType_Open_Blind) {
|
||
return [DatingStageView class];
|
||
}
|
||
if (roomInfo.datingState == RoomDatingStateChangeType_Close &&
|
||
![self.stageView isKindOfClass:[SocialStageView class]]) {
|
||
return [SocialStageView class];
|
||
}
|
||
if (roomInfo.type == RoomType_Anchor) {
|
||
if (roomInfo.roomModeType == RoomModeType_Open_AcrossRoomPK_mode &&
|
||
![self.stageView isKindOfClass:[AnchorPKStageView class]]) {
|
||
return [AnchorPKStageView class];
|
||
} else if (roomInfo.roomModeType == RoomModeType_Normal_Mode &&
|
||
![self.stageView isKindOfClass:[AnchorStageView class]]) {
|
||
return [AnchorStageView class];
|
||
}
|
||
} else if (roomInfo.type == RoomType_MiniGame) {
|
||
return [LittleGameScrollStageView class];
|
||
} else if (roomInfo.type == RoomType_19Mic) {
|
||
return [NineteenMicStageView class];
|
||
} else if (roomInfo.type == RoomType_20Mic) {
|
||
return [TwentyMicStageView class];
|
||
} else if (roomInfo.type == RoomType_15Mic) {
|
||
return [FifteenMicStageView class];
|
||
} else if (roomInfo.type == RoomType_10Mic) {
|
||
return [TenMicStageView class];
|
||
} else if (roomInfo.hadChangeRoomType && ![self.stageView isKindOfClass:[SocialStageView class]]) {
|
||
return [SocialStageView class];
|
||
}
|
||
return [SocialStageView class];
|
||
}
|
||
|
||
- (void)changeStageViewOnRoomUpdate {
|
||
NSLog(@"🔄 changeStageViewOnRoomUpdate: 开始更新 stageView");
|
||
|
||
if (![self updateStageView]) {
|
||
NSLog(@"❌ changeStageViewOnRoomUpdate: updateStageView 失败");
|
||
return;
|
||
}
|
||
|
||
NSLog(@"✅ changeStageViewOnRoomUpdate: updateStageView 成功,当前 alpha = %.2f", self.stageView.alpha);
|
||
|
||
// 🔧 新增:发送房间类型变化通知
|
||
[[NSNotificationCenter defaultCenter] postNotificationName:@"RoomTypeChanged"
|
||
object:nil
|
||
userInfo:@{@"roomType": @(self.roomInfo.type)}];
|
||
|
||
if (!self.stageView.superview) {
|
||
NSLog(@"🔧 changeStageViewOnRoomUpdate: 添加 stageView 到视图层级");
|
||
[self.view insertSubview:self.stageView
|
||
belowSubview:self.roomHeaderView];
|
||
|
||
// 防止小屏机麦位挡住按钮
|
||
NSInteger index_sideMenu = -1;
|
||
NSInteger index_stageView = -1;
|
||
for (UIView *view in self.view.subviews) {
|
||
if (index_sideMenu == -1 || index_stageView == -1) {
|
||
if (view == self.sideMenu) {
|
||
index_sideMenu = [self.view.subviews indexOfObject:view];
|
||
}
|
||
if (view == self.stageView) {
|
||
index_stageView = [self.view.subviews indexOfObject:view];
|
||
}
|
||
} else {
|
||
[self.view exchangeSubviewAtIndex:index_sideMenu withSubviewAtIndex:index_stageView];
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
NSLog(@"🔧 changeStageViewOnRoomUpdate: 设置 stageView.alpha = 1 (之前 = %.2f)", self.stageView.alpha);
|
||
self.stageView.alpha = 1;
|
||
NSLog(@"✅ changeStageViewOnRoomUpdate: stageView.alpha 已设置为 1");
|
||
|
||
// 调试:检查最终状态
|
||
[self debugStageViewStatus];
|
||
|
||
// 🔧 新增:如果是 SocialStageView,绘制中点矩形
|
||
[self drawSocialStageMidpointRects];
|
||
|
||
// 🔧 新增:进房成功后调用CP相关API
|
||
[self callMicCpListByRoomUidAfterRoomEntered];
|
||
|
||
// 🔧 新增:stage view类型变化时调用CP相关API
|
||
NSMutableDictionary<NSString *,MicroQueueModel *> *currentQueue = [self.stageView getMicroQueue];
|
||
[self callMicCpListByUidListWithQueue:currentQueue];
|
||
|
||
// 🔧 新增:检查19 mic房间中央位置(position 6)用户资格
|
||
[self checkCentralPositionUserQualification:currentQueue];
|
||
|
||
[self addExitGameButton];
|
||
|
||
self.quickMessageContainerView.hidden = YES;
|
||
[self.quickMessageContainerView mas_updateConstraints:^(MASConstraintMaker *make) {
|
||
make.height.mas_equalTo(0);
|
||
}];
|
||
|
||
switch (self.roomInfo.type) {
|
||
case RoomType_MiniGame: {
|
||
[self.stageView mas_remakeConstraints:^(MASConstraintMaker *make) {
|
||
make.leading.trailing.mas_equalTo(self.view);
|
||
make.top.mas_equalTo(self.roomHeaderView.mas_bottom).offset(26 + 4);
|
||
make.height.mas_equalTo(self.stageView.hightForStageView);
|
||
}];
|
||
CGFloat height = 80;
|
||
if (iPhoneXSeries) {
|
||
height = 100;
|
||
}
|
||
[self.messageContainerView mas_remakeConstraints:^(MASConstraintMaker *make) {
|
||
make.height.mas_equalTo(height);
|
||
make.bottom.mas_equalTo(self.quickMessageContainerView.mas_top).offset(-5);
|
||
make.leading.mas_equalTo(self.view);
|
||
make.trailing.mas_equalTo(self.sideMenu.mas_leading).offset(-10);
|
||
}];
|
||
|
||
[self.sideMenu displayForMiniGame];
|
||
[self.sideMenu mas_remakeConstraints:^(MASConstraintMaker *make) {
|
||
make.trailing.mas_equalTo(self.view);
|
||
make.bottom.mas_equalTo(self.quickMessageContainerView.mas_top).offset(-5);
|
||
make.width.mas_equalTo(87);
|
||
}];
|
||
}
|
||
break;
|
||
default: {
|
||
[self.stageView mas_remakeConstraints:^(MASConstraintMaker *make) {
|
||
make.leading.trailing.mas_equalTo(self.view);
|
||
make.top.mas_equalTo(self.roomHeaderView.mas_bottom);
|
||
make.height.mas_equalTo(self.stageView.hightForStageView);
|
||
}];
|
||
|
||
[self.messageContainerView mas_remakeConstraints:^(MASConstraintMaker *make) {
|
||
make.top.mas_equalTo(self.stageView.mas_bottom);
|
||
make.bottom.mas_equalTo(self.quickMessageContainerView.mas_top).offset(-5);
|
||
make.leading.mas_equalTo(self.view);
|
||
make.trailing.mas_equalTo(self.sideMenu.mas_leading).offset(-10);
|
||
}];
|
||
|
||
if (self.roomInfo.type == RoomType_19Mic || self.roomInfo.type == RoomType_20Mic) {
|
||
[self.sideMenu mas_remakeConstraints:^(MASConstraintMaker *make) {
|
||
make.trailing.mas_equalTo(self.view);
|
||
make.height.mas_equalTo(160);
|
||
make.bottom.mas_equalTo(self.quickMessageContainerView.mas_top).offset(-5);
|
||
make.width.mas_equalTo(87);
|
||
}];
|
||
} else {
|
||
[self.sideMenu mas_remakeConstraints:^(MASConstraintMaker *make) {
|
||
make.top.mas_equalTo(self.messageContainerView);
|
||
make.trailing.mas_equalTo(self.view);
|
||
make.bottom.mas_equalTo(self.quickMessageContainerView.mas_top).offset(-5);
|
||
make.width.mas_equalTo(87);
|
||
}];
|
||
}
|
||
}
|
||
break;
|
||
}
|
||
}
|
||
|
||
- (void)changeStageViewOnAnchorRoom {
|
||
if (self.roomInfo.roomModeType == RoomModeType_Open_AcrossRoomPK_mode && ![self.stageView isKindOfClass:[AnchorPKStageView class]]) {
|
||
[self.stageView removeFromSuperview];
|
||
self.stageView = nil;
|
||
self.stageView = [[AnchorPKStageView alloc] initWithDelegate:self];
|
||
} else if(self.roomInfo.roomModeType == RoomModeType_Normal_Mode && ![self.stageView isKindOfClass:[AnchorStageView class]]) {
|
||
[self.stageView removeFromSuperview];
|
||
self.stageView = nil;
|
||
self.stageView = [[AnchorStageView alloc] initWithDelegate:self];
|
||
}
|
||
if (!self.stageView.superview) {
|
||
[self.anchorScrollView insertSubview:self.stageView belowSubview:self.roomHeaderView];
|
||
}
|
||
|
||
[self.stageView mas_remakeConstraints:^(MASConstraintMaker *make) {
|
||
make.leading.trailing.mas_equalTo(self.anchorScrollView.middleImageView);
|
||
make.top.mas_equalTo(self.roomHeaderView.mas_bottom);
|
||
make.height.mas_equalTo(self.stageView.hightForStageView);
|
||
}];
|
||
[self.messageContainerView mas_remakeConstraints:^(MASConstraintMaker *make) {
|
||
make.top.mas_equalTo(self.stageView.mas_bottom);
|
||
make.bottom.mas_equalTo(self.quickMessageContainerView.mas_top).mas_offset(-5);
|
||
make.leading.mas_equalTo(self.anchorScrollView.middleImageView);
|
||
make.trailing.mas_equalTo(self.sideMenu.mas_leading).offset(-10);
|
||
}];
|
||
|
||
CGFloat quickMsgHeight = 30;
|
||
//记录最后关闭时间
|
||
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
|
||
NSNumber *closeCount = [defaults objectForKey:kRoomQuickMessageCloseCount];
|
||
if (closeCount.intValue > 3 || self.roomInfo.speakTemplate.count <=0) {
|
||
quickMsgHeight = 0;
|
||
} else {
|
||
quickMsgHeight = 30;
|
||
}
|
||
self.quickMessageContainerView.titleArray = self.roomInfo.speakTemplate;
|
||
[self.quickMessageContainerView mas_remakeConstraints:^(MASConstraintMaker *make) {
|
||
make.height.mas_equalTo(0);
|
||
make.bottom.mas_equalTo(self.backContainerView).mas_offset(-5-40-8-kSafeAreaBottomHeight);
|
||
make.leading.trailing.mas_equalTo(self.anchorScrollView.middleImageView);
|
||
}];
|
||
[self.sideMenu mas_remakeConstraints:^(MASConstraintMaker *make) {
|
||
make.top.mas_equalTo(self.messageContainerView);
|
||
make.trailing.mas_equalTo(self.anchorScrollView.middleImageView);
|
||
make.bottom.mas_equalTo(self.quickMessageContainerView.mas_top).mas_offset(-5);
|
||
make.width.mas_equalTo(87);
|
||
}];
|
||
}
|
||
|
||
- (void)setRoomInfo:(RoomInfoModel *)roomInfo {
|
||
if (_roomInfo == roomInfo) {
|
||
return;
|
||
}
|
||
_roomInfo = roomInfo;
|
||
|
||
NSString *roomId = @(self.roomInfo.roomId).stringValue;
|
||
NSLog(@"🎮 设置房间ID: %@", roomId);
|
||
[[TurboModeStateManager sharedManager] setCurrentRoomId:roomId];
|
||
[[LuckyPackageLogicManager sharedInstance] setRoomUid:@(roomInfo.uid).stringValue];
|
||
[[RoomResourceManager sharedManager] updateCurrentSkinID:roomInfo.usedMicSkinId
|
||
effectID:roomInfo.usedMicEffectId];
|
||
|
||
[self.sideMenu updateView];
|
||
}
|
||
|
||
#pragma mark - Game Switch
|
||
- (void)addExitGameButton {
|
||
[self removeExitGameButton];
|
||
|
||
if (self.roomInfo.type != RoomType_MiniGame) {
|
||
return;
|
||
}
|
||
|
||
if (_exitGameButton == nil) {
|
||
_exitGameButton = [UIButton buttonWithType:UIButtonTypeCustom];
|
||
[_exitGameButton setTitle:@"切换" forState:UIControlStateNormal];
|
||
[_exitGameButton setImage:[UIImage imageNamed:@"ms_room_game_switch_button"] forState:UIControlStateNormal];
|
||
[_exitGameButton addTarget:self action:@selector(didTapExitGameButton) forControlEvents:UIControlEventTouchUpInside];
|
||
}
|
||
[self.view addSubview:self.exitGameButton];
|
||
[self.exitGameButton mas_makeConstraints:^(MASConstraintMaker *make) {
|
||
make.top.mas_equalTo(self.stageView.mas_bottom).offset(10);
|
||
make.leading.mas_equalTo(self.view).offset(12);
|
||
make.width.height.equalTo(@21);
|
||
}];
|
||
}
|
||
|
||
- (void)removeExitGameButton {
|
||
[self.exitGameButton removeFromSuperview];
|
||
}
|
||
|
||
- (void)didTapExitGameButton {
|
||
if ([self.littleGameView isInSudGame]) {
|
||
[XNDJTDDLoadingTool showErrorWithMessage:YMLocalizedString(@"XPRoomFunctionContainerView19")];
|
||
} else {
|
||
@kWeakify(self);
|
||
[TTPopup alertWithMessage:YMLocalizedString(@"XPRoomFunctionContainerView20") confirmHandler:^{
|
||
@kStrongify(self);
|
||
[XNDJTDDLoadingTool showLoading];
|
||
[self exitLittleGame];
|
||
} cancelHandler:^{ }];
|
||
}
|
||
}
|
||
|
||
- (void)exitLittleGame {
|
||
RoomInfoModel * roomInfo = self.getRoomInfo;
|
||
NSMutableDictionary * params = [NSMutableDictionary dictionary];
|
||
NSString * ticket = [AccountInfoStorage instance].getTicket;
|
||
[params setObject:ticket forKey:@"ticket"];
|
||
[params setObject:@(roomInfo.uid).stringValue forKey:@"uid"];
|
||
[params setObject:[NSString stringWithFormat:@"%ld", roomInfo.uid] forKey:@"roomUid"];
|
||
if (roomInfo.title.length > 0) {
|
||
[params setObject:roomInfo.title forKey:@"title"];
|
||
}
|
||
|
||
if (roomInfo.roomPwd.length > 0) {
|
||
[params setObject:roomInfo.roomPwd forKey:@"roomPwd"];
|
||
} else{
|
||
[params setObject:@"" forKey:@"roomPwd"];
|
||
}
|
||
|
||
if (roomInfo.tagId > 0) {
|
||
[params setObject:[NSString stringWithFormat:@"%ld", roomInfo.tagId] forKey:@"tagId"];
|
||
}
|
||
|
||
if (self.roomInfo.oldType == 0) {
|
||
self.roomInfo.oldType = RoomType_Room;
|
||
}
|
||
[params setObject:@(self.roomInfo.oldType) forKey:@"type"];
|
||
[params setObject:@"0" forKey:@"mgId"];
|
||
[params setObject:@(roomInfo.hasAnimationEffect) forKey:@"hasAnimationEffect"];
|
||
|
||
[Api ownerUpdateRoomInfo:^(BaseModel * _Nullable data, NSInteger code, NSString * _Nullable msg) {
|
||
if (code == 200) {
|
||
[XNDJTDDLoadingTool hideHUD];
|
||
} else {
|
||
[XNDJTDDLoadingTool showErrorWithMessage:msg];
|
||
}
|
||
} params:params];
|
||
|
||
[self.littleGameView handleSelfInExitEvent];
|
||
[self.littleGameView destroyMG];
|
||
}
|
||
|
||
#pragma mark- XPReceiveRedPacketViewDelegate
|
||
- (void)closeViewAction{
|
||
self.isShowRedPacket = NO;
|
||
|
||
}
|
||
#pragma mark- PIRoomEnterRedPacketViewDelegate
|
||
- (void)openRedPacketWithModel:(XPRedPacketModel *)redModel{
|
||
XPReceiveRedPacketView *view = [[XPReceiveRedPacketView alloc] initWithFrame:CGRectMake(0, 0, KScreenWidth, KScreenHeight)];
|
||
view.receiveModel = redModel;
|
||
view.delegate = self;
|
||
self.isShowRedPacket = YES;
|
||
for (UIView *subView in self.view.subviews) {
|
||
if([subView isKindOfClass:[XPReceiveRedPacketView class]]) {
|
||
view.alphaView.backgroundColor = [UIColor clearColor];
|
||
break;
|
||
}
|
||
}
|
||
[self.view addSubview:view];
|
||
[self.view bringSubviewToFront:view];
|
||
}
|
||
#pragma mark - CountDownHelperDelegate
|
||
- (void)onCountdownFinish {
|
||
[[NSNotificationCenter defaultCenter]postNotificationName:kFreeGiftCountdownNotification object:nil userInfo:@{@"isCountdownFinish":@(YES)}];
|
||
if(self.freeModel.curStage.integerValue < self.freeModel.maxStage.integerValue){
|
||
[self.presenter getFreeGiftData];
|
||
}
|
||
if(self.freeModel.curStage.intValue == 0){
|
||
self.freeView.freeModel = self.freeModel;
|
||
if(!self.freeView.superview){
|
||
[kWindow addSubview:self.freeView];
|
||
}
|
||
}
|
||
}
|
||
|
||
- (void)onCountdownOpen:(int)time {
|
||
NSInteger seconds = time;
|
||
int hours = (seconds)%(24*3600)/3600;
|
||
int minutes = (seconds)%3600/60;
|
||
int second = (seconds)%60;
|
||
[[NSNotificationCenter defaultCenter] postNotificationName:kFreeGiftCountdownNotification
|
||
object:nil
|
||
userInfo:@{@"text": [NSString stringWithFormat:@"%02d:%02d:%02d", hours, minutes, second],
|
||
@"isCountdownFinish": @(NO)}];
|
||
}
|
||
|
||
|
||
- (void)cancelRoomArrangeMic {
|
||
///退出排麦
|
||
if (self.roomInfo.roomModeType == RoomModeType_Open_Micro_Mode || self.roomInfo.roomModeType == RoomModeType_Open_Blind) {
|
||
NSString * roomUid = [NSString stringWithFormat:@"%ld", self.roomInfo.uid];
|
||
NSString * uid = [AccountInfoStorage instance].getUid;
|
||
[Api getRoomArrangeMicList:^(BaseModel * _Nullable data, NSInteger code, NSString * _Nullable msg) {
|
||
if (code == 200) {
|
||
ArrangeMicModel * arrangeMicModel= [ArrangeMicModel modelWithJSON:data.data];
|
||
if (arrangeMicModel.myPos.intValue > 0) {
|
||
__block NSString * grouptype = @"0";
|
||
if (self.roomInfo.roomModeType == RoomModeType_Open_Blind) {
|
||
[arrangeMicModel.queue enumerateObjectsUsingBlock:^(ArrangeMicUserModel * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
|
||
if (obj.uid.integerValue == [AccountInfoStorage instance].getUid.integerValue) {
|
||
grouptype = [NSString stringWithFormat:@"%ld", obj.groupType];
|
||
*stop = YES;
|
||
}
|
||
}];
|
||
|
||
}
|
||
[Api cancelArrangeMic:^(BaseModel * _Nullable data, NSInteger code, NSString * _Nullable msg) {} roomUid:roomUid operUid:uid groupType:grouptype];
|
||
}
|
||
}
|
||
} roomUid:roomUid operUid:uid page:@"1" pageSize:@"50"];
|
||
}else if(self.roomInfo.roomModeType == RoomModeType_Open_PK_Mode) {
|
||
NSString * roomUid = [NSString stringWithFormat:@"%ld", self.roomInfo.uid];
|
||
NSString * uid = [AccountInfoStorage instance].getUid;
|
||
[Api getRoomPKUserList:^(BaseModel * _Nullable data, NSInteger code, NSString * _Nullable msg) {
|
||
if (code == 200) {
|
||
ArrangeMicModel * arrangeMicModel= [ArrangeMicModel modelWithJSON:data.data];
|
||
if (arrangeMicModel.myPos.intValue > 0) {
|
||
__block NSString * grouptype = @"0";
|
||
[arrangeMicModel.queue enumerateObjectsUsingBlock:^(ArrangeMicUserModel * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
|
||
if (obj.uid.integerValue == [AccountInfoStorage instance].getUid.integerValue) {
|
||
grouptype = [NSString stringWithFormat:@"%ld", obj.groupType];
|
||
*stop = YES;
|
||
}
|
||
}];
|
||
[Api cancelRoomPKArrangeMic:^(BaseModel * _Nullable data, NSInteger code, NSString * _Nullable msg) {
|
||
|
||
} roomUid:roomUid operUid:uid groupType:grouptype];
|
||
}
|
||
}
|
||
} roomUid:roomUid operUid:uid page:@"1" pageSize:@"50"];
|
||
}
|
||
}
|
||
|
||
///超管进入密码房间
|
||
- (void)superAdminEnterPwdRoom:(RoomInfoModel *)roomInfo {
|
||
__block BOOL isSuperAdmin = NO;
|
||
[self.superMangerList enumerateObjectsUsingBlock:^(GuildSuperAdminInfoModel * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
|
||
if ([obj.uid isEqualToString:[AccountInfoStorage instance].getUid]) {
|
||
isSuperAdmin = YES;
|
||
*stop = YES;
|
||
}
|
||
}];
|
||
|
||
if (!isSuperAdmin) {
|
||
isSuperAdmin = self.userInfo.platformRole == 1;
|
||
}
|
||
|
||
if (!isSuperAdmin) {
|
||
XPRoomSettingInputView * titleView = [[XPRoomSettingInputView alloc] init];
|
||
titleView.maxCount = 15;
|
||
titleView.delegate = self;
|
||
titleView.type = RoomSettingInputType_Input_Pwd;
|
||
TTPopupConfig * config = [[TTPopupConfig alloc] init];
|
||
config.contentView = titleView;
|
||
config.maskBackgroundAlpha = 1;
|
||
config.shouldDismissOnBackgroundTouch = NO;
|
||
[TTPopup popupWithConfig:config];
|
||
} else {
|
||
self.roomInfo.datingState = roomInfo.roomModeType == RoomModeType_Open_Blind ? RoomDatingStateChangeType_Open : RoomDatingStateChangeType_Normal;
|
||
[self changeStageViewOnRoomUpdate];
|
||
[self.roomHeaderView onRoomEntered];
|
||
[self.sideMenu onRoomEntered];
|
||
|
||
[self.backContainerView onRoomEntered];
|
||
[self.littleGameView onRoomEntered];
|
||
if ([XPRoomMiniManager shareManager].getRoomInfo.uid != self.roomUid.integerValue) {// 最小化进房 还是原来的房间的话 不需要重新进入云信 因为压根没退
|
||
// 🔧 防护:检查是否允许进房
|
||
if (!self.isExitingRoom && self.isViewActive) {
|
||
[self.presenter enterNIMRoom:[NSString stringWithFormat:@"%ld", self.roomInfo.roomId] user:self.userInfo];
|
||
}
|
||
[self.functionView onRoomEntered];
|
||
[self.messageContainerView onRoomEntered];
|
||
[self.menuContainerView onRoomEntered];
|
||
} else {
|
||
//虽然没退出房间 但是队列还是要拿的
|
||
[self.stageView onRoomMiniEntered];
|
||
[self.messageContainerView onRoomMiniEntered];
|
||
[self.functionView onRoomMiniEntered];
|
||
[self.functionView onRoomEntered];
|
||
[self.menuContainerView onRoomMiniEntered];
|
||
|
||
// 🔧 最小化进房:初始化当前用户麦位状态
|
||
[self initializeCurrentUserMicStatusForMiniEnter];
|
||
}
|
||
[[XPRoomMiniManager shareManager] configRoomInfo:nil];
|
||
[[XPRoomMiniManager shareManager] configUserInfo:nil];
|
||
[[XPRoomMiniManager shareManager] configCurrentMusic:nil isPlaying:NO];
|
||
}
|
||
}
|
||
|
||
///超管进个播有密码房间
|
||
- (void)handleSuperManagerEnterAnchorRoom:(RoomInfoModel *)roomInfo {
|
||
__block BOOL isSuperAdmin = NO;
|
||
[self.superMangerList enumerateObjectsUsingBlock:^(GuildSuperAdminInfoModel * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
|
||
if ([obj.uid isEqualToString:[AccountInfoStorage instance].getUid]) {
|
||
isSuperAdmin = YES;
|
||
*stop = YES;
|
||
}
|
||
}];
|
||
if (!isSuperAdmin) {
|
||
isSuperAdmin = self.userInfo.platformRole == 1;
|
||
}
|
||
if (!isSuperAdmin) {
|
||
XPRoomSettingInputView * titleView = [[XPRoomSettingInputView alloc] init];
|
||
titleView.maxCount = 15;
|
||
titleView.delegate = self;
|
||
titleView.type = RoomSettingInputType_Input_Pwd;
|
||
TTPopupConfig * config = [[TTPopupConfig alloc] init];
|
||
config.contentView = titleView;
|
||
config.maskBackgroundAlpha = 1;
|
||
config.shouldDismissOnBackgroundTouch = NO;
|
||
[TTPopup popupWithConfig:config];
|
||
} else {
|
||
self.roomInfo.datingState = roomInfo.roomModeType == RoomModeType_Open_Blind ? RoomDatingStateChangeType_Open : RoomDatingStateChangeType_Normal;
|
||
if (!self.anchorScrollView.superview) {
|
||
[self.view insertSubview:self.anchorScrollView belowSubview:self.menuContainerView];
|
||
}
|
||
[self.backContainerView removeFromSuperview];
|
||
[self.stageView removeFromSuperview];
|
||
[self.messageContainerView removeFromSuperview];
|
||
[self.quickMessageContainerView removeFromSuperview];
|
||
[self.sideMenu removeFromSuperview];
|
||
[self.roomHeaderView removeFromSuperview];
|
||
[self.functionView removeFromSuperview];
|
||
|
||
[self.anchorScrollView addSubview:self.backContainerView];
|
||
[self.anchorScrollView addSubview:self.stageView];
|
||
[self.anchorScrollView addSubview:self.messageContainerView];
|
||
[self.anchorScrollView addSubview:self.quickMessageContainerView];
|
||
[self.anchorScrollView addSubview:self.sideMenu];
|
||
[self.anchorScrollView addSubview:self.roomHeaderView];
|
||
if (!self.menuContainerView.superview) {
|
||
[self.view addSubview:self.menuContainerView];
|
||
}
|
||
[self.anchorScrollView addSubview:self.functionView];
|
||
[self.view bringSubviewToFront:self.animationView];
|
||
|
||
[self updateViewConstraintsOnAnchorRoom];
|
||
[self changeStageViewOnAnchorRoom];
|
||
|
||
[self.roomHeaderView onRoomEntered];
|
||
[self.sideMenu onRoomEntered];
|
||
|
||
|
||
[self.backContainerView onRoomEntered];
|
||
[self.littleGameView onRoomEntered];
|
||
if ([XPRoomMiniManager shareManager].getRoomInfo.uid != self.roomUid.integerValue) {// 最小化进房 还是原来的房间的话 不需要重新进入云信 因为压根没退
|
||
// 🔧 防护:检查是否允许进房
|
||
if (!self.isExitingRoom && self.isViewActive) {
|
||
[self.presenter enterNIMRoom:[NSString stringWithFormat:@"%ld", self.roomInfo.roomId] user:self.userInfo];
|
||
}
|
||
[self.functionView onRoomEntered];
|
||
[self.messageContainerView onRoomEntered];
|
||
[self.menuContainerView onRoomEntered];
|
||
} else {
|
||
//虽然没退出房间 但是队列还是要拿的
|
||
[self.stageView onRoomMiniEntered];
|
||
[self.messageContainerView onRoomMiniEntered];
|
||
[self.functionView onRoomMiniEntered];
|
||
[self.functionView onRoomEntered];
|
||
[self.menuContainerView onRoomMiniEntered];
|
||
|
||
// 🔧 最小化进房:初始化当前用户麦位状态
|
||
[self initializeCurrentUserMicStatusForMiniEnter];
|
||
}
|
||
[[XPRoomMiniManager shareManager] configRoomInfo:nil];
|
||
[[XPRoomMiniManager shareManager] configUserInfo:nil];
|
||
[[XPRoomMiniManager shareManager] configCurrentMusic:nil isPlaying:NO];
|
||
}
|
||
}
|
||
///展示个播上划引导
|
||
- (void)showAnchorScrollTipView {
|
||
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
|
||
NSString *anchoScrollTip = [defaults objectForKey:kHadShowAnchorRoomTipKey];
|
||
if (!anchoScrollTip) {
|
||
UIWindow *window = [UIApplication sharedApplication].delegate.window;
|
||
[window addSubview:self.anchorScrollTipView];
|
||
[window bringSubviewToFront:self.anchorScrollTipView];
|
||
}
|
||
}
|
||
-(void)requesstShieldingAction{
|
||
[self.presenter requestShieldingWithType:@"1" objId:[NSString stringWithFormat:@"%ld",self.roomInfo.uid]];
|
||
}
|
||
-(void)requestShieldingSuccess{
|
||
[self showErrorToast:YMLocalizedString(@"RoomHeaderView11")];
|
||
[self exitRoom];
|
||
}
|
||
#pragma mark - 本地礼物特效更新
|
||
- (void)myGiftEffectUpdate:(NSNotification *)notification {
|
||
NSDictionary * dic = notification.object;
|
||
self.roomInfo.hasAnimationEffect = ((NSNumber *)dic[@"hasAnimationEffect"]).boolValue;
|
||
self.hasAnimationEffect = self.roomInfo.hasAnimationEffect;
|
||
[self.roomHeaderView onRoomUpdate];
|
||
}
|
||
#pragma mark - XPRoomProtocol
|
||
///获取已解锁照片id列表
|
||
-(void)getUnlockRoomAlbumPhotoListSuccessWithList:(NSArray *)list{}
|
||
///获取踢人房间列表
|
||
-(void)getKickUserListSuccessWithList:(NSArray *)list{
|
||
NSString *uid = [[AccountInfoStorage instance]getUid];
|
||
for (id obj in list) {
|
||
if([obj integerValue] == [uid integerValue]){
|
||
[self exitRoom];
|
||
[XNDJTDDLoadingTool showErrorWithMessage:YMLocalizedString(@"XPRoomViewController0")];
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
- (void)handleRoomWithPasswordAfterInitRoom {
|
||
if (!self.isRequestSuperAdmin) {
|
||
@kWeakify(self);
|
||
[Api getRoomSuperAdminList:^(BaseModel * _Nullable data, NSInteger code, NSString * _Nullable msg) {
|
||
@kStrongify(self);
|
||
NSArray<GuildSuperAdminInfoModel *> * array = [GuildSuperAdminInfoModel modelsWithArray:data.data];
|
||
self.superMangerList = array;
|
||
[self superAdminEnterPwdRoom:self.roomInfo];
|
||
} roomUid:self.roomUid];
|
||
} else {
|
||
[self superAdminEnterPwdRoom:self.roomInfo];
|
||
}
|
||
}
|
||
|
||
- (void)handleRoomWithoutPasswordAfterInitRoom {
|
||
NSLog(@"🔄 handleRoomWithoutPasswordAfterInitRoom: 开始处理无密码房间");
|
||
|
||
self.roomInfo.datingState = (self.roomInfo.roomModeType == RoomModeType_Open_Blind) ?
|
||
RoomDatingStateChangeType_Open :
|
||
RoomDatingStateChangeType_Normal;
|
||
|
||
NSLog(@"🔧 handleRoomWithoutPasswordAfterInitRoom: 调用 changeStageViewOnRoomUpdate");
|
||
[self changeStageViewOnRoomUpdate];
|
||
NSLog(@"✅ handleRoomWithoutPasswordAfterInitRoom: changeStageViewOnRoomUpdate 完成");
|
||
[self.roomHeaderView onRoomEntered];
|
||
[self.sideMenu onRoomEntered];
|
||
|
||
[self.backContainerView onRoomEntered];
|
||
[self.littleGameView onRoomEntered];
|
||
|
||
self.quickMessageContainerView.titleArray = self.roomInfo.speakTemplate;
|
||
|
||
if ([XPRoomMiniManager shareManager].getRoomInfo.uid != self.roomUid.integerValue) {
|
||
[self.functionView onRoomEntered];
|
||
[self.messageContainerView onRoomEntered];
|
||
[self.menuContainerView onRoomEntered];
|
||
|
||
// 通知云信重新进房
|
||
[self.presenter enterNIMRoom:@(self.roomInfo.roomId).stringValue
|
||
user:self.userInfo];
|
||
} else {
|
||
//虽然没退出房间 但是队列还是要拿的
|
||
[self.stageView onRoomMiniEntered];
|
||
|
||
[self.functionView onRoomMiniEntered];
|
||
[self.sideMenu onRoomMiniEntered];
|
||
[self.functionView onRoomEntered];
|
||
[self.menuContainerView onRoomMiniEntered];
|
||
// PK 状态下,从最小化进房需要模仿初始化房间,丢 2 次 roominfo 进去 functionView
|
||
if (self.roomInfo.roomModeType == RoomModeType_Open_AcrossRoomPK_mode ||
|
||
self.roomInfo.roomModeType == RoomModeType_Open_PK_Mode) {
|
||
[self.functionView onRoomEntered];
|
||
}
|
||
|
||
[self.messageContainerView onRoomMiniEntered];
|
||
|
||
// 🔧 最小化进房:初始化当前用户麦位状态
|
||
[self initializeCurrentUserMicStatusForMiniEnter];
|
||
}
|
||
[self cleanMiniRoomStatues];
|
||
}
|
||
|
||
- (void)enterMyRoom {
|
||
if (self.roomInfo.roomId > 0) { // 存在房间信息,直接使用房间信息开房
|
||
if (self.roomInfo.type == RoomType_MiniGame &&
|
||
self.roomInfo.mgId > 0) {
|
||
self.mgId = [NSString stringWithFormat:@"%lld", self.roomInfo.mgId];
|
||
}
|
||
[self.presenter openRoom:self.roomInfo.title
|
||
type:self.roomInfo.type
|
||
roomPwd:self.roomInfo.roomPwd
|
||
roomDesc:self.roomInfo.roomDesc
|
||
backPic:@""
|
||
mgId:self.mgId];
|
||
} else { // 不存在房间信息,全新开房
|
||
NSString* title = [NSString stringWithFormat:YMLocalizedString(@"XPRoomViewController1"), self.userInfo.nick];
|
||
RoomType type = RoomType_Room;
|
||
if (self.mgId.length > 0) {
|
||
type = RoomType_MiniGame;
|
||
}
|
||
[self.presenter openRoom:title
|
||
type:type
|
||
roomPwd:@""
|
||
roomDesc:@""
|
||
backPic:@""
|
||
mgId:self.mgId];
|
||
}
|
||
}
|
||
|
||
- (void)cleanMiniRoomStatues {
|
||
[[XPRoomMiniManager shareManager] configRoomInfo:nil];
|
||
[[XPRoomMiniManager shareManager] configUserInfo:nil];
|
||
[[XPRoomMiniManager shareManager] configCurrentMusic:nil isPlaying:NO];
|
||
}
|
||
|
||
- (void)initEnterRoomSuccess:(RoomInfoModel *)roomInfo user:(UserInfoModel *)userInfo {
|
||
[XNDJTDDLoadingTool hideHUDInView:self.navigationController.view];
|
||
|
||
[XPSkillCardPlayerManager shareInstance].roomUid = @(roomInfo.uid).stringValue;
|
||
|
||
userInfo.fromUid = self.fromUid;
|
||
userInfo.fromType = self.fromType;
|
||
userInfo.fromNick = self.fromNick;
|
||
|
||
self.hasAnimationEffect = roomInfo.hasAnimationEffect;
|
||
self.roomInfo = roomInfo;
|
||
self.userInfo = userInfo;
|
||
|
||
// 修复:首次获取roominfo成功后,同步礼物特效状态到开关
|
||
NSString *roomId = @(roomInfo.roomId).stringValue;
|
||
[[TurboModeStateManager sharedManager] updateGiftEffectsForRoom:roomId
|
||
enabled:roomInfo.hasAnimationEffect];
|
||
|
||
[self requestBoomData];
|
||
|
||
@kWeakify(self);
|
||
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_global_queue(0, 0), ^{
|
||
@kStrongify(self);
|
||
//获取一下红包信息
|
||
[self.presenter getRedPacket:[NSString stringWithFormat:@"%ld", self.roomInfo.uid]];
|
||
[self getOnlineCount];
|
||
});
|
||
|
||
switch (roomInfo.type) {
|
||
case RoomType_Anchor:
|
||
[self handleInitAnchorRoom];
|
||
[self showAnchorScrollTipView];
|
||
break;
|
||
|
||
default: {
|
||
if (roomInfo.valid) { // 房间有效,直接进入房间
|
||
if (roomInfo.roomPwd.length > 0 &&
|
||
roomInfo.uid != [AccountInfoStorage instance].getUid.integerValue &&
|
||
[XPRoomMiniManager shareManager].getRoomInfo.uid != self.roomUid.integerValue) {//进房密码的情况
|
||
[self handleRoomWithPasswordAfterInitRoom];
|
||
} else {
|
||
[self handleRoomWithoutPasswordAfterInitRoom];
|
||
}
|
||
} else { // 房间无效,分是否为自己房间进行处理
|
||
if ([self.roomUid isEqualToString:[NSString stringWithFormat:@"%ld", userInfo.uid]]) {
|
||
// 当前用户进入自己房间
|
||
[self enterMyRoom];
|
||
} else { // 当前用户进入别人房间
|
||
[self showSuccessToast:YMLocalizedString(@"XPRoomViewController2")];
|
||
[self enterRoomFail:0];
|
||
}
|
||
} }
|
||
break;
|
||
}
|
||
|
||
[self.menuContainerView recheckMicState];
|
||
}
|
||
|
||
- (void)openRoomSuccess:(RoomInfoModel *)roomInfo {
|
||
[XNDJTDDLoadingTool hideHUDInView:self.navigationController.view];
|
||
|
||
self.roomInfo = roomInfo;
|
||
[XPSkillCardPlayerManager shareInstance].is9Mic = roomInfo.type == RoomType_Room;
|
||
|
||
if (roomInfo.type == RoomType_Anchor) {
|
||
[self handleInitAnchorRoom];
|
||
[self showAnchorScrollTipView];
|
||
return;
|
||
}
|
||
|
||
[self changeStageViewOnRoomUpdate];
|
||
[self.roomHeaderView onRoomEntered];
|
||
[self.sideMenu onRoomEntered];
|
||
|
||
[self.backContainerView onRoomEntered];
|
||
[self.littleGameView onRoomEntered];
|
||
[self.functionView onRoomEntered];
|
||
[self.messageContainerView onRoomEntered];
|
||
|
||
self.quickMessageContainerView.titleArray = self.roomInfo.speakTemplate;
|
||
|
||
// 🔧 防护:检查是否允许进房
|
||
if (!self.isExitingRoom && self.isViewActive) {
|
||
[self.presenter enterNIMRoom:[NSString stringWithFormat:@"%ld", self.roomInfo.roomId] user:self.userInfo];
|
||
}
|
||
}
|
||
|
||
- (void)enterRoomSuccess:(NIMChatroom *)chatRoom {
|
||
[XNDJTDDLoadingTool hideHUDInView:self.navigationController.view];
|
||
|
||
// 🔧 防护:检查 VC 是否仍然有效
|
||
if (self.isExitingRoom || !self.isViewActive) {
|
||
NSLog(@"🔧 enterRoomSuccess: VC 已退出或不可见,忽略回调");
|
||
return;
|
||
}
|
||
|
||
[self.stageView onRoomEntered];
|
||
[self.functionView onRoomEntered];
|
||
|
||
// 🔧 新增:初始化当前用户的麦位状态
|
||
[self initializeCurrentUserMicStatus];
|
||
|
||
//上报进房
|
||
if (self.roomInfo != nil) {
|
||
[self.presenter reportUserInterRoom:[NSString stringWithFormat:@"%zd", self.roomInfo.uid]];
|
||
}
|
||
if (self.giftId.length) {
|
||
///有的时候 拉取麦序的话 可能会有点延迟 导致送礼物的人 没有拉取到
|
||
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
|
||
[[NSNotificationCenter defaultCenter] postNotificationName:@"kShowGiftView" object:@{@"giftId": self.giftId}];
|
||
});
|
||
}
|
||
}
|
||
|
||
- (void)enterRoomFail:(NSInteger)code {
|
||
[XNDJTDDLoadingTool hideHUDInView:self.navigationController.view];
|
||
[self hideHUD];
|
||
|
||
// 🔧 防护:检查 VC 是否仍然有效
|
||
if (self.isExitingRoom || !self.isViewActive) {
|
||
NSLog(@"🔧 enterRoomFail: VC 已退出或不可见,忽略回调 (code: %ld)", (long)code);
|
||
return;
|
||
}
|
||
|
||
if (code == 13003) {
|
||
[self showErrorToast:YMLocalizedString(@"XPRoomViewController3")];
|
||
}
|
||
[self dismissViewControllerAnimated:YES completion:nil];
|
||
}
|
||
-(void)getOnlineCount{
|
||
@kWeakify(self);
|
||
[Api requestRoomOnlineUserList:^(BaseModel * _Nullable data, NSInteger code, NSString * _Nullable msg) {
|
||
@kStrongify(self);
|
||
if(code == 200){
|
||
NSMutableArray *temp = @[].mutableCopy;
|
||
NSArray *list = [XPMessageRemoteExtModel modelsWithArray:data.data];
|
||
for (XPMessageRemoteExtModel *model in list) {
|
||
if (model.platformRole != 1) {
|
||
[temp addObject:model];
|
||
}
|
||
}
|
||
self.roomInfo.onlineNum = temp.count;
|
||
[self.functionView updateOnlineCount:[NSString stringWithFormat:@"%ld",temp.count] countList:temp.copy isUpdateCount:NO];
|
||
}
|
||
// 更安全的輪詢
|
||
@kWeakify(self);
|
||
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(60 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
|
||
@kStrongify(self);
|
||
if (self) {
|
||
[self getOnlineCount];
|
||
}
|
||
});
|
||
} roomUid:self.roomUid];
|
||
}
|
||
///请求房间超管成功
|
||
///这个接口本来是想和roominfo 和userinfo 一起请求的 但是 进房的同步操作 只有超管进入密码房间才会有同步的问题
|
||
- (void)getRoomSuperAdminSuccess:(NSArray *)list {
|
||
self.isRequestSuperAdmin = YES;
|
||
self.superMangerList = list;
|
||
}
|
||
|
||
///获取推荐滚动的个播房列表(只有第一次进房获取)
|
||
- (void)getNextAnchorRoomSuccess:(RoomInfoModel *)roomInfo {
|
||
[self hideHUD];
|
||
if (roomInfo) { //获取下一个房间成功
|
||
if (![self.anchorRoomList containsObject:self.roomUid]) {
|
||
[self.anchorRoomList addObject:self.roomUid];
|
||
}
|
||
self.anchorIndex = self.anchorRoomList.count -1;
|
||
//1、退出房间操作
|
||
self.anchorScrollView.isCanScrollTop = YES;
|
||
self.anchorScrollView.contentOffset = CGPointMake(0, KScreenHeight);
|
||
self.isRequestSuperAdmin = NO;
|
||
[self exitOldRoom];
|
||
[self.presenter exitNIMRoom:[NSString stringWithFormat:@"%ld", self.roomInfo.roomId]];
|
||
[[XPRoomMiniManager shareManager] resetLocalMessage];
|
||
[[RtcManager instance] exitRoom];
|
||
[self.presenter reportUserOutRoom:[NSString stringWithFormat:@"%ld", self.roomInfo.uid]];
|
||
[self.functionView onRoomChange];
|
||
//2、移除房间子控件
|
||
[self.stageView removeFromSuperview];
|
||
[self.messageContainerView removeFromSuperview];
|
||
[self.quickMessageContainerView removeFromSuperview];
|
||
[self.sideMenu removeFromSuperview];
|
||
[self.roomHeaderView removeFromSuperview];
|
||
[self.functionView removeFromSuperview];
|
||
self.functionView = nil;
|
||
self.messageContainerView = nil;
|
||
self.stageView = nil;
|
||
[self.menuContainerView removeFromSuperview];
|
||
self.menuContainerView = nil;
|
||
//3、重新进入房间
|
||
self.roomUid = [NSString stringWithFormat:@"%zd", roomInfo.uid];
|
||
[self.presenter initEnterRoom:self.roomUid user:[AccountInfoStorage instance].getUid];
|
||
/// 公屏 福袋礼物爆出的礼物 需要依赖 当前房间中的礼物列表 需要提前获取礼物列表 可以拿到礼物 没有想到别的方法去解决这个问题 有需要改的在修改吧
|
||
[self.presenter getNormalGiftList:self.roomUid];
|
||
///获取房间超管列表
|
||
[self.presenter getRoomSuperAdmin:self.roomUid];
|
||
} else {
|
||
if (self.anchorScrollView.isCanScrollTop) {
|
||
self.anchorScrollView.contentOffset = CGPointMake(0, KScreenHeight);
|
||
} else {
|
||
self.anchorScrollView.contentOffset = CGPointMake(0, 0);
|
||
}
|
||
[self showErrorToast:YMLocalizedString(@"XPRoomViewController4")];
|
||
}
|
||
}
|
||
|
||
- (void)getCurrentRoomInfoSuccess:(RoomInfoModel *)roomInfo {
|
||
[self hideHUD];
|
||
self.anchorScrollView.contentOffset = CGPointMake(0, KScreenHeight);
|
||
if (roomInfo && roomInfo.valid) {
|
||
//1、退出房间操作
|
||
self.isRequestSuperAdmin = NO;
|
||
[self exitOldRoom];
|
||
[self.presenter exitNIMRoom:[NSString stringWithFormat:@"%ld", self.roomInfo.roomId]];
|
||
[[XPRoomMiniManager shareManager] resetLocalMessage];
|
||
[[RtcManager instance] exitRoom];
|
||
[self.presenter reportUserOutRoom:[NSString stringWithFormat:@"%ld", self.roomInfo.uid]];
|
||
//2、移除房间子控件
|
||
// [self.backContainerView removeFromSuperview];
|
||
[self.stageView removeFromSuperview];
|
||
[self.messageContainerView removeFromSuperview];
|
||
[self.quickMessageContainerView removeFromSuperview];
|
||
[self.sideMenu removeFromSuperview];
|
||
[self.roomHeaderView removeFromSuperview];
|
||
[self.functionView removeFromSuperview];
|
||
self.functionView = nil;
|
||
self.messageContainerView = nil;
|
||
self.stageView = nil;
|
||
[self.menuContainerView removeFromSuperview];
|
||
self.menuContainerView = nil;
|
||
//3、重新进入房间
|
||
self.roomUid = [NSString stringWithFormat:@"%zd", roomInfo.uid];
|
||
[self.presenter initEnterRoom:self.roomUid user:[AccountInfoStorage instance].getUid];
|
||
/// 公屏 福袋礼物爆出的礼物 需要依赖 当前房间中的礼物列表 需要提前获取礼物列表 可以拿到礼物 没有想到别的方法去解决这个问题 有需要改的在修改吧
|
||
[self.presenter getNormalGiftList:self.roomUid];
|
||
///获取房间超管列表
|
||
[self.presenter getRoomSuperAdmin:self.roomUid];
|
||
} else {
|
||
[self showErrorToast:YMLocalizedString(@"XPRoomViewController5")];
|
||
}
|
||
}
|
||
|
||
///个播房初始化一些操作
|
||
- (void)handleInitAnchorRoom {
|
||
if (self.roomInfo.valid) { // 房间有效,直接进入房间
|
||
if (self.roomInfo.roomPwd.length > 0 &&
|
||
self.roomInfo.uid != [AccountInfoStorage instance].getUid.integerValue &&
|
||
[XPRoomMiniManager shareManager].getRoomInfo.uid != self.roomUid.integerValue) {//进房密码的情况
|
||
if (!self.isRequestSuperAdmin) {
|
||
@kWeakify(self);
|
||
[Api getRoomSuperAdminList:^(BaseModel * _Nullable data, NSInteger code, NSString * _Nullable msg) {
|
||
@kStrongify(self);
|
||
NSArray<GuildSuperAdminInfoModel *> * array = [GuildSuperAdminInfoModel modelsWithArray:data.data];
|
||
self.superMangerList = array;
|
||
[self handleSuperManagerEnterAnchorRoom:self.roomInfo];
|
||
} roomUid:self.roomUid];
|
||
} else {
|
||
[self handleSuperManagerEnterAnchorRoom:self.roomInfo];
|
||
}
|
||
} else {
|
||
self.roomInfo.datingState = self.roomInfo.roomModeType == RoomModeType_Open_Blind ? RoomDatingStateChangeType_Open : RoomDatingStateChangeType_Normal;
|
||
|
||
[self __removeAllViews];
|
||
|
||
if (!self.anchorScrollView.superview) {
|
||
[self.view addSubview:self.anchorScrollView];
|
||
}
|
||
|
||
[self.anchorScrollView addSubview:self.backContainerView];
|
||
[self.anchorScrollView addSubview:self.stageView];
|
||
[self.anchorScrollView addSubview:self.messageContainerView];
|
||
[self.anchorScrollView addSubview:self.quickMessageContainerView];
|
||
[self.anchorScrollView addSubview:self.sideMenu];
|
||
[self.anchorScrollView addSubview:self.roomHeaderView];
|
||
[self.anchorScrollView addSubview:self.menuContainerView];
|
||
[self.anchorScrollView addSubview:self.functionView];
|
||
[self.view bringSubviewToFront:self.animationView];
|
||
|
||
[self updateViewConstraintsOnAnchorRoom];
|
||
[self changeStageViewOnAnchorRoom];
|
||
|
||
[self.roomHeaderView onRoomEntered];
|
||
[self.sideMenu onRoomEntered];
|
||
|
||
|
||
[self.backContainerView onRoomEntered];
|
||
[self.littleGameView onRoomEntered];
|
||
if ([XPRoomMiniManager shareManager].getRoomInfo.uid != self.roomUid.integerValue) {// 最小化进房 还是原来的房间的话 不需要重新进入云信 因为压根没退
|
||
// 🔧 防护:检查是否允许进房
|
||
if (!self.isExitingRoom && self.isViewActive) {
|
||
[self.presenter enterNIMRoom:[NSString stringWithFormat:@"%ld", self.roomInfo.roomId] user:self.userInfo];
|
||
}
|
||
[self.functionView onRoomEntered];
|
||
[self.messageContainerView onRoomEntered];
|
||
[self.menuContainerView onRoomEntered];
|
||
} else {
|
||
//虽然没退出房间 但是队列还是要拿的
|
||
[self.stageView onRoomMiniEntered];
|
||
[self.messageContainerView onRoomMiniEntered];
|
||
[self.functionView onRoomMiniEntered];
|
||
[self.functionView onRoomEntered];
|
||
[self.menuContainerView onRoomMiniEntered];
|
||
|
||
// 🔧 最小化进房:初始化当前用户麦位状态
|
||
[self initializeCurrentUserMicStatusForMiniEnter];
|
||
}
|
||
|
||
[self cleanMiniRoomStatues];
|
||
}
|
||
} else { // 房间无效,分是否为自己房间进行处理
|
||
if ([self.roomUid isEqualToString:[NSString stringWithFormat:@"%ld", self.userInfo.uid]]) { // 当前用户进入自己房间
|
||
if (self.roomInfo.roomId > 0) { // 存在房间信息,直接使用房间信息开房
|
||
if (self.roomInfo.type == RoomType_MiniGame && self.roomInfo.mgId > 0) {
|
||
self.mgId = [NSString stringWithFormat:@"%lld", self.roomInfo.mgId];
|
||
}
|
||
[self.presenter openRoom:self.roomInfo.title type:self.roomInfo.type roomPwd:self.roomInfo.roomPwd roomDesc:self.roomInfo.roomDesc backPic:@"" mgId:self.mgId];
|
||
} else { // 不存在房间信息,全新开房
|
||
NSString* title = [NSString stringWithFormat:YMLocalizedString(@"XPRoomViewController6"), self.userInfo.nick];
|
||
RoomType type = RoomType_Room;
|
||
if (self.mgId.length > 0) {
|
||
type = RoomType_MiniGame;
|
||
}
|
||
[self.presenter openRoom:title type:type roomPwd:@"" roomDesc:@"" backPic:@"" mgId:self.mgId];
|
||
}
|
||
} else { // 当前用户进入别人房间
|
||
[self showSuccessToast:YMLocalizedString(@"XPRoomViewController7")];
|
||
[self enterRoomFail:0];
|
||
}
|
||
}
|
||
}
|
||
- (void)getRedPacketInfoSuccess:(XPRedPacketModel *)redInfo{
|
||
XPReceiveRedPacketView *view = [[XPReceiveRedPacketView alloc] initWithFrame:CGRectMake(0, 0, KScreenWidth, KScreenHeight)];
|
||
view.delegate = self;
|
||
self.isShowRedPacket = YES;
|
||
redInfo.validityType = 0;
|
||
redInfo.kind = 1;
|
||
view.receiveModel = redInfo;
|
||
view.inAllPacketRoom = YES;
|
||
for (UIView *subView in self.view.subviews) {
|
||
if([subView isKindOfClass:[XPReceiveRedPacketView class]]) {
|
||
view.alphaView.backgroundColor = [UIColor clearColor];
|
||
break;
|
||
}
|
||
}
|
||
[self.view addSubview:view];
|
||
[self.view bringSubviewToFront:view];
|
||
}
|
||
|
||
- (void)getRedPacketSuccess:(NSArray *)list {
|
||
if(list.count > 0){
|
||
self.sideMenu.redPacketList = [NSMutableArray arrayWithArray:list];
|
||
}
|
||
}
|
||
|
||
-(void)getFreeGiftDataSuccess:(XPFreeGiftModel *)freeModel{
|
||
self.freeModel = freeModel;
|
||
self.menuContainerView.freeModel = freeModel;
|
||
if(self.freeModel.curStage.integerValue < self.freeModel.maxStage.integerValue){
|
||
[CountDownHelper shareHelper].isCountdownFinish = NO;
|
||
[[CountDownHelper shareHelper] openCountdownWithTime:freeModel.curStageSecond.intValue];
|
||
}else{
|
||
if([CountDownHelper shareHelper].isCountdownFinish == NO){
|
||
[CountDownHelper shareHelper].isCountdownFinish = YES;
|
||
}
|
||
[[NSNotificationCenter defaultCenter]postNotificationName:kFreeGiftCountdownNotification object:nil userInfo:@{@"isHiddenCountdown":@(YES)}];
|
||
[[CountDownHelper shareHelper] stopCountDown];
|
||
}
|
||
|
||
if(self.freeModel.curStage.intValue > 0 && [[XPRoomMiniManager shareManager].curState isEqualToString:@"0"]){
|
||
self.freeView.freeModel = self.freeModel;
|
||
if(!self.freeView.superview){
|
||
[kWindow addSubview:self.freeView];
|
||
}
|
||
[XPRoomMiniManager shareManager].curState = nil;
|
||
}
|
||
}
|
||
|
||
|
||
#pragma mark - NIMChatroomManagerDelegate
|
||
- (void)chatroomBeKicked:(NIMChatroomBeKickedResult *)result {
|
||
|
||
if (result.reason == 5) {
|
||
[self showErrorToast:YMLocalizedString(@"XPRoomViewController9")];
|
||
}
|
||
[self.presenter exitNIMRoom:[NSString stringWithFormat:@"%ld", self.roomInfo.roomId]];
|
||
[[XPRoomMiniManager shareManager] resetLocalMessage];
|
||
[self cancelRoomArrangeMic];
|
||
[[RtcManager instance] exitRoom];
|
||
[self.presenter reportUserOutRoom:[NSString stringWithFormat:@"%ld", self.roomInfo.uid]];
|
||
[self.littleGameView handleSelfInExitEvent];
|
||
[self.littleGameView destroyMG];
|
||
[self dismissViewControllerAnimated:YES completion:nil];
|
||
}
|
||
|
||
#pragma mark - NIMChatManagerDelegate
|
||
- (void)__removeAllViews {
|
||
[self.anchorScrollView removeFromSuperview];
|
||
[self.backContainerView removeFromSuperview];
|
||
[self.stageView removeFromSuperview];
|
||
[self.messageContainerView removeFromSuperview];
|
||
[self.quickMessageContainerView removeFromSuperview];
|
||
[self.sideMenu removeFromSuperview];
|
||
[self.roomHeaderView removeFromSuperview];
|
||
[self.functionView removeFromSuperview];
|
||
[self.menuContainerView removeFromSuperview];
|
||
}
|
||
|
||
- (void)onRecvMessages:(NSArray<NIMMessage *> *)messages {
|
||
// 入口排查日志:批次大小、线程和时间戳
|
||
for (NIMMessage * message in messages) {
|
||
///房间内收到p2p的消息 比如升级消息
|
||
if (message.session.sessionType == NIMSessionTypeP2P) {
|
||
if(message.messageType == NIMMessageTypeCustom) {
|
||
NIMCustomObject *obj = (NIMCustomObject *)message.messageObject;
|
||
if (obj.attachment != nil && [obj.attachment isKindOfClass:[AttachmentModel class]]) {
|
||
AttachmentModel * attachment = (AttachmentModel *)obj.attachment;
|
||
if (attachment.first == CustomMessageType_User_UpGrade) {
|
||
ContentLevelUpgradeModel * levelInfo = [ContentLevelUpgradeModel modelWithDictionary:attachment.data];
|
||
if (attachment.second == Custom_Message_Sub_User_UpGrade_Exper) {
|
||
self.userInfo.userLevelVo.experLevelSeq = levelInfo.levelSeq;
|
||
} else if(attachment.second == Custom_Message_Sub_User_UpGrade_Charm) {
|
||
self.userInfo.userLevelVo.charmLevelSeq = levelInfo.levelSeq;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
// 非房间内消息不处理(记录过滤原因)
|
||
if (message.session.sessionType != NIMSessionTypeChatroom) {
|
||
NSLog(@"[Recv] ⛔️ 过滤:非聊天室消息 | type=%ld | sid=%@",
|
||
(long)message.session.sessionType, message.session.sessionId);
|
||
continue;
|
||
}
|
||
|
||
if (![message.session.sessionId isEqualToString:@(self.roomInfo.roomId).stringValue]) {
|
||
NSLog(@"[Recv] ⛔️ 过滤:房间不匹配 | msg.sid=%@ | curRoomId=%@",
|
||
message.session.sessionId, @(self.roomInfo.roomId).stringValue);
|
||
continue;
|
||
}
|
||
|
||
NSLog(@"[Recv] --- Message Raw Attach Content: %@, %@, %ld", @(message.senderClientType), message.rawAttachContent, (long)message.messageType);
|
||
|
||
if ([message.rawAttachContent containsString:@"\"allRoomMsg\":1"]) {
|
||
NSLog(@"[Recv] --- 拦截旧的全房间消息");
|
||
continue;
|
||
}
|
||
|
||
if (message.messageType == NIMMessageTypeNotification) {
|
||
[self handleNIMNotificationTypeMessage:message];
|
||
} else if (message.messageType == NIMMessageTypeCustom) {
|
||
[self handleNimCustomTypeMessage:message];
|
||
} else if(message.messageType == NIMMessageTypeText) {
|
||
[self.messageContainerView handleNIMTextMessage:message];
|
||
[self.littleGameView handleNIMTextMessage:message];
|
||
} else if(message.messageType == NIMMessageTypeTip) {
|
||
[self.messageContainerView handleNIMTextMessage:message];
|
||
}else if(message.messageType == NIMMessageTypeImage){
|
||
[self.messageContainerView handleNIMImageMessage:message];
|
||
}
|
||
}
|
||
}
|
||
|
||
- (void)handleNIMNotificationTypeMessage:(NIMMessage *)message {
|
||
NIMNotificationObject *notiMsg = (NIMNotificationObject *)message.messageObject;
|
||
NIMChatroomNotificationContent *content = (NIMChatroomNotificationContent *)notiMsg.content;
|
||
|
||
if (![notiMsg.content isKindOfClass:[NIMChatroomNotificationContent class]]) {
|
||
// content 可能为其他类型,不处理
|
||
return;
|
||
}
|
||
|
||
NSInteger onLineNumber = self.roomInfo.onlineNum;
|
||
switch (content.eventType) {
|
||
case NIMChatroomEventTypeInfoUpdated: // 麦序状态更新
|
||
{
|
||
NSDictionary *data = [content.notifyExt toJSONObject];
|
||
[self handleSwitchRoomType:data];
|
||
}
|
||
break;
|
||
case NIMChatroomEventTypeEnter:
|
||
{
|
||
if (content.source.userId.integerValue == [AccountInfoStorage instance].getUid.integerValue){
|
||
[self.presenter getKickUserListWithRoomUid:@(self.roomInfo.uid).stringValue];
|
||
}
|
||
if (content.source.userId.integerValue != [AccountInfoStorage instance].getUid.integerValue && self.userInfo.platformRole != 1) {
|
||
onLineNumber += 1;
|
||
}else {
|
||
///如果是自己的话 如果有坐骑的话
|
||
[self userEnterRoomSuccess];
|
||
///在活动页面 判断是否显示 相亲加入的按钮 所以需要等用户进房成功之后才能获取 房间角色
|
||
[self.sideMenu onRoomUpdate];
|
||
|
||
[self.menuContainerView onRoomUpdate];
|
||
}
|
||
|
||
break;
|
||
}
|
||
case NIMChatroomEventTypeAddBlack:
|
||
case NIMChatroomEventTypeKicked:
|
||
case NIMChatroomEventTypeExit:
|
||
onLineNumber -= 1;
|
||
break;
|
||
case NIMChatroomEventTypeQueueChange: // 麦序上下麦
|
||
{
|
||
NSDictionary* data = (NSDictionary *)content.ext;
|
||
UserInfoModel* userInfo = [UserInfoModel modelWithJSON:[data objectForKey:NIMChatroomEventInfoQueueChangeItemValueKey]];
|
||
NSInteger changeType = [data[NIMChatroomEventInfoQueueChangeTypeKey] integerValue];
|
||
|
||
NSLog(@"🔧 接收到麦序变化通知:用户 %ld,变化类型 %ld", (long)userInfo.uid, (long)changeType);
|
||
|
||
// 处理排麦场景
|
||
if (changeType == 1 && userInfo.uid == [AccountInfoStorage instance].getUid.integerValue) {
|
||
[self cancelRoomArrangeMic];
|
||
}
|
||
|
||
// 他人上麦:通过自定义消息同步CP,直接返回
|
||
if (changeType == 1 && userInfo.uid != [AccountInfoStorage instance].getUid.integerValue) {
|
||
// 🔧 改进:处理其他用户上麦场景
|
||
[self handleOtherUserMicChange:userInfo changeType:changeType];
|
||
} else {
|
||
// 他人下麦:仅更新缓存与显示,跳过 API
|
||
if (changeType == 2 && userInfo.uid != [AccountInfoStorage instance].getUid.integerValue) {
|
||
// 🔧 改进:处理其他用户切换mic场景
|
||
[self handleOtherUserMicChange:userInfo changeType:changeType];
|
||
} else {
|
||
NSNumber *key = nil;
|
||
if ([notiMsg respondsToSelector:@selector(attachContent)]) {
|
||
NSString *jsonString = (NSString *)[notiMsg performSelector:@selector(attachContent)];
|
||
NSData *jsonData = [jsonString dataUsingEncoding:NSUTF8StringEncoding];
|
||
NSError *error = nil;
|
||
NSDictionary *attachData = [NSJSONSerialization JSONObjectWithData:jsonData options:0 error:&error];
|
||
if (!error) {
|
||
NSDictionary *dataDic = [attachData objectForKey:@"data"];
|
||
NSString *queueChange = [dataDic objectForKey:@"queueChange"];
|
||
if (![NSString isEmpty:queueChange]) {
|
||
jsonData = [queueChange dataUsingEncoding:NSUTF8StringEncoding];
|
||
NSError *e = nil;
|
||
NSDictionary *queueChangeData = [NSJSONSerialization JSONObjectWithData:jsonData options:0 error:&error];
|
||
if (!e) {
|
||
key = [queueChangeData objectForKey:@"key"];
|
||
}
|
||
}
|
||
}
|
||
}
|
||
if (key) {
|
||
// 通过 key 更新麦位队列
|
||
NSInteger position = key.integerValue;
|
||
NSMutableDictionary<NSString *,MicroQueueModel *> *currentQueue = [self.stageView getMicroQueue];
|
||
if (currentQueue) {
|
||
for (NSString *key in [currentQueue allKeys]) {
|
||
if (key.integerValue == position) {
|
||
MicroQueueModel *model = [currentQueue objectForKey:key];
|
||
if (changeType == 2) {
|
||
// 用户下 mic
|
||
model.userInfo = nil;
|
||
} else {
|
||
// 用户上 mic
|
||
model.userInfo = userInfo;
|
||
}
|
||
break;
|
||
}
|
||
}
|
||
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.25 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
|
||
[self handleMicChangeForCP:currentQueue];
|
||
});
|
||
}
|
||
} else {
|
||
// 获取最新的麦位队列
|
||
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
|
||
NSMutableDictionary<NSString *,MicroQueueModel *> *currentQueue = [self.stageView getMicroQueue];
|
||
if (currentQueue) {
|
||
[self handleMicChangeForCP:currentQueue];
|
||
}
|
||
});
|
||
}
|
||
}
|
||
}
|
||
}
|
||
break;
|
||
case NIMChatroomEventTypeAddManager: {
|
||
NIMChatroomNotificationMember *targets = [content.targets firstObject];
|
||
if (targets.userId.integerValue == self.userInfo.uid) {
|
||
[XNDJTDDLoadingTool showSuccessWithMessage:YMLocalizedString(@"1.0.34_text_15")];
|
||
}
|
||
|
||
}
|
||
break;
|
||
case NIMChatroomEventTypeRemoveManager: {
|
||
NIMChatroomNotificationMember *targets = [content.targets firstObject];
|
||
if (targets.userId.integerValue == self.userInfo.uid) {
|
||
[XNDJTDDLoadingTool showSuccessWithMessage:YMLocalizedString(@"1.0.34_text_16")];
|
||
}
|
||
}
|
||
break;
|
||
default:
|
||
break;
|
||
}
|
||
self.roomInfo.onlineNum = onLineNumber;
|
||
[self.functionView updateOnlineCount:[NSString stringWithFormat:@"%ld",onLineNumber] countList:@[] isUpdateCount:YES];
|
||
[self.roomHeaderView onRoomUpdate];
|
||
[self.stageView handleNIMNotificationMessage:message];
|
||
[self.animationView handleNIMNotificationMessage:message];
|
||
[self.messageContainerView handleNIMNotificationMessage:message];
|
||
[self.sideMenu handleNIMNotificationMessage:message];
|
||
[self.menuContainerView handleNIMNotificationMessage:message];
|
||
[self.functionView handleNIMNotificationMessage:message];
|
||
[self.littleGameView handleNIMNotificationMessage:message];
|
||
if([self.stageView findMicroViewByUid:@(self.userInfo.uid).stringValue] != nil){
|
||
[XPSkillCardPlayerManager shareInstance].isMineInMic = YES;
|
||
}else{
|
||
[XPSkillCardPlayerManager shareInstance].isMineInMic = NO;
|
||
};
|
||
}
|
||
|
||
- (void)handleSwitchRoomType:(NSDictionary *)data {
|
||
int type = [data[@"type"] intValue];
|
||
switch (type) {
|
||
case 1: // 房间信息变化
|
||
case 3: // 房间信息 & 麦位信息变化
|
||
{
|
||
NSMutableDictionary *lastRoomInfoDic = [NSMutableDictionary dictionaryWithDictionary:[self.roomInfo model2dictionary]];
|
||
[lastRoomInfoDic addEntriesFromDictionary: ((NSString *)data[@"roomInfo"]).toJSONObject];
|
||
RoomInfoModel *newRoomInfo = [RoomInfoModel modelWithJSON:lastRoomInfoDic];
|
||
|
||
if (newRoomInfo.type != RoomType_MiniGame) {
|
||
newRoomInfo.mgId = 0;
|
||
}
|
||
newRoomInfo.hasAnimationEffect = self.hasAnimationEffect;
|
||
if (newRoomInfo.roomModeType == RoomModeType_Open_Blind && self.roomInfo.roomModeType != RoomModeType_Open_Blind) {
|
||
///普通房 切换为相亲房
|
||
newRoomInfo.datingState = RoomDatingStateChangeType_Open;
|
||
} else if(newRoomInfo.roomModeType != RoomModeType_Open_Blind && self.roomInfo.roomModeType == RoomModeType_Open_Blind) {
|
||
///关闭了相亲房
|
||
newRoomInfo.datingState = RoomDatingStateChangeType_Close;
|
||
} else {
|
||
newRoomInfo.datingState = RoomDatingStateChangeType_Normal;
|
||
}
|
||
//房间类型是否变更了(从个播->普通,个播->小游戏等)
|
||
newRoomInfo.hadChangeRoomType = self.roomInfo.type != newRoomInfo.type;
|
||
BOOL anchorToOther = newRoomInfo.type != RoomType_Anchor && self.roomInfo.type == RoomType_Anchor;//个播变其他房
|
||
self.roomInfo = newRoomInfo;
|
||
|
||
[self.backContainerView onRoomUpdate];
|
||
|
||
self.quickMessageContainerView.titleArray = self.roomInfo.speakTemplate;
|
||
if (self.roomInfo.type == RoomType_Anchor && self.roomInfo.hadChangeRoomType) {///从其他房变为个播房
|
||
[self handleInitAnchorRoom];
|
||
[self showAnchorScrollTipView];
|
||
} else if (anchorToOther) {
|
||
[self __removeAllViews];
|
||
|
||
[self.view addSubview:self.backContainerView];
|
||
[self.view addSubview:self.stageView];
|
||
[self.view addSubview:self.messageContainerView];
|
||
[self.view addSubview:self.quickMessageContainerView];
|
||
[self.view addSubview:self.menuContainerView];
|
||
[self.view addSubview:self.sideMenu];
|
||
[self.view addSubview:self.roomHeaderView];
|
||
[self.view bringSubviewToFront:self.menuContainerView];
|
||
[self.view addSubview:self.functionView];
|
||
[self.view bringSubviewToFront:self.animationView];
|
||
|
||
[self initSubViewConstraints];
|
||
[self changeStageViewOnRoomUpdate];
|
||
[self.stageView onRoomUpdate];
|
||
[self.menuContainerView onRoomUpdate];
|
||
[self.functionView onRoomUpdate];
|
||
[self.sideMenu onRoomUpdate];
|
||
[self.messageContainerView onRoomUpdate];
|
||
[self.littleGameView onRoomUpdate];
|
||
} else {
|
||
if (self.roomInfo.type == RoomType_Anchor) {
|
||
[self changeStageViewOnAnchorRoom];
|
||
} else if (self.roomInfo.type == RoomType_20Mic) {
|
||
[self __layoutTwentyMicStage];
|
||
[self changeStageViewOnRoomUpdate];
|
||
[self.twentyMicStageView onRoomUpdate];
|
||
} else if (self.roomInfo.type == RoomType_19Mic) {
|
||
[self __layoutNineteenMicStage];
|
||
[self changeStageViewOnRoomUpdate];
|
||
[self.nineteenMicStageView onRoomUpdate];
|
||
} else if (self.roomInfo.type == RoomType_15Mic) {
|
||
[self __layoutFifteenMicStage];
|
||
[self changeStageViewOnRoomUpdate];
|
||
[self.fifteenMicStageView onRoomUpdate];
|
||
} else if (self.roomInfo.type == RoomType_10Mic) {
|
||
[self __layoutTenMicStage];
|
||
[self changeStageViewOnRoomUpdate];
|
||
[self.tenMicStageView onRoomUpdate];
|
||
} else {
|
||
[self changeStageViewOnRoomUpdate];
|
||
}
|
||
[self.stageView onRoomUpdate];
|
||
[self.menuContainerView onRoomUpdate];
|
||
[self.functionView onRoomUpdate];
|
||
[self.sideMenu onRoomUpdate];
|
||
|
||
[self.messageContainerView onRoomUpdate];
|
||
[self.littleGameView onRoomUpdate];
|
||
}
|
||
}
|
||
break;
|
||
}
|
||
}
|
||
|
||
- (void)handleNimCustomTypeMessage:(NIMMessage *)message {
|
||
NIMCustomObject *obj = (NIMCustomObject *)message.messageObject;
|
||
if (obj.attachment != nil && [obj.attachment isKindOfClass:[AttachmentModel class]]) {
|
||
AttachmentModel * attachment = (AttachmentModel *)obj.attachment;
|
||
[self.stageView handleNIMCustomMessage:message];
|
||
[self.animationView handleNIMCustomMessage:message];
|
||
[self.menuContainerView handleNIMCustomMessage:message];
|
||
[self.sideMenu handleNIMCustomMessage:message];
|
||
[self.functionView handleNIMCustomMessage:message];
|
||
[self.littleGameView handleNIMCustomMessage:message];
|
||
[self.messageContainerView handleNIMCustomMessage:message];
|
||
|
||
switch (attachment.first) {
|
||
case ClientMessage_Type:
|
||
switch (attachment.second) {
|
||
case ClientMessage_UpMic_Ask:
|
||
[self handleUpMicAsk:attachment];
|
||
break;
|
||
case ClientMessage_UpMic_Agree:
|
||
[self handleUpMicAgree:attachment];
|
||
break;
|
||
case ClientMessage_UpMic_Reject:
|
||
[XNDJTDDLoadingTool showErrorWithMessage:YMLocalizedString(@"20.20.62_text_4")];
|
||
break;
|
||
}
|
||
break;
|
||
|
||
case CustomMessageType_First_Recharge_Reward:
|
||
switch (attachment.second) {
|
||
case Custom_Message_Sub_Room_First_Recharge_Reward:
|
||
self.userInfo.isFirstCharge = NO;
|
||
[self.menuContainerView onRoomUpdate];
|
||
[self.sideMenu onRoomUpdate];
|
||
break;
|
||
}
|
||
break;
|
||
|
||
case CustomMessageType_Update_RoomInfo:
|
||
switch (attachment.second) {
|
||
case Custom_Message_Sub_Update_RoomInfo_MessageState: {
|
||
///兼容安卓和iOS 协议不同的问题
|
||
NSDictionary * dic= attachment.data[@"roomInfo"];
|
||
if (dic.allKeys.count <=0) {
|
||
dic = attachment.data;
|
||
}
|
||
RoomInfoModel * roomInfo = [RoomInfoModel modelWithDictionary:dic];
|
||
self.roomInfo.isCloseScreen = roomInfo.isCloseScreen;
|
||
|
||
[self.menuContainerView onRoomUpdate];
|
||
}
|
||
break;
|
||
|
||
case Custom_Message_Sub_Update_RoomInfo_AnimateEffect: {
|
||
NSDictionary * dic= attachment.data[@"roomInfo"];
|
||
if (dic.allKeys.count <=0) {
|
||
dic = attachment.data;
|
||
}
|
||
RoomInfoModel * roomInfo = [RoomInfoModel modelWithDictionary:dic];
|
||
self.roomInfo.hasAnimationEffect = roomInfo.hasAnimationEffect;
|
||
[self.roomHeaderView onRoomUpdate];
|
||
}
|
||
break;
|
||
}
|
||
break;
|
||
|
||
case CustomMessageType_Queue:
|
||
switch (attachment.second) {
|
||
case Custom_Message_Sub_Queue_Invite: {
|
||
NSDictionary *dic = attachment.data;
|
||
NSString *uid = dic[@"uid"];
|
||
if (uid.integerValue == [AccountInfoStorage instance].getUid.integerValue) {
|
||
[self cancelRoomArrangeMic];
|
||
}
|
||
}
|
||
break;
|
||
}
|
||
break;
|
||
|
||
case CustomMessageType_Hall_Super_Admin:
|
||
switch (attachment.second) {
|
||
case Custom_Message_Sub_Hall_Super_Admin_Kick_Manager_Out_Room: {
|
||
XPKickUserModel * userInfo = [XPKickUserModel modelWithJSON:attachment.data];
|
||
if (userInfo.targetUid == [AccountInfoStorage instance].getUid.integerValue) {
|
||
[self.presenter exitNIMRoom:[NSString stringWithFormat:@"%ld", self.roomInfo.roomId]];
|
||
[[XPRoomMiniManager shareManager] resetLocalMessage];
|
||
[self cancelRoomArrangeMic];
|
||
[[RtcManager instance] exitRoom];
|
||
[self.presenter reportUserOutRoom:[NSString stringWithFormat:@"%ld", self.roomInfo.uid]];
|
||
[self.littleGameView handleSelfInExitEvent];
|
||
[self.littleGameView destroyMG];
|
||
[self dismissViewControllerAnimated:YES completion:nil];
|
||
}
|
||
}
|
||
break;
|
||
}
|
||
break;
|
||
|
||
case CustomMessageType_RedPacket:
|
||
switch (attachment.second) {
|
||
case Custom_Message_Sub_RoomDiamandRedPacket: {
|
||
XPReceiveRedPacketView *view = [[XPReceiveRedPacketView alloc] initWithFrame:CGRectMake(0, 0, KScreenWidth, KScreenHeight)];
|
||
XPRedPacketModel *data = [XPRedPacketModel modelWithJSON:attachment.data];
|
||
view.delegate = self;
|
||
self.isShowRedPacket = YES;
|
||
data.validityType = 0;
|
||
data.kind = 1;
|
||
data.redEnvelopeId = attachment.data[@"redEnvelopeId"];
|
||
view.receiveModel = data;
|
||
for (UIView *subView in self.view.subviews) {
|
||
if([subView isKindOfClass:[XPReceiveRedPacketView class]]) {
|
||
view.alphaView.backgroundColor = [UIColor clearColor];
|
||
break;
|
||
}
|
||
}
|
||
[self.view addSubview:view];
|
||
[self.view bringSubviewToFront:view];
|
||
if(self.sideMenu.redPacketList == nil){
|
||
self.sideMenu.redPacketList = [NSMutableArray array];
|
||
}
|
||
NSMutableArray *redPacketList = [NSMutableArray arrayWithArray:self.sideMenu.redPacketList];
|
||
[redPacketList insertObject:data atIndex:0];
|
||
self.sideMenu.redPacketList = redPacketList;
|
||
}
|
||
break;
|
||
|
||
case Custom_Message_Sub_NewRoomDiamandRedPacket: {
|
||
XPRedPacketModel *curData = [XPRedPacketModel modelWithJSON:attachment.data];
|
||
if(self.sideMenu.redPacketList == nil){
|
||
self.sideMenu.redPacketList = [NSMutableArray array];
|
||
}
|
||
NSMutableArray *redPacketList = [NSMutableArray arrayWithArray:self.sideMenu.redPacketList];
|
||
[redPacketList insertObject:curData atIndex:0];
|
||
if(self.roomInfo.uid > 0 && curData.redEnvelopeNum.integerValue != redPacketList.count){
|
||
[self.presenter getRedPacket:[NSString stringWithFormat:@"%ld", self.roomInfo.uid]];
|
||
return;
|
||
}
|
||
curData.redEnvelopeId = attachment.data[@"redEnvelopeId"];
|
||
if(curData.validityType == 0){
|
||
XPReceiveRedPacketView *view = [[XPReceiveRedPacketView alloc] initWithFrame:CGRectMake(0, 0, KScreenWidth, KScreenHeight)];
|
||
view.delegate = self;
|
||
self.isShowRedPacket = YES;
|
||
view.receiveModel = curData;
|
||
for (UIView *subView in self.view.subviews) {
|
||
if([subView isKindOfClass:[XPReceiveRedPacketView class]]) {
|
||
view.alphaView.backgroundColor = [UIColor clearColor];
|
||
break;
|
||
}
|
||
}
|
||
[self.view addSubview:view];
|
||
[self.view bringSubviewToFront:view];
|
||
}
|
||
self.sideMenu.redPacketList = redPacketList;
|
||
}
|
||
break;
|
||
}
|
||
break;
|
||
|
||
case CustomMessageType_Free_Gift_Star_Reset_Time:
|
||
switch (attachment.second) {
|
||
case Custom_Message_Sub_Free_Gift_Star_Reset_Time:
|
||
[self.presenter getFreeGiftData];
|
||
[[NSNotificationCenter defaultCenter]postNotificationName:kFreeGiftCountdownNotification object:nil userInfo:@{@"isReset":@(YES)}];
|
||
break;
|
||
|
||
case Custom_Message_Sub_Update_Gift_Information:
|
||
[self.presenter getFreeGiftData];
|
||
[[NSNotificationCenter defaultCenter]postNotificationName:kFreeGiftCountdownNotification object:nil userInfo:@{@"updateGiftInfo":attachment.data ?: @""}];
|
||
break;
|
||
}
|
||
break;
|
||
|
||
case CustomMessageType_Custom_Room_Background:
|
||
switch (attachment.second) {
|
||
case Custom_Message_Sub_Custom_Room_Background:
|
||
if ([attachment.data isKindOfClass:[NSDictionary class]]) {
|
||
NSString *url = attachment.data[@"url"];
|
||
if (![NSString isEmpty:url]) {
|
||
self.roomInfo.backPic = url;//@"https://tva1.moyu.im/mw600/9f0b0dd5ly1hvacrep5fhj20jg0t60w4.jpg";
|
||
[self.backContainerView onRoomUpdate];
|
||
}
|
||
}
|
||
break;
|
||
}
|
||
break;
|
||
|
||
case CustomMessageType_RoomLevel_Update:
|
||
switch (attachment.second) {
|
||
case Custom_Message_Sub_RoomLevel_Update:
|
||
if ([attachment.data isKindOfClass:[NSDictionary class]]) {
|
||
NSString *url = attachment.data[@"roomLevelIcon"];
|
||
NSNumber *roomLevel = attachment.data[@"roomLevel"];
|
||
if (![NSString isEmpty:url] && roomLevel.integerValue > self.roomHeaderView.tag) {
|
||
self.roomHeaderView.tag = roomLevel.integerValue;
|
||
[self.roomHeaderView updateLevel:url];
|
||
self.roomInfo.roomLevelIcon = url;
|
||
}
|
||
}
|
||
break;
|
||
}
|
||
break;
|
||
|
||
case MicRelationship_Type:
|
||
switch (attachment.second) {
|
||
case MicRelationship_CP:
|
||
[self handleMicRelationshipCPMessage:attachment];
|
||
break;
|
||
}
|
||
break;
|
||
|
||
case CustomMessageType_CP:
|
||
switch (attachment.second) {
|
||
case Custom_Message_Sub_CP_Binding:
|
||
case Custom_Message_Sub_CP_Upgrade:
|
||
[self handleCPBindingOrUpgradeMessage:attachment];
|
||
break;
|
||
}
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
/// 处理CP绑定或升级消息
|
||
- (void)handleCPBindingOrUpgradeMessage:(AttachmentModel *)attachment {
|
||
NSLog(@"🔧 处理CP绑定或升级消息:first=%ld, second=%ld", (long)attachment.first, (long)attachment.second);
|
||
|
||
// 只有在完成进房初始化后才处理CP相关逻辑
|
||
if (!self.hasCompletedRoomInitialization) {
|
||
NSLog(@"🔧 进房初始化中,跳过CP绑定/升级处理");
|
||
return;
|
||
}
|
||
|
||
// 获取当前麦位队列
|
||
NSMutableDictionary<NSString *,MicroQueueModel *> *currentQueue = [self.stageView getMicroQueue];
|
||
if (!currentQueue) {
|
||
NSLog(@"⚠️ 无法获取当前麦位队列,跳过CP绑定/升级处理");
|
||
return;
|
||
}
|
||
|
||
// 使用 MicMidpointRectManager 处理CP绑定/升级消息
|
||
MicMidpointRectManager *manager = (MicMidpointRectManager *)[self.stageView performSelector:@selector(midpointRectManager)];
|
||
if (manager) {
|
||
// 计算麦位总数
|
||
NSInteger micCount = [self getMicCountForRoomType:self.roomInfo.type];
|
||
[manager handleCPBindingOrUpgradeMessageWithStageView:self.stageView
|
||
micCount:micCount
|
||
queue:currentQueue];
|
||
}
|
||
|
||
// 调用CP API更新状态
|
||
[self callMicCpListByUidListWithQueue:currentQueue];
|
||
|
||
NSLog(@"✅ CP绑定/升级消息处理完成");
|
||
}
|
||
|
||
/// 处理麦位变化相关的CP逻辑
|
||
- (void)handleMicChangeForCP:(NSMutableDictionary<NSString *,MicroQueueModel *> *)queue {
|
||
NSLog(@"🔧 处理麦位变化相关的CP逻辑");
|
||
|
||
// 更新当前用户的麦位状态
|
||
[self updateCurrentUserMicStatus:queue];
|
||
|
||
// 只有在完成进房初始化后才处理CP相关逻辑
|
||
if (self.hasCompletedRoomInitialization) {
|
||
// 使用 MicMidpointRectManager 处理CP逻辑
|
||
MicMidpointRectManager *manager = (MicMidpointRectManager *)[self.stageView performSelector:@selector(midpointRectManager)];
|
||
if (manager) {
|
||
// 计算麦位总数
|
||
NSInteger micCount = [self getMicCountForRoomType:self.roomInfo.type];
|
||
[manager handleMicChangeForCPWithStageView:self.stageView
|
||
micCount:micCount
|
||
queue:queue
|
||
currentUserUid:[AccountInfoStorage instance].getUid.integerValue
|
||
roomType:self.roomInfo.type];
|
||
}
|
||
|
||
// 调用CP API
|
||
[self callMicCpListByUidListWithQueue:queue];
|
||
|
||
// 🔧 新增:检查19 mic房间中央位置用户资格
|
||
[self checkCentralPositionUserQualification:queue];
|
||
} else {
|
||
NSLog(@"🔧 进房初始化中,跳过CP相关处理");
|
||
}
|
||
}
|
||
|
||
/// 处理麦位关系CP消息
|
||
- (void)handleMicRelationshipCPMessage:(AttachmentModel *)attachment {
|
||
NSLog(@"🔧 接收到麦位关系CP消息");
|
||
|
||
if (!attachment.data) {
|
||
NSLog(@"⚠️ 麦位关系CP消息:data格式错误,跳过处理");
|
||
return;
|
||
}
|
||
|
||
NSDictionary *jsonDic = (NSDictionary *)attachment.data;
|
||
NSString *jsonString = [jsonDic objectForKey:@"data"];
|
||
NSData *jsonData = [jsonString dataUsingEncoding:NSUTF8StringEncoding];
|
||
|
||
NSError *error = nil;
|
||
NSArray *dataArray = [NSJSONSerialization JSONObjectWithData:jsonData options:0 error:&error];
|
||
if (error) {
|
||
NSLog(@"❌ 麦位关系CP消息:JSON解析失败 - %@", error.localizedDescription);
|
||
return;
|
||
}
|
||
|
||
if (![dataArray isKindOfClass:[NSArray class]]) {
|
||
NSLog(@"⚠️ 麦位关系CP消息:消息格式错误,跳过处理");
|
||
return;
|
||
}
|
||
|
||
// 解析CP数据
|
||
NSMutableArray<MicCpInfoModel *> *cpList = [NSMutableArray array];
|
||
for (NSDictionary *cpDict in dataArray) {
|
||
if ([cpDict isKindOfClass:[NSDictionary class]]) {
|
||
MicCpInfoModel *cpInfo = [[MicCpInfoModel alloc] init];
|
||
cpInfo.uid = [cpDict[@"uid"] integerValue];
|
||
cpInfo.loverUid = [cpDict[@"loverUid"] integerValue];
|
||
cpInfo.cpLevel = [cpDict[@"cpLevel"] integerValue];
|
||
[cpList addObject:cpInfo];
|
||
}
|
||
}
|
||
|
||
NSLog(@"🔧 麦位关系CP消息:解析到 %lu 条CP数据", (unsigned long)cpList.count);
|
||
|
||
// 更新当前CP列表
|
||
self.currentCpList = cpList.copy;
|
||
|
||
// 使用 MicMidpointRectManager 处理麦位关系CP消息
|
||
MicMidpointRectManager *manager = (MicMidpointRectManager *)[self.stageView performSelector:@selector(midpointRectManager)];
|
||
if (manager) {
|
||
[manager handleMicRelationshipCPMessage:cpList];
|
||
}
|
||
|
||
// 刷新CP SVGA显示
|
||
[self drawSocialStageMidpointRects];
|
||
|
||
NSLog(@"🔧 麦位关系CP消息处理完成");
|
||
}
|
||
|
||
- (void)handleUpMicAsk:(AttachmentModel *)attachment {
|
||
NSNumber *targetUid = [attachment.data objectForKey:@"targetUid"];
|
||
if (!targetUid || ![targetUid.stringValue isEqualToString:[AccountInfoStorage instance].getUid]) {
|
||
return;
|
||
}
|
||
|
||
// 先清理之前的定时器(如果存在)
|
||
if (self.upMicAskTimer) {
|
||
[self.upMicAskTimer invalidate];
|
||
self.upMicAskTimer = nil;
|
||
}
|
||
|
||
TTAlertConfig *config = [[TTAlertConfig alloc] init];
|
||
config.title = YMLocalizedString(@"20.20.62_text_1");
|
||
config.message = YMLocalizedString(@"20.20.62_text_2");
|
||
config.actionStyle = TTAlertActionBothStyle;
|
||
|
||
// 自定义按钮
|
||
config.confirmButtonConfig.title = YMLocalizedString(@"MessageContentGuildView5");
|
||
config.cancelButtonConfig.title = YMLocalizedString(@"MessageContentGuildView4");
|
||
|
||
// 再觸發的話,clean 舊內容
|
||
[TTPopup dismiss];
|
||
[self removeUpMicAskTimer];
|
||
|
||
@kWeakify(self);
|
||
[TTPopup alertWithConfig:config
|
||
confirmHandler:^{
|
||
@kStrongify(self);
|
||
// 用户点击确认,清理定时器
|
||
[self removeUpMicAskTimer];
|
||
[self sendResponseUpMicMessage:attachment.data isAgree:YES];
|
||
} cancelHandler:^{
|
||
@kStrongify(self);
|
||
// 用户点击取消,清理定时器
|
||
[self removeUpMicAskTimer];
|
||
[self sendResponseUpMicMessage:attachment.data isAgree:NO];
|
||
}];
|
||
|
||
// 设置10秒后自动移除弹窗的定时器
|
||
self.upMicAskTimer = [NSTimer scheduledTimerWithTimeInterval:10.0
|
||
target:self
|
||
selector:@selector(autoDismissUpMicAskPopup)
|
||
userInfo:nil
|
||
repeats:NO];
|
||
}
|
||
|
||
- (void)removeUpMicAskTimer {
|
||
if (self.upMicAskTimer) {
|
||
[self.upMicAskTimer invalidate];
|
||
self.upMicAskTimer = nil;
|
||
}
|
||
}
|
||
|
||
/**
|
||
自动移除上麦请求弹窗
|
||
10秒后自动调用,移除弹窗并清理定时器
|
||
*/
|
||
- (void)autoDismissUpMicAskPopup {
|
||
// 移除弹窗
|
||
[TTPopup dismiss];
|
||
|
||
// 清理定时器
|
||
if (self.upMicAskTimer) {
|
||
[self.upMicAskTimer invalidate];
|
||
self.upMicAskTimer = nil;
|
||
}
|
||
|
||
NSLog(@"⏰ 上麦请求弹窗已自动移除(10秒超时)");
|
||
}
|
||
|
||
- (void)handleUpMicAgree:(AttachmentModel *)attachment {
|
||
NSDictionary *originalData = attachment.data;
|
||
NSNumber *position = [originalData objectForKey:@"position"];
|
||
NSNumber *targetUid = [originalData objectForKey:@"targetUid"];
|
||
|
||
if (!position || !targetUid) {
|
||
return;
|
||
}
|
||
NSNumber *sendTime = [originalData objectForKey:@"sendTime"];
|
||
if (!sendTime) {
|
||
return;
|
||
} else {
|
||
int64_t nowMillis = (int64_t)([[NSDate date] timeIntervalSince1970] * 1000);
|
||
if (nowMillis - sendTime.doubleValue > 10 * 1000) {
|
||
// 已经超过 10 秒
|
||
return;
|
||
}
|
||
}
|
||
|
||
NSMutableDictionary * dic = [NSMutableDictionary dictionary];
|
||
[dic setValue:position forKey:@"micPosition"];
|
||
[dic setValue:targetUid forKey:@"uid"];
|
||
AttachmentModel *attachement = [[AttachmentModel alloc]init];
|
||
attachement.first = CustomMessageType_Queue;
|
||
attachement.second = Custom_Message_Sub_Queue_Invite;
|
||
attachement.data = dic;
|
||
|
||
NIMMessage *message = [[NIMMessage alloc]init];
|
||
NIMCustomObject *object = [[NIMCustomObject alloc] init];
|
||
object.attachment = attachement;
|
||
message.messageObject = object;
|
||
//构造会话
|
||
NIMSession *session = [NIMSession session: @(self.roomInfo.roomId).stringValue
|
||
type:NIMSessionTypeChatroom];
|
||
[[NIMSDK sharedSDK].chatManager sendMessage:message toSession:session error:nil];
|
||
}
|
||
|
||
- (void)sendResponseUpMicMessage:(NSDictionary *)originalData isAgree:(BOOL)isAgree {
|
||
AttachmentModel *attachment = [[AttachmentModel alloc] init];
|
||
attachment.first = ClientMessage_Type;
|
||
attachment.second = isAgree ? ClientMessage_UpMic_Agree : ClientMessage_UpMic_Reject;
|
||
attachment.data = originalData;
|
||
|
||
NSString *sessionID = @(self.roomInfo.roomId).stringValue;
|
||
NIMMessage *message = [[NIMMessage alloc]init];
|
||
NIMCustomObject *object = [[NIMCustomObject alloc] init];
|
||
object.attachment = attachment;
|
||
message.messageObject = object;
|
||
|
||
NIMSessionType sessionType = NIMSessionTypeChatroom;
|
||
//构造会话
|
||
NIMSession *session = [NIMSession session:sessionID type:sessionType];
|
||
[[NIMSDK sharedSDK].chatManager sendMessage:message toSession:session completion:^(NSError * _Nullable error) {
|
||
BOOL onMain = [NSThread isMainThread];
|
||
if (error) {
|
||
NSLog(@"[[Send] ❌ 发送失败 | sessionId=%@ | code=%ld | desc=%@ | main=%@ | ts=%.3f",
|
||
sessionID, (long)error.code, error.localizedDescription, onMain ? @"YES" : @"NO", [[NSDate date] timeIntervalSince1970]);
|
||
} else {
|
||
NSLog(@"[Send] ✅ 发送成功 | sessionId=%@ | main=%@ | ts=%.3f",
|
||
sessionID, onMain ? @"YES" : @"NO", [[NSDate date] timeIntervalSince1970]);
|
||
}
|
||
}];
|
||
}
|
||
|
||
#pragma mark - NIMBroadcastDelegate
|
||
// 广播消息
|
||
- (void)onReceiveBroadcastMessage:(NIMBroadcastMessage *)broadcastMessage{
|
||
if (broadcastMessage.content) {
|
||
NSDictionary *msgDictionary = [broadcastMessage.content toJSONObject];
|
||
AttachmentModel *attachment = [AttachmentModel modelWithJSON:msgDictionary[@"body"]];
|
||
NSString *partitionId = [NSString stringWithFormat:@"%@",attachment.data[@"partitionId"]];
|
||
if(![partitionId isEqualToString:self.getUserInfo.partitionId]){
|
||
return;
|
||
}
|
||
BOOL isHave = NO;
|
||
if(attachment.first == CustomMessageType_Look_Love && attachment.second == Custom_Message_Sub_Look_Love_InRoom_NeedAllMicSend){
|
||
isHave = YES;
|
||
|
||
}else if(attachment.first == CustomMessageType_Super_Gift &&
|
||
(attachment.second == Custom_Message_Sub_Super_Gift || attachment.second == Custom_Message_Sub_Super_Gift_Room_Message)){
|
||
isHave = YES;
|
||
}else if(attachment.first == CustomMessageType_General_Public_Screen && attachment.second == Custom_Message_Sub_General_Public_Screen_All_Room){
|
||
isHave = YES;
|
||
}else if (attachment.first == CustomMessageType_Treasure_Fairy && (attachment.second == Custom_Message_Sub_Treasure_Fairy_Draw_Gift_L4 || attachment.second == Custom_Message_Sub_Treasure_Fairy_Draw_Gift_L5 || attachment.second == Custom_Message_Sub_Treasure_Fairy_Convert_L1 || attachment.second == Custom_Message_Sub_Treasure_Fairy_Convert_L2 || attachment.second == Custom_Message_Sub_Treasure_Fairy_Convert_L3)) { //夺宝精灵
|
||
isHave = YES;
|
||
}else if (attachment.first == CustomMessageType_Tarot && (attachment.second == Custom_Message_Sub_Tarot_Advanced || attachment.second == Custom_Message_Sub_Tarot_Intermediate)){
|
||
isHave = YES;
|
||
}else if(attachment.first == CustomMessageType_LuckyBag && attachment.second == Custom_Message_Sub_Room_Gift_LuckBag_FullScree){
|
||
isHave = YES;
|
||
}
|
||
if (attachment.first == CustomMessageType_RedPacket && attachment.second == Custom_Message_Sub_AllDiamandRedPacket) {
|
||
if(self.isShowRedPacket == YES)return;
|
||
XPRedPacketModel *data = [XPRedPacketModel modelWithDictionary:attachment.data];
|
||
data.validityType = 0;
|
||
data.kind = 1;
|
||
data.redEnvelopeId = attachment.data[@"redEnvelopeId"];
|
||
RoomInfoModel *roomInfo = self.roomInfo;
|
||
XPReceiveRedPacketView *view = [[XPReceiveRedPacketView alloc] initWithFrame:CGRectMake(0, 0, KScreenWidth, KScreenHeight)];
|
||
view.delegate = self;
|
||
self.isShowRedPacket = YES;
|
||
if (roomInfo.uid == data.roomUid.integerValue) {
|
||
view.inAllPacketRoom = YES;
|
||
} else {
|
||
view.inAllPacketRoom = NO;
|
||
}
|
||
view.receiveModel = data;
|
||
[self.view addSubview:view];
|
||
[self.view bringSubviewToFront:view];
|
||
}
|
||
|
||
if(isHave == NO)return;
|
||
attachment.isBroadcast = YES;
|
||
NIMMessage *message = [NIMMessage new];
|
||
NIMCustomObject *object = [NIMCustomObject new];
|
||
object.attachment = attachment;
|
||
message.messageObject = object;
|
||
|
||
[self.messageContainerView handleNIMTextMessage:message];
|
||
}
|
||
}
|
||
//发送消息成功回调
|
||
- (void)sendMessage:(NIMMessage *)message didCompleteWithError:(NSError *)error {
|
||
if (message.yidunAntiSpamRes) {
|
||
NSDictionary * spamRes = message.yidunAntiSpamRes.toJSONObject;
|
||
id spamResExt = ((NSString *)spamRes[@"ext"]).toJSONObject;
|
||
NSDictionary *antispamDic = nil;
|
||
if ([spamResExt isKindOfClass:[NSArray class]]) {
|
||
antispamDic = [spamResExt xpSafeObjectAtIndex:0];
|
||
} else if ([spamResExt isKindOfClass:[NSDictionary class]]) {
|
||
antispamDic = spamResExt[@"antispam"];
|
||
}
|
||
NSDictionary *realAntiDic = nil;
|
||
if ([[antispamDic allKeys] containsObject:@"antispam"]) {
|
||
realAntiDic = antispamDic[@"antispam"];;
|
||
} else {
|
||
realAntiDic = antispamDic;
|
||
}
|
||
if (realAntiDic) {
|
||
NSInteger suggestion = [realAntiDic[@"suggestion"] integerValue];
|
||
if (suggestion == 2) {
|
||
[self showErrorToast:YMLocalizedString(@"XPRoomViewController10")];
|
||
}
|
||
}
|
||
}
|
||
|
||
if (![message.session.sessionId isEqualToString:[NSString stringWithFormat:@"%ld", self.roomInfo.roomId]]) {
|
||
return;
|
||
}
|
||
|
||
if (error) {
|
||
NSLog(@"%@", error);
|
||
return;
|
||
};
|
||
if (message.messageType == NIMMessageTypeCustom) {
|
||
NIMCustomObject *obj = (NIMCustomObject *)message.messageObject;
|
||
if (obj.attachment != nil && [obj.attachment isKindOfClass:[AttachmentModel class]]) {
|
||
AttachmentModel * attachment = (AttachmentModel *)obj.attachment;
|
||
[self.stageView handleNIMCustomMessage:message];
|
||
[self.animationView handleNIMCustomMessage:message];
|
||
[self.functionView handleNIMCustomMessage:message];
|
||
if (attachment.first == CustomMessageType_Update_RoomInfo && attachment.second == Custom_Message_Sub_Update_RoomInfo_MessageState) {
|
||
NSDictionary * dic= attachment.data[@"roomInfo"];
|
||
if (dic.allKeys.count <=0) {
|
||
dic = attachment.data;
|
||
}
|
||
RoomInfoModel * roomInfo = [RoomInfoModel modelWithDictionary:dic];
|
||
self.roomInfo.isCloseScreen = roomInfo.isCloseScreen;
|
||
[self.menuContainerView onRoomUpdate];
|
||
}else if(attachment.first == CustomMessageType_Update_RoomInfo && attachment.second == Custom_Message_Sub_Update_RoomInfo_AnimateEffect){
|
||
NSDictionary * dic= attachment.data[@"roomInfo"];
|
||
if (dic.allKeys.count <= 0) {
|
||
dic = attachment.data;
|
||
}
|
||
RoomInfoModel * roomInfo = [RoomInfoModel modelWithDictionary:dic];
|
||
self.roomInfo.hasAnimationEffect = roomInfo.hasAnimationEffect;
|
||
}
|
||
[self.roomHeaderView onRoomUpdate];
|
||
[self.messageContainerView handleNIMCustomMessage:message];
|
||
}
|
||
}else if(message.messageType == NIMMessageTypeText) {
|
||
[self.messageContainerView handleNIMTextMessage:message];;
|
||
}
|
||
}
|
||
|
||
#pragma mark - NIMLoginManagerDelegate
|
||
- (void)onKickout:(NIMLoginKickoutResult *)result {
|
||
// [self exitRoom];
|
||
[self dismissViewControllerAnimated:YES completion:nil];
|
||
}
|
||
|
||
|
||
#pragma mark - NIMConversationManagerDelegate
|
||
- (void)didAddRecentSession:(NIMRecentSession *)recentSession
|
||
totalUnreadCount:(NSInteger)totalUnreadCount {
|
||
[self.menuContainerView addNIMRecentSession:recentSession];
|
||
}
|
||
|
||
- (void)didUpdateRecentSession:(NIMRecentSession *)recentSession
|
||
totalUnreadCount:(NSInteger)totalUnreadCount {
|
||
[self.menuContainerView addNIMRecentSession:recentSession];
|
||
}
|
||
|
||
- (void)didRemoveRecentSession:(NIMRecentSession *)recentSession
|
||
totalUnreadCount:(NSInteger)totalUnreadCount {
|
||
[self.menuContainerView removeNIMRecentSession:recentSession];
|
||
}
|
||
|
||
#pragma mark - RoomDelegate
|
||
- (RoomInfoModel *)getRoomInfo {
|
||
return self.roomInfo;
|
||
}
|
||
|
||
- (UserInfoModel *)getUserInfo {
|
||
return self.userInfo;
|
||
}
|
||
|
||
- (BOOL)isManagerOrOwner {
|
||
return self.roomUid.integerValue == self.userInfo.uid ||
|
||
[self.superMangerList filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"uid == %d", self.userInfo.uid]] > 0;
|
||
}
|
||
|
||
-(NSMutableArray *)getPlayList{
|
||
return self.sideMenu.playList;
|
||
}
|
||
|
||
-(NSMutableArray *)getLittleGameList {
|
||
return self.sideMenu.littleGameList;
|
||
}
|
||
|
||
- (void)exitRoom {
|
||
[XNDJTDDLoadingTool showLoading];
|
||
|
||
// 🔧 防护:标记正在退出房间
|
||
self.isExitingRoom = YES;
|
||
|
||
[XPSkillCardPlayerManager shareInstance].micState = MICState_None;
|
||
|
||
[self.stageView exitNIMRoom];
|
||
[self.menuContainerView menuResignFirstResponder];
|
||
|
||
[self.animationView resumeTimer];
|
||
|
||
switch (self.roomInfo.roomModeType) {
|
||
case RoomModeType_Open_Micro_Mode:
|
||
case RoomModeType_Open_Blind:
|
||
[self exitRoomAndCancelArrangeMic];
|
||
break;
|
||
case RoomModeType_Open_PK_Mode:
|
||
[self exitRoomWhenPKing];
|
||
break;
|
||
case RoomType_MiniGame:
|
||
[self exitRoomWhenPlayMiniGame];
|
||
break;
|
||
default:
|
||
[self exitRoomPage];
|
||
break;
|
||
}
|
||
}
|
||
|
||
- (BOOL)isSameRoom:(NSString *)targetUid {
|
||
return [self.roomUid isEqualToString:targetUid];
|
||
}
|
||
|
||
- (void)exitRoomAndCancelArrangeMic {
|
||
NSString * roomUid = [NSString stringWithFormat:@"%ld", self.roomInfo.uid];
|
||
NSString * uid = [AccountInfoStorage instance].getUid;
|
||
[Api getRoomArrangeMicList:^(BaseModel * _Nullable data, NSInteger code, NSString * _Nullable msg) {
|
||
if (code == 200) {
|
||
ArrangeMicModel * arrangeMicModel= [ArrangeMicModel modelWithJSON:data.data];
|
||
if (arrangeMicModel.myPos.intValue > 0) {
|
||
[TTPopup alertWithMessage:YMLocalizedString(@"XPRoomViewController11") confirmHandler:^{
|
||
__block NSString * grouptype = @"0";
|
||
if (self.roomInfo.roomModeType == RoomModeType_Open_Blind) {
|
||
[arrangeMicModel.queue enumerateObjectsUsingBlock:^(ArrangeMicUserModel * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
|
||
if (obj.uid.integerValue == [AccountInfoStorage instance].getUid.integerValue) {
|
||
grouptype = [NSString stringWithFormat:@"%ld", obj.groupType];
|
||
*stop = YES;
|
||
}
|
||
}];
|
||
}
|
||
[Api cancelArrangeMic:^(BaseModel * _Nullable data, NSInteger code, NSString * _Nullable msg) {
|
||
|
||
} roomUid:roomUid operUid:uid groupType:grouptype];
|
||
|
||
[self exitRoomPage];
|
||
} cancelHandler:^{
|
||
|
||
}];
|
||
return;
|
||
}
|
||
}
|
||
|
||
[self exitRoomPage];
|
||
} roomUid:roomUid operUid:uid page:@"1" pageSize:@"50"];
|
||
}
|
||
|
||
- (void)exitRoomWhenPKing {
|
||
NSString * roomUid = [NSString stringWithFormat:@"%ld", self.roomInfo.uid];
|
||
NSString * uid = [AccountInfoStorage instance].getUid;
|
||
[Api getRoomPKUserList:^(BaseModel * _Nullable data, NSInteger code, NSString * _Nullable msg) {
|
||
if (code == 200) {
|
||
ArrangeMicModel * arrangeMicModel= [ArrangeMicModel modelWithJSON:data.data];
|
||
if (arrangeMicModel.myPos.intValue > 0) {
|
||
[TTPopup alertWithMessage:YMLocalizedString(@"XPRoomViewController11") confirmHandler:^{
|
||
__block NSString * grouptype = @"0";
|
||
[arrangeMicModel.queue enumerateObjectsUsingBlock:^(ArrangeMicUserModel * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
|
||
if (obj.uid.integerValue == [AccountInfoStorage instance].getUid.integerValue) {
|
||
grouptype = [NSString stringWithFormat:@"%ld", obj.groupType];
|
||
*stop = YES;
|
||
}
|
||
}];
|
||
[Api cancelRoomPKArrangeMic:^(BaseModel * _Nullable data, NSInteger code, NSString * _Nullable msg) {
|
||
|
||
} roomUid:roomUid operUid:uid groupType:grouptype];
|
||
|
||
[self exitRoomPage];
|
||
} cancelHandler:^{
|
||
|
||
}];
|
||
return;
|
||
}
|
||
}
|
||
|
||
[self exitRoomPage];
|
||
|
||
} roomUid:roomUid operUid:uid page:@"1" pageSize:@"50"];
|
||
}
|
||
|
||
- (void)exitRoomWhenPlayMiniGame {
|
||
if ([self.littleGameView isInSudGame]) {
|
||
TTAlertConfig *config = [[TTAlertConfig alloc] init];
|
||
config.cancelButtonConfig.title = YMLocalizedString(@"XPRoomSettingInputView4");
|
||
config.confirmButtonConfig.title = YMLocalizedString(@"TTAlertConfig0");
|
||
config.message = YMLocalizedString(@"XPRoomViewController14");
|
||
@kWeakify(self);
|
||
[TTPopup alertWithConfig:config confirmHandler:^{ // 知道了
|
||
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
|
||
@kStrongify(self);
|
||
[self exitRoomPage];
|
||
});
|
||
} cancelHandler:^{
|
||
}];
|
||
} else {
|
||
[self exitRoomPage];
|
||
}
|
||
}
|
||
|
||
- (void)exitRoomPage {
|
||
if (self.roomInfo.type == RoomType_MiniGame) {
|
||
[self.littleGameView handleSelfInExitEvent];
|
||
[self.littleGameView destroyMG];
|
||
}
|
||
[[XPRoomMiniManager shareManager] resetLocalMessage];
|
||
|
||
// 🔧 防护:确保 TRTC 退出
|
||
[[RtcManager instance] exitRoom];
|
||
|
||
// 🔧 防护:标记房间已退出
|
||
self.isExitingRoom = YES;
|
||
self.isViewActive = NO;
|
||
|
||
[self.presenter exitNIMRoom:[NSString stringWithFormat:@"%ld", self.roomInfo.roomId]];
|
||
[self.presenter reportUserOutRoom:[NSString stringWithFormat:@"%ld", self.roomInfo.uid]];
|
||
[self handleFirstOutRoom];
|
||
[self dismissViewControllerAnimated:YES completion:^{
|
||
[XNDJTDDLoadingTool hideHUD];
|
||
}];
|
||
}
|
||
|
||
- (void)miniRoom {
|
||
if(self.freeModel != nil){
|
||
[XPRoomMiniManager shareManager].curState = self.freeModel.curStage;
|
||
}
|
||
|
||
[self.menuContainerView menuResignFirstResponder];
|
||
|
||
NSDictionary *roomInfoDic = self.roomInfo.model2dictionary != nil ? self.roomInfo.model2dictionary : @{};
|
||
NSDictionary *userInfoDic = self.userInfo.model2dictionary != nil ? self.userInfo.model2dictionary : @{};
|
||
NSMutableDictionary *queueDic = self.getMicroQueue != nil ? self.getMicroQueue : [@{} mutableCopy];
|
||
if(self.roomInfo.type == RoomType_MiniGame) {
|
||
if ([self.littleGameView isInSudGame]) {
|
||
TTAlertConfig *config = [[TTAlertConfig alloc] init];
|
||
config.cancelButtonConfig.title = YMLocalizedString(@"XPRoomViewController15");
|
||
config.confirmButtonConfig.title = YMLocalizedString(@"XPRoomViewController16");
|
||
config.message = YMLocalizedString(@"XPRoomViewController17");
|
||
@kWeakify(self);
|
||
[TTPopup alertWithConfig:config confirmHandler:^{ // 知道了
|
||
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
|
||
@kStrongify(self);
|
||
[[XPRoomMiniManager shareManager] configRoomInfo:self.roomInfo];
|
||
[[XPRoomMiniManager shareManager] configUserInfo:self.userInfo];
|
||
[[XPRoomMiniManager shareManager] configCurrentMusic:self.functionView.getCurrentMusic isPlaying:self.functionView.isPlaying];
|
||
NSDictionary * dic = @{@"roomInfo":roomInfoDic, @"userInfo":userInfoDic, @"microQueue":queueDic};
|
||
[[NSNotificationCenter defaultCenter] postNotificationName:kRoomMiniNotificationKey object:nil userInfo:dic];
|
||
[self.view endEditing:YES];
|
||
[self.littleGameView handleSelfInExitEvent];
|
||
[self.littleGameView destroyMG];
|
||
[self handleFirstOutRoom];
|
||
[self dismissViewControllerAnimated:YES completion:nil];
|
||
});
|
||
} cancelHandler:^{
|
||
}];
|
||
} else {
|
||
[[XPRoomMiniManager shareManager] configRoomInfo:self.roomInfo];
|
||
[[XPRoomMiniManager shareManager] configUserInfo:self.userInfo];
|
||
[[XPRoomMiniManager shareManager] configCurrentMusic:self.functionView.getCurrentMusic isPlaying:self.functionView.isPlaying];
|
||
NSDictionary * dic = @{@"roomInfo":roomInfoDic, @"userInfo":userInfoDic, @"microQueue":queueDic};
|
||
[[NSNotificationCenter defaultCenter] postNotificationName:kRoomMiniNotificationKey object:nil userInfo:dic];
|
||
[self.view endEditing:YES];
|
||
[self.littleGameView handleSelfInExitEvent];
|
||
[self.littleGameView destroyMG];
|
||
[self handleFirstOutRoom];
|
||
[self dismissViewControllerAnimated:YES completion:nil];
|
||
}
|
||
}else {
|
||
[[XPRoomMiniManager shareManager] configRoomInfo:self.roomInfo];
|
||
[[XPRoomMiniManager shareManager] configUserInfo:self.userInfo];
|
||
[[XPRoomMiniManager shareManager] configCurrentMusic:self.functionView.getCurrentMusic isPlaying:self.functionView.isPlaying];
|
||
NSDictionary * dic = @{@"roomInfo":roomInfoDic, @"userInfo":userInfoDic, @"microQueue":queueDic};
|
||
[[NSNotificationCenter defaultCenter] postNotificationName:kRoomMiniNotificationKey object:nil userInfo:dic];
|
||
[self.view endEditing:YES];
|
||
[self handleFirstOutRoom];
|
||
[self dismissViewControllerAnimated:YES completion:nil];
|
||
}
|
||
}
|
||
|
||
- (void)showPKPanel {
|
||
[self.functionView showPKPanelView];
|
||
}
|
||
|
||
- (UINavigationController *)getCurrentNav {
|
||
return self.navigationController;
|
||
}
|
||
-(UIView *)getSuperView{
|
||
return self.view;
|
||
}
|
||
- (NSMutableDictionary<NSString *,MicroQueueModel *> *)getMicroQueue {
|
||
return [self.stageView getMicroQueue];
|
||
}
|
||
|
||
- (NSArray *)getRoomSuperAdminList {
|
||
return self.superMangerList;
|
||
}
|
||
|
||
- (NSArray *)getRoomPKGroupTeamList {
|
||
return [self.functionView getRoomPKGroupTeamList];
|
||
}
|
||
|
||
- (BOOL)isRoomPKPlaying {
|
||
return [self.functionView isRoomPKPlaying];
|
||
}
|
||
|
||
- (void)onMicroQueueUpdate:(NSMutableDictionary<NSString *,MicroQueueModel *> *)queue {
|
||
[self.menuContainerView onMicroQueueUpdate:queue];
|
||
[self.functionView onRoomUpdate];
|
||
[self.functionView onMicroQueueUpdate:queue];
|
||
|
||
// 获取当前用户麦位状态
|
||
NSDictionary *currentStatus = [self getCurrentUserMicStatus:queue];
|
||
BOOL isOnMic = [currentStatus[@"isOnMic"] boolValue];
|
||
|
||
if (isOnMic) {
|
||
self.anchorScrollView.scrollEnabled = NO;
|
||
} else {
|
||
self.anchorScrollView.scrollEnabled = YES;
|
||
}
|
||
|
||
// 🔧 注意:CP相关的处理逻辑已迁移到 NIMChatroomEventTypeQueueChange 中
|
||
// 这里只处理UI相关的更新,不再处理CP逻辑
|
||
}
|
||
|
||
- (CGPoint)animationPointAtStageViewByUid:(NSString *)uid {
|
||
return [self.stageView animationPointAtStageViewByUid:uid];
|
||
}
|
||
|
||
- (CGPoint)animationPointAtStageViewByIndex:(NSInteger)index {
|
||
return [self.stageView animationPointAtStageViewByIndex:index];
|
||
}
|
||
|
||
- (void)getRoomBoomInfoSuccess:(NSArray <BoomDetailModel*> *)models {
|
||
[[RoomBoomManager sharedManager] updateBoomDetailArray:models];
|
||
[self.sideMenu updateForBoomDetailArray:models];
|
||
}
|
||
|
||
- (void)getRoomBoomExplosionSuccess:(BoomInfoModel *)model {
|
||
[[RoomBoomManager sharedManager] receiveEnterRoomBoom:model];
|
||
}
|
||
|
||
/// 统一的CP API成功回调方法
|
||
- (void)handleMicCpListSuccess:(NSArray<MicCpInfoModel *> *)cpList {
|
||
NSLog(@"🔧 CP API成功回调:接收到 %lu 条CP数据", (unsigned long)cpList.count);
|
||
|
||
self.currentCpList = cpList;
|
||
|
||
// 使用 MicMidpointRectManager 更新CP列表缓存并重绘
|
||
MicMidpointRectManager *manager = (MicMidpointRectManager *)[self.stageView performSelector:@selector(midpointRectManager)];
|
||
if (manager) {
|
||
// 计算麦位总数
|
||
NSInteger micCount = [self getMicCountForRoomType:self.roomInfo.type];
|
||
[manager updateCpListCacheAndRedraw:cpList
|
||
stageView:self.stageView
|
||
micCount:micCount
|
||
roomType:self.roomInfo.type];
|
||
}
|
||
|
||
// 如果当前用户麦位状态发生变化(上麦、下麦、换位),发送 NIM message
|
||
if (self.currentUserMicStatusChanged) {
|
||
[self sendMicRelationshipNIMessage:cpList];
|
||
self.currentUserMicStatusChanged = NO; // 重置标志
|
||
}
|
||
|
||
NSLog(@"🔧 CP API成功回调:处理完成");
|
||
}
|
||
|
||
/// 按房间UID获取CP列表成功回调
|
||
- (void)getMicCpListByRoomUidSuccess:(NSArray <MicCpInfoModel *> *)cpList {
|
||
NSLog(@"🔧 按房间UID获取CP列表成功:接收到 %lu 条CP数据", (unsigned long)cpList.count);
|
||
[self handleMicCpListSuccess:cpList];
|
||
}
|
||
|
||
/// 按用户UID列表获取CP列表成功回调
|
||
- (void)getMicCpListByUidListSuccess:(NSArray<MicCpInfoModel *> *)cpList {
|
||
NSLog(@"🔧 按用户UID列表获取CP列表成功:接收到 %lu 条CP数据", (unsigned long)cpList.count);
|
||
[self handleMicCpListSuccess:cpList];
|
||
}
|
||
|
||
#pragma mark - 首次退出非自己的房间,处理是否需要弹新用户充值优惠
|
||
- (void)handleFirstOutRoom {
|
||
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
|
||
if (![defaults boolForKey:kHadQuitOtherRoomKey] && self.userInfo.uid != self.roomInfo.uid && self.userInfo.showLimitCharge) {
|
||
[defaults setBool:YES forKey:kHadQuitOtherRoomKey];
|
||
[defaults synchronize];
|
||
[[NSNotificationCenter defaultCenter] postNotificationName:kNewUserRechargeKey object:nil];
|
||
}
|
||
}
|
||
#pragma mark - XPRoomLittleGameContainerViewDelegate
|
||
- (void)hiddenSudGamePostionView {
|
||
[self.functionView hiddenSudGamePostionView];
|
||
}
|
||
|
||
#pragma mark - AnchorRoomScrollViewDelegate
|
||
- (void)anchorScrollViewScrollToNext:(AnchorRoomScrollView *)anchorScrollView {
|
||
if (!self) {
|
||
return;
|
||
}
|
||
[self.view endEditing:YES];
|
||
[self showAnchorLoading];
|
||
[self.presenter getCycleAnchorRoomList:[NSString stringWithFormat:@"%ld", self.roomInfo.uid]];
|
||
}
|
||
|
||
|
||
- (void)anchorScrollViewScrollToPrevious:(AnchorRoomScrollView *)anchorScrollView {
|
||
if (!self || self.anchorRoomList.count <= 0) {
|
||
return;
|
||
}
|
||
[self.view endEditing:YES];
|
||
[self showAnchorLoading];
|
||
if (self.anchorIndex < self.anchorRoomList.count) {
|
||
NSString * roomUid = [self.anchorRoomList xpSafeObjectAtIndex:self.anchorIndex];
|
||
[self.presenter getCurrentRoomInfo:roomUid];
|
||
self.anchorIndex --;
|
||
}else {
|
||
[self showErrorToast:YMLocalizedString(@"XPRoomViewController13")];
|
||
self.anchorScrollView.contentOffset = CGPointMake(0, KScreenHeight);
|
||
}
|
||
}
|
||
|
||
#pragma mark - XPRoomSettingInputViewDelegate
|
||
///点击了完成
|
||
- (void)xPRoomSettingInputView:(XPRoomSettingInputView *)view didClickConfirm:(NSString *)text type:(RoomSettingInputType)type {
|
||
NSString *pwdDes = [DESEncrypt encryptUseDES:text key:KeyWithType(KeyType_PasswordEncode)];
|
||
if ([pwdDes isEqualToString:self.roomInfo.roomPwd]) {
|
||
[TTPopup dismiss];
|
||
view.isPwdError = NO;
|
||
if (self.roomInfo.type == RoomType_Anchor) {
|
||
[self __removeAllViews];
|
||
if (!self.anchorScrollView.superview) {
|
||
[self.view insertSubview:self.anchorScrollView belowSubview:self.menuContainerView];
|
||
}
|
||
|
||
[self.anchorScrollView addSubview:self.backContainerView];
|
||
[self.anchorScrollView addSubview:self.stageView];
|
||
[self.anchorScrollView addSubview:self.messageContainerView];
|
||
[self.anchorScrollView addSubview:self.quickMessageContainerView];
|
||
[self.anchorScrollView addSubview:self.sideMenu];
|
||
[self.anchorScrollView addSubview:self.roomHeaderView];
|
||
if (!self.menuContainerView.superview) {
|
||
[self.view addSubview:self.menuContainerView];
|
||
}
|
||
[self.anchorScrollView addSubview:self.functionView];
|
||
|
||
[self.view bringSubviewToFront:self.animationView];
|
||
|
||
[self updateViewConstraintsOnAnchorRoom];
|
||
[self changeStageViewOnAnchorRoom];
|
||
|
||
[self.roomHeaderView onRoomEntered];
|
||
[self.sideMenu onRoomEntered];
|
||
|
||
|
||
[self.backContainerView onRoomEntered];
|
||
[self.littleGameView onRoomEntered];
|
||
[self.littleGameView onRoomEntered];
|
||
if ([XPRoomMiniManager shareManager].getRoomInfo.uid != self.roomUid.integerValue) {// 最小化进房 还是原来的房间的话 不需要重新进入云信 因为压根没退
|
||
// 🔧 防护:检查是否允许进房
|
||
if (!self.isExitingRoom && self.isViewActive) {
|
||
[self.presenter enterNIMRoom:[NSString stringWithFormat:@"%ld", self.roomInfo.roomId] user:self.userInfo];
|
||
}
|
||
[self.functionView onRoomEntered];
|
||
[self.messageContainerView onRoomEntered];
|
||
[self.menuContainerView onRoomEntered];
|
||
} else {
|
||
//虽然没退出房间 但是队列还是要拿的
|
||
[self.stageView onRoomMiniEntered];
|
||
[self.messageContainerView onRoomMiniEntered];
|
||
[self.functionView onRoomMiniEntered];
|
||
[self.functionView onRoomEntered];
|
||
[self.menuContainerView onRoomMiniEntered];
|
||
|
||
// 🔧 最小化进房:初始化当前用户麦位状态
|
||
[self initializeCurrentUserMicStatusForMiniEnter];
|
||
}
|
||
[[XPRoomMiniManager shareManager] configRoomInfo:nil];
|
||
[[XPRoomMiniManager shareManager] configUserInfo:nil];
|
||
[[XPRoomMiniManager shareManager] configCurrentMusic:nil isPlaying:NO];
|
||
} else {
|
||
[self.roomHeaderView onRoomEntered];
|
||
[self.sideMenu onRoomEntered];
|
||
|
||
[self.menuContainerView onRoomEntered];
|
||
[self changeStageViewOnRoomUpdate];
|
||
[self.backContainerView onRoomEntered];
|
||
[self.littleGameView onRoomEntered];
|
||
[self.functionView onRoomEntered];
|
||
// 🔧 防护:检查是否允许进房
|
||
if (!self.isExitingRoom && self.isViewActive) {
|
||
[self.presenter enterNIMRoom:[NSString stringWithFormat:@"%ld", self.roomInfo.roomId] user:self.userInfo];
|
||
}
|
||
[self.messageContainerView onRoomEntered];
|
||
[self.littleGameView onRoomEntered];
|
||
[[XPRoomMiniManager shareManager] configRoomInfo:nil];
|
||
[[XPRoomMiniManager shareManager] configUserInfo:nil];
|
||
[[XPRoomMiniManager shareManager] configCurrentMusic:nil isPlaying:NO];
|
||
}
|
||
} else {
|
||
view.isPwdError = YES;
|
||
}
|
||
}
|
||
|
||
- (void)didClickCancel:(RoomSettingInputType)type {
|
||
if (type == RoomSettingInputType_Input_Pwd) {
|
||
[self enterRoomFail:0];
|
||
}
|
||
}
|
||
-(NSInteger)getPublicScreenType{
|
||
return self.messageContainerView.type;
|
||
}
|
||
|
||
- (void)displayMusicPanel {
|
||
[self.functionView showMusicPanel];
|
||
}
|
||
|
||
- (void)updateScreenMessageState:(BOOL)isClose {
|
||
self.roomInfo.isCloseScreen = isClose;
|
||
}
|
||
|
||
#pragma mark - XPFirstRechargeViewDelegate
|
||
-(void)rechargeHandle{}
|
||
-(void)contactCustomerService{
|
||
TTAlertConfig *config = [[TTAlertConfig alloc]init];
|
||
config.title = YMLocalizedString(@"XPIAPRechargeViewController7");
|
||
config.message = YMLocalizedString(@"XPIAPRechargeViewController8");
|
||
TTAlertButtonConfig *confirmButtonConfig = [[TTAlertButtonConfig alloc]init];
|
||
confirmButtonConfig.title = YMLocalizedString(@"XPIAPRechargeViewController9");
|
||
UIImage *image = [UIImage gradientColorImageFromColors:@[UIColorFromRGB(0x13E2F5),UIColorFromRGB(0x9DB4FF),UIColorFromRGB(0xCC67FF)] gradientType:GradientTypeLeftToRight imgSize:CGSizeMake(200, 200)];
|
||
confirmButtonConfig.backgroundColor = [UIColor colorWithPatternImage:image];
|
||
confirmButtonConfig.cornerRadius = 38/2;
|
||
config.confirmButtonConfig = confirmButtonConfig;
|
||
@kWeakify(self);
|
||
[TTPopup alertWithConfig:config confirmHandler:^{
|
||
@kStrongify(self);
|
||
[self requestContactCustomerService];
|
||
} cancelHandler:^{
|
||
}];
|
||
|
||
}
|
||
-(void)requestContactCustomerService{
|
||
[XNDJTDDLoadingTool showLoading];
|
||
[Api requestContactCustomerServiceCompletion:^(BaseModel * _Nullable data, NSInteger code, NSString * _Nullable msg) {
|
||
[XNDJTDDLoadingTool hideHUD];
|
||
if(code == 200){
|
||
NSString *uid = [NSString stringWithFormat:@"%@",data.data];
|
||
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
|
||
NIMSession * session = [NIMSession session:uid type:NIMSessionTypeP2P];
|
||
SessionViewController * sessionVC = [[SessionViewController alloc] initWithSession:session];
|
||
[self.getCurrentNav pushViewController:sessionVC animated:YES];
|
||
});
|
||
}
|
||
}];
|
||
}
|
||
- (XPRoomBackContainerView *)backContainerView {
|
||
if (!_backContainerView) {
|
||
_backContainerView = [[XPRoomBackContainerView alloc] initWithdelegate:self];
|
||
}
|
||
return _backContainerView;
|
||
}
|
||
|
||
- (RoomHeaderView *)roomHeaderView {
|
||
if (!_roomHeaderView) {
|
||
_roomHeaderView = [[RoomHeaderView alloc] initWithDelegate:self];
|
||
}
|
||
return _roomHeaderView;
|
||
}
|
||
|
||
- (MsRoomMessageMainView *)messageContainerView {
|
||
if (!_messageContainerView) {
|
||
_messageContainerView = [[MsRoomMessageMainView alloc] initWithDelegate:self];
|
||
}
|
||
return _messageContainerView;
|
||
}
|
||
|
||
- (XPRoomQuickMessageContainView *)quickMessageContainerView {
|
||
if(!_quickMessageContainerView) {
|
||
_quickMessageContainerView = [[XPRoomQuickMessageContainView alloc] initWithDelegate:self];
|
||
}
|
||
return _quickMessageContainerView;
|
||
}
|
||
|
||
- (XPRoomMenuContainerView *)menuContainerView {
|
||
if (!_menuContainerView) {
|
||
_menuContainerView = [[XPRoomMenuContainerView alloc] initWithDelegate:self];
|
||
@kWeakify(self);
|
||
[_menuContainerView setUpdateHeight:^(CGFloat height) {
|
||
@kStrongify(self);
|
||
[self.menuContainerView mas_remakeConstraints:^(MASConstraintMaker *make) {
|
||
make.leading.trailing.mas_equalTo(self.view);
|
||
if (iPhoneXSeries) {
|
||
make.bottom.mas_equalTo(self.view);
|
||
} else {
|
||
make.bottom.mas_equalTo(self.view).offset(-10);
|
||
}
|
||
make.height.mas_equalTo(height + kSafeAreaBottomHeight);
|
||
}];
|
||
}];
|
||
}
|
||
return _menuContainerView;
|
||
}
|
||
|
||
- (RoomSideMenu *)sideMenu {
|
||
if (!_sideMenu) {
|
||
_sideMenu = [[RoomSideMenu alloc] initWithDelegate:self];
|
||
}
|
||
return _sideMenu;
|
||
}
|
||
|
||
- (RoomAnimationView *)animationView {
|
||
if (!_animationView) {
|
||
_animationView = [[RoomAnimationView alloc] initWithHostDelegate:self];
|
||
}
|
||
return _animationView;
|
||
}
|
||
|
||
- (XPRoomFunctionContainerView *)functionView {
|
||
if (!_functionView) {
|
||
_functionView = [[XPRoomFunctionContainerView alloc] initWithDelegate:self];
|
||
}
|
||
return _functionView;
|
||
}
|
||
|
||
- (StageView *)stageView {
|
||
// 🔧 修改:如果 StageViewManager 已初始化,返回其管理的 stageView
|
||
if (self.stageViewManager && self.stageViewManager.currentStageView) {
|
||
return self.stageViewManager.currentStageView;
|
||
}
|
||
|
||
// 🔧 降级:只有在 StageViewManager 不可用时才创建默认的 SocialStageView
|
||
if (!_stageView) {
|
||
_stageView = [[SocialStageView alloc] initWithDelegate:self];
|
||
_stageView.alpha = 0;
|
||
NSLog(@"⚠️ 使用降级 stageView: SocialStageView");
|
||
}
|
||
return _stageView;
|
||
}
|
||
|
||
- (TenMicStageView *)tenMicStageView {
|
||
if (!_tenMicStageView) {
|
||
_tenMicStageView = [[TenMicStageView alloc] initWithDelegate:self];
|
||
}
|
||
return _tenMicStageView;
|
||
}
|
||
|
||
- (NineteenMicStageView *)nineteenMicStageView {
|
||
if (!_nineteenMicStageView) {
|
||
_nineteenMicStageView = [[NineteenMicStageView alloc] initWithDelegate:self];
|
||
}
|
||
return _nineteenMicStageView;
|
||
}
|
||
|
||
- (TwentyMicStageView *)twentyMicStageView {
|
||
if (!_twentyMicStageView) {
|
||
_twentyMicStageView = [[TwentyMicStageView alloc] initWithDelegate:self];
|
||
}
|
||
return _twentyMicStageView;
|
||
}
|
||
|
||
- (FifteenMicStageView *)fifteenMicStageView {
|
||
if (!_fifteenMicStageView) {
|
||
_fifteenMicStageView = [[FifteenMicStageView alloc] initWithDelegate:self];
|
||
}
|
||
return _fifteenMicStageView;
|
||
}
|
||
|
||
- (XPRoomLittleGameContainerView *)littleGameView {
|
||
if (!_littleGameView) {
|
||
_littleGameView = [[XPRoomLittleGameContainerView alloc] initWithDelegate:self];
|
||
_littleGameView.delegate = self;
|
||
}
|
||
return _littleGameView;
|
||
}
|
||
- (AnchorRoomScrollView *)anchorScrollView {
|
||
if (!_anchorScrollView) {
|
||
_anchorScrollView = [[AnchorRoomScrollView alloc] initWithFrame:CGRectMake(0, 0, KScreenWidth, KScreenHeight)];
|
||
_anchorScrollView.anchorScrollDelegate = self;
|
||
_anchorScrollView.hostDelegate = self;
|
||
if (@available(iOS 11.0, *)) {
|
||
_anchorScrollView.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever;
|
||
}
|
||
}
|
||
return _anchorScrollView;
|
||
}
|
||
|
||
- (AnchorRoomSrollTipView *)anchorScrollTipView {
|
||
if (!_anchorScrollTipView) {
|
||
_anchorScrollTipView = [[AnchorRoomSrollTipView alloc] initWithFrame:CGRectMake(0, 0, KScreenWidth, KScreenHeight)];
|
||
}
|
||
return _anchorScrollTipView;
|
||
}
|
||
|
||
- (NSMutableArray<NSString *> *)anchorRoomList {
|
||
if (!_anchorRoomList) {
|
||
_anchorRoomList = [NSMutableArray array];
|
||
}
|
||
return _anchorRoomList;
|
||
}
|
||
|
||
-(XPFreeGiftsObtainView *)freeView{
|
||
if (!_freeView){
|
||
_freeView = [[XPFreeGiftsObtainView alloc]initWithFrame:CGRectMake(0, 0, KScreenWidth, KScreenHeight)];
|
||
}
|
||
return _freeView;
|
||
}
|
||
- (PIRoomEnterRedPacketView *)redPacketView{
|
||
if(!_redPacketView){
|
||
_redPacketView = [[PIRoomEnterRedPacketView alloc]initWithFrame:CGRectZero];
|
||
_redPacketView.hidden = YES;
|
||
_redPacketView.isInRoom = YES;
|
||
_redPacketView.delegate = self;
|
||
|
||
}
|
||
return _redPacketView;
|
||
}
|
||
|
||
#pragma mark - 公共房间消息转发处理
|
||
|
||
- (void)handlePublicRoomMessageForward:(NSNotification *)notification {
|
||
NIMMessage *message = notification.object;
|
||
if (![message isKindOfClass:[NIMMessage class]]) {
|
||
NSLog(@"XPRoomViewController: 收到无效的公共房间转发消息");
|
||
return;
|
||
}
|
||
|
||
// 检查房间是否处于活跃状态
|
||
if (!self.roomInfo || !self.messageContainerView) {
|
||
NSLog(@"XPRoomViewController: 房间未就绪,忽略公共房间转发消息");
|
||
return;
|
||
}
|
||
|
||
switch (message.messageType) {
|
||
case NIMMessageTypeNotification:
|
||
[self handleNIMNotificationTypeMessage:message];
|
||
break;
|
||
case NIMMessageTypeCustom:
|
||
[self handleNimCustomTypeMessage:message];
|
||
break;
|
||
case NIMMessageTypeText:
|
||
[self.messageContainerView handleNIMTextMessage:message];
|
||
[self.littleGameView handleNIMTextMessage:message];
|
||
break;
|
||
case NIMMessageTypeTip:
|
||
[self.messageContainerView handleNIMTextMessage:message];
|
||
break;
|
||
case NIMMessageTypeImage:
|
||
[self.messageContainerView handleNIMImageMessage:message];
|
||
break;
|
||
default:
|
||
break;
|
||
}
|
||
}
|
||
|
||
// 新增:StageViewManager 懒加载
|
||
- (StageViewManager *)stageViewManager {
|
||
if (!_stageViewManager) {
|
||
_stageViewManager = [[StageViewManager alloc] init];
|
||
NSLog(@"✅ StageViewManager 懒加载初始化成功");
|
||
}
|
||
return _stageViewManager;
|
||
}
|
||
|
||
// 新增:设置 StageViewManager
|
||
- (void)setupStageViewManager {
|
||
// 触发懒加载
|
||
[self stageViewManager];
|
||
NSLog(@"✅ StageViewManager 设置完成");
|
||
}
|
||
|
||
// 调试方法:检查 stageView 状态
|
||
- (void)debugStageViewStatus {
|
||
NSLog(@"🔍 DEBUG: stageView 状态检查");
|
||
NSLog(@" - stageView: %@", self.stageView);
|
||
NSLog(@" - stageView.alpha: %.2f", self.stageView.alpha);
|
||
NSLog(@" - stageView.hidden: %@", self.stageView.hidden ? @"YES" : @"NO");
|
||
NSLog(@" - stageView.superview: %@", self.stageView.superview);
|
||
NSLog(@" - stageView.frame: %@", NSStringFromCGRect(self.stageView.frame));
|
||
NSLog(@" - stageView.class: %@", NSStringFromClass([self.stageView class]));
|
||
}
|
||
|
||
|
||
/// 在 StageView 上绘制符合条件的相邻麦位中点矩形
|
||
- (void)drawSocialStageMidpointRects {
|
||
if (!self.stageView) {
|
||
NSLog(@"🔧 当前没有 stageView,跳过中点矩形绘制");
|
||
return;
|
||
}
|
||
|
||
// 使用 MicMidpointRectManager 绘制社交舞台中点矩形
|
||
MicMidpointRectManager *manager = (MicMidpointRectManager *)[self.stageView performSelector:@selector(midpointRectManager)];
|
||
if (manager) {
|
||
// 计算麦位总数
|
||
NSInteger micCount = [self getMicCountForRoomType:self.roomInfo.type];
|
||
[manager drawSocialStageMidpointRectsWithStageView:self.stageView
|
||
micCount:micCount
|
||
roomType:self.roomInfo.type];
|
||
} else {
|
||
NSLog(@"🔧 无法获取 midpointRectManager,跳过中点矩形绘制");
|
||
}
|
||
}
|
||
|
||
/// 进房成功后调用CP相关API
|
||
- (void)callMicCpListByRoomUidAfterRoomEntered {
|
||
NSLog(@"🔧 进房成功:开始调用 micCpListByRoomUid API");
|
||
|
||
if (!self.roomInfo) {
|
||
NSLog(@"⚠️ 进房成功:roomInfo为空,跳过CP API调用");
|
||
return;
|
||
}
|
||
|
||
NSString *roomUid = [NSString stringWithFormat:@"%ld", (long)self.roomInfo.uid];
|
||
NSLog(@"🔧 进房成功:房间UID: %@, 房间类型: %ld", roomUid, (long)self.roomInfo.type);
|
||
|
||
// 调用 micCpListByRoomUid 方法
|
||
if ([self.presenter respondsToSelector:@selector(micCpListByRoomUid:)]) {
|
||
NSLog(@"🔧 进房成功:调用 micCpListByRoomUid: %@", roomUid);
|
||
[self.presenter micCpListByRoomUid:roomUid];
|
||
} else {
|
||
NSLog(@"⚠️ 进房成功:presenter不支持micCpListByRoomUid方法");
|
||
}
|
||
|
||
NSLog(@"🔧 进房成功:micCpListByRoomUid API调用完成");
|
||
}
|
||
|
||
/// 获取当前用户及其左右相邻用户的uid列表(最多3个)
|
||
- (NSArray<NSString *> *)getAllMicUserUidsWithQueue:(NSMutableDictionary<NSString *,MicroQueueModel *> *)queue {
|
||
NSMutableArray<NSString *> *micUserUids = [NSMutableArray array];
|
||
|
||
if (!self.roomInfo) {
|
||
NSLog(@"⚠️ 获取mic用户列表:roomInfo为空");
|
||
return micUserUids;
|
||
}
|
||
|
||
// 获取当前用户的麦位位置
|
||
NSInteger currentUserMicPosition = self.currentUserMicPosition;
|
||
if (currentUserMicPosition == -1) {
|
||
NSLog(@"🔧 获取mic用户列表:当前用户不在麦上,返回空数据");
|
||
// 通知 manager 移除该用户 UID 的相关数据
|
||
NSInteger currentUid = [AccountInfoStorage instance].getUid.integerValue;
|
||
[self removeCpDataForUids:@[@(currentUid)]];
|
||
return micUserUids;
|
||
}
|
||
|
||
// 获取最大麦位数
|
||
NSInteger maxMicCount = 0;
|
||
switch (self.roomInfo.type) {
|
||
case RoomType_Room:
|
||
maxMicCount = 9;
|
||
break;
|
||
case RoomType_10Mic:
|
||
maxMicCount = 10;
|
||
break;
|
||
case RoomType_15Mic:
|
||
maxMicCount = 15;
|
||
break;
|
||
case RoomType_19Mic:
|
||
maxMicCount = 19;
|
||
break;
|
||
case RoomType_20Mic:
|
||
maxMicCount = 20;
|
||
break;
|
||
default:
|
||
maxMicCount = 9; // 默认9麦
|
||
break;
|
||
}
|
||
|
||
// 获取当前用户及其左右相邻用户的UID
|
||
NSInteger leftPosition = currentUserMicPosition - 1;
|
||
NSInteger rightPosition = currentUserMicPosition + 1;
|
||
|
||
// 获取左边用户
|
||
if (leftPosition >= 0) {
|
||
NSString *leftPositionKey = [NSString stringWithFormat:@"%ld", (long)leftPosition];
|
||
MicroQueueModel *leftMicModel = queue[leftPositionKey];
|
||
if (leftMicModel && leftMicModel.userInfo && leftMicModel.userInfo.uid > 0) {
|
||
[micUserUids addObject:[NSString stringWithFormat:@"%ld", (long)leftMicModel.userInfo.uid]];
|
||
}
|
||
}
|
||
|
||
// 获取当前用户
|
||
NSString *currentPositionKey = [NSString stringWithFormat:@"%ld", (long)currentUserMicPosition];
|
||
MicroQueueModel *currentMicModel = queue[currentPositionKey];
|
||
if (currentMicModel && currentMicModel.userInfo && currentMicModel.userInfo.uid > 0) {
|
||
[micUserUids addObject:[NSString stringWithFormat:@"%ld", (long)currentMicModel.userInfo.uid]];
|
||
}
|
||
|
||
// 获取右边用户
|
||
if (rightPosition < maxMicCount) {
|
||
NSString *rightPositionKey = [NSString stringWithFormat:@"%ld", (long)rightPosition];
|
||
MicroQueueModel *rightMicModel = queue[rightPositionKey];
|
||
if (rightMicModel && rightMicModel.userInfo && rightMicModel.userInfo.uid > 0) {
|
||
[micUserUids addObject:[NSString stringWithFormat:@"%ld", (long)rightMicModel.userInfo.uid]];
|
||
}
|
||
}
|
||
|
||
// 🔧 修复:即使只有当前用户一个人,也返回当前用户的UID,确保能触发NIM message
|
||
if (micUserUids.count == 1) {
|
||
NSLog(@"🔧 获取mic用户列表:只有当前用户一个人,但仍需发送NIM message");
|
||
// 不返回空数组,保持当前用户UID,确保能触发CP API和NIM message
|
||
}
|
||
|
||
NSLog(@"🔧 获取mic用户列表:当前用户麦位 %ld,找到 %lu 个相关用户: %@",
|
||
(long)currentUserMicPosition, (unsigned long)micUserUids.count, micUserUids);
|
||
return micUserUids;
|
||
}
|
||
|
||
|
||
/// 处理其他用户mic变化(包括切换场景)
|
||
- (void)handleOtherUserMicChange:(UserInfoModel *)userInfo changeType:(NSInteger)changeType {
|
||
if (!self.stageView || ![self.stageView respondsToSelector:@selector(midpointRectManager)]) {
|
||
NSLog(@"🔧 处理其他用户mic变化:stageView 不支持 midpointRectManager,跳过处理");
|
||
return;
|
||
}
|
||
|
||
// 获取当前麦位队列
|
||
NSMutableDictionary<NSString *,MicroQueueModel *> *currentQueue = [self.stageView getMicroQueue];
|
||
if (!currentQueue) {
|
||
NSLog(@"🔧 处理其他用户mic变化:无法获取当前麦位队列,跳过处理");
|
||
return;
|
||
}
|
||
|
||
// 使用 MicMidpointRectManager 处理其他用户mic变化
|
||
MicMidpointRectManager *manager = (MicMidpointRectManager *)[self.stageView performSelector:@selector(midpointRectManager)];
|
||
if (manager) {
|
||
// 计算麦位总数
|
||
NSInteger micCount = [self getMicCountForRoomType:self.roomInfo.type];
|
||
[manager handleOtherUserMicChange:userInfo
|
||
changeType:changeType
|
||
stageView:self.stageView
|
||
micCount:micCount
|
||
queue:currentQueue
|
||
roomType:self.roomInfo.type];
|
||
}
|
||
|
||
// 处理API调用
|
||
if (changeType == 2) { // 其他用户下麦
|
||
// 获取剩余用户列表
|
||
NSMutableArray<NSString *> *remainingUids = [NSMutableArray array];
|
||
for (NSString *positionKey in currentQueue.allKeys) {
|
||
MicroQueueModel *micModel = currentQueue[positionKey];
|
||
if (micModel && micModel.userInfo && micModel.userInfo.uid > 0) {
|
||
[remainingUids addObject:[NSString stringWithFormat:@"%ld", (long)micModel.userInfo.uid]];
|
||
}
|
||
}
|
||
|
||
// 调用API更新剩余用户的CP状态
|
||
if (remainingUids.count > 0) {
|
||
[self.presenter micCpListByUidList:remainingUids];
|
||
}
|
||
|
||
// 重绘
|
||
[self drawSocialStageMidpointRects];
|
||
|
||
} else if (changeType == 1) { // 其他用户上麦
|
||
// 调用CP API更新状态
|
||
[self callMicCpListByUidListWithQueue:currentQueue];
|
||
|
||
// 重新绘制所有CP关系
|
||
[self drawSocialStageMidpointRects];
|
||
}
|
||
}
|
||
|
||
|
||
/// 通用的CP数据移除方法
|
||
- (void)removeCpDataForUids:(NSArray<NSNumber *> *)uids {
|
||
if (!self.stageView || ![self.stageView respondsToSelector:@selector(midpointRectManager)]) {
|
||
NSLog(@"🔧 移除CP数据:stageView 不支持 midpointRectManager,跳过处理");
|
||
return;
|
||
}
|
||
|
||
if (uids.count == 0) {
|
||
NSLog(@"🔧 移除CP数据:没有需要移除的用户,跳过处理");
|
||
return;
|
||
}
|
||
|
||
// 使用 MicMidpointRectManager 移除CP数据
|
||
MicMidpointRectManager *manager = (MicMidpointRectManager *)[self.stageView performSelector:@selector(midpointRectManager)];
|
||
if (manager) {
|
||
[manager removeCpDataForUids:uids];
|
||
NSLog(@"🔧 移除CP数据完成:UIDs %@", uids);
|
||
}
|
||
}
|
||
|
||
|
||
/// 统一的CP API调用方法
|
||
- (void)callMicCpListByUidListWithQueue:(NSMutableDictionary<NSString *,MicroQueueModel *> *)queue {
|
||
NSLog(@"🔧 调用CP API:开始获取mic用户列表");
|
||
|
||
// 直接从queue获取当前所有在mic上的用户uid列表,确保数据是最新的
|
||
NSMutableArray<NSString *> *micUserUids = [NSMutableArray array];
|
||
|
||
if (queue) {
|
||
for (NSString *positionKey in queue.allKeys) {
|
||
MicroQueueModel *micModel = queue[positionKey];
|
||
if (micModel && micModel.userInfo && micModel.userInfo.uid > 0) {
|
||
[micUserUids addObject:[NSString stringWithFormat:@"%ld", (long)micModel.userInfo.uid]];
|
||
}
|
||
}
|
||
}
|
||
|
||
if (micUserUids.count == 0) {
|
||
NSLog(@"🔧 调用CP API:没有用户在mic上,跳过API调用");
|
||
return;
|
||
}
|
||
|
||
// 调用 micCpListByUidList 方法
|
||
NSLog(@"🔧 调用CP API:micCpListByUidList: %@", micUserUids);
|
||
[self.presenter micCpListByUidList:micUserUids];
|
||
|
||
NSLog(@"🔧 调用CP API:完成");
|
||
}
|
||
|
||
/// 初始化当前用户的麦位状态
|
||
- (void)initializeCurrentUserMicStatus {
|
||
NSLog(@"🔧 初始化当前用户麦位状态");
|
||
|
||
// 重置状态
|
||
self.currentUserMicStatusChanged = NO;
|
||
self.currentUserWasOnMic = NO;
|
||
self.currentUserMicPosition = -1;
|
||
self.hasCompletedRoomInitialization = NO; // 标记为未完成初始化
|
||
|
||
// 获取当前麦位状态
|
||
NSMutableDictionary<NSString *,MicroQueueModel *> *currentQueue = [self.stageView getMicroQueue];
|
||
if (currentQueue && currentQueue.count > 0) {
|
||
NSDictionary *currentStatus = [self getCurrentUserMicStatus:currentQueue];
|
||
BOOL isOnMic = [currentStatus[@"isOnMic"] boolValue];
|
||
NSInteger micPosition = [currentStatus[@"micPosition"] integerValue];
|
||
|
||
self.currentUserWasOnMic = isOnMic;
|
||
self.currentUserMicPosition = micPosition;
|
||
|
||
NSLog(@"🔧 初始化完成 - 当前用户是否在麦上: %@, 麦位: %ld",
|
||
isOnMic ? @"是" : @"否", (long)micPosition);
|
||
} else {
|
||
NSLog(@"🔧 初始化完成 - 当前没有麦位数据");
|
||
}
|
||
|
||
// 延迟设置初始化完成标志,确保进房时的麦位更新不会触发API调用
|
||
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
|
||
self.hasCompletedRoomInitialization = YES;
|
||
NSLog(@"🔧 进房初始化完成,后续麦位变动将触发 micCpListByUidList 调用");
|
||
});
|
||
}
|
||
|
||
/// 最小化进房时初始化当前用户麦位状态
|
||
- (void)initializeCurrentUserMicStatusForMiniEnter {
|
||
NSLog(@"🔧 最小化进房:初始化当前用户麦位状态");
|
||
|
||
// 重置状态
|
||
self.currentUserMicStatusChanged = NO;
|
||
self.currentUserWasOnMic = NO;
|
||
self.currentUserMicPosition = -1;
|
||
self.hasCompletedRoomInitialization = NO; // 标记为未完成初始化
|
||
|
||
// 获取当前麦位状态
|
||
NSMutableDictionary<NSString *,MicroQueueModel *> *currentQueue = [self.stageView getMicroQueue];
|
||
if (currentQueue && currentQueue.count > 0) {
|
||
NSDictionary *currentStatus = [self getCurrentUserMicStatus:currentQueue];
|
||
BOOL isOnMic = [currentStatus[@"isOnMic"] boolValue];
|
||
NSInteger micPosition = [currentStatus[@"micPosition"] integerValue];
|
||
|
||
self.currentUserWasOnMic = isOnMic;
|
||
self.currentUserMicPosition = micPosition;
|
||
|
||
NSLog(@"🔧 最小化进房初始化完成 - 当前用户是否在麦上: %@, 麦位: %ld",
|
||
isOnMic ? @"是" : @"否", (long)micPosition);
|
||
} else {
|
||
NSLog(@"🔧 最小化进房初始化完成 - 当前没有麦位数据");
|
||
}
|
||
|
||
// 最小化进房时立即设置初始化完成标志,因为云信已经连接
|
||
self.hasCompletedRoomInitialization = YES;
|
||
NSLog(@"🔧 最小化进房初始化完成,后续麦位变动将触发 micCpListByUidList 调用");
|
||
}
|
||
|
||
/// 获取当前用户的麦位状态
|
||
- (NSDictionary *)getCurrentUserMicStatus:(NSMutableDictionary<NSString *,MicroQueueModel *> *)queue {
|
||
NSInteger currentUid = [AccountInfoStorage instance].getUid.integerValue;
|
||
BOOL isOnMic = NO;
|
||
NSInteger micPosition = -1;
|
||
|
||
for (NSString *position in queue.allKeys) {
|
||
MicroQueueModel *micModel = queue[position];
|
||
if (micModel.userInfo.uid > 0 && micModel.userInfo.uid == currentUid) {
|
||
isOnMic = YES;
|
||
micPosition = position.integerValue;
|
||
break;
|
||
}
|
||
}
|
||
|
||
return @{
|
||
@"isOnMic": @(isOnMic),
|
||
@"micPosition": @(micPosition)
|
||
};
|
||
}
|
||
|
||
/// 检查当前用户麦位状态是否发生变化(上麦、下麦、换位)
|
||
- (BOOL)checkCurrentUserMicStatusChanged:(NSMutableDictionary<NSString *,MicroQueueModel *> *)queue {
|
||
NSDictionary *currentStatus = [self getCurrentUserMicStatus:queue];
|
||
BOOL currentUserOnMic = [currentStatus[@"isOnMic"] boolValue];
|
||
NSInteger currentMicPosition = [currentStatus[@"micPosition"] integerValue];
|
||
|
||
// 情况1:之前不在麦上,现在在麦上(上麦)
|
||
if (currentUserOnMic && !self.currentUserWasOnMic) {
|
||
NSLog(@"🔧 检测到当前用户刚刚上麦,麦位: %ld", (long)currentMicPosition);
|
||
return YES;
|
||
}
|
||
|
||
// 情况2:之前在麦上,现在不在麦上(下麦)
|
||
if (!currentUserOnMic && self.currentUserWasOnMic) {
|
||
NSLog(@"🔧 检测到当前用户刚刚下麦,之前麦位: %ld", (long)self.currentUserMicPosition);
|
||
return YES;
|
||
}
|
||
|
||
// 情况3:之前在麦上,现在也在麦上,但位置不同(换位)
|
||
if (currentUserOnMic && self.currentUserWasOnMic &&
|
||
currentMicPosition != self.currentUserMicPosition) {
|
||
NSLog(@"🔧 检测到当前用户换麦位,从 %ld 换到 %ld",
|
||
(long)self.currentUserMicPosition, (long)currentMicPosition);
|
||
return YES;
|
||
}
|
||
|
||
return NO;
|
||
}
|
||
|
||
/// 更新当前用户的麦位状态
|
||
- (void)updateCurrentUserMicStatus:(NSMutableDictionary<NSString *,MicroQueueModel *> *)queue {
|
||
NSDictionary *currentStatus = [self getCurrentUserMicStatus:queue];
|
||
BOOL currentUserOnMic = [currentStatus[@"isOnMic"] boolValue];
|
||
NSInteger micPosition = [currentStatus[@"micPosition"] integerValue];
|
||
|
||
// 检查麦位状态是否发生变化(上麦、下麦、换位)
|
||
if ([self checkCurrentUserMicStatusChanged:queue]) {
|
||
self.currentUserMicStatusChanged = YES;
|
||
}
|
||
|
||
// 更新状态
|
||
self.currentUserWasOnMic = currentUserOnMic;
|
||
self.currentUserMicPosition = micPosition;
|
||
}
|
||
|
||
/// 发送麦位关系 NIM message
|
||
- (void)sendMicRelationshipNIMessage:(NSArray<MicCpInfoModel *> *)cpList {
|
||
NSLog(@"🔧 发送麦位关系 NIM message,CP数据条数: %ld,当前用户麦位: %ld",
|
||
(long)cpList.count, (long)self.currentUserMicPosition);
|
||
|
||
if (!self.roomInfo) {
|
||
NSLog(@"⚠️ 发送麦位关系 NIM message:roomInfo为空,跳过发送");
|
||
return;
|
||
}
|
||
|
||
// 将 CP 数据转换为 JSON string
|
||
NSMutableArray *cpDataArray = [NSMutableArray array];
|
||
for (MicCpInfoModel *cpInfo in cpList) {
|
||
NSDictionary *cpDict = @{
|
||
@"uid": @(cpInfo.uid),
|
||
@"loverUid": @(cpInfo.loverUid),
|
||
@"cpLevel": @(cpInfo.cpLevel)
|
||
};
|
||
[cpDataArray addObject:cpDict];
|
||
}
|
||
|
||
NSError *error = nil;
|
||
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:cpDataArray.copy
|
||
options:0
|
||
error:&error];
|
||
if (error) {
|
||
NSLog(@"❌ 发送麦位关系 NIM message:JSON序列化失败 - %@", error.localizedDescription);
|
||
return;
|
||
}
|
||
|
||
NSString *jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
|
||
NSLog(@"🔧 发送麦位关系 NIM message:JSON数据 - %@", jsonString);
|
||
|
||
NSDictionary *finalData = @{@"first": @(MicRelationship_Type),
|
||
@"second":@(MicRelationship_CP),
|
||
@"data":jsonString};
|
||
|
||
// 创建 AttachmentModel
|
||
AttachmentModel *attachment = [[AttachmentModel alloc] init];
|
||
attachment.first = MicRelationship_Type; // 1001
|
||
attachment.second = MicRelationship_CP; // 10011
|
||
attachment.data = finalData;
|
||
|
||
// 创建 NIM message
|
||
NIMMessage *message = [[NIMMessage alloc] init];
|
||
NIMCustomObject *object = [[NIMCustomObject alloc] init];
|
||
object.attachment = attachment;
|
||
message.messageObject = object;
|
||
|
||
// 设置用户信息到 remoteExt
|
||
UserInfoModel *userInfo = [self getUserInfo];
|
||
XPMessageRemoteExtModel *extModel = [[XPMessageRemoteExtModel alloc] init];
|
||
extModel.androidBubbleUrl = userInfo.androidBubbleUrl;
|
||
extModel.iosBubbleUrl = userInfo.iosBubbleUrl;
|
||
extModel.fromSayHelloChannel = userInfo.fromSayHelloChannel;
|
||
extModel.platformRole = userInfo.platformRole;
|
||
NSMutableDictionary *remoteExt = [NSMutableDictionary dictionaryWithObject:extModel.model2dictionary forKey:[NSString stringWithFormat:@"%ld", userInfo.uid]];
|
||
message.remoteExt = remoteExt;
|
||
|
||
// 构造会话
|
||
NSString *sessionID = [NSString stringWithFormat:@"%ld", self.roomInfo.roomId];
|
||
NIMSession *session = [NIMSession session:sessionID type:NIMSessionTypeChatroom];
|
||
|
||
// 发送消息
|
||
[[NIMSDK sharedSDK].chatManager sendMessage:message toSession:session completion:^(NSError * _Nullable error) {
|
||
if (error) {
|
||
NSLog(@"❌ 发送麦位关系 NIM message 失败 - %@", error.localizedDescription);
|
||
} else {
|
||
NSLog(@"✅ 发送麦位关系 NIM message 成功");
|
||
}
|
||
}];
|
||
}
|
||
|
||
/// 更新 MicMidpointRectManager 的缓存
|
||
- (void)updateMicMidpointRectManagerCache:(NSArray<MicCpInfoModel *> *)cpList {
|
||
if (!self.stageView) {
|
||
NSLog(@"<EFBFBD><EFBFBD> 更新缓存:stageView 为空,跳过缓存更新");
|
||
return;
|
||
}
|
||
|
||
MicMidpointRectManager *midpointRectManager = (MicMidpointRectManager *)[self.stageView performSelector:@selector(midpointRectManager)];
|
||
if (midpointRectManager) {
|
||
// 设置房间类型
|
||
midpointRectManager.roomType = self.roomInfo.type;
|
||
// 获取当前用户及其相邻用户的UID列表
|
||
NSMutableDictionary<NSString *,MicroQueueModel *> *currentQueue = [self.stageView getMicroQueue];
|
||
NSArray<NSString *> *micUserUids = [self getAllMicUserUidsWithQueue:currentQueue];
|
||
|
||
// 转换为 NSNumber 数组
|
||
NSMutableArray<NSNumber *> *uidNumbers = [NSMutableArray array];
|
||
for (NSString *uidString in micUserUids) {
|
||
[uidNumbers addObject:@(uidString.integerValue)];
|
||
}
|
||
|
||
// 更新缓存:先移除相关用户的旧数据,再合并新数据
|
||
[midpointRectManager mergeCpListCache:cpList replaceForUids:uidNumbers];
|
||
|
||
NSLog(@"<EFBFBD><EFBFBD> 更新缓存完成:CP数据条数 %lu,相关用户 %@",
|
||
(unsigned long)cpList.count, uidNumbers);
|
||
}
|
||
}
|
||
|
||
/// 更新 MicMidpointRectManager 的麦位快照
|
||
- (void)updateMicMidpointRectManagerSnapshot {
|
||
if (!self.stageView) {
|
||
NSLog(@"<EFBFBD><EFBFBD> 更新快照:stageView 为空,跳过快照更新");
|
||
return;
|
||
}
|
||
|
||
// 获取当前舞台类型的麦位总数
|
||
NSInteger micCount = 0;
|
||
if (self.roomInfo) {
|
||
switch (self.roomInfo.type) {
|
||
case RoomType_Room: micCount = 9; break;
|
||
case RoomType_10Mic: micCount = 10; break;
|
||
case RoomType_15Mic: micCount = 15; break;
|
||
case RoomType_19Mic: micCount = 19; break;
|
||
case RoomType_20Mic: micCount = 20; break;
|
||
default: micCount = 9; break;
|
||
}
|
||
}
|
||
|
||
MicMidpointRectManager *midpointRectManager = (MicMidpointRectManager *)[self.stageView performSelector:@selector(midpointRectManager)];
|
||
if (midpointRectManager) {
|
||
// 设置房间类型
|
||
midpointRectManager.roomType = self.roomInfo.type;
|
||
[midpointRectManager rebuildMicSnapshotWithStageView:self.stageView micCount:micCount];
|
||
NSLog(@"🔧 更新麦位快照完成:麦位总数 %ld", (long)micCount);
|
||
}
|
||
}
|
||
|
||
/// 根据房间类型获取麦位总数
|
||
- (NSInteger)getMicCountForRoomType:(NSInteger)roomType {
|
||
switch (roomType) {
|
||
case RoomType_Room: return 9;
|
||
case RoomType_10Mic: return 10;
|
||
case RoomType_15Mic: return 15;
|
||
case RoomType_19Mic: return 19;
|
||
case RoomType_20Mic: return 20;
|
||
default: return 9;
|
||
}
|
||
}
|
||
|
||
/// 检查19 mic房间中央位置(position 6)用户资格
|
||
- (void)checkCentralPositionUserQualification:(NSMutableDictionary<NSString *,MicroQueueModel *> *)queue {
|
||
// 只检查19 mic房间
|
||
if (self.roomInfo.type != RoomType_19Mic) {
|
||
return;
|
||
}
|
||
|
||
NSLog(@"🔧 检查19 mic房间中央位置用户资格");
|
||
|
||
// 查找中央位置(position 6)的用户
|
||
MicroQueueModel *centralMicModel = nil;
|
||
for (NSString *positionKey in queue.allKeys) {
|
||
MicroQueueModel *micModel = queue[positionKey];
|
||
if (micModel.microState.position == 6) {
|
||
centralMicModel = micModel;
|
||
break;
|
||
}
|
||
}
|
||
|
||
// 如果中央位置有用户,检查其资格
|
||
if (centralMicModel && centralMicModel.userInfo) {
|
||
NSString *userId = [NSString stringWithFormat:@"%ld", (long)centralMicModel.userInfo.uid];
|
||
NSLog(@"🔧 中央位置用户:%@,检查资格", userId);
|
||
|
||
// 调用Boss位置资格检查API
|
||
[Api requestBossMicUp:^(BaseModel * _Nullable data, NSInteger code, NSString * _Nullable msg) {
|
||
if (code == 200) {
|
||
NSLog(@"✅ 中央位置用户资格检查通过:%@", userId);
|
||
} else {
|
||
NSLog(@"❌ 中央位置用户资格检查失败:%@,错误:%@", userId, msg);
|
||
// 不满足条件的用户需要下mic
|
||
[self forceDownMicForUser:userId atPosition:6];
|
||
}
|
||
} roomUid:@(self.roomInfo.uid).stringValue uid:userId];
|
||
} else {
|
||
NSLog(@"🔧 中央位置无用户,无需检查");
|
||
}
|
||
}
|
||
|
||
/// 强制用户下mic
|
||
- (void)forceDownMicForUser:(NSString *)userId atPosition:(NSInteger)position {
|
||
NSLog(@"🔧 强制用户下mic:%@,位置:%ld", userId, (long)position);
|
||
|
||
// 使用 NIM 的 API 强制下mic
|
||
NIMChatroomQueueRemoveRequest *request = [[NIMChatroomQueueRemoveRequest alloc] init];
|
||
request.key = [NSString stringWithFormat:@"%ld", (long)position];
|
||
request.roomId = @(self.roomInfo.roomId).stringValue;
|
||
|
||
[[NIMSDK sharedSDK].chatroomManager removeChatroomQueueObject:request completion:^(NSError * _Nullable error, NSDictionary<NSString *,NSString *> * _Nullable element) {
|
||
if (error) {
|
||
NSLog(@"❌ 强制下mic失败:%@,错误:%@", userId, error.localizedDescription);
|
||
[XNDJTDDLoadingTool showErrorWithMessage:@"强制下mic失败"];
|
||
} else {
|
||
NSLog(@"✅ 强制下mic成功:%@", userId);
|
||
[XNDJTDDLoadingTool showSuccessWithMessage:@"中央位置需要满足贡献值要求,已自动下mic"];
|
||
}
|
||
}];
|
||
}
|
||
|
||
@end
|